Instant Articles for WP - Version 4.0.0

Version Description

Download this release

Release Info

Developer diegoquinteiro
Plugin Icon 128x128 Instant Articles for WP
Version 4.0.0
Comparing to
See all releases

Code changes from version 3.3.5 to 4.0.0

Files changed (118) hide show
  1. class-instant-articles-amp-markup.php +173 -0
  2. class-instant-articles-post.php +77 -5
  3. compat.php +2 -2
  4. compat/class-instant-articles-google-analytics-for-wordpress.php +14 -8
  5. facebook-instant-articles.php +98 -16
  6. meta-box/class-instant-articles-meta-box.php +10 -42
  7. meta-box/meta-box-template.php +45 -116
  8. readme.txt +1 -1
  9. rules-configuration.json +3 -0
  10. vendor/autoload.php +1 -1
  11. vendor/bin/phpcbf +23 -0
  12. vendor/bin/phpcs +25 -0
  13. vendor/composer/autoload_classmap.php +252 -0
  14. vendor/composer/autoload_psr4.php +1 -1
  15. vendor/composer/autoload_real.php +7 -7
  16. vendor/composer/autoload_static.php +257 -4
  17. vendor/composer/installed.json +213 -43
  18. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/.gitignore +7 -0
  19. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/.travis.yml +28 -0
  20. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/CONTRIBUTING.md +54 -0
  21. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/LICENSE +19 -0
  22. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/README.md +105 -0
  23. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/composer.json +43 -0
  24. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/composer.lock +1329 -0
  25. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-override-styling.php +31 -0
  26. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-quick-start.php +64 -0
  27. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-simple-styling.php +32 -0
  28. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/instant-article-example.html +89 -0
  29. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/quiet_logger.php +18 -0
  30. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/styles/gray.style.json +993 -0
  31. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/styles/style-got-from-somewhereelse.json +993 -0
  32. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/phpcs.xml +8 -0
  33. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/phpunit.xml +18 -0
  34. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPArticle.php +1460 -0
  35. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCaption.php +158 -0
  36. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPContext.php +709 -0
  37. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCover.php +59 -0
  38. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCoverImage.php +90 -0
  39. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPHeader.php +141 -0
  40. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPImage.php +23 -0
  41. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/configuration/default-amp.style.json +1133 -0
  42. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/configuration/global.amp.css +202 -0
  43. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/CSSBuilder.php +189 -0
  44. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/CallbackHook.php +390 -0
  45. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Hook.php +161 -0
  46. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Observer.php +285 -0
  47. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Warning.php +40 -0
  48. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPArticleTest.php +1092 -0
  49. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPCaptionTest.php +149 -0
  50. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPContextTest.php +563 -0
  51. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPCoverImageTest.php +129 -0
  52. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPHeaderTest.php +107 -0
  53. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/amp-converted.html +54 -0
  54. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/amp-example.html +79 -0
  55. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/fail1.jpg +0 -0
  56. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/fb_icon_325x325.png +0 -0
  57. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/heart-rate-age-300x182.gif +0 -0
  58. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/timelapse-final-4x3.mp4 +0 -0
  59. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test1-amp-converted.html +90 -0
  60. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test1-instant-article.html +58 -0
  61. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test2-amp-converted.html +95 -0
  62. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test2-instant-article.html +60 -0
  63. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test3-amp-converted.html +99 -0
  64. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test3-instant-article.html +73 -0
  65. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test4-amp-converted.html +103 -0
  66. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test4-instant-article.html +73 -0
  67. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test5-amp-converted.html +112 -0
  68. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test5-instant-article.html +80 -0
  69. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/tutorial-amp-converted.html +258 -0
  70. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/tutorial-instant-article.html +277 -0
  71. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/default.amp-custom.css +9 -0
  72. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/default.style.json +1128 -0
  73. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/wod-gray.style.json +993 -0
  74. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/CSSBuilderTest.php +190 -0
  75. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/FileUtilsPHPUnitTestCase.php +80 -0
  76. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/Greeting.php +46 -0
  77. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/HookTest.php +252 -0
  78. vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/ObserverTest.php +155 -0
  79. vendor/facebook/facebook-instant-articles-sdk-php/.travis.yml +1 -0
  80. vendor/facebook/facebook-instant-articles-sdk-php/README.md +22 -10
  81. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Analytics.php +1 -1
  82. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Emphasized.php +53 -0
  83. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/InstantArticle.php +29 -6
  84. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/TextContainer.php +9 -1
  85. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Parser/Parser.php +7 -3
  86. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Parser/instant-articles-rules.json +14 -1
  87. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/EmphasizedRule.php +38 -0
  88. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/InstantArticleRule.php +7 -0
  89. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/TimeRule.php +8 -1
  90. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php +35 -1
  91. vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Validators/Type.php +2 -2
  92. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/ImageTest.php +2 -2
  93. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/InstantArticleTest.php +33 -1
  94. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/ParagraphTest.php +3 -1
  95. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/Validators/InstantArticleValidatorTest.php +2 -2
  96. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/Validators/TypeTest.php +3 -1
  97. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/ParserTest.php +52 -0
  98. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-ads.html +38 -0
  99. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-no-timezone.html +199 -0
  100. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-nyc-timezone.html +199 -0
  101. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-standard-timezone.html +199 -0
  102. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example.html +1 -1
  103. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CustomHTMLTransformerTest.php +1 -1
  104. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple-ia.html +2 -45
  105. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple.html +2 -42
  106. vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Rules/AuthorRuleTest.php +36 -0
  107. vendor/squizlabs/php_codesniffer/.gitattributes +13 -0
  108. vendor/squizlabs/php_codesniffer/.gitignore +6 -0
  109. vendor/squizlabs/php_codesniffer/CONTRIBUTING.md +13 -0
  110. vendor/squizlabs/php_codesniffer/CodeSniffer.conf.dist +9 -0
  111. vendor/squizlabs/php_codesniffer/CodeSniffer.php +2578 -0
  112. vendor/squizlabs/php_codesniffer/CodeSniffer/CLI.php +1444 -0
  113. vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Generator.php +184 -0
  114. vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/HTML.php +292 -0
  115. vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Markdown.php +179 -0
  116. vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Text.php +265 -0
  117. vendor/squizlabs/php_codesniffer/CodeSniffer/Exception.php +31 -0
  118. vendor/squizlabs/php_codesniffer/CodeSniffer/File.php +1502 -0
class-instant-articles-amp-markup.php ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Facebook Instant Articles for WP.
4
+ * This source code is licensed under the license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @package default
8
+ * @since 4.0
9
+ */
10
+
11
+ use Facebook\InstantArticles\AMP\AMPArticle;
12
+ use Facebook\InstantArticles\Validators\Type;
13
+
14
+ class Instant_Articles_AMP_Markup {
15
+
16
+ const SETTING_AMP_MARKUP = 'amp_markup'; // Setting to check if AMP Markup generation is enabled
17
+ const SETTING_STYLE = 'amp_stylesheet'; // Setting that stores the JSON stylesheet
18
+ const SETTING_DL_MEDIA = 'amp_download_media'; // Enable or disable media download option
19
+ const QUERY_ARG = 'amp_markup'; // Query argument that will trigger the AMP markup generation
20
+
21
+ // To memoize the settings
22
+ static $settings = null;
23
+
24
+ /**
25
+ * Gets the settings
26
+ *
27
+ * @return array The settings, check Instant_Articles_Option::get_option_decoded()
28
+ * @since 4.0
29
+ */
30
+ static function get_settings() {
31
+ if ( self::$settings === null ) {
32
+ self::$settings = Instant_Articles_Option_AMP::get_option_decoded();
33
+ }
34
+
35
+ return self::$settings;
36
+ }
37
+
38
+ /**
39
+ * Checks if the AMP markup is enabled
40
+ *
41
+ * @return bool true if markup is enabled
42
+ * @since 4.0
43
+ */
44
+ static function is_markup_enabled() {
45
+ $settings = self::get_settings();
46
+
47
+ return
48
+ isset( $settings[ self::SETTING_AMP_MARKUP ] )
49
+ ? (bool) $settings[ self::SETTING_AMP_MARKUP ]
50
+ : false;
51
+ }
52
+
53
+ /**
54
+ * Adds the meta tag for AMP Markup if enabled
55
+ *
56
+ * @since 4.0
57
+ */
58
+ static function inject_link_rel() {
59
+
60
+ if ( ! self::is_markup_enabled() ) {
61
+ return;
62
+ }
63
+
64
+ // Transform the post to an Instant Article.
65
+ $adapter = new Instant_Articles_Post( get_post() );
66
+
67
+ if ( ! $adapter->should_submit_post() ) {
68
+ return;
69
+ }
70
+
71
+ $url = $adapter->get_canonical_url();
72
+ $url = add_query_arg( self::QUERY_ARG, '1', $url );
73
+
74
+ echo '<link rel="amphtml" href="' . $url . '">';
75
+
76
+ }
77
+
78
+ /**
79
+ * Generates the AMP markup if post has amp_markup
80
+ *
81
+ * NOTE: side-effect: function calls die() in the end.
82
+ *
83
+ * @since 4.0
84
+ */
85
+ static function markup_version() {
86
+ if ( ! (isset( $_GET[ self::QUERY_ARG ] ) && $_GET[ self::QUERY_ARG ]) ) {
87
+ return;
88
+ }
89
+
90
+ $settings = self::get_settings();
91
+
92
+ if ( ! self::is_markup_enabled() ) {
93
+ return;
94
+ }
95
+
96
+ $has_stylesheet =
97
+ isset( $settings[ self::SETTING_STYLE ] )
98
+ ? self::validate_json( $settings[ self::SETTING_STYLE ] )
99
+ : false;
100
+
101
+ $properties = array();
102
+
103
+ $download_media =
104
+ isset( $settings[ self::SETTING_DL_MEDIA ] )
105
+ ? (bool) $settings[ self::SETTING_DL_MEDIA ]
106
+ : false;
107
+
108
+ $properties[ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY ] = $download_media;
109
+
110
+ if ( $has_stylesheet ) {
111
+ $properties[ AMPArticle::OVERRIDE_STYLES_KEY ] =
112
+ json_decode( $settings[ self::SETTING_STYLE ], true );
113
+ }
114
+
115
+ $post = get_post();
116
+
117
+ // This array will hold the image sizes
118
+ $media_sizes = array();
119
+
120
+ // Get all children with mime type image that are attached to the posts
121
+ // NOTE: this will not get images that are not hosted in the WP
122
+ $image_children = get_children( 'post_type=attachment&post_mime_type=image&post_parent=' . $post->ID );
123
+
124
+ foreach ( $image_children as $img_id => $img ) {
125
+ $meta = wp_get_attachment_metadata( $img_id );
126
+
127
+ // Removes the file name from the URL
128
+ $url_chunks = explode( '/', $img->guid );
129
+ array_pop( $url_chunks );
130
+ $base_image_url = implode( '/', $url_chunks ) . '/';
131
+
132
+ // This is the uploaded original file
133
+ $media_sizes[ $img->guid ] = array( $meta['width'], $meta['height'] );
134
+
135
+ // These are the possible redimensions
136
+ foreach ( $meta['sizes'] as $size ) {
137
+ $size_url = $base_image_url . $size['file'];
138
+ $media_sizes[ $size_url ] = array( $size['width'], $size['height'] );
139
+ }
140
+ }
141
+
142
+ $properties[ AMPArticle::MEDIA_SIZES_KEY ] = $media_sizes;
143
+
144
+ // Transform the post to an Instant Article.
145
+ $adapter = new Instant_Articles_Post( $post );
146
+ $article = $adapter->to_instant_article();
147
+ $article_html = $article->render();
148
+ $amp = AMPArticle::create( $article_html, $properties );
149
+ echo $amp->render();
150
+
151
+ die();
152
+ }
153
+
154
+ /**
155
+ * Helper function to validate the json string
156
+ *
157
+ * @param $json_str string JSON string
158
+ * @return bool true for valid JSON
159
+ * @since 4.0
160
+ */
161
+ static function validate_json( $json_str ) {
162
+ if ( Type::isTextEmpty( $json_str ) ) {
163
+ return false;
164
+ }
165
+
166
+ json_decode( $json_str );
167
+ if ( json_last_error() == JSON_ERROR_NONE ) {
168
+ return true;
169
+ }
170
+
171
+ return false;
172
+ }
173
+ }
class-instant-articles-post.php CHANGED
@@ -17,7 +17,10 @@ use Facebook\InstantArticles\Elements\Image;
17
  use Facebook\InstantArticles\Elements\Video;
18
  use Facebook\InstantArticles\Elements\Caption;
19
  use Facebook\InstantArticles\Elements\Footer;
 
20
  use Facebook\InstantArticles\Transformer\Transformer;
 
 
21
  /**
22
  * Class responsible for constructing our content and preparing it for rendering
23
  *
@@ -690,8 +693,11 @@ class Instant_Articles_Post {
690
  Image::setDefaultCommentEnabled( $settings_publishing[ 'comments_on_media' ] );
691
  Video::setDefaultCommentEnabled( $settings_publishing[ 'comments_on_media' ] );
692
  }
693
-
694
- $transformer->transformString( $this->instant_article, $this->get_the_content(), get_option( 'blog_charset' ) );
 
 
 
695
 
696
  $this->add_ads_from_settings();
697
  $this->add_analytics_from_settings();
@@ -865,6 +871,69 @@ class Instant_Articles_Post {
865
  }
866
  }
867
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
868
  /**
869
  * Apply appearance settings for an InstantArticle.
870
  *
@@ -880,9 +949,12 @@ class Instant_Articles_Post {
880
  }
881
 
882
  if ( isset( $settings['copyright'] ) && ! empty( $settings['copyright'] ) ) {
883
- $this->instant_article->withFooter(
884
- Footer::create()->withCopyright( $settings['copyright'] )
885
- );
 
 
 
886
  }
887
 
888
  if ( isset( $settings['rtl_enabled'] ) ) {
17
  use Facebook\InstantArticles\Elements\Video;
18
  use Facebook\InstantArticles\Elements\Caption;
19
  use Facebook\InstantArticles\Elements\Footer;
20
+ use Facebook\InstantArticles\Elements\Small;
21
  use Facebook\InstantArticles\Transformer\Transformer;
22
+ use Facebook\InstantArticles\Validators\Type;
23
+
24
  /**
25
  * Class responsible for constructing our content and preparing it for rendering
26
  *
693
  Image::setDefaultCommentEnabled( $settings_publishing[ 'comments_on_media' ] );
694
  Video::setDefaultCommentEnabled( $settings_publishing[ 'comments_on_media' ] );
695
  }
696
+
697
+ $the_content = $this->get_the_content();
698
+ if (!Type::isTextEmpty($the_content)) {
699
+ $transformer->transformString( $this->instant_article, $the_content, get_option( 'blog_charset' ) );
700
+ }
701
 
702
  $this->add_ads_from_settings();
703
  $this->add_analytics_from_settings();
871
  }
872
  }
873
 
874
+ /**
875
+ * Returns whether the article should be ingested as an Instant Article.
876
+ */
877
+ public function should_submit_post() {
878
+
879
+ $post = get_post( $this->get_the_id() );
880
+
881
+ $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
882
+ if ( ! $fb_page_settings[ "page_id" ] ) {
883
+ return false;
884
+ }
885
+
886
+ // Don't process if this is just a revision or an autosave.
887
+ if ( wp_is_post_revision( $this->post ) || wp_is_post_autosave( $this->post ) ) {
888
+ return false;
889
+ }
890
+
891
+ // Don't process if this post is not published
892
+ if ( 'publish' !== $post->post_status ) {
893
+ return false;
894
+ }
895
+
896
+ // Only process posts
897
+ $post_types = apply_filters( 'instant_articles_post_types', array( 'post' ) );
898
+ if ( ! in_array( $post->post_type, $post_types ) ) {
899
+ return false;
900
+ }
901
+
902
+ // Transform the post to an Instant Article.
903
+ $adapter = new Instant_Articles_Post( $post );
904
+ $instant_article = $this->to_instant_article();
905
+
906
+ // Skip empty articles or articles missing title.
907
+ // This is important because the save_post action is also triggered by bulk updates, but in this case
908
+ // WordPress does not load the content field from DB for performance reasons. In this case, articles
909
+ // will be empty here, despite of them actually having content.
910
+ if ( count( $instant_article->getChildren() ) === 0 || ! $instant_article->getHeader() || ! $instant_article->getHeader()->getTitle() ) {
911
+ return false;
912
+ }
913
+
914
+ // Don't publish posts with password protection
915
+ if ( post_password_required( $post ) ) {
916
+ return false;
917
+ }
918
+
919
+ // Don't process if contains warnings and blocker flag for transformation warnings is turned on.
920
+ $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
921
+ $force_submit = get_post_meta( $post->ID, IA_PLUGIN_FORCE_SUBMIT_KEY, true );
922
+ if ( count( $this->transformer->getWarnings() ) > 0
923
+ && ( ! isset( $publishing_settings[ 'publish_with_warnings' ] ) || ! $publishing_settings[ 'publish_with_warnings' ] )
924
+ && ( ! $force_submit )
925
+ ) {
926
+ return false;
927
+ }
928
+
929
+ // Allow to disable post submit via filter
930
+ if ( false === apply_filters( 'instant_articles_should_submit_post', true, $adapter ) ) {
931
+ return false;
932
+ }
933
+
934
+ return true;
935
+ }
936
+
937
  /**
938
  * Apply appearance settings for an InstantArticle.
939
  *
949
  }
950
 
951
  if ( isset( $settings['copyright'] ) && ! empty( $settings['copyright'] ) ) {
952
+ $footer = Footer::create();
953
+ $this->transformer->transformString(
954
+ $footer,
955
+ '<small>' . $settings['copyright'] . '</small>',
956
+ get_option( 'blog_charset' ) );
957
+ $this->instant_article->withFooter( $footer );
958
  }
959
 
960
  if ( isset( $settings['rtl_enabled'] ) ) {
compat.php CHANGED
@@ -21,8 +21,8 @@ if ( defined( 'WPSEO_VERSION' ) && ! defined( 'WPSEO_IA_COMPAT' ) ) {
21
  $yseo->init();
22
  }
23
 
24
- // Load support for Google Analytics for WordPress (Google Analytics by Yoast).
25
- if ( defined( 'GAWP_VERSION' ) && ! defined( 'GAWP_IA_COMPAT' ) ) {
26
  include( dirname( __FILE__ ) . '/compat/class-instant-articles-google-analytics-for-wordpress.php' );
27
  $gawp = new Instant_Articles_Google_Analytics_For_WordPress;
28
  $gawp->init();
21
  $yseo->init();
22
  }
23
 
24
+ // Load support for Google Analytics for WordPress by MonsterInsights.
25
+ if ( ( defined( 'GAWP_VERSION' ) || function_exists( 'MonsterInsights' ) ) && ! defined( 'GAWP_IA_COMPAT' ) ) {
26
  include( dirname( __FILE__ ) . '/compat/class-instant-articles-google-analytics-for-wordpress.php' );
27
  $gawp = new Instant_Articles_Google_Analytics_For_WordPress;
28
  $gawp->init();
compat/class-instant-articles-google-analytics-for-wordpress.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * Support class for Google Analytics for WordPress (Google Analytics by Yoast)
5
  *
6
  * @since 0.1
7
  */
@@ -30,7 +30,7 @@ class Instant_Articles_Google_Analytics_For_WordPress {
30
  */
31
  function add_to_registry( &$registry ) {
32
 
33
- $display_name = 'Google Analytics by Yoast';
34
 
35
  $identifier = 'google-analytics-for-wordpress';
36
 
@@ -49,16 +49,22 @@ class Instant_Articles_Google_Analytics_For_WordPress {
49
  */
50
  function get_raw_embed_code() {
51
 
52
- $options = Yoast_GA_Options::instance()->options;
53
 
54
- if ( isset( $options['enable_universal'] ) && 1 === intval( $options['enable_universal'] ) ) {
55
- $tracker = new Yoast_GA_Universal;
56
  } else {
57
- $tracker = new Yoast_GA_JS;
 
 
 
 
 
 
 
 
58
  }
59
 
60
- ob_start();
61
- $tracker->tracking();
62
  $ga_code = ob_get_clean();
63
 
64
  return $ga_code;
1
  <?php
2
 
3
  /**
4
+ * Support class for Google Analytics for WordPress by MonsterInsights
5
  *
6
  * @since 0.1
7
  */
30
  */
31
  function add_to_registry( &$registry ) {
32
 
33
+ $display_name = 'Google Analytics by MonsterInsights';
34
 
35
  $identifier = 'google-analytics-for-wordpress';
36
 
49
  */
50
  function get_raw_embed_code() {
51
 
52
+ ob_start();
53
 
54
+ if ( function_exists( 'monsterinsights_tracking_script' ) ) {
55
+ monsterinsights_tracking_script();
56
  } else {
57
+ $options = Yoast_GA_Options::instance()->options;
58
+
59
+ if ( isset( $options['enable_universal'] ) && 1 === intval( $options['enable_universal'] ) ) {
60
+ $tracker = new Yoast_GA_Universal;
61
+ } else {
62
+ $tracker = new Yoast_GA_JS;
63
+ }
64
+
65
+ $tracker->tracking();
66
  }
67
 
 
 
68
  $ga_code = ob_get_clean();
69
 
70
  return $ga_code;
facebook-instant-articles.php CHANGED
@@ -4,7 +4,7 @@
4
  * Description: Add support for Instant Articles for Facebook to your WordPress site.
5
  * Author: Automattic, Dekode, Facebook
6
  * Author URI: https://vip.wordpress.com/plugins/instant-articles/
7
- * Version: 3.3.5
8
  * Text Domain: instant-articles
9
  * License: GPLv2
10
  * License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -31,6 +31,7 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
31
 
32
  $autoloader = require __DIR__ . '/vendor/autoload.php';
33
  $autoloader->add( 'Facebook\\', __DIR__ . '/vendor/facebook/facebook-instant-articles-sdk-php/src' );
 
34
 
35
  // Configures log to go through console.
36
  \Logger::configure(
@@ -67,11 +68,12 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
67
 
68
  defined( 'ABSPATH' ) || die( 'Shame on you' );
69
 
70
- define( 'IA_PLUGIN_VERSION', '3.3.5' );
71
  define( 'IA_PLUGIN_PATH_FULL', __FILE__ );
72
  define( 'IA_PLUGIN_PATH', plugin_basename( __FILE__ ) );
73
  define( 'IA_PLUGIN_FILE_BASENAME', pathinfo( __FILE__, PATHINFO_FILENAME ) );
74
  define( 'IA_PLUGIN_TEXT_DOMAIN', 'instant-articles' );
 
75
 
76
  // Let users define their own feed slug.
77
  if ( ! defined( 'INSTANT_ARTICLES_SLUG' ) ) {
@@ -82,7 +84,7 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
82
  require_once( dirname( __FILE__ ) . '/class-instant-articles-post.php' );
83
  require_once( dirname( __FILE__ ) . '/wizard/class-instant-articles-wizard.php' );
84
  require_once( dirname( __FILE__ ) . '/meta-box/class-instant-articles-meta-box.php' );
85
- require_once( dirname( __FILE__ ) . '/class-instant-articles-publisher.php' );
86
 
87
  /**
88
  * Plugin activation hook to add our rewrite rules.
@@ -102,7 +104,7 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
102
  add_action( 'network_admin_notices', 'instant_articles_setup_admin_notice' ); // also show message on multisite
103
  function instant_articles_setup_admin_notice() {
104
  global $pagenow;
105
- if ( $pagenow === 'plugins.php' && Instant_Articles_Wizard_State::get_current_state() !== Instant_Articles_Wizard_State::STATE_REVIEW_SUBMISSION ) {
106
  $settings_url = Instant_Articles_Wizard::get_url();
107
  echo '<div class="updated settings-error notice is-dismissible">';
108
  echo '<p>Congrats, you\'ve installed the Instant Articles for WP plugin. Now <a href="' . esc_url_raw($settings_url) . '">set it up</a> to start publishing Instant Articles.';
@@ -314,13 +316,6 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
314
  IA_PLUGIN_VERSION,
315
  false
316
  );
317
- wp_register_script(
318
- 'instant-articles-wizard',
319
- plugins_url( '/js/instant-articles-wizard.js', __FILE__ ),
320
- null,
321
- IA_PLUGIN_VERSION,
322
- false
323
- );
324
  }
325
  add_action( 'init', 'instant_articles_register_scripts' );
326
 
@@ -354,20 +349,107 @@ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
354
  $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
355
  $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
356
 
357
- if ( isset( $fb_page_settings['page_id'] ) ) {
358
  ?>
359
- <meta property="fb:pages" content="<?php echo esc_attr( $fb_page_settings['page_id'] ); ?>" />
360
  <?php
361
  }
362
  }
363
  add_action( 'wp_head', 'inject_url_claiming_meta_tag' );
364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  // Initialize the Instant Articles meta box.
366
  Instant_Articles_Meta_Box::init();
367
 
368
- // Initialize the Instant Articles publisher.
369
- Instant_Articles_Publisher::init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
- // Initialize the Instant Articles Wizard page.
372
  Instant_Articles_Wizard::init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  }
4
  * Description: Add support for Instant Articles for Facebook to your WordPress site.
5
  * Author: Automattic, Dekode, Facebook
6
  * Author URI: https://vip.wordpress.com/plugins/instant-articles/
7
+ * Version: 4.0.0
8
  * Text Domain: instant-articles
9
  * License: GPLv2
10
  * License URI: http://www.gnu.org/licenses/gpl-2.0.html
31
 
32
  $autoloader = require __DIR__ . '/vendor/autoload.php';
33
  $autoloader->add( 'Facebook\\', __DIR__ . '/vendor/facebook/facebook-instant-articles-sdk-php/src' );
34
+ $autoloader->add( 'Facebook\\', __DIR__ . '/vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src' );
35
 
36
  // Configures log to go through console.
37
  \Logger::configure(
68
 
69
  defined( 'ABSPATH' ) || die( 'Shame on you' );
70
 
71
+ define( 'IA_PLUGIN_VERSION', '4.0.0' );
72
  define( 'IA_PLUGIN_PATH_FULL', __FILE__ );
73
  define( 'IA_PLUGIN_PATH', plugin_basename( __FILE__ ) );
74
  define( 'IA_PLUGIN_FILE_BASENAME', pathinfo( __FILE__, PATHINFO_FILENAME ) );
75
  define( 'IA_PLUGIN_TEXT_DOMAIN', 'instant-articles' );
76
+ define( 'IA_PLUGIN_FORCE_SUBMIT_KEY', 'instant_articles_force_submit' );
77
 
78
  // Let users define their own feed slug.
79
  if ( ! defined( 'INSTANT_ARTICLES_SLUG' ) ) {
84
  require_once( dirname( __FILE__ ) . '/class-instant-articles-post.php' );
85
  require_once( dirname( __FILE__ ) . '/wizard/class-instant-articles-wizard.php' );
86
  require_once( dirname( __FILE__ ) . '/meta-box/class-instant-articles-meta-box.php' );
87
+ require_once( dirname( __FILE__ ) . '/class-instant-articles-amp-markup.php' );
88
 
89
  /**
90
  * Plugin activation hook to add our rewrite rules.
104
  add_action( 'network_admin_notices', 'instant_articles_setup_admin_notice' ); // also show message on multisite
105
  function instant_articles_setup_admin_notice() {
106
  global $pagenow;
107
+ if ( $pagenow === 'plugins.php' && ! Instant_Articles_Option_FB_Page::get_option_decoded()[ "page_id" ] ) {
108
  $settings_url = Instant_Articles_Wizard::get_url();
109
  echo '<div class="updated settings-error notice is-dismissible">';
110
  echo '<p>Congrats, you\'ve installed the Instant Articles for WP plugin. Now <a href="' . esc_url_raw($settings_url) . '">set it up</a> to start publishing Instant Articles.';
316
  IA_PLUGIN_VERSION,
317
  false
318
  );
 
 
 
 
 
 
 
319
  }
320
  add_action( 'init', 'instant_articles_register_scripts' );
321
 
349
  $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
350
  $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
351
 
352
+ if ( isset( $fb_page_settings[ 'page_id' ] ) ) {
353
  ?>
354
+ <meta property="fb:pages" content="<?php echo esc_attr( $fb_page_settings[ 'page_id' ] ); ?>" />
355
  <?php
356
  }
357
  }
358
  add_action( 'wp_head', 'inject_url_claiming_meta_tag' );
359
 
360
+ /**
361
+ * Automatically add meta tag for Instant Articles Open Publish scraper
362
+ *
363
+ * @since 4.0
364
+ */
365
+ function inject_ia_markup_meta_tag() {
366
+ $post = get_post();
367
+ // Transform the post to an Instant Article.
368
+ $adapter = new Instant_Articles_Post( $post );
369
+ if ( $adapter->should_submit_post() ) {
370
+ $url = $adapter->get_canonical_url();
371
+ $url = add_query_arg( 'ia_markup', '1', $url );
372
+ $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
373
+ $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
374
+ $dev_mode = isset( $publishing_settings['dev_mode'] )
375
+ ? ( $publishing_settings['dev_mode'] ? true : false )
376
+ : false;
377
+
378
+ if ( $dev_mode ) {
379
+ ?>
380
+ <meta property="ia:markup_url_dev" content="<?php echo esc_attr( $url ); ?>" />
381
+ <?php
382
+ } else {
383
+ ?>
384
+ <meta property="ia:markup_url" content="<?php echo esc_attr( $url ); ?>" />
385
+ <?php
386
+ }
387
+ }
388
+ }
389
+ add_action( 'wp_head', 'inject_ia_markup_meta_tag' );
390
+
391
+ // Injects the <link rel...> tag if the AMP Markup is enabled
392
+ add_action( 'wp_head', array('Instant_Articles_AMP_Markup', 'inject_link_rel') );
393
+
394
  // Initialize the Instant Articles meta box.
395
  Instant_Articles_Meta_Box::init();
396
 
397
+ function ia_markup_version( ) {
398
+ $post = get_post();
399
+
400
+ if (isset( $_GET[ 'ia_markup' ] ) && $_GET[ 'ia_markup' ]) {
401
+ // Transform the post to an Instant Article.
402
+ $adapter = new Instant_Articles_Post( $post );
403
+ $article = $adapter->to_instant_article();
404
+ echo $article->render( null, true );
405
+
406
+ die();
407
+ }
408
+ }
409
+ add_action( 'wp', 'ia_markup_version' );
410
+
411
+ // Add hook for generating the AMP markup
412
+ add_action( 'wp', array('Instant_Articles_AMP_Markup', 'markup_version') );
413
 
 
414
  Instant_Articles_Wizard::init();
415
+
416
+ function rescrape_article( $post_id, $post ) {
417
+ $adapter = new Instant_Articles_Post( $post );
418
+ $old_slugs = get_post_meta( $post_id, '_wp_old_slug' );
419
+ if ( $adapter->should_submit_post() ) {
420
+ try {
421
+ $client = Facebook\HttpClients\HttpClientsFactory::createHttpClient( null );
422
+ $url_encoded = urlencode($adapter->get_canonical_url());
423
+ $client->send(
424
+ "https://graph.facebook.com/?id=$url_encoded&scrape=true",
425
+ 'POST',
426
+ '',
427
+ array(),
428
+ 60
429
+ );
430
+ foreach ( $old_slugs as $slug ) {
431
+ $clone_post = clone $post;
432
+ $clone_post->post_name = $slug;
433
+ $clone_adapter = new Instant_Articles_Post( $clone_post );
434
+
435
+ $url_encoded = urlencode($clone_adapter->get_canonical_url());
436
+ $client->send(
437
+ "https://graph.facebook.com/?id=$url_encoded&scrape=true",
438
+ 'POST',
439
+ '',
440
+ array(),
441
+ 60
442
+ );
443
+ }
444
+ } catch ( Exception $e ) {
445
+ Logger::getLogger( 'instantarticles-wp-plugin' )->error(
446
+ 'Unable to submit article.',
447
+ $e->getTraceAsString()
448
+ );
449
+ }
450
+ }
451
+ }
452
+ add_action( 'save_post', 'rescrape_article', 999, 2 );
453
+
454
+
455
  }
meta-box/class-instant-articles-meta-box.php CHANGED
@@ -75,8 +75,7 @@ class Instant_Articles_Meta_Box {
75
 
76
  check_ajax_referer( 'instant-articles-force-submit-' . $post_id, 'security' );
77
  $force = sanitize_text_field( $_POST[ 'force' ] ) === 'true';
78
- update_post_meta( $post_id, Instant_Articles_Publisher::FORCE_SUBMIT_KEY, $force );
79
- Instant_Articles_Publisher::submit_article( $post_id, get_post( $post_id ) );
80
  }
81
 
82
  /**
@@ -94,53 +93,22 @@ class Instant_Articles_Meta_Box {
94
  $adapter = new Instant_Articles_Post( $post );
95
  $article = $adapter->to_instant_article();
96
  $canonical_url = $adapter->get_canonical_url();
97
- $submission_status = null;
98
- $published = 'publish' === $post->post_status;
99
  $dev_mode = false;
100
- $force_submit = get_post_meta( $post_id, Instant_Articles_Publisher::FORCE_SUBMIT_KEY, true );
101
- $should_submit_post = apply_filters( 'instant_articles_should_submit_post', true, $adapter );
102
 
103
  Instant_Articles_Wizard::menu_items();
104
  $settings_page_href = Instant_Articles_Wizard::get_url();
105
 
106
  $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
107
  $publish_with_warnings = $publishing_settings[ 'publish_with_warnings' ];
108
- if ( $published ) {
109
- try {
110
- $fb_app_settings = Instant_Articles_Option_FB_App::get_option_decoded();
111
- $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
112
- $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
113
-
114
- $dev_mode = isset( $publishing_settings['dev_mode'] )
115
- ? ( $publishing_settings['dev_mode'] ? true : false )
116
- : false;
117
-
118
- if ( isset( $fb_app_settings['app_id'] )
119
- && isset( $fb_app_settings['app_secret'] )
120
- && isset( $fb_page_settings['page_access_token'] )
121
- && isset( $fb_page_settings['page_id'] ) ) {
122
- // Instantiate a new Client to get the status of this article.
123
- $client = Client::create(
124
- $fb_app_settings['app_id'],
125
- $fb_app_settings['app_secret'],
126
- $fb_page_settings['page_access_token'],
127
- $fb_page_settings['page_id'],
128
- $dev_mode
129
- );
130
-
131
- $submission_status_id = get_post_meta( $post_id, Instant_Articles_Publisher::SUBMISSION_ID_KEY, true );
132
- if ( ! empty( $submission_status_id ) ) {
133
- $submission_status = $client->getSubmissionStatus( $submission_status_id );
134
- } else {
135
- // Grab the latest status of this article and display.
136
- $article_id = $client->getArticleIDFromCanonicalURL( $canonical_url );
137
- $submission_status = $client->getLastSubmissionStatus( $article_id );
138
- }
139
- }
140
- } catch ( FacebookResponseException $e ) {
141
- $submission_status = null;
142
- }
143
- }
144
 
145
  include( dirname( __FILE__ ) . '/meta-box-template.php' );
146
 
75
 
76
  check_ajax_referer( 'instant-articles-force-submit-' . $post_id, 'security' );
77
  $force = sanitize_text_field( $_POST[ 'force' ] ) === 'true';
78
+ update_post_meta( $post_id, IA_PLUGIN_FORCE_SUBMIT_KEY, $force );
 
79
  }
80
 
81
  /**
93
  $adapter = new Instant_Articles_Post( $post );
94
  $article = $adapter->to_instant_article();
95
  $canonical_url = $adapter->get_canonical_url();
96
+ $published = ( 'publish' === $post->post_status );
 
97
  $dev_mode = false;
98
+ $force_submit = get_post_meta( $post_id, IA_PLUGIN_FORCE_SUBMIT_KEY, true );
99
+ $instant_articles_should_submit_post_filter = apply_filters( 'instant_articles_should_submit_post', true, $adapter );
100
 
101
  Instant_Articles_Wizard::menu_items();
102
  $settings_page_href = Instant_Articles_Wizard::get_url();
103
 
104
  $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
105
  $publish_with_warnings = $publishing_settings[ 'publish_with_warnings' ];
106
+ $fb_page_settings = Instant_Articles_Option_FB_Page::get_option_decoded();
107
+ $publishing_settings = Instant_Articles_Option_Publishing::get_option_decoded();
108
+
109
+ $dev_mode = isset( $publishing_settings['dev_mode'] )
110
+ ? ( $publishing_settings['dev_mode'] ? true : false )
111
+ : false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  include( dirname( __FILE__ ) . '/meta-box-template.php' );
114
 
meta-box/meta-box-template.php CHANGED
@@ -18,135 +18,64 @@ use Facebook\InstantArticles\Client\ServerMessage;
18
  </a>
19
  <?php endif; ?>
20
 
21
- <?php if ( ! $should_submit_post ) : ?>
 
 
 
 
 
 
 
 
22
  <p>
23
  <b>
24
  <span class="dashicons dashicons-no-alt"></span>
25
  This post will not be submitted to Instant Articles due to a rule created in your site.
26
  </b>
27
  </p>
 
28
  <?php elseif ( ! $published ) : ?>
29
  <p>
30
  <b>
31
  <span class="dashicons dashicons-media-document"></span>
32
- Your post will be submitted to Instant Articles once it is published.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </b>
34
  </p>
35
-
36
- <?php elseif ( $submission_status ) : ?>
37
-
38
- <!-- Display the last submission status -->
39
- <?php switch ( $submission_status->getStatus() ) :
40
- case InstantArticleStatus::SUCCESS : ?>
41
- <p>
42
- <b>
43
- <span class="dashicons dashicons-yes"></span>
44
- Your article was submitted to Instant Articles successfully
45
- </b>
46
- </p>
47
- <?php break; ?>
48
-
49
- <?php case InstantArticleStatus::FAILED : ?>
50
- <p>
51
- <b>
52
- <span class="dashicons dashicons-no-alt"></span>
53
- It wasn't possible to submit your article
54
- </b>
55
- </p>
56
- <?php break; ?>
57
-
58
- <?php case InstantArticleStatus::IN_PROGRESS : ?>
59
- <p>
60
- <b>
61
- <span class="dashicons dashicons-update"></span>
62
- Your article is being submitted...
63
- </b>
64
- </p>
65
- <script>
66
- setTimeout(function () {
67
- instant_articles_load_meta_box( <?php echo absint( $post->ID ); ?> );
68
- }, 2000);
69
- </script>
70
-
71
- <?php break; ?>
72
-
73
- <?php default : ?>
74
- <p>
75
- <b>
76
- <span class="dashicons dashicons-no-alt"></span>
77
- This post was not yet submitted to Instant Articles.
78
- </b>
79
- </p>
80
- <?php break; ?>
81
-
82
- <?php endswitch; ?>
83
-
84
-
85
- <!-- Display the submission messages if any -->
86
- <?php if ( count( $submission_status->getMessages() ) > 0 ) : ?>
87
-
88
- <p>The server responded with the following messages:</p>
89
-
90
- <ul class="instant-articles-messages">
91
-
92
- <?php foreach ( $submission_status->getMessages() as $message ) : ?>
93
-
94
- <?php switch ( $message->getLevel() ) :
95
- case ServerMessage::WARNING : ?>
96
- <li class="wp-ui-text-highlight">
97
- <span class="dashicons dashicons-warning"></span>
98
- <div>
99
- <?php echo esc_html( $message->getMessage() ); ?>
100
- </div>
101
- </li>
102
- <?php break; ?>
103
-
104
- <?php case ServerMessage::ERROR : ?>
105
- <li class="wp-ui-text-notification">
106
- <span class="dashicons dashicons-dismiss"></span>
107
- <div>
108
- <?php echo esc_html( $message->getMessage() ); ?>
109
- </div>
110
- </li>
111
- <?php break; ?>
112
-
113
- <?php case ServerMessage::FATAL : ?>
114
- <li class="wp-ui-text-notification">
115
- <span class="dashicons dashicons-sos"></span>
116
- <div>
117
- <?php echo esc_html( $message->getMessage() ); ?>
118
- </div>
119
- </li>
120
- <?php break; ?>
121
-
122
- <?php default: ?>
123
- <li class="wp-ui-text-highlight">
124
- <span class="dashicons dashicons-info"></span>
125
- <div>
126
- <?php echo esc_html( $message->getMessage() ); ?>
127
- </div>
128
- </li>
129
-
130
- <?php endswitch; ?>
131
-
132
- <?php endforeach; ?>
133
- </ul>
134
-
135
- <?php endif; ?>
136
-
137
- <?php else : ?>
138
-
139
- <p>
140
- <b>
141
- <span class="dashicons dashicons-no-alt"></span>
142
- Could not connect to your page. Please check the
143
- <a href="<?php echo esc_url( $settings_page_href ); ?>">Instant Articles plugin settings</a>.
144
- </b>
145
- </p>
146
-
147
- <?php endif; ?>
148
-
149
  <hr>
 
 
 
 
 
 
 
 
 
150
 
151
  <!-- Transformer messages -->
152
  <?php if ( count( $adapter->transformer->getWarnings() ) > 0 ) : ?>
18
  </a>
19
  <?php endif; ?>
20
 
21
+ <?php if ( $adapter->should_submit_post() ) : ?>
22
+ <p>
23
+ <b>
24
+ <span class="dashicons dashicons-yes"></span>
25
+ This post will be available as an Instant Article.
26
+ </b>
27
+ </p>
28
+ <hr>
29
+ <?php elseif ( ! $instant_articles_should_submit_post_filter ) : ?>
30
  <p>
31
  <b>
32
  <span class="dashicons dashicons-no-alt"></span>
33
  This post will not be submitted to Instant Articles due to a rule created in your site.
34
  </b>
35
  </p>
36
+ <hr>
37
  <?php elseif ( ! $published ) : ?>
38
  <p>
39
  <b>
40
  <span class="dashicons dashicons-media-document"></span>
41
+ This post will be submitted to Instant Articles once it is published.
42
+ </b>
43
+ </p>
44
+ <hr>
45
+ <?php elseif ( ! $article->getHeader() || ! $article->getHeader()->getTitle() ) : ?>
46
+ <p>
47
+ <b>
48
+ <span class="dashicons dashicons-no-alt"></span>
49
+ This post will not be submitted to Instant Articles because it is missing a title.
50
+ </b>
51
+ </p>
52
+ <hr>
53
+ <?php elseif ( count( $article->getChildren() ) === 0 ) : ?>
54
+ <p>
55
+ <b>
56
+ <span class="dashicons dashicons-no-alt"></span>
57
+ This post will not be submitted to Instant Articles because it is missing content.
58
+ </b>
59
+ </p>
60
+ <hr>
61
+ <?php elseif ( ! $fb_page_settings[ "page_id" ] ) : ?>
62
+ <p>
63
+ <b>
64
+ <span class="dashicons dashicons-no-alt"></span>
65
+ No Facebook Page was selected. Please configure your page in the
66
+ <a href="<?php echo esc_url( $settings_page_href ); ?>">Instant Articles plugin settings</a>.
67
  </b>
68
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  <hr>
70
+ <?php elseif ( count( $adapter->transformer->getWarnings() ) > 0 ) : ?>
71
+ <p>
72
+ <b>
73
+ <span class="dashicons dashicons-no-alt"></span>
74
+ This post will not be submitted to Instant Articles because the transformation raised some warnings.
75
+ </b>
76
+ </p>
77
+ <hr>
78
+ <?php endif; ?>
79
 
80
  <!-- Transformer messages -->
81
  <?php if ( count( $adapter->transformer->getWarnings() ) > 0 ) : ?>
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: trrine, olethomas, bjornjohansen, dekode, automattic, facebook
3
  Tags: instant articles, facebook, mobile
4
  Requires at least: 4.3
5
  Tested up to: 4.6
6
- Stable tag: 3.3.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
3
  Tags: instant articles, facebook, mobile
4
  Requires at least: 4.3
5
  Tested up to: 4.6
6
+ Stable tag: 4.0.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
rules-configuration.json CHANGED
@@ -26,6 +26,9 @@
26
  }, {
27
  "class": "ParagraphRule",
28
  "selector": "p"
 
 
 
29
  }, {
30
  "class": "LineBreakRule",
31
  "selector": "br"
26
  }, {
27
  "class": "ParagraphRule",
28
  "selector": "p"
29
+ }, {
30
+ "class": "FooterSmallRule",
31
+ "selector": "small"
32
  }, {
33
  "class": "LineBreakRule",
34
  "selector": "br"
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit36fdde57bb31390b63c9fa4f374d8837::getLoader();
vendor/bin/phpcbf ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env php
2
+ <?php
3
+ /**
4
+ * PHP Code Beautifier and Fixer
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * @category PHP
9
+ * @package PHP_CodeSniffer
10
+ * @author Greg Sherwood <gsherwood@squiz.net>
11
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
+ * @link http://pear.php.net/package/PHP_CodeSniffer
14
+ */
15
+
16
+ if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) {
17
+ include_once dirname(__FILE__).'/../CodeSniffer/CLI.php';
18
+ } else {
19
+ include_once 'PHP/CodeSniffer/CLI.php';
20
+ }
21
+
22
+ $cli = new PHP_CodeSniffer_CLI();
23
+ $cli->runphpcbf();
vendor/bin/phpcs ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env php
2
+ <?php
3
+ /**
4
+ * PHP_CodeSniffer tokenizes PHP code and detects violations of a
5
+ * defined set of coding standards.
6
+ *
7
+ * PHP version 5
8
+ *
9
+ * @category PHP
10
+ * @package PHP_CodeSniffer
11
+ * @author Greg Sherwood <gsherwood@squiz.net>
12
+ * @author Marc McIntyre <mmcintyre@squiz.net>
13
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
14
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
15
+ * @link http://pear.php.net/package/PHP_CodeSniffer
16
+ */
17
+
18
+ if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) {
19
+ include_once dirname(__FILE__).'/../CodeSniffer/CLI.php';
20
+ } else {
21
+ include_once 'PHP/CodeSniffer/CLI.php';
22
+ }
23
+
24
+ $cli = new PHP_CodeSniffer_CLI();
25
+ $cli->runphpcs();
vendor/composer/autoload_classmap.php CHANGED
@@ -6,6 +6,68 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  'Logger' => $vendorDir . '/apache/log4php/src/main/php/Logger.php',
10
  'LoggerAppender' => $vendorDir . '/apache/log4php/src/main/php/LoggerAppender.php',
11
  'LoggerAppenderConsole' => $vendorDir . '/apache/log4php/src/main/php/appenders/LoggerAppenderConsole.php',
@@ -85,4 +147,194 @@ return array(
85
  'LoggerRoot' => $vendorDir . '/apache/log4php/src/main/php/LoggerRoot.php',
86
  'LoggerThrowableInformation' => $vendorDir . '/apache/log4php/src/main/php/LoggerThrowableInformation.php',
87
  'LoggerUtils' => $vendorDir . '/apache/log4php/src/main/php/helpers/LoggerUtils.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'Generic_Sniffs_Arrays_DisallowLongArraySyntaxSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php',
10
+ 'Generic_Sniffs_Arrays_DisallowShortArraySyntaxSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Arrays/DisallowShortArraySyntaxSniff.php',
11
+ 'Generic_Sniffs_Classes_DuplicateClassNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php',
12
+ 'Generic_Sniffs_Classes_OpeningBraceSameLineSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/OpeningBraceSameLineSniff.php',
13
+ 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php',
14
+ 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php',
15
+ 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php',
16
+ 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php',
17
+ 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php',
18
+ 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php',
19
+ 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php',
20
+ 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php',
21
+ 'Generic_Sniffs_Commenting_DocCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/DocCommentSniff.php',
22
+ 'Generic_Sniffs_Commenting_FixmeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php',
23
+ 'Generic_Sniffs_Commenting_TodoSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php',
24
+ 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php',
25
+ 'Generic_Sniffs_Debug_CSSLintSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php',
26
+ 'Generic_Sniffs_Debug_ClosureLinterSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php',
27
+ 'Generic_Sniffs_Debug_ESLintSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ESLintSniff.php',
28
+ 'Generic_Sniffs_Debug_JSHintSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php',
29
+ 'Generic_Sniffs_Files_ByteOrderMarkSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php',
30
+ 'Generic_Sniffs_Files_EndFileNewlineSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php',
31
+ 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php',
32
+ 'Generic_Sniffs_Files_InlineHTMLSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php',
33
+ 'Generic_Sniffs_Files_LineEndingsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php',
34
+ 'Generic_Sniffs_Files_LineLengthSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php',
35
+ 'Generic_Sniffs_Files_LowercasedFilenameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php',
36
+ 'Generic_Sniffs_Files_OneClassPerFileSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php',
37
+ 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php',
38
+ 'Generic_Sniffs_Files_OneTraitPerFileSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneTraitPerFileSniff.php',
39
+ 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php',
40
+ 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php',
41
+ 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php',
42
+ 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php',
43
+ 'Generic_Sniffs_Formatting_SpaceAfterNotSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterNotSniff.php',
44
+ 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php',
45
+ 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php',
46
+ 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php',
47
+ 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php',
48
+ 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php',
49
+ 'Generic_Sniffs_Metrics_NestingLevelSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php',
50
+ 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php',
51
+ 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php',
52
+ 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php',
53
+ 'Generic_Sniffs_PHP_BacktickOperatorSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/BacktickOperatorSniff.php',
54
+ 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php',
55
+ 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php',
56
+ 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php',
57
+ 'Generic_Sniffs_PHP_DisallowAlternativePHPTagsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php',
58
+ 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php',
59
+ 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php',
60
+ 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php',
61
+ 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php',
62
+ 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php',
63
+ 'Generic_Sniffs_PHP_SAPIUsageSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php',
64
+ 'Generic_Sniffs_PHP_SyntaxSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SyntaxSniff.php',
65
+ 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php',
66
+ 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php',
67
+ 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php',
68
+ 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php',
69
+ 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php',
70
+ 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php',
71
  'Logger' => $vendorDir . '/apache/log4php/src/main/php/Logger.php',
72
  'LoggerAppender' => $vendorDir . '/apache/log4php/src/main/php/LoggerAppender.php',
73
  'LoggerAppenderConsole' => $vendorDir . '/apache/log4php/src/main/php/appenders/LoggerAppenderConsole.php',
147
  'LoggerRoot' => $vendorDir . '/apache/log4php/src/main/php/LoggerRoot.php',
148
  'LoggerThrowableInformation' => $vendorDir . '/apache/log4php/src/main/php/LoggerThrowableInformation.php',
149
  'LoggerUtils' => $vendorDir . '/apache/log4php/src/main/php/helpers/LoggerUtils.php',
150
+ 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php',
151
+ 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php',
152
+ 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php',
153
+ 'MySource_Sniffs_Channels_IncludeSystemSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php',
154
+ 'MySource_Sniffs_Channels_UnusedSystemSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php',
155
+ 'MySource_Sniffs_Commenting_FunctionCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php',
156
+ 'MySource_Sniffs_Debug_DebugCodeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php',
157
+ 'MySource_Sniffs_Debug_FirebugConsoleSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php',
158
+ 'MySource_Sniffs_Objects_AssignThisSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php',
159
+ 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php',
160
+ 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php',
161
+ 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php',
162
+ 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php',
163
+ 'MySource_Sniffs_PHP_GetRequestDataSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php',
164
+ 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php',
165
+ 'MySource_Sniffs_Strings_JoinStringsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php',
166
+ 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php',
167
+ 'PEAR_Sniffs_Commenting_ClassCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php',
168
+ 'PEAR_Sniffs_Commenting_FileCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php',
169
+ 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php',
170
+ 'PEAR_Sniffs_Commenting_InlineCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php',
171
+ 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php',
172
+ 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php',
173
+ 'PEAR_Sniffs_Files_IncludingFileSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php',
174
+ 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php',
175
+ 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php',
176
+ 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php',
177
+ 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php',
178
+ 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php',
179
+ 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php',
180
+ 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php',
181
+ 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php',
182
+ 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php',
183
+ 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php',
184
+ 'PHP_CodeSniffer' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer.php',
185
+ 'PHP_CodeSniffer_CLI' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/CLI.php',
186
+ 'PHP_CodeSniffer_DocGenerators_Generator' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Generator.php',
187
+ 'PHP_CodeSniffer_DocGenerators_HTML' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/HTML.php',
188
+ 'PHP_CodeSniffer_DocGenerators_Markdown' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Markdown.php',
189
+ 'PHP_CodeSniffer_DocGenerators_Text' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Text.php',
190
+ 'PHP_CodeSniffer_Exception' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Exception.php',
191
+ 'PHP_CodeSniffer_File' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/File.php',
192
+ 'PHP_CodeSniffer_Fixer' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Fixer.php',
193
+ 'PHP_CodeSniffer_Report' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Report.php',
194
+ 'PHP_CodeSniffer_Reporting' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reporting.php',
195
+ 'PHP_CodeSniffer_Reports_Cbf' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Cbf.php',
196
+ 'PHP_CodeSniffer_Reports_Checkstyle' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Checkstyle.php',
197
+ 'PHP_CodeSniffer_Reports_Csv' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Csv.php',
198
+ 'PHP_CodeSniffer_Reports_Diff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Diff.php',
199
+ 'PHP_CodeSniffer_Reports_Emacs' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Emacs.php',
200
+ 'PHP_CodeSniffer_Reports_Full' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Full.php',
201
+ 'PHP_CodeSniffer_Reports_Gitblame' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Gitblame.php',
202
+ 'PHP_CodeSniffer_Reports_Hgblame' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Hgblame.php',
203
+ 'PHP_CodeSniffer_Reports_Info' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Info.php',
204
+ 'PHP_CodeSniffer_Reports_Json' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Json.php',
205
+ 'PHP_CodeSniffer_Reports_Junit' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Junit.php',
206
+ 'PHP_CodeSniffer_Reports_Notifysend' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Notifysend.php',
207
+ 'PHP_CodeSniffer_Reports_Source' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Source.php',
208
+ 'PHP_CodeSniffer_Reports_Summary' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Summary.php',
209
+ 'PHP_CodeSniffer_Reports_Svnblame' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Svnblame.php',
210
+ 'PHP_CodeSniffer_Reports_VersionControl' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/VersionControl.php',
211
+ 'PHP_CodeSniffer_Reports_Xml' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Xml.php',
212
+ 'PHP_CodeSniffer_Sniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Sniff.php',
213
+ 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php',
214
+ 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php',
215
+ 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php',
216
+ 'PHP_CodeSniffer_Standards_IncorrectPatternException' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/IncorrectPatternException.php',
217
+ 'PHP_CodeSniffer_Tokenizers_CSS' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/CSS.php',
218
+ 'PHP_CodeSniffer_Tokenizers_Comment' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/Comment.php',
219
+ 'PHP_CodeSniffer_Tokenizers_JS' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/JS.php',
220
+ 'PHP_CodeSniffer_Tokenizers_PHP' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/PHP.php',
221
+ 'PHP_CodeSniffer_Tokens' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Tokens.php',
222
+ 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php',
223
+ 'PSR1_Sniffs_Files_SideEffectsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php',
224
+ 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php',
225
+ 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php',
226
+ 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php',
227
+ 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php',
228
+ 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php',
229
+ 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php',
230
+ 'PSR2_Sniffs_Files_ClosingTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/ClosingTagSniff.php',
231
+ 'PSR2_Sniffs_Files_EndFileNewlineSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php',
232
+ 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php',
233
+ 'PSR2_Sniffs_Methods_FunctionClosingBraceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionClosingBraceSniff.php',
234
+ 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php',
235
+ 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php',
236
+ 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php',
237
+ 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php',
238
+ 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php',
239
+ 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php',
240
+ 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php',
241
+ 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php',
242
+ 'Squiz_Sniffs_CSS_ColonSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php',
243
+ 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php',
244
+ 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php',
245
+ 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php',
246
+ 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php',
247
+ 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php',
248
+ 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php',
249
+ 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php',
250
+ 'Squiz_Sniffs_CSS_IndentationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php',
251
+ 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php',
252
+ 'Squiz_Sniffs_CSS_MissingColonSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php',
253
+ 'Squiz_Sniffs_CSS_NamedColoursSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php',
254
+ 'Squiz_Sniffs_CSS_OpacitySniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php',
255
+ 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php',
256
+ 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php',
257
+ 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php',
258
+ 'Squiz_Sniffs_Classes_ClassFileNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php',
259
+ 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php',
260
+ 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php',
261
+ 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php',
262
+ 'Squiz_Sniffs_Classes_ValidClassNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php',
263
+ 'Squiz_Sniffs_Commenting_BlockCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php',
264
+ 'Squiz_Sniffs_Commenting_ClassCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php',
265
+ 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php',
266
+ 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php',
267
+ 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php',
268
+ 'Squiz_Sniffs_Commenting_FileCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php',
269
+ 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php',
270
+ 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php',
271
+ 'Squiz_Sniffs_Commenting_InlineCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php',
272
+ 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php',
273
+ 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php',
274
+ 'Squiz_Sniffs_Commenting_VariableCommentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php',
275
+ 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php',
276
+ 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php',
277
+ 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php',
278
+ 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php',
279
+ 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php',
280
+ 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php',
281
+ 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php',
282
+ 'Squiz_Sniffs_Debug_JSLintSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php',
283
+ 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php',
284
+ 'Squiz_Sniffs_Files_FileExtensionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php',
285
+ 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php',
286
+ 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php',
287
+ 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php',
288
+ 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php',
289
+ 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php',
290
+ 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php',
291
+ 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php',
292
+ 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php',
293
+ 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php',
294
+ 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php',
295
+ 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php',
296
+ 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php',
297
+ 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php',
298
+ 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php',
299
+ 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php',
300
+ 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php',
301
+ 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php',
302
+ 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php',
303
+ 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php',
304
+ 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php',
305
+ 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php',
306
+ 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php',
307
+ 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php',
308
+ 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php',
309
+ 'Squiz_Sniffs_PHP_EvalSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php',
310
+ 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php',
311
+ 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php',
312
+ 'Squiz_Sniffs_PHP_HeredocSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php',
313
+ 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php',
314
+ 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php',
315
+ 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php',
316
+ 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php',
317
+ 'Squiz_Sniffs_Scope_MethodScopeSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php',
318
+ 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php',
319
+ 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php',
320
+ 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php',
321
+ 'Squiz_Sniffs_Strings_EchoedStringsSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php',
322
+ 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php',
323
+ 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php',
324
+ 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php',
325
+ 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php',
326
+ 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php',
327
+ 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php',
328
+ 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php',
329
+ 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php',
330
+ 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php',
331
+ 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php',
332
+ 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php',
333
+ 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php',
334
+ 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php',
335
+ 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php',
336
+ 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php',
337
+ 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php',
338
+ 'Zend_Sniffs_Files_ClosingTagSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php',
339
+ 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => $vendorDir . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php',
340
  );
vendor/composer/autoload_psr4.php CHANGED
@@ -7,6 +7,6 @@ $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
  'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
10
- 'Facebook\\InstantArticles\\' => array($vendorDir . '/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles'),
11
  'Facebook\\' => array($vendorDir . '/facebook/graph-sdk/src/Facebook'),
12
  );
7
 
8
  return array(
9
  'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
10
+ 'Facebook\\InstantArticles\\' => array($vendorDir . '/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles', $vendorDir . '/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles'),
11
  'Facebook\\' => array($vendorDir . '/facebook/graph-sdk/src/Facebook'),
12
  );
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInitfa8bfc5d2717dd9298c7d3347cfeea3b
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequirefa8bfc5d2717dd9298c7d3347cfeea3b($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequirefa8bfc5d2717dd9298c7d3347cfeea3b($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit36fdde57bb31390b63c9fa4f374d8837
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit36fdde57bb31390b63c9fa4f374d8837', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit36fdde57bb31390b63c9fa4f374d8837', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire36fdde57bb31390b63c9fa4f374d8837($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire36fdde57bb31390b63c9fa4f374d8837($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b
8
  {
9
  public static $files = array (
10
  'c65d09b6820da036953a371c8c73a9b1' => __DIR__ . '/..' . '/facebook/graph-sdk/src/Facebook/polyfills.php',
@@ -30,6 +30,7 @@ class ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b
30
  'Facebook\\InstantArticles\\' =>
31
  array (
32
  0 => __DIR__ . '/..' . '/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles',
 
33
  ),
34
  'Facebook\\' =>
35
  array (
@@ -38,6 +39,68 @@ class ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b
38
  );
39
 
40
  public static $classMap = array (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  'Logger' => __DIR__ . '/..' . '/apache/log4php/src/main/php/Logger.php',
42
  'LoggerAppender' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerAppender.php',
43
  'LoggerAppenderConsole' => __DIR__ . '/..' . '/apache/log4php/src/main/php/appenders/LoggerAppenderConsole.php',
@@ -117,14 +180,204 @@ class ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b
117
  'LoggerRoot' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerRoot.php',
118
  'LoggerThrowableInformation' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerThrowableInformation.php',
119
  'LoggerUtils' => __DIR__ . '/..' . '/apache/log4php/src/main/php/helpers/LoggerUtils.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  );
121
 
122
  public static function getInitializer(ClassLoader $loader)
123
  {
124
  return \Closure::bind(function () use ($loader) {
125
- $loader->prefixLengthsPsr4 = ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b::$prefixLengthsPsr4;
126
- $loader->prefixDirsPsr4 = ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b::$prefixDirsPsr4;
127
- $loader->classMap = ComposerStaticInitfa8bfc5d2717dd9298c7d3347cfeea3b::$classMap;
128
 
129
  }, null, ClassLoader::class);
130
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837
8
  {
9
  public static $files = array (
10
  'c65d09b6820da036953a371c8c73a9b1' => __DIR__ . '/..' . '/facebook/graph-sdk/src/Facebook/polyfills.php',
30
  'Facebook\\InstantArticles\\' =>
31
  array (
32
  0 => __DIR__ . '/..' . '/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles',
33
+ 1 => __DIR__ . '/..' . '/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles',
34
  ),
35
  'Facebook\\' =>
36
  array (
39
  );
40
 
41
  public static $classMap = array (
42
+ 'Generic_Sniffs_Arrays_DisallowLongArraySyntaxSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php',
43
+ 'Generic_Sniffs_Arrays_DisallowShortArraySyntaxSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Arrays/DisallowShortArraySyntaxSniff.php',
44
+ 'Generic_Sniffs_Classes_DuplicateClassNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php',
45
+ 'Generic_Sniffs_Classes_OpeningBraceSameLineSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Classes/OpeningBraceSameLineSniff.php',
46
+ 'Generic_Sniffs_CodeAnalysis_EmptyStatementSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/EmptyStatementSniff.php',
47
+ 'Generic_Sniffs_CodeAnalysis_ForLoopShouldBeWhileLoopSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopShouldBeWhileLoopSniff.php',
48
+ 'Generic_Sniffs_CodeAnalysis_ForLoopWithTestFunctionCallSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/ForLoopWithTestFunctionCallSniff.php',
49
+ 'Generic_Sniffs_CodeAnalysis_JumbledIncrementerSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php',
50
+ 'Generic_Sniffs_CodeAnalysis_UnconditionalIfStatementSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnconditionalIfStatementSniff.php',
51
+ 'Generic_Sniffs_CodeAnalysis_UnnecessaryFinalModifierSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnnecessaryFinalModifierSniff.php',
52
+ 'Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UnusedFunctionParameterSniff.php',
53
+ 'Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php',
54
+ 'Generic_Sniffs_Commenting_DocCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/DocCommentSniff.php',
55
+ 'Generic_Sniffs_Commenting_FixmeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/FixmeSniff.php',
56
+ 'Generic_Sniffs_Commenting_TodoSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Commenting/TodoSniff.php',
57
+ 'Generic_Sniffs_ControlStructures_InlineControlStructureSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php',
58
+ 'Generic_Sniffs_Debug_CSSLintSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/CSSLintSniff.php',
59
+ 'Generic_Sniffs_Debug_ClosureLinterSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php',
60
+ 'Generic_Sniffs_Debug_ESLintSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/ESLintSniff.php',
61
+ 'Generic_Sniffs_Debug_JSHintSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Debug/JSHintSniff.php',
62
+ 'Generic_Sniffs_Files_ByteOrderMarkSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php',
63
+ 'Generic_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php',
64
+ 'Generic_Sniffs_Files_EndFileNoNewlineSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php',
65
+ 'Generic_Sniffs_Files_InlineHTMLSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php',
66
+ 'Generic_Sniffs_Files_LineEndingsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineEndingsSniff.php',
67
+ 'Generic_Sniffs_Files_LineLengthSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LineLengthSniff.php',
68
+ 'Generic_Sniffs_Files_LowercasedFilenameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php',
69
+ 'Generic_Sniffs_Files_OneClassPerFileSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneClassPerFileSniff.php',
70
+ 'Generic_Sniffs_Files_OneInterfacePerFileSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneInterfacePerFileSniff.php',
71
+ 'Generic_Sniffs_Files_OneTraitPerFileSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Files/OneTraitPerFileSniff.php',
72
+ 'Generic_Sniffs_Formatting_DisallowMultipleStatementsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/DisallowMultipleStatementsSniff.php',
73
+ 'Generic_Sniffs_Formatting_MultipleStatementAlignmentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php',
74
+ 'Generic_Sniffs_Formatting_NoSpaceAfterCastSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php',
75
+ 'Generic_Sniffs_Formatting_SpaceAfterCastSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterCastSniff.php',
76
+ 'Generic_Sniffs_Formatting_SpaceAfterNotSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Formatting/SpaceAfterNotSniff.php',
77
+ 'Generic_Sniffs_Functions_CallTimePassByReferenceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php',
78
+ 'Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php',
79
+ 'Generic_Sniffs_Functions_OpeningFunctionBraceBsdAllmanSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php',
80
+ 'Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php',
81
+ 'Generic_Sniffs_Metrics_CyclomaticComplexitySniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php',
82
+ 'Generic_Sniffs_Metrics_NestingLevelSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php',
83
+ 'Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php',
84
+ 'Generic_Sniffs_NamingConventions_ConstructorNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php',
85
+ 'Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php',
86
+ 'Generic_Sniffs_PHP_BacktickOperatorSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/BacktickOperatorSniff.php',
87
+ 'Generic_Sniffs_PHP_CharacterBeforePHPOpeningTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php',
88
+ 'Generic_Sniffs_PHP_ClosingPHPTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ClosingPHPTagSniff.php',
89
+ 'Generic_Sniffs_PHP_DeprecatedFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php',
90
+ 'Generic_Sniffs_PHP_DisallowAlternativePHPTagsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php',
91
+ 'Generic_Sniffs_PHP_DisallowShortOpenTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php',
92
+ 'Generic_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php',
93
+ 'Generic_Sniffs_PHP_LowerCaseConstantSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php',
94
+ 'Generic_Sniffs_PHP_LowerCaseKeywordSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php',
95
+ 'Generic_Sniffs_PHP_NoSilencedErrorsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/NoSilencedErrorsSniff.php',
96
+ 'Generic_Sniffs_PHP_SAPIUsageSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php',
97
+ 'Generic_Sniffs_PHP_SyntaxSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/SyntaxSniff.php',
98
+ 'Generic_Sniffs_PHP_UpperCaseConstantSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/PHP/UpperCaseConstantSniff.php',
99
+ 'Generic_Sniffs_Strings_UnnecessaryStringConcatSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php',
100
+ 'Generic_Sniffs_VersionControl_SubversionPropertiesSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php',
101
+ 'Generic_Sniffs_WhiteSpace_DisallowSpaceIndentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php',
102
+ 'Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php',
103
+ 'Generic_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php',
104
  'Logger' => __DIR__ . '/..' . '/apache/log4php/src/main/php/Logger.php',
105
  'LoggerAppender' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerAppender.php',
106
  'LoggerAppenderConsole' => __DIR__ . '/..' . '/apache/log4php/src/main/php/appenders/LoggerAppenderConsole.php',
180
  'LoggerRoot' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerRoot.php',
181
  'LoggerThrowableInformation' => __DIR__ . '/..' . '/apache/log4php/src/main/php/LoggerThrowableInformation.php',
182
  'LoggerUtils' => __DIR__ . '/..' . '/apache/log4php/src/main/php/helpers/LoggerUtils.php',
183
+ 'MySource_Sniffs_CSS_BrowserSpecificStylesSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php',
184
+ 'MySource_Sniffs_Channels_DisallowSelfActionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php',
185
+ 'MySource_Sniffs_Channels_IncludeOwnSystemSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php',
186
+ 'MySource_Sniffs_Channels_IncludeSystemSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php',
187
+ 'MySource_Sniffs_Channels_UnusedSystemSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php',
188
+ 'MySource_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php',
189
+ 'MySource_Sniffs_Debug_DebugCodeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php',
190
+ 'MySource_Sniffs_Debug_FirebugConsoleSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php',
191
+ 'MySource_Sniffs_Objects_AssignThisSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/AssignThisSniff.php',
192
+ 'MySource_Sniffs_Objects_CreateWidgetTypeCallbackSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php',
193
+ 'MySource_Sniffs_Objects_DisallowNewWidgetSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php',
194
+ 'MySource_Sniffs_PHP_AjaxNullComparisonSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php',
195
+ 'MySource_Sniffs_PHP_EvalObjectFactorySniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php',
196
+ 'MySource_Sniffs_PHP_GetRequestDataSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php',
197
+ 'MySource_Sniffs_PHP_ReturnFunctionValueSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php',
198
+ 'MySource_Sniffs_Strings_JoinStringsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php',
199
+ 'PEAR_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Classes/ClassDeclarationSniff.php',
200
+ 'PEAR_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/ClassCommentSniff.php',
201
+ 'PEAR_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FileCommentSniff.php',
202
+ 'PEAR_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php',
203
+ 'PEAR_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Commenting/InlineCommentSniff.php',
204
+ 'PEAR_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/ControlSignatureSniff.php',
205
+ 'PEAR_Sniffs_ControlStructures_MultiLineConditionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/ControlStructures/MultiLineConditionSniff.php',
206
+ 'PEAR_Sniffs_Files_IncludingFileSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Files/IncludingFileSniff.php',
207
+ 'PEAR_Sniffs_Formatting_MultiLineAssignmentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Formatting/MultiLineAssignmentSniff.php',
208
+ 'PEAR_Sniffs_Functions_FunctionCallSignatureSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionCallSignatureSniff.php',
209
+ 'PEAR_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php',
210
+ 'PEAR_Sniffs_Functions_ValidDefaultValueSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/Functions/ValidDefaultValueSniff.php',
211
+ 'PEAR_Sniffs_NamingConventions_ValidClassNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidClassNameSniff.php',
212
+ 'PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidFunctionNameSniff.php',
213
+ 'PEAR_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php',
214
+ 'PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ObjectOperatorIndentSniff.php',
215
+ 'PEAR_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php',
216
+ 'PEAR_Sniffs_WhiteSpace_ScopeIndentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PEAR/Sniffs/WhiteSpace/ScopeIndentSniff.php',
217
+ 'PHP_CodeSniffer' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer.php',
218
+ 'PHP_CodeSniffer_CLI' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/CLI.php',
219
+ 'PHP_CodeSniffer_DocGenerators_Generator' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Generator.php',
220
+ 'PHP_CodeSniffer_DocGenerators_HTML' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/HTML.php',
221
+ 'PHP_CodeSniffer_DocGenerators_Markdown' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Markdown.php',
222
+ 'PHP_CodeSniffer_DocGenerators_Text' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Text.php',
223
+ 'PHP_CodeSniffer_Exception' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Exception.php',
224
+ 'PHP_CodeSniffer_File' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/File.php',
225
+ 'PHP_CodeSniffer_Fixer' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Fixer.php',
226
+ 'PHP_CodeSniffer_Report' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Report.php',
227
+ 'PHP_CodeSniffer_Reporting' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reporting.php',
228
+ 'PHP_CodeSniffer_Reports_Cbf' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Cbf.php',
229
+ 'PHP_CodeSniffer_Reports_Checkstyle' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Checkstyle.php',
230
+ 'PHP_CodeSniffer_Reports_Csv' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Csv.php',
231
+ 'PHP_CodeSniffer_Reports_Diff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Diff.php',
232
+ 'PHP_CodeSniffer_Reports_Emacs' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Emacs.php',
233
+ 'PHP_CodeSniffer_Reports_Full' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Full.php',
234
+ 'PHP_CodeSniffer_Reports_Gitblame' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Gitblame.php',
235
+ 'PHP_CodeSniffer_Reports_Hgblame' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Hgblame.php',
236
+ 'PHP_CodeSniffer_Reports_Info' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Info.php',
237
+ 'PHP_CodeSniffer_Reports_Json' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Json.php',
238
+ 'PHP_CodeSniffer_Reports_Junit' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Junit.php',
239
+ 'PHP_CodeSniffer_Reports_Notifysend' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Notifysend.php',
240
+ 'PHP_CodeSniffer_Reports_Source' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Source.php',
241
+ 'PHP_CodeSniffer_Reports_Summary' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Summary.php',
242
+ 'PHP_CodeSniffer_Reports_Svnblame' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Svnblame.php',
243
+ 'PHP_CodeSniffer_Reports_VersionControl' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/VersionControl.php',
244
+ 'PHP_CodeSniffer_Reports_Xml' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Reports/Xml.php',
245
+ 'PHP_CodeSniffer_Sniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Sniff.php',
246
+ 'PHP_CodeSniffer_Standards_AbstractPatternSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractPatternSniff.php',
247
+ 'PHP_CodeSniffer_Standards_AbstractScopeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractScopeSniff.php',
248
+ 'PHP_CodeSniffer_Standards_AbstractVariableSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/AbstractVariableSniff.php',
249
+ 'PHP_CodeSniffer_Standards_IncorrectPatternException' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/IncorrectPatternException.php',
250
+ 'PHP_CodeSniffer_Tokenizers_CSS' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/CSS.php',
251
+ 'PHP_CodeSniffer_Tokenizers_Comment' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/Comment.php',
252
+ 'PHP_CodeSniffer_Tokenizers_JS' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/JS.php',
253
+ 'PHP_CodeSniffer_Tokenizers_PHP' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Tokenizers/PHP.php',
254
+ 'PHP_CodeSniffer_Tokens' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Tokens.php',
255
+ 'PSR1_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Classes/ClassDeclarationSniff.php',
256
+ 'PSR1_Sniffs_Files_SideEffectsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Files/SideEffectsSniff.php',
257
+ 'PSR1_Sniffs_Methods_CamelCapsMethodNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php',
258
+ 'PSR2_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php',
259
+ 'PSR2_Sniffs_Classes_PropertyDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php',
260
+ 'PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ControlStructureSpacingSniff.php',
261
+ 'PSR2_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/ElseIfDeclarationSniff.php',
262
+ 'PSR2_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php',
263
+ 'PSR2_Sniffs_Files_ClosingTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/ClosingTagSniff.php',
264
+ 'PSR2_Sniffs_Files_EndFileNewlineSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php',
265
+ 'PSR2_Sniffs_Methods_FunctionCallSignatureSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionCallSignatureSniff.php',
266
+ 'PSR2_Sniffs_Methods_FunctionClosingBraceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/FunctionClosingBraceSniff.php',
267
+ 'PSR2_Sniffs_Methods_MethodDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Methods/MethodDeclarationSniff.php',
268
+ 'PSR2_Sniffs_Namespaces_NamespaceDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/NamespaceDeclarationSniff.php',
269
+ 'PSR2_Sniffs_Namespaces_UseDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php',
270
+ 'Squiz_Sniffs_Arrays_ArrayBracketSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayBracketSpacingSniff.php',
271
+ 'Squiz_Sniffs_Arrays_ArrayDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php',
272
+ 'Squiz_Sniffs_CSS_ClassDefinitionClosingBraceSpaceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php',
273
+ 'Squiz_Sniffs_CSS_ClassDefinitionNameSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php',
274
+ 'Squiz_Sniffs_CSS_ClassDefinitionOpeningBraceSpaceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php',
275
+ 'Squiz_Sniffs_CSS_ColonSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php',
276
+ 'Squiz_Sniffs_CSS_ColourDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php',
277
+ 'Squiz_Sniffs_CSS_DisallowMultipleStyleDefinitionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php',
278
+ 'Squiz_Sniffs_CSS_DuplicateClassDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php',
279
+ 'Squiz_Sniffs_CSS_DuplicateStyleDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php',
280
+ 'Squiz_Sniffs_CSS_EmptyClassDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php',
281
+ 'Squiz_Sniffs_CSS_EmptyStyleDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php',
282
+ 'Squiz_Sniffs_CSS_ForbiddenStylesSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php',
283
+ 'Squiz_Sniffs_CSS_IndentationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/IndentationSniff.php',
284
+ 'Squiz_Sniffs_CSS_LowercaseStyleDefinitionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php',
285
+ 'Squiz_Sniffs_CSS_MissingColonSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php',
286
+ 'Squiz_Sniffs_CSS_NamedColoursSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php',
287
+ 'Squiz_Sniffs_CSS_OpacitySniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/OpacitySniff.php',
288
+ 'Squiz_Sniffs_CSS_SemicolonSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php',
289
+ 'Squiz_Sniffs_CSS_ShorthandSizeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php',
290
+ 'Squiz_Sniffs_Classes_ClassDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php',
291
+ 'Squiz_Sniffs_Classes_ClassFileNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php',
292
+ 'Squiz_Sniffs_Classes_DuplicatePropertySniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php',
293
+ 'Squiz_Sniffs_Classes_LowercaseClassKeywordsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/LowercaseClassKeywordsSniff.php',
294
+ 'Squiz_Sniffs_Classes_SelfMemberReferenceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php',
295
+ 'Squiz_Sniffs_Classes_ValidClassNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php',
296
+ 'Squiz_Sniffs_Commenting_BlockCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php',
297
+ 'Squiz_Sniffs_Commenting_ClassCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClassCommentSniff.php',
298
+ 'Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php',
299
+ 'Squiz_Sniffs_Commenting_DocCommentAlignmentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php',
300
+ 'Squiz_Sniffs_Commenting_EmptyCatchCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/EmptyCatchCommentSniff.php',
301
+ 'Squiz_Sniffs_Commenting_FileCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php',
302
+ 'Squiz_Sniffs_Commenting_FunctionCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php',
303
+ 'Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php',
304
+ 'Squiz_Sniffs_Commenting_InlineCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/InlineCommentSniff.php',
305
+ 'Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php',
306
+ 'Squiz_Sniffs_Commenting_PostStatementCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php',
307
+ 'Squiz_Sniffs_Commenting_VariableCommentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php',
308
+ 'Squiz_Sniffs_ControlStructures_ControlSignatureSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ControlSignatureSniff.php',
309
+ 'Squiz_Sniffs_ControlStructures_ElseIfDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ElseIfDeclarationSniff.php',
310
+ 'Squiz_Sniffs_ControlStructures_ForEachLoopDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php',
311
+ 'Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php',
312
+ 'Squiz_Sniffs_ControlStructures_InlineIfDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/InlineIfDeclarationSniff.php',
313
+ 'Squiz_Sniffs_ControlStructures_LowercaseDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/LowercaseDeclarationSniff.php',
314
+ 'Squiz_Sniffs_ControlStructures_SwitchDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php',
315
+ 'Squiz_Sniffs_Debug_JSLintSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JSLintSniff.php',
316
+ 'Squiz_Sniffs_Debug_JavaScriptLintSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php',
317
+ 'Squiz_Sniffs_Files_FileExtensionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php',
318
+ 'Squiz_Sniffs_Formatting_OperatorBracketSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php',
319
+ 'Squiz_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php',
320
+ 'Squiz_Sniffs_Functions_FunctionDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDeclarationSniff.php',
321
+ 'Squiz_Sniffs_Functions_FunctionDuplicateArgumentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/FunctionDuplicateArgumentSniff.php',
322
+ 'Squiz_Sniffs_Functions_GlobalFunctionSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/GlobalFunctionSniff.php',
323
+ 'Squiz_Sniffs_Functions_LowercaseFunctionKeywordsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/LowercaseFunctionKeywordsSniff.php',
324
+ 'Squiz_Sniffs_Functions_MultiLineFunctionDeclarationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php',
325
+ 'Squiz_Sniffs_NamingConventions_ValidFunctionNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidFunctionNameSniff.php',
326
+ 'Squiz_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/NamingConventions/ValidVariableNameSniff.php',
327
+ 'Squiz_Sniffs_Objects_DisallowObjectStringIndexSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php',
328
+ 'Squiz_Sniffs_Objects_ObjectInstantiationSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectInstantiationSniff.php',
329
+ 'Squiz_Sniffs_Objects_ObjectMemberCommaSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php',
330
+ 'Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php',
331
+ 'Squiz_Sniffs_Operators_IncrementDecrementUsageSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/IncrementDecrementUsageSniff.php',
332
+ 'Squiz_Sniffs_Operators_ValidLogicalOperatorsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Operators/ValidLogicalOperatorsSniff.php',
333
+ 'Squiz_Sniffs_PHP_CommentedOutCodeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php',
334
+ 'Squiz_Sniffs_PHP_DisallowBooleanStatementSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowBooleanStatementSniff.php',
335
+ 'Squiz_Sniffs_PHP_DisallowComparisonAssignmentSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowComparisonAssignmentSniff.php',
336
+ 'Squiz_Sniffs_PHP_DisallowInlineIfSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowInlineIfSniff.php',
337
+ 'Squiz_Sniffs_PHP_DisallowMultipleAssignmentsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php',
338
+ 'Squiz_Sniffs_PHP_DisallowObEndFlushSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowObEndFlushSniff.php',
339
+ 'Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DisallowSizeFunctionsInLoopsSniff.php',
340
+ 'Squiz_Sniffs_PHP_DiscouragedFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/DiscouragedFunctionsSniff.php',
341
+ 'Squiz_Sniffs_PHP_EmbeddedPhpSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php',
342
+ 'Squiz_Sniffs_PHP_EvalSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/EvalSniff.php',
343
+ 'Squiz_Sniffs_PHP_ForbiddenFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php',
344
+ 'Squiz_Sniffs_PHP_GlobalKeywordSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/GlobalKeywordSniff.php',
345
+ 'Squiz_Sniffs_PHP_HeredocSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/HeredocSniff.php',
346
+ 'Squiz_Sniffs_PHP_InnerFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/InnerFunctionsSniff.php',
347
+ 'Squiz_Sniffs_PHP_LowercasePHPFunctionsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/LowercasePHPFunctionsSniff.php',
348
+ 'Squiz_Sniffs_PHP_NonExecutableCodeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/PHP/NonExecutableCodeSniff.php',
349
+ 'Squiz_Sniffs_Scope_MemberVarScopeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php',
350
+ 'Squiz_Sniffs_Scope_MethodScopeSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/MethodScopeSniff.php',
351
+ 'Squiz_Sniffs_Scope_StaticThisUsageSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Scope/StaticThisUsageSniff.php',
352
+ 'Squiz_Sniffs_Strings_ConcatenationSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php',
353
+ 'Squiz_Sniffs_Strings_DoubleQuoteUsageSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php',
354
+ 'Squiz_Sniffs_Strings_EchoedStringsSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php',
355
+ 'Squiz_Sniffs_WhiteSpace_CastSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/CastSpacingSniff.php',
356
+ 'Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php',
357
+ 'Squiz_Sniffs_WhiteSpace_FunctionClosingBraceSpaceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php',
358
+ 'Squiz_Sniffs_WhiteSpace_FunctionOpeningBraceSpaceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php',
359
+ 'Squiz_Sniffs_WhiteSpace_FunctionSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php',
360
+ 'Squiz_Sniffs_WhiteSpace_LanguageConstructSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php',
361
+ 'Squiz_Sniffs_WhiteSpace_LogicalOperatorSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/LogicalOperatorSpacingSniff.php',
362
+ 'Squiz_Sniffs_WhiteSpace_MemberVarSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php',
363
+ 'Squiz_Sniffs_WhiteSpace_ObjectOperatorSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php',
364
+ 'Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php',
365
+ 'Squiz_Sniffs_WhiteSpace_PropertyLabelSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php',
366
+ 'Squiz_Sniffs_WhiteSpace_ScopeClosingBraceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php',
367
+ 'Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php',
368
+ 'Squiz_Sniffs_WhiteSpace_SemicolonSpacingSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php',
369
+ 'Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/SuperfluousWhitespaceSniff.php',
370
+ 'Zend_Sniffs_Debug_CodeAnalyzerSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/Debug/CodeAnalyzerSniff.php',
371
+ 'Zend_Sniffs_Files_ClosingTagSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/Files/ClosingTagSniff.php',
372
+ 'Zend_Sniffs_NamingConventions_ValidVariableNameSniff' => __DIR__ . '/..' . '/squizlabs/php_codesniffer/CodeSniffer/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php',
373
  );
374
 
375
  public static function getInitializer(ClassLoader $loader)
376
  {
377
  return \Closure::bind(function () use ($loader) {
378
+ $loader->prefixLengthsPsr4 = ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837::$prefixLengthsPsr4;
379
+ $loader->prefixDirsPsr4 = ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837::$prefixDirsPsr4;
380
+ $loader->classMap = ComposerStaticInit36fdde57bb31390b63c9fa4f374d8837::$classMap;
381
 
382
  }, null, ClassLoader::class);
383
  }
vendor/composer/installed.json CHANGED
@@ -1,4 +1,64 @@
1
  [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "name": "apache/log4php",
4
  "version": "2.3.0",
@@ -6,7 +66,7 @@
6
  "source": {
7
  "type": "git",
8
  "url": "https://git-wip-us.apache.org/repos/asf/logging-log4php.git",
9
- "reference": "8c6df2481cd68d0d211d38f700406c5f0a9de0c2"
10
  },
11
  "require": {
12
  "php": ">=5.2.7"
@@ -32,88 +92,146 @@
32
  ]
33
  },
34
  {
35
- "name": "facebook/graph-sdk",
36
- "version": "5.5.0",
37
- "version_normalized": "5.5.0.0",
38
  "source": {
39
  "type": "git",
40
- "url": "https://github.com/facebook/php-graph-sdk.git",
41
- "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1"
42
  },
43
  "dist": {
44
  "type": "zip",
45
- "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
46
- "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
47
  "shasum": ""
48
  },
49
  "require": {
50
- "php": "^5.4|^7.0"
 
 
 
51
  },
52
  "require-dev": {
53
- "guzzlehttp/guzzle": "~5.0",
54
- "mockery/mockery": "~0.8",
55
  "phpunit/phpunit": "~4.0"
56
  },
57
- "suggest": {
58
- "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client",
59
- "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5"
60
- },
61
- "time": "2017-04-20 14:15:02",
62
  "type": "library",
63
  "extra": {
64
  "branch-alias": {
65
- "dev-master": "5.x-dev"
66
  }
67
  },
68
  "installation-source": "dist",
69
  "autoload": {
70
- "psr-4": {
71
- "Facebook\\": "src/Facebook/"
72
- },
73
- "files": [
74
- "src/Facebook/polyfills.php"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  ]
76
  },
77
  "notification-url": "https://packagist.org/downloads/",
78
  "license": [
79
- "Facebook Platform"
80
  ],
81
  "authors": [
82
  {
83
- "name": "Facebook",
84
- "homepage": "https://github.com/facebook/php-graph-sdk/contributors"
85
  }
86
  ],
87
- "description": "Facebook SDK for PHP",
88
- "homepage": "https://github.com/facebook/php-graph-sdk",
89
  "keywords": [
90
- "facebook",
91
- "sdk"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  ]
93
  },
94
  {
95
  "name": "symfony/css-selector",
96
- "version": "v3.2.8",
97
- "version_normalized": "3.2.8.0",
98
  "source": {
99
  "type": "git",
100
  "url": "https://github.com/symfony/css-selector.git",
101
- "reference": "02983c144038e697c959e6b06ef6666de759ccbc"
102
  },
103
  "dist": {
104
  "type": "zip",
105
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/02983c144038e697c959e6b06ef6666de759ccbc",
106
- "reference": "02983c144038e697c959e6b06ef6666de759ccbc",
107
  "shasum": ""
108
  },
109
  "require": {
110
- "php": ">=5.5.9"
111
  },
112
- "time": "2017-05-01 14:55:58",
113
  "type": "library",
114
  "extra": {
115
  "branch-alias": {
116
- "dev-master": "3.2-dev"
117
  }
118
  },
119
  "installation-source": "dist",
@@ -148,17 +266,17 @@
148
  },
149
  {
150
  "name": "facebook/facebook-instant-articles-sdk-php",
151
- "version": "v1.5.7",
152
- "version_normalized": "1.5.7.0",
153
  "source": {
154
  "type": "git",
155
  "url": "https://github.com/facebook/facebook-instant-articles-sdk-php.git",
156
- "reference": "540cfcf1df49ce98d1942c34672ac10bf8888bd7"
157
  },
158
  "dist": {
159
  "type": "zip",
160
- "url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-php/zipball/540cfcf1df49ce98d1942c34672ac10bf8888bd7",
161
- "reference": "540cfcf1df49ce98d1942c34672ac10bf8888bd7",
162
  "shasum": ""
163
  },
164
  "require": {
@@ -172,7 +290,7 @@
172
  "phpunit/phpunit": "^4.8",
173
  "squizlabs/php_codesniffer": "^2.6.0"
174
  },
175
- "time": "2017-04-27 18:49:03",
176
  "type": "library",
177
  "installation-source": "dist",
178
  "autoload": {
@@ -198,5 +316,57 @@
198
  "instant",
199
  "sdk"
200
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  }
202
  ]
1
  [
2
+ {
3
+ "name": "facebook/graph-sdk",
4
+ "version": "5.5.0",
5
+ "version_normalized": "5.5.0.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/facebook/php-graph-sdk.git",
9
+ "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
14
+ "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": "^5.4|^7.0"
19
+ },
20
+ "require-dev": {
21
+ "guzzlehttp/guzzle": "~5.0",
22
+ "mockery/mockery": "~0.8",
23
+ "phpunit/phpunit": "~4.0"
24
+ },
25
+ "suggest": {
26
+ "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client",
27
+ "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5"
28
+ },
29
+ "time": "2017-04-20 14:15:02",
30
+ "type": "library",
31
+ "extra": {
32
+ "branch-alias": {
33
+ "dev-master": "5.x-dev"
34
+ }
35
+ },
36
+ "installation-source": "dist",
37
+ "autoload": {
38
+ "psr-4": {
39
+ "Facebook\\": "src/Facebook/"
40
+ },
41
+ "files": [
42
+ "src/Facebook/polyfills.php"
43
+ ]
44
+ },
45
+ "notification-url": "https://packagist.org/downloads/",
46
+ "license": [
47
+ "Facebook Platform"
48
+ ],
49
+ "authors": [
50
+ {
51
+ "name": "Facebook",
52
+ "homepage": "https://github.com/facebook/php-graph-sdk/contributors"
53
+ }
54
+ ],
55
+ "description": "Facebook SDK for PHP",
56
+ "homepage": "https://github.com/facebook/php-graph-sdk",
57
+ "keywords": [
58
+ "facebook",
59
+ "sdk"
60
+ ]
61
+ },
62
  {
63
  "name": "apache/log4php",
64
  "version": "2.3.0",
66
  "source": {
67
  "type": "git",
68
  "url": "https://git-wip-us.apache.org/repos/asf/logging-log4php.git",
69
+ "reference": "cac428b6f67d2035af39784da1d1a299ef42fcf2"
70
  },
71
  "require": {
72
  "php": ">=5.2.7"
92
  ]
93
  },
94
  {
95
+ "name": "squizlabs/php_codesniffer",
96
+ "version": "2.9.1",
97
+ "version_normalized": "2.9.1.0",
98
  "source": {
99
  "type": "git",
100
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
101
+ "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62"
102
  },
103
  "dist": {
104
  "type": "zip",
105
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62",
106
+ "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62",
107
  "shasum": ""
108
  },
109
  "require": {
110
+ "ext-simplexml": "*",
111
+ "ext-tokenizer": "*",
112
+ "ext-xmlwriter": "*",
113
+ "php": ">=5.1.2"
114
  },
115
  "require-dev": {
 
 
116
  "phpunit/phpunit": "~4.0"
117
  },
118
+ "time": "2017-05-22 02:43:20",
119
+ "bin": [
120
+ "scripts/phpcs",
121
+ "scripts/phpcbf"
122
+ ],
123
  "type": "library",
124
  "extra": {
125
  "branch-alias": {
126
+ "dev-master": "2.x-dev"
127
  }
128
  },
129
  "installation-source": "dist",
130
  "autoload": {
131
+ "classmap": [
132
+ "CodeSniffer.php",
133
+ "CodeSniffer/CLI.php",
134
+ "CodeSniffer/Exception.php",
135
+ "CodeSniffer/File.php",
136
+ "CodeSniffer/Fixer.php",
137
+ "CodeSniffer/Report.php",
138
+ "CodeSniffer/Reporting.php",
139
+ "CodeSniffer/Sniff.php",
140
+ "CodeSniffer/Tokens.php",
141
+ "CodeSniffer/Reports/",
142
+ "CodeSniffer/Tokenizers/",
143
+ "CodeSniffer/DocGenerators/",
144
+ "CodeSniffer/Standards/AbstractPatternSniff.php",
145
+ "CodeSniffer/Standards/AbstractScopeSniff.php",
146
+ "CodeSniffer/Standards/AbstractVariableSniff.php",
147
+ "CodeSniffer/Standards/IncorrectPatternException.php",
148
+ "CodeSniffer/Standards/Generic/Sniffs/",
149
+ "CodeSniffer/Standards/MySource/Sniffs/",
150
+ "CodeSniffer/Standards/PEAR/Sniffs/",
151
+ "CodeSniffer/Standards/PSR1/Sniffs/",
152
+ "CodeSniffer/Standards/PSR2/Sniffs/",
153
+ "CodeSniffer/Standards/Squiz/Sniffs/",
154
+ "CodeSniffer/Standards/Zend/Sniffs/"
155
  ]
156
  },
157
  "notification-url": "https://packagist.org/downloads/",
158
  "license": [
159
+ "BSD-3-Clause"
160
  ],
161
  "authors": [
162
  {
163
+ "name": "Greg Sherwood",
164
+ "role": "lead"
165
  }
166
  ],
167
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
168
+ "homepage": "http://www.squizlabs.com/php-codesniffer",
169
  "keywords": [
170
+ "phpcs",
171
+ "standards"
172
+ ]
173
+ },
174
+ {
175
+ "name": "wp-coding-standards/wpcs",
176
+ "version": "0.11.0",
177
+ "version_normalized": "0.11.0.0",
178
+ "source": {
179
+ "type": "git",
180
+ "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
181
+ "reference": "407e4b85f547a5251185f89ceae6599917343388"
182
+ },
183
+ "dist": {
184
+ "type": "zip",
185
+ "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/407e4b85f547a5251185f89ceae6599917343388",
186
+ "reference": "407e4b85f547a5251185f89ceae6599917343388",
187
+ "shasum": ""
188
+ },
189
+ "require": {
190
+ "squizlabs/php_codesniffer": "^2.8.1"
191
+ },
192
+ "time": "2017-03-20 23:17:58",
193
+ "type": "library",
194
+ "installation-source": "dist",
195
+ "notification-url": "https://packagist.org/downloads/",
196
+ "license": [
197
+ "MIT"
198
+ ],
199
+ "authors": [
200
+ {
201
+ "name": "Contributors",
202
+ "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
203
+ }
204
+ ],
205
+ "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
206
+ "keywords": [
207
+ "phpcs",
208
+ "standards",
209
+ "wordpress"
210
  ]
211
  },
212
  {
213
  "name": "symfony/css-selector",
214
+ "version": "v2.8.22",
215
+ "version_normalized": "2.8.22.0",
216
  "source": {
217
  "type": "git",
218
  "url": "https://github.com/symfony/css-selector.git",
219
+ "reference": "ba3204654efa779691fac9e948a96b4a7067e4ab"
220
  },
221
  "dist": {
222
  "type": "zip",
223
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/ba3204654efa779691fac9e948a96b4a7067e4ab",
224
+ "reference": "ba3204654efa779691fac9e948a96b4a7067e4ab",
225
  "shasum": ""
226
  },
227
  "require": {
228
+ "php": ">=5.3.9"
229
  },
230
+ "time": "2017-05-01 14:31:55",
231
  "type": "library",
232
  "extra": {
233
  "branch-alias": {
234
+ "dev-master": "2.8-dev"
235
  }
236
  },
237
  "installation-source": "dist",
266
  },
267
  {
268
  "name": "facebook/facebook-instant-articles-sdk-php",
269
+ "version": "v1.6.1",
270
+ "version_normalized": "1.6.1.0",
271
  "source": {
272
  "type": "git",
273
  "url": "https://github.com/facebook/facebook-instant-articles-sdk-php.git",
274
+ "reference": "511d15d741796c7da68742e565d98f97464d2d6b"
275
  },
276
  "dist": {
277
  "type": "zip",
278
+ "url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-php/zipball/511d15d741796c7da68742e565d98f97464d2d6b",
279
+ "reference": "511d15d741796c7da68742e565d98f97464d2d6b",
280
  "shasum": ""
281
  },
282
  "require": {
290
  "phpunit/phpunit": "^4.8",
291
  "squizlabs/php_codesniffer": "^2.6.0"
292
  },
293
+ "time": "2017-06-20 13:45:09",
294
  "type": "library",
295
  "installation-source": "dist",
296
  "autoload": {
316
  "instant",
317
  "sdk"
318
  ]
319
+ },
320
+ {
321
+ "name": "facebook/facebook-instant-articles-sdk-extensions-in-php",
322
+ "version": "v0.1.1",
323
+ "version_normalized": "0.1.1.0",
324
+ "source": {
325
+ "type": "git",
326
+ "url": "https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php.git",
327
+ "reference": "f574ad6230ced8d8159b7b59a41ac6238d8d6353"
328
+ },
329
+ "dist": {
330
+ "type": "zip",
331
+ "url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-extensions-in-php/zipball/f574ad6230ced8d8159b7b59a41ac6238d8d6353",
332
+ "reference": "f574ad6230ced8d8159b7b59a41ac6238d8d6353",
333
+ "shasum": ""
334
+ },
335
+ "require": {
336
+ "facebook/facebook-instant-articles-sdk-php": "^1.6",
337
+ "php": "^5.4 || ^7.0"
338
+ },
339
+ "require-dev": {
340
+ "phpunit/phpunit": "^4.8"
341
+ },
342
+ "time": "2017-06-26 19:59:19",
343
+ "type": "library",
344
+ "installation-source": "dist",
345
+ "autoload": {
346
+ "psr-4": {
347
+ "Facebook\\InstantArticles\\": "src/Facebook/InstantArticles/"
348
+ }
349
+ },
350
+ "notification-url": "https://packagist.org/downloads/",
351
+ "license": [
352
+ "proprietary"
353
+ ],
354
+ "authors": [
355
+ {
356
+ "name": "Facebook",
357
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/contributors"
358
+ }
359
+ ],
360
+ "description": "Facebook Instant Articles SDK Extensions in PHP to transform Instant Articles markup file into AMP",
361
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php",
362
+ "keywords": [
363
+ "amp",
364
+ "articles",
365
+ "extensions",
366
+ "facebook",
367
+ "instant",
368
+ "instantarticles",
369
+ "sdk"
370
+ ]
371
  }
372
  ]
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ composer.phar
2
+ /vendor/
3
+ *.ignored
4
+ **/IgnoredTest.php
5
+ .DS_Store
6
+ .vscode
7
+ **/ignored-*
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/.travis.yml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - '5.5'
5
+ - '5.6'
6
+ - '7.0'
7
+ - '7.1'
8
+ - hhvm
9
+
10
+ dist: trusty
11
+ sudo: false
12
+
13
+ cache:
14
+ directories:
15
+ - $HOME/.composer/cache
16
+
17
+ before_install:
18
+ - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi
19
+ - travis_retry composer self-update
20
+ - composer validate
21
+ - composer config github-oauth.github.com $GITHUB_TOKEN
22
+
23
+ install:
24
+ - travis_retry composer install --no-interaction --prefer-dist
25
+
26
+ script:
27
+ - vendor/bin/phpunit
28
+ - if [[ "$WITH_CS" == "true" ]]; then vendor/bin/phpcs --standard=phpcs.xml -p; fi
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/CONTRIBUTING.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing to Facebook Instant Articles SDK Extensions in PHP
2
+ We want to make contributing to this project as easy and transparent as possible.
3
+
4
+ We accept contributions via pull requests on [GitHub](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php).
5
+
6
+ ## Pull Requests
7
+ - **Sign the CLA** - In order to accept your pull request, we need you to submit a [Contributor License Agreement](https://code.facebook.com/cla). You only need to do this once to work on any of Facebook's open source projects.
8
+
9
+ - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to run [PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer) as you code.
10
+
11
+ - **Add tests** - If you've added code that can be tested, add tests.
12
+
13
+ - **Document any change in behaviour** - Make sure the README file is updated in your PR. Include any notes for documentation items which needs to be updated on the main [docs on Facebook's Developer site](https://developers.facebook.com/docs/instant-articles/sdk/).
14
+
15
+ - **Consider our release cycle** - We try to follow [SemVer](http://semver.org/). Randomly breaking public APIs is not an option.
16
+
17
+ - **Create topic branches** - Don't ask us to pull from your master branch.
18
+
19
+ - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
20
+
21
+ - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
22
+
23
+ - **Ensure tests pass!** - Please [run the tests](https://github.com/facebook/facebook-instant-articles-sdk-extensions-php#testing-and-developing) before submitting your pull request, and make sure they pass. We won't accept a patch until all tests pass.
24
+
25
+ - **Ensure no coding standards violations** - Please run [PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer) using the PSR-2 standard before submitting your pull request. A violation will cause the build to fail, so please make sure there are no violations. We can't accept a patch if the build fails.
26
+
27
+
28
+ ## Issues
29
+ We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue.
30
+
31
+
32
+ ## Running Tests
33
+
34
+ ``` bash
35
+ $ ./vendor/bin/phpunit
36
+ ```
37
+
38
+ When doing a pull request, consider if this diff has a testcase that was covered in a wrong way or if it needs a new test case.
39
+
40
+
41
+ ## Running PHP Code Sniffer
42
+
43
+ Run Code Sniffer against the `src/` and `tests/` directories.
44
+
45
+ ``` bash
46
+ $ vendor/bin/phpcs --standard=phpcs.xml -p
47
+ ```
48
+
49
+ Give a try for the autofixer for code style
50
+
51
+ ``` bash
52
+ $ vendor/bin/phpcbf --standard-phpcs.xml -p
53
+ ```
54
+ **Happy coding**!
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
2
+
3
+ You are hereby granted a non-exclusive, worldwide, royalty-free license to
4
+ use, copy, modify, and distribute this software in source code or binary
5
+ form for use in connection with the web services and APIs provided by
6
+ Facebook.
7
+
8
+ As with any software that integrates with the Facebook platform, your use
9
+ of this software is subject to the Facebook Developer Principles and
10
+ Policies [http://developers.facebook.com/policy/]. This copyright notice
11
+ shall be included in all copies or substantial portions of the software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/README.md ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Facebook Instant Articles SDK Extensions in PHP #
2
+
3
+ [![Build Status](https://travis-ci.org/facebook/facebook-instant-articles-sdk-extensions-in-php.svg?branch=master)](https://travis-ci.org/facebook/facebook-instant-articles-sdk-extensions-in-php)
4
+ [![Latest Stable Version](https://poser.pugx.org/facebook/facebook-instant-articles-sdk-extensions-in-php/v/stable)](https://packagist.org/packages/facebook/facebook-instant-articles-sdk-extensions-in-php)
5
+
6
+ The Facebook Instant Articles SDK Extensions in PHP provides a native PHP interface for converting valid Instant Articles into AMP. This gives developers the ability to have AMP content right after getting his own Instant Article markup format ready.
7
+
8
+ The Extension package consists of:
9
+ - **Environment**: PHP >= 5.4 or HHVM
10
+ - **Dependencies**: It relies solely on the [Instant Articles SDK](https://github.com/Facebook/facebook-instant-articles-sdk-php) and its dependencies to get the Instant Article markup format available into the Elements object tree structure. It also depends on [Composer](https://getcomposer.org/) dependency manager.
11
+ - **AMP**: The AMP transformation was based on the current implementation and definition from [AMP project](https://www.ampproject.org/).
12
+
13
+ ## Quick Start
14
+
15
+ ```sh
16
+ $ composer require facebook/facebook-instant-articles-sdk-extensions-in-php
17
+ ```
18
+
19
+ After the installation, you can include the auto loader script in your source with:
20
+
21
+ ```PHP
22
+ require_once('vendor/autoload.php');
23
+ ```
24
+
25
+ Also be sure to check [the quick start example](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/examples/example-quick-start.php).
26
+
27
+ ## Official Documentation
28
+
29
+ You can find examples on how to use the different components of this SDK to integrate with your CMS in the [Quick Start Guide](https://developers.facebook.com/docs/instant-articles/other-formats/#quickstart) of the [documentation](https://developers.facebook.com/docs/instant-articles/other-formats/).
30
+
31
+ ## Contributing
32
+
33
+ Clone the repository
34
+ ```sh
35
+ $ git clone https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php.git
36
+ ```
37
+
38
+ [Composer](https://getcomposer.org/) is a prerequisite for testing and developing. [Install composer globally](https://getcomposer.org/doc/00-intro.md#globally), then install project dependencies by running this command in the project's root directory:
39
+
40
+ ```sh
41
+ $ composer install
42
+ ```
43
+
44
+ To run the tests:
45
+
46
+ ```sh
47
+ $ composer test
48
+ ```
49
+
50
+ To fix and check for coding style issues:
51
+
52
+ ```sh
53
+ $ composer cs
54
+ ```
55
+
56
+ Extra lazy? Run
57
+
58
+ ```sh
59
+ $ composer all
60
+ ```
61
+
62
+ to fix and check for coding style issues, and run the tests.
63
+
64
+ If you change structure, paths, namespaces, etc., make sure you run the [autoload generator](https://getcomposer.org/doc/03-cli.md#dump-autoload):
65
+ ```sh
66
+ $ composer dump-autoload
67
+ ```
68
+
69
+ ___
70
+ **For us to accept contributions you will have to first sign the [Contributor License Agreement](https://code.facebook.com/cla). Please see [CONTRIBUTING](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/CONTRIBUTING.md) for details.**
71
+ ___
72
+
73
+ ## Troubleshooting
74
+
75
+ If you are encountering problems, the following tips may help in troubleshooting issues:
76
+
77
+ - Set the `threshold` in the [configuration of the Logger](https://logging.apache.org/log4php/docs/configuration.html#PHP) to `DEBUG` to expose more details about the items processed by the Transformer, conversely, to make it more quiet set it to `INFO`, check [this script](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/examples/quiet_logger.php) for details.
78
+ - If your images are having dimension/aspect ratio problems, please check the [the quick start example](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/examples/example-quick-start.php) for more information.
79
+ - At the moment, we have no way to determine a video's width and height, you need to explicitly pass that information via properties, see how to do it [here](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/examples/example-quick-start.php).
80
+
81
+ ### Filing an issue
82
+
83
+ - Be sure you've looked for the similar issue into the [Issues list](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/issues)
84
+
85
+ - Inform the Canonical URL of your Instant Article being converted
86
+
87
+ - Inform the [exported JSON from the style editor](https://developers.facebook.com/docs/instant-articles/other-formats#style)
88
+
89
+ Issue template:
90
+ ```
91
+ # Issue Data
92
+ Instant Article Canonical URL: `http://yourdomain.com/path/article.html`
93
+ Exported Style JSON: `{...}`
94
+ Page ID: `12345`
95
+
96
+ # Problem noticed
97
+ 1. Image XYZ missing
98
+
99
+ # Expected result
100
+ 1. The Image XYZ should be present.
101
+ ```
102
+
103
+ ## License
104
+
105
+ Please see the [license file](https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/blob/master/LICENSE) for more information.
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/composer.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "facebook/facebook-instant-articles-sdk-extensions-in-php",
3
+ "description": "Facebook Instant Articles SDK Extensions in PHP to transform Instant Articles markup file into AMP",
4
+ "keywords": ["facebook", "sdk", "instant", "articles", "instantarticles", "amp", "extensions"],
5
+ "type": "library",
6
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php",
7
+ "license": "proprietary",
8
+ "authors": [{
9
+ "name": "Facebook",
10
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-extensions-in-php/contributors"
11
+ }],
12
+ "require": {
13
+ "php": "^5.4 || ^7.0",
14
+ "facebook/facebook-instant-articles-sdk-php": "^1.6"
15
+ },
16
+ "require-dev": {
17
+ "phpunit/phpunit": "^4.8"
18
+ },
19
+ "autoload": {
20
+ "psr-4": {
21
+ "Facebook\\InstantArticles\\": "src/Facebook/InstantArticles/"
22
+ }
23
+ },
24
+ "autoload-dev": {
25
+ "psr-4": {
26
+ "Facebook\\InstantArticles\\": "tests/Facebook/InstantArticles/"
27
+ }
28
+ },
29
+ "scripts": {
30
+ "all": [
31
+ "@cs",
32
+ "@test"
33
+ ],
34
+ "cs": [
35
+ "composer install",
36
+ "phpcbf --standard=phpcs.xml -p || phpcs --standard=phpcs.xml -p"
37
+ ],
38
+ "test": [
39
+ "composer install",
40
+ "phpunit"
41
+ ]
42
+ }
43
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/composer.lock ADDED
@@ -0,0 +1,1329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "content-hash": "b5add67aa5284f095c0e347b2a704d1b",
8
+ "packages": [
9
+ {
10
+ "name": "apache/log4php",
11
+ "version": "2.3.0",
12
+ "source": {
13
+ "type": "git",
14
+ "url": "https://git-wip-us.apache.org/repos/asf/logging-log4php.git",
15
+ "reference": "cac428b6f67d2035af39784da1d1a299ef42fcf2"
16
+ },
17
+ "require": {
18
+ "php": ">=5.2.7"
19
+ },
20
+ "type": "library",
21
+ "autoload": {
22
+ "classmap": [
23
+ "src/main/php/"
24
+ ]
25
+ },
26
+ "notification-url": "https://packagist.org/downloads/",
27
+ "license": [
28
+ "Apache-2.0"
29
+ ],
30
+ "description": "A versatile logging framework for PHP",
31
+ "homepage": "http://logging.apache.org/log4php/",
32
+ "keywords": [
33
+ "log",
34
+ "logging",
35
+ "php"
36
+ ],
37
+ "time": "2012-10-26T09:13:25+00:00"
38
+ },
39
+ {
40
+ "name": "facebook/facebook-instant-articles-sdk-php",
41
+ "version": "v1.6.0",
42
+ "source": {
43
+ "type": "git",
44
+ "url": "https://github.com/facebook/facebook-instant-articles-sdk-php.git",
45
+ "reference": "c0d9491ad7c44ae1e96fa7d5f7f54262b9f8186d"
46
+ },
47
+ "dist": {
48
+ "type": "zip",
49
+ "url": "https://api.github.com/repos/facebook/facebook-instant-articles-sdk-php/zipball/c0d9491ad7c44ae1e96fa7d5f7f54262b9f8186d",
50
+ "reference": "c0d9491ad7c44ae1e96fa7d5f7f54262b9f8186d",
51
+ "shasum": ""
52
+ },
53
+ "require": {
54
+ "apache/log4php": "2.3.0",
55
+ "facebook/graph-sdk": "~5.0",
56
+ "php": "^5.4 || ^7.0",
57
+ "symfony/css-selector": "2.8.* || ^3.0"
58
+ },
59
+ "require-dev": {
60
+ "fzaninotto/faker": "^1.6.0",
61
+ "phpunit/phpunit": "^4.8",
62
+ "squizlabs/php_codesniffer": "^2.6.0"
63
+ },
64
+ "type": "library",
65
+ "autoload": {
66
+ "psr-4": {
67
+ "Facebook\\InstantArticles\\": "src/Facebook/InstantArticles/"
68
+ }
69
+ },
70
+ "notification-url": "https://packagist.org/downloads/",
71
+ "license": [
72
+ "proprietary"
73
+ ],
74
+ "authors": [
75
+ {
76
+ "name": "Facebook",
77
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-php/contributors"
78
+ }
79
+ ],
80
+ "description": "Facebook Instant Articles SDK for PHP",
81
+ "homepage": "https://github.com/facebook/facebook-instant-articles-sdk-php",
82
+ "keywords": [
83
+ "articles",
84
+ "facebook",
85
+ "instant",
86
+ "sdk"
87
+ ],
88
+ "time": "2017-05-24T22:31:08+00:00"
89
+ },
90
+ {
91
+ "name": "facebook/graph-sdk",
92
+ "version": "5.5.0",
93
+ "source": {
94
+ "type": "git",
95
+ "url": "https://github.com/facebook/php-graph-sdk.git",
96
+ "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1"
97
+ },
98
+ "dist": {
99
+ "type": "zip",
100
+ "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
101
+ "reference": "93d7dc87e55a541d2e27d38f3aed40abbffdf6e1",
102
+ "shasum": ""
103
+ },
104
+ "require": {
105
+ "php": "^5.4|^7.0"
106
+ },
107
+ "require-dev": {
108
+ "guzzlehttp/guzzle": "~5.0",
109
+ "mockery/mockery": "~0.8",
110
+ "phpunit/phpunit": "~4.0"
111
+ },
112
+ "suggest": {
113
+ "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client",
114
+ "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5"
115
+ },
116
+ "type": "library",
117
+ "extra": {
118
+ "branch-alias": {
119
+ "dev-master": "5.x-dev"
120
+ }
121
+ },
122
+ "autoload": {
123
+ "psr-4": {
124
+ "Facebook\\": "src/Facebook/"
125
+ },
126
+ "files": [
127
+ "src/Facebook/polyfills.php"
128
+ ]
129
+ },
130
+ "notification-url": "https://packagist.org/downloads/",
131
+ "license": [
132
+ "Facebook Platform"
133
+ ],
134
+ "authors": [
135
+ {
136
+ "name": "Facebook",
137
+ "homepage": "https://github.com/facebook/php-graph-sdk/contributors"
138
+ }
139
+ ],
140
+ "description": "Facebook SDK for PHP",
141
+ "homepage": "https://github.com/facebook/php-graph-sdk",
142
+ "keywords": [
143
+ "facebook",
144
+ "sdk"
145
+ ],
146
+ "time": "2017-04-20T14:15:02+00:00"
147
+ },
148
+ {
149
+ "name": "symfony/css-selector",
150
+ "version": "v3.2.8",
151
+ "source": {
152
+ "type": "git",
153
+ "url": "https://github.com/symfony/css-selector.git",
154
+ "reference": "02983c144038e697c959e6b06ef6666de759ccbc"
155
+ },
156
+ "dist": {
157
+ "type": "zip",
158
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/02983c144038e697c959e6b06ef6666de759ccbc",
159
+ "reference": "02983c144038e697c959e6b06ef6666de759ccbc",
160
+ "shasum": ""
161
+ },
162
+ "require": {
163
+ "php": ">=5.5.9"
164
+ },
165
+ "type": "library",
166
+ "extra": {
167
+ "branch-alias": {
168
+ "dev-master": "3.2-dev"
169
+ }
170
+ },
171
+ "autoload": {
172
+ "psr-4": {
173
+ "Symfony\\Component\\CssSelector\\": ""
174
+ },
175
+ "exclude-from-classmap": [
176
+ "/Tests/"
177
+ ]
178
+ },
179
+ "notification-url": "https://packagist.org/downloads/",
180
+ "license": [
181
+ "MIT"
182
+ ],
183
+ "authors": [
184
+ {
185
+ "name": "Jean-François Simon",
186
+ "email": "jeanfrancois.simon@sensiolabs.com"
187
+ },
188
+ {
189
+ "name": "Fabien Potencier",
190
+ "email": "fabien@symfony.com"
191
+ },
192
+ {
193
+ "name": "Symfony Community",
194
+ "homepage": "https://symfony.com/contributors"
195
+ }
196
+ ],
197
+ "description": "Symfony CssSelector Component",
198
+ "homepage": "https://symfony.com",
199
+ "time": "2017-05-01T14:55:58+00:00"
200
+ }
201
+ ],
202
+ "packages-dev": [
203
+ {
204
+ "name": "doctrine/instantiator",
205
+ "version": "1.0.5",
206
+ "source": {
207
+ "type": "git",
208
+ "url": "https://github.com/doctrine/instantiator.git",
209
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
210
+ },
211
+ "dist": {
212
+ "type": "zip",
213
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
214
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
215
+ "shasum": ""
216
+ },
217
+ "require": {
218
+ "php": ">=5.3,<8.0-DEV"
219
+ },
220
+ "require-dev": {
221
+ "athletic/athletic": "~0.1.8",
222
+ "ext-pdo": "*",
223
+ "ext-phar": "*",
224
+ "phpunit/phpunit": "~4.0",
225
+ "squizlabs/php_codesniffer": "~2.0"
226
+ },
227
+ "type": "library",
228
+ "extra": {
229
+ "branch-alias": {
230
+ "dev-master": "1.0.x-dev"
231
+ }
232
+ },
233
+ "autoload": {
234
+ "psr-4": {
235
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
236
+ }
237
+ },
238
+ "notification-url": "https://packagist.org/downloads/",
239
+ "license": [
240
+ "MIT"
241
+ ],
242
+ "authors": [
243
+ {
244
+ "name": "Marco Pivetta",
245
+ "email": "ocramius@gmail.com",
246
+ "homepage": "http://ocramius.github.com/"
247
+ }
248
+ ],
249
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
250
+ "homepage": "https://github.com/doctrine/instantiator",
251
+ "keywords": [
252
+ "constructor",
253
+ "instantiate"
254
+ ],
255
+ "time": "2015-06-14T21:17:01+00:00"
256
+ },
257
+ {
258
+ "name": "phpdocumentor/reflection-common",
259
+ "version": "1.0",
260
+ "source": {
261
+ "type": "git",
262
+ "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
263
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
264
+ },
265
+ "dist": {
266
+ "type": "zip",
267
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
268
+ "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
269
+ "shasum": ""
270
+ },
271
+ "require": {
272
+ "php": ">=5.5"
273
+ },
274
+ "require-dev": {
275
+ "phpunit/phpunit": "^4.6"
276
+ },
277
+ "type": "library",
278
+ "extra": {
279
+ "branch-alias": {
280
+ "dev-master": "1.0.x-dev"
281
+ }
282
+ },
283
+ "autoload": {
284
+ "psr-4": {
285
+ "phpDocumentor\\Reflection\\": [
286
+ "src"
287
+ ]
288
+ }
289
+ },
290
+ "notification-url": "https://packagist.org/downloads/",
291
+ "license": [
292
+ "MIT"
293
+ ],
294
+ "authors": [
295
+ {
296
+ "name": "Jaap van Otterdijk",
297
+ "email": "opensource@ijaap.nl"
298
+ }
299
+ ],
300
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
301
+ "homepage": "http://www.phpdoc.org",
302
+ "keywords": [
303
+ "FQSEN",
304
+ "phpDocumentor",
305
+ "phpdoc",
306
+ "reflection",
307
+ "static analysis"
308
+ ],
309
+ "time": "2015-12-27T11:43:31+00:00"
310
+ },
311
+ {
312
+ "name": "phpdocumentor/reflection-docblock",
313
+ "version": "3.1.1",
314
+ "source": {
315
+ "type": "git",
316
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
317
+ "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
318
+ },
319
+ "dist": {
320
+ "type": "zip",
321
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
322
+ "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
323
+ "shasum": ""
324
+ },
325
+ "require": {
326
+ "php": ">=5.5",
327
+ "phpdocumentor/reflection-common": "^1.0@dev",
328
+ "phpdocumentor/type-resolver": "^0.2.0",
329
+ "webmozart/assert": "^1.0"
330
+ },
331
+ "require-dev": {
332
+ "mockery/mockery": "^0.9.4",
333
+ "phpunit/phpunit": "^4.4"
334
+ },
335
+ "type": "library",
336
+ "autoload": {
337
+ "psr-4": {
338
+ "phpDocumentor\\Reflection\\": [
339
+ "src/"
340
+ ]
341
+ }
342
+ },
343
+ "notification-url": "https://packagist.org/downloads/",
344
+ "license": [
345
+ "MIT"
346
+ ],
347
+ "authors": [
348
+ {
349
+ "name": "Mike van Riel",
350
+ "email": "me@mikevanriel.com"
351
+ }
352
+ ],
353
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
354
+ "time": "2016-09-30T07:12:33+00:00"
355
+ },
356
+ {
357
+ "name": "phpdocumentor/type-resolver",
358
+ "version": "0.2.1",
359
+ "source": {
360
+ "type": "git",
361
+ "url": "https://github.com/phpDocumentor/TypeResolver.git",
362
+ "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
363
+ },
364
+ "dist": {
365
+ "type": "zip",
366
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
367
+ "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
368
+ "shasum": ""
369
+ },
370
+ "require": {
371
+ "php": ">=5.5",
372
+ "phpdocumentor/reflection-common": "^1.0"
373
+ },
374
+ "require-dev": {
375
+ "mockery/mockery": "^0.9.4",
376
+ "phpunit/phpunit": "^5.2||^4.8.24"
377
+ },
378
+ "type": "library",
379
+ "extra": {
380
+ "branch-alias": {
381
+ "dev-master": "1.0.x-dev"
382
+ }
383
+ },
384
+ "autoload": {
385
+ "psr-4": {
386
+ "phpDocumentor\\Reflection\\": [
387
+ "src/"
388
+ ]
389
+ }
390
+ },
391
+ "notification-url": "https://packagist.org/downloads/",
392
+ "license": [
393
+ "MIT"
394
+ ],
395
+ "authors": [
396
+ {
397
+ "name": "Mike van Riel",
398
+ "email": "me@mikevanriel.com"
399
+ }
400
+ ],
401
+ "time": "2016-11-25T06:54:22+00:00"
402
+ },
403
+ {
404
+ "name": "phpspec/prophecy",
405
+ "version": "v1.7.0",
406
+ "source": {
407
+ "type": "git",
408
+ "url": "https://github.com/phpspec/prophecy.git",
409
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
410
+ },
411
+ "dist": {
412
+ "type": "zip",
413
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
414
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
415
+ "shasum": ""
416
+ },
417
+ "require": {
418
+ "doctrine/instantiator": "^1.0.2",
419
+ "php": "^5.3|^7.0",
420
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
421
+ "sebastian/comparator": "^1.1|^2.0",
422
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
423
+ },
424
+ "require-dev": {
425
+ "phpspec/phpspec": "^2.5|^3.2",
426
+ "phpunit/phpunit": "^4.8 || ^5.6.5"
427
+ },
428
+ "type": "library",
429
+ "extra": {
430
+ "branch-alias": {
431
+ "dev-master": "1.6.x-dev"
432
+ }
433
+ },
434
+ "autoload": {
435
+ "psr-0": {
436
+ "Prophecy\\": "src/"
437
+ }
438
+ },
439
+ "notification-url": "https://packagist.org/downloads/",
440
+ "license": [
441
+ "MIT"
442
+ ],
443
+ "authors": [
444
+ {
445
+ "name": "Konstantin Kudryashov",
446
+ "email": "ever.zet@gmail.com",
447
+ "homepage": "http://everzet.com"
448
+ },
449
+ {
450
+ "name": "Marcello Duarte",
451
+ "email": "marcello.duarte@gmail.com"
452
+ }
453
+ ],
454
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
455
+ "homepage": "https://github.com/phpspec/prophecy",
456
+ "keywords": [
457
+ "Double",
458
+ "Dummy",
459
+ "fake",
460
+ "mock",
461
+ "spy",
462
+ "stub"
463
+ ],
464
+ "time": "2017-03-02T20:05:34+00:00"
465
+ },
466
+ {
467
+ "name": "phpunit/php-code-coverage",
468
+ "version": "2.2.4",
469
+ "source": {
470
+ "type": "git",
471
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
472
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
473
+ },
474
+ "dist": {
475
+ "type": "zip",
476
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
477
+ "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
478
+ "shasum": ""
479
+ },
480
+ "require": {
481
+ "php": ">=5.3.3",
482
+ "phpunit/php-file-iterator": "~1.3",
483
+ "phpunit/php-text-template": "~1.2",
484
+ "phpunit/php-token-stream": "~1.3",
485
+ "sebastian/environment": "^1.3.2",
486
+ "sebastian/version": "~1.0"
487
+ },
488
+ "require-dev": {
489
+ "ext-xdebug": ">=2.1.4",
490
+ "phpunit/phpunit": "~4"
491
+ },
492
+ "suggest": {
493
+ "ext-dom": "*",
494
+ "ext-xdebug": ">=2.2.1",
495
+ "ext-xmlwriter": "*"
496
+ },
497
+ "type": "library",
498
+ "extra": {
499
+ "branch-alias": {
500
+ "dev-master": "2.2.x-dev"
501
+ }
502
+ },
503
+ "autoload": {
504
+ "classmap": [
505
+ "src/"
506
+ ]
507
+ },
508
+ "notification-url": "https://packagist.org/downloads/",
509
+ "license": [
510
+ "BSD-3-Clause"
511
+ ],
512
+ "authors": [
513
+ {
514
+ "name": "Sebastian Bergmann",
515
+ "email": "sb@sebastian-bergmann.de",
516
+ "role": "lead"
517
+ }
518
+ ],
519
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
520
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
521
+ "keywords": [
522
+ "coverage",
523
+ "testing",
524
+ "xunit"
525
+ ],
526
+ "time": "2015-10-06T15:47:00+00:00"
527
+ },
528
+ {
529
+ "name": "phpunit/php-file-iterator",
530
+ "version": "1.4.2",
531
+ "source": {
532
+ "type": "git",
533
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
534
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
535
+ },
536
+ "dist": {
537
+ "type": "zip",
538
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
539
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
540
+ "shasum": ""
541
+ },
542
+ "require": {
543
+ "php": ">=5.3.3"
544
+ },
545
+ "type": "library",
546
+ "extra": {
547
+ "branch-alias": {
548
+ "dev-master": "1.4.x-dev"
549
+ }
550
+ },
551
+ "autoload": {
552
+ "classmap": [
553
+ "src/"
554
+ ]
555
+ },
556
+ "notification-url": "https://packagist.org/downloads/",
557
+ "license": [
558
+ "BSD-3-Clause"
559
+ ],
560
+ "authors": [
561
+ {
562
+ "name": "Sebastian Bergmann",
563
+ "email": "sb@sebastian-bergmann.de",
564
+ "role": "lead"
565
+ }
566
+ ],
567
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
568
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
569
+ "keywords": [
570
+ "filesystem",
571
+ "iterator"
572
+ ],
573
+ "time": "2016-10-03T07:40:28+00:00"
574
+ },
575
+ {
576
+ "name": "phpunit/php-text-template",
577
+ "version": "1.2.1",
578
+ "source": {
579
+ "type": "git",
580
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
581
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
582
+ },
583
+ "dist": {
584
+ "type": "zip",
585
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
586
+ "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
587
+ "shasum": ""
588
+ },
589
+ "require": {
590
+ "php": ">=5.3.3"
591
+ },
592
+ "type": "library",
593
+ "autoload": {
594
+ "classmap": [
595
+ "src/"
596
+ ]
597
+ },
598
+ "notification-url": "https://packagist.org/downloads/",
599
+ "license": [
600
+ "BSD-3-Clause"
601
+ ],
602
+ "authors": [
603
+ {
604
+ "name": "Sebastian Bergmann",
605
+ "email": "sebastian@phpunit.de",
606
+ "role": "lead"
607
+ }
608
+ ],
609
+ "description": "Simple template engine.",
610
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
611
+ "keywords": [
612
+ "template"
613
+ ],
614
+ "time": "2015-06-21T13:50:34+00:00"
615
+ },
616
+ {
617
+ "name": "phpunit/php-timer",
618
+ "version": "1.0.9",
619
+ "source": {
620
+ "type": "git",
621
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
622
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
623
+ },
624
+ "dist": {
625
+ "type": "zip",
626
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
627
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
628
+ "shasum": ""
629
+ },
630
+ "require": {
631
+ "php": "^5.3.3 || ^7.0"
632
+ },
633
+ "require-dev": {
634
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
635
+ },
636
+ "type": "library",
637
+ "extra": {
638
+ "branch-alias": {
639
+ "dev-master": "1.0-dev"
640
+ }
641
+ },
642
+ "autoload": {
643
+ "classmap": [
644
+ "src/"
645
+ ]
646
+ },
647
+ "notification-url": "https://packagist.org/downloads/",
648
+ "license": [
649
+ "BSD-3-Clause"
650
+ ],
651
+ "authors": [
652
+ {
653
+ "name": "Sebastian Bergmann",
654
+ "email": "sb@sebastian-bergmann.de",
655
+ "role": "lead"
656
+ }
657
+ ],
658
+ "description": "Utility class for timing",
659
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
660
+ "keywords": [
661
+ "timer"
662
+ ],
663
+ "time": "2017-02-26T11:10:40+00:00"
664
+ },
665
+ {
666
+ "name": "phpunit/php-token-stream",
667
+ "version": "1.4.11",
668
+ "source": {
669
+ "type": "git",
670
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
671
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
672
+ },
673
+ "dist": {
674
+ "type": "zip",
675
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
676
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
677
+ "shasum": ""
678
+ },
679
+ "require": {
680
+ "ext-tokenizer": "*",
681
+ "php": ">=5.3.3"
682
+ },
683
+ "require-dev": {
684
+ "phpunit/phpunit": "~4.2"
685
+ },
686
+ "type": "library",
687
+ "extra": {
688
+ "branch-alias": {
689
+ "dev-master": "1.4-dev"
690
+ }
691
+ },
692
+ "autoload": {
693
+ "classmap": [
694
+ "src/"
695
+ ]
696
+ },
697
+ "notification-url": "https://packagist.org/downloads/",
698
+ "license": [
699
+ "BSD-3-Clause"
700
+ ],
701
+ "authors": [
702
+ {
703
+ "name": "Sebastian Bergmann",
704
+ "email": "sebastian@phpunit.de"
705
+ }
706
+ ],
707
+ "description": "Wrapper around PHP's tokenizer extension.",
708
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
709
+ "keywords": [
710
+ "tokenizer"
711
+ ],
712
+ "time": "2017-02-27T10:12:30+00:00"
713
+ },
714
+ {
715
+ "name": "phpunit/phpunit",
716
+ "version": "4.8.35",
717
+ "source": {
718
+ "type": "git",
719
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
720
+ "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87"
721
+ },
722
+ "dist": {
723
+ "type": "zip",
724
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/791b1a67c25af50e230f841ee7a9c6eba507dc87",
725
+ "reference": "791b1a67c25af50e230f841ee7a9c6eba507dc87",
726
+ "shasum": ""
727
+ },
728
+ "require": {
729
+ "ext-dom": "*",
730
+ "ext-json": "*",
731
+ "ext-pcre": "*",
732
+ "ext-reflection": "*",
733
+ "ext-spl": "*",
734
+ "php": ">=5.3.3",
735
+ "phpspec/prophecy": "^1.3.1",
736
+ "phpunit/php-code-coverage": "~2.1",
737
+ "phpunit/php-file-iterator": "~1.4",
738
+ "phpunit/php-text-template": "~1.2",
739
+ "phpunit/php-timer": "^1.0.6",
740
+ "phpunit/phpunit-mock-objects": "~2.3",
741
+ "sebastian/comparator": "~1.2.2",
742
+ "sebastian/diff": "~1.2",
743
+ "sebastian/environment": "~1.3",
744
+ "sebastian/exporter": "~1.2",
745
+ "sebastian/global-state": "~1.0",
746
+ "sebastian/version": "~1.0",
747
+ "symfony/yaml": "~2.1|~3.0"
748
+ },
749
+ "suggest": {
750
+ "phpunit/php-invoker": "~1.1"
751
+ },
752
+ "bin": [
753
+ "phpunit"
754
+ ],
755
+ "type": "library",
756
+ "extra": {
757
+ "branch-alias": {
758
+ "dev-master": "4.8.x-dev"
759
+ }
760
+ },
761
+ "autoload": {
762
+ "classmap": [
763
+ "src/"
764
+ ]
765
+ },
766
+ "notification-url": "https://packagist.org/downloads/",
767
+ "license": [
768
+ "BSD-3-Clause"
769
+ ],
770
+ "authors": [
771
+ {
772
+ "name": "Sebastian Bergmann",
773
+ "email": "sebastian@phpunit.de",
774
+ "role": "lead"
775
+ }
776
+ ],
777
+ "description": "The PHP Unit Testing framework.",
778
+ "homepage": "https://phpunit.de/",
779
+ "keywords": [
780
+ "phpunit",
781
+ "testing",
782
+ "xunit"
783
+ ],
784
+ "time": "2017-02-06T05:18:07+00:00"
785
+ },
786
+ {
787
+ "name": "phpunit/phpunit-mock-objects",
788
+ "version": "2.3.8",
789
+ "source": {
790
+ "type": "git",
791
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
792
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
793
+ },
794
+ "dist": {
795
+ "type": "zip",
796
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
797
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
798
+ "shasum": ""
799
+ },
800
+ "require": {
801
+ "doctrine/instantiator": "^1.0.2",
802
+ "php": ">=5.3.3",
803
+ "phpunit/php-text-template": "~1.2",
804
+ "sebastian/exporter": "~1.2"
805
+ },
806
+ "require-dev": {
807
+ "phpunit/phpunit": "~4.4"
808
+ },
809
+ "suggest": {
810
+ "ext-soap": "*"
811
+ },
812
+ "type": "library",
813
+ "extra": {
814
+ "branch-alias": {
815
+ "dev-master": "2.3.x-dev"
816
+ }
817
+ },
818
+ "autoload": {
819
+ "classmap": [
820
+ "src/"
821
+ ]
822
+ },
823
+ "notification-url": "https://packagist.org/downloads/",
824
+ "license": [
825
+ "BSD-3-Clause"
826
+ ],
827
+ "authors": [
828
+ {
829
+ "name": "Sebastian Bergmann",
830
+ "email": "sb@sebastian-bergmann.de",
831
+ "role": "lead"
832
+ }
833
+ ],
834
+ "description": "Mock Object library for PHPUnit",
835
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
836
+ "keywords": [
837
+ "mock",
838
+ "xunit"
839
+ ],
840
+ "time": "2015-10-02T06:51:40+00:00"
841
+ },
842
+ {
843
+ "name": "sebastian/comparator",
844
+ "version": "1.2.4",
845
+ "source": {
846
+ "type": "git",
847
+ "url": "https://github.com/sebastianbergmann/comparator.git",
848
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
849
+ },
850
+ "dist": {
851
+ "type": "zip",
852
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
853
+ "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
854
+ "shasum": ""
855
+ },
856
+ "require": {
857
+ "php": ">=5.3.3",
858
+ "sebastian/diff": "~1.2",
859
+ "sebastian/exporter": "~1.2 || ~2.0"
860
+ },
861
+ "require-dev": {
862
+ "phpunit/phpunit": "~4.4"
863
+ },
864
+ "type": "library",
865
+ "extra": {
866
+ "branch-alias": {
867
+ "dev-master": "1.2.x-dev"
868
+ }
869
+ },
870
+ "autoload": {
871
+ "classmap": [
872
+ "src/"
873
+ ]
874
+ },
875
+ "notification-url": "https://packagist.org/downloads/",
876
+ "license": [
877
+ "BSD-3-Clause"
878
+ ],
879
+ "authors": [
880
+ {
881
+ "name": "Jeff Welch",
882
+ "email": "whatthejeff@gmail.com"
883
+ },
884
+ {
885
+ "name": "Volker Dusch",
886
+ "email": "github@wallbash.com"
887
+ },
888
+ {
889
+ "name": "Bernhard Schussek",
890
+ "email": "bschussek@2bepublished.at"
891
+ },
892
+ {
893
+ "name": "Sebastian Bergmann",
894
+ "email": "sebastian@phpunit.de"
895
+ }
896
+ ],
897
+ "description": "Provides the functionality to compare PHP values for equality",
898
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
899
+ "keywords": [
900
+ "comparator",
901
+ "compare",
902
+ "equality"
903
+ ],
904
+ "time": "2017-01-29T09:50:25+00:00"
905
+ },
906
+ {
907
+ "name": "sebastian/diff",
908
+ "version": "1.4.3",
909
+ "source": {
910
+ "type": "git",
911
+ "url": "https://github.com/sebastianbergmann/diff.git",
912
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
913
+ },
914
+ "dist": {
915
+ "type": "zip",
916
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
917
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
918
+ "shasum": ""
919
+ },
920
+ "require": {
921
+ "php": "^5.3.3 || ^7.0"
922
+ },
923
+ "require-dev": {
924
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
925
+ },
926
+ "type": "library",
927
+ "extra": {
928
+ "branch-alias": {
929
+ "dev-master": "1.4-dev"
930
+ }
931
+ },
932
+ "autoload": {
933
+ "classmap": [
934
+ "src/"
935
+ ]
936
+ },
937
+ "notification-url": "https://packagist.org/downloads/",
938
+ "license": [
939
+ "BSD-3-Clause"
940
+ ],
941
+ "authors": [
942
+ {
943
+ "name": "Kore Nordmann",
944
+ "email": "mail@kore-nordmann.de"
945
+ },
946
+ {
947
+ "name": "Sebastian Bergmann",
948
+ "email": "sebastian@phpunit.de"
949
+ }
950
+ ],
951
+ "description": "Diff implementation",
952
+ "homepage": "https://github.com/sebastianbergmann/diff",
953
+ "keywords": [
954
+ "diff"
955
+ ],
956
+ "time": "2017-05-22T07:24:03+00:00"
957
+ },
958
+ {
959
+ "name": "sebastian/environment",
960
+ "version": "1.3.8",
961
+ "source": {
962
+ "type": "git",
963
+ "url": "https://github.com/sebastianbergmann/environment.git",
964
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
965
+ },
966
+ "dist": {
967
+ "type": "zip",
968
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
969
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
970
+ "shasum": ""
971
+ },
972
+ "require": {
973
+ "php": "^5.3.3 || ^7.0"
974
+ },
975
+ "require-dev": {
976
+ "phpunit/phpunit": "^4.8 || ^5.0"
977
+ },
978
+ "type": "library",
979
+ "extra": {
980
+ "branch-alias": {
981
+ "dev-master": "1.3.x-dev"
982
+ }
983
+ },
984
+ "autoload": {
985
+ "classmap": [
986
+ "src/"
987
+ ]
988
+ },
989
+ "notification-url": "https://packagist.org/downloads/",
990
+ "license": [
991
+ "BSD-3-Clause"
992
+ ],
993
+ "authors": [
994
+ {
995
+ "name": "Sebastian Bergmann",
996
+ "email": "sebastian@phpunit.de"
997
+ }
998
+ ],
999
+ "description": "Provides functionality to handle HHVM/PHP environments",
1000
+ "homepage": "http://www.github.com/sebastianbergmann/environment",
1001
+ "keywords": [
1002
+ "Xdebug",
1003
+ "environment",
1004
+ "hhvm"
1005
+ ],
1006
+ "time": "2016-08-18T05:49:44+00:00"
1007
+ },
1008
+ {
1009
+ "name": "sebastian/exporter",
1010
+ "version": "1.2.2",
1011
+ "source": {
1012
+ "type": "git",
1013
+ "url": "https://github.com/sebastianbergmann/exporter.git",
1014
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
1015
+ },
1016
+ "dist": {
1017
+ "type": "zip",
1018
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
1019
+ "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
1020
+ "shasum": ""
1021
+ },
1022
+ "require": {
1023
+ "php": ">=5.3.3",
1024
+ "sebastian/recursion-context": "~1.0"
1025
+ },
1026
+ "require-dev": {
1027
+ "ext-mbstring": "*",
1028
+ "phpunit/phpunit": "~4.4"
1029
+ },
1030
+ "type": "library",
1031
+ "extra": {
1032
+ "branch-alias": {
1033
+ "dev-master": "1.3.x-dev"
1034
+ }
1035
+ },
1036
+ "autoload": {
1037
+ "classmap": [
1038
+ "src/"
1039
+ ]
1040
+ },
1041
+ "notification-url": "https://packagist.org/downloads/",
1042
+ "license": [
1043
+ "BSD-3-Clause"
1044
+ ],
1045
+ "authors": [
1046
+ {
1047
+ "name": "Jeff Welch",
1048
+ "email": "whatthejeff@gmail.com"
1049
+ },
1050
+ {
1051
+ "name": "Volker Dusch",
1052
+ "email": "github@wallbash.com"
1053
+ },
1054
+ {
1055
+ "name": "Bernhard Schussek",
1056
+ "email": "bschussek@2bepublished.at"
1057
+ },
1058
+ {
1059
+ "name": "Sebastian Bergmann",
1060
+ "email": "sebastian@phpunit.de"
1061
+ },
1062
+ {
1063
+ "name": "Adam Harvey",
1064
+ "email": "aharvey@php.net"
1065
+ }
1066
+ ],
1067
+ "description": "Provides the functionality to export PHP variables for visualization",
1068
+ "homepage": "http://www.github.com/sebastianbergmann/exporter",
1069
+ "keywords": [
1070
+ "export",
1071
+ "exporter"
1072
+ ],
1073
+ "time": "2016-06-17T09:04:28+00:00"
1074
+ },
1075
+ {
1076
+ "name": "sebastian/global-state",
1077
+ "version": "1.1.1",
1078
+ "source": {
1079
+ "type": "git",
1080
+ "url": "https://github.com/sebastianbergmann/global-state.git",
1081
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
1082
+ },
1083
+ "dist": {
1084
+ "type": "zip",
1085
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
1086
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
1087
+ "shasum": ""
1088
+ },
1089
+ "require": {
1090
+ "php": ">=5.3.3"
1091
+ },
1092
+ "require-dev": {
1093
+ "phpunit/phpunit": "~4.2"
1094
+ },
1095
+ "suggest": {
1096
+ "ext-uopz": "*"
1097
+ },
1098
+ "type": "library",
1099
+ "extra": {
1100
+ "branch-alias": {
1101
+ "dev-master": "1.0-dev"
1102
+ }
1103
+ },
1104
+ "autoload": {
1105
+ "classmap": [
1106
+ "src/"
1107
+ ]
1108
+ },
1109
+ "notification-url": "https://packagist.org/downloads/",
1110
+ "license": [
1111
+ "BSD-3-Clause"
1112
+ ],
1113
+ "authors": [
1114
+ {
1115
+ "name": "Sebastian Bergmann",
1116
+ "email": "sebastian@phpunit.de"
1117
+ }
1118
+ ],
1119
+ "description": "Snapshotting of global state",
1120
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
1121
+ "keywords": [
1122
+ "global state"
1123
+ ],
1124
+ "time": "2015-10-12T03:26:01+00:00"
1125
+ },
1126
+ {
1127
+ "name": "sebastian/recursion-context",
1128
+ "version": "1.0.5",
1129
+ "source": {
1130
+ "type": "git",
1131
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
1132
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
1133
+ },
1134
+ "dist": {
1135
+ "type": "zip",
1136
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
1137
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
1138
+ "shasum": ""
1139
+ },
1140
+ "require": {
1141
+ "php": ">=5.3.3"
1142
+ },
1143
+ "require-dev": {
1144
+ "phpunit/phpunit": "~4.4"
1145
+ },
1146
+ "type": "library",
1147
+ "extra": {
1148
+ "branch-alias": {
1149
+ "dev-master": "1.0.x-dev"
1150
+ }
1151
+ },
1152
+ "autoload": {
1153
+ "classmap": [
1154
+ "src/"
1155
+ ]
1156
+ },
1157
+ "notification-url": "https://packagist.org/downloads/",
1158
+ "license": [
1159
+ "BSD-3-Clause"
1160
+ ],
1161
+ "authors": [
1162
+ {
1163
+ "name": "Jeff Welch",
1164
+ "email": "whatthejeff@gmail.com"
1165
+ },
1166
+ {
1167
+ "name": "Sebastian Bergmann",
1168
+ "email": "sebastian@phpunit.de"
1169
+ },
1170
+ {
1171
+ "name": "Adam Harvey",
1172
+ "email": "aharvey@php.net"
1173
+ }
1174
+ ],
1175
+ "description": "Provides functionality to recursively process PHP variables",
1176
+ "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1177
+ "time": "2016-10-03T07:41:43+00:00"
1178
+ },
1179
+ {
1180
+ "name": "sebastian/version",
1181
+ "version": "1.0.6",
1182
+ "source": {
1183
+ "type": "git",
1184
+ "url": "https://github.com/sebastianbergmann/version.git",
1185
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
1186
+ },
1187
+ "dist": {
1188
+ "type": "zip",
1189
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1190
+ "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1191
+ "shasum": ""
1192
+ },
1193
+ "type": "library",
1194
+ "autoload": {
1195
+ "classmap": [
1196
+ "src/"
1197
+ ]
1198
+ },
1199
+ "notification-url": "https://packagist.org/downloads/",
1200
+ "license": [
1201
+ "BSD-3-Clause"
1202
+ ],
1203
+ "authors": [
1204
+ {
1205
+ "name": "Sebastian Bergmann",
1206
+ "email": "sebastian@phpunit.de",
1207
+ "role": "lead"
1208
+ }
1209
+ ],
1210
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1211
+ "homepage": "https://github.com/sebastianbergmann/version",
1212
+ "time": "2015-06-21T13:59:46+00:00"
1213
+ },
1214
+ {
1215
+ "name": "symfony/yaml",
1216
+ "version": "v3.2.8",
1217
+ "source": {
1218
+ "type": "git",
1219
+ "url": "https://github.com/symfony/yaml.git",
1220
+ "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6"
1221
+ },
1222
+ "dist": {
1223
+ "type": "zip",
1224
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6",
1225
+ "reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6",
1226
+ "shasum": ""
1227
+ },
1228
+ "require": {
1229
+ "php": ">=5.5.9"
1230
+ },
1231
+ "require-dev": {
1232
+ "symfony/console": "~2.8|~3.0"
1233
+ },
1234
+ "suggest": {
1235
+ "symfony/console": "For validating YAML files using the lint command"
1236
+ },
1237
+ "type": "library",
1238
+ "extra": {
1239
+ "branch-alias": {
1240
+ "dev-master": "3.2-dev"
1241
+ }
1242
+ },
1243
+ "autoload": {
1244
+ "psr-4": {
1245
+ "Symfony\\Component\\Yaml\\": ""
1246
+ },
1247
+ "exclude-from-classmap": [
1248
+ "/Tests/"
1249
+ ]
1250
+ },
1251
+ "notification-url": "https://packagist.org/downloads/",
1252
+ "license": [
1253
+ "MIT"
1254
+ ],
1255
+ "authors": [
1256
+ {
1257
+ "name": "Fabien Potencier",
1258
+ "email": "fabien@symfony.com"
1259
+ },
1260
+ {
1261
+ "name": "Symfony Community",
1262
+ "homepage": "https://symfony.com/contributors"
1263
+ }
1264
+ ],
1265
+ "description": "Symfony Yaml Component",
1266
+ "homepage": "https://symfony.com",
1267
+ "time": "2017-05-01T14:55:58+00:00"
1268
+ },
1269
+ {
1270
+ "name": "webmozart/assert",
1271
+ "version": "1.2.0",
1272
+ "source": {
1273
+ "type": "git",
1274
+ "url": "https://github.com/webmozart/assert.git",
1275
+ "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
1276
+ },
1277
+ "dist": {
1278
+ "type": "zip",
1279
+ "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
1280
+ "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
1281
+ "shasum": ""
1282
+ },
1283
+ "require": {
1284
+ "php": "^5.3.3 || ^7.0"
1285
+ },
1286
+ "require-dev": {
1287
+ "phpunit/phpunit": "^4.6",
1288
+ "sebastian/version": "^1.0.1"
1289
+ },
1290
+ "type": "library",
1291
+ "extra": {
1292
+ "branch-alias": {
1293
+ "dev-master": "1.3-dev"
1294
+ }
1295
+ },
1296
+ "autoload": {
1297
+ "psr-4": {
1298
+ "Webmozart\\Assert\\": "src/"
1299
+ }
1300
+ },
1301
+ "notification-url": "https://packagist.org/downloads/",
1302
+ "license": [
1303
+ "MIT"
1304
+ ],
1305
+ "authors": [
1306
+ {
1307
+ "name": "Bernhard Schussek",
1308
+ "email": "bschussek@gmail.com"
1309
+ }
1310
+ ],
1311
+ "description": "Assertions to validate method input/output with nice error messages.",
1312
+ "keywords": [
1313
+ "assert",
1314
+ "check",
1315
+ "validate"
1316
+ ],
1317
+ "time": "2016-11-23T20:04:58+00:00"
1318
+ }
1319
+ ],
1320
+ "aliases": [],
1321
+ "minimum-stability": "stable",
1322
+ "stability-flags": [],
1323
+ "prefer-stable": false,
1324
+ "prefer-lowest": false,
1325
+ "platform": {
1326
+ "php": "^5.4 || ^7.0"
1327
+ },
1328
+ "platform-dev": []
1329
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-override-styling.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ require_once __DIR__ . '/../vendor/autoload.php';
11
+
12
+ use Facebook\InstantArticles\AMP\AMPArticle;
13
+
14
+ // Prevents the logger from dumping too much info, check the file for details
15
+ include __DIR__ . '/quiet_logger.php';
16
+
17
+ // Load instant article file into string
18
+ $instant_article_string = file_get_contents(__DIR__.'/instant-article-example.html');
19
+
20
+ // Loads from a file or even you could load from the graph API style Editor.
21
+ $styleGotFromSomewhereElse = file_get_contents(__DIR__.'/styles/style-got-from-somewhereelse.json');
22
+
23
+ $properties = array(
24
+ // Overrides any style linked from the Instant Article, this might be useful if you want to apply a different style than the one in specified Instant Articles.
25
+ 'override-styles' => json_decode($styleGotFromSomewhereElse, true)
26
+ );
27
+
28
+ // Converts it into AMP
29
+ $amp_string = AMPArticle::create($instant_article_string, $properties)->render();
30
+
31
+ print($amp_string);
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-quick-start.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ require_once __DIR__ . '/../vendor/autoload.php';
11
+
12
+ // Prevents the logger from dumping too much info, check the file for details
13
+ include __DIR__ . '/quiet_logger.php';
14
+
15
+ use Facebook\InstantArticles\AMP\AMPArticle;
16
+
17
+ // Load instant article file into string
18
+ $instant_article_string = file_get_contents(__DIR__.'/instant-article-example.html');
19
+
20
+ // Instant articles have no width and height information for images and video on
21
+ // it's markup but the AMP spec requires everything to have explicit sizing.
22
+
23
+ // This will hold our custom properties
24
+ $properties = array();
25
+
26
+ // Videos require explicit sizing, if you fail to provide it, the default values
27
+ // may distort your Videos
28
+ $properties[AMPArticle::MEDIA_SIZES_KEY]
29
+ ['http://mydomain.com/path/to/video.mp4'] = array(320, 240);
30
+
31
+ // Images can also be passed
32
+ // IMPORTANT: The image will not have fixed-width, but it will respect the
33
+ // aspect ration provided here. They are using the responsive layout
34
+ $properties[AMPArticle::MEDIA_SIZES_KEY]
35
+ ['http://mydomain.com/path/to/crazy.jpg'] = array(640, 480);
36
+
37
+ // The SDK can automatically download the images and get their sizes if they are not
38
+ // in the array above, if you enable the following option.
39
+ //
40
+ // WARNING: THIS MAY LEAD TO EXCESSIVE DOWNLOADING - USE WITH CAUTION
41
+ // WE STRONGLY RECOMMEND YOU TO PASS THE IMAGE SIZING VIA THE
42
+ // $properties[AMPArticle::MEDIA_SIZES_KEY] ARRAY
43
+ //
44
+ // You can check in the markup that the image fb_icon_325x325.png
45
+ // has the correct 325x325 size after enabling this option.
46
+ $properties[AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY] = true;
47
+
48
+ // AMP has its own format for setting tracking pixels and/or analytics calls.
49
+ // You can provide a list of one or more strings containing the markup for
50
+ // the <amp-analytics> or <amp pixel> tags to the following option.
51
+ //
52
+ // See also the AMP specs for these tags:
53
+ // - https://www.ampproject.org/docs/reference/components/amp-analytics
54
+ // - https://www.ampproject.org/docs/reference/components/amp-pixel
55
+ $properties[AMPArticle::ANALYTICS_KEY] = array(
56
+ '<amp-pixel src="http://mydomain.com/my_tracking_pixel.gif">',
57
+ '<amp-analytics config="https://mydomain.com/analytics.config.json"></amp-analytics>'
58
+ );
59
+
60
+ // Converts it into AMP
61
+ $amp_string =
62
+ AMPArticle::create($instant_article_string, $properties)->render();
63
+
64
+ print($amp_string);
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/example-simple-styling.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ require_once __DIR__ . '/../vendor/autoload.php';
11
+
12
+ use Facebook\InstantArticles\AMP\AMPArticle;
13
+
14
+ // Prevents the logger from dumping too much info, check the file for details
15
+ include __DIR__ . '/quiet_logger.php';
16
+
17
+ // Load instant article file into string
18
+ $instant_article_string = file_get_contents(__DIR__.'/instant-article-example.html');
19
+ $properties = array(
20
+ 'lang' => 'en-US', // You can set the language your article have
21
+ 'styles-folder' => __DIR__.'/styles' // Where the styles are stored
22
+ );
23
+
24
+ /*
25
+ As the name of the style used within the Instant article refers to <code>"gray"</code>, the
26
+ file within directory <code>/styles</code> will be the <code>/styles/gray.style.json.</code>
27
+ */
28
+
29
+ // Converts it into AMP
30
+ $amp_string = AMPArticle::create($instant_article_string, $properties)->render();
31
+
32
+ print($amp_string);
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/instant-article-example.html ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en" prefix="op: http://media.facebook.com/op#">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <!-- URL of the web version of this article -->
6
+ <link rel="canonical" href="http://example.com/article.html">
7
+ <meta property="op:markup_version" content="v1.0">
8
+ <meta property="fb:article_style" content="gray">
9
+ </head>
10
+ <body>
11
+ <article>
12
+ <header>
13
+ <!-- The title and subtitle shown in your Instant Article -->
14
+ <h1>Article Title</h1>
15
+ <h2>Article Subtitle</h2>
16
+
17
+ <!-- The date and time when your article was originally published -->
18
+ <time class="op-published" datetime="2014-11-11T04:44:16Z">November 11th, 4:44 PM</time>
19
+
20
+ <!-- The date and time when your article was last updated -->
21
+ <time class="op-modified" dateTime="2014-12-11T04:44:16Z">December 11th, 4:44 PM</time>
22
+
23
+ <!-- The authors of your article -->
24
+ <address>
25
+ <a rel="facebook" href="http://facebook.com/brandon.diamond">Brandon Diamond</a>
26
+ Brandon is an avid zombie hunter.
27
+ </address>
28
+ <address>
29
+ <a>TR Vishwanath</a>
30
+ Vish is a scholar and a gentleman.
31
+ </address>
32
+
33
+ <!-- The cover image shown inside your article -->
34
+ <figure>
35
+ <img src="http://mydomain.com/path/to/cover_img.jpg" />
36
+ <figcaption>This image is amazing</figcaption>
37
+ </figure>
38
+
39
+ <!-- A kicker for your article -->
40
+ <h3 class="op-kicker">
41
+ This is a kicker
42
+ </h3>
43
+
44
+ </header>
45
+
46
+ <!-- Article body goes here -->
47
+
48
+ <!-- Body text for your article -->
49
+ <p> Article content </p>
50
+
51
+ <!-- A video within your article -->
52
+ <figure>
53
+ <video>
54
+ <source src="http://mydomain.com/path/to/video.mp4" type="video/mp4" />
55
+ </video>
56
+ </figure>
57
+
58
+ <!-- An ad within your article -->
59
+ <figure class="op-ad">
60
+ <iframe src="https://www.adserver.com/ss;adtype=banner320x50" height="60" width="320"></iframe>
61
+ </figure>
62
+
63
+ <!-- Image hotlinked from some other domain -->
64
+ <figure>
65
+ <img src="https://www.facebook.com/images/fb_icon_325x325.png" />
66
+ <figcaption>Like it!</figcaption>
67
+ </figure>
68
+
69
+ <!-- Image -->
70
+ <figure>
71
+ <img src="http://mydomain.com/path/to/crazy.jpg" />
72
+ <figcaption>This is crazy</figcaption>
73
+ </figure>
74
+
75
+ <!-- Analytics code for your article -->
76
+ <figure class="op-tracker">
77
+ <iframe src="" hidden></iframe>
78
+ </figure>
79
+
80
+ <footer>
81
+ <!-- Credits for your article -->
82
+ <aside>Acknowledgements</aside>
83
+
84
+ <!-- Copyright details for your article -->
85
+ <small>Legal notes</small>
86
+ </footer>
87
+ </article>
88
+ </body>
89
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/quiet_logger.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ \Logger::configure(
4
+ [
5
+ 'rootLogger' => [
6
+ 'appenders' => ['facebook-instantarticles-traverser']
7
+ ],
8
+ 'appenders' => [
9
+ 'facebook-instantarticles-traverser' => [
10
+ 'class' => 'LoggerAppenderConsole',
11
+ 'threshold' => 'INFO',
12
+ 'layout' => [
13
+ 'class' => 'LoggerLayoutSimple'
14
+ ]
15
+ ]
16
+ ]
17
+ ]
18
+ );
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/styles/gray.style.json ADDED
@@ -0,0 +1,993 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#EEEEEE",
3
+ "header": {
4
+ "logo": {
5
+ "dataURL": null,
6
+ "id": "1229084557204785",
7
+ "full_resolution_url": "https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&oh=c8337650a88e7fdb6d31088a15a7d9d8&oe=599B24B5&__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8",
8
+ "full_resolution_width": 2600,
9
+ "full_resolution_height": 512,
10
+ "thumbnail_url": "https://fb-s-d-a.akamaihd.net/h-ak-xpf1/v/t39.5687-6/17634152_1374280939304404_1278222734471462912_n.png?_nc_log=1&oh=d3e95b10e960a9527ad643c47d821160&oe=598664D5&__gda__=1498346669_5ee6f5a2bd8d17474bfb46398d9b888a",
11
+ "article_scaling_factor": 1
12
+ },
13
+ "logo_scale": 1,
14
+ "accent_color": "#000000",
15
+ "background_color": "#666666",
16
+ "bar_color": null
17
+ },
18
+ "kicker": {
19
+ "font": "Helvetica Neue",
20
+ "color": "#000000",
21
+ "background_color": "#00FFFFFF",
22
+ "capitalization": "ALL_CAPS",
23
+ "text_alignment": "LEFT",
24
+ "display": "INLINE",
25
+ "line_height_scale": 1,
26
+ "text_size_scale": 1,
27
+ "margin": {
28
+ "right": {
29
+ "scaling_factor": 1,
30
+ "size": "DOCUMENT_MARGIN"
31
+ },
32
+ "left": {
33
+ "scaling_factor": 1,
34
+ "size": "DOCUMENT_MARGIN"
35
+ }
36
+ },
37
+ "border": {
38
+ "top": {
39
+ "width": 0
40
+ },
41
+ "right": {
42
+ "width": 0
43
+ },
44
+ "bottom": {
45
+ "width": 0
46
+ },
47
+ "left": {
48
+ "width": 0
49
+ }
50
+ },
51
+ "padding": {
52
+ "top": {
53
+ "scaling_factor": 1,
54
+ "size": "NONE"
55
+ },
56
+ "right": {
57
+ "scaling_factor": 1,
58
+ "size": "NONE"
59
+ },
60
+ "bottom": {
61
+ "scaling_factor": 1,
62
+ "size": "NONE"
63
+ },
64
+ "left": {
65
+ "scaling_factor": 1,
66
+ "size": "NONE"
67
+ }
68
+ }
69
+ },
70
+ "title": {
71
+ "font": "Georgia",
72
+ "color": "#000000",
73
+ "background_color": "#00FFFFFF",
74
+ "capitalization": "NONE",
75
+ "text_alignment": "LEFT",
76
+ "display": "INLINE",
77
+ "line_height_scale": 1,
78
+ "text_size_scale": 1,
79
+ "margin": {
80
+ "right": {
81
+ "scaling_factor": 1,
82
+ "size": "DOCUMENT_MARGIN"
83
+ },
84
+ "left": {
85
+ "scaling_factor": 1,
86
+ "size": "DOCUMENT_MARGIN"
87
+ }
88
+ },
89
+ "border": {
90
+ "top": {
91
+ "width": 0
92
+ },
93
+ "right": {
94
+ "width": 0
95
+ },
96
+ "bottom": {
97
+ "width": 0
98
+ },
99
+ "left": {
100
+ "width": 0
101
+ }
102
+ },
103
+ "padding": {
104
+ "top": {
105
+ "scaling_factor": 1,
106
+ "size": "NONE"
107
+ },
108
+ "right": {
109
+ "scaling_factor": 1,
110
+ "size": "NONE"
111
+ },
112
+ "bottom": {
113
+ "scaling_factor": 1,
114
+ "size": "NONE"
115
+ },
116
+ "left": {
117
+ "scaling_factor": 1,
118
+ "size": "NONE"
119
+ }
120
+ }
121
+ },
122
+ "subtitle": {
123
+ "font": "Georgia",
124
+ "color": "#000000",
125
+ "background_color": "#00FFFFFF",
126
+ "capitalization": "NONE",
127
+ "text_alignment": "LEFT",
128
+ "display": "INLINE",
129
+ "line_height_scale": 1,
130
+ "text_size_scale": 1,
131
+ "margin": {
132
+ "right": {
133
+ "scaling_factor": 1,
134
+ "size": "DOCUMENT_MARGIN"
135
+ },
136
+ "left": {
137
+ "scaling_factor": 1,
138
+ "size": "DOCUMENT_MARGIN"
139
+ }
140
+ },
141
+ "border": {
142
+ "top": {
143
+ "width": 0
144
+ },
145
+ "right": {
146
+ "width": 0
147
+ },
148
+ "bottom": {
149
+ "width": 0
150
+ },
151
+ "left": {
152
+ "width": 0
153
+ }
154
+ },
155
+ "padding": {
156
+ "top": {
157
+ "scaling_factor": 1,
158
+ "size": "NONE"
159
+ },
160
+ "right": {
161
+ "scaling_factor": 1,
162
+ "size": "NONE"
163
+ },
164
+ "bottom": {
165
+ "scaling_factor": 1,
166
+ "size": "NONE"
167
+ },
168
+ "left": {
169
+ "scaling_factor": 1,
170
+ "size": "NONE"
171
+ }
172
+ }
173
+ },
174
+ "byline": {
175
+ "font": "Helvetica Neue",
176
+ "color": "#000000",
177
+ "capitalization": "ALL_CAPS",
178
+ "text_alignment": "LEFT",
179
+ "line_height_scale": 1,
180
+ "text_size_scale": 1,
181
+ "margin": {
182
+ "right": {
183
+ "scaling_factor": 1,
184
+ "size": "DOCUMENT_MARGIN"
185
+ },
186
+ "left": {
187
+ "scaling_factor": 1,
188
+ "size": "DOCUMENT_MARGIN"
189
+ }
190
+ }
191
+ },
192
+ "date_style": "MONTH_DAY_YEAR",
193
+ "primary_heading": {
194
+ "font": "Georgia",
195
+ "color": "#000000",
196
+ "background_color": "#00FFFFFF",
197
+ "capitalization": "NONE",
198
+ "text_alignment": "LEFT",
199
+ "display": "INLINE",
200
+ "line_height_scale": 1,
201
+ "text_size_scale": 1,
202
+ "margin": {
203
+ "right": {
204
+ "scaling_factor": 1,
205
+ "size": "DOCUMENT_MARGIN"
206
+ },
207
+ "left": {
208
+ "scaling_factor": 1,
209
+ "size": "DOCUMENT_MARGIN"
210
+ }
211
+ },
212
+ "border": {
213
+ "top": {
214
+ "width": 0
215
+ },
216
+ "right": {
217
+ "width": 0
218
+ },
219
+ "bottom": {
220
+ "width": 0
221
+ },
222
+ "left": {
223
+ "width": 0
224
+ }
225
+ },
226
+ "padding": {
227
+ "top": {
228
+ "scaling_factor": 1,
229
+ "size": "NONE"
230
+ },
231
+ "right": {
232
+ "scaling_factor": 1,
233
+ "size": "NONE"
234
+ },
235
+ "bottom": {
236
+ "scaling_factor": 1,
237
+ "size": "NONE"
238
+ },
239
+ "left": {
240
+ "scaling_factor": 1,
241
+ "size": "NONE"
242
+ }
243
+ }
244
+ },
245
+ "secondary_heading": {
246
+ "font": "Georgia",
247
+ "color": "#000000",
248
+ "background_color": "#00FFFFFF",
249
+ "capitalization": "NONE",
250
+ "text_alignment": "LEFT",
251
+ "display": "INLINE",
252
+ "line_height_scale": 1,
253
+ "text_size_scale": 1,
254
+ "margin": {
255
+ "right": {
256
+ "scaling_factor": 1,
257
+ "size": "DOCUMENT_MARGIN"
258
+ },
259
+ "left": {
260
+ "scaling_factor": 1,
261
+ "size": "DOCUMENT_MARGIN"
262
+ }
263
+ },
264
+ "border": {
265
+ "top": {
266
+ "width": 0
267
+ },
268
+ "right": {
269
+ "width": 0
270
+ },
271
+ "bottom": {
272
+ "width": 0
273
+ },
274
+ "left": {
275
+ "width": 0
276
+ }
277
+ },
278
+ "padding": {
279
+ "top": {
280
+ "scaling_factor": 1,
281
+ "size": "NONE"
282
+ },
283
+ "right": {
284
+ "scaling_factor": 1,
285
+ "size": "NONE"
286
+ },
287
+ "bottom": {
288
+ "scaling_factor": 1,
289
+ "size": "NONE"
290
+ },
291
+ "left": {
292
+ "scaling_factor": 1,
293
+ "size": "NONE"
294
+ }
295
+ }
296
+ },
297
+ "body_text": {
298
+ "font": "Georgia",
299
+ "color": "#000000",
300
+ "capitalization": "NONE",
301
+ "text_alignment": "LEFT",
302
+ "line_height_scale": 1,
303
+ "text_size_scale": 1,
304
+ "margin": {
305
+ "right": {
306
+ "scaling_factor": 1,
307
+ "size": "DOCUMENT_MARGIN"
308
+ },
309
+ "left": {
310
+ "scaling_factor": 1,
311
+ "size": "DOCUMENT_MARGIN"
312
+ }
313
+ }
314
+ },
315
+ "inline_link": {
316
+ "color": "#000000",
317
+ "underline": "SIMPLE_UNDERLINE",
318
+ "font": "Georgia"
319
+ },
320
+ "block_quote": {
321
+ "font": "Georgia",
322
+ "color": "#000000",
323
+ "background_color": "#00FFFFFF",
324
+ "capitalization": "NONE",
325
+ "text_alignment": "LEFT",
326
+ "display": "BLOCK",
327
+ "line_height_scale": 1,
328
+ "text_size_scale": 1,
329
+ "margin": {
330
+ "right": {
331
+ "scaling_factor": 1,
332
+ "size": "DOCUMENT_MARGIN"
333
+ },
334
+ "left": {
335
+ "scaling_factor": 1,
336
+ "size": "DOCUMENT_MARGIN"
337
+ }
338
+ },
339
+ "border": {
340
+ "top": {
341
+ "color": "#000000",
342
+ "width": 0
343
+ },
344
+ "right": {
345
+ "color": "#000000",
346
+ "width": 0
347
+ },
348
+ "bottom": {
349
+ "color": "#000000",
350
+ "width": 0
351
+ },
352
+ "left": {
353
+ "color": "#000000",
354
+ "width": 2
355
+ }
356
+ },
357
+ "padding": {
358
+ "top": {
359
+ "scaling_factor": 1,
360
+ "size": "NONE"
361
+ },
362
+ "right": {
363
+ "scaling_factor": 1,
364
+ "size": "SMALL"
365
+ },
366
+ "bottom": {
367
+ "scaling_factor": 1,
368
+ "size": "NONE"
369
+ },
370
+ "left": {
371
+ "scaling_factor": 1,
372
+ "size": "MEDIUM"
373
+ }
374
+ }
375
+ },
376
+ "pull_quote": {
377
+ "font": "Georgia",
378
+ "color": "#000000",
379
+ "background_color": "#00FFFFFF",
380
+ "capitalization": "NONE",
381
+ "text_alignment": "LEFT",
382
+ "display": "INLINE",
383
+ "line_height_scale": 1,
384
+ "text_size_scale": 1,
385
+ "margin": {
386
+ "right": {
387
+ "scaling_factor": 1,
388
+ "size": "DOCUMENT_MARGIN"
389
+ },
390
+ "left": {
391
+ "scaling_factor": 1,
392
+ "size": "DOCUMENT_MARGIN"
393
+ }
394
+ },
395
+ "border": {
396
+ "top": {
397
+ "width": 0
398
+ },
399
+ "right": {
400
+ "width": 0
401
+ },
402
+ "bottom": {
403
+ "width": 0
404
+ },
405
+ "left": {
406
+ "width": 0
407
+ }
408
+ },
409
+ "padding": {
410
+ "top": {
411
+ "scaling_factor": 1,
412
+ "size": "NONE"
413
+ },
414
+ "right": {
415
+ "scaling_factor": 1,
416
+ "size": "NONE"
417
+ },
418
+ "bottom": {
419
+ "scaling_factor": 1,
420
+ "size": "NONE"
421
+ },
422
+ "left": {
423
+ "scaling_factor": 1,
424
+ "size": "NONE"
425
+ }
426
+ }
427
+ },
428
+ "pull_quote_attribution": {
429
+ "font": "Helvetica Neue",
430
+ "color": "#000000",
431
+ "background_color": "#00FFFFFF",
432
+ "capitalization": "ALL_CAPS",
433
+ "text_alignment": "LEFT",
434
+ "display": "INLINE",
435
+ "line_height_scale": 1,
436
+ "text_size_scale": 1,
437
+ "margin": {
438
+ "right": {
439
+ "scaling_factor": 1,
440
+ "size": "DOCUMENT_MARGIN"
441
+ },
442
+ "left": {
443
+ "scaling_factor": 1,
444
+ "size": "DOCUMENT_MARGIN"
445
+ }
446
+ },
447
+ "border": {
448
+ "top": {
449
+ "width": 0
450
+ },
451
+ "right": {
452
+ "width": 0
453
+ },
454
+ "bottom": {
455
+ "width": 0
456
+ },
457
+ "left": {
458
+ "width": 0
459
+ }
460
+ },
461
+ "padding": {
462
+ "top": {
463
+ "scaling_factor": 1,
464
+ "size": "NONE"
465
+ },
466
+ "right": {
467
+ "scaling_factor": 1,
468
+ "size": "NONE"
469
+ },
470
+ "bottom": {
471
+ "scaling_factor": 1,
472
+ "size": "NONE"
473
+ },
474
+ "left": {
475
+ "scaling_factor": 1,
476
+ "size": "NONE"
477
+ }
478
+ }
479
+ },
480
+ "caption_title_small": {
481
+ "font": "Helvetica Neue Bold",
482
+ "color": "#808080",
483
+ "background_color": "#00FFFF",
484
+ "capitalization": "NONE",
485
+ "display": "INLINE",
486
+ "line_height_scale": 1,
487
+ "text_size_scale": 1,
488
+ "margin": {
489
+ "right": {
490
+ "scaling_factor": 1,
491
+ "size": "DOCUMENT_MARGIN"
492
+ },
493
+ "left": {
494
+ "scaling_factor": 1,
495
+ "size": "DOCUMENT_MARGIN"
496
+ }
497
+ },
498
+ "border": {
499
+ "top": {
500
+ "width": 0
501
+ },
502
+ "right": {
503
+ "width": 0
504
+ },
505
+ "bottom": {
506
+ "width": 0
507
+ },
508
+ "left": {
509
+ "width": 0
510
+ }
511
+ },
512
+ "padding": {
513
+ "top": {
514
+ "scaling_factor": 1,
515
+ "size": "NONE"
516
+ },
517
+ "right": {
518
+ "scaling_factor": 1,
519
+ "size": "NONE"
520
+ },
521
+ "bottom": {
522
+ "scaling_factor": 1,
523
+ "size": "NONE"
524
+ },
525
+ "left": {
526
+ "scaling_factor": 1,
527
+ "size": "NONE"
528
+ }
529
+ }
530
+ },
531
+ "caption_description_small": {
532
+ "font": "Helvetica Neue",
533
+ "color": "#808080",
534
+ "background_color": "#00FFFFFF",
535
+ "capitalization": "NONE",
536
+ "display": "INLINE",
537
+ "line_height_scale": 1,
538
+ "text_size_scale": 1,
539
+ "margin": {
540
+ "right": {
541
+ "scaling_factor": 1,
542
+ "size": "DOCUMENT_MARGIN"
543
+ },
544
+ "left": {
545
+ "scaling_factor": 1,
546
+ "size": "DOCUMENT_MARGIN"
547
+ }
548
+ },
549
+ "border": {
550
+ "top": {
551
+ "width": 0
552
+ },
553
+ "right": {
554
+ "width": 0
555
+ },
556
+ "bottom": {
557
+ "width": 0
558
+ },
559
+ "left": {
560
+ "width": 0
561
+ }
562
+ },
563
+ "padding": {
564
+ "top": {
565
+ "scaling_factor": 1,
566
+ "size": "NONE"
567
+ },
568
+ "right": {
569
+ "scaling_factor": 1,
570
+ "size": "NONE"
571
+ },
572
+ "bottom": {
573
+ "scaling_factor": 1,
574
+ "size": "NONE"
575
+ },
576
+ "left": {
577
+ "scaling_factor": 1,
578
+ "size": "NONE"
579
+ }
580
+ }
581
+ },
582
+ "caption_credit": {
583
+ "font": "Helvetica Neue",
584
+ "color": "#BFBFBF",
585
+ "background_color": "#00FFFFFF",
586
+ "capitalization": "ALL_CAPS",
587
+ "display": "INLINE",
588
+ "line_height_scale": 1,
589
+ "text_size_scale": 1,
590
+ "margin": {
591
+ "right": {
592
+ "scaling_factor": 1,
593
+ "size": "DOCUMENT_MARGIN"
594
+ },
595
+ "left": {
596
+ "scaling_factor": 1,
597
+ "size": "DOCUMENT_MARGIN"
598
+ }
599
+ },
600
+ "border": {
601
+ "top": {
602
+ "width": 0
603
+ },
604
+ "right": {
605
+ "width": 0
606
+ },
607
+ "bottom": {
608
+ "width": 0
609
+ },
610
+ "left": {
611
+ "width": 0
612
+ }
613
+ },
614
+ "padding": {
615
+ "top": {
616
+ "scaling_factor": 1,
617
+ "size": "NONE"
618
+ },
619
+ "right": {
620
+ "scaling_factor": 1,
621
+ "size": "NONE"
622
+ },
623
+ "bottom": {
624
+ "scaling_factor": 1,
625
+ "size": "NONE"
626
+ },
627
+ "left": {
628
+ "scaling_factor": 1,
629
+ "size": "NONE"
630
+ }
631
+ }
632
+ },
633
+ "caption_title": {
634
+ "font": "Georgia",
635
+ "color": "#808080",
636
+ "background_color": "#00FFFFFF",
637
+ "capitalization": "NONE",
638
+ "display": "INLINE",
639
+ "line_height_scale": 1,
640
+ "text_size_scale": 1,
641
+ "margin": {
642
+ "right": {
643
+ "scaling_factor": 1,
644
+ "size": "DOCUMENT_MARGIN"
645
+ },
646
+ "left": {
647
+ "scaling_factor": 1,
648
+ "size": "DOCUMENT_MARGIN"
649
+ }
650
+ },
651
+ "border": {
652
+ "top": {
653
+ "width": 0
654
+ },
655
+ "right": {
656
+ "width": 0
657
+ },
658
+ "bottom": {
659
+ "width": 0
660
+ },
661
+ "left": {
662
+ "width": 0
663
+ }
664
+ },
665
+ "padding": {
666
+ "top": {
667
+ "scaling_factor": 1,
668
+ "size": "NONE"
669
+ },
670
+ "right": {
671
+ "scaling_factor": 1,
672
+ "size": "NONE"
673
+ },
674
+ "bottom": {
675
+ "scaling_factor": 1,
676
+ "size": "NONE"
677
+ },
678
+ "left": {
679
+ "scaling_factor": 1,
680
+ "size": "NONE"
681
+ }
682
+ }
683
+ },
684
+ "caption_description": {
685
+ "font": "Georgia",
686
+ "color": "#808080",
687
+ "background_color": "#00FFFFFF",
688
+ "capitalization": "NONE",
689
+ "display": "INLINE",
690
+ "line_height_scale": 1,
691
+ "text_size_scale": 1,
692
+ "margin": {
693
+ "right": {
694
+ "scaling_factor": 1,
695
+ "size": "DOCUMENT_MARGIN"
696
+ },
697
+ "left": {
698
+ "scaling_factor": 1,
699
+ "size": "DOCUMENT_MARGIN"
700
+ }
701
+ },
702
+ "border": {
703
+ "top": {
704
+ "width": 0
705
+ },
706
+ "right": {
707
+ "width": 0
708
+ },
709
+ "bottom": {
710
+ "width": 0
711
+ },
712
+ "left": {
713
+ "width": 0
714
+ }
715
+ },
716
+ "padding": {
717
+ "top": {
718
+ "scaling_factor": 1,
719
+ "size": "NONE"
720
+ },
721
+ "right": {
722
+ "scaling_factor": 1,
723
+ "size": "NONE"
724
+ },
725
+ "bottom": {
726
+ "scaling_factor": 1,
727
+ "size": "NONE"
728
+ },
729
+ "left": {
730
+ "scaling_factor": 1,
731
+ "size": "NONE"
732
+ }
733
+ }
734
+ },
735
+ "caption_title_large": {
736
+ "font": "Georgia",
737
+ "color": "#808080",
738
+ "background_color": "#00FFFFFF",
739
+ "capitalization": "NONE",
740
+ "display": "INLINE",
741
+ "line_height_scale": 1,
742
+ "text_size_scale": 1,
743
+ "margin": {
744
+ "right": {
745
+ "scaling_factor": 1,
746
+ "size": "DOCUMENT_MARGIN"
747
+ },
748
+ "left": {
749
+ "scaling_factor": 1,
750
+ "size": "DOCUMENT_MARGIN"
751
+ }
752
+ },
753
+ "border": {
754
+ "top": {
755
+ "width": 0
756
+ },
757
+ "right": {
758
+ "width": 0
759
+ },
760
+ "bottom": {
761
+ "width": 0
762
+ },
763
+ "left": {
764
+ "width": 0
765
+ }
766
+ },
767
+ "padding": {
768
+ "top": {
769
+ "scaling_factor": 1,
770
+ "size": "NONE"
771
+ },
772
+ "right": {
773
+ "scaling_factor": 1,
774
+ "size": "NONE"
775
+ },
776
+ "bottom": {
777
+ "scaling_factor": 1,
778
+ "size": "NONE"
779
+ },
780
+ "left": {
781
+ "scaling_factor": 1,
782
+ "size": "NONE"
783
+ }
784
+ }
785
+ },
786
+ "caption_description_large": {
787
+ "font": "Georgia",
788
+ "color": "#808080",
789
+ "background_color": "#00FFFFFF",
790
+ "capitalization": "NONE",
791
+ "display": "INLINE",
792
+ "line_height_scale": 1,
793
+ "text_size_scale": 1,
794
+ "margin": {
795
+ "right": {
796
+ "scaling_factor": 1,
797
+ "size": "DOCUMENT_MARGIN"
798
+ },
799
+ "left": {
800
+ "scaling_factor": 1,
801
+ "size": "DOCUMENT_MARGIN"
802
+ }
803
+ },
804
+ "border": {
805
+ "top": {
806
+ "width": 0
807
+ },
808
+ "right": {
809
+ "width": 0
810
+ },
811
+ "bottom": {
812
+ "width": 0
813
+ },
814
+ "left": {
815
+ "width": 0
816
+ }
817
+ },
818
+ "padding": {
819
+ "top": {
820
+ "scaling_factor": 1,
821
+ "size": "NONE"
822
+ },
823
+ "right": {
824
+ "scaling_factor": 1,
825
+ "size": "NONE"
826
+ },
827
+ "bottom": {
828
+ "scaling_factor": 1,
829
+ "size": "NONE"
830
+ },
831
+ "left": {
832
+ "scaling_factor": 1,
833
+ "size": "NONE"
834
+ }
835
+ }
836
+ },
837
+ "caption_title_extra_large": {
838
+ "font": "Georgia",
839
+ "color": "#808080",
840
+ "background_color": "#00FFFFFF",
841
+ "capitalization": "NONE",
842
+ "display": "INLINE",
843
+ "line_height_scale": 1,
844
+ "text_size_scale": 1,
845
+ "margin": {
846
+ "right": {
847
+ "scaling_factor": 1,
848
+ "size": "DOCUMENT_MARGIN"
849
+ },
850
+ "left": {
851
+ "scaling_factor": 1,
852
+ "size": "DOCUMENT_MARGIN"
853
+ }
854
+ },
855
+ "border": {
856
+ "top": {
857
+ "width": 0
858
+ },
859
+ "right": {
860
+ "width": 0
861
+ },
862
+ "bottom": {
863
+ "width": 0
864
+ },
865
+ "left": {
866
+ "width": 0
867
+ }
868
+ },
869
+ "padding": {
870
+ "top": {
871
+ "scaling_factor": 1,
872
+ "size": "NONE"
873
+ },
874
+ "right": {
875
+ "scaling_factor": 1,
876
+ "size": "NONE"
877
+ },
878
+ "bottom": {
879
+ "scaling_factor": 1,
880
+ "size": "NONE"
881
+ },
882
+ "left": {
883
+ "scaling_factor": 1,
884
+ "size": "NONE"
885
+ }
886
+ }
887
+ },
888
+ "caption_description_extra_large": {
889
+ "font": "Georgia",
890
+ "color": "#808080",
891
+ "background_color": "#00FFFFFF",
892
+ "capitalization": "NONE",
893
+ "display": "INLINE",
894
+ "line_height_scale": 1,
895
+ "text_size_scale": 1,
896
+ "margin": {
897
+ "right": {
898
+ "scaling_factor": 1,
899
+ "size": "DOCUMENT_MARGIN"
900
+ },
901
+ "left": {
902
+ "scaling_factor": 1,
903
+ "size": "DOCUMENT_MARGIN"
904
+ }
905
+ },
906
+ "border": {
907
+ "top": {
908
+ "width": 0
909
+ },
910
+ "right": {
911
+ "width": 0
912
+ },
913
+ "bottom": {
914
+ "width": 0
915
+ },
916
+ "left": {
917
+ "width": 0
918
+ }
919
+ },
920
+ "padding": {
921
+ "top": {
922
+ "scaling_factor": 1,
923
+ "size": "NONE"
924
+ },
925
+ "right": {
926
+ "scaling_factor": 1,
927
+ "size": "NONE"
928
+ },
929
+ "bottom": {
930
+ "scaling_factor": 1,
931
+ "size": "NONE"
932
+ },
933
+ "left": {
934
+ "scaling_factor": 1,
935
+ "size": "NONE"
936
+ }
937
+ }
938
+ },
939
+ "footer": {
940
+ "font": "Helvetica Neue",
941
+ "color": "#000000",
942
+ "background_color": "#00FFFFFF",
943
+ "capitalization": "NONE",
944
+ "text_alignment": "LEFT",
945
+ "display": "INLINE",
946
+ "line_height_scale": 1,
947
+ "text_size_scale": 1,
948
+ "margin": {
949
+ "right": {
950
+ "scaling_factor": 1,
951
+ "size": "DOCUMENT_MARGIN"
952
+ },
953
+ "left": {
954
+ "scaling_factor": 1,
955
+ "size": "DOCUMENT_MARGIN"
956
+ }
957
+ },
958
+ "border": {
959
+ "top": {
960
+ "width": 0
961
+ },
962
+ "right": {
963
+ "width": 0
964
+ },
965
+ "bottom": {
966
+ "width": 0
967
+ },
968
+ "left": {
969
+ "width": 0
970
+ }
971
+ },
972
+ "padding": {
973
+ "top": {
974
+ "scaling_factor": 1,
975
+ "size": "NONE"
976
+ },
977
+ "right": {
978
+ "scaling_factor": 1,
979
+ "size": "NONE"
980
+ },
981
+ "bottom": {
982
+ "scaling_factor": 1,
983
+ "size": "NONE"
984
+ },
985
+ "left": {
986
+ "scaling_factor": 1,
987
+ "size": "NONE"
988
+ }
989
+ }
990
+ },
991
+ "id": "1755859684428101",
992
+ "name": "wod-gray"
993
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/examples/styles/style-got-from-somewhereelse.json ADDED
@@ -0,0 +1,993 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#EEEEEE",
3
+ "header": {
4
+ "logo": {
5
+ "dataURL": null,
6
+ "id": "1229084557204785",
7
+ "full_resolution_url": "https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&oh=c8337650a88e7fdb6d31088a15a7d9d8&oe=599B24B5&__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8",
8
+ "full_resolution_width": 2600,
9
+ "full_resolution_height": 512,
10
+ "thumbnail_url": "https://fb-s-d-a.akamaihd.net/h-ak-xpf1/v/t39.5687-6/17634152_1374280939304404_1278222734471462912_n.png?_nc_log=1&oh=d3e95b10e960a9527ad643c47d821160&oe=598664D5&__gda__=1498346669_5ee6f5a2bd8d17474bfb46398d9b888a",
11
+ "article_scaling_factor": 1
12
+ },
13
+ "logo_scale": 1,
14
+ "accent_color": "#000000",
15
+ "background_color": "#000066",
16
+ "bar_color": null
17
+ },
18
+ "kicker": {
19
+ "font": "Helvetica Neue",
20
+ "color": "#000000",
21
+ "background_color": "#00FFFFFF",
22
+ "capitalization": "ALL_CAPS",
23
+ "text_alignment": "LEFT",
24
+ "display": "INLINE",
25
+ "line_height_scale": 1,
26
+ "text_size_scale": 1,
27
+ "margin": {
28
+ "right": {
29
+ "scaling_factor": 1,
30
+ "size": "DOCUMENT_MARGIN"
31
+ },
32
+ "left": {
33
+ "scaling_factor": 1,
34
+ "size": "DOCUMENT_MARGIN"
35
+ }
36
+ },
37
+ "border": {
38
+ "top": {
39
+ "width": 0
40
+ },
41
+ "right": {
42
+ "width": 0
43
+ },
44
+ "bottom": {
45
+ "width": 0
46
+ },
47
+ "left": {
48
+ "width": 0
49
+ }
50
+ },
51
+ "padding": {
52
+ "top": {
53
+ "scaling_factor": 1,
54
+ "size": "NONE"
55
+ },
56
+ "right": {
57
+ "scaling_factor": 1,
58
+ "size": "NONE"
59
+ },
60
+ "bottom": {
61
+ "scaling_factor": 1,
62
+ "size": "NONE"
63
+ },
64
+ "left": {
65
+ "scaling_factor": 1,
66
+ "size": "NONE"
67
+ }
68
+ }
69
+ },
70
+ "title": {
71
+ "font": "Georgia",
72
+ "color": "#000000",
73
+ "background_color": "#00FFFFFF",
74
+ "capitalization": "NONE",
75
+ "text_alignment": "LEFT",
76
+ "display": "INLINE",
77
+ "line_height_scale": 1,
78
+ "text_size_scale": 1,
79
+ "margin": {
80
+ "right": {
81
+ "scaling_factor": 1,
82
+ "size": "DOCUMENT_MARGIN"
83
+ },
84
+ "left": {
85
+ "scaling_factor": 1,
86
+ "size": "DOCUMENT_MARGIN"
87
+ }
88
+ },
89
+ "border": {
90
+ "top": {
91
+ "width": 0
92
+ },
93
+ "right": {
94
+ "width": 0
95
+ },
96
+ "bottom": {
97
+ "width": 0
98
+ },
99
+ "left": {
100
+ "width": 0
101
+ }
102
+ },
103
+ "padding": {
104
+ "top": {
105
+ "scaling_factor": 1,
106
+ "size": "NONE"
107
+ },
108
+ "right": {
109
+ "scaling_factor": 1,
110
+ "size": "NONE"
111
+ },
112
+ "bottom": {
113
+ "scaling_factor": 1,
114
+ "size": "NONE"
115
+ },
116
+ "left": {
117
+ "scaling_factor": 1,
118
+ "size": "NONE"
119
+ }
120
+ }
121
+ },
122
+ "subtitle": {
123
+ "font": "Georgia",
124
+ "color": "#000000",
125
+ "background_color": "#00FFFFFF",
126
+ "capitalization": "NONE",
127
+ "text_alignment": "LEFT",
128
+ "display": "INLINE",
129
+ "line_height_scale": 1,
130
+ "text_size_scale": 1,
131
+ "margin": {
132
+ "right": {
133
+ "scaling_factor": 1,
134
+ "size": "DOCUMENT_MARGIN"
135
+ },
136
+ "left": {
137
+ "scaling_factor": 1,
138
+ "size": "DOCUMENT_MARGIN"
139
+ }
140
+ },
141
+ "border": {
142
+ "top": {
143
+ "width": 0
144
+ },
145
+ "right": {
146
+ "width": 0
147
+ },
148
+ "bottom": {
149
+ "width": 0
150
+ },
151
+ "left": {
152
+ "width": 0
153
+ }
154
+ },
155
+ "padding": {
156
+ "top": {
157
+ "scaling_factor": 1,
158
+ "size": "NONE"
159
+ },
160
+ "right": {
161
+ "scaling_factor": 1,
162
+ "size": "NONE"
163
+ },
164
+ "bottom": {
165
+ "scaling_factor": 1,
166
+ "size": "NONE"
167
+ },
168
+ "left": {
169
+ "scaling_factor": 1,
170
+ "size": "NONE"
171
+ }
172
+ }
173
+ },
174
+ "byline": {
175
+ "font": "Helvetica Neue",
176
+ "color": "#000000",
177
+ "capitalization": "ALL_CAPS",
178
+ "text_alignment": "LEFT",
179
+ "line_height_scale": 1,
180
+ "text_size_scale": 1,
181
+ "margin": {
182
+ "right": {
183
+ "scaling_factor": 1,
184
+ "size": "DOCUMENT_MARGIN"
185
+ },
186
+ "left": {
187
+ "scaling_factor": 1,
188
+ "size": "DOCUMENT_MARGIN"
189
+ }
190
+ }
191
+ },
192
+ "date_style": "MONTH_DAY_YEAR",
193
+ "primary_heading": {
194
+ "font": "Georgia",
195
+ "color": "#000000",
196
+ "background_color": "#00FFFFFF",
197
+ "capitalization": "NONE",
198
+ "text_alignment": "LEFT",
199
+ "display": "INLINE",
200
+ "line_height_scale": 1,
201
+ "text_size_scale": 1,
202
+ "margin": {
203
+ "right": {
204
+ "scaling_factor": 1,
205
+ "size": "DOCUMENT_MARGIN"
206
+ },
207
+ "left": {
208
+ "scaling_factor": 1,
209
+ "size": "DOCUMENT_MARGIN"
210
+ }
211
+ },
212
+ "border": {
213
+ "top": {
214
+ "width": 0
215
+ },
216
+ "right": {
217
+ "width": 0
218
+ },
219
+ "bottom": {
220
+ "width": 0
221
+ },
222
+ "left": {
223
+ "width": 0
224
+ }
225
+ },
226
+ "padding": {
227
+ "top": {
228
+ "scaling_factor": 1,
229
+ "size": "NONE"
230
+ },
231
+ "right": {
232
+ "scaling_factor": 1,
233
+ "size": "NONE"
234
+ },
235
+ "bottom": {
236
+ "scaling_factor": 1,
237
+ "size": "NONE"
238
+ },
239
+ "left": {
240
+ "scaling_factor": 1,
241
+ "size": "NONE"
242
+ }
243
+ }
244
+ },
245
+ "secondary_heading": {
246
+ "font": "Georgia",
247
+ "color": "#000000",
248
+ "background_color": "#00FFFFFF",
249
+ "capitalization": "NONE",
250
+ "text_alignment": "LEFT",
251
+ "display": "INLINE",
252
+ "line_height_scale": 1,
253
+ "text_size_scale": 1,
254
+ "margin": {
255
+ "right": {
256
+ "scaling_factor": 1,
257
+ "size": "DOCUMENT_MARGIN"
258
+ },
259
+ "left": {
260
+ "scaling_factor": 1,
261
+ "size": "DOCUMENT_MARGIN"
262
+ }
263
+ },
264
+ "border": {
265
+ "top": {
266
+ "width": 0
267
+ },
268
+ "right": {
269
+ "width": 0
270
+ },
271
+ "bottom": {
272
+ "width": 0
273
+ },
274
+ "left": {
275
+ "width": 0
276
+ }
277
+ },
278
+ "padding": {
279
+ "top": {
280
+ "scaling_factor": 1,
281
+ "size": "NONE"
282
+ },
283
+ "right": {
284
+ "scaling_factor": 1,
285
+ "size": "NONE"
286
+ },
287
+ "bottom": {
288
+ "scaling_factor": 1,
289
+ "size": "NONE"
290
+ },
291
+ "left": {
292
+ "scaling_factor": 1,
293
+ "size": "NONE"
294
+ }
295
+ }
296
+ },
297
+ "body_text": {
298
+ "font": "Georgia",
299
+ "color": "#000000",
300
+ "capitalization": "NONE",
301
+ "text_alignment": "LEFT",
302
+ "line_height_scale": 1,
303
+ "text_size_scale": 1,
304
+ "margin": {
305
+ "right": {
306
+ "scaling_factor": 1,
307
+ "size": "DOCUMENT_MARGIN"
308
+ },
309
+ "left": {
310
+ "scaling_factor": 1,
311
+ "size": "DOCUMENT_MARGIN"
312
+ }
313
+ }
314
+ },
315
+ "inline_link": {
316
+ "color": "#000000",
317
+ "underline": "SIMPLE_UNDERLINE",
318
+ "font": "Georgia"
319
+ },
320
+ "block_quote": {
321
+ "font": "Georgia",
322
+ "color": "#000000",
323
+ "background_color": "#00FFFFFF",
324
+ "capitalization": "NONE",
325
+ "text_alignment": "LEFT",
326
+ "display": "BLOCK",
327
+ "line_height_scale": 1,
328
+ "text_size_scale": 1,
329
+ "margin": {
330
+ "right": {
331
+ "scaling_factor": 1,
332
+ "size": "DOCUMENT_MARGIN"
333
+ },
334
+ "left": {
335
+ "scaling_factor": 1,
336
+ "size": "DOCUMENT_MARGIN"
337
+ }
338
+ },
339
+ "border": {
340
+ "top": {
341
+ "color": "#000000",
342
+ "width": 0
343
+ },
344
+ "right": {
345
+ "color": "#000000",
346
+ "width": 0
347
+ },
348
+ "bottom": {
349
+ "color": "#000000",
350
+ "width": 0
351
+ },
352
+ "left": {
353
+ "color": "#000000",
354
+ "width": 2
355
+ }
356
+ },
357
+ "padding": {
358
+ "top": {
359
+ "scaling_factor": 1,
360
+ "size": "NONE"
361
+ },
362
+ "right": {
363
+ "scaling_factor": 1,
364
+ "size": "SMALL"
365
+ },
366
+ "bottom": {
367
+ "scaling_factor": 1,
368
+ "size": "NONE"
369
+ },
370
+ "left": {
371
+ "scaling_factor": 1,
372
+ "size": "MEDIUM"
373
+ }
374
+ }
375
+ },
376
+ "pull_quote": {
377
+ "font": "Georgia",
378
+ "color": "#000000",
379
+ "background_color": "#00FFFFFF",
380
+ "capitalization": "NONE",
381
+ "text_alignment": "LEFT",
382
+ "display": "INLINE",
383
+ "line_height_scale": 1,
384
+ "text_size_scale": 1,
385
+ "margin": {
386
+ "right": {
387
+ "scaling_factor": 1,
388
+ "size": "DOCUMENT_MARGIN"
389
+ },
390
+ "left": {
391
+ "scaling_factor": 1,
392
+ "size": "DOCUMENT_MARGIN"
393
+ }
394
+ },
395
+ "border": {
396
+ "top": {
397
+ "width": 0
398
+ },
399
+ "right": {
400
+ "width": 0
401
+ },
402
+ "bottom": {
403
+ "width": 0
404
+ },
405
+ "left": {
406
+ "width": 0
407
+ }
408
+ },
409
+ "padding": {
410
+ "top": {
411
+ "scaling_factor": 1,
412
+ "size": "NONE"
413
+ },
414
+ "right": {
415
+ "scaling_factor": 1,
416
+ "size": "NONE"
417
+ },
418
+ "bottom": {
419
+ "scaling_factor": 1,
420
+ "size": "NONE"
421
+ },
422
+ "left": {
423
+ "scaling_factor": 1,
424
+ "size": "NONE"
425
+ }
426
+ }
427
+ },
428
+ "pull_quote_attribution": {
429
+ "font": "Helvetica Neue",
430
+ "color": "#000000",
431
+ "background_color": "#00FFFFFF",
432
+ "capitalization": "ALL_CAPS",
433
+ "text_alignment": "LEFT",
434
+ "display": "INLINE",
435
+ "line_height_scale": 1,
436
+ "text_size_scale": 1,
437
+ "margin": {
438
+ "right": {
439
+ "scaling_factor": 1,
440
+ "size": "DOCUMENT_MARGIN"
441
+ },
442
+ "left": {
443
+ "scaling_factor": 1,
444
+ "size": "DOCUMENT_MARGIN"
445
+ }
446
+ },
447
+ "border": {
448
+ "top": {
449
+ "width": 0
450
+ },
451
+ "right": {
452
+ "width": 0
453
+ },
454
+ "bottom": {
455
+ "width": 0
456
+ },
457
+ "left": {
458
+ "width": 0
459
+ }
460
+ },
461
+ "padding": {
462
+ "top": {
463
+ "scaling_factor": 1,
464
+ "size": "NONE"
465
+ },
466
+ "right": {
467
+ "scaling_factor": 1,
468
+ "size": "NONE"
469
+ },
470
+ "bottom": {
471
+ "scaling_factor": 1,
472
+ "size": "NONE"
473
+ },
474
+ "left": {
475
+ "scaling_factor": 1,
476
+ "size": "NONE"
477
+ }
478
+ }
479
+ },
480
+ "caption_title_small": {
481
+ "font": "Helvetica Neue Bold",
482
+ "color": "#808080",
483
+ "background_color": "#00FFFF",
484
+ "capitalization": "NONE",
485
+ "display": "INLINE",
486
+ "line_height_scale": 1,
487
+ "text_size_scale": 1,
488
+ "margin": {
489
+ "right": {
490
+ "scaling_factor": 1,
491
+ "size": "DOCUMENT_MARGIN"
492
+ },
493
+ "left": {
494
+ "scaling_factor": 1,
495
+ "size": "DOCUMENT_MARGIN"
496
+ }
497
+ },
498
+ "border": {
499
+ "top": {
500
+ "width": 0
501
+ },
502
+ "right": {
503
+ "width": 0
504
+ },
505
+ "bottom": {
506
+ "width": 0
507
+ },
508
+ "left": {
509
+ "width": 0
510
+ }
511
+ },
512
+ "padding": {
513
+ "top": {
514
+ "scaling_factor": 1,
515
+ "size": "NONE"
516
+ },
517
+ "right": {
518
+ "scaling_factor": 1,
519
+ "size": "NONE"
520
+ },
521
+ "bottom": {
522
+ "scaling_factor": 1,
523
+ "size": "NONE"
524
+ },
525
+ "left": {
526
+ "scaling_factor": 1,
527
+ "size": "NONE"
528
+ }
529
+ }
530
+ },
531
+ "caption_description_small": {
532
+ "font": "Helvetica Neue",
533
+ "color": "#808080",
534
+ "background_color": "#00FFFFFF",
535
+ "capitalization": "NONE",
536
+ "display": "INLINE",
537
+ "line_height_scale": 1,
538
+ "text_size_scale": 1,
539
+ "margin": {
540
+ "right": {
541
+ "scaling_factor": 1,
542
+ "size": "DOCUMENT_MARGIN"
543
+ },
544
+ "left": {
545
+ "scaling_factor": 1,
546
+ "size": "DOCUMENT_MARGIN"
547
+ }
548
+ },
549
+ "border": {
550
+ "top": {
551
+ "width": 0
552
+ },
553
+ "right": {
554
+ "width": 0
555
+ },
556
+ "bottom": {
557
+ "width": 0
558
+ },
559
+ "left": {
560
+ "width": 0
561
+ }
562
+ },
563
+ "padding": {
564
+ "top": {
565
+ "scaling_factor": 1,
566
+ "size": "NONE"
567
+ },
568
+ "right": {
569
+ "scaling_factor": 1,
570
+ "size": "NONE"
571
+ },
572
+ "bottom": {
573
+ "scaling_factor": 1,
574
+ "size": "NONE"
575
+ },
576
+ "left": {
577
+ "scaling_factor": 1,
578
+ "size": "NONE"
579
+ }
580
+ }
581
+ },
582
+ "caption_credit": {
583
+ "font": "Helvetica Neue",
584
+ "color": "#BFBFBF",
585
+ "background_color": "#00FFFFFF",
586
+ "capitalization": "ALL_CAPS",
587
+ "display": "INLINE",
588
+ "line_height_scale": 1,
589
+ "text_size_scale": 1,
590
+ "margin": {
591
+ "right": {
592
+ "scaling_factor": 1,
593
+ "size": "DOCUMENT_MARGIN"
594
+ },
595
+ "left": {
596
+ "scaling_factor": 1,
597
+ "size": "DOCUMENT_MARGIN"
598
+ }
599
+ },
600
+ "border": {
601
+ "top": {
602
+ "width": 0
603
+ },
604
+ "right": {
605
+ "width": 0
606
+ },
607
+ "bottom": {
608
+ "width": 0
609
+ },
610
+ "left": {
611
+ "width": 0
612
+ }
613
+ },
614
+ "padding": {
615
+ "top": {
616
+ "scaling_factor": 1,
617
+ "size": "NONE"
618
+ },
619
+ "right": {
620
+ "scaling_factor": 1,
621
+ "size": "NONE"
622
+ },
623
+ "bottom": {
624
+ "scaling_factor": 1,
625
+ "size": "NONE"
626
+ },
627
+ "left": {
628
+ "scaling_factor": 1,
629
+ "size": "NONE"
630
+ }
631
+ }
632
+ },
633
+ "caption_title": {
634
+ "font": "Georgia",
635
+ "color": "#808080",
636
+ "background_color": "#00FFFFFF",
637
+ "capitalization": "NONE",
638
+ "display": "INLINE",
639
+ "line_height_scale": 1,
640
+ "text_size_scale": 1,
641
+ "margin": {
642
+ "right": {
643
+ "scaling_factor": 1,
644
+ "size": "DOCUMENT_MARGIN"
645
+ },
646
+ "left": {
647
+ "scaling_factor": 1,
648
+ "size": "DOCUMENT_MARGIN"
649
+ }
650
+ },
651
+ "border": {
652
+ "top": {
653
+ "width": 0
654
+ },
655
+ "right": {
656
+ "width": 0
657
+ },
658
+ "bottom": {
659
+ "width": 0
660
+ },
661
+ "left": {
662
+ "width": 0
663
+ }
664
+ },
665
+ "padding": {
666
+ "top": {
667
+ "scaling_factor": 1,
668
+ "size": "NONE"
669
+ },
670
+ "right": {
671
+ "scaling_factor": 1,
672
+ "size": "NONE"
673
+ },
674
+ "bottom": {
675
+ "scaling_factor": 1,
676
+ "size": "NONE"
677
+ },
678
+ "left": {
679
+ "scaling_factor": 1,
680
+ "size": "NONE"
681
+ }
682
+ }
683
+ },
684
+ "caption_description": {
685
+ "font": "Georgia",
686
+ "color": "#808080",
687
+ "background_color": "#00FFFFFF",
688
+ "capitalization": "NONE",
689
+ "display": "INLINE",
690
+ "line_height_scale": 1,
691
+ "text_size_scale": 1,
692
+ "margin": {
693
+ "right": {
694
+ "scaling_factor": 1,
695
+ "size": "DOCUMENT_MARGIN"
696
+ },
697
+ "left": {
698
+ "scaling_factor": 1,
699
+ "size": "DOCUMENT_MARGIN"
700
+ }
701
+ },
702
+ "border": {
703
+ "top": {
704
+ "width": 0
705
+ },
706
+ "right": {
707
+ "width": 0
708
+ },
709
+ "bottom": {
710
+ "width": 0
711
+ },
712
+ "left": {
713
+ "width": 0
714
+ }
715
+ },
716
+ "padding": {
717
+ "top": {
718
+ "scaling_factor": 1,
719
+ "size": "NONE"
720
+ },
721
+ "right": {
722
+ "scaling_factor": 1,
723
+ "size": "NONE"
724
+ },
725
+ "bottom": {
726
+ "scaling_factor": 1,
727
+ "size": "NONE"
728
+ },
729
+ "left": {
730
+ "scaling_factor": 1,
731
+ "size": "NONE"
732
+ }
733
+ }
734
+ },
735
+ "caption_title_large": {
736
+ "font": "Georgia",
737
+ "color": "#808080",
738
+ "background_color": "#00FFFFFF",
739
+ "capitalization": "NONE",
740
+ "display": "INLINE",
741
+ "line_height_scale": 1,
742
+ "text_size_scale": 1,
743
+ "margin": {
744
+ "right": {
745
+ "scaling_factor": 1,
746
+ "size": "DOCUMENT_MARGIN"
747
+ },
748
+ "left": {
749
+ "scaling_factor": 1,
750
+ "size": "DOCUMENT_MARGIN"
751
+ }
752
+ },
753
+ "border": {
754
+ "top": {
755
+ "width": 0
756
+ },
757
+ "right": {
758
+ "width": 0
759
+ },
760
+ "bottom": {
761
+ "width": 0
762
+ },
763
+ "left": {
764
+ "width": 0
765
+ }
766
+ },
767
+ "padding": {
768
+ "top": {
769
+ "scaling_factor": 1,
770
+ "size": "NONE"
771
+ },
772
+ "right": {
773
+ "scaling_factor": 1,
774
+ "size": "NONE"
775
+ },
776
+ "bottom": {
777
+ "scaling_factor": 1,
778
+ "size": "NONE"
779
+ },
780
+ "left": {
781
+ "scaling_factor": 1,
782
+ "size": "NONE"
783
+ }
784
+ }
785
+ },
786
+ "caption_description_large": {
787
+ "font": "Georgia",
788
+ "color": "#808080",
789
+ "background_color": "#00FFFFFF",
790
+ "capitalization": "NONE",
791
+ "display": "INLINE",
792
+ "line_height_scale": 1,
793
+ "text_size_scale": 1,
794
+ "margin": {
795
+ "right": {
796
+ "scaling_factor": 1,
797
+ "size": "DOCUMENT_MARGIN"
798
+ },
799
+ "left": {
800
+ "scaling_factor": 1,
801
+ "size": "DOCUMENT_MARGIN"
802
+ }
803
+ },
804
+ "border": {
805
+ "top": {
806
+ "width": 0
807
+ },
808
+ "right": {
809
+ "width": 0
810
+ },
811
+ "bottom": {
812
+ "width": 0
813
+ },
814
+ "left": {
815
+ "width": 0
816
+ }
817
+ },
818
+ "padding": {
819
+ "top": {
820
+ "scaling_factor": 1,
821
+ "size": "NONE"
822
+ },
823
+ "right": {
824
+ "scaling_factor": 1,
825
+ "size": "NONE"
826
+ },
827
+ "bottom": {
828
+ "scaling_factor": 1,
829
+ "size": "NONE"
830
+ },
831
+ "left": {
832
+ "scaling_factor": 1,
833
+ "size": "NONE"
834
+ }
835
+ }
836
+ },
837
+ "caption_title_extra_large": {
838
+ "font": "Georgia",
839
+ "color": "#808080",
840
+ "background_color": "#00FFFFFF",
841
+ "capitalization": "NONE",
842
+ "display": "INLINE",
843
+ "line_height_scale": 1,
844
+ "text_size_scale": 1,
845
+ "margin": {
846
+ "right": {
847
+ "scaling_factor": 1,
848
+ "size": "DOCUMENT_MARGIN"
849
+ },
850
+ "left": {
851
+ "scaling_factor": 1,
852
+ "size": "DOCUMENT_MARGIN"
853
+ }
854
+ },
855
+ "border": {
856
+ "top": {
857
+ "width": 0
858
+ },
859
+ "right": {
860
+ "width": 0
861
+ },
862
+ "bottom": {
863
+ "width": 0
864
+ },
865
+ "left": {
866
+ "width": 0
867
+ }
868
+ },
869
+ "padding": {
870
+ "top": {
871
+ "scaling_factor": 1,
872
+ "size": "NONE"
873
+ },
874
+ "right": {
875
+ "scaling_factor": 1,
876
+ "size": "NONE"
877
+ },
878
+ "bottom": {
879
+ "scaling_factor": 1,
880
+ "size": "NONE"
881
+ },
882
+ "left": {
883
+ "scaling_factor": 1,
884
+ "size": "NONE"
885
+ }
886
+ }
887
+ },
888
+ "caption_description_extra_large": {
889
+ "font": "Georgia",
890
+ "color": "#808080",
891
+ "background_color": "#00FFFFFF",
892
+ "capitalization": "NONE",
893
+ "display": "INLINE",
894
+ "line_height_scale": 1,
895
+ "text_size_scale": 1,
896
+ "margin": {
897
+ "right": {
898
+ "scaling_factor": 1,
899
+ "size": "DOCUMENT_MARGIN"
900
+ },
901
+ "left": {
902
+ "scaling_factor": 1,
903
+ "size": "DOCUMENT_MARGIN"
904
+ }
905
+ },
906
+ "border": {
907
+ "top": {
908
+ "width": 0
909
+ },
910
+ "right": {
911
+ "width": 0
912
+ },
913
+ "bottom": {
914
+ "width": 0
915
+ },
916
+ "left": {
917
+ "width": 0
918
+ }
919
+ },
920
+ "padding": {
921
+ "top": {
922
+ "scaling_factor": 1,
923
+ "size": "NONE"
924
+ },
925
+ "right": {
926
+ "scaling_factor": 1,
927
+ "size": "NONE"
928
+ },
929
+ "bottom": {
930
+ "scaling_factor": 1,
931
+ "size": "NONE"
932
+ },
933
+ "left": {
934
+ "scaling_factor": 1,
935
+ "size": "NONE"
936
+ }
937
+ }
938
+ },
939
+ "footer": {
940
+ "font": "Helvetica Neue",
941
+ "color": "#000000",
942
+ "background_color": "#00FFFFFF",
943
+ "capitalization": "NONE",
944
+ "text_alignment": "LEFT",
945
+ "display": "INLINE",
946
+ "line_height_scale": 1,
947
+ "text_size_scale": 1,
948
+ "margin": {
949
+ "right": {
950
+ "scaling_factor": 1,
951
+ "size": "DOCUMENT_MARGIN"
952
+ },
953
+ "left": {
954
+ "scaling_factor": 1,
955
+ "size": "DOCUMENT_MARGIN"
956
+ }
957
+ },
958
+ "border": {
959
+ "top": {
960
+ "width": 0
961
+ },
962
+ "right": {
963
+ "width": 0
964
+ },
965
+ "bottom": {
966
+ "width": 0
967
+ },
968
+ "left": {
969
+ "width": 0
970
+ }
971
+ },
972
+ "padding": {
973
+ "top": {
974
+ "scaling_factor": 1,
975
+ "size": "NONE"
976
+ },
977
+ "right": {
978
+ "scaling_factor": 1,
979
+ "size": "NONE"
980
+ },
981
+ "bottom": {
982
+ "scaling_factor": 1,
983
+ "size": "NONE"
984
+ },
985
+ "left": {
986
+ "scaling_factor": 1,
987
+ "size": "NONE"
988
+ }
989
+ }
990
+ },
991
+ "id": "1755859684428101",
992
+ "name": "wod-gray"
993
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/phpcs.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="facebook/facebook-instant-articles-sdk-extensions-php">
3
+ <file>.</file>
4
+ <exclude-pattern>vendor/</exclude-pattern>
5
+ <arg name="colors" />
6
+ <arg value="sn" />
7
+ <rule ref="PSR2" />
8
+ </ruleset>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/phpunit.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <phpunit
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
5
+ bootstrap="vendor/autoload.php"
6
+ colors="true"
7
+ >
8
+ <testsuites>
9
+ <testsuite name="The project's test suite">
10
+ <directory>./tests</directory>
11
+ </testsuite>
12
+ </testsuites>
13
+ <filter>
14
+ <whitelist>
15
+ <directory>./src</directory>
16
+ </whitelist>
17
+ </filter>
18
+ </phpunit>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPArticle.php ADDED
@@ -0,0 +1,1460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Elements\Element;
12
+ use Facebook\InstantArticles\Elements\Paragraph;
13
+ use Facebook\InstantArticles\Elements\Blockquote;
14
+ use Facebook\InstantArticles\Elements\Ad;
15
+ use Facebook\InstantArticles\Elements\Analytics;
16
+ use Facebook\InstantArticles\Elements\H1;
17
+ use Facebook\InstantArticles\Elements\H2;
18
+ use Facebook\InstantArticles\Elements\ListElement;
19
+ use Facebook\InstantArticles\Elements\Pullquote;
20
+ use Facebook\InstantArticles\Elements\Image;
21
+ use Facebook\InstantArticles\Elements\Caption;
22
+ use Facebook\InstantArticles\Elements\AnimatedGIF;
23
+ use Facebook\InstantArticles\Elements\Video;
24
+ use Facebook\InstantArticles\Elements\Audio;
25
+ use Facebook\InstantArticles\Elements\Slideshow;
26
+ use Facebook\InstantArticles\Elements\Interactive;
27
+ use Facebook\InstantArticles\Elements\SocialEmbed;
28
+ use Facebook\InstantArticles\Elements\Map;
29
+ use Facebook\InstantArticles\Elements\RelatedArticles;
30
+ use Facebook\InstantArticles\Elements\TextContainer;
31
+ use Facebook\InstantArticles\Elements\InstantArticleInterface;
32
+ use Facebook\InstantArticles\Elements\InstantArticle;
33
+
34
+ use Facebook\InstantArticles\Parser\Parser;
35
+ use Facebook\InstantArticles\Validators\Type;
36
+ use Facebook\InstantArticles\Utils\Observer;
37
+
38
+ class AMPArticle extends Element implements InstantArticleInterface
39
+ {
40
+ const DEFAULT_MARGIN = 16.4;
41
+ const DEFAULT_WIDTH = 380;
42
+ const DEFAULT_HEIGHT = 240;
43
+ const DEFAULT_LOGO_WIDTH = 230;
44
+ const DEFAULT_LOGO_HEIGHT = 44;
45
+ const DEFAULT_DATE_FORMAT = 'F d, Y';
46
+ const DEFAULT_CSS_PREFIX = 'ia2amp-';
47
+
48
+ const STYLES_FOLDER_KEY = 'styles-folder';
49
+ const OVERRIDE_STYLES_KEY = 'override-styles';
50
+ const MEDIA_CACHE_FOLDER_KEY = 'media-cache-folder';
51
+ const ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY = 'enable-download-for-media-sizing';
52
+ const DEFAULT_MEDIA_WIDTH_KEY = 'default-media-width';
53
+ const DEFAULT_MEDIA_HEIGHT_KEY = 'default-media-height';
54
+ const MEDIA_SIZES_KEY = 'media-sizes';
55
+ const PUBLISHER_KEY = 'publisher';
56
+ const GOOGLE_MAPS_KEY = 'google_maps_key';
57
+ const ANALYTICS_KEY = 'analytics';
58
+
59
+ const MEDIA_TYPE_IMAGE = 'image';
60
+ const MEDIA_TYPE_VIDEO = 'video';
61
+
62
+ const MEDIA_SIZE_MODE_RESPONSIVE = 'responsive';
63
+ const MEDIA_SIZE_MODE_VIEWPORT = 'viewport';
64
+ const MEDIA_SIZE_MODE_SCALED = 'scaled';
65
+
66
+ private $instantArticle;
67
+ /*
68
+ 'lang' => 'en-US',
69
+ 'css-selector-prefix' => 'ia2amp-',
70
+ 'styles-folder' => '/articles/styles'
71
+ 'media-cache-folder' => '/articles/media',
72
+ 'enable-download-for-media-sizing' => FALSE,
73
+ 'default-media-width' => 380,
74
+ 'default-media-height' => 240,
75
+ 'media-sizes' => array(),
76
+ 'publisher' => array(),
77
+ 'analytics' => array(),
78
+ */
79
+ private $properties = array();
80
+
81
+ /**
82
+ * @var Observer The instance for Observing and Hooking system for extensions
83
+ */
84
+ private $observer;
85
+
86
+ private $dateFormat = AMPArticle::DEFAULT_DATE_FORMAT;
87
+ private $logo;
88
+
89
+ private $customCSSElement;
90
+ private $ampHeader;
91
+
92
+ private function __construct($instantArticle, $properties, $observer)
93
+ {
94
+ $this->instantArticle = $instantArticle;
95
+ $this->properties = $properties;
96
+ $this->observer = $observer;
97
+ }
98
+
99
+ /**
100
+ * Factory method to instantiate the AMPArticle converter.
101
+ * @param string|InstantArticle $instantArticle The instant article that will be parsed if informed as string.
102
+ * @param array() $properties the configuration for the AMP conversion. @see https://developers.facebook.com/docs/instant-articles/other-formats
103
+ * @param Observer $observer optional, will be created in case none informed. This is the hooking system for code level customizations.
104
+ */
105
+ public static function create($instantArticle, $properties = array(), $observer = null)
106
+ {
107
+ // Treats if the informed content is string, parsing it into InstantArticle.
108
+ if (Type::is($instantArticle, Type::STRING)) {
109
+ libxml_use_internal_errors(true);
110
+ $document = new \DOMDocument('1.0');
111
+ $document->loadHTML($instantArticle);
112
+ libxml_use_internal_errors(false);
113
+
114
+ $parser = new Parser();
115
+ $instantArticle = $parser->parse($document);
116
+ }
117
+
118
+ // Enforces that $instantArticle is typeof InstantArticle class.
119
+ Type::enforce($instantArticle, InstantArticle::getClassName());
120
+
121
+ if ($properties === null) {
122
+ $properties = array();
123
+ }
124
+
125
+ if ($observer == null) {
126
+ $observer = Observer::create();
127
+ }
128
+
129
+ return new self($instantArticle, $properties, $observer);
130
+ }
131
+
132
+ public function getObserver()
133
+ {
134
+ return $this->observer;
135
+ }
136
+
137
+ public function getInstantArticle()
138
+ {
139
+ return $this->instantArticle;
140
+ }
141
+
142
+ public function render($doctype = '<!doctype html>', $format = true)
143
+ {
144
+ $doctype = is_null($doctype) ? '<!doctype html>' : $doctype;
145
+ $rendered = parent::render($doctype, $format);
146
+
147
+ // Makes empty value attribute definition, since we use DOMDocument::saveXML()
148
+ $rendered = str_replace('amp=""', 'amp', $rendered);
149
+ $rendered = str_replace('amp-custom=""', 'amp-custom', $rendered);
150
+ $rendered = str_replace('amp-boilerplate=""', 'amp-boilerplate', $rendered);
151
+ $rendered = str_replace('async=""', 'async', $rendered);
152
+
153
+ return $rendered;
154
+ }
155
+
156
+ public function toDOMElement($document = null)
157
+ {
158
+ if (isset($this->properties['css-selector-prefix'])) {
159
+ $prefix = $this->properties['css-selector-prefix'];
160
+ } else {
161
+ $prefix = self::DEFAULT_CSS_PREFIX;
162
+ }
163
+
164
+ $mediaSizes =
165
+ array_key_exists(self::MEDIA_SIZES_KEY, $this->properties) ?
166
+ $this->properties[self::MEDIA_SIZES_KEY] :
167
+ null;
168
+
169
+ $mediaCacheFolder =
170
+ array_key_exists(self::MEDIA_CACHE_FOLDER_KEY, $this->properties) ?
171
+ $this->properties[self::MEDIA_CACHE_FOLDER_KEY] :
172
+ null;
173
+
174
+ $enableDownloadForMediaSizing =
175
+ (array_key_exists(self::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY, $this->properties) &&
176
+ $this->properties[self::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY] === true);
177
+
178
+ $defaultWidth = array_key_exists(self::DEFAULT_MEDIA_WIDTH_KEY, $this->properties)
179
+ ? $this->properties[self::DEFAULT_MEDIA_WIDTH_KEY]
180
+ : self::DEFAULT_WIDTH;
181
+ $defaultHeight = array_key_exists(self::DEFAULT_MEDIA_HEIGHT_KEY, $this->properties)
182
+ ? $this->properties[self::DEFAULT_MEDIA_HEIGHT_KEY]
183
+ : self::DEFAULT_HEIGHT;
184
+
185
+
186
+ $context = AMPContext::create($document, $this->instantArticle, $prefix);
187
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
188
+
189
+ $ampDocument = $this->observer->applyFilters('AMP_DOCUMENT', $this->transformInstantArticle($context), $context);
190
+
191
+ return $ampDocument;
192
+ }
193
+
194
+ /**
195
+ * Builds the analytics tag from the strings on the properties.
196
+ *
197
+ * The format of the $properties['analytics'] should be a list of strings
198
+ * containing the raw markup of the analytics tags (either amp-analytics or amp-pixel).
199
+ */
200
+ public function buildAnalytics($context = null)
201
+ {
202
+ if (!isset($this->properties[self::ANALYTICS_KEY])) {
203
+ return null;
204
+ }
205
+
206
+ if ($context === null) {
207
+ $context = $this->getContext();
208
+ if ($context === null) {
209
+ throw new Exception('No context found.');
210
+ }
211
+ }
212
+
213
+ $document = $context->getDocument();
214
+ $container = $document->createDocumentFragment();
215
+
216
+ foreach ($this->properties[self::ANALYTICS_KEY] as $analyticsString) {
217
+ $fragment = $document->createDocumentFragment();
218
+ $successs = $fragment->appendXML($analyticsString);
219
+
220
+ if (!$successs || // Broken XML
221
+ $fragment->childNodes->length !== 1 || // Not a single tag
222
+ !($fragment->firstChild instanceof \DOMElement) || // Not a tag
223
+ !(
224
+ $fragment->firstChild->tagName !== 'amp-analytics' || // Not a <amp-analytics> tag
225
+ $fragment->firstChild->tagName !== 'amp-pixel' // Or a <amp-pixel> tag
226
+ )
227
+ ) {
228
+ $context->addWarning("Invalid Analytics markup. AMP Analytics code should be a single <amp-analytics> or <amp-pixel> tag.", $analyticsString);
229
+ return null;
230
+ }
231
+
232
+ $container->appendChild($this->observer->applyFilters('AMP_ANALYTICS', $fragment, $this->properties));
233
+ }
234
+
235
+ if ($container->childNodes->length === 0) {
236
+ return null;
237
+ }
238
+
239
+ return $container;
240
+ }
241
+
242
+ public function transformInstantArticle($context)
243
+ {
244
+ // Builds and appends head to the HTML document
245
+ $html = $context->createElement('html', null, null, array("amp" => ""));
246
+ if ($context->getInstantArticle()->isRTLEnabled()) {
247
+ $html->setAttribute('dir', 'rtl');
248
+ }
249
+ if (isset($this->properties['lang'])) {
250
+ $html->setAttribute('lang', $this->properties['lang']);
251
+ }
252
+ $context->withHtml($html);
253
+
254
+ $head = $this->observer->applyFilters('AMP_HEAD', $this->transformMetaInfoHead($context), $context);
255
+ $context->withHead($head);
256
+
257
+ // Build and append body and article tags to the HTML document
258
+ $body = $this->observer->applyFilters('AMP_BODY', $this->buildBody($context), $context);
259
+ $context->withBody($body);
260
+
261
+ $header = $this->observer->applyFilters('AMP_HEADER', $this->transformArticleHeader($context), $context);
262
+ $context->withHeader($header);
263
+
264
+ $article = $this->observer->applyFilters('AMP_ARTICLE', $this->transformArticleContent($context), $context);
265
+ $context->withArticle($article);
266
+
267
+ $footer = $this->observer->applyFilters('AMP_FOOTER', $this->transformArticleFooter($context), $context);
268
+ //$context->withFooter($footer);
269
+
270
+ // Set the Custom CSS content
271
+ $cssDeclarations = $this->getCustomCSS($context);
272
+ $cssTextContent = $context->getDocument()->createTextNode($cssDeclarations);
273
+ $this->customCSSElement->appendChild($cssTextContent);
274
+
275
+ // Create the logo image, if set
276
+ $this->ampHeader->genHeaderLogo($this->logo);
277
+ // Create the text element for the published date using parsed format from styles
278
+ $this->ampHeader->genArticlePublishDate($this->dateFormat);
279
+
280
+ // Add the analytics code
281
+ $analytics = $this->buildAnalytics();
282
+ if ($analytics !== null) {
283
+ $head->appendChild($this->buildCustomElementScriptEntry('amp-analytics', 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js', $context));
284
+ $body->insertBefore($analytics, $body->firstChild);
285
+ }
286
+
287
+ return $html;
288
+ }
289
+
290
+ public function buildBody($context)
291
+ {
292
+ return $context->createElement('body', $context->getHtml(), 'body');
293
+ }
294
+
295
+ public function transformArticleHeader($context)
296
+ {
297
+ $this->ampHeader = new AMPHeader($context);
298
+ return $this->ampHeader->build();
299
+ }
300
+
301
+ public function transformMetaInfoHead($context)
302
+ {
303
+ // Builds the Head
304
+ $head = $context->createElement('head');
305
+ $context->getHtml()->appendChild($head);
306
+
307
+ // Builds meta charset and append to head
308
+ if ($context->getInstantArticle()->getCharset()) {
309
+ $context->createElement('meta', $head, null, array('charset' => $context->getInstantArticle()->getCharset()));
310
+ }
311
+
312
+ // Builds meta viewport and append to head
313
+ $context->createElement(
314
+ 'meta',
315
+ $head,
316
+ null,
317
+ array(
318
+ 'name' => 'viewport',
319
+ 'content' => 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no'
320
+ )
321
+ );
322
+
323
+ // Builds ampjs script and append to head
324
+ $context->createElement('script', $head, null, array('src' => 'https://cdn.ampproject.org/v0.js', 'async' => ''));
325
+
326
+ // Builds boilerplate css style and append to head
327
+ $boilerplate = $context->createElement('style', $head, null, array('amp-boilerplate' => ''));
328
+ $boilerplateContent = $context->getDocument()->createTextNode('body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}');
329
+ $boilerplate->appendChild($boilerplateContent);
330
+
331
+ // Builds noscript css style and append to head
332
+ $noscript = $context->createElement('noscript', $head);
333
+ $noscriptBoilerplate = $context->createElement('style', $noscript, null, array('amp-boilerplate' => ''));
334
+ $noscriptBoilerplateContent = $context->getDocument()->createTextNode('body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}');
335
+ $noscriptBoilerplate->appendChild($noscriptBoilerplateContent);
336
+
337
+ // Builds canonical link and append to head
338
+ $link = $context->createElement('link', $head, null, array('rel' => 'canonical', 'href' => $context->getInstantArticle()->getCanonicalURL()));
339
+
340
+ // Builds custom css style and append to head
341
+ $ampCustomCSS = $this->buildCustomCSS($context);
342
+ $head->appendChild($ampCustomCSS);
343
+ // Save element, so we can add the custom CSS content after the whole article is processed
344
+ $this->customCSSElement = $ampCustomCSS;
345
+
346
+ // Builds Schema.org metadata and appends to head
347
+ $discoveryScript = $context->createElement('script', $head, null, array('type' => 'application/ld+json'));
348
+ $discoveryScriptContent = $this->buildSchemaOrgMetadata($context);
349
+ $discoveryScript->appendChild($context->getDocument()->createTextNode($discoveryScriptContent));
350
+
351
+ // Builds title and append to head
352
+ $title = $context->createElement('title', $head);
353
+ $titleText = $context->getInstantArticle()->getHeader()->getTitle()->textToDOMDocumentFragment($context->getDocument());
354
+ $title->appendChild($titleText);
355
+
356
+ return $head;
357
+ }
358
+
359
+ public function transformArticleContent($context)
360
+ {
361
+ $article = $context->createElement('article', $context->getBody(), 'article');
362
+
363
+ $containsIframe = false;
364
+ $containsSlideshow = false;
365
+ $containsAudio = false;
366
+ $containsVideo = false;
367
+
368
+ if ($context->getInstantArticle()->getChildren()) {
369
+ foreach ($context->getInstantArticle()->getChildren() as $child) {
370
+ if (Type::is($child, TextContainer::getClassName())) {
371
+ if (count($child->getTextChildren()) === 0) {
372
+ continue;
373
+ } elseif (count($child->getTextChildren()) === 1) {
374
+ if (Type::is($child->getTextChildren()[0], Type::STRING) &&
375
+ trim($child->getTextChildren()[0]) === '') {
376
+ continue;
377
+ }
378
+ }
379
+ }
380
+ if (Type::is($child, Paragraph::getClassName())) {
381
+ $childElement = $this->observer->applyFilters('IA_PARAGRAPH', $this->buildRegularDomElement($context, $child, 'p'), $child, $context);
382
+ } else if (Type::is($child, Blockquote::getClassName())) {
383
+ $childElement = $this->observer->applyFilters('IA_BLOCKQUOTE', $this->buildRegularDomElement($context, $child, 'blockquote'), $child, $context);
384
+ } else if (Type::is($child, H1::getClassName())) {
385
+ $childElement = $this->observer->applyFilters('IA_H1', $this->buildRegularDomElement($context, $child, 'h1'), $child, $context);
386
+ } else if (Type::is($child, H2::getClassName())) {
387
+ $childElement = $this->observer->applyFilters('IA_H2', $this->buildRegularDomElement($context, $child, 'h2'), $child, $context);
388
+ } else if (Type::is($child, ListElement::getClassName())) {
389
+ $childElement = $this->observer->applyFilters('IA_LIST', $this->buildRegularDomElement($context, $child, 'list'), $child, $context);
390
+ } else if (Type::is($child, Pullquote::getClassName())) {
391
+ $childElement = $this->observer->applyFilters('IA_PULLQUOTE', $this->buildRegularDomElement($context, $child, 'pullquote'), $child, $context);
392
+ } else if (Type::is($child, Image::getClassName())) {
393
+ $childElement = $this->observer->applyFilters('IA_IMAGE', $this->buildImage($child, $context, 'image'), $child, $context);
394
+ } else if (Type::is($child, AnimatedGIF::getClassName())) {
395
+ $childElement = $this->observer->applyFilters('IA_GIF', $this->buildGIF($child, $context, 'gif'), $child, $context);
396
+ } else if (Type::is($child, Video::getClassName())) {
397
+ if (!$containsVideo) {
398
+ $containsVideo = true;
399
+ $context->getHead()->appendChild($this->buildCustomElementScriptEntry('amp-video', 'https://cdn.ampproject.org/v0/amp-video-0.1.js', $context));
400
+ }
401
+ $childElement = $this->observer->applyFilters('IA_VIDEO', $this->buildVideo($child, $context, 'video'), $child, $context);
402
+ } else if (Type::is($child, Audio::getClassName())) {
403
+ if (!$containsAudio) {
404
+ $containsAudio = true;
405
+ $context->getHead()->appendChild($this->buildCustomElementScriptEntry('amp-audio', 'https://cdn.ampproject.org/v0/amp-audio-0.1.js', $context));
406
+ }
407
+ $childElement = $this->observer->applyFilters('IA_AUDIO', $this->buildAudio($child, $context, 'audio'), $child, $context);
408
+ } else if (Type::is($child, Slideshow::getClassName())) {
409
+ if (!$containsSlideshow) {
410
+ $containsSlideshow = true;
411
+ $context->getHead()->appendChild($this->buildCustomElementScriptEntry('amp-carousel', 'https://cdn.ampproject.org/v0/amp-carousel-0.1.js', $context));
412
+ }
413
+ $childElement = $this->observer->applyFilters('IA_SLIDESHOW', $this->buildSlideshow($child, $context, 'slideshow'), $child, $context);
414
+ } else if ((Type::is($child, Interactive::getClassName()) || Type::is($child, SocialEmbed::getClassName())) && !Type::isTextEmpty($child->getSource())) {
415
+ if (!$containsIframe) {
416
+ $containsIframe = true;
417
+ $context->getHead()->appendChild($this->buildCustomElementScriptEntry('amp-iframe', 'https://cdn.ampproject.org/v0/amp-iframe-0.1.js', $context));
418
+ }
419
+ $childElement = $this->observer->applyFilters('IA_INTERACTIVE', $this->buildIframe($child, $context, 'interactive', true), $child, $context);
420
+ } else if (Type::is($child, Map::getClassName())) {
421
+ if (!$containsIframe) {
422
+ $containsIframe = true;
423
+ $context->getHead()->appendChild($this->buildCustomElementScriptEntry('amp-iframe', 'https://cdn.ampproject.org/v0/amp-iframe-0.1.js', $context));
424
+ }
425
+ $childElement = $this->observer->applyFilters('IA_MAP', $this->buildMaps($child, $context, 'map'), $child, $context);
426
+ } else if (Type::is($child, RelatedArticles::getClassName())) {
427
+ $childElement->setAttribute('class', $context->buildCssClass('related-articles'));
428
+ // TODO RelatedArticles is not covered yet, since AMP didn't get a good structure for it up to date.
429
+ } else if (Type::is($child, Analytics::getClassName())) {
430
+ if ($this->buildAnalytics() === null) {
431
+ $context->addWarning(
432
+ 'Your Instant Article has analytics code, and you didn\'t provide an AMP analytics json. Your data will not be tracked. See the documentation at https://www.ampproject.org/docs/reference/components/amp-analytics on how to build your analytics component for AMP.',
433
+ $child
434
+ );
435
+ }
436
+ continue;
437
+ } else if (Type::is($child, Ad::getClassName())) {
438
+ $childElement = $this->observer->applyFilters('IA_AD', $this->buildAd($child, $context, 'ad'), $child, $context);
439
+ } else {
440
+ // Not a know element, bypasses it
441
+ continue;
442
+ }
443
+
444
+ $context->addItem($childElement);
445
+ $article->appendChild($childElement);
446
+ $context->buildSpacingDiv($article);
447
+ }
448
+ }
449
+
450
+ return $article;
451
+ }
452
+
453
+ public function buildRegularDomElement($context, $child, $cssClass)
454
+ {
455
+ $element = $child->toDOMElement($context->getDocument());
456
+ $element->setAttribute('class', $context->buildCssClass($cssClass));
457
+ $context->withPreviousElementIdentifier($cssClass);
458
+
459
+ return $element;
460
+ }
461
+
462
+ public function transformArticleFooter($context)
463
+ {
464
+ $footer = $this->instantArticle->getFooter();
465
+ if ($footer && $footer->isValid()) {
466
+ $ampFooter = $context->createElement('footer', null, 'footer');
467
+ $context->getArticle()->appendChild($ampFooter);
468
+
469
+ // Credits
470
+ $credits = $footer->getCredits();
471
+ if ($credits) {
472
+ $ampCredits = $context->createElement('aside', $ampFooter);
473
+ if (is_array($credits)) {
474
+ foreach ($credits as $paragraph) {
475
+ $ampCredits->appendChild($paragraph->toDOMElement($context->getDocument()));
476
+ }
477
+ } else {
478
+ $ampCredits->appendChild($context->getDocument()->createTextNode($credits));
479
+ }
480
+ }
481
+
482
+ // Copyright
483
+ $copyright = $footer->getCopyright();
484
+ if ($copyright) {
485
+ $ampCopyright = $context->createElement('small', $ampFooter);
486
+ $ampCopyright->appendChild($copyright->textToDOMDocumentFragment($context->getDocument()));
487
+ }
488
+
489
+ return $ampFooter;
490
+ }
491
+ return null;
492
+ }
493
+
494
+ public function buildCustomElementScriptEntry($customElementName, $src, $context)
495
+ {
496
+ $script = $context->getDocument()->createElement('script');
497
+ $script->setAttribute('async', '');
498
+ $script->setAttribute('custom-element', $customElementName);
499
+ $script->setAttribute('src', $src);
500
+ return $script;
501
+ }
502
+
503
+ private function buildImage($image, $context, $cssClass, $withContainer = true, $mediaSizeMode = self::MEDIA_SIZE_MODE_RESPONSIVE)
504
+ {
505
+ if ($withContainer) {
506
+ $ampImgContainer = $context->createElement('div', null, $cssClass);
507
+ }
508
+
509
+ $ampImg = $context->getDocument()->createElement('amp-img');
510
+ $imageURL = $image->getUrl();
511
+
512
+ $imageDimensions = $this->getMediaDimensions($imageURL, AMPContext::MEDIA_TYPE_IMAGE);
513
+ $imageWidth = $imageDimensions[0];
514
+ $imageHeight = $imageDimensions[1];
515
+
516
+ if ($mediaSizeMode === self::MEDIA_SIZE_MODE_VIEWPORT) {
517
+ $horizontalScale = self::DEFAULT_WIDTH / $imageWidth;
518
+ $verticalScale = self::DEFAULT_HEIGHT / $imageHeight;
519
+ $maxScale = max($horizontalScale, $verticalScale);
520
+
521
+ $translateX = (int) (-($imageWidth * $maxScale - self::DEFAULT_WIDTH) / 2);
522
+ $translateY = (int) (-($imageHeight * $maxScale - self::DEFAULT_HEIGHT) / 2);
523
+
524
+ $imageCSSClass = $context->buildCssClass('header-cover-img');
525
+ $ampImg->setAttribute('class', $imageCSSClass);
526
+
527
+ $context->getCssBuilder()->addProperty("amp-img.$imageCSSClass", 'transform', "translate({$translateX}px, {$translateY}px)");
528
+
529
+ $containerCSSClass = $ampImgContainer->getAttribute('class');
530
+ $context->getCssBuilder()
531
+ ->addProperty("div.$containerCSSClass", 'width', self::DEFAULT_WIDTH.'px')
532
+ ->addProperty("div.$containerCSSClass", 'height', self::DEFAULT_HEIGHT.'px')
533
+ ->addProperty("div.$containerCSSClass", 'overflow', 'hidden');
534
+
535
+ $imageWidth = (int) ($imageWidth * $maxScale);
536
+ $imageHeight = (int) ($imageHeight * $maxScale);
537
+ } else if ($mediaSizeMode === self::MEDIA_SIZE_MODE_SCALED) {
538
+ // Somehow the full width on mobile is 380, so I resize image height on same ratio
539
+ $resizedWidthFactor = (double) (self::DEFAULT_WIDTH / (int) $imageWidth);
540
+ $imageWidth = self::DEFAULT_WIDTH;
541
+ $imageHeight = (int) ($imageHeight * $resizedWidthFactor);
542
+ } else {
543
+ $ampImg->setAttribute('layout', 'responsive');
544
+ }
545
+
546
+ $ampImg->setAttribute('src', $imageURL);
547
+ $ampImg->setAttribute('width', (string) $imageWidth);
548
+ $ampImg->setAttribute('height', (string) $imageHeight);
549
+
550
+ $caption = $image->getCaption();
551
+ if ($caption) {
552
+ $ampFigure = $this->buildCaption($caption, $context, $ampImg);
553
+
554
+ // Replaces the top level image element with the figure
555
+ $ampImg = $ampFigure;
556
+ }
557
+
558
+ if ($withContainer) {
559
+ $ampImgContainer->appendChild($ampImg);
560
+ }
561
+
562
+ return ($withContainer) ? $ampImgContainer : $ampImg;
563
+ }
564
+
565
+ private function buildGIF($image, $context, $cssClass, $withContainer = true)
566
+ {
567
+ if ($withContainer) {
568
+ $ampImgContainer = $context->createElement('div', null, $cssClass);
569
+ }
570
+
571
+ $ampImg = $context->getDocument()->createElement('amp-anim');
572
+ $imageURL = $image->getUrl();
573
+
574
+ $imageDimensions = $this->getMediaDimensions($imageURL, AMPContext::MEDIA_TYPE_IMAGE);
575
+ $imageWidth = $imageDimensions[0];
576
+ $imageHeight = $imageDimensions[1];
577
+
578
+ $ampImg->setAttribute('src', $imageURL);
579
+ $ampImg->setAttribute('width', $imageWidth);
580
+ $ampImg->setAttribute('height', $imageHeight);
581
+
582
+ $caption = $image->getCaption();
583
+ if ($caption) {
584
+ $ampFigure = $this->buildCaption($caption, $context, $image);
585
+
586
+ // Replaces the top level image with the figure
587
+ $ampImg = $ampFigure;
588
+ }
589
+
590
+ if ($withContainer) {
591
+ $ampImgContainer->appendChild($ampImg);
592
+ }
593
+
594
+ return ($withContainer) ? $ampImgContainer : $ampImg;
595
+ }
596
+
597
+ private function buildVideo($video, $context, $cssClass)
598
+ {
599
+ $ampVideoContainer = $context->createElement('div', null, $cssClass);
600
+
601
+ $ampVideo = $context->getDocument()->createElement('amp-video');
602
+ $videoUrl = $video->getUrl();
603
+
604
+ $videoDimensions = $this->getMediaDimensions($videoUrl, AMPContext::MEDIA_TYPE_VIDEO);
605
+ $videoWidth = $videoDimensions[0];
606
+ $videoHeight = $videoDimensions[1];
607
+
608
+ $ampVideo->setAttribute('src', $this->ensureHttps($context, $videoUrl));
609
+ $ampVideo->setAttribute('width', $videoWidth);
610
+ $ampVideo->setAttribute('height', $videoHeight);
611
+
612
+ $caption = $video->getCaption();
613
+ if ($caption) {
614
+ $ampFigure = $this->buildCaption($caption, $context, $ampVideo);
615
+
616
+ // Replaces the top level video with the figure
617
+ $ampVideo = $ampFigure;
618
+ }
619
+
620
+ $ampVideoContainer->appendChild($ampVideo);
621
+
622
+ return $ampVideoContainer;
623
+ }
624
+
625
+ private function buildAudio($video, $context, $cssClass)
626
+ {
627
+ $ampAudio = $context->createElement('div', null, $cssClass);
628
+
629
+ // TODO Audio is not yet covered into first version of converter.
630
+
631
+ return $ampAudio;
632
+ }
633
+
634
+ private function buildSlideshow($slideshow, $context, $cssClass)
635
+ {
636
+ $ampCarouselContainer = $context->createElement('div', null, $cssClass);
637
+
638
+ $ampCarousel = $context->getDocument()->createElement('amp-carousel');
639
+
640
+ foreach ($slideshow->getArticleImages() as $image) {
641
+ $ampImage = $this->buildImage($image, $context, 'slideshow-image', true, self::MEDIA_SIZE_MODE_SCALED);
642
+ $ampCarousel->appendChild($ampImage);
643
+
644
+ if (!isset($imageWidth) && !isset($imageHeight)) {
645
+ $imageUrl = $image->getUrl();
646
+ $imageDimensions = $this->getMediaDimensions($imageUrl, AMPContext::MEDIA_TYPE_IMAGE);
647
+ $imageWidth = $imageDimensions[0];
648
+ $imageHeight = $imageDimensions[1];
649
+ }
650
+ }
651
+ $ampCarousel->setAttribute('width', (string) $imageWidth);
652
+ $ampCarousel->setAttribute('height', (string) $imageHeight);
653
+
654
+ $caption = $slideshow->getCaption();
655
+ if ($caption) {
656
+ $ampFigure = $this->buildCaption($caption, $context, $ampCarousel);
657
+
658
+ // Replaces the top level carousel with the figure
659
+ $ampCarousel = $ampFigure;
660
+ }
661
+
662
+ $ampCarouselContainer->appendChild($ampCarousel);
663
+
664
+ $context->withPreviousElementIdentifier($cssClass);
665
+
666
+ return $ampCarouselContainer;
667
+ }
668
+
669
+ private function buildCaption($caption, $context, $ampCaptionedElement)
670
+ {
671
+ $container = $context->createElement('figure', null, 'figure');
672
+
673
+ $fontSize = $caption->getFontSize();
674
+ $cssClass = 'figcaption-' . ($fontSize ? $fontSize : 'small');
675
+
676
+ $ampCaption = $context->createElement('figcaption', $container, $cssClass);
677
+
678
+ $position = $caption->getPosition();
679
+ if (!$position) {
680
+ $position = Caption::POSITION_BELOW;
681
+ }
682
+
683
+ if ($position === Caption::POSITION_BELOW) {
684
+ $container->appendChild($ampCaptionedElement);
685
+ $container->appendChild($ampCaption);
686
+ } else {
687
+ $container->appendChild($ampCaption);
688
+ $container->appendChild($ampCaptionedElement);
689
+ }
690
+
691
+ // Title
692
+ $title = $caption->getTitle();
693
+ if ($title) {
694
+ $ampCaptionTitle = $context->createElement('h1', $ampCaption);
695
+ $ampTitleText = $title->textToDOMDocumentFragment($context->getDocument());
696
+ $ampCaptionTitle->appendChild($ampTitleText);
697
+ }
698
+
699
+ // SubTitle
700
+ $subTitle = $caption->getSubTitle();
701
+ if ($subTitle) {
702
+ $ampCaptionSubTitle = $context->createElement('h2', $ampCaption);
703
+ $ampSubTitleText = $subTitle->textToDOMDocumentFragment($context->getDocument());
704
+ $ampCaptionSubTitle->appendChild($ampSubTitleText);
705
+ }
706
+
707
+ // Text
708
+ $ampCaptionText = $caption->textToDOMDocumentFragment($context->getDocument());
709
+ $ampCaption->appendChild($ampCaptionText);
710
+
711
+ // Credit
712
+ $credit = $caption->getCredit();
713
+ if ($credit) {
714
+ $ampCaptionCredit = $context->createElement('cite', $ampCaption);
715
+ $ampCreditText = $credit->textToDOMDocumentFragment($context->getDocument());
716
+ $ampCaptionCredit->appendChild($ampCreditText);
717
+ }
718
+
719
+ $ampCSSClasses = array();
720
+ $ampCSSClasses[] = $context->buildCssClass('figcaption');
721
+
722
+ if ($caption->getFontSize()) {
723
+ $ampCSSClasses[] = $context->buildCssClass($caption->getFontSize());
724
+ } else {
725
+ $ampCSSClasses[] = $context->buildCssClass(Caption::SIZE_SMALL);
726
+ }
727
+ if ($caption->getTextAlignment()) {
728
+ $ampCSSClasses[] = $context->buildCssClass($caption->getTextAlignment());
729
+ }
730
+ if ($caption->getPosition()) {
731
+ $ampCSSClasses[] = $context->buildCssClass($caption->getPosition());
732
+ }
733
+ if ($caption->getVerticalAlignment()) {
734
+ $ampCSSClasses[] = $context->buildCssClass($caption->getVerticalAlignment());
735
+ }
736
+
737
+ $ampCaption->setAttribute('class', implode(' ', $ampCSSClasses));
738
+
739
+ return $container;
740
+ }
741
+
742
+ private function buildIframe($interactive, $context, $cssClass, $isCaptionable)
743
+ {
744
+ $srcUrl = $interactive->getSource();
745
+
746
+ // Based on $srcUrl build:
747
+ // TODO check URLs for youtube, Facebook, Twitter, Instagram, Vimeo, Vine, playbuzz, soundcloud
748
+
749
+ $iframeContainer = $context->createElement('div', null, $cssClass);
750
+
751
+ $ampIframe = $context->getDocument()->createElement('amp-iframe');
752
+ $ampIframe->setAttribute('src', $this->ensureHttps($context, $srcUrl));
753
+ $ampIframe->setAttribute('width', self::DEFAULT_WIDTH);
754
+ $ampIframe->setAttribute('height', self::DEFAULT_HEIGHT);
755
+ $ampIframe->setAttribute('sandbox', 'allow-scripts allow-same-origin');
756
+ $ampIframe->setAttribute('layout', 'responsive');
757
+ $ampIframe->setAttribute('frameborder', '0');
758
+
759
+ if ($isCaptionable) {
760
+ $caption = $interactive->getCaption();
761
+ if ($caption) {
762
+ $ampFigure = $this->buildCaption($caption, $context, $ampIframe);
763
+
764
+ // Replaces the top level iframe with the figure
765
+ $ampIframe = $ampFigure;
766
+ }
767
+ }
768
+
769
+ $iframeContainer->appendChild($ampIframe);
770
+
771
+ return $iframeContainer;
772
+ }
773
+
774
+ private function buildAd($ad, $context, $cssClass)
775
+ {
776
+ $srcUrl = $ad->getSource();
777
+ $html = $ad->getHtml();
778
+ $height = $ad->getHeight();
779
+ $width = $ad->getWidth();
780
+
781
+ $ampAdContainer = $context->createElement('div', null, $cssClass);
782
+ $ampAd = $context->createElement('amp-iframe', $ampAdContainer);
783
+
784
+ if (!Type::isTextEmpty($srcUrl)) {
785
+ $ampAd->setAttribute('src', $this->ensureHttps($context, $srcUrl));
786
+ }
787
+ $ampAd->setAttribute('width', $width ? $width : self::DEFAULT_WIDTH);
788
+ $ampAd->setAttribute('height', $height ? $height : self::DEFAULT_HEIGHT);
789
+ $ampAd->setAttribute('sandbox', 'allow-scripts allow-same-origin');
790
+ $ampAd->setAttribute('layout', 'responsive');
791
+ $ampAd->setAttribute('frameborder', '0');
792
+
793
+ if ($html) {
794
+ $iframeBody = $context->getDocument()->importNode($html, true);
795
+ $ampAd->appendChild($iframeBody);
796
+ }
797
+
798
+ return $ampAdContainer;
799
+ }
800
+
801
+ private function buildMaps($map, $context, $cssClass)
802
+ {
803
+ $geoTag = $map->getGeotag();
804
+ if (!$geoTag) {
805
+ $context->addWarning('Map::getGeotag() returned an empty map definition.', $map);
806
+ return $context->createElement('div');
807
+ }
808
+
809
+ $googleAPIKey = isset($this->properties[self::GOOGLE_MAPS_KEY]) ? $this->properties[self::GOOGLE_MAPS_KEY] : null;
810
+ $googleAPIKey = $this->getObserver()->applyFilters('GET_GOOGLE_MAPS_KEY', $googleAPIKey, $this->properties, $context);
811
+
812
+ if (Type::isTextEmpty($googleAPIKey)) {
813
+ $context->addWarning('Facebook Instant Article Maps are converted into Google Maps by default. To accomplish that, you will need to inform into your $properties parameter the "google_maps_key" => "<your key>". Find more here how to get your Google Maps key: https://developers.google.com/maps/documentation/javascript/get-api-key', $map);
814
+ return $context->createElement('div');
815
+ }
816
+
817
+ $coordinates = $this->extractCoordinatesFromGeotag($geoTag->getScript());
818
+ if (!$coordinates || empty($coordinates)) {
819
+ $context->addWarning('Map::getGeotag invalid or incompatible. We could not extract latitud and/or longitud from it.', $geoTag->getScript());
820
+ return $context->createElement('div');
821
+ }
822
+ $latitud = $coordinates[0];
823
+ $longitud = $coordinates[1];
824
+
825
+ // By default it will use Google Maps as mapping system
826
+ // The URL should be: https://www.google.com/maps/embed/v1/place?key=<API_GOOGLE_KEY>q=%2244.0,122.0%22
827
+ $srcUrl = "https://www.google.com/maps/embed/v1/place?key=$googleAPIKey&q=%22$latitud,$longitud%22";
828
+
829
+ // <amp-iframe
830
+ // width="600"
831
+ // height="400"
832
+ // layout="responsive"
833
+ // sandbox="allow-scripts allow-same-origin allow-popups"
834
+ // frameborder="0"
835
+ // src="https://www.google.com/maps/embed/v1/place?key=<key>&q="44.0,122.0">
836
+ // </amp-iframe>
837
+
838
+ $ampMap = $context->createElement('div', null, $cssClass);
839
+
840
+ $ampIframe = $context->createElement('amp-iframe', $ampMap);
841
+ $ampIframe->setAttribute('src', $srcUrl);
842
+ $ampIframe->setAttribute('width', self::DEFAULT_WIDTH);
843
+ $ampIframe->setAttribute('height', self::DEFAULT_HEIGHT);
844
+ $ampIframe->setAttribute('sandbox', 'allow-scripts allow-same-origin allow-popups');
845
+ $ampIframe->setAttribute('layout', 'responsive');
846
+ $ampIframe->setAttribute('frameborder', '0');
847
+
848
+ $caption = $map->getCaption();
849
+ if ($caption) {
850
+ // Replace the top level map with the wrapped figure with caption
851
+ $ampMap = $this->buildCaption($caption, $context, $ampMap);
852
+ }
853
+
854
+ return $ampMap;
855
+ }
856
+
857
+ /**
858
+ * Extracts latitud and longitud from Geotag json.
859
+ * Example json expected on $mapJson:
860
+ * <code>
861
+ * {
862
+ * "type": "Feature",
863
+ * "geometry": {
864
+ * "type": "Point",
865
+ * "coordinates": [23.166667, 89.216667] // This is the content we are looking for.
866
+ * },
867
+ * "properties": {
868
+ * "title": "Jessore, Bangladesh",
869
+ * "radius": 750000,
870
+ * "pivot": true,
871
+ * "style": "satellite",
872
+ * }
873
+ * }
874
+ * </code>
875
+ * @param string $mapJson The geotag format json string. It will look for the geometry->coordinates attribute.
876
+ */
877
+ private function extractCoordinatesFromGeotag($mapJson)
878
+ {
879
+ $geotag = json_decode($mapJson, true);
880
+ if (isset($geotag['type'])) {
881
+ if ($geotag['type'] === 'FeatureCollection' && isset($geotag['features'])) {
882
+ $features = $geotag['features'];
883
+ foreach ($features as $feature) {
884
+ if (isset($feature['geometry']) && isset($feature['geometry']['coordinates'])) {
885
+ return $feature['geometry']['coordinates'];
886
+ }
887
+ }
888
+ } else if (isset($geotag['geometry']) && isset($geotag['geometry']['coordinates'])) {
889
+ return $geotag['geometry']['coordinates'];
890
+ }
891
+ }
892
+ return null;
893
+ }
894
+
895
+ private function buildCustomCSS($context)
896
+ {
897
+ $ampCustomCSS = $context->getDocument()->createElement('style');
898
+ $ampCustomCSS->setAttribute('amp-custom', '');
899
+ // Note: Custom CSS content will be generated after the whole article is processed
900
+ return $ampCustomCSS;
901
+ }
902
+
903
+ /**
904
+ * Retrieves the Width and Height of the media.
905
+ * Media size lookup order:
906
+ * 1. The array $properties[MEDIA_SIZES_KEY][$mediaURL]
907
+ * 2. Local directory cache (from getMediaDimensionsFromCache(), configured by $properties[MEDIA_CACHE_FOLDER_KEY])
908
+ * 3. Download the image and get the size, if enabled by $properties[ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY]
909
+ * @param string $mediaURL The media's URL
910
+ * @param string $mediaType One of the MEDIA_TYPE_* constants (optional)
911
+ * @return array [ width, height ]
912
+ */
913
+ public function getMediaDimensions($mediaURL, $mediaType = null)
914
+ {
915
+ if (array_key_exists(self::MEDIA_SIZES_KEY, $this->properties) &&
916
+ array_key_exists($mediaURL, $this->properties[self::MEDIA_SIZES_KEY])) {
917
+ return $this->properties[self::MEDIA_SIZES_KEY][$mediaURL];
918
+ }
919
+
920
+ $mediaDimensions = $this->getMediaDimensionsFromCache($mediaURL);
921
+ if ($mediaDimensions) {
922
+ return $mediaDimensions;
923
+ }
924
+
925
+ if ($mediaType === AMPContext::MEDIA_TYPE_IMAGE &&
926
+ array_key_exists(self::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY, $this->properties) &&
927
+ $this->properties[self::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY] === true) {
928
+ $retrievedSizes = getimagesize($mediaURL);
929
+ if ($retrievedSizes && !empty($retrievedSizes) && $retrievedSizes[0] !== 0) {
930
+ return $retrievedSizes;
931
+ }
932
+ }
933
+
934
+ $width = array_key_exists(self::DEFAULT_MEDIA_WIDTH_KEY, $this->properties)
935
+ ? $this->properties[self::DEFAULT_MEDIA_WIDTH_KEY]
936
+ : self::DEFAULT_WIDTH;
937
+ $height = array_key_exists(self::DEFAULT_MEDIA_HEIGHT_KEY, $this->properties)
938
+ ? $this->properties[self::DEFAULT_MEDIA_HEIGHT_KEY]
939
+ : self::DEFAULT_HEIGHT;
940
+
941
+ return array($width, $height);
942
+ }
943
+
944
+ private function getMediaDimensionsFromCache($mediaURL)
945
+ {
946
+ if (!array_key_exists(self::MEDIA_CACHE_FOLDER_KEY, $this->properties)) {
947
+ return null;
948
+ }
949
+
950
+ $mediaCacheFolder = $this->properties[self::MEDIA_CACHE_FOLDER_KEY];
951
+ if (!file_exists($mediaCacheFolder)) {
952
+ return null;
953
+ }
954
+
955
+ $fileName = basename($mediaURL);
956
+ if (!$fileName) {
957
+ return null;
958
+ }
959
+
960
+ $cachedFile = $mediaCacheFolder . DIRECTORY_SEPARATOR . $fileName;
961
+ if (!file_exists($cachedFile)) {
962
+ return null;
963
+ }
964
+
965
+ return getimagesize($cachedFile);
966
+ }
967
+
968
+ public function getCustomCSS($context)
969
+ {
970
+ $stylesFolder = (array_key_exists(AMPArticle::STYLES_FOLDER_KEY, $this->properties)
971
+ ? $this->properties[AMPArticle::STYLES_FOLDER_KEY]
972
+ : __DIR__) . '/';
973
+
974
+ $styleName = $this->instantArticle->getStyle();
975
+ if ($styleName == null) {
976
+ $styleName = 'default';
977
+ }
978
+ // Try to get the Instant Articles styles from properties
979
+ if (array_key_exists(AMPArticle::OVERRIDE_STYLES_KEY, $this->properties)) {
980
+ $styles = $this->properties[AMPArticle::OVERRIDE_STYLES_KEY];
981
+ } else {
982
+ if (!file_exists($stylesFolder . $styleName . '.style.json')) {
983
+ $stylesFile = file_get_contents(__DIR__ . '/configuration/default-amp.style.json');
984
+ $styles = json_decode($stylesFile, true);
985
+ } else {
986
+ $stylesFile = file_get_contents($stylesFolder . $styleName . '.style.json');
987
+ $styles = json_decode($stylesFile, true);
988
+ }
989
+ }
990
+
991
+ if (file_exists($stylesFolder . 'global.amp-custom.css')) {
992
+ $globalCSSFile = file_get_contents($stylesFolder . 'global.amp-custom.css');
993
+ $globalCSSFile = str_replace(array("\r", "\n"), ' ', $globalCSSFile);
994
+ }
995
+
996
+ if (file_exists($stylesFolder . $styleName . '.amp-custom.css')) {
997
+ $customCSSFile = file_get_contents($stylesFolder . $styleName . '.amp-custom.css');
998
+ $customCSSFile = str_replace(array("\r", "\n"), ' ', $customCSSFile);
999
+ }
1000
+
1001
+ if (!isset($globalCSSFile) && !isset($customCSSFile)) {
1002
+ $defaultCSSFile = file_get_contents(__DIR__ . '/configuration/global.amp.css');
1003
+ $defaultCSSFile = str_replace(array("\r", "\n"), ' ', $defaultCSSFile);
1004
+ }
1005
+
1006
+ $this->articleColorsStyles($styles, $context);
1007
+ $this->articleHeadStyles($styles, $context);
1008
+ $this->articleBodyStyles($styles, $context);
1009
+ $this->articleQuoteStyles($styles, $context);
1010
+ $this->articleCaptionStyles($styles, $context);
1011
+ $this->articleFooterStyles($styles, $context);
1012
+ return
1013
+ $context->getCssBuilder()->build(false).
1014
+ (isset($globalCSSFile) ? $globalCSSFile : '').
1015
+ (isset($customCSSFile) ? $customCSSFile : '').
1016
+ (!isset($globalCSSFile) && !isset($customCSSFile) ? $defaultCSSFile : '');
1017
+ }
1018
+
1019
+ private function articleColorsStyles($styles, $context)
1020
+ {
1021
+ $backgroundColor = AMPArticle::toRGB($styles['background_color']);
1022
+ $context->getCssBuilder()->addProperty('html', 'background-color', $backgroundColor);
1023
+ }
1024
+
1025
+ private function articleHeadStyles($styles, $context)
1026
+ {
1027
+ $mappings = array(
1028
+ $context->buildCssSelector('header-category') => 'kicker',
1029
+ $context->buildCssSelector('header-h1') => 'title',
1030
+ $context->buildCssSelector('header-h2') => 'subtitle',
1031
+ $context->buildCssSelector('header h3') => 'byline'
1032
+ );
1033
+
1034
+ $dateFormatMappings = array(
1035
+ 'MONTH_AND_DAY' => 'F d',
1036
+ 'MONTH_AND_YEAR' => 'F Y',
1037
+ 'MONTH_DAY_YEAR' => 'F d, Y',
1038
+ 'YEAR' => 'Y',
1039
+ 'MONTH_DAY_YEAR_TIME' => 'F d, Y H:i A',
1040
+ );
1041
+ if (array_key_exists('date_style', $styles)) {
1042
+ $dateFormat = $styles['date_style'];
1043
+ if (array_key_exists($dateFormat, $dateFormatMappings)) {
1044
+ $this->dateFormat = $dateFormatMappings[$dateFormat];
1045
+ }
1046
+ }
1047
+
1048
+ return $this->buildCSSRulesFromMappings($mappings, $styles, $context) .
1049
+ $this->articleLogo($styles, $context);
1050
+ }
1051
+
1052
+ private function tryGetColor($sourceStyles, $colorStylePropertyName)
1053
+ {
1054
+ if (array_key_exists($colorStylePropertyName, $sourceStyles)) {
1055
+ $color = $sourceStyles[$colorStylePropertyName];
1056
+ if ($color) {
1057
+ return self::toRGB($color);
1058
+ }
1059
+ }
1060
+
1061
+ return null;
1062
+ }
1063
+
1064
+ private function articleLogo($styles, $context)
1065
+ {
1066
+ $headerStyles = $styles['header'];
1067
+
1068
+ $backgroundColor = $this->tryGetColor($headerStyles, 'background_color');
1069
+ if ($backgroundColor) {
1070
+ $context->getCssBuilder()->addToSelector('header-bar', 'background-color', $backgroundColor);
1071
+ }
1072
+
1073
+ $barColor = $this->tryGetColor($headerStyles, 'bar_color');
1074
+ if ($barColor) {
1075
+ $cssSelector= '.' . $context->buildCssClass('spacing') . '.after-header-bar';
1076
+ $context->getCssBuilder()->addProperty($cssSelector, 'border-top-color', $barColor);
1077
+ $context->getCssBuilder()->addProperty($cssSelector, 'border-top-style', 'solid');
1078
+ $context->getCssBuilder()->addProperty($cssSelector, 'border-top-width', '1px');
1079
+ }
1080
+
1081
+ if (!array_key_exists('logo', $headerStyles)) {
1082
+ return '';
1083
+ }
1084
+ $logoStyles = $headerStyles['logo'];
1085
+
1086
+ $dataURL = array_key_exists('dataURL', $logoStyles)
1087
+ ? $logoStyles['dataURL']
1088
+ : null;
1089
+ $fullResURL = $logoStyles['full_resolution_url'];
1090
+
1091
+ $defaultLogoHeight = $this->observer->applyFilters('DEFAULT_LOGO_HEIGHT', self::DEFAULT_LOGO_HEIGHT);
1092
+ $defaultLogoWidth = $this->observer->applyFilters('DEFAULT_LOGO_WIDTH', self::DEFAULT_LOGO_WIDTH);
1093
+ $logoWidth = $logoStyles['full_resolution_width'];
1094
+ $logoHeight = $logoStyles['full_resolution_height'];
1095
+ $resizeScale = $headerStyles['logo_scale'] || 1.0;
1096
+ $resizeScale *= min(
1097
+ $defaultLogoHeight / $logoHeight,
1098
+ $defaultLogoWidth / $logoWidth
1099
+ );
1100
+
1101
+ $logoURL = $dataURL ? $dataURL : $fullResURL;
1102
+ $scaledLogoWidth = (int) ($logoWidth * $resizeScale);
1103
+ $scaledLogoHeight = (int) ($logoHeight * $resizeScale);
1104
+ $this->logo = new AMPImage($logoURL, $scaledLogoWidth, $scaledLogoHeight);
1105
+ }
1106
+
1107
+ private function articleBodyStyles($styles, $context)
1108
+ {
1109
+ $mappings = array(
1110
+ $context->buildCssSelector('h1') => 'primary_heading',
1111
+ $context->buildCssSelector('h2') => 'secondary_heading',
1112
+ $context->buildCssSelector('p') => 'body_text',
1113
+ $context->buildCssSelector('article a') => 'inline_link',
1114
+ );
1115
+ $this->buildCSSRulesFromMappings($mappings, $styles, $context);
1116
+ }
1117
+
1118
+ private function articleQuoteStyles($styles, $context)
1119
+ {
1120
+ $mappings = array(
1121
+ $context->buildCssSelector('blockquote') => 'block_quote',
1122
+ $context->buildCssSelector('pullquote') => 'pull_quote',
1123
+ $context->buildCssSelector('pullquote cite') => 'pull_quote_attribution',
1124
+ );
1125
+ $this->buildCSSRulesFromMappings($mappings, $styles, $context);
1126
+ }
1127
+
1128
+ private function articleCaptionStyles($styles, $context)
1129
+ {
1130
+ $mappings = array(
1131
+ '.ia2amp-op-small h1' => 'caption_title_small',
1132
+ '.ia2amp-op-small h2' => 'caption_description_small',
1133
+
1134
+ '.ia2amp-op-medium h1' => 'caption_title',
1135
+ '.ia2amp-op-medium h2' => 'caption_description',
1136
+
1137
+ '.ia2amp-op-large h1' => 'caption_title_large',
1138
+ '.ia2amp-op-large h2' => 'caption_description_large',
1139
+
1140
+ '.ia2amp-op-extra-large h1' => 'caption_title_extra_large',
1141
+ '.ia2amp-op-extra-large h2' => 'caption_description_extra_large',
1142
+
1143
+ '.ia2amp-figcaption cite' => 'caption_credit',
1144
+ );
1145
+ $this->buildCSSRulesFromMappings($mappings, $styles, $context);
1146
+ }
1147
+
1148
+ private function articleFooterStyles($styles, $context)
1149
+ {
1150
+ $mappings = array(
1151
+ $context->buildCssSelector('footer') => 'footer',
1152
+ );
1153
+ $this->buildCSSRulesFromMappings($mappings, $styles, $context);
1154
+ }
1155
+
1156
+ private function buildTextCSSDeclarationBlock($selector, $textStyles, $textType, $context)
1157
+ {
1158
+ $mappings = array(
1159
+ 'font-family' => 'font',
1160
+ 'text-align' => 'text_alignment',
1161
+ 'display' => 'display',
1162
+ );
1163
+ $filteredMappings = AMPArticle::filterMappings($mappings, $textStyles);
1164
+
1165
+ $textTransformMappings = array(
1166
+ 'ALL_CAPS' => 'uppercase',
1167
+ 'ALL_LOWER_CASE' => 'lowercase',
1168
+ 'NONE' => 'none',
1169
+ );
1170
+ if (array_key_exists('capitalization', $textStyles)) {
1171
+ $filteredMappings['text-transform'] = $textTransformMappings[$textStyles['capitalization']];
1172
+ }
1173
+
1174
+ if (array_key_exists('underline', $textStyles) && $textStyles['underline'] != 'NONE') {
1175
+ $filteredMappings['text-decoration'] = 'underline';
1176
+ }
1177
+
1178
+ if (array_key_exists('background_color', $textStyles)) {
1179
+ $filteredMappings['background-color'] = AMPArticle::toRGB($textStyles['background_color']);
1180
+ }
1181
+
1182
+ if (array_key_exists('color', $textStyles)) {
1183
+ $filteredMappings['color'] = AMPArticle::toRGB($textStyles['color']);
1184
+ }
1185
+
1186
+ $spacingMappings = array(
1187
+ 'NONE' => 0,
1188
+ 'DOCUMENT_MARGIN' => AMPArticle::DEFAULT_MARGIN,
1189
+ 'EXTRA_SMALL' => 16,
1190
+ 'SMALL' => 32,
1191
+ 'MEDIUM' => 46,
1192
+ 'LARGE' => 64,
1193
+ 'EXTRA_LARGE' => 96,
1194
+ );
1195
+ $marginMappings = AMPArticle::getSpacingDeclarationBlocks($spacingMappings, 'margin', $textStyles);
1196
+ $filteredMappings = array_merge($filteredMappings, $marginMappings);
1197
+ $paddingMappings = AMPArticle::getSpacingDeclarationBlocks($spacingMappings, 'padding', $textStyles);
1198
+ $filteredMappings = array_merge($filteredMappings, $paddingMappings);
1199
+
1200
+ $borderMappings = AMPArticle::getBorderDeclarationBlocks($textStyles);
1201
+ $filteredMappings = array_merge($filteredMappings, $borderMappings);
1202
+
1203
+ foreach ($filteredMappings as $filteredKey => $cssValue) {
1204
+ $context->getCssBuilder()->addProperty($selector, $filteredKey, $cssValue);
1205
+ }
1206
+ }
1207
+
1208
+ private static function filterMappings($mappings, $styles)
1209
+ {
1210
+ $result = array();
1211
+ foreach ($mappings as $cssKey => $styleKey) {
1212
+ if (array_key_exists($styleKey, $styles)) {
1213
+ $result[$cssKey] = $styles[$styleKey];
1214
+ }
1215
+ }
1216
+ return $result;
1217
+ }
1218
+
1219
+ private static function getSpacingDeclarationBlocks($spacingMappings, $spacingType, $textStyles)
1220
+ {
1221
+ $directions = array(
1222
+ 'top',
1223
+ 'right',
1224
+ 'bottom',
1225
+ 'left',
1226
+ );
1227
+ if (!array_key_exists($spacingType, $textStyles)) {
1228
+ return array();
1229
+ }
1230
+ $spacingStyles = $textStyles[$spacingType];
1231
+ $spacings = array();
1232
+ foreach ($directions as $direction) {
1233
+ $spacing = AMPArticle::getDirectionSpacing($spacingMappings, $direction, $spacingStyles);
1234
+ $spacings[] = $spacing != 0 ? $spacing . 'px' : '0';
1235
+ }
1236
+ return array($spacingType => implode(' ', $spacings));
1237
+ }
1238
+
1239
+ private function buildCSSRulesFromMappings($mappings, $styles, $context)
1240
+ {
1241
+ foreach ($mappings as $selector => $objectKey) {
1242
+ if (array_key_exists($objectKey, $styles)) {
1243
+ $this->buildTextCSSDeclarationBlock($selector, $styles[$objectKey], $objectKey, $context);
1244
+ }
1245
+ }
1246
+ }
1247
+
1248
+ private static function getDirectionSpacing($spacingMappings, $direction, $spacingStyles)
1249
+ {
1250
+ return array_key_exists($direction, $spacingStyles)
1251
+ ? AMPArticle::getSpacing($spacingMappings, $spacingStyles[$direction])
1252
+ : 0;
1253
+ }
1254
+
1255
+ private static function getSpacing($spacingMappings, $spacingDirectionStyles)
1256
+ {
1257
+ $size = $spacingDirectionStyles['size'];
1258
+ $scalingFactor = $spacingDirectionStyles['scaling_factor'];
1259
+ return $spacingMappings[$size] * $scalingFactor;
1260
+ }
1261
+
1262
+ private static function getBorderDeclarationBlocks($textStyles)
1263
+ {
1264
+ $directions = array(
1265
+ 'top',
1266
+ 'right',
1267
+ 'bottom',
1268
+ 'left',
1269
+ );
1270
+ if (!array_key_exists('border', $textStyles)) {
1271
+ return array();
1272
+ }
1273
+ $borderStyles = $textStyles['border'];
1274
+ $declarationBlocks = array();
1275
+ $borderWidths = array();
1276
+ foreach ($directions as $direction) {
1277
+ if (array_key_exists($direction, $borderStyles)) {
1278
+ $borderDirectionStyles = $borderStyles[$direction];
1279
+ $borderWidth = $borderDirectionStyles['width'];
1280
+
1281
+ if (array_key_exists('color', $borderDirectionStyles)) {
1282
+ $declarationBlocks["border-$direction-color"] = AMPArticle::toRGB($borderDirectionStyles['color']);
1283
+ }
1284
+ } else {
1285
+ $borderWidth = 0;
1286
+ }
1287
+ $borderWidths[] = $borderWidth !== 0 ? $borderWidth . 'px' : '0';
1288
+ }
1289
+ $declarationBlocks['border-width'] = implode(' ', $borderWidths);
1290
+ $declarationBlocks['border-style'] = 'solid';
1291
+ return $declarationBlocks;
1292
+ }
1293
+
1294
+ public static function toRGB($color)
1295
+ {
1296
+ // Normalize #FFFFFF to ffffff
1297
+ $color = strtolower($color);
1298
+ if (substr($color, 0, 1) == '#') {
1299
+ $color = substr($color, 1);
1300
+ }
1301
+
1302
+ // Match correct patter for each strlen
1303
+ switch (strlen($color)) {
1304
+ case 3:
1305
+ // RGB
1306
+ $a = null;
1307
+ $r = hexdec(substr($color, 0, 1) . substr($color, 0, 1));
1308
+ $g = hexdec(substr($color, 1, 1) . substr($color, 1, 1));
1309
+ $b = hexdec(substr($color, 2, 1) . substr($color, 2, 1));
1310
+ break;
1311
+ case 4:
1312
+ // ARGB
1313
+ $a = hexdec(substr($color, 0, 1) . substr($color, 0, 1));
1314
+ $r = hexdec(substr($color, 1, 1) . substr($color, 1, 1));
1315
+ $g = hexdec(substr($color, 2, 1) . substr($color, 2, 1));
1316
+ $b = hexdec(substr($color, 3, 1) . substr($color, 3, 1));
1317
+ break;
1318
+ case 6:
1319
+ // RRGGBB
1320
+ $a = null;
1321
+ $r = hexdec(substr($color, 0, 2));
1322
+ $g = hexdec(substr($color, 2, 2));
1323
+ $b = hexdec(substr($color, 4, 2));
1324
+ break;
1325
+ case 8:
1326
+ // AARRGGBB
1327
+ $a = hexdec(substr($color, 0, 2));
1328
+ $r = hexdec(substr($color, 2, 2));
1329
+ $g = hexdec(substr($color, 4, 2));
1330
+ $b = hexdec(substr($color, 6, 2));
1331
+ break;
1332
+ }
1333
+
1334
+ $alpha = 1.0;
1335
+ // Alpha range is 0-1, not 0-255: https://www.w3.org/TR/css-color-4/
1336
+ if ($a !== null) {
1337
+ $alpha = round($a / 255.0, 2);
1338
+ }
1339
+
1340
+ $rgb = [ $r, $g, $b ];
1341
+ $rgb = implode(',', $rgb);
1342
+
1343
+ return $alpha === 1.0
1344
+ ? 'rgb(' . $rgb . ')'
1345
+ : 'rgba(' . $rgb . ',' . $alpha . ')';
1346
+ }
1347
+
1348
+ public function buildSchemaOrgMetadata($context)
1349
+ {
1350
+ $header = $this->instantArticle->getHeader();
1351
+ $published = $header->getPublished();
1352
+ $modified = $header->getModified();
1353
+
1354
+ $metadata = array(
1355
+ '@context' => 'http://schema.org',
1356
+ '@type' => 'NewsArticle',
1357
+ 'mainEntityOfPage' => $this->instantArticle->getCanonicalURL(),
1358
+ 'headline' => $this->instantArticle->getHeader()->getTitle()->getPlainText(),
1359
+ 'datePublished' => date_format($published->getDatetime(), 'c'),
1360
+ 'description' => $this->instantArticle->getFirstParagraph()->getPlainText(),
1361
+ );
1362
+
1363
+ if ($modified) {
1364
+ $metadata['dateModified'] = date_format($modified->getDatetime(), 'c');
1365
+ }
1366
+
1367
+ $authors = $header->getAuthors();
1368
+ foreach ($authors as $author) {
1369
+ $metadata['author'] = array(
1370
+ '@type' => 'Person',
1371
+ 'name' => $author->getName(),
1372
+ );
1373
+ break;
1374
+ }
1375
+
1376
+ $cover = $this->observer->applyFilters('AMP_GETMETADATAIMAGE', $this->getMetadataImage($this->properties), $this->properties);
1377
+ if ($cover) {
1378
+ $metadata['image'] = $cover;
1379
+ }
1380
+
1381
+ $publisher = $this->observer->applyFilters('AMP_GETPUBLISHER', $this->getPublisher($this->properties), $this->properties);
1382
+ if ($publisher) {
1383
+ $metadata['publisher'] = $publisher;
1384
+ }
1385
+
1386
+ // Prevent URL slashes to be escaped
1387
+ return json_encode($metadata, JSON_UNESCAPED_SLASHES);
1388
+ }
1389
+
1390
+ public function getPublisher($properties)
1391
+ {
1392
+ $publisher = array_key_exists(self::PUBLISHER_KEY, $properties) ? $properties[self::PUBLISHER_KEY] : null;
1393
+
1394
+ if ($publisher && Type::is($publisher, Type::STRING)) {
1395
+ // String values will be treated as organization names
1396
+ $publisher = array(
1397
+ '@type' => 'Organization',
1398
+ 'name' => $publisher,
1399
+ );
1400
+ }
1401
+
1402
+ return $publisher;
1403
+ }
1404
+
1405
+ public function getMetadataImage($properties)
1406
+ {
1407
+ $imageURL = null;
1408
+ $header = $this->instantArticle->getHeader();
1409
+
1410
+ $cover = $header->getCover();
1411
+ if ($cover) {
1412
+ $imageURL = $this->getImageURLFromElement($cover);
1413
+ }
1414
+ if (!$imageURL) {
1415
+ // Article does not have cover image, look for the first suitable children
1416
+ foreach ($this->instantArticle->getChildren() as $child) {
1417
+ $imageURL = $this->getImageURLFromElement($child);
1418
+ if ($imageURL) {
1419
+ break;
1420
+ }
1421
+ }
1422
+ }
1423
+
1424
+ if ($imageURL) {
1425
+ $imageDimensions = $this->getMediaDimensions($imageURL, AMPContext::MEDIA_TYPE_IMAGE);
1426
+
1427
+ return array(
1428
+ '@type' => 'ImageObject',
1429
+ 'url' => $imageURL,
1430
+ 'width' => $imageDimensions[0],
1431
+ 'height' => $imageDimensions[1],
1432
+ );
1433
+ }
1434
+
1435
+ return null;
1436
+ }
1437
+
1438
+ private function getImageURLFromElement($element)
1439
+ {
1440
+ if (Type::is($element, Image::getClassName())) {
1441
+ return $element->getUrl();
1442
+ } else if (Type::is($element, Slideshow::getClassName())) {
1443
+ foreach ($element->getArticleImages() as $articleImage) {
1444
+ if ($articleImage->isValid()) {
1445
+ return $articleImage->getUrl();
1446
+ }
1447
+ }
1448
+ }
1449
+
1450
+ return null;
1451
+ }
1452
+
1453
+ private function ensureHttps($context, $url)
1454
+ {
1455
+ if (strpos($url, 'http:') !== false) {
1456
+ $context->addWarning('URLs for videos, iframes, analytics and ads should be HTTPS. Double check if this one is still valid using HTTPS protocol', $url);
1457
+ }
1458
+ return Type::isTextEmpty($url) ? $url : preg_replace("/^http:/i", "https:", $url);
1459
+ }
1460
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCaption.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Elements\Caption;
12
+
13
+ class AMPCaption
14
+ {
15
+ /**
16
+ * @var Context the conversion context holder
17
+ */
18
+ private $context;
19
+
20
+ /**
21
+ * @var Caption the Element Caption
22
+ */
23
+ private $caption;
24
+
25
+ /**
26
+ * @var DOMNode The DOMNode html element being captionized
27
+ */
28
+ private $ampTag;
29
+
30
+ /**
31
+ * @var DOMNode The Final container for Caption
32
+ */
33
+ private $container;
34
+
35
+ /**
36
+ * @var DOMNode The figcaption DOMNode that will hold the text content.
37
+ */
38
+ private $ampCaption;
39
+
40
+
41
+ /**
42
+ * @param Caption $caption The element from SDK that contains all Caption data.
43
+ * @param Context $context Conversion context var.
44
+ */
45
+ public function __construct($caption, $context, $ampCaptionedElement)
46
+ {
47
+ $this->caption = $caption;
48
+ $this->context = $context;
49
+ $this->ampTag = $ampCaptionedElement;
50
+ }
51
+
52
+ public static function create($caption, $context, $ampCaptionedElement)
53
+ {
54
+ return new AMPCaption($caption, $context, $ampCaptionedElement);
55
+ }
56
+
57
+ private function genContainer()
58
+ {
59
+ $this->container = $this->context->createElement('figure', null, 'figure');
60
+ }
61
+
62
+ private function appendCaptioned()
63
+ {
64
+ $fontSize = $this->caption->getFontSize();
65
+ $cssClass = 'figcaption-' . ($fontSize ? $fontSize : 'small');
66
+
67
+ $this->ampCaption = $this->context->createElement('figcaption', null, $cssClass);
68
+
69
+ $position = $this->caption->getPosition();
70
+ if (!$position) {
71
+ $position = Caption::POSITION_BELOW;
72
+ }
73
+
74
+ if ($position === Caption::POSITION_BELOW) {
75
+ $this->container->appendChild($this->ampTag);
76
+ $this->container->appendChild($this->ampCaption);
77
+ } else {
78
+ $this->container->appendChild($this->ampCaption);
79
+ $this->container->appendChild($this->ampTag);
80
+ }
81
+ }
82
+
83
+ private function genTitle()
84
+ {
85
+ // Title
86
+ $title = $this->caption->getTitle();
87
+ if ($title) {
88
+ $ampTitle = $this->context->createElement('h1', $this->ampCaption);
89
+ $ampTitleText = $title->textToDOMDocumentFragment($this->context->getDocument());
90
+ $ampTitle->appendChild($ampTitleText);
91
+ }
92
+ }
93
+
94
+ private function genSubtitle()
95
+ {
96
+ // SubTitle
97
+ $subTitle = $this->caption->getSubTitle();
98
+ if ($subTitle) {
99
+ $ampSubTitle = $this->context->createElement('h2', $this->ampCaption);
100
+ $ampSubTitleText = $subTitle->textToDOMDocumentFragment($this->context->getDocument());
101
+ $ampSubTitle->appendChild($ampSubTitleText);
102
+ }
103
+ }
104
+
105
+ private function genText()
106
+ {
107
+ // Text
108
+ $ampText = $this->caption->textToDOMDocumentFragment($this->context->getDocument());
109
+ $this->ampCaption->appendChild($ampText);
110
+ }
111
+
112
+ private function genCredit()
113
+ {
114
+ // Credit
115
+ $credit = $this->caption->getCredit();
116
+ if ($credit) {
117
+ $ampCredit = $this->context->createElement('cite', $this->ampCaption);
118
+ $ampCreditText = $credit->textToDOMDocumentFragment($this->context->getDocument());
119
+ $ampCredit->appendChild($ampCreditText);
120
+ }
121
+ }
122
+
123
+ private function applyStyleClasses()
124
+ {
125
+ $ampCSSClasses = array();
126
+ $ampCSSClasses[] = $this->context->buildCssClass('figcaption');
127
+
128
+ if ($this->caption->getFontSize()) {
129
+ $ampCSSClasses[] = $this->context->buildCssClass($this->caption->getFontSize());
130
+ } else {
131
+ $ampCSSClasses[] = $this->context->buildCssClass(Caption::SIZE_SMALL);
132
+ }
133
+ if ($this->caption->getTextAlignment()) {
134
+ $ampCSSClasses[] = $this->context->buildCssClass($this->caption->getTextAlignment());
135
+ }
136
+ if ($this->caption->getPosition()) {
137
+ $ampCSSClasses[] = $this->context->buildCssClass($this->caption->getPosition());
138
+ }
139
+ if ($this->caption->getVerticalAlignment()) {
140
+ $ampCSSClasses[] = $this->context->buildCssClass($this->caption->getVerticalAlignment());
141
+ }
142
+
143
+ $this->ampCaption->setAttribute('class', implode(' ', $ampCSSClasses));
144
+ }
145
+
146
+ public function build()
147
+ {
148
+ $this->genContainer();
149
+ $this->appendCaptioned();
150
+ $this->genTitle();
151
+ $this->genSubtitle();
152
+ $this->genText();
153
+ $this->genCredit();
154
+ $this->applyStyleClasses();
155
+
156
+ return $this->container;
157
+ }
158
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPContext.php ADDED
@@ -0,0 +1,709 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Elements\InstantArticle;
12
+
13
+ use Facebook\InstantArticles\Validators\Type;
14
+ use Facebook\InstantArticles\Utils\Warning;
15
+ use Facebook\InstantArticles\Utils\CSSBuilder;
16
+
17
+ class AMPContext
18
+ {
19
+ private $instantArticle;
20
+ private $document;
21
+
22
+ private $html;
23
+ private $head;
24
+ private $body;
25
+ private $article;
26
+ private $header;
27
+ private $headerBar;
28
+ private $headerBarLogo;
29
+ private $headerTitle;
30
+ private $headerAuthor;
31
+ private $headerKicker;
32
+ private $headerDate;
33
+ private $articleItems = array();
34
+ private $footer;
35
+
36
+ private $cssPrefix;
37
+ private $previousElementIdentifier;
38
+ private $previousSpacing;
39
+
40
+ private $warnings = array();
41
+
42
+ private $cssBuilder;
43
+
44
+ private $mediaSizes;
45
+ private $mediaCacheFolder;
46
+ private $enableDownloadForMediaSizing;
47
+ private $defaultWidth;
48
+ private $defaultHeight;
49
+
50
+ const MEDIA_TYPE_IMAGE = 'image';
51
+ const MEDIA_TYPE_VIDEO = 'video';
52
+
53
+ const DEFAULT_WIDTH = AMPArticle::DEFAULT_WIDTH;
54
+ const DEFAULT_HEIGHT = AMPArticle::DEFAULT_HEIGHT;
55
+
56
+ /**
57
+ * Private constructor. Use self::create($document, $instantArticle)
58
+ */
59
+ private function __construct()
60
+ {
61
+ }
62
+
63
+ /**
64
+ * Factory method to create the AMPContext
65
+ * @param DOMDocument $document The root document used on the context. If null informed, a new one will be created.
66
+ * @param InstantArticle $instantArticle The Element InstantArticle that will be used during conversion.
67
+ * @param string $cssPrefix The css prefix for building element classes.
68
+ */
69
+ public static function create($document, $instantArticle, $cssPrefix = "ia2amp-")
70
+ {
71
+ $context = new self();
72
+
73
+ return $context->withDocument($document)
74
+ ->withInstantArticle($instantArticle)
75
+ ->withCssPrefix($cssPrefix)
76
+ ->withCssBuilder(new CSSBuilder($cssPrefix));
77
+ }
78
+
79
+ /**
80
+ * Sets the document. Private method since this should be unmodifiable.
81
+ * @param DOMDocument $document The root document to be used.
82
+ * @return $this reference.
83
+ */
84
+ private function withDocument($document)
85
+ {
86
+ if (!isset($document) || $document === null) {
87
+ $document = new \DOMDocument();
88
+ }
89
+ Type::enforce($document, \DOMDocument::class);
90
+ $this->document = $document;
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Sets the css prefix. Private method since this should be unmodifiable.
96
+ * @param string $cssPrefix The css prefix to construct element classes.
97
+ * @return $this reference.
98
+ */
99
+ private function withCssPrefix($cssPrefix)
100
+ {
101
+ Type::enforce($cssPrefix, Type::STRING);
102
+ $this->cssPrefix = $cssPrefix;
103
+ return $this;
104
+ }
105
+
106
+ /**
107
+ * Sets the CSSBuilder.
108
+ * @param CSSBuilder $cssBuilder The css builder instance to be used.
109
+ * @return $this reference.
110
+ */
111
+ public function withCssBuilder($cssBuilder)
112
+ {
113
+ Type::enforce($cssBuilder, CSSBuilder::getClassName());
114
+ $this->cssBuilder = $cssBuilder;
115
+ return $this;
116
+ }
117
+
118
+ /**
119
+ * Gets the CssBuilder being used in this context.
120
+ * @return CSSBuilder being used in this context.
121
+ */
122
+ public function getCssBuilder()
123
+ {
124
+ return $this->cssBuilder;
125
+ }
126
+
127
+ /**
128
+ * Gets the root document being used in this context.
129
+ * @return DOMDocument $document The root document.
130
+ */
131
+ public function getDocument()
132
+ {
133
+ return $this->document;
134
+ }
135
+
136
+ /**
137
+ * Creates an element named by $tagName using the $document.
138
+ * @param string $tagName The tag name that will be used: <tagName>
139
+ * @param array(<string>=><string>) $attributes mapped array of attributes to be set to this Element being created.
140
+ * @param string $cssClass The element class for styling purposes.
141
+ * @param $DOMNode $container The container element where the new created element will be appended. Optional.
142
+ * @return DOMElement <$tagName> element using the DOMDocument $document from context.
143
+ */
144
+ public function createElement($tagName, $container = null, $cssClass = null, $attributes = null)
145
+ {
146
+ $element = $this->getDocument()->createElement($tagName);
147
+ if (!isset($attributes) || !$attributes) {
148
+ $attributes = array();
149
+ }
150
+ if (!Type::isTextEmpty($cssClass)) {
151
+ $attributes['class'] = $this->buildCssClass($cssClass);
152
+ }
153
+ foreach ($attributes as $name => $value) {
154
+ $element->setAttribute($name, $value);
155
+ }
156
+ $this->withPreviousElementIdentifier($cssClass);
157
+
158
+ if (isset($container) && $container) {
159
+ Type::enforce($container, get_class(new \DOMNode()));
160
+ $container->appendChild($element);
161
+ }
162
+
163
+ return $element;
164
+ }
165
+
166
+
167
+ public function buildCssClass($cssClassName)
168
+ {
169
+ return $this->cssPrefix.$cssClassName;
170
+ }
171
+
172
+ public function buildCssSelector($cssClassName)
173
+ {
174
+ return '.'.$this->buildCssClass($cssClassName);
175
+ }
176
+
177
+ public function withPreviousElementIdentifier($identifier)
178
+ {
179
+ $this->previousElementIdentifier = $identifier;
180
+ }
181
+
182
+ /**
183
+ * This will create a div with spacing, telling on class about the previous element.
184
+ * @param \DOMElement $container where this spacing will be appended to.
185
+ */
186
+ public function buildSpacingDiv($container)
187
+ {
188
+ if ($this->previousSpacing) {
189
+ if (!Type::isTextEmpty($this->previousElementIdentifier)) {
190
+ $class = $this->previousSpacing->getAttribute('class');
191
+ $class = $class.' before-'.$this->previousElementIdentifier;
192
+ $this->previousSpacing->setAttribute('class', $class);
193
+ }
194
+ }
195
+ $previousClass = Type::isTextEmpty($this->previousElementIdentifier) ? '' : ' after-'.$this->previousElementIdentifier;
196
+ $this->previousSpacing = $this->createElement('div', $container, 'spacing'.$previousClass);
197
+ }
198
+
199
+ /**
200
+ * Sets the InstantArticle reference. Private method since this should be unmodifiable.
201
+ * @param InstantArticle $instantArticle The element being used as conversion.
202
+ * @return $this reference.
203
+ */
204
+ private function withInstantArticle($instantArticle)
205
+ {
206
+ Type::enforce($instantArticle, InstantArticle::class);
207
+ $this->instantArticle = $instantArticle;
208
+ return $this;
209
+ }
210
+
211
+ /**
212
+ * Gets the InstantArticle being used in this context.
213
+ * @return InstantArticle $instantArticle conversion instance.
214
+ */
215
+ public function getInstantArticle()
216
+ {
217
+ return $this->instantArticle;
218
+ }
219
+
220
+ /**
221
+ * Sets the <html> full document.
222
+ * WARNING: by setting this, will overwrite the full document, be sure to
223
+ * have a valid AMP document while setting.
224
+ * @param DOMElement $html The html tag, should be a <html> tag.
225
+ * @throws InvalidArgumentException case not a DOMElement or not a <html> tag.
226
+ * @return $this instance.
227
+ */
228
+ public function withHtml($html)
229
+ {
230
+ Type::enforceElementTag($html, 'html');
231
+ $this->html = $html;
232
+ return $this;
233
+ }
234
+
235
+ /**
236
+ * Checks the existence of <html> tag.
237
+ * @return boolean true if <html> tag was set, false otherwise.
238
+ */
239
+ public function hasHtml()
240
+ {
241
+ return isset($this->html) && $this->html !== null;
242
+ }
243
+
244
+ /**
245
+ * Gets the <html> tag.
246
+ * @return DOMElement $html The <html> tag.
247
+ */
248
+ public function getHtml()
249
+ {
250
+ return $this->html;
251
+ }
252
+
253
+ /**
254
+ * Sets the <head> tag.
255
+ * WARNING: by setting this, will overwrite the head from document, be sure to
256
+ * have a valid AMP head while setting.
257
+ * @param DOMElement $head The head tag, should be a <head> tag.
258
+ * @throws InvalidArgumentException case not a DOMElement or not a <head> tag.
259
+ * @return $this instance.
260
+ */
261
+ public function withHead($head)
262
+ {
263
+ Type::enforceElementTag($head, 'head');
264
+ $this->head = $head;
265
+ return $this;
266
+ }
267
+
268
+ /**
269
+ * Checks the existence of <head> tag.
270
+ * @return boolean true if <head> tag was set, false otherwise.
271
+ */
272
+ public function hasHead()
273
+ {
274
+ return isset($this->head) && $this->head !== null;
275
+ }
276
+
277
+ /**
278
+ * Gets the <head> tag.
279
+ * @return DOMElement $head The <head> tag.
280
+ */
281
+ public function getHead()
282
+ {
283
+ return $this->head;
284
+ }
285
+
286
+ /**
287
+ * Sets the <body> tag.
288
+ * WARNING: by setting this, will overwrite the body from document, be sure to
289
+ * have a valid AMP body while setting.
290
+ * @param DOMElement $body The body tag, should be a <body> tag.
291
+ * @throws InvalidArgumentException case not a DOMElement or not a <body> tag.
292
+ * @return $this instance.
293
+ */
294
+ public function withBody($body)
295
+ {
296
+ Type::enforceElementTag($body, 'body');
297
+ $this->body = $body;
298
+ return $this;
299
+ }
300
+
301
+ /**
302
+ * Checks the existence of <body> tag.
303
+ * @return boolean true if <body> tag was set, false otherwise.
304
+ */
305
+ public function hasBody()
306
+ {
307
+ return isset($this->body) && $this->body !== null;
308
+ }
309
+
310
+ /**
311
+ * Gets the <body> tag.
312
+ * @return DOMElement $body The <body> tag.
313
+ */
314
+ public function getBody()
315
+ {
316
+ return $this->body;
317
+ }
318
+
319
+ /**
320
+ * Sets the <article> tag.
321
+ * WARNING: by setting this, will overwrite the article from document, be sure to
322
+ * have a valid AMP article while setting.
323
+ * @param DOMElement $article The article tag, should be a <article> tag.
324
+ * @throws InvalidArgumentException case not a DOMElement or not a <article> tag.
325
+ * @return $this instance.
326
+ */
327
+ public function withArticle($article)
328
+ {
329
+ Type::enforceElementTag($article, 'article');
330
+ $this->article = $article;
331
+ return $this;
332
+ }
333
+
334
+ /**
335
+ * Checks the existence of <article> tag.
336
+ * @return boolean true if <article> tag was set, false otherwise.
337
+ */
338
+ public function hasArticle()
339
+ {
340
+ return isset($this->article) && $this->article !== null;
341
+ }
342
+
343
+ /**
344
+ * Gets the <article> tag.
345
+ * @return DOMElement $article The <article> tag.
346
+ */
347
+ public function getArticle()
348
+ {
349
+ return $this->article;
350
+ }
351
+
352
+ /**
353
+ * Sets the <header> tag.
354
+ * WARNING: by setting this, will overwrite the header from document, be sure to
355
+ * have a valid AMP header while setting.
356
+ * @param DOMElement $header The header tag, should be a <header> tag.
357
+ * @throws InvalidArgumentException case not a DOMElement or not a <header> tag.
358
+ * @return $this instance.
359
+ */
360
+ public function withHeader($header)
361
+ {
362
+ Type::enforceElementTag($header, 'header');
363
+ $this->header = $header;
364
+ return $this;
365
+ }
366
+
367
+ /**
368
+ * Checks the existence of <header> tag.
369
+ * @return boolean true if <header> tag was set, false otherwise.
370
+ */
371
+ public function hasHeader()
372
+ {
373
+ return isset($this->header) && $this->header !== null;
374
+ }
375
+
376
+ /**
377
+ * Gets the <header> tag.
378
+ * @return DOMElement $header The <header> tag.
379
+ */
380
+ public function getHeader()
381
+ {
382
+ return $this->header;
383
+ }
384
+
385
+ /**
386
+ * Sets the headerBar <div> tag.
387
+ * WARNING: by setting this, will overwrite the headerBar from document, be sure to
388
+ * have a valid AMP headerBar while setting.
389
+ * @param DOMElement $headerBar The headerBar tag, should be a <div> tag.
390
+ * @throws InvalidArgumentException case not a DOMElement or not a <div> tag.
391
+ * @return $this instance.
392
+ */
393
+ public function withHeaderBar($headerBar)
394
+ {
395
+ Type::enforceElementTag($headerBar, 'div');
396
+ $this->headerBar = $headerBar;
397
+ return $this;
398
+ }
399
+
400
+ /**
401
+ * Checks the existence of headerBar <div> tag.
402
+ * @return boolean true if headerBar <div> tag was set, false otherwise.
403
+ */
404
+ public function hasHeaderBar()
405
+ {
406
+ return isset($this->headerBar) && $this->headerBar !== null;
407
+ }
408
+
409
+ /**
410
+ * Gets the <headerBar> tag.
411
+ * @return DOMElement $headerBar The <headerBar> tag.
412
+ */
413
+ public function getHeaderBar()
414
+ {
415
+ return $this->headerBar;
416
+ }
417
+
418
+ /**
419
+ * Sets the headerBarLogo <div> tag.
420
+ * WARNING: by setting this, will overwrite the headerBarLogo from document, be sure to
421
+ * have a valid AMP headerBarLogo while setting.
422
+ * @param DOMElement $headerBarLogo The headerBarLogo tag, should be a <div> tag.
423
+ * @throws InvalidArgumentException case not a DOMElement or not a <div> tag.
424
+ * @return $this instance.
425
+ */
426
+ public function withHeaderBarLogo($headerBarLogo)
427
+ {
428
+ Type::enforceElementTag($headerBarLogo, 'div');
429
+ $this->headerBarLogo = $headerBarLogo;
430
+ return $this;
431
+ }
432
+
433
+ /**
434
+ * Checks the existence of headerBarLogo <div> tag.
435
+ * @return boolean true if headerBarLogo <div> tag was set, false otherwise.
436
+ */
437
+ public function hasHeaderBarLogo()
438
+ {
439
+ return isset($this->headerBarLogo) && $this->headerBarLogo !== null;
440
+ }
441
+
442
+ /**
443
+ * Gets the <headerBarLogo> tag.
444
+ * @return DOMElement $headerBarLogo The <headerBarLogo> tag.
445
+ */
446
+ public function getHeaderBarLogo()
447
+ {
448
+ return $this->headerBarLogo;
449
+ }
450
+
451
+ /**
452
+ * Sets the <h1> title tag.
453
+ * WARNING: by setting this, will overwrite the title from document, be sure to
454
+ * have a valid AMP title while setting.
455
+ * @param DOMElement $h1 The title tag, should be a <h1> tag.
456
+ * @throws InvalidArgumentException case not a DOMElement or not a <h1> tag.
457
+ * @return $this instance.
458
+ */
459
+ public function withHeaderTitle($h1)
460
+ {
461
+ Type::enforceElementTag($h1, 'h1');
462
+ $this->headerTitle = $h1;
463
+ return $this;
464
+ }
465
+
466
+ /**
467
+ * Checks the existence of <h1> title tag.
468
+ * @return boolean true if <h1> title tag was set, false otherwise.
469
+ */
470
+ public function hasHeaderTitle()
471
+ {
472
+ return isset($this->headerTitle) && $this->headerTitle !== null;
473
+ }
474
+
475
+ /**
476
+ * Gets the <h1> title tag.
477
+ * @return DOMElement $headerTitle The <h1> title tag.
478
+ */
479
+ public function getHeaderTitle()
480
+ {
481
+ return $this->headerTitle;
482
+ }
483
+
484
+ /**
485
+ * Sets the <h3> author tag.
486
+ * WARNING: by setting this, will overwrite the author from document, be sure to
487
+ * have a valid AMP author while setting.
488
+ * @param DOMElement $h3 The author tag, should be a <h3> tag.
489
+ * @throws InvalidArgumentException case not a DOMElement or not a <h3> tag.
490
+ * @return $this instance.
491
+ */
492
+ public function withHeaderAuthor($h3)
493
+ {
494
+ Type::enforceElementTag($h3, 'h3');
495
+ $this->headerAuthor = $h3;
496
+ return $this;
497
+ }
498
+
499
+ /**
500
+ * Checks the existence of <h3> author tag.
501
+ * @return boolean true if <h3> author tag was set, false otherwise.
502
+ */
503
+ public function hasHeaderAuthor()
504
+ {
505
+ return isset($this->headerAuthor) && $this->headerAuthor !== null;
506
+ }
507
+
508
+ /**
509
+ * Gets the <h3> author tag.
510
+ * @return DOMElement $headerAuthor The <h3> tag.
511
+ */
512
+ public function getHeaderAuthor()
513
+ {
514
+ return $this->headerAuthor;
515
+ }
516
+
517
+ /**
518
+ * Sets the <h2> kicker tag.
519
+ * WARNING: by setting this, will overwrite the kicker from document, be sure to
520
+ * have a valid AMP kicker while setting.
521
+ * @param DOMElement $h2 The kicker tag, should be a <h2> tag.
522
+ * @throws InvalidArgumentException case not a DOMElement or not a <h2> tag.
523
+ * @return $this instance.
524
+ */
525
+ public function withHeaderKicker($h2)
526
+ {
527
+ Type::enforceElementTag($h2, 'h2');
528
+ $this->headerKicker = $h2;
529
+ return $this;
530
+ }
531
+
532
+ /**
533
+ * Checks the existence of <h2> kicker tag.
534
+ * @return boolean true if <h2> kicker tag was set, false otherwise.
535
+ */
536
+ public function hasHeaderKicker()
537
+ {
538
+ return isset($this->headerKicker) && $this->headerKicker !== null;
539
+ }
540
+
541
+ /**
542
+ * Gets the <h2> kicker tag.
543
+ * @return DOMElement $headerKicker The <h2> kicker tag.
544
+ */
545
+ public function getHeaderKicker()
546
+ {
547
+ return $this->headerKicker;
548
+ }
549
+
550
+ /**
551
+ * Sets the <h3> date tag.
552
+ * WARNING: by setting this, will overwrite the date from document, be sure to
553
+ * have a valid AMP date while setting.
554
+ * @param DOMElement $h3 The date tag, should be a <h3> tag.
555
+ * @throws InvalidArgumentException case not a DOMElement or not a <h3> tag.
556
+ * @return $this instance.
557
+ */
558
+ public function withHeaderDate($h3)
559
+ {
560
+ Type::enforceElementTag($h3, 'h3');
561
+ $this->headerDate = $h3;
562
+ return $this;
563
+ }
564
+
565
+ /**
566
+ * Checks the existence of <h3> date tag.
567
+ * @return boolean true if <h3> date tag was set, false otherwise.
568
+ */
569
+ public function hasHeaderDate()
570
+ {
571
+ return isset($this->headerDate) && $this->headerDate !== null;
572
+ }
573
+
574
+ /**
575
+ * Gets the <h3> date tag.
576
+ * @return DOMElement $headerDate The <h3> tag.
577
+ */
578
+ public function getHeaderDate()
579
+ {
580
+ return $this->headerDate;
581
+ }
582
+
583
+ /**
584
+ * Add new items to the document
585
+ */
586
+ public function addItem($item)
587
+ {
588
+ $element = new \DOMElement('dummy');
589
+ Type::enforce($item, get_class($element));
590
+ $this->articleItems[] = $item;
591
+ }
592
+
593
+ /**
594
+ * Sets the <footer> tag.
595
+ * WARNING: by setting this, will overwrite the footer from document, be sure to
596
+ * have a valid AMP footer while setting.
597
+ * @param DOMElement $footer The footer tag, should be a <footer> tag.
598
+ * @throws InvalidArgumentException case not a DOMElement or not a <footer> tag.
599
+ * @return $this instance.
600
+ */
601
+ public function withFooter($footer)
602
+ {
603
+ Type::enforceElementTag($footer, 'footer');
604
+ $this->footer = $footer;
605
+ return $this;
606
+ }
607
+
608
+ /**
609
+ * Checks the existence of <footer> tag.
610
+ * @return boolean true if <footer> tag was set, false otherwise.
611
+ */
612
+ public function hasFooter()
613
+ {
614
+ return isset($this->footer) && $this->footer !== null;
615
+ }
616
+
617
+ /**
618
+ * Gets the <footer> tag.
619
+ * @return DOMElement $footer The <footer> tag.
620
+ */
621
+ public function getFooter()
622
+ {
623
+ return $this->footer;
624
+ }
625
+
626
+ /**
627
+ * Use this method to add a new warning message to the context when something unexpected happened.
628
+ * @param string $message The message warning.
629
+ * @param mixed $contextObj an object to be stringified to better understand the context where this warning was generated.
630
+ * @param Exception $exception **optional** The exception that generated this warning.
631
+ */
632
+ public function addWarning($message, $contextObj, $exception = null)
633
+ {
634
+ $this->warnings[] = new Warning($message, $contextObj, $exception);
635
+ return $this;
636
+ }
637
+
638
+ /**
639
+ * @return The warnings from the context.
640
+ */
641
+ public function getWarnings()
642
+ {
643
+ return $this->warnings;
644
+ }
645
+
646
+ /**
647
+ * @param array $mediaSizes The map of URLs and sizes already defined.
648
+ * @param string|file $mediaCacheFolder Where the cache is stored.
649
+ * @param boolean $enableDownloadForMediaSizing Indicates wheather the images will be downloaded or not to check sizes.
650
+ * @param int $defaultWidth The default width that will be used to image in case no dimensions is found for this image.
651
+ * @param int $defaultHeight The default height that will be used to image in case no dimensions is found for this image.
652
+ * @return $this instance.
653
+ */
654
+ public function withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight)
655
+ {
656
+ $this->mediaSizes = $mediaSizes;
657
+ $this->mediaCacheFolder = $mediaCacheFolder;
658
+ $this->enableDownloadForMediaSizing = $enableDownloadForMediaSizing;
659
+ $this->defaultWidth = $defaultWidth;
660
+ $this->defaultHeight = $defaultHeight;
661
+ return $this;
662
+ }
663
+
664
+ /**
665
+ * Returns an array(width, height) based on that image URL.
666
+ * @param string $mediaURL
667
+ * @param string $mediaType: Possible values: AMPContext::MEDIA_TYPE_IMAGE and AMPContext::MEDIA_TYPE_VIDEO.
668
+ * @return array with 2 possitions, first being width, second being the height.
669
+ */
670
+ public function getMediaDimensions($mediaURL, $mediaType = null)
671
+ {
672
+ if ($this->mediaSizes && array_key_exists($mediaURL, $this->mediaSizes)) {
673
+ return $this->mediaSizes[$mediaURL];
674
+ }
675
+
676
+ $mediaDimensions = $this->getMediaDimensionsFromCache($mediaURL);
677
+ if ($mediaDimensions) {
678
+ return $mediaDimensions;
679
+ }
680
+
681
+ if ($mediaType === AMPContext::MEDIA_TYPE_IMAGE && $this->enableDownloadForMediaSizing) {
682
+ $retrievedSizes = getimagesize($mediaURL);
683
+ if ($retrievedSizes && !empty($retrievedSizes) && $retrievedSizes[0] !== 0) {
684
+ return $retrievedSizes;
685
+ }
686
+ }
687
+
688
+ return array($this->defaultWidth, $this->defaultHeight);
689
+ }
690
+
691
+ private function getMediaDimensionsFromCache($mediaURL)
692
+ {
693
+ if (!$this->mediaCacheFolder || !file_exists($this->mediaCacheFolder)) {
694
+ return null;
695
+ }
696
+
697
+ $fileName = basename($mediaURL);
698
+ if (!$fileName) {
699
+ return null;
700
+ }
701
+
702
+ $cachedFile = $this->mediaCacheFolder . DIRECTORY_SEPARATOR . $fileName;
703
+ if (!file_exists($cachedFile)) {
704
+ return null;
705
+ }
706
+
707
+ return getimagesize($cachedFile);
708
+ }
709
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCover.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Validators\Type;
12
+ use Facebook\InstantArticles\Elements\Image;
13
+ use Facebook\InstantArticles\Elements\Slideshow;
14
+ use Facebook\InstantArticles\Elements\Video;
15
+
16
+ class AMPCover
17
+ {
18
+ /**
19
+ * @var Context the conversion context holder
20
+ */
21
+ private $context;
22
+
23
+ /**
24
+ * @var Image|Video|Slideshow The element cover
25
+ */
26
+ private $coverElement;
27
+
28
+ /**
29
+ * @var DOMNode The html tag holding the final element;
30
+ */
31
+ private $coverTag;
32
+
33
+ /**
34
+ * @param Context $context Conversion context var.
35
+ * @param Image|Video|Slideshow $coverElement The element from SDK that will generate the cover.
36
+ */
37
+ public function __construct($context, $coverElement)
38
+ {
39
+ $this->context = $context;
40
+ $this->coverElement = $coverElement;
41
+ }
42
+
43
+ private function genContainer()
44
+ {
45
+ if (Type::is($this->coverElement, Image::getClassName())) {
46
+ $this->coverTag = AMPCoverImage::create($this->coverElement, $this->context, 'cover-image')->build();
47
+ } else if (Type::is($this->coverElement, Slideshow::getClassName())) {
48
+ //return $this->buildSlideshow($this->coverElement, $context, 'cover-slideshow');
49
+ } else if (Type::is($this->coverElement, Video::getClassName())) {
50
+ //return $this->buildVideo($this->coverElement, $context, 'cover-video');
51
+ }
52
+ }
53
+
54
+ public function build()
55
+ {
56
+ $this->genContainer();
57
+ return $this->coverTag;
58
+ }
59
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPCoverImage.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ class AMPCoverImage
12
+ {
13
+ // Constructor setup
14
+ private $image;
15
+ private $context;
16
+ private $cssClass;
17
+
18
+ // Generator fill in
19
+ private $containerTag;
20
+ private $ampImgTag;
21
+
22
+ private function __construct($image, $context, $cssClass)
23
+ {
24
+ $this->image = $image;
25
+ $this->context = $context;
26
+ $this->cssClass = $cssClass;
27
+ }
28
+
29
+ public static function create($image, $context, $cssClass)
30
+ {
31
+ return new self($image, $context, $cssClass);
32
+ }
33
+
34
+ private function genContainer()
35
+ {
36
+ $this->containerTag = $this->context->createElement('div', null, $this->cssClass);
37
+ }
38
+
39
+ private function genCaptionContainer()
40
+ {
41
+ $caption = $this->image->getCaption();
42
+ if ($caption) {
43
+ $this->ampImgTag =
44
+ AMPCaption::create($caption, $this->context, $this->ampImgTag)->build();
45
+ }
46
+ }
47
+
48
+ private function genAmpImage()
49
+ {
50
+ $this->ampImgTag = $this->context->createElement('amp-img', null, 'header-cover-img');
51
+ $imageURL = $this->image->getUrl();
52
+
53
+ $imageDimensions = $this->context->getMediaDimensions($imageURL, AMPContext::MEDIA_TYPE_IMAGE);
54
+ $imageWidth = $imageDimensions[0];
55
+ $imageHeight = $imageDimensions[1];
56
+
57
+ $horizontalScale = AMPContext::DEFAULT_WIDTH / $imageWidth;
58
+ $verticalScale = AMPContext::DEFAULT_HEIGHT / $imageHeight;
59
+ $maxScale = max($horizontalScale, $verticalScale);
60
+
61
+ $translateX = (int) (-($imageWidth * $maxScale - AMPContext::DEFAULT_WIDTH) / 2);
62
+ $translateY = (int) (-($imageHeight * $maxScale - AMPContext::DEFAULT_HEIGHT) / 2);
63
+
64
+ $imageWidth = (int) ($imageWidth * $maxScale);
65
+ $imageHeight = (int) ($imageHeight * $maxScale);
66
+
67
+ $this->ampImgTag->setAttribute('src', $imageURL);
68
+ $this->ampImgTag->setAttribute('width', (string) $imageWidth);
69
+ $this->ampImgTag->setAttribute('height', (string) $imageHeight);
70
+
71
+ $imageCSSClass = $this->ampImgTag->getAttribute('class');
72
+ $containerCSSClass = $this->containerTag->getAttribute('class');
73
+ $this->context->getCssBuilder()
74
+ ->addProperty("amp-img.$imageCSSClass", 'transform', "translate({$translateX}px, {$translateY}px)")
75
+ ->addProperty("div.$containerCSSClass", 'width', AMPContext::DEFAULT_WIDTH.'px')
76
+ ->addProperty("div.$containerCSSClass", 'height', AMPContext::DEFAULT_HEIGHT.'px')
77
+ ->addProperty("div.$containerCSSClass", 'overflow', 'hidden');
78
+
79
+ }
80
+
81
+ public function build()
82
+ {
83
+ $this->genContainer();
84
+ $this->genAmpImage();
85
+ $this->genCaptionContainer();
86
+
87
+ $this->containerTag->appendChild($this->ampImgTag);
88
+ return $this->containerTag;
89
+ }
90
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPHeader.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ class AMPHeader
12
+ {
13
+ private $header;
14
+ private $context;
15
+ private $publishDateElement;
16
+
17
+ public function __construct($context)
18
+ {
19
+ $this->context = $context;
20
+ }
21
+
22
+ private function iaHeader()
23
+ {
24
+ return $this->context->getInstantArticle()->getHeader();
25
+ }
26
+
27
+ private function genKicker()
28
+ {
29
+ if ($this->iaHeader()->getKicker()) {
30
+ $kicker = $this->context->createElement('h2', $this->header, 'header-category');
31
+ $kicker->appendChild($this->context->getInstantArticle()
32
+ ->getHeader()
33
+ ->getKicker()
34
+ ->textToDOMDocumentFragment($this->context->getDocument()));
35
+ $this->context->buildSpacingDiv($this->header);
36
+ }
37
+ }
38
+
39
+ private function genTitle()
40
+ {
41
+ $iaTitle = $this->iaHeader()
42
+ ->getTitle()
43
+ ->textToDOMDocumentFragment($this->context->getDocument());
44
+
45
+ $h1 = $this->context->createElement('h1', $this->header, 'header-h1');
46
+ $h1->appendChild($iaTitle);
47
+ $this->context->buildSpacingDiv($this->header);
48
+ }
49
+
50
+ private function genHeaderBar()
51
+ {
52
+ $this->headerBar = $this->context->createElement('div', $this->header, 'header-bar');
53
+ $this->context->buildSpacingDiv($this->header);
54
+ // Note: The logo will be added after the whole article is processed
55
+ }
56
+
57
+ private function genSubtitle()
58
+ {
59
+ if ($this->iaHeader()->getSubtitle()) {
60
+ $iaHeaderSubtitle = $this->iaHeader()->getSubtitle()->textToDOMDocumentFragment($this->context->getDocument());
61
+ $subtitle = $this->context->createElement('h2', $this->header, 'header-h2');
62
+ $subtitle->appendChild($iaHeaderSubtitle);
63
+
64
+ $this->context->buildSpacingDiv($this->header);
65
+ }
66
+ }
67
+
68
+ private function genArticlePublishDateElement()
69
+ {
70
+ $this->publishDateElement = $this->context->createElement('h3', $this->header, 'header-date');
71
+ // Note: The published date will be added after the whole article is processed
72
+ $this->context->buildSpacingDiv($this->header);
73
+ }
74
+
75
+ private function genAuthors()
76
+ {
77
+ $authors = $this->context->createElement('h3', $this->header, 'header-author');
78
+ $authorsElement = $this->iaHeader()->getAuthors();
79
+ $authorsString = [];
80
+ foreach ($authorsElement as $author) {
81
+ $authorsString[] = $author->getName();
82
+ }
83
+ $authors->appendChild($this->context->getDocument()->createTextNode('By '.implode($authorsString, ', ')));
84
+ $this->context->buildSpacingDiv($this->header);
85
+ }
86
+
87
+ private function genContainer()
88
+ {
89
+ // Builds the content Header, with proper colors and image, adding to body
90
+ $this->header = $this->context->createElement('header', $this->context->getBody(), 'header');
91
+ // Creates the cover content for the cover and appends to the header
92
+ if ($this->context->getInstantArticle()->getHeader()->getCover()) {
93
+ $ampCover = new AMPCover($this->context, $this->context->getInstantArticle()->getHeader()->getCover());
94
+ $this->header->appendChild($ampCover->build());
95
+ }
96
+ }
97
+
98
+ public function genHeaderLogo($logo)
99
+ {
100
+ if (!isset($logo->url)) {
101
+ return;
102
+ }
103
+
104
+ $ampImageContainer = $this->context->createElement(
105
+ 'div',
106
+ $this->headerBar,
107
+ 'header-bar-img-container'
108
+ );
109
+ $ampImage = $this->context->createElement(
110
+ 'amp-img',
111
+ $ampImageContainer,
112
+ null,
113
+ array(
114
+ 'src' => $logo->url,
115
+ 'width' => $logo->width,
116
+ 'height' => $logo->height
117
+ )
118
+ );
119
+ }
120
+
121
+ public function genArticlePublishDate($dateFormat)
122
+ {
123
+ $datetime = $this->iaHeader()->getPublished()->getDatetime();
124
+ $this->publishDateElement->appendChild(
125
+ $this->context->getDocument()->createTextNode(date_format($datetime, $dateFormat))
126
+ );
127
+ }
128
+
129
+ public function build()
130
+ {
131
+ $this->genContainer();
132
+ $this->genHeaderBar();
133
+ $this->genKicker();
134
+ $this->genTitle();
135
+ $this->genSubtitle();
136
+ $this->genAuthors();
137
+ $this->genArticlePublishDateElement();
138
+
139
+ return $this->header;
140
+ }
141
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/AMPImage.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ class AMPImage
12
+ {
13
+ public $url;
14
+ public $width;
15
+ public $height;
16
+
17
+ public function __construct($url, $width, $height)
18
+ {
19
+ $this->url = $url;
20
+ $this->width = $width;
21
+ $this->height = $height;
22
+ }
23
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/configuration/default-amp.style.json ADDED
@@ -0,0 +1,1133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#FFFFFF",
3
+ "title": {
4
+ "background_color": "#FFFFFF",
5
+ "border": {
6
+ "bottom": {
7
+ "width": 0
8
+ },
9
+ "left": {
10
+ "width": 0
11
+ },
12
+ "right": {
13
+ "width": 0
14
+ },
15
+ "top": {
16
+ "width": 0
17
+ }
18
+ },
19
+ "capitalization": "NONE",
20
+ "color": "#000000",
21
+ "display": "INLINE",
22
+ "font": "Georgia",
23
+ "line_height_scale": 1,
24
+ "margin": {
25
+ "left": {
26
+ "scaling_factor": 1,
27
+ "size": "DOCUMENT_MARGIN"
28
+ },
29
+ "right": {
30
+ "scaling_factor": 1,
31
+ "size": "DOCUMENT_MARGIN"
32
+ }
33
+ },
34
+ "padding": {
35
+ "bottom": {
36
+ "scaling_factor": 1,
37
+ "size": "NONE"
38
+ },
39
+ "left": {
40
+ "scaling_factor": 1,
41
+ "size": "NONE"
42
+ },
43
+ "right": {
44
+ "scaling_factor": 1,
45
+ "size": "NONE"
46
+ },
47
+ "top": {
48
+ "scaling_factor": 1,
49
+ "size": "NONE"
50
+ }
51
+ },
52
+ "text_alignment": "LEFT",
53
+ "text_size_scale": 1,
54
+ "underline": "NONE"
55
+ },
56
+ "subtitle": {
57
+ "background_color": "#FFFFFF",
58
+ "border": {
59
+ "bottom": {
60
+ "width": 0
61
+ },
62
+ "left": {
63
+ "width": 0
64
+ },
65
+ "right": {
66
+ "width": 0
67
+ },
68
+ "top": {
69
+ "width": 0
70
+ }
71
+ },
72
+ "capitalization": "NONE",
73
+ "color": "#000000",
74
+ "display": "INLINE",
75
+ "font": "Georgia",
76
+ "line_height_scale": 1,
77
+ "margin": {
78
+ "left": {
79
+ "scaling_factor": 1,
80
+ "size": "DOCUMENT_MARGIN"
81
+ },
82
+ "right": {
83
+ "scaling_factor": 1,
84
+ "size": "DOCUMENT_MARGIN"
85
+ }
86
+ },
87
+ "padding": {
88
+ "bottom": {
89
+ "scaling_factor": 1,
90
+ "size": "NONE"
91
+ },
92
+ "left": {
93
+ "scaling_factor": 1,
94
+ "size": "NONE"
95
+ },
96
+ "right": {
97
+ "scaling_factor": 1,
98
+ "size": "NONE"
99
+ },
100
+ "top": {
101
+ "scaling_factor": 1,
102
+ "size": "NONE"
103
+ }
104
+ },
105
+ "text_alignment": "LEFT",
106
+ "text_size_scale": 1,
107
+ "underline": "NONE"
108
+ },
109
+ "kicker": {
110
+ "background_color": "#FFFFFF",
111
+ "border": {
112
+ "bottom": {
113
+ "width": 0
114
+ },
115
+ "left": {
116
+ "width": 0
117
+ },
118
+ "right": {
119
+ "width": 0
120
+ },
121
+ "top": {
122
+ "width": 0
123
+ }
124
+ },
125
+ "capitalization": "ALL_CAPS",
126
+ "color": "#000000",
127
+ "display": "INLINE",
128
+ "font": "Helvetica Neue",
129
+ "line_height_scale": 1,
130
+ "margin": {
131
+ "left": {
132
+ "scaling_factor": 1,
133
+ "size": "DOCUMENT_MARGIN"
134
+ },
135
+ "right": {
136
+ "scaling_factor": 1,
137
+ "size": "DOCUMENT_MARGIN"
138
+ }
139
+ },
140
+ "padding": {
141
+ "bottom": {
142
+ "scaling_factor": 1,
143
+ "size": "NONE"
144
+ },
145
+ "left": {
146
+ "scaling_factor": 1,
147
+ "size": "NONE"
148
+ },
149
+ "right": {
150
+ "scaling_factor": 1,
151
+ "size": "NONE"
152
+ },
153
+ "top": {
154
+ "scaling_factor": 1,
155
+ "size": "NONE"
156
+ }
157
+ },
158
+ "text_alignment": "LEFT",
159
+ "text_size_scale": 1,
160
+ "underline": "NONE"
161
+ },
162
+ "byline": {
163
+ "border": {
164
+ "bottom": {
165
+ "width": 0
166
+ },
167
+ "left": {
168
+ "width": 0
169
+ },
170
+ "right": {
171
+ "width": 0
172
+ },
173
+ "top": {
174
+ "width": 0
175
+ }
176
+ },
177
+ "capitalization": "ALL_CAPS",
178
+ "color": "#000000",
179
+ "display": "INLINE",
180
+ "font": "Helvetica Neue",
181
+ "line_height_scale": 1,
182
+ "margin": {
183
+ "left": {
184
+ "scaling_factor": 1,
185
+ "size": "DOCUMENT_MARGIN"
186
+ },
187
+ "right": {
188
+ "scaling_factor": 1,
189
+ "size": "DOCUMENT_MARGIN"
190
+ }
191
+ },
192
+ "padding": {
193
+ "bottom": {
194
+ "scaling_factor": 1,
195
+ "size": "NONE"
196
+ },
197
+ "left": {
198
+ "scaling_factor": 1,
199
+ "size": "NONE"
200
+ },
201
+ "right": {
202
+ "scaling_factor": 1,
203
+ "size": "NONE"
204
+ },
205
+ "top": {
206
+ "scaling_factor": 1,
207
+ "size": "NONE"
208
+ }
209
+ },
210
+ "text_alignment": "LEFT",
211
+ "text_size_scale": 1,
212
+ "underline": "NONE"
213
+ },
214
+ "date_style": "MONTH_DAY_YEAR",
215
+ "primary_heading": {
216
+ "background_color": "#FFFFFF",
217
+ "border": {
218
+ "bottom": {
219
+ "width": 0
220
+ },
221
+ "left": {
222
+ "width": 0
223
+ },
224
+ "right": {
225
+ "width": 0
226
+ },
227
+ "top": {
228
+ "width": 0
229
+ }
230
+ },
231
+ "capitalization": "NONE",
232
+ "color": "#000000",
233
+ "display": "INLINE",
234
+ "font": "Georgia",
235
+ "line_height_scale": 1,
236
+ "margin": {
237
+ "left": {
238
+ "scaling_factor": 1,
239
+ "size": "DOCUMENT_MARGIN"
240
+ },
241
+ "right": {
242
+ "scaling_factor": 1,
243
+ "size": "DOCUMENT_MARGIN"
244
+ }
245
+ },
246
+ "padding": {
247
+ "bottom": {
248
+ "scaling_factor": 1,
249
+ "size": "NONE"
250
+ },
251
+ "left": {
252
+ "scaling_factor": 1,
253
+ "size": "NONE"
254
+ },
255
+ "right": {
256
+ "scaling_factor": 1,
257
+ "size": "NONE"
258
+ },
259
+ "top": {
260
+ "scaling_factor": 1,
261
+ "size": "NONE"
262
+ }
263
+ },
264
+ "text_alignment": "LEFT",
265
+ "text_size_scale": 1,
266
+ "underline": "NONE"
267
+ },
268
+ "secondary_heading": {
269
+ "background_color": "#FFFFFF",
270
+ "border": {
271
+ "bottom": {
272
+ "width": 0
273
+ },
274
+ "left": {
275
+ "width": 0
276
+ },
277
+ "right": {
278
+ "width": 0
279
+ },
280
+ "top": {
281
+ "width": 0
282
+ }
283
+ },
284
+ "capitalization": "NONE",
285
+ "color": "#000000",
286
+ "display": "INLINE",
287
+ "font": "Georgia",
288
+ "line_height_scale": 1,
289
+ "margin": {
290
+ "left": {
291
+ "scaling_factor": 1,
292
+ "size": "DOCUMENT_MARGIN"
293
+ },
294
+ "right": {
295
+ "scaling_factor": 1,
296
+ "size": "DOCUMENT_MARGIN"
297
+ }
298
+ },
299
+ "padding": {
300
+ "bottom": {
301
+ "scaling_factor": 1,
302
+ "size": "NONE"
303
+ },
304
+ "left": {
305
+ "scaling_factor": 1,
306
+ "size": "NONE"
307
+ },
308
+ "right": {
309
+ "scaling_factor": 1,
310
+ "size": "NONE"
311
+ },
312
+ "top": {
313
+ "scaling_factor": 1,
314
+ "size": "NONE"
315
+ }
316
+ },
317
+ "text_alignment": "LEFT",
318
+ "text_size_scale": 1,
319
+ "underline": "NONE"
320
+ },
321
+ "body_text": {
322
+ "border": {
323
+ "bottom": {
324
+ "width": 0
325
+ },
326
+ "left": {
327
+ "width": 0
328
+ },
329
+ "right": {
330
+ "width": 0
331
+ },
332
+ "top": {
333
+ "width": 0
334
+ }
335
+ },
336
+ "capitalization": "NONE",
337
+ "color": "#000000",
338
+ "display": "INLINE",
339
+ "font": "Georgia",
340
+ "line_height_scale": 1,
341
+ "margin": {
342
+ "left": {
343
+ "scaling_factor": 1,
344
+ "size": "DOCUMENT_MARGIN"
345
+ },
346
+ "right": {
347
+ "scaling_factor": 1,
348
+ "size": "DOCUMENT_MARGIN"
349
+ }
350
+ },
351
+ "padding": {
352
+ "bottom": {
353
+ "scaling_factor": 1,
354
+ "size": "NONE"
355
+ },
356
+ "left": {
357
+ "scaling_factor": 1,
358
+ "size": "NONE"
359
+ },
360
+ "right": {
361
+ "scaling_factor": 1,
362
+ "size": "NONE"
363
+ },
364
+ "top": {
365
+ "scaling_factor": 1,
366
+ "size": "NONE"
367
+ }
368
+ },
369
+ "text_alignment": "LEFT",
370
+ "text_size_scale": 1,
371
+ "underline": "NONE"
372
+ },
373
+ "inline_link": {
374
+ "border": {
375
+ "bottom": {
376
+ "width": 0
377
+ },
378
+ "left": {
379
+ "width": 0
380
+ },
381
+ "right": {
382
+ "width": 0
383
+ },
384
+ "top": {
385
+ "width": 0
386
+ }
387
+ },
388
+ "capitalization": "NONE",
389
+ "color": "#000000",
390
+ "display": "INLINE",
391
+ "font": "Georgia",
392
+ "line_height_scale": 1,
393
+ "margin": {
394
+ "left": {
395
+ "scaling_factor": 1,
396
+ "size": "DOCUMENT_MARGIN"
397
+ },
398
+ "right": {
399
+ "scaling_factor": 1,
400
+ "size": "DOCUMENT_MARGIN"
401
+ }
402
+ },
403
+ "padding": {
404
+ "bottom": {
405
+ "scaling_factor": 1,
406
+ "size": "NONE"
407
+ },
408
+ "left": {
409
+ "scaling_factor": 1,
410
+ "size": "NONE"
411
+ },
412
+ "right": {
413
+ "scaling_factor": 1,
414
+ "size": "NONE"
415
+ },
416
+ "top": {
417
+ "scaling_factor": 1,
418
+ "size": "NONE"
419
+ }
420
+ },
421
+ "text_alignment": "LEFT",
422
+ "text_size_scale": 1,
423
+ "underline": "SIMPLE_UNDERLINE"
424
+ },
425
+ "block_quote": {
426
+ "background_color": "#FFFFFF",
427
+ "border": {
428
+ "bottom": {
429
+ "color": "#000000",
430
+ "width": 0
431
+ },
432
+ "left": {
433
+ "color": "#000000",
434
+ "width": 2
435
+ },
436
+ "right": {
437
+ "color": "#000000",
438
+ "width": 0
439
+ },
440
+ "top": {
441
+ "color": "#000000",
442
+ "width": 0
443
+ }
444
+ },
445
+ "capitalization": "NONE",
446
+ "color": "#000000",
447
+ "display": "INLINE",
448
+ "font": "Georgia",
449
+ "line_height_scale": 1,
450
+ "margin": {
451
+ "left": {
452
+ "scaling_factor": 1,
453
+ "size": "DOCUMENT_MARGIN"
454
+ },
455
+ "right": {
456
+ "scaling_factor": 1,
457
+ "size": "DOCUMENT_MARGIN"
458
+ }
459
+ },
460
+ "padding": {
461
+ "bottom": {
462
+ "scaling_factor": 1,
463
+ "size": "NONE"
464
+ },
465
+ "left": {
466
+ "scaling_factor": 1,
467
+ "size": "MEDIUM"
468
+ },
469
+ "right": {
470
+ "scaling_factor": 1,
471
+ "size": "SMALL"
472
+ },
473
+ "top": {
474
+ "scaling_factor": 1,
475
+ "size": "NONE"
476
+ }
477
+ },
478
+ "text_alignment": "LEFT",
479
+ "text_size_scale": 1,
480
+ "underline": "NONE"
481
+ },
482
+ "pull_quote": {
483
+ "background_color": "#FFFFFF",
484
+ "border": {
485
+ "bottom": {
486
+ "width": 0
487
+ },
488
+ "left": {
489
+ "width": 0
490
+ },
491
+ "right": {
492
+ "width": 0
493
+ },
494
+ "top": {
495
+ "width": 0
496
+ }
497
+ },
498
+ "capitalization": "NONE",
499
+ "color": "#000000",
500
+ "display": "INLINE",
501
+ "font": "Georgia",
502
+ "line_height_scale": 1,
503
+ "margin": {
504
+ "left": {
505
+ "scaling_factor": 1,
506
+ "size": "DOCUMENT_MARGIN"
507
+ },
508
+ "right": {
509
+ "scaling_factor": 1,
510
+ "size": "DOCUMENT_MARGIN"
511
+ }
512
+ },
513
+ "padding": {
514
+ "bottom": {
515
+ "scaling_factor": 1,
516
+ "size": "NONE"
517
+ },
518
+ "left": {
519
+ "scaling_factor": 1,
520
+ "size": "NONE"
521
+ },
522
+ "right": {
523
+ "scaling_factor": 1,
524
+ "size": "NONE"
525
+ },
526
+ "top": {
527
+ "scaling_factor": 1,
528
+ "size": "NONE"
529
+ }
530
+ },
531
+ "text_alignment": "LEFT",
532
+ "text_size_scale": 1,
533
+ "underline": "NONE"
534
+ },
535
+ "pull_quote_attribution": {
536
+ "background_color": "#FFFFFF",
537
+ "border": {
538
+ "bottom": {
539
+ "width": 0
540
+ },
541
+ "left": {
542
+ "width": 0
543
+ },
544
+ "right": {
545
+ "width": 0
546
+ },
547
+ "top": {
548
+ "width": 0
549
+ }
550
+ },
551
+ "capitalization": "ALL_CAPS",
552
+ "color": "#000000",
553
+ "display": "INLINE",
554
+ "font": "Helvetica Neue",
555
+ "line_height_scale": 1,
556
+ "margin": {
557
+ "left": {
558
+ "scaling_factor": 1,
559
+ "size": "DOCUMENT_MARGIN"
560
+ },
561
+ "right": {
562
+ "scaling_factor": 1,
563
+ "size": "DOCUMENT_MARGIN"
564
+ }
565
+ },
566
+ "padding": {
567
+ "bottom": {
568
+ "scaling_factor": 1,
569
+ "size": "NONE"
570
+ },
571
+ "left": {
572
+ "scaling_factor": 1,
573
+ "size": "NONE"
574
+ },
575
+ "right": {
576
+ "scaling_factor": 1,
577
+ "size": "NONE"
578
+ },
579
+ "top": {
580
+ "scaling_factor": 1,
581
+ "size": "NONE"
582
+ }
583
+ },
584
+ "text_alignment": "LEFT",
585
+ "text_size_scale": 1,
586
+ "underline": "NONE"
587
+ },
588
+ "caption_title_small": {
589
+ "background_color": "#FFFFFF",
590
+ "border": {
591
+ "bottom": {
592
+ "width": 0
593
+ },
594
+ "left": {
595
+ "width": 0
596
+ },
597
+ "right": {
598
+ "width": 0
599
+ },
600
+ "top": {
601
+ "width": 0
602
+ }
603
+ },
604
+ "capitalization": "NONE",
605
+ "color": "#808080",
606
+ "display": "INLINE",
607
+ "font": "Helvetica Neue Bold",
608
+ "line_height_scale": 1,
609
+ "margin": {
610
+ "left": {
611
+ "scaling_factor": 1,
612
+ "size": "DOCUMENT_MARGIN"
613
+ },
614
+ "right": {
615
+ "scaling_factor": 1,
616
+ "size": "DOCUMENT_MARGIN"
617
+ }
618
+ },
619
+ "padding": {
620
+ "bottom": {
621
+ "scaling_factor": 1,
622
+ "size": "NONE"
623
+ },
624
+ "left": {
625
+ "scaling_factor": 1,
626
+ "size": "NONE"
627
+ },
628
+ "right": {
629
+ "scaling_factor": 1,
630
+ "size": "NONE"
631
+ },
632
+ "top": {
633
+ "scaling_factor": 1,
634
+ "size": "NONE"
635
+ }
636
+ },
637
+ "text_alignment": "LEFT",
638
+ "text_size_scale": 1,
639
+ "underline": "NONE"
640
+ },
641
+ "caption_title": {
642
+ "background_color": "#FFFFFF",
643
+ "border": {
644
+ "bottom": {
645
+ "width": 0
646
+ },
647
+ "left": {
648
+ "width": 0
649
+ },
650
+ "right": {
651
+ "width": 0
652
+ },
653
+ "top": {
654
+ "width": 0
655
+ }
656
+ },
657
+ "capitalization": "NONE",
658
+ "color": "#808080",
659
+ "display": "INLINE",
660
+ "font": "Georgia",
661
+ "line_height_scale": 1,
662
+ "margin": {
663
+ "left": {
664
+ "scaling_factor": 1,
665
+ "size": "DOCUMENT_MARGIN"
666
+ },
667
+ "right": {
668
+ "scaling_factor": 1,
669
+ "size": "DOCUMENT_MARGIN"
670
+ }
671
+ },
672
+ "padding": {
673
+ "bottom": {
674
+ "scaling_factor": 1,
675
+ "size": "NONE"
676
+ },
677
+ "left": {
678
+ "scaling_factor": 1,
679
+ "size": "NONE"
680
+ },
681
+ "right": {
682
+ "scaling_factor": 1,
683
+ "size": "NONE"
684
+ },
685
+ "top": {
686
+ "scaling_factor": 1,
687
+ "size": "NONE"
688
+ }
689
+ },
690
+ "text_alignment": "LEFT",
691
+ "text_size_scale": 1,
692
+ "underline": "NONE"
693
+ },
694
+ "caption_title_large": {
695
+ "background_color": "#FFFFFF",
696
+ "border": {
697
+ "bottom": {
698
+ "width": 0
699
+ },
700
+ "left": {
701
+ "width": 0
702
+ },
703
+ "right": {
704
+ "width": 0
705
+ },
706
+ "top": {
707
+ "width": 0
708
+ }
709
+ },
710
+ "capitalization": "NONE",
711
+ "color": "#808080",
712
+ "display": "INLINE",
713
+ "font": "Georgia",
714
+ "line_height_scale": 1,
715
+ "margin": {
716
+ "left": {
717
+ "scaling_factor": 1,
718
+ "size": "DOCUMENT_MARGIN"
719
+ },
720
+ "right": {
721
+ "scaling_factor": 1,
722
+ "size": "DOCUMENT_MARGIN"
723
+ }
724
+ },
725
+ "padding": {
726
+ "bottom": {
727
+ "scaling_factor": 1,
728
+ "size": "NONE"
729
+ },
730
+ "left": {
731
+ "scaling_factor": 1,
732
+ "size": "NONE"
733
+ },
734
+ "right": {
735
+ "scaling_factor": 1,
736
+ "size": "NONE"
737
+ },
738
+ "top": {
739
+ "scaling_factor": 1,
740
+ "size": "NONE"
741
+ }
742
+ },
743
+ "text_alignment": "LEFT",
744
+ "text_size_scale": 1,
745
+ "underline": "NONE"
746
+ },
747
+ "caption_title_extra_large": {
748
+ "background_color": "#FFFFFF",
749
+ "border": {
750
+ "bottom": {
751
+ "width": 0
752
+ },
753
+ "left": {
754
+ "width": 0
755
+ },
756
+ "right": {
757
+ "width": 0
758
+ },
759
+ "top": {
760
+ "width": 0
761
+ }
762
+ },
763
+ "capitalization": "NONE",
764
+ "color": "#808080",
765
+ "display": "INLINE",
766
+ "font": "Georgia",
767
+ "line_height_scale": 1,
768
+ "margin": {
769
+ "left": {
770
+ "scaling_factor": 1,
771
+ "size": "DOCUMENT_MARGIN"
772
+ },
773
+ "right": {
774
+ "scaling_factor": 1,
775
+ "size": "DOCUMENT_MARGIN"
776
+ }
777
+ },
778
+ "padding": {
779
+ "bottom": {
780
+ "scaling_factor": 1,
781
+ "size": "NONE"
782
+ },
783
+ "left": {
784
+ "scaling_factor": 1,
785
+ "size": "NONE"
786
+ },
787
+ "right": {
788
+ "scaling_factor": 1,
789
+ "size": "NONE"
790
+ },
791
+ "top": {
792
+ "scaling_factor": 1,
793
+ "size": "NONE"
794
+ }
795
+ },
796
+ "text_alignment": "LEFT",
797
+ "text_size_scale": 1,
798
+ "underline": "NONE"
799
+ },
800
+ "caption_credit": {
801
+ "background_color": "#FFFFFF",
802
+ "border": {
803
+ "bottom": {
804
+ "width": 0
805
+ },
806
+ "left": {
807
+ "width": 0
808
+ },
809
+ "right": {
810
+ "width": 0
811
+ },
812
+ "top": {
813
+ "width": 0
814
+ }
815
+ },
816
+ "capitalization": "ALL_CAPS",
817
+ "color": "#BFBFBF",
818
+ "display": "INLINE",
819
+ "font": "Helvetica Neue",
820
+ "line_height_scale": 1,
821
+ "margin": {
822
+ "left": {
823
+ "scaling_factor": 1,
824
+ "size": "DOCUMENT_MARGIN"
825
+ },
826
+ "right": {
827
+ "scaling_factor": 1,
828
+ "size": "DOCUMENT_MARGIN"
829
+ }
830
+ },
831
+ "padding": {
832
+ "bottom": {
833
+ "scaling_factor": 1,
834
+ "size": "NONE"
835
+ },
836
+ "left": {
837
+ "scaling_factor": 1,
838
+ "size": "NONE"
839
+ },
840
+ "right": {
841
+ "scaling_factor": 1,
842
+ "size": "NONE"
843
+ },
844
+ "top": {
845
+ "scaling_factor": 1,
846
+ "size": "NONE"
847
+ }
848
+ },
849
+ "text_alignment": "LEFT",
850
+ "text_size_scale": 1,
851
+ "underline": "NONE"
852
+ },
853
+ "caption_description_small": {
854
+ "background_color": "#FFFFFF",
855
+ "border": {
856
+ "bottom": {
857
+ "width": 0
858
+ },
859
+ "left": {
860
+ "width": 0
861
+ },
862
+ "right": {
863
+ "width": 0
864
+ },
865
+ "top": {
866
+ "width": 0
867
+ }
868
+ },
869
+ "capitalization": "NONE",
870
+ "color": "#808080",
871
+ "display": "INLINE",
872
+ "font": "Helvetica Neue",
873
+ "line_height_scale": 1,
874
+ "margin": {
875
+ "left": {
876
+ "scaling_factor": 1,
877
+ "size": "DOCUMENT_MARGIN"
878
+ },
879
+ "right": {
880
+ "scaling_factor": 1,
881
+ "size": "DOCUMENT_MARGIN"
882
+ }
883
+ },
884
+ "padding": {
885
+ "bottom": {
886
+ "scaling_factor": 1,
887
+ "size": "NONE"
888
+ },
889
+ "left": {
890
+ "scaling_factor": 1,
891
+ "size": "NONE"
892
+ },
893
+ "right": {
894
+ "scaling_factor": 1,
895
+ "size": "NONE"
896
+ },
897
+ "top": {
898
+ "scaling_factor": 1,
899
+ "size": "NONE"
900
+ }
901
+ },
902
+ "text_alignment": "LEFT",
903
+ "text_size_scale": 1,
904
+ "underline": "NONE"
905
+ },
906
+ "caption_description": {
907
+ "background_color": "#FFFFFF",
908
+ "border": {
909
+ "bottom": {
910
+ "width": 0
911
+ },
912
+ "left": {
913
+ "width": 0
914
+ },
915
+ "right": {
916
+ "width": 0
917
+ },
918
+ "top": {
919
+ "width": 0
920
+ }
921
+ },
922
+ "capitalization": "NONE",
923
+ "color": "#808080",
924
+ "display": "INLINE",
925
+ "font": "Georgia",
926
+ "line_height_scale": 1,
927
+ "margin": {
928
+ "left": {
929
+ "scaling_factor": 1,
930
+ "size": "DOCUMENT_MARGIN"
931
+ },
932
+ "right": {
933
+ "scaling_factor": 1,
934
+ "size": "DOCUMENT_MARGIN"
935
+ }
936
+ },
937
+ "padding": {
938
+ "bottom": {
939
+ "scaling_factor": 1,
940
+ "size": "NONE"
941
+ },
942
+ "left": {
943
+ "scaling_factor": 1,
944
+ "size": "NONE"
945
+ },
946
+ "right": {
947
+ "scaling_factor": 1,
948
+ "size": "NONE"
949
+ },
950
+ "top": {
951
+ "scaling_factor": 1,
952
+ "size": "NONE"
953
+ }
954
+ },
955
+ "text_alignment": "LEFT",
956
+ "text_size_scale": 1,
957
+ "underline": "NONE"
958
+ },
959
+ "caption_description_large": {
960
+ "background_color": "#FFFFFF",
961
+ "border": {
962
+ "bottom": {
963
+ "width": 0
964
+ },
965
+ "left": {
966
+ "width": 0
967
+ },
968
+ "right": {
969
+ "width": 0
970
+ },
971
+ "top": {
972
+ "width": 0
973
+ }
974
+ },
975
+ "capitalization": "NONE",
976
+ "color": "#808080",
977
+ "display": "INLINE",
978
+ "font": "Georgia",
979
+ "line_height_scale": 1,
980
+ "margin": {
981
+ "left": {
982
+ "scaling_factor": 1,
983
+ "size": "DOCUMENT_MARGIN"
984
+ },
985
+ "right": {
986
+ "scaling_factor": 1,
987
+ "size": "DOCUMENT_MARGIN"
988
+ }
989
+ },
990
+ "padding": {
991
+ "bottom": {
992
+ "scaling_factor": 1,
993
+ "size": "NONE"
994
+ },
995
+ "left": {
996
+ "scaling_factor": 1,
997
+ "size": "NONE"
998
+ },
999
+ "right": {
1000
+ "scaling_factor": 1,
1001
+ "size": "NONE"
1002
+ },
1003
+ "top": {
1004
+ "scaling_factor": 1,
1005
+ "size": "NONE"
1006
+ }
1007
+ },
1008
+ "text_alignment": "LEFT",
1009
+ "text_size_scale": 1,
1010
+ "underline": "NONE"
1011
+ },
1012
+ "caption_description_extra_large": {
1013
+ "background_color": "#FFFFFF",
1014
+ "border": {
1015
+ "bottom": {
1016
+ "width": 0
1017
+ },
1018
+ "left": {
1019
+ "width": 0
1020
+ },
1021
+ "right": {
1022
+ "width": 0
1023
+ },
1024
+ "top": {
1025
+ "width": 0
1026
+ }
1027
+ },
1028
+ "capitalization": "NONE",
1029
+ "color": "#808080",
1030
+ "display": "INLINE",
1031
+ "font": "Georgia",
1032
+ "line_height_scale": 1,
1033
+ "margin": {
1034
+ "left": {
1035
+ "scaling_factor": 1,
1036
+ "size": "DOCUMENT_MARGIN"
1037
+ },
1038
+ "right": {
1039
+ "scaling_factor": 1,
1040
+ "size": "DOCUMENT_MARGIN"
1041
+ }
1042
+ },
1043
+ "padding": {
1044
+ "bottom": {
1045
+ "scaling_factor": 1,
1046
+ "size": "NONE"
1047
+ },
1048
+ "left": {
1049
+ "scaling_factor": 1,
1050
+ "size": "NONE"
1051
+ },
1052
+ "right": {
1053
+ "scaling_factor": 1,
1054
+ "size": "NONE"
1055
+ },
1056
+ "top": {
1057
+ "scaling_factor": 1,
1058
+ "size": "NONE"
1059
+ }
1060
+ },
1061
+ "text_alignment": "LEFT",
1062
+ "text_size_scale": 1,
1063
+ "underline": "NONE"
1064
+ },
1065
+ "footer": {
1066
+ "background_color": "#00FFFFFF",
1067
+ "border": {
1068
+ "bottom": {
1069
+ "width": 0
1070
+ },
1071
+ "left": {
1072
+ "width": 0
1073
+ },
1074
+ "right": {
1075
+ "width": 0
1076
+ },
1077
+ "top": {
1078
+ "width": 0
1079
+ }
1080
+ },
1081
+ "capitalization": "NONE",
1082
+ "color": "#000000",
1083
+ "display": "INLINE",
1084
+ "font": "Helvetica Neue",
1085
+ "line_height_scale": 1,
1086
+ "margin": {
1087
+ "left": {
1088
+ "scaling_factor": 1,
1089
+ "size": "DOCUMENT_MARGIN"
1090
+ },
1091
+ "right": {
1092
+ "scaling_factor": 1,
1093
+ "size": "DOCUMENT_MARGIN"
1094
+ }
1095
+ },
1096
+ "padding": {
1097
+ "bottom": {
1098
+ "scaling_factor": 1,
1099
+ "size": "NONE"
1100
+ },
1101
+ "left": {
1102
+ "scaling_factor": 1,
1103
+ "size": "NONE"
1104
+ },
1105
+ "right": {
1106
+ "scaling_factor": 1,
1107
+ "size": "NONE"
1108
+ },
1109
+ "top": {
1110
+ "scaling_factor": 1,
1111
+ "size": "NONE"
1112
+ }
1113
+ },
1114
+ "text_alignment": "LEFT",
1115
+ "text_size_scale": 1,
1116
+ "underline": "NONE"
1117
+ },
1118
+ "id": "1331594966932732",
1119
+ "name": "default",
1120
+ "is_default": false,
1121
+ "header": {
1122
+ "accent_color": "#989898",
1123
+ "background_color": "#0f5aa5",
1124
+ "logo": {
1125
+ "full_resolution_url": "https://scontent.xx.fbcdn.net/v/t39.5687-6/18601675_1346062722145630_7520526922577608704_n.png?_nc_log=1&oh=da39b645a2451707922783ca9216798c&oe=59ABEE74",
1126
+ "full_resolution_width": 690,
1127
+ "full_resolution_height": 132,
1128
+ "thumbnail_url": "https://fb-s-c-a.akamaihd.net/h-ak-fbx/v/t39.5687-6/18316413_1479102688826582_6425345085692444672_n.png?_nc_log=1&oh=bdbfc80602af9814d5ded9fa697c2541&oe=59BA0B55&__gda__=1503683893_41eab7141458daff7d6e0ad0d8ad7506",
1129
+ "id": "1346062718812297"
1130
+ },
1131
+ "logo_scale": 1
1132
+ }
1133
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/AMP/configuration/global.amp.css ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*Global Styles*/
2
+ .ia2amp-header-bar {
3
+ margin: -5px 0 0 0;
4
+ height: 55px;
5
+ font: 0/0 a;
6
+ }
7
+ .ia2amp-header-bar:before {
8
+ content: ' ';
9
+ display: inline-block;
10
+ vertical-align: middle;
11
+ height: 100%;
12
+ width: 16.4px;
13
+ }
14
+ .ia2amp-header-bar-img-container {
15
+ display: inline-block;
16
+ vertical-align: middle;
17
+ }
18
+ .ia2amp-header-category {
19
+ font-size: 10px;
20
+ line-height: 12px;
21
+ display: block;
22
+ font-weight: normal;
23
+ }
24
+ .ia2amp-header-h1 {
25
+ font-size: 24px;
26
+ line-height: 30px;
27
+ display: block;
28
+ font-weight: normal;
29
+ }
30
+ .ia2amp-header-h2 {
31
+ font-size: 16px;
32
+ line-height: 20px;
33
+ display: block;
34
+ font-weight: normal;
35
+ }
36
+ .ia2amp-header h3 {
37
+ font-size: 8px;
38
+ line-height: 12px;
39
+ display: block;
40
+ font-weight: normal;
41
+ }
42
+
43
+ .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 {
44
+ display: block;
45
+ font-weight: normal;
46
+ }
47
+
48
+ .ia2amp-h1 {
49
+ font-size: 19px;
50
+ line-height: 23px;
51
+ }
52
+
53
+ .ia2amp-h2 {
54
+ font-size: 16px;
55
+ line-height: 20px;
56
+ }
57
+
58
+ .ia2amp-p {
59
+ font-size: 14px;
60
+ line-height: 20px;
61
+ display: inline-block;
62
+
63
+
64
+ }
65
+ .ia2amp-p a {
66
+ margin: 0;
67
+ }
68
+
69
+ .ia2amp-blockquote {
70
+ font-size: 14px;
71
+ line-height: 20px;
72
+ padding: 0px 13.2px 0px 18.8px;
73
+ }
74
+
75
+ .ia2amp-spacing {
76
+ display: block;
77
+ height: 18.8px;
78
+ margin: 0 16.4px 0 16.4px;
79
+ }
80
+
81
+ header figure figcaption {
82
+ display: none;
83
+ }
84
+
85
+ .ia2amp-figure {
86
+ margin: 0;
87
+ }
88
+
89
+ .ia2amp-op-small h1, .ia2amp-op-small h2 {
90
+ font-size: 10px;
91
+ display: block;
92
+ }
93
+
94
+ .ia2amp-op-medium h1, .ia2amp-op-medium h2 {
95
+ font-size: 14px;
96
+ display: block;
97
+ }
98
+
99
+ .ia2amp-op-large h1, .ia2amp-op-large h2 {
100
+ font-size: 16px;
101
+ display: block;
102
+ }
103
+
104
+ .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 {
105
+ font-size: 23px;
106
+ display: block;
107
+ }
108
+
109
+ .ia2amp-figcaption cite {
110
+ font-size: 8px;
111
+ display: block;
112
+ }
113
+
114
+ .ia2amp-op-left {
115
+ text-align: left;
116
+ }
117
+
118
+ .ia2amp-op-center {
119
+ text-align: center;
120
+ }
121
+
122
+ .ia2amp-op-right {
123
+ text-align: right;
124
+ }
125
+
126
+ .ia2amp-figure {
127
+ position: relative;
128
+ }
129
+
130
+ figcaption.ia2amp-op-vertical-center {
131
+ position: absolute;
132
+ z-index: 1000;
133
+ }
134
+
135
+ .ia2amp-footer {
136
+ display: block;
137
+ font-size: 12px;
138
+ line-height: 17px;
139
+ }
140
+
141
+ .ia2amp-footer aside p {
142
+ margin: 0;
143
+ }
144
+
145
+ .ia2amp-spacing.after-header-bar.before-header-category {
146
+ height: 18.8px;
147
+ }
148
+
149
+ .ia2amp-spacing.after-header-category.before-header-h1,
150
+ .ia2amp-spacing.after-header-h1.before-header-h2 {
151
+ height: 13.2px;
152
+ }
153
+
154
+ .ia2amp-spacing.after-h1.before-h2 {
155
+ height: 13.2px;
156
+ }
157
+
158
+ .ia2amp-spacing.after-li.before-li {
159
+ height: 13.2px;
160
+ }
161
+
162
+ .ia2amp-spacing.after-footer.before-footer {
163
+ height: 18.8px;
164
+ }
165
+
166
+ .ia2amp-spacing.after-header-h1.before-header-author,
167
+ .ia2amp-spacing.after-header-h2.before-header-author {
168
+ height: 18.8px;
169
+ }
170
+
171
+ .ia2amp-spacing.after-header-author.before-header-date {
172
+ height: 0;
173
+ }
174
+
175
+ .ia2amp-spacing.after-header-date.before-h1,
176
+ .ia2amp-spacing.after-header-date.before-h2,
177
+ .ia2amp-spacing.after-header-date.before-p {
178
+ height: 26.4px;
179
+ }
180
+
181
+ .ia2amp-spacing.after-h1.before-p,
182
+ .ia2amp-spacing.after-h2.before-p,
183
+ .ia2amp-spacing.after-h3.before-p {
184
+ height: 18.8px;
185
+ }
186
+
187
+ .ia2amp-spacing.after-blockquote.before-p {
188
+ height: 18.8px;
189
+ }
190
+
191
+ .ia2amp-spacing.after-slideshow,
192
+ .ia2amp-spacing.before-slideshow,
193
+ .ia2amp-spacing.after-interactive,
194
+ .ia2amp-spacing.before-interactive,
195
+ .ia2amp-spacing.after-image,
196
+ .ia2amp-spacing.before-image,
197
+ .ia2amp-spacing.after-figcaption-small,
198
+ .ia2amp-spacing.after-figcaption-medium,
199
+ .ia2amp-spacing.after-figcaption-large,
200
+ .ia2amp-spacing.after-figcaption-extra-large {
201
+ height: 26.4px;
202
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/CSSBuilder.php ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ /**
12
+ * Helper class to build up CSS structure file.
13
+ * Usage example:
14
+ * <code>
15
+ * $cssBuilder = new CSSBuilder();
16
+ * $cssBuilder->addProperty('.someClass', 'width', '300px')
17
+ * ->addProperty('.someClass', 'height', '400px')
18
+ * ->addProperty('.otherClass', 'background-color', '#aabbcc')
19
+ * ->addProperty('.otherClass', 'border-width', '2px');
20
+ * $result = $cssBuilder->build(true);
21
+ * </code>
22
+ */
23
+ class CSSBuilder
24
+ {
25
+ /**
26
+ * @var array('string'=>array('string' => properties))
27
+ */
28
+ private $selectors = array();
29
+
30
+ /**
31
+ * @var string prefix for css selector classes
32
+ */
33
+ private $prefix;
34
+
35
+ /**
36
+ * @var string spacing For height on the separator divs
37
+ */
38
+ private $spacing;
39
+
40
+ public function __construct($prefix = 'ia2amp-', $spacing = 'spacing')
41
+ {
42
+ $this->prefix = $prefix;
43
+ $this->spacing = $spacing;
44
+ }
45
+
46
+ /**
47
+ * Simple key => value method setting for CSS properties. This method does not apply any validation
48
+ * be cautious about using it.
49
+ * @param string $selector The selector for the CSS, free format accepted. Be cautious.
50
+ * @param string $property The property name on CSS, free format accepted. Be cautious.
51
+ * @param string $value The property value on CSS, free format accepted. Be cautious.
52
+ * @return CSSBuilder $this instance.
53
+ */
54
+ public function addProperty($selector, $property, $value)
55
+ {
56
+ if (isset($this->selectors[$selector])) {
57
+ $selectorProps = $this->selectors[$selector];
58
+ } else {
59
+ $selectorProps = array();
60
+ }
61
+
62
+ $selectorProps[$property] = $value;
63
+ $this->selectors[$selector] = $selectorProps;
64
+
65
+ return $this;
66
+ }
67
+
68
+ /**
69
+ * Adds property and value to the $class. It creates the selector, apply prefix and builds up
70
+ * css selector class grouping the properties.
71
+ * @param string|array<string> $class The class to be applied to the selector.
72
+ * @param string $property The property name on CSS, free format accepted. Be cautious.
73
+ * @param string $value The property value on CSS, free format accepted. Be cautious.
74
+ * @return CSSBuilder $this instance.
75
+ */
76
+ public function addToSelector($class, $property, $value)
77
+ {
78
+ return $this->addProperty($this->buildCssSelector($class), $property, $value);
79
+ }
80
+
81
+ /**
82
+ * Adds dimension sized property value to the $class. It creates the selector, apply prefix and builds up
83
+ * css selector class grouping the properties. If value not informed, zero will be placed.
84
+ * @param string|array<string> $class The class to be applied to the selector.
85
+ * @param string $property The property name on CSS, free format accepted. Be cautious.
86
+ * @param string|float|int $dimension The property value on CSS.
87
+ * @param string $unit The unit to be applied. Default value: 'px'.
88
+ * @return CSSBuilder $this instance.
89
+ */
90
+ public function addDimensionToSelector($class, $property, $dimension, $unit = 'px')
91
+ {
92
+ return $this->addProperty($this->buildCssSelector($class), $property, $dimension ? $dimension.$unit : '0');
93
+ }
94
+
95
+ /**
96
+ * Adds condensed dimensions to property value selected by $class. If value not informed, zero will be placed.
97
+ * @param string|array<string> $class The class to be applied to the selector.
98
+ * @param string $property The property name on CSS, free format accepted. Be cautious.
99
+ * @param string|float|int $top The property value for top position on CSS.
100
+ * @param string|float|int $right The property value for right position on CSS.
101
+ * @param string|float|int $bottom The property value for bottom position on CSS.
102
+ * @param string|float|int $left The property value for left position on CSS.
103
+ * * @param string $unit The unit to be applied. Default value: 'px'.
104
+ * @return CSSBuilder $this instance.
105
+ */
106
+ public function addTopRightBottomLeftToSelector($class, $property, $top, $right, $bottom, $left, $unit = 'px')
107
+ {
108
+ $dimension =
109
+ ($top ? $top.$unit : '0').' '.
110
+ ($right ? $right.$unit : '0').' '.
111
+ ($bottom ? $bottom.$unit : '0').' '.
112
+ ($left ? $left.$unit : '0');
113
+ return $this->addProperty($this->buildCssSelector($class), $property, $dimension);
114
+ }
115
+
116
+ /**
117
+ * Adds spacing height value to the proper selected class.
118
+ * @param string|array<string> $class The class to be applied to the selector.
119
+ * @param string|float|int $height The spacing value for spacing.
120
+ * @param string $unit The unity to be applied. Default value: 'px'.
121
+ * @return CSSBuilder $this instance.
122
+ */
123
+ public function addHeightSpacingToSelector($class, $height, $unit = 'px')
124
+ {
125
+ return $this->addProperty(
126
+ $this->buildCssSelector($class).' + '.$this->buildCssSelector($this->spacing),
127
+ 'height',
128
+ $height ? $height.$unit : '0'
129
+ );
130
+ }
131
+
132
+
133
+ private function buildCssClass($cssClassName)
134
+ {
135
+ return $this->prefix.$cssClassName;
136
+ }
137
+
138
+ private function buildCssSelector($class)
139
+ {
140
+ if (is_array($class)) {
141
+ $selectors = array();
142
+ foreach ($class as $singleClass) {
143
+ $selectors[] = $this->buildCssSelector($singleClass);
144
+ }
145
+ return implode(', ', $selectors);
146
+ } else {
147
+ return '.'.$this->buildCssClass($class);
148
+ }
149
+ }
150
+
151
+
152
+ /**
153
+ * Builds the css output representing the current status of the CSSBuilder structure.
154
+ * @param $formatOutput boolean Indicates if output will be formated.
155
+ * @return string The CSS generated based on current status.
156
+ */
157
+ public function build($formatOutput = true)
158
+ {
159
+ $result = '';
160
+ $formatIdent = $formatOutput ? ' ' : '';
161
+ $formatNewLine = $formatOutput ? "\n" : '';
162
+ foreach ($this->selectors as $selector => $properties) {
163
+ if ($properties && !empty($properties)) {
164
+ if ($result !== '') {
165
+ $result = $result.$formatNewLine.$formatNewLine;
166
+ }
167
+
168
+ $result = $result.$selector.' {'.$formatNewLine;
169
+ foreach ($properties as $property => $value) {
170
+ $result = $result.$formatIdent.$property.': '.$value.';';
171
+ $result = $result.$formatNewLine;
172
+ }
173
+ $result = $result.'}';
174
+ }
175
+ }
176
+
177
+ return $result;
178
+ }
179
+
180
+ /**
181
+ * Auxiliary method to extract the full qualified class name.
182
+ *
183
+ * @return string The full qualified name of class.
184
+ */
185
+ public static function getClassName()
186
+ {
187
+ return get_called_class();
188
+ }
189
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/CallbackHook.php ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ /**
12
+ * CallbackHook class. This is the helper class to get the hooks prioritized, called, removed and mantained.
13
+ */
14
+ class CallbackHook implements \Iterator, \ArrayAccess
15
+ {
16
+
17
+ /**
18
+ * @var array Callback functions/instance->methods
19
+ */
20
+ public $callbacks = array();
21
+
22
+ /**
23
+ * @var array The priority keys of actively running iterations of a hook.
24
+ */
25
+ private $iterations = array();
26
+
27
+ /**
28
+ * @var array The current priority of actively running iterations of a hook.
29
+ */
30
+ private $currentPriority = array();
31
+
32
+ /**
33
+ * @var int Number of levels this hook can be recursively called.
34
+ */
35
+ private $nestingLevel = 0;
36
+
37
+ /**
38
+ * Hooks a function or method to a specific filter action.
39
+ *
40
+ * @param string $tag The name of the filter to hook the $functionToAdd callback to.
41
+ * @param callable $functionToAdd The callback to be run when the filter is applied.
42
+ * @param int $priority The order in which the functions associated with a
43
+ * particular action are executed. Lower numbers correspond with
44
+ * earlier execution, and functions with the same priority are executed
45
+ * in the order in which they were added to the action.
46
+ * @param int $acceptedArgs The number of arguments the function accepts.
47
+ */
48
+ public function addFilter($idx, $tag, $functionToAdd, $priority, $acceptedArgs)
49
+ {
50
+ $priorityExisted = isset($this->callbacks[$priority]);
51
+
52
+ $this->callbacks[$priority][$idx] = array(
53
+ 'function' => $functionToAdd,
54
+ 'accepted_args' => $acceptedArgs
55
+ );
56
+
57
+ // if we're adding a new priority to the list, put them back in sorted order
58
+ if (!$priorityExisted && count($this->callbacks) > 1) {
59
+ ksort($this->callbacks, SORT_NUMERIC);
60
+ }
61
+
62
+ if ($this->nestingLevel > 0) {
63
+ $this->resortPerPriority($priority, $priorityExisted);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Handles reseting callback priority keys mid-iteration.
69
+ *
70
+ * @param bool|int $newPriority Optional. The priority of the new filter being added. Default false,
71
+ * for no priority being added.
72
+ * @param bool $priorityExisted Optional. Flag for whether the priority already existed before the new
73
+ * filter was added. Default false.
74
+ */
75
+ private function resortPerPriority($newPriority = false, $priorityExisted = false)
76
+ {
77
+ $newPriorities = array_keys($this->callbacks);
78
+
79
+ // If there are no remaining hooks, clear out all running iterations.
80
+ if (! $newPriorities) {
81
+ foreach ($this->iterations as $index => $iteration) {
82
+ $this->iterations[$index] = $newPriorities;
83
+ }
84
+ return;
85
+ }
86
+
87
+ $min = min($newPriorities);
88
+ foreach ($this->iterations as $index => &$iteration) {
89
+ $current = current($iteration);
90
+ // If we're already at the end of this iteration, just leave the array pointer where it is.
91
+ if (false === $current) {
92
+ continue;
93
+ }
94
+
95
+ $iteration = $newPriorities;
96
+
97
+ if ($current < $min) {
98
+ array_unshift($iteration, $current);
99
+ continue;
100
+ }
101
+
102
+ while (current($iteration) < $current) {
103
+ if (false === next($iteration)) {
104
+ break;
105
+ }
106
+ }
107
+
108
+ // If we have a new priority that didn't exist, but ::applyFilters() thinks it's the current priority...
109
+ if ($newPriority === $this->currentPriority[$index] && ! $priorityExisted) {
110
+ /*
111
+ * ... and the new priority is the same as what $this->iterations thinks is the previous
112
+ * priority, we need to move back to it.
113
+ */
114
+
115
+ if (false === current($iteration)) {
116
+ // If we've already moved off the end of the array, go back to the last element.
117
+ $prev = end($iteration);
118
+ } else {
119
+ // Otherwise, just go back to the previous element.
120
+ $prev = prev($iteration);
121
+ }
122
+ if (false === $prev) {
123
+ // Start of the array. Reset, and go about our day.
124
+ reset($iteration);
125
+ } elseif ($newPriority !== $prev) {
126
+ // Previous wasn't the same. Move forward again.
127
+ next($iteration);
128
+ }
129
+ }
130
+ }
131
+ unset($iteration);
132
+ }
133
+
134
+ /**
135
+ * Unhooks a function or method from a specific filter action.
136
+ *
137
+ * @param string $tag The filter hook to which the function to be removed is hooked. Used
138
+ * for building the callback ID when SPL is not available.
139
+ * @param int $priority The exact priority used when adding the original filter callback.
140
+ * @return bool Whether the callback existed before it was removed.
141
+ */
142
+ public function removeFilter($idx, $tag, $priority)
143
+ {
144
+ $exists = isset($this->callbacks[$priority][$idx]);
145
+ if ($exists) {
146
+ unset($this->callbacks[$priority][$idx]);
147
+ if (! $this->callbacks[$priority]) {
148
+ unset($this->callbacks[$priority]);
149
+ if ($this->nestingLevel > 0) {
150
+ $this->resortPerPriority();
151
+ }
152
+ }
153
+ }
154
+ return $exists;
155
+ }
156
+
157
+ /**
158
+ * Checks if a specific action has been registered for this hook.
159
+ *
160
+ * @param callable|bool $functionToCheck Optional. The callback to check for. Default false.
161
+ * @param string $tag Optional. The name of the filter hook. Used for building
162
+ * the callback ID when SPL is not available. Default empty.
163
+ * @return bool|int The priority of that hook is returned, or false if the function is not attached.
164
+ */
165
+ public function hasFilter($idx, $tag = '', $functionToCheck = false)
166
+ {
167
+ if (false === $functionToCheck) {
168
+ return $this->hasFilters();
169
+ }
170
+
171
+ if (! $idx) {
172
+ return false;
173
+ }
174
+
175
+ foreach ($this->callbacks as $priority => $callbacks) {
176
+ if (isset($callbacks[$idx])) {
177
+ return $priority;
178
+ }
179
+ }
180
+
181
+ return false;
182
+ }
183
+
184
+ /**
185
+ * Checks if any callbacks have been registered for this hook.
186
+ *
187
+ * @return bool True if callbacks have been registered for the current hook, otherwise false.
188
+ */
189
+ public function hasFilters()
190
+ {
191
+ foreach ($this->callbacks as $callbacks) {
192
+ if ($callbacks) {
193
+ return true;
194
+ }
195
+ }
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * Removes all callbacks from the current filter.
201
+ *
202
+ * @param int|bool $priority Optional. The priority number to remove. Default false.
203
+ */
204
+ public function removeAllFilters($priority = false)
205
+ {
206
+ if (! $this->callbacks) {
207
+ return;
208
+ }
209
+
210
+ if (false === $priority) {
211
+ $this->callbacks = array();
212
+ } else if (isset($this->callbacks[$priority])) {
213
+ unset($this->callbacks[$priority]);
214
+ }
215
+
216
+ if ($this->nestingLevel > 0) {
217
+ $this->resortPerPriority();
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Calls the callback functions added to a filter hook.
223
+ *
224
+ * @param mixed $value The value to filter.
225
+ * @param array $args Arguments to pass to callbacks.
226
+ * @return mixed The filtered value after all hooked functions are applied to it.
227
+ */
228
+ public function applyFilters($value, $args)
229
+ {
230
+ if (!$this->callbacks) {
231
+ return $value;
232
+ }
233
+
234
+ $nestingLevel = $this->nestingLevel++;
235
+
236
+ $this->iterations[$nestingLevel] = array_keys($this->callbacks);
237
+ $num_args = count($args);
238
+
239
+ do {
240
+ $this->currentPriority[$nestingLevel] = $priority = current($this->iterations[$nestingLevel]);
241
+
242
+ foreach ($this->callbacks[$priority] as $callbackPriority) {
243
+ $args[0] = $value;
244
+
245
+ // Avoid the array_slice if possible.
246
+ if ($callbackPriority['accepted_args'] == 0) {
247
+ $value = call_user_func_array($callbackPriority['function'], array());
248
+ } elseif ($callbackPriority['accepted_args'] >= $num_args) {
249
+ $value = call_user_func_array($callbackPriority['function'], $args);
250
+ } else {
251
+ $value = call_user_func_array($callbackPriority['function'], array_slice($args, 0, (int)$callbackPriority['accepted_args']));
252
+ }
253
+ }
254
+ } while (false !== next($this->iterations[$nestingLevel]));
255
+
256
+ unset($this->iterations[$nestingLevel]);
257
+ unset($this->currentPriority[$nestingLevel]);
258
+
259
+ $this->nestingLevel--;
260
+
261
+ return $value;
262
+ }
263
+
264
+ /**
265
+ * Return the current priority level of the currently running iteration of the hook.
266
+ *
267
+ * @return int|false If the hook is running, return the current priority level. If it isn't running, return false.
268
+ */
269
+ public function currentPriority()
270
+ {
271
+ if (false === current($this->iterations)) {
272
+ return false;
273
+ }
274
+
275
+ return current(current($this->iterations));
276
+ }
277
+
278
+ /**
279
+ * Determines whether an offset value exists.
280
+ *
281
+ * @link http://php.net/manual/en/arrayaccess.offsetexists.php
282
+ *
283
+ * @param mixed $offset An offset to check for.
284
+ * @return bool True if the offset exists, false otherwise.
285
+ */
286
+ public function offsetExists($offset)
287
+ {
288
+ return isset($this->callbacks[$offset]);
289
+ }
290
+
291
+ /**
292
+ * Retrieves a value at a specified offset.
293
+ *
294
+ * @link http://php.net/manual/en/arrayaccess.offsetget.php
295
+ *
296
+ * @param mixed $offset The offset to retrieve.
297
+ * @return mixed If set, the value at the specified offset, null otherwise.
298
+ */
299
+ public function offsetGet($offset)
300
+ {
301
+ return isset($this->callbacks[$offset]) ? $this->callbacks[$offset] : null;
302
+ }
303
+
304
+ /**
305
+ * Sets a value at a specified offset.
306
+ *
307
+ * @link http://php.net/manual/en/arrayaccess.offsetset.php
308
+ *
309
+ * @param mixed $offset The offset to assign the value to.
310
+ * @param mixed $value The value to set.
311
+ */
312
+ public function offsetSet($offset, $value)
313
+ {
314
+ if (is_null($offset)) {
315
+ $this->callbacks[] = $value;
316
+ } else {
317
+ $this->callbacks[$offset] = $value;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Unsets a specified offset.
323
+ *
324
+ * @link http://php.net/manual/en/arrayaccess.offsetunset.php
325
+ *
326
+ * @param mixed $offset The offset to unset.
327
+ */
328
+ public function offsetUnset($offset)
329
+ {
330
+ unset($this->callbacks[$offset]);
331
+ }
332
+
333
+ /**
334
+ * Returns the current element.
335
+ *
336
+ * @link http://php.net/manual/en/iterator.current.php
337
+ *
338
+ * @return array Of callbacks at current priority.
339
+ */
340
+ public function current()
341
+ {
342
+ return current($this->callbacks);
343
+ }
344
+
345
+ /**
346
+ * Moves forward to the next element.
347
+ *
348
+ * @link http://php.net/manual/en/iterator.next.php
349
+ *
350
+ * @return array Of callbacks at next priority.
351
+ */
352
+ public function next()
353
+ {
354
+ return next($this->callbacks);
355
+ }
356
+
357
+ /**
358
+ * Returns the key of the current element.
359
+ *
360
+ * @link http://php.net/manual/en/iterator.key.php
361
+ *
362
+ * @return mixed Returns current priority on success, or NULL on failure
363
+ */
364
+ public function key()
365
+ {
366
+ return key($this->callbacks);
367
+ }
368
+
369
+ /**
370
+ * Checks if current position is valid.
371
+ *
372
+ * @link http://php.net/manual/en/iterator.valid.php
373
+ *
374
+ * @return boolean
375
+ */
376
+ public function valid()
377
+ {
378
+ return key($this->callbacks) !== null;
379
+ }
380
+
381
+ /**
382
+ * Rewinds the Iterator to the first element.
383
+ *
384
+ * @link http://php.net/manual/en/iterator.rewind.php
385
+ */
386
+ public function rewind()
387
+ {
388
+ reset($this->callbacks);
389
+ }
390
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Hook.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ /**
12
+ * Class to facilitate hooking callable statements.
13
+ * Usage example:
14
+ * <code>
15
+ * // Obtain the hook instance or create one
16
+ * Hook::create();
17
+ * // Name your hook with the string you want and set the default function to be called.
18
+ * $result = $hook->call('hook_name', array('Facebook\InstantArticles\hook\HookTest', 'staticMethodHookParams'), array('param1', 'param2'));
19
+ * // Anyone can override your callable by using this line:
20
+ * $hook->setHook('hook_name', array($this, 'methodHookReplacing'));
21
+ * </code>
22
+ */
23
+ class Hook
24
+ {
25
+ /* Hooks to have overriden callable */
26
+ private $hooks = array();
27
+ private $params = array();
28
+
29
+ /* Hooks to have before callable */
30
+ private $beforeHooks = array();
31
+ private $beforeParams = array();
32
+
33
+ /* Hooks to have after callable */
34
+ private $afterHooks = array();
35
+ private $afterParams = array();
36
+
37
+ /**
38
+ * Private constructor to force factory method: Hook::create();
39
+ */
40
+ private function __construct()
41
+ {
42
+ }
43
+
44
+ /**
45
+ * @return Hook new instance of the Hook class.
46
+ */
47
+ public static function create()
48
+ {
49
+ return new self();
50
+ }
51
+
52
+ public function clearHooks($hookName)
53
+ {
54
+ $this->removeHook($hookName);
55
+ $this->removeAfterHook($hookName);
56
+ $this->removeBeforeHook($hookName);
57
+ }
58
+
59
+ /**
60
+ * Overrides a hook by name, by setting a new callable, with params.
61
+ * @param string $hookName The name for callable instruction to be intercepted/hooked. Use different names if you need different hooks.
62
+ * @param string/array $callable The string method to be called or array with array('Namespace.ClassName', 'methodName')
63
+ * @param array(mixed) The params to be used into your methodName from your callable.
64
+ */
65
+ public function setHook($hookName, $callable, $params = null)
66
+ {
67
+ $this->hooks[$hookName] = $callable;
68
+ if (isset($params) && $params) {
69
+ $this->params[$hookName] = $params;
70
+ }
71
+ }
72
+
73
+ public function removeHook($hookName)
74
+ {
75
+ unset($this->hooks[$hookName]);
76
+ }
77
+
78
+ /**
79
+ * Overrides a before event hook by name, by setting a new callable, with params. The returned value from the beforeHook will be ignored. There is no blocking system.
80
+ * @param string $hookName The name for callable instruction to be intercepted/hooked. Use different names if you need different hooks.
81
+ * @param string/array $callable The string method to be called or array with array('Namespace.ClassName', 'methodName')
82
+ * @param array(mixed) The params to be used into your methodName from your callable.
83
+ */
84
+ public function setBeforeHook($hookName, $callable, $params = null)
85
+ {
86
+ $this->beforeHooks[$hookName] = $callable;
87
+ if (isset($params) && $params) {
88
+ $this->beforeParams[$hookName] = $params;
89
+ }
90
+ }
91
+
92
+ public function removeBeforeHook($hookName)
93
+ {
94
+ unset($this->beforeHooks[$hookName]);
95
+ }
96
+
97
+ /**
98
+ * Overrides a after event hook by name, by setting a new callable, with params. The returned value from the after will be ignored.
99
+ * @param string $hookName The name for callable instruction to be intercepted/hooked. Use different names if you need different hooks.
100
+ * @param string/array $callable The string method to be called or array with array('Namespace.ClassName', 'methodName')
101
+ * @param array(mixed) The params to be used into your methodName from your callable.
102
+ */
103
+ public function setAfterHook($hookName, $callable, $params = null)
104
+ {
105
+ $this->afterHooks[$hookName] = $callable;
106
+ if (isset($params) && $params) {
107
+ $this->afterParams[$hookName] = $params;
108
+ }
109
+ }
110
+
111
+ public function removeAfterHook($hookName)
112
+ {
113
+ unset($this->afterHooks[$hookName]);
114
+ }
115
+
116
+ /**
117
+ * Any callable method/call that you want to make it possible to have it
118
+ * possible to be overriden or a before/after hook, just call it by name
119
+ * using your hook instance. This make the callable to be intercepted/overriden.
120
+ * @param string $hookName The name for callable instruction to be intercepted/hooked. Use different names if you need different hooks.
121
+ * @param string/array $callable The string method to be called or array with array('Namespace.ClassName', 'methodName')
122
+ * @param array(mixed) The params to be used into your methodName from your callable.
123
+ */
124
+ public function call($hookName, $callable, $params = array())
125
+ {
126
+ // Treats before hook is called. To set something to happen before any hook, just use setBeforeHook('hook_name', ...)
127
+ if (array_key_exists($hookName, $this->beforeHooks) && isset($this->beforeHooks[$hookName])) {
128
+ $beforeCallable = $this->beforeHooks[$hookName];
129
+ $beforeParams = array();
130
+ if (array_key_exists($hookName, $this->beforeParams) && isset($this->beforeParams[$hookName])) {
131
+ $beforeParams = $this->beforeParams[$hookName];
132
+ }
133
+ // Calls the "before" event $hookName, ignoring the return
134
+ call_user_func_array($beforeCallable, $beforeParams);
135
+ }
136
+
137
+ // Treats the Hook itself
138
+ if (array_key_exists($hookName, $this->hooks) && isset($this->hooks[$hookName])) {
139
+ $callable = $this->hooks[$hookName];
140
+ if (array_key_exists($hookName, $this->params) && isset($this->params[$hookName])) {
141
+ $params = $this->params[$hookName];
142
+ }
143
+ }
144
+ $return = call_user_func_array($callable, $params);
145
+
146
+
147
+ // Treats after hook is called. To set something to happen after any hook, just use setAfterHook('hook_name', ...)
148
+ if (array_key_exists($hookName, $this->afterHooks) && isset($this->afterHooks[$hookName])) {
149
+ $afterCallable = $this->afterHooks[$hookName];
150
+ $afterParams = array();
151
+ if (array_key_exists($hookName, $this->afterParams) && isset($this->afterParams[$hookName])) {
152
+ $afterParams = $this->afterParams[$hookName];
153
+ }
154
+
155
+ // Calls the "after" event $hookName ignoring the return
156
+ call_user_func_array($afterCallable, $afterParams);
157
+ }
158
+
159
+ return $return;
160
+ }
161
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Observer.php ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ /**
12
+ * Class Observer for managing filtering into the key and extensible points into
13
+ * your project architecture.
14
+ *
15
+ * Usage example:
16
+ * <code>
17
+ * // Obtain the observer instance or create one
18
+ * $observer = Observer::create();
19
+ * // Name your hook with the string you want and set the default function to be called.
20
+ * $result = $obs->applyFilters('filter name', SomeClass::statciMethodBeingCalled('param1', 'param2'));
21
+ * // Anyone can override your callable by using this line:
22
+ * $obs->addFilter('filter name', array($this, 'methodHookReplacing'));
23
+ * </code>
24
+ */
25
+ class Observer
26
+ {
27
+ private static $filterCount = 0;
28
+
29
+ /* Filters configured. Mapped array: 'filter name' => CallbackHolder */
30
+ private $callbacks = array();
31
+
32
+ /**
33
+ * Private constructor to force factory method: Hook::create();
34
+ */
35
+ private function __construct()
36
+ {
37
+ }
38
+
39
+ /**
40
+ * @return Hook new instance of the Hook class.
41
+ */
42
+ public static function create()
43
+ {
44
+ return new self();
45
+ }
46
+
47
+ /**
48
+ * Hook functions/methods to change, replace or add info to the data you are filtering.
49
+ *
50
+ * Anyone can modify data by binding a callback to a filter hook. When the filter
51
+ * is later applied, each bound callback is run in order of priority, and given
52
+ * the opportunity to modify a value by returning a new value or modifying the
53
+ * value orinally returned.
54
+ *
55
+ * Check the following example on how we can bind callback to a filter:
56
+ *
57
+ * function myCallback( $value ) {
58
+ * // Maybe modify $value in some way.
59
+ * return $value;
60
+ * }
61
+ * $observer = Observer::create();
62
+ * $observer->addFilter('myFilterName', 'myCallback');
63
+ *
64
+ * Bound callbacks can receive zero to the total defined in addFilter method call.
65
+ *
66
+ * Here are few more examples about how to call the apply filters and how to set it up
67
+ * on the addFilter method. For example:
68
+ *
69
+ * // Call to be filtered
70
+ * $value = $observer->applyFilters('filterName', $value, $arg2, $arg3);
71
+ *
72
+ * // Accepting zero/one arguments.
73
+ * function callbackFunction() {
74
+ * ...
75
+ * return 'value overriden';
76
+ * }
77
+ * $observer = Observer::create();
78
+ * $observer->addFilter('filterName', 'callbackFunction'); // Where $priority is default 10, $acceptedArgs is default 1.
79
+ *
80
+ * // Accepting two arguments (three possible).
81
+ * function callbackFunction( $value, $arg2 ) {
82
+ * ...
83
+ * return $modifiedValue;
84
+ * }
85
+ * $observer = Observer::create();
86
+ * $observer->addFilter( 'filterName', 'callbackFunction', 5, 2 ); // Where $priority is 5, $acceptedArgs is 2.
87
+ *
88
+ * @param string $tag The name of the filter hook.
89
+ * @param callable $functionToAdd The callback to be called when the filter is applied.
90
+ * @param int $priority Optional. Priority order to run the multiple hooks appended to same $tag.
91
+ * As lower the number is, more priority it will have. Default 10.
92
+ * @param int $acceptedArgs Optional. The number of arguments the function accepts. Default 1.
93
+ */
94
+ public function addFilter($tag, $functionToAdd, $priority = 10, $acceptedArgs = 1)
95
+ {
96
+ // This is a crude filter, needs to create the CallbackHook manager for that
97
+ if (!isset($this->callbacks[$tag])) {
98
+ $this->callbacks[$tag] = new CallbackHook();
99
+ }
100
+ // Builds unique identifier for this callback call. This is important due to
101
+ // same method calls from different instances.
102
+ $idx = $this->getUniqueIndexID($tag, $functionToAdd);
103
+ $this->callbacks[$tag]->addFilter($idx, $tag, $functionToAdd, $priority, $acceptedArgs);
104
+ }
105
+
106
+ /**
107
+ * Call all the functions hooked to that filter name. If none are hooked the value will be returned back.
108
+ *
109
+ * A good strategy to use this function is to create hooking points into your code, by easily calling the
110
+ * applyFilters() method.
111
+ *
112
+ * Check this example:
113
+ * $observer = Observer::create();
114
+ * $url = $observer->applyFilters('GET_THE_URL', $a_url);
115
+ *
116
+ * You might not have initially a filter designed to this URL getter, but in
117
+ * the future you might have a URL redirect or even https enforcement, or anything
118
+ *
119
+ * When callback functions get attached to this 'GET_THE_URL' hook name, it will
120
+ * filter and can modify the final result.
121
+ *
122
+ * Full example:
123
+ *
124
+ * // The filter callback function
125
+ * function myCallback($value, $param1, $param2) {
126
+ * // do something with the value
127
+ * return $value;
128
+ * }
129
+ * $observer = Observer::create();
130
+ * $observer->addFilter('filter name', 'myCallback', 10, 3);
131
+ *
132
+ * /*
133
+ * * Apply the filters calling the 'myCallback' function we
134
+ * * "hooked" to $tag using the addFilter() method.
135
+ * * 'filter name' is the filter hook $tag
136
+ * * 'value to filter' is the value being filtered
137
+ * * $param1 and $param2 are the additional arguments passed to the callback.
138
+ * $value = $observer->applyFilters('filter name', 'value to filter', $param1, $param2);
139
+ *
140
+ * @param string $tag The name of the filter hook.
141
+ * @param mixed $value The value on which the filters hooked to `$tag` are applied on.
142
+ * @param mixed $var,... Additional variables passed to the functions hooked to `$tag`.
143
+ * @return mixed The filtered value after all hooked functions are applied to it.
144
+ */
145
+ public function applyFilters($tag, $value/*, $var...*/)
146
+ {
147
+ $args = array();
148
+
149
+ // In case no filters configured for this hook, simply return informed value.
150
+ if (!isset($this->callbacks[$tag])) {
151
+ return $value;
152
+ }
153
+
154
+ // Uses this to be compatible with PHP < 5.6
155
+ $args = func_get_args();
156
+
157
+ // Removes the $tag, since this is not an expected parameter to callbacks.
158
+ array_shift($args);
159
+
160
+ $filtered = $this->callbacks[$tag]->applyFilters($value, $args);
161
+
162
+ return $filtered;
163
+ }
164
+
165
+ /**
166
+ * Removes a function from a specified filter hook.
167
+ *
168
+ * This function removes a specific function attached to a filter hook.
169
+ * To remove a hook, the $functionToRemove and $priority arguments must match
170
+ * when the hook was added by calling #addFilter() method.
171
+ *
172
+ * @param string $tag The filter hook name where function + priority will be removed from
173
+ * @param callable $functionToRemove The function/instance->method will be removed.
174
+ * @param int $priority Optional. The priority of the function to be removed. Default 10.
175
+ * @return bool True if found function to remove from filter list, false otherwise.
176
+ */
177
+ public function removeFilter($tag, $functionToRemove, $priority = 10)
178
+ {
179
+ $return = false;
180
+ if (isset($this->callbacks[$tag])) {
181
+ $idx = $this->getUniqueIndexID($tag, $functionToRemove);
182
+ $return = $this->callbacks[$tag]->removeFilter($idx, $tag, $priority);
183
+ if (! $this->callbacks[$tag]->callbacks) {
184
+ unset($this->callbacks[$tag]);
185
+ }
186
+ }
187
+ return $return;
188
+ }
189
+
190
+ /**
191
+ * Remove all of the hooks from a filter.
192
+ *
193
+ * @param string $tag The filter to remove hooks from.
194
+ * @param int|bool $priority Optional. The priority number to remove. Default false.
195
+ */
196
+ public function removeAllFilters($tag, $priority = false)
197
+ {
198
+ if (isset($this->callbacks[$tag])) {
199
+ $this->callbacks[$tag]->removeAllFilters($priority);
200
+ if (!$this->callbacks[$tag]->hasFilters()) {
201
+ unset($this->callbacks[$tag]);
202
+ }
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Serialize and generates an index for storage and retrival of method/functions as callbacks.
208
+ *
209
+ * This index will be used mostly for instance method callback hooks. Since those cam imply into
210
+ * having conflicting names.
211
+ *
212
+ * <code>
213
+ * $bar1 = new Bar();
214
+ * $bar2 = new Bar();
215
+ *
216
+ * // Check that the callbacks are registered under same method name, same class,
217
+ * // same priority, but using different instances.
218
+ * $observer->addFilter('FILTER_NAME', array($bar1, 'foo'), 10);
219
+ * $observer->addFilter('FILTER_NAME', array($bar2, 'foo'), 10);
220
+ * </code>
221
+ *
222
+ * @param string $tag Used in counting how many hooks were applied
223
+ * @param callable $function Used for creating unique id
224
+ * @param int|bool $priority Used in counting how many hooks were applied. If === false
225
+ * and $function is an object reference, we return the unique id only if it already has one,
226
+ * false otherwise.
227
+ * @return string|false Unique ID for usage as array key or false if $priority === false
228
+ * and $function is an object reference, and it does not already have a unique id.
229
+ */
230
+ private function getUniqueIndexID($tag, $function)
231
+ {
232
+ if (is_string($function)) {
233
+ return $function;
234
+ }
235
+ if ($function instanceof \Closure) {
236
+ // If a Closure is used, it cannot be retrieved or removed
237
+ // individually later
238
+ return 'Closure' . self::$filterCount++;
239
+ }
240
+ if (is_object($function)) {
241
+ $function = array($function, '');
242
+ } else {
243
+ $function = (array) $function;
244
+ }
245
+
246
+ if (is_string($function[0])) {
247
+ // Static call
248
+ return $function[0] . '::' . $function[1];
249
+ } elseif (is_object($function[0])) {
250
+ // Instance call
251
+ if (function_exists('spl_object_hash')) {
252
+ return spl_object_hash($function[0]).'->' . $function[1];
253
+ } else {
254
+ $obj_idx = get_class($function[0]).'->'.$function[1];
255
+ if (!isset($function[0]->filterIdx)) {
256
+ $obj_idx = $obj_idx . self::$filterCount;
257
+ $function[0]->filterIdx = self::$filterCount;
258
+ self::$filterCount++;
259
+ } else {
260
+ $obj_idx = $obj_idx . $function[0]->filterIdx;
261
+ }
262
+ return $obj_idx;
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Check if any filter has been registered for a hook.
269
+ *
270
+ * @param string $tag The name of the filter.
271
+ * @param callable|bool $functionToCheck Optional. Callable that will be checked.
272
+ * @return false|int If $functionToCheck is omitted, returns boolean for whether the hook has
273
+ * anything registered. With a specific function, the priority of that
274
+ * hook is returned, false otherwise.
275
+ */
276
+ public function hasFilter($tag, $functionToCheck = false)
277
+ {
278
+ // If hook name has nothing, then nothing is hooked there.
279
+ if (!isset($this->callbacks[$tag])) {
280
+ return false;
281
+ }
282
+ $idx = $this->getUniqueIndexID($tag, $functionToCheck);
283
+ return $this->callbacks[$tag]->hasFilter($idx, $tag, $functionToCheck);
284
+ }
285
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/src/Facebook/InstantArticles/Utils/Warning.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ use Facebook\InstantArticles\Validators\Type;
12
+
13
+ class Warning
14
+ {
15
+ private $exception;
16
+ private $message;
17
+ private $context;
18
+
19
+ public function __construct($message, $context = null, $exception = null)
20
+ {
21
+ $this->message = $message;
22
+ $this->context = $context;
23
+ $this->exception = $exception;
24
+ }
25
+
26
+ public function __toString()
27
+ {
28
+ $finalMessage = $this->message;
29
+
30
+ if ($this->context !== null) {
31
+ $finalMessage = $finalMessage."\nObject in the context: ".Type::stringify($this->context);
32
+ }
33
+
34
+ if ($this->exception) {
35
+ $finalMessage = $finalMessage."\nException cause: ".Type::stringify($this->exception);
36
+ }
37
+
38
+ return $finalMessage;
39
+ }
40
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPArticleTest.php ADDED
@@ -0,0 +1,1092 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Elements\InstantArticle;
12
+ use Facebook\InstantArticles\Parser\Parser;
13
+ use Facebook\InstantArticles\Utils\FileUtilsPHPUnitTestCase;
14
+
15
+ class AMPArticleTest extends FileUtilsPHPUnitTestCase
16
+ {
17
+ public function testParseIA()
18
+ {
19
+ $html_file = $this->loadHTMLFile(__DIR__ . '/articles/test1-instant-article.html');
20
+ $document = $this->loadDOMDocument(__DIR__ . '/articles/test1-instant-article.html');
21
+
22
+ $parser = new Parser();
23
+ $instant_article = $parser->parse($document);
24
+ $instant_article->addMetaProperty('op:generator:version', '1.0.0');
25
+ $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
26
+ $result = $instant_article->render('', true)."\n";
27
+
28
+ $this->assertEquals($html_file, $result);
29
+ }
30
+
31
+ public function testTransformIAtoAMPTest1()
32
+ {
33
+ $customProperties = array_merge(
34
+ $this->getWodExpertCustomProperties(),
35
+ array(
36
+ 'media-sizes' => array(
37
+ 'http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg' => array(
38
+ 800,
39
+ 454,
40
+ ),
41
+ ),
42
+ )
43
+ );
44
+ $this->runIAtoAMPTest('test1', $customProperties);
45
+ }
46
+
47
+ public function testTransformIAtoAMPTest2()
48
+ {
49
+ $customProperties = $this->getWodExpertCustomProperties();
50
+ $this->runIAtoAMPTest('test2', $customProperties);
51
+ }
52
+
53
+ public function testTransformIAtoAMPTest3()
54
+ {
55
+ $customProperties = $this->getWodExpertCustomProperties();
56
+ $this->runIAtoAMPTest('test3', $customProperties);
57
+ }
58
+
59
+ public function testTransformIAtoAMPTest4()
60
+ {
61
+ $customProperties = $this->getWodExpertCustomProperties();
62
+ $this->runIAtoAMPTest('test4', $customProperties);
63
+ }
64
+
65
+ public function testTransformIAtoAMPTest5()
66
+ {
67
+ $customProperties = $this->getWodExpertCustomProperties();
68
+ $this->runIAtoAMPTest('test5', $customProperties);
69
+ }
70
+
71
+ private function getWodExpertCustomProperties()
72
+ {
73
+ return array(
74
+ AMPArticle::PUBLISHER_KEY => array(
75
+ '@type' => 'Organization',
76
+ 'name' => 'WOD Expert',
77
+ 'logo' => array(
78
+ '@type' => 'ImageObject',
79
+ 'url' => 'http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png',
80
+ 'width' => 600,
81
+ 'height' => 60,
82
+ ),
83
+ )
84
+ );
85
+ }
86
+
87
+ public function testTransformIAtoAMPTestTutorial()
88
+ {
89
+ $this->runIAtoAMPTest('tutorial', array('google_maps_key'=>'123'));
90
+ }
91
+
92
+ private function getRenderer($test, $customProperties = null)
93
+ {
94
+ $instantArticle = $this->loadInstantArticle(__DIR__ . '/articles/'.$test.'-instant-article.html');
95
+
96
+ $properties = array(
97
+ 'lang' => 'en-US',
98
+ AMPArticle::STYLES_FOLDER_KEY => __DIR__,
99
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
100
+ );
101
+ if (!is_null($customProperties)) {
102
+ $properties = array_merge($properties, $customProperties);
103
+ }
104
+
105
+ return AMPArticle::create($instantArticle, $properties);
106
+ }
107
+
108
+ private function getRenderedAMP($test, $customProperties = null)
109
+ {
110
+ $renderer = $this->getRenderer($test, $customProperties);
111
+
112
+ return $renderer->render(null, true)."\n";
113
+ }
114
+
115
+ private function getMarkupWithoutStyles($markup)
116
+ {
117
+ libxml_use_internal_errors(true);
118
+ $markupDocument = new \DOMDocument();
119
+ $markupDocument->loadHTML($markup);
120
+ libxml_use_internal_errors(false);
121
+
122
+ $xPath = new \DOMXPath($markupDocument);
123
+ if ($customStyle = $xPath->query('//style[@amp-custom]')->item(0)) {
124
+ $customStyle->parentNode->removeChild($customStyle);
125
+ }
126
+ return $markupDocument->saveHTML();
127
+ }
128
+
129
+ private function compareIgnoringStyles($ampExpected, $ampRendered)
130
+ {
131
+ $ampExpectedNoStyles = $this->getMarkupWithoutStyles($ampExpected);
132
+ $ampRenderedNoStyles = $this->getMarkupWithoutStyles($ampRendered);
133
+
134
+ $this->assertEquals($ampExpectedNoStyles, $ampRenderedNoStyles);
135
+ }
136
+
137
+ public function runIAtoAMPTest($test, $customProperties = null)
138
+ {
139
+ $ampRendered = $this->getRenderedAMP($test, $customProperties);
140
+
141
+ $ampExpected = $this->loadHTMLFile(__DIR__.'/articles/'.$test.'-amp-converted.html');
142
+ $this->compareIgnoringStyles($ampExpected, $ampRendered);
143
+
144
+ // Sets content into the file for double checking testing
145
+ // file_put_contents(__DIR__.'/articles/'.$test.'-amp-converted.html', $ampRendered);
146
+ }
147
+
148
+ private function getRenderedMarkupXPathQuery($test, $xPathExpression, $customProperties = null)
149
+ {
150
+ $amp_rendered = $this->getRenderedAMP($test, $customProperties);
151
+
152
+ $renderedDocument = $this->loadDOMDocumentFromString($amp_rendered);
153
+ $xPath = new \DOMXPath($renderedDocument);
154
+
155
+ return $xPath->query($xPathExpression);
156
+ }
157
+
158
+ public function testArticleHasSingleLdJsonScript()
159
+ {
160
+ $xPathQuery = $this->getRenderedMarkupXPathQuery('test1', '//script[@type="application/ld+json"]');
161
+ $this->assertEquals(1, $xPathQuery->length);
162
+ }
163
+
164
+ private function getDiscoveryMetadata($test, $customProperties = null)
165
+ {
166
+ $renderer = $this->getRenderer($test, $customProperties);
167
+ $context = AMPContext::create(new \DOMDocument(), $renderer->getInstantArticle(), 'ia2amp-');
168
+
169
+ $discoveryMetadataContent = $renderer->buildSchemaOrgMetadata($context);
170
+ return json_decode($discoveryMetadataContent, true);
171
+ }
172
+
173
+ private function verifySchemaOrgHasExpectedValue($key, $expectedValue, $test = 'test1', $customProperties = null)
174
+ {
175
+ $discoveryMetadata = $this->getDiscoveryMetadata($test, $customProperties);
176
+
177
+ $this->assertArrayHasKey($key, $discoveryMetadata, "Could not find $key key in Schema.org metadata");
178
+ $this->assertEquals($expectedValue, $discoveryMetadata[$key], "Unexpected value found for $key");
179
+ }
180
+
181
+ private function verifySchemaOrgDoesNotHaveKey($key, $test = 'test1')
182
+ {
183
+ $discoveryMetadata = $this->getDiscoveryMetadata($test);
184
+
185
+ $this->assertFalse(array_key_exists($key, $discoveryMetadata), "Found unexpected '$key' key in Schema.org metadata");
186
+ }
187
+
188
+ public function testSchemaOrgContext()
189
+ {
190
+ $this->verifySchemaOrgHasExpectedValue('@context', 'http://schema.org');
191
+ }
192
+
193
+ public function testSchemaOrgType()
194
+ {
195
+ $this->verifySchemaOrgHasExpectedValue('@type', 'NewsArticle');
196
+ }
197
+
198
+ public function testSchemaOrgMainEntityOfPage()
199
+ {
200
+ $this->verifySchemaOrgHasExpectedValue('mainEntityOfPage', 'http://blog.wod.expert/very-first-wod/');
201
+ }
202
+
203
+ public function testSchemaOrgHeadline()
204
+ {
205
+ $this->verifySchemaOrgHasExpectedValue('headline', 'Very First WOD!');
206
+ }
207
+
208
+ public function testSchemaOrgDatePublished()
209
+ {
210
+ $this->verifySchemaOrgHasExpectedValue('datePublished', '2016-05-10T18:05:36+00:00');
211
+ }
212
+
213
+ public function testSchemaOrgDateModified()
214
+ {
215
+ $this->verifySchemaOrgHasExpectedValue('dateModified', '2017-03-17T16:46:07+00:00');
216
+ }
217
+
218
+ public function testSchemaOrgHasDateModified()
219
+ {
220
+ $key = 'dateModified';
221
+ $discoveryMetadata = $this->getDiscoveryMetadata('tutorial');
222
+ $this->assertTrue(array_key_exists($key, $discoveryMetadata), "Did not found expected '$key' key in Schema.org metadata");
223
+ }
224
+
225
+ public function testSchemaOrgAuthor()
226
+ {
227
+ $expectedAuthor = array(
228
+ '@type' => 'Person',
229
+ 'name' => 'Éverton Rosário',
230
+ );
231
+
232
+ $this->verifySchemaOrgHasExpectedValue('author', $expectedAuthor);
233
+ }
234
+
235
+ public function testSchemaOrgImageNoCache()
236
+ {
237
+ $expectedImage = array(
238
+ '@type' => 'ImageObject',
239
+ 'url' => 'http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg',
240
+ 'width' => 380,
241
+ 'height' => 240,
242
+ );
243
+
244
+ $this->verifySchemaOrgHasExpectedValue('image', $expectedImage);
245
+ }
246
+
247
+ public function testSchemaOrgImageWithCache()
248
+ {
249
+ $expectedImage = array(
250
+ '@type' => 'ImageObject',
251
+ 'url' => 'http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg',
252
+ 'width' => 400,
253
+ 'height' => 227,
254
+ );
255
+ $customProperties = array(
256
+ AMPArticle::MEDIA_CACHE_FOLDER_KEY => __DIR__ . '/articles/media-cache',
257
+ );
258
+
259
+ $this->verifySchemaOrgHasExpectedValue('image', $expectedImage, 'test1', $customProperties);
260
+ }
261
+
262
+ public function testSchemaOrgDescription()
263
+ {
264
+ $this->verifySchemaOrgHasExpectedValue('description', 'The first WOD we never forget! Just to be sure we are talking about same thing, WOD stands for “Workout of the Day”.  You feel you’re already gone on the warm up session.');
265
+ }
266
+
267
+ public function testSchemaOrgPublisherName()
268
+ {
269
+ $publisherName = 'The Publisher';
270
+ $customProperties = array(AMPArticle::PUBLISHER_KEY => $publisherName);
271
+
272
+ $expectedPublisher = array(
273
+ '@type' => 'Organization',
274
+ 'name' => $publisherName,
275
+ );
276
+
277
+ $this->verifySchemaOrgHasExpectedValue('publisher', $expectedPublisher, 'test1', $customProperties);
278
+ }
279
+
280
+ public function testSchemaOrgPublisherArray()
281
+ {
282
+ $publisher = array(
283
+ '@type' => 'Robot',
284
+ 'name' => 'The Robot',
285
+ );
286
+ $customProperties = array(AMPArticle::PUBLISHER_KEY => $publisher);
287
+
288
+ $this->verifySchemaOrgHasExpectedValue('publisher', $publisher, 'test1', $customProperties);
289
+ }
290
+
291
+ public function testSchemaOrgNoPublisher()
292
+ {
293
+ $this->verifySchemaOrgDoesNotHaveKey('publisher');
294
+ }
295
+
296
+ private function getRenderedLogoElement($test = 'test1')
297
+ {
298
+ $xPathQuery = $this->getRenderedMarkupXPathQuery(
299
+ $test,
300
+ '//div[@class=\'ia2amp-header-bar-img-container\']/amp-img'
301
+ );
302
+
303
+ return $xPathQuery->item(0);
304
+ }
305
+
306
+ public function testLogoURL()
307
+ {
308
+ $logoElement = $this->getRenderedLogoElement();
309
+ $this->assertNotNull($logoElement);
310
+ $src = $logoElement->getAttribute('src');
311
+
312
+ $this->assertEquals(
313
+ 'https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&oh=c8337650a88e7fdb6d31088a15a7d9d8&oe=599B24B5&__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8',
314
+ $src
315
+ );
316
+ }
317
+
318
+ public function testLogoWidth()
319
+ {
320
+ $logoElement = $this->getRenderedLogoElement();
321
+ $this->assertNotNull($logoElement);
322
+ $width = $logoElement->getAttribute('width');
323
+
324
+ $this->assertEquals(223, $width);
325
+ }
326
+
327
+ public function testLogoHeight()
328
+ {
329
+ $logoElement = $this->getRenderedLogoElement();
330
+ $this->assertNotNull($logoElement);
331
+ $height = $logoElement->getAttribute('height');
332
+
333
+ $this->assertEquals(44, $height);
334
+ }
335
+
336
+ public function testCachedImageHeight()
337
+ {
338
+ $expectedHeight = 181;
339
+ $customProperties = array(
340
+ AMPArticle::MEDIA_CACHE_FOLDER_KEY => __DIR__ . '/articles/media-cache',
341
+ );
342
+
343
+ $coverImageXPathQuery = $this->getRenderedMarkupXPathQuery(
344
+ 'test2',
345
+ '//article//amp-img',
346
+ $customProperties
347
+ );
348
+ $coverImageElement = $coverImageXPathQuery->item(0);
349
+
350
+ $this->assertEquals($expectedHeight, $coverImageElement->getAttribute('height'));
351
+ }
352
+
353
+ public function testImageHeightDownloadDisabled()
354
+ {
355
+ $expectedHeight = 240;
356
+ $customProperties = array(
357
+ AMPArticle::MEDIA_CACHE_FOLDER_KEY => __DIR__ . '/articles/media-cache',
358
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
359
+ );
360
+
361
+ $imageXPathQuery = $this->getRenderedMarkupXPathQuery(
362
+ 'test1',
363
+ '//div[@class=\'ia2amp-slideshow-image\']//amp-img',
364
+ $customProperties
365
+ );
366
+ $firstArticleImageElement = $imageXPathQuery->item(0);
367
+
368
+ $this->assertEquals($expectedHeight, $firstArticleImageElement->getAttribute('height'));
369
+ }
370
+
371
+ public function testImageHeightDefaultProperty()
372
+ {
373
+ $expectedHeight = 120;
374
+ $customProperties = array(
375
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
376
+ AMPArticle::DEFAULT_MEDIA_HEIGHT_KEY => $expectedHeight,
377
+ );
378
+
379
+ $imageXPathQuery = $this->getRenderedMarkupXPathQuery(
380
+ 'test1',
381
+ '//div[@class=\'ia2amp-slideshow-image\']//amp-img',
382
+ $customProperties
383
+ );
384
+ $firstArticleImageElement = $imageXPathQuery->item(0);
385
+
386
+ $this->assertEquals($expectedHeight, $firstArticleImageElement->getAttribute('height'));
387
+ }
388
+
389
+ public function testImageHeightFromMediaSizes()
390
+ {
391
+ $expectedHeight = 253;
392
+ $customProperties = array(
393
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
394
+ AMPArticle::MEDIA_SIZES_KEY => array(
395
+ "http://blog.wod.expert/wp-content/uploads/2017/03/fail2.jpg" => array(90, 60),
396
+ ),
397
+ );
398
+
399
+ $imageXPathQuery = $this->getRenderedMarkupXPathQuery(
400
+ 'test1',
401
+ '//div[@class=\'ia2amp-slideshow-image\']//amp-img',
402
+ $customProperties
403
+ );
404
+ $firstArticleImageElement = $imageXPathQuery->item(0);
405
+
406
+ $this->assertEquals($expectedHeight, $firstArticleImageElement->getAttribute('height'));
407
+ }
408
+
409
+ public function testVideoHeightDefaultProperty()
410
+ {
411
+ $expectedHeight = 120;
412
+ $customProperties = array(
413
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
414
+ AMPArticle::DEFAULT_MEDIA_HEIGHT_KEY => $expectedHeight,
415
+ );
416
+
417
+ $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
418
+ 'tutorial',
419
+ '//amp-video',
420
+ $customProperties
421
+ );
422
+ $firstArticleVideoElement = $videoXPathQuery->item(0);
423
+
424
+ $this->assertEquals($expectedHeight, $firstArticleVideoElement->getAttribute('height'));
425
+ }
426
+
427
+ public function testVideoWidthFromMediaSizes()
428
+ {
429
+ $expectedWidth = 380;
430
+ $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
431
+ 'tutorial',
432
+ '//amp-video',
433
+ null
434
+ );
435
+ $firstArticleVideoElement = $videoXPathQuery->item(0);
436
+
437
+ $this->assertEquals($expectedWidth, $firstArticleVideoElement->getAttribute('width'));
438
+ }
439
+
440
+ public function testVideoHeightFromMediaSizes()
441
+ {
442
+ $expectedHeight = 240;
443
+ $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
444
+ 'tutorial',
445
+ '//amp-video',
446
+ null
447
+ );
448
+ $firstArticleVideoElement = $videoXPathQuery->item(0);
449
+
450
+ $this->assertEquals($expectedHeight, $firstArticleVideoElement->getAttribute('height'));
451
+ }
452
+
453
+ public function testFooterCredits()
454
+ {
455
+ $creditsXPathQuery = $this->getRenderedMarkupXPathQuery(
456
+ 'test1',
457
+ '//article/footer/aside'
458
+ );
459
+
460
+ $creditsElement = $creditsXPathQuery->item(0);
461
+
462
+ $this->assertEquals('WOD Expert', trim($creditsElement->textContent));
463
+ }
464
+
465
+ public function testFooterCopyright()
466
+ {
467
+ $copyrightXPathQuery = $this->getRenderedMarkupXPathQuery(
468
+ 'test1',
469
+ '//article/footer/small'
470
+ );
471
+
472
+ $copyrightElement = $copyrightXPathQuery->item(0);
473
+
474
+ $this->assertEquals('© 2017 WOD Expert', trim($copyrightElement->textContent));
475
+ }
476
+
477
+ public function testCoverImageWidth()
478
+ {
479
+ $expectedWidth = 422;
480
+ $coverImageXPathQuery = $this->getRenderedMarkupXPathQuery(
481
+ 'test1',
482
+ '//amp-img[@class=\'ia2amp-header-cover-img\']',
483
+ array(
484
+ 'media-sizes' => array(
485
+ 'http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg' => array(
486
+ 800,
487
+ 454,
488
+ ),
489
+ ),
490
+ )
491
+ );
492
+
493
+ $coverImageElement = $coverImageXPathQuery->item(0);
494
+
495
+ $this->assertEquals($expectedWidth, $coverImageElement->getAttribute('width'));
496
+ }
497
+
498
+ public function testCoverImageHeight()
499
+ {
500
+ $expectedHeight = 240;
501
+ $coverImageXPathQuery = $this->getRenderedMarkupXPathQuery(
502
+ 'test1',
503
+ '//amp-img[@class=\'ia2amp-header-cover-img\']',
504
+ array(
505
+ 'media-sizes' => array(
506
+ 'http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg' => array(
507
+ 800,
508
+ 454,
509
+ ),
510
+ ),
511
+ )
512
+ );
513
+
514
+ $coverImageElement = $coverImageXPathQuery->item(0);
515
+
516
+ $this->assertEquals($expectedHeight, $coverImageElement->getAttribute('height'));
517
+ }
518
+
519
+ /**
520
+ * @dataProvider testToRGBDataProvider
521
+ */
522
+ public function testToRG($hexColor, $expected)
523
+ {
524
+ $rgb = AMPArticle::toRGB($hexColor);
525
+ $this->assertEquals($expected, $rgb);
526
+ }
527
+
528
+ public function testToRGBDataProvider()
529
+ {
530
+ return array(
531
+ array('FFAABB', 'rgb(255,170,187)'),
532
+ array('#FFAABB', 'rgb(255,170,187)'),
533
+ array('#FFFFAABB', 'rgb(255,170,187)'),
534
+ array('EEFFAABB', 'rgba(255,170,187,0.93)'),
535
+ array('#EEFFAABB', 'rgba(255,170,187,0.93)'),
536
+ array('#00FFFFFF', 'rgba(255,255,255,0)'),
537
+ );
538
+ }
539
+
540
+ private function getDefaultStyles()
541
+ {
542
+ $jsonStyles = file_get_contents(__DIR__ . '/default.style.json');
543
+ return json_decode($jsonStyles, true);
544
+ }
545
+
546
+ public function testBackgroundColorStyle()
547
+ {
548
+ $hexColor = AMPArticleTest::getRandomHexColor();
549
+
550
+ $defaultStyles = $this->getDefaultStyles();
551
+ $defaultStyles['background_color'] = $hexColor;
552
+
553
+ $customProperties = array(
554
+ AMPArticle::OVERRIDE_STYLES_KEY => $defaultStyles,
555
+ );
556
+
557
+ $renderer = $this->getRenderer('test1', $customProperties);
558
+ $context = AMPContext::create(new \DOMDocument(), $renderer->getInstantArticle(), 'ia2amp-');
559
+ $css = $renderer->getCustomCSS($context);
560
+
561
+ // Escape parenthesis before using regex
562
+ $expectedValue = str_replace(')', '\)', str_replace('(', '\(', AMPArticle::toRGB($hexColor)));
563
+ $this->validateCSSRule($css, 'html', 'background-color', $expectedValue);
564
+ }
565
+
566
+ public function textStylesDataProvider()
567
+ {
568
+ return array_merge(
569
+ // Head
570
+ $this->getTextStylesTestData('kicker', '.ia2amp-header-category'),
571
+ $this->getTextStylesTestData('title', '.ia2amp-header-h1'),
572
+ $this->getTextStylesTestData('subtitle', '.ia2amp-header-h2'),
573
+ $this->getTextStylesTestData('byline', '.ia2amp-header h3'),
574
+ // Body
575
+ $this->getTextStylesTestData('primary_heading', '.ia2amp-h1'),
576
+ $this->getTextStylesTestData('secondary_heading', '.ia2amp-h2'),
577
+ $this->getTextStylesTestData('body_text', '.ia2amp-p'),
578
+ $this->getTextStylesTestData('inline_link', '.ia2amp-article a'),
579
+ // Quotes
580
+ $this->getTextStylesTestData('block_quote', '.ia2amp-blockquote'),
581
+ $this->getTextStylesTestData('pull_quote', '.ia2amp-pullquote'),
582
+ $this->getTextStylesTestData('pull_quote_attribution', '.ia2amp-pullquote cite'),
583
+ // Captions
584
+ $this->getTextStylesTestData('caption_title_small', '.ia2amp-op-small h1'),
585
+ $this->getTextStylesTestData('caption_description_small', '.ia2amp-op-small h2'),
586
+ $this->getTextStylesTestData('caption_title', '.ia2amp-op-medium h1'),
587
+ $this->getTextStylesTestData('caption_description', '.ia2amp-op-medium h2'),
588
+ $this->getTextStylesTestData('caption_title_large', '.ia2amp-op-large h1'),
589
+ $this->getTextStylesTestData('caption_description_large', '.ia2amp-op-large h2'),
590
+ $this->getTextStylesTestData('caption_title_extra_large', '.ia2amp-op-extra-large h1'),
591
+ $this->getTextStylesTestData('caption_description_extra_large', '.ia2amp-op-extra-large h2'),
592
+ $this->getTextStylesTestData('caption_credit', '.ia2amp-figcaption cite'),
593
+ // Footer
594
+ $this->getTextStylesTestData('footer', '.ia2amp-footer')
595
+ );
596
+ }
597
+
598
+ /**
599
+ * @dataProvider textStylesDataProvider
600
+ */
601
+ public function testTextStyles($styleName, $secondLevelProperty, $cssSelector, $cssProperty, $styleValue, $expectedCSSValue)
602
+ {
603
+ $this->validateSecondLevelProperty($styleName, $secondLevelProperty, $cssSelector, $cssProperty, $styleValue, $expectedCSSValue);
604
+ }
605
+
606
+ /**
607
+ * @dataProvider testTextStylesDataProvider
608
+ */
609
+ private function getTextStylesTestData($styleName, $cssSelector)
610
+ {
611
+ $testData = array();
612
+
613
+ // Font Family
614
+ $testData = array_merge(
615
+ $testData,
616
+ $this->getSecondLevelPropertyTestData(
617
+ 'randomDataProvider',
618
+ 'passThroughValuesProvider',
619
+ $styleName,
620
+ 'font',
621
+ $cssSelector,
622
+ 'font-family'
623
+ )
624
+ );
625
+
626
+ // Color
627
+ $testData = array_merge(
628
+ $testData,
629
+ $this->getSecondLevelPropertyTestData(
630
+ 'colorDataProvider',
631
+ 'passThroughValuesProvider',
632
+ $styleName,
633
+ 'color',
634
+ $cssSelector,
635
+ 'color'
636
+ )
637
+ );
638
+
639
+ // Background Color
640
+ $testData = array_merge(
641
+ $testData,
642
+ $this->getSecondLevelPropertyTestData(
643
+ 'colorDataProvider',
644
+ 'passThroughValuesProvider',
645
+ $styleName,
646
+ 'background_color',
647
+ $cssSelector,
648
+ 'background-color'
649
+ )
650
+ );
651
+
652
+ // Text Transform
653
+ $testData = array_merge(
654
+ $testData,
655
+ $this->getSecondLevelPropertyTestData(
656
+ 'textTransformDataProvider',
657
+ 'passThroughValuesProvider',
658
+ $styleName,
659
+ 'capitalization',
660
+ $cssSelector,
661
+ 'text-transform'
662
+ )
663
+ );
664
+
665
+ // Text Alignment
666
+ $testData = array_merge(
667
+ $testData,
668
+ $this->getSecondLevelPropertyTestData(
669
+ 'textAlignmentDataProvider',
670
+ 'passThroughValuesProvider',
671
+ $styleName,
672
+ 'text_alignment',
673
+ $cssSelector,
674
+ 'text-align'
675
+ )
676
+ );
677
+
678
+ // Display
679
+ $testData = array_merge(
680
+ $testData,
681
+ $this->getSecondLevelPropertyTestData(
682
+ 'displayDataProvider',
683
+ 'passThroughValuesProvider',
684
+ $styleName,
685
+ 'display',
686
+ $cssSelector,
687
+ 'display'
688
+ )
689
+ );
690
+
691
+ // Margin
692
+ $testData = array_merge(
693
+ $testData,
694
+ $this->getSecondLevelPropertyTestData(
695
+ 'marginDataProvider',
696
+ 'spacingValuesProvider',
697
+ $styleName,
698
+ 'margin',
699
+ $cssSelector,
700
+ 'margin'
701
+ )
702
+ );
703
+
704
+ // Padding
705
+ $testData = array_merge(
706
+ $testData,
707
+ $this->getSecondLevelPropertyTestData(
708
+ 'paddingDataProvider',
709
+ 'spacingValuesProvider',
710
+ $styleName,
711
+ 'padding',
712
+ $cssSelector,
713
+ 'padding'
714
+ )
715
+ );
716
+
717
+ // Border Width
718
+ $testData = array_merge(
719
+ $testData,
720
+ $this->getSecondLevelPropertyTestData(
721
+ 'borderWidthDataProvider',
722
+ 'borderWidthValuesProvider',
723
+ $styleName,
724
+ 'border',
725
+ $cssSelector,
726
+ 'border-width'
727
+ )
728
+ );
729
+
730
+ return $testData;
731
+ }
732
+
733
+ /**
734
+ * Builds the arguments that will be pased to function validateSecondLevelProperty
735
+ *
736
+ * @param string $dataProviderFunctionName The name of the parameterless function that serves as Data Provider
737
+ * @param string $validationArgumentsProviderFunctionName The name of the function that receives the Data Provider rows and converts them to pairs of style
738
+ * @param string $styleName The style name that will be used for validateSecondLevelProperty
739
+ * @param object $secondLevelProperty The name of the property that will be transformed in the styles for the unit test
740
+ * @param string $cssSelector The CSS selector that will be used to verify the unit test result
741
+ * @param string $cssProperty The CSS property that will be used to verify the unit test result
742
+ * @return array An array with the style value that will be set, and the expected CSS value that will be generated
743
+ */
744
+ private function getSecondLevelPropertyTestData(
745
+ $dataProviderFunctionName,
746
+ $validationArgumentsProviderFunctionName,
747
+ $styleName,
748
+ $secondLevelProperty,
749
+ $cssSelector,
750
+ $cssProperty
751
+ ) {
752
+
753
+ $testData = array();
754
+
755
+ // Get all test cases for the given Data Provider function
756
+ $dataProviderTestData = call_user_func_array(array($this, $dataProviderFunctionName), array());
757
+
758
+ foreach ($dataProviderTestData as $dataProviderTestItem) {
759
+ // Call the Validation Arguments Provider function using the values from the Data Provider
760
+ $styleAndCssValues = call_user_func_array(array($this, $validationArgumentsProviderFunctionName), $dataProviderTestItem);
761
+ // Merge the known values with the mappings of style value to expected CSS value
762
+ $testDataItem = array_merge(
763
+ array(
764
+ $styleName,
765
+ $secondLevelProperty,
766
+ $cssSelector,
767
+ $cssProperty,
768
+ ),
769
+ $styleAndCssValues
770
+ );
771
+ // Add the merged values to the list of test items
772
+ $testData[] = $testDataItem;
773
+ }
774
+
775
+ return $testData;
776
+ }
777
+
778
+ /**
779
+ * Takes an Instant Article style property name and an expected value and returns both in an array
780
+ *
781
+ * @param string $stylePropertyName
782
+ * @param string $expectedCSSValue
783
+ * @return array
784
+ */
785
+ private function passThroughValuesProvider($stylePropertyName, $expectedCSSValue)
786
+ {
787
+ return array($stylePropertyName, $expectedCSSValue);
788
+ }
789
+
790
+ /**
791
+ * Generates random values for function passThroughValuesProvider
792
+ *
793
+ * @return array
794
+ */
795
+ private function randomDataProvider()
796
+ {
797
+ $randomValue = rand();
798
+ return array(
799
+ array($randomValue, $randomValue),
800
+ );
801
+ }
802
+
803
+ /**
804
+ * Generates color values for function passThroughValuesProvider
805
+ *
806
+ * @return array
807
+ */
808
+ private function colorDataProvider()
809
+ {
810
+ $hexColor = AMPArticleTest::getRandomHexColor();
811
+ // Escape parenthesis before using regex
812
+ $expectedValue = str_replace(')', '\)', str_replace('(', '\(', AMPArticle::toRGB($hexColor)));
813
+ return array(
814
+ array($hexColor, $expectedValue),
815
+ );
816
+ }
817
+
818
+ /**
819
+ * Generates text transform values for function passThroughValuesProvider
820
+ *
821
+ * @return array
822
+ */
823
+ private function textTransformDataProvider()
824
+ {
825
+ return array(
826
+ array('ALL_CAPS', 'uppercase'),
827
+ array('NONE', 'none'),
828
+ array('ALL_LOWER_CASE', 'lowercase'),
829
+ );
830
+ }
831
+
832
+ /**
833
+ * Generates text alignment values for function passThroughValuesProvider
834
+ *
835
+ * @return array
836
+ */
837
+ public function textAlignmentDataProvider()
838
+ {
839
+ return array(
840
+ array('LEFT', 'LEFT'),
841
+ array('CENTER', 'CENTER'),
842
+ array('RIGHT', 'RIGHT'),
843
+ );
844
+ }
845
+
846
+ /**
847
+ * Generates display values for function passThroughValuesProvider
848
+ *
849
+ * @return array
850
+ */
851
+ public function displayDataProvider()
852
+ {
853
+ return array(
854
+ array('INLINE', 'INLINE'),
855
+ array('BLOCK', 'BLOCK'),
856
+ );
857
+ }
858
+
859
+ /**
860
+ * Generates spacing (margin or padding) Instant Article style values and expected CSS values
861
+ *
862
+ * @param int $size The Instant Article style size value
863
+ * @param int $baseSpacingValue The value that will be multiplied by the scaling factor
864
+ * @param string $direction A valid direction for a border style e.g. 'top'
865
+ * @param string $spacingFormat The expected spacing format e.g. '0 0 0 %spx'
866
+ * @return array
867
+ */
868
+ public function spacingValuesProvider($size, $baseSpacingValue, $direction, $spacingFormat)
869
+ {
870
+ $scalingFactor = rand(0, 1000) / 1000 + 0.5;
871
+ $directionSpacing = array(
872
+ 'scaling_factor' => $scalingFactor,
873
+ 'size' => $size,
874
+ );
875
+ $spacingStyle = array(
876
+ $direction => $directionSpacing,
877
+ );
878
+
879
+ $expectedSpacing = $baseSpacingValue * $scalingFactor;
880
+ $expectedValue = sprintf($spacingFormat, $expectedSpacing);
881
+
882
+ return array($spacingStyle, $expectedValue);
883
+ }
884
+
885
+ /**
886
+ * Generates margin values for function spacingValuesProvider
887
+ *
888
+ * @return array
889
+ */
890
+ private function marginDataProvider()
891
+ {
892
+ return array(
893
+ // size, baseSpacingValue, direction, spacingFormat
894
+ array('DOCUMENT_MARGIN', AMPArticle::DEFAULT_MARGIN, 'right', '0 %spx 0 0'),
895
+ array('DOCUMENT_MARGIN', AMPArticle::DEFAULT_MARGIN, 'left', '0 0 0 %spx'),
896
+
897
+ array('NONE', 0, 'right', '0 0 0 0'),
898
+ array('NONE', 0, 'left', '0 0 0 0'),
899
+ );
900
+ }
901
+
902
+ /**
903
+ * Generates padding values for function spacingValuesProvider
904
+ *
905
+ * @return array
906
+ */
907
+ private function paddingDataProvider()
908
+ {
909
+ return array(
910
+ // size, baseSpacingValue, direction, spacingFormat
911
+ array('NONE', 0, 'top', '0 0 0 0'),
912
+ array('NONE', 0, 'right', '0 0 0 0'),
913
+ array('NONE', 0, 'bottom', '0 0 0 0'),
914
+ array('NONE', 0, 'left', '0 0 0 0'),
915
+
916
+ array('MEDIUM', 46, 'top', '%spx 0 0 0'),
917
+ array('MEDIUM', 46, 'right', '0 %spx 0 0'),
918
+ array('MEDIUM', 46, 'bottom', '0 0 %spx 0'),
919
+ array('MEDIUM', 46, 'left', '0 0 0 %spx'),
920
+ );
921
+ }
922
+
923
+ /**
924
+ * Generates Border Color Instant Article style values and expected CSS values
925
+ *
926
+ * @param string $direction A valid direction for a border style e.g. 'top'
927
+ * @return array
928
+ */
929
+ public function borderColorValuesProvider($direction)
930
+ {
931
+ $width = rand(0, 100);
932
+ $hexColor = AMPArticleTest::getRandomHexColor();
933
+ $directionBorder = array(
934
+ 'color' => $hexColor,
935
+ 'width' => $width,
936
+ );
937
+ $borderStyle = array(
938
+ $direction => $directionBorder,
939
+ );
940
+
941
+ // Escape parenthesis before using regex
942
+ $expectedValue = str_replace(')', '\)', str_replace('(', '\(', AMPArticle::toRGB($hexColor)));
943
+
944
+ return array($borderStyle, $expectedValue);
945
+ }
946
+
947
+ /**
948
+ * Generates values for function borderColorValuesProvider
949
+ *
950
+ * @return array
951
+ */
952
+ private function directionsDataProvider()
953
+ {
954
+ return array(
955
+ array('top'),
956
+ array('right'),
957
+ array('bottom'),
958
+ array('left'),
959
+ );
960
+ }
961
+
962
+ /**
963
+ * Generates Border Width Instant Article style values and expected CSS values
964
+ *
965
+ * @param string $direction A valid direction for a border style e.g. 'top'
966
+ * @param string $borderFormat The expected format of the border width for the given direction e.g. '%s 0 0 0'
967
+ * @return array
968
+ */
969
+ public function borderWidthValuesProvider($direction, $borderFormat)
970
+ {
971
+ $width = rand(0, 100);
972
+ $directionBorder = array(
973
+ 'color' => '#000000',
974
+ 'width' => $width,
975
+ );
976
+ $borderStyle = array(
977
+ $direction => $directionBorder,
978
+ );
979
+
980
+ $expectedValue = sprintf($borderFormat, $width !== 0 ? $width . 'px' : 0);
981
+ return array($borderStyle, $expectedValue);
982
+ }
983
+
984
+ /**
985
+ * Generates arguments for function borderWidthValuesProvider
986
+ *
987
+ * @return array
988
+ */
989
+ private function borderWidthDataProvider()
990
+ {
991
+ return array(
992
+ array('top', '%s 0 0 0'),
993
+ array('right', '0 %s 0 0'),
994
+ array('bottom', '0 0 %s 0'),
995
+ array('left', '0 0 0 %s'),
996
+ );
997
+ }
998
+
999
+ /**
1000
+ * Validates the transformation of Instant Article Styles to CSS by updating a second level JSON property and looking for an expected CSS value
1001
+ *
1002
+ * @param string $firstLevelKey The name of the Instant Article styles object that is the parent of the property that will be tested
1003
+ * @param string $secondLevelKey The name of the Instant Article styles object that will be tested
1004
+ * @param string $cssSelector The CSS selector that will be used to verify the genarted CSS
1005
+ * @param string $cssProperty The name of CSS property that will be used to test the transformation
1006
+ * @param string $styleValue The style value that will be assigned to test the generation of an expected CSS value
1007
+ * @param object $expectedCSSValue The value of CSS property that will be used to test the transformation
1008
+ * @return void
1009
+ */
1010
+ private function validateSecondLevelProperty($firstLevelKey, $secondLevelKey, $cssSelector, $cssProperty, $styleValue, $expectedCSSValue)
1011
+ {
1012
+ // Load the default values
1013
+ $testStyles = $this->getDefaultStyles();
1014
+ // Set the style property value that will be used to generate the expected CSS
1015
+ $testStyles[$firstLevelKey][$secondLevelKey] = $styleValue;
1016
+
1017
+ $customProperties = array(
1018
+ // Use the updated styles instead of the ones defined in the Instant Article document
1019
+ AMPArticle::OVERRIDE_STYLES_KEY => $testStyles,
1020
+ );
1021
+
1022
+ $renderer = $this->getRenderer('test1', $customProperties);
1023
+ $context = AMPContext::create(new \DOMDocument(), $renderer->getInstantArticle(), 'ia2amp-');
1024
+ $css = $renderer->getCustomCSS($context);
1025
+
1026
+ // Look for the expected CSS
1027
+ $this->validateCSSRule($css, $cssSelector, $cssProperty, $expectedCSSValue);
1028
+ }
1029
+
1030
+ /**
1031
+ * Inspects CSS rules looking for expected values using regular expressions
1032
+ *
1033
+ * @param string $css The CSS rules that will be inspected
1034
+ * @param string $selector The CSS selector whose rules will be inspected
1035
+ * @param string $property The CSS property that will be verified
1036
+ * @param string $value The CSS property value that will be verified
1037
+ * @return void
1038
+ */
1039
+ private function validateCSSRule($css, $selector, $property, $value)
1040
+ {
1041
+ // Escape the dot (used on class name selectors) so it is not interpreted as any character
1042
+ $selector = str_replace('.', '\.', $selector);
1043
+
1044
+ $cssRulePattern = '/' . $selector. '\s*{[^}]*'. $property . ':\s*' . $value . ';/';
1045
+ $this->assertEquals(1, preg_match($cssRulePattern, $css), "Could not find CSS rule '$property' for selector '$selector'");
1046
+ }
1047
+
1048
+ /**
1049
+ * Generates a random color expressed as three hexadecimal values
1050
+ *
1051
+ * @return string E.g. '#237A90'
1052
+ */
1053
+ private static function getRandomHexColor()
1054
+ {
1055
+ $red = rand(0, 255);
1056
+ $green = rand(0, 255);
1057
+ $blue = rand(0, 255);
1058
+
1059
+ return '#' . str_pad(dechex($red), 2, '0', STR_PAD_LEFT) .
1060
+ str_pad(dechex($green), 2, '0', STR_PAD_LEFT) .
1061
+ str_pad(dechex($blue), 2, '0', STR_PAD_LEFT);
1062
+ }
1063
+
1064
+ public function testBuildAnalytics()
1065
+ {
1066
+ $properties = array();
1067
+ $properties['analytics'] = [
1068
+ '<amp-pixel src="https://foo.com/pixel?RANDOM"></amp-pixel>',
1069
+ '<amp-analytics><script type="application/json">{}</script></amp-analytics>'
1070
+ ];
1071
+
1072
+ $context = AMPContext::create(new \DOMDocument(), InstantArticle::create());
1073
+
1074
+ $article = AMPArticle::create('<html></html>', $properties);
1075
+ $fragment = $article->buildAnalytics($context);
1076
+
1077
+ $this->assertEquals(2, $fragment->childNodes->length);
1078
+
1079
+ $pixel = $fragment->firstChild;
1080
+ $this->assertEquals('amp-pixel', $pixel->tagName);
1081
+ $this->assertEquals('https://foo.com/pixel?RANDOM', $pixel->getAttribute('src'));
1082
+
1083
+ $analytics = $fragment->childNodes->item(1);
1084
+ $this->assertEquals('amp-analytics', $analytics->tagName);
1085
+ $this->assertEquals(1, $analytics->childNodes->length);
1086
+
1087
+ $analyticsScript = $analytics->firstChild;
1088
+ $this->assertEquals('script', $analyticsScript->tagName);
1089
+ $this->assertEquals('application/json', $analyticsScript->getAttribute('type'));
1090
+ $this->assertEquals('{}', $analyticsScript->textContent);
1091
+ }
1092
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPCaptionTest.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+
12
+ use Facebook\InstantArticles\Elements\InstantArticle;
13
+ use Facebook\InstantArticles\Elements\Header;
14
+ use Facebook\InstantArticles\Elements\Image;
15
+ use Facebook\InstantArticles\Elements\Time;
16
+ use Facebook\InstantArticles\Elements\Author;
17
+ use Facebook\InstantArticles\Elements\Caption;
18
+ use PHPUnit\Framework;
19
+
20
+ class AMPCaptionTest extends Framework\TestCase
21
+ {
22
+
23
+ protected function setUp()
24
+ {
25
+ \Logger::configure(
26
+ [
27
+ 'rootLogger' => [
28
+ 'appenders' => ['facebook-instantarticles-traverser']
29
+ ],
30
+ 'appenders' => [
31
+ 'facebook-instantarticles-traverser' => [
32
+ 'class' => 'LoggerAppenderConsole',
33
+ 'threshold' => 'INFO',
34
+ 'layout' => [
35
+ 'class' => 'LoggerLayoutSimple'
36
+ ]
37
+ ]
38
+ ]
39
+ ]
40
+ );
41
+ }
42
+
43
+ private function genInstantArticle()
44
+ {
45
+ return InstantArticle::create()
46
+ ->withHeader(
47
+ Header::create()
48
+ ->withTitle('Big Top Title')
49
+ ->withSubTitle('Smaller SubTitle')
50
+ ->withPublishTime(
51
+ Time::create(Time::PUBLISHED)
52
+ ->withDatetime(
53
+ \DateTime::createFromFormat(
54
+ 'j-M-Y G:i:s',
55
+ '14-Aug-1984 19:30:00'
56
+ )
57
+ )
58
+ )
59
+ ->addAuthor(
60
+ Author::create()
61
+ ->withName('Author One')
62
+ ->withDescription('Passionate coder and mountain biker')
63
+ )
64
+ ->addAuthor(
65
+ Author::create()
66
+ ->withName('Author Two')
67
+ ->withDescription('Weend surfer with heavy weight coding skils')
68
+ ->withURL('http://facebook.com/author')
69
+ )
70
+ ->withKicker('Some kicker of this article')
71
+ ->withCover(
72
+ Image::create()
73
+ ->withURL('http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg')
74
+ ->withCaption(
75
+ Caption::create()
76
+ ->appendText('Some caption to the image')
77
+ )
78
+ )
79
+ );
80
+ }
81
+
82
+ private function genContext($document, $instantArticle)
83
+ {
84
+ $context = AMPContext::create($document, $instantArticle);
85
+
86
+ $mediaSizes = array();
87
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
88
+ $enableDownloadForMediaSizing = false;
89
+ $defaultWidth = 1000;
90
+ $defaultHeight = 900;
91
+
92
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
93
+
94
+ return $context;
95
+ }
96
+
97
+ public function testCaptionOnElementBottomByDefault()
98
+ {
99
+ $expected =
100
+ '<figure class="ia2amp-figure">'.
101
+ '<amp-img/>'.
102
+ '<figcaption class="ia2amp-figcaption ia2amp-op-small">Some caption to the image</figcaption>'.
103
+ '</figure>';
104
+ $instantArticle = $this->genInstantArticle();
105
+
106
+ $document = new \DOMDocument();
107
+ $context = $this->genContext($document, $instantArticle);
108
+
109
+ $ampImg = $document->createElement('amp-img');
110
+ $result = AMPCaption::create($instantArticle->getHeader()->getCover()->getCaption(), $context, $ampImg)->build();
111
+ $this->assertEquals($expected, $result->ownerDocument->saveXML($result));
112
+ }
113
+
114
+ public function testCaptionOnTopOfElement()
115
+ {
116
+ $expected =
117
+ '<figure class="ia2amp-figure">'.
118
+ '<figcaption class="ia2amp-figcaption ia2amp-op-small ia2amp-op-vertical-above">Some caption to the image</figcaption>'.
119
+ '<amp-img/>'.
120
+ '</figure>';
121
+ $instantArticle = $this->genInstantArticle();
122
+ $instantArticle->getHeader()->getCover()->getCaption()->withPosition(Caption::POSITION_ABOVE);
123
+
124
+ $document = new \DOMDocument();
125
+ $context = $this->genContext($document, $instantArticle);
126
+
127
+ $ampImg = $document->createElement('amp-img');
128
+ $result = AMPCaption::create($instantArticle->getHeader()->getCover()->getCaption(), $context, $ampImg)->build();
129
+ $this->assertEquals($expected, $result->ownerDocument->saveXML($result));
130
+ }
131
+
132
+ public function testCaptionOnTopOfElementBiggerSize()
133
+ {
134
+ $expected =
135
+ '<figure class="ia2amp-figure">'.
136
+ '<figcaption class="ia2amp-figcaption ia2amp-op-extra-large ia2amp-op-vertical-above">Some caption to the image</figcaption>'.
137
+ '<amp-img/>'.
138
+ '</figure>';
139
+ $instantArticle = $this->genInstantArticle();
140
+ $instantArticle->getHeader()->getCover()->getCaption()->withPosition(Caption::POSITION_ABOVE)->withFontsize(Caption::SIZE_XLARGE);
141
+
142
+ $document = new \DOMDocument();
143
+ $context = $this->genContext($document, $instantArticle);
144
+
145
+ $ampImg = $document->createElement('amp-img');
146
+ $result = AMPCaption::create($instantArticle->getHeader()->getCover()->getCaption(), $context, $ampImg)->build();
147
+ $this->assertEquals($expected, $result->ownerDocument->saveXML($result));
148
+ }
149
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPContextTest.php ADDED
@@ -0,0 +1,563 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Elements\InstantArticle;
12
+ use Facebook\InstantArticles\Elements\Paragraph;
13
+ use PHPUnit\Framework;
14
+
15
+
16
+
17
+ class AMPContextTest extends Framework\TestCase
18
+ {
19
+ protected function setUp()
20
+ {
21
+ \Logger::configure(
22
+ [
23
+ 'rootLogger' => [
24
+ 'appenders' => ['facebook-instantarticles-traverser']
25
+ ],
26
+ 'appenders' => [
27
+ 'facebook-instantarticles-traverser' => [
28
+ 'class' => 'LoggerAppenderConsole',
29
+ 'threshold' => 'INFO',
30
+ 'layout' => [
31
+ 'class' => 'LoggerLayoutSimple'
32
+ ]
33
+ ]
34
+ ]
35
+ ]
36
+ );
37
+ }
38
+
39
+ public function testContextCreation()
40
+ {
41
+ $context = AMPContext::create(new \DOMDocument(), InstantArticle::create());
42
+ $this->assertNotNull($context);
43
+ }
44
+
45
+ public function testContextCreationErrorDocument()
46
+ {
47
+ $this->setExpectedException('InvalidArgumentException');
48
+ $context = AMPContext::create("new \DOMDocument()", InstantArticle::create());
49
+ }
50
+
51
+ public function testContextCreationErrorIA()
52
+ {
53
+ $this->setExpectedException('InvalidArgumentException');
54
+ $context = AMPContext::create(new \DOMDocument(), Paragraph::create());
55
+ }
56
+
57
+ public function testCreatingHtml()
58
+ {
59
+ $document = new \DOMDocument();
60
+ $context = AMPContext::create($document, InstantArticle::create());
61
+ $context->withHtml($document->createElement('html'));
62
+ $this->assertTrue($context->hasHtml());
63
+ }
64
+
65
+ public function testCreatingHtmlEmpty()
66
+ {
67
+ $document = new \DOMDocument();
68
+ $context = AMPContext::create($document, InstantArticle::create());
69
+ $this->assertFalse($context->hasHtml());
70
+ }
71
+
72
+ public function testCreatingHtmlInvalid()
73
+ {
74
+ $document = new \DOMDocument();
75
+ $context = AMPContext::create($document, InstantArticle::create());
76
+ $this->setExpectedException('InvalidArgumentException', 'Tag <html> expected, <script> informed.');
77
+ $context->withHtml($document->createElement('script'));
78
+ }
79
+
80
+ public function testCreatingHead()
81
+ {
82
+ $document = new \DOMDocument();
83
+ $context = AMPContext::create($document, InstantArticle::create());
84
+ $context->withHead($document->createElement('head'));
85
+ $this->assertTrue($context->hasHead());
86
+ }
87
+
88
+ public function testCreatingHeadEmpty()
89
+ {
90
+ $document = new \DOMDocument();
91
+ $context = AMPContext::create($document, InstantArticle::create());
92
+ $this->assertFalse($context->hasHead());
93
+ }
94
+
95
+ public function testCreatingHeadInvalid()
96
+ {
97
+ $document = new \DOMDocument();
98
+ $context = AMPContext::create($document, InstantArticle::create());
99
+ $this->setExpectedException('InvalidArgumentException', 'Tag <head> expected, <script> informed.');
100
+ $context->withHead($document->createElement('script'));
101
+ }
102
+
103
+ public function testCreatingBody()
104
+ {
105
+ $document = new \DOMDocument();
106
+ $context = AMPContext::create($document, InstantArticle::create());
107
+ $context->withBody($document->createElement('body'));
108
+ $this->assertTrue($context->hasBody());
109
+ }
110
+
111
+ public function testCreatingBodyEmpty()
112
+ {
113
+ $document = new \DOMDocument();
114
+ $context = AMPContext::create($document, InstantArticle::create());
115
+ $this->assertFalse($context->hasBody());
116
+ }
117
+
118
+ public function testCreatingBodyInvalid()
119
+ {
120
+ $document = new \DOMDocument();
121
+ $context = AMPContext::create($document, InstantArticle::create());
122
+ $this->setExpectedException('InvalidArgumentException', 'Tag <body> expected, <script> informed.');
123
+ $context->withBody($document->createElement('script'));
124
+ }
125
+
126
+ public function testCreatingArticle()
127
+ {
128
+ $document = new \DOMDocument();
129
+ $context = AMPContext::create($document, InstantArticle::create());
130
+ $context->withArticle($document->createElement('article'));
131
+ $this->assertTrue($context->hasArticle());
132
+ }
133
+
134
+ public function testCreatingArticleEmpty()
135
+ {
136
+ $document = new \DOMDocument();
137
+ $context = AMPContext::create($document, InstantArticle::create());
138
+ $this->assertFalse($context->hasArticle());
139
+ }
140
+
141
+ public function testCreatingArticleInvalid()
142
+ {
143
+ $document = new \DOMDocument();
144
+ $context = AMPContext::create($document, InstantArticle::create());
145
+ $this->setExpectedException('InvalidArgumentException', 'Tag <article> expected, <script> informed.');
146
+ $context->withArticle($document->createElement('script'));
147
+ }
148
+
149
+ public function testCreatingHeader()
150
+ {
151
+ $document = new \DOMDocument();
152
+ $context = AMPContext::create($document, InstantArticle::create());
153
+ $context->withHeader($document->createElement('header'));
154
+ $this->assertTrue($context->hasHeader());
155
+ }
156
+
157
+ public function testCreatingHeaderEmpty()
158
+ {
159
+ $document = new \DOMDocument();
160
+ $context = AMPContext::create($document, InstantArticle::create());
161
+ $this->assertFalse($context->hasHeader());
162
+ }
163
+
164
+ public function testCreatingHeaderInvalid()
165
+ {
166
+ $document = new \DOMDocument();
167
+ $context = AMPContext::create($document, InstantArticle::create());
168
+ $this->setExpectedException('InvalidArgumentException', 'Tag <header> expected, <script> informed.');
169
+ $context->withHeader($document->createElement('script'));
170
+ }
171
+
172
+ public function testCreatingHeaderBar()
173
+ {
174
+ $document = new \DOMDocument();
175
+ $context = AMPContext::create($document, InstantArticle::create());
176
+ $context->withHeaderBar($document->createElement('div'));
177
+ $this->assertTrue($context->hasHeaderBar());
178
+ }
179
+
180
+ public function testCreatingHeaderBarEmpty()
181
+ {
182
+ $document = new \DOMDocument();
183
+ $context = AMPContext::create($document, InstantArticle::create());
184
+ $this->assertFalse($context->hasHeaderBar());
185
+ }
186
+
187
+ public function testCreatingHeaderBarInvalid()
188
+ {
189
+ $document = new \DOMDocument();
190
+ $context = AMPContext::create($document, InstantArticle::create());
191
+ $this->setExpectedException('InvalidArgumentException', 'Tag <div> expected, <script> informed.');
192
+ $context->withHeaderBar($document->createElement('script'));
193
+ }
194
+
195
+ public function testCreatingHeaderBarLogo()
196
+ {
197
+ $document = new \DOMDocument();
198
+ $context = AMPContext::create($document, InstantArticle::create());
199
+ $context->withHeaderBarLogo($document->createElement('div'));
200
+ $this->assertTrue($context->hasHeaderBarLogo());
201
+ }
202
+
203
+ public function testCreatingHeaderBarLogoEmpty()
204
+ {
205
+ $document = new \DOMDocument();
206
+ $context = AMPContext::create($document, InstantArticle::create());
207
+ $this->assertFalse($context->hasHeaderBarLogo());
208
+ }
209
+
210
+ public function testCreatingHeaderBarLogoInvalid()
211
+ {
212
+ $document = new \DOMDocument();
213
+ $context = AMPContext::create($document, InstantArticle::create());
214
+ $this->setExpectedException('InvalidArgumentException', 'Tag <div> expected, <script> informed.');
215
+ $context->withHeaderBarLogo($document->createElement('script'));
216
+ }
217
+
218
+ public function testCreatingHeaderTitle()
219
+ {
220
+ $document = new \DOMDocument();
221
+ $context = AMPContext::create($document, InstantArticle::create());
222
+ $context->withHeaderTitle($document->createElement('h1'));
223
+ $this->assertTrue($context->hasHeaderTitle());
224
+ }
225
+
226
+ public function testCreatingHeaderTitleEmpty()
227
+ {
228
+ $document = new \DOMDocument();
229
+ $context = AMPContext::create($document, InstantArticle::create());
230
+ $this->assertFalse($context->hasHeaderTitle());
231
+ }
232
+
233
+ public function testCreatingHeaderTitleInvalid()
234
+ {
235
+ $document = new \DOMDocument();
236
+ $context = AMPContext::create($document, InstantArticle::create());
237
+ $this->setExpectedException('InvalidArgumentException', 'Tag <h1> expected, <script> informed.');
238
+ $context->withHeaderTitle($document->createElement('script'));
239
+ }
240
+
241
+ public function testCreatingHeaderAuthor()
242
+ {
243
+ $document = new \DOMDocument();
244
+ $context = AMPContext::create($document, InstantArticle::create());
245
+ $context->withHeaderAuthor($document->createElement('h3'));
246
+ $this->assertTrue($context->hasHeaderAuthor());
247
+ }
248
+
249
+ public function testCreatingHeaderAuthorEmpty()
250
+ {
251
+ $document = new \DOMDocument();
252
+ $context = AMPContext::create($document, InstantArticle::create());
253
+ $this->assertFalse($context->hasHeaderAuthor());
254
+ }
255
+
256
+ public function testCreatingHeaderAuthorInvalid()
257
+ {
258
+ $document = new \DOMDocument();
259
+ $context = AMPContext::create($document, InstantArticle::create());
260
+ $this->setExpectedException('InvalidArgumentException', 'Tag <h3> expected, <script> informed.');
261
+ $context->withHeaderAuthor($document->createElement('script'));
262
+ }
263
+
264
+ public function testCreatingHeaderKicker()
265
+ {
266
+ $document = new \DOMDocument();
267
+ $context = AMPContext::create($document, InstantArticle::create());
268
+ $context->withHeaderKicker($document->createElement('h2'));
269
+ $this->assertTrue($context->hasHeaderKicker());
270
+ }
271
+
272
+ public function testCreatingHeaderKickerEmpty()
273
+ {
274
+ $document = new \DOMDocument();
275
+ $context = AMPContext::create($document, InstantArticle::create());
276
+ $this->assertFalse($context->hasHeaderKicker());
277
+ }
278
+
279
+ public function testCreatingHeaderKickerInvalid()
280
+ {
281
+ $document = new \DOMDocument();
282
+ $context = AMPContext::create($document, InstantArticle::create());
283
+ $this->setExpectedException('InvalidArgumentException', 'Tag <h2> expected, <script> informed.');
284
+ $context->withHeaderKicker($document->createElement('script'));
285
+ }
286
+
287
+ public function testCreatingHeaderDate()
288
+ {
289
+ $document = new \DOMDocument();
290
+ $context = AMPContext::create($document, InstantArticle::create());
291
+ $context->withHeaderDate($document->createElement('h3'));
292
+ $this->assertTrue($context->hasHeaderDate());
293
+ }
294
+
295
+ public function testCreatingHeaderDateEmpty()
296
+ {
297
+ $document = new \DOMDocument();
298
+ $context = AMPContext::create($document, InstantArticle::create());
299
+ $this->assertFalse($context->hasHeaderDate());
300
+ }
301
+
302
+ public function testCreatingHeaderDateInvalid()
303
+ {
304
+ $document = new \DOMDocument();
305
+ $context = AMPContext::create($document, InstantArticle::create());
306
+ $this->setExpectedException('InvalidArgumentException', 'Tag <h3> expected, <script> informed.');
307
+ $context->withHeaderDate($document->createElement('script'));
308
+ }
309
+
310
+ public function testInformedImageDimensions()
311
+ {
312
+ $expectedWidth = 800;
313
+ $expectedHeight = 500;
314
+
315
+ $document = new \DOMDocument();
316
+ $context = AMPContext::create($document, InstantArticle::create());
317
+
318
+ $mediaSizes = array('https://www.facebook.com/images/fb_icon_325x325.png' => array($expectedWidth, $expectedHeight));
319
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
320
+ $enableDownloadForMediaSizing = true;
321
+ $defaultWidth = 1000;
322
+ $defaultHeight = 900;
323
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
324
+
325
+ $dimensions = $context->getMediaDimensions('https://www.facebook.com/images/fb_icon_325x325.png');
326
+
327
+ $this->assertEquals($expectedWidth, $dimensions[0]);
328
+ $this->assertEquals($expectedHeight, $dimensions[1]);
329
+ }
330
+
331
+ public function testCachedImageDimensions()
332
+ {
333
+ $expectedWidth = 325;
334
+ $expectedHeight = 325;
335
+
336
+ $document = new \DOMDocument();
337
+ $context = AMPContext::create($document, InstantArticle::create());
338
+
339
+ $mediaSizes = array();
340
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
341
+ $enableDownloadForMediaSizing = true;
342
+ $defaultWidth = 1000;
343
+ $defaultHeight = 900;
344
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
345
+
346
+ $dimensions = $context->getMediaDimensions('https://www.facebook.com/images/fb_icon_325x325.png');
347
+
348
+ $this->assertEquals($expectedWidth, $dimensions[0]);
349
+ $this->assertEquals($expectedHeight, $dimensions[1]);
350
+ }
351
+
352
+ public function testImageDimensionsDownloadDisabled()
353
+ {
354
+ $expectedWidth = 325;
355
+ $expectedHeight = 325;
356
+
357
+ $document = new \DOMDocument();
358
+ $context = AMPContext::create($document, InstantArticle::create());
359
+
360
+ $mediaSizes = array();
361
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
362
+ $enableDownloadForMediaSizing = false;
363
+ $defaultWidth = 1000;
364
+ $defaultHeight = 900;
365
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
366
+
367
+ $dimensions = $context->getMediaDimensions('https://www.facebook.com/images/fb_icon_325x325.png');
368
+
369
+ $this->assertEquals($expectedWidth, $dimensions[0]);
370
+ $this->assertEquals($expectedHeight, $dimensions[1]);
371
+ }
372
+
373
+ public function testImageDimensionsDownloadEnabled()
374
+ {
375
+ $expectedWidth = 325;
376
+ $expectedHeight = 325;
377
+
378
+ $document = new \DOMDocument();
379
+ $context = AMPContext::create($document, InstantArticle::create());
380
+
381
+ $mediaSizes = array();
382
+ $mediaCacheFolder = null;
383
+ $enableDownloadForMediaSizing = true;
384
+ $defaultWidth = 1000;
385
+ $defaultHeight = 900;
386
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
387
+
388
+ $dimensions = $context->getMediaDimensions('https://www.facebook.com/images/fb_icon_325x325.png', AMPContext::MEDIA_TYPE_IMAGE);
389
+
390
+ $this->assertEquals($expectedWidth, $dimensions[0]);
391
+ $this->assertEquals($expectedHeight, $dimensions[1]);
392
+ }
393
+
394
+ public function testImageDimensionsDefault()
395
+ {
396
+ $document = new \DOMDocument();
397
+ $context = AMPContext::create($document, InstantArticle::create());
398
+
399
+ $mediaSizes = array();
400
+ $mediaCacheFolder = null;
401
+ $enableDownloadForMediaSizing = false;
402
+ $defaultWidth = 1000;
403
+ $defaultHeight = 900;
404
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
405
+
406
+ $dimensions = $context->getMediaDimensions('https://www.facebook.com/images/fb_icon_325x325.png', AMPContext::MEDIA_TYPE_IMAGE);
407
+
408
+ $this->assertEquals($defaultWidth, $dimensions[0]);
409
+ $this->assertEquals($defaultHeight, $dimensions[1]);
410
+ }
411
+
412
+ public function testInformedVideoDimensions()
413
+ {
414
+ $expectedWidth = 800;
415
+ $expectedHeight = 500;
416
+
417
+ $document = new \DOMDocument();
418
+ $context = AMPContext::create($document, InstantArticle::create());
419
+
420
+ $mediaSizes = array('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4' => array($expectedWidth, $expectedHeight));
421
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
422
+ $enableDownloadForMediaSizing = true;
423
+ $defaultWidth = 1000;
424
+ $defaultHeight = 900;
425
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
426
+
427
+ $dimensions = $context->getMediaDimensions('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4', AMPContext::MEDIA_TYPE_VIDEO);
428
+
429
+ $this->assertEquals($expectedWidth, $dimensions[0]);
430
+ $this->assertEquals($expectedHeight, $dimensions[1]);
431
+ }
432
+
433
+ public function testCachedVideoDimensions()
434
+ {
435
+ $document = new \DOMDocument();
436
+ $context = AMPContext::create($document, InstantArticle::create());
437
+
438
+ $mediaSizes = array();
439
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
440
+ $enableDownloadForMediaSizing = true;
441
+ $defaultWidth = 1000;
442
+ $defaultHeight = 900;
443
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
444
+
445
+ $dimensions = $context->getMediaDimensions('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4', AMPContext::MEDIA_TYPE_VIDEO);
446
+
447
+ $this->assertEquals($defaultWidth, $dimensions[0]);
448
+ $this->assertEquals($defaultHeight, $dimensions[1]);
449
+ }
450
+
451
+ public function testVideoDimensionsDownloadDisabled()
452
+ {
453
+ $document = new \DOMDocument();
454
+ $context = AMPContext::create($document, InstantArticle::create());
455
+
456
+ $mediaSizes = array();
457
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
458
+ $enableDownloadForMediaSizing = false;
459
+ $defaultWidth = 1000;
460
+ $defaultHeight = 900;
461
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
462
+
463
+ $dimensions = $context->getMediaDimensions('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4', AMPContext::MEDIA_TYPE_VIDEO);
464
+
465
+ $this->assertEquals($defaultWidth, $dimensions[0]);
466
+ $this->assertEquals($defaultHeight, $dimensions[1]);
467
+ }
468
+
469
+ public function testVideoDimensionsDownloadEnabled()
470
+ {
471
+ $document = new \DOMDocument();
472
+ $context = AMPContext::create($document, InstantArticle::create());
473
+
474
+ $mediaSizes = array();
475
+ $mediaCacheFolder = null;
476
+ $enableDownloadForMediaSizing = true;
477
+ $defaultWidth = 1000;
478
+ $defaultHeight = 900;
479
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
480
+
481
+ $dimensions = $context->getMediaDimensions('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4', AMPContext::MEDIA_TYPE_VIDEO);
482
+
483
+ $this->assertEquals($defaultWidth, $dimensions[0]);
484
+ $this->assertEquals($defaultHeight, $dimensions[1]);
485
+ }
486
+
487
+ public function testVideoDimensionsDefault()
488
+ {
489
+ $document = new \DOMDocument();
490
+ $context = AMPContext::create($document, InstantArticle::create());
491
+
492
+ $mediaSizes = array();
493
+ $mediaCacheFolder = null;
494
+ $enableDownloadForMediaSizing = false;
495
+ $defaultWidth = 1000;
496
+ $defaultHeight = 900;
497
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
498
+
499
+ $dimensions = $context->getMediaDimensions('http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4', AMPContext::MEDIA_TYPE_VIDEO);
500
+
501
+ $this->assertEquals($defaultWidth, $dimensions[0]);
502
+ $this->assertEquals($defaultHeight, $dimensions[1]);
503
+ }
504
+
505
+ //
506
+ // public function testVideoHeightDefaultProperty()
507
+ // {
508
+ // $expectedHeight = 120;
509
+ // $customProperties = array(
510
+ // AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
511
+ // AMPArticle::DEFAULT_MEDIA_HEIGHT_KEY => $expectedHeight,
512
+ // );
513
+ //
514
+ // $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
515
+ // 'natgeo',
516
+ // '//amp-video',
517
+ // $customProperties
518
+ // );
519
+ // $firstArticleVideoElement = $videoXPathQuery->item(0);
520
+ //
521
+ // $this->assertEquals($expectedHeight, $firstArticleVideoElement->getAttribute('height'));
522
+ // }
523
+ //
524
+ // public function testVideoWidthFromMediaSizes()
525
+ // {
526
+ // $expectedWidth = 90;
527
+ // $customProperties = array(
528
+ // AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
529
+ // AMPArticle::MEDIA_SIZES_KEY => array(
530
+ // "http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4" => array($expectedWidth, 60),
531
+ // ),
532
+ // );
533
+ //
534
+ // $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
535
+ // 'natgeo',
536
+ // '//amp-video',
537
+ // $customProperties
538
+ // );
539
+ // $firstArticleVideoElement = $videoXPathQuery->item(0);
540
+ //
541
+ // $this->assertEquals($expectedWidth, $firstArticleVideoElement->getAttribute('width'));
542
+ // }
543
+ //
544
+ // public function testVideoHeightFromMediaSizes()
545
+ // {
546
+ // $expectedHeight = 60;
547
+ // $customProperties = array(
548
+ // AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
549
+ // AMPArticle::MEDIA_SIZES_KEY => array(
550
+ // "http://ngm.nationalgeographic.com/2015/05/building-bees/v/timelapse-final-4x3.mp4" => array(90, $expectedHeight),
551
+ // ),
552
+ // );
553
+ //
554
+ // $videoXPathQuery = $this->getRenderedMarkupXPathQuery(
555
+ // 'natgeo',
556
+ // '//amp-video',
557
+ // $customProperties
558
+ // );
559
+ // $firstArticleVideoElement = $videoXPathQuery->item(0);
560
+ //
561
+ // $this->assertEquals($expectedHeight, $firstArticleVideoElement->getAttribute('height'));
562
+ // }
563
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPCoverImageTest.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+
12
+ use Facebook\InstantArticles\Elements\InstantArticle;
13
+ use Facebook\InstantArticles\Elements\Header;
14
+ use Facebook\InstantArticles\Elements\Image;
15
+ use Facebook\InstantArticles\Elements\Time;
16
+ use Facebook\InstantArticles\Elements\Author;
17
+ use Facebook\InstantArticles\Elements\Caption;
18
+ use PHPUnit\Framework;
19
+
20
+ class AMPCoverImageTest extends Framework\TestCase
21
+ {
22
+
23
+ protected function setUp()
24
+ {
25
+ \Logger::configure(
26
+ [
27
+ 'rootLogger' => [
28
+ 'appenders' => ['facebook-instantarticles-traverser']
29
+ ],
30
+ 'appenders' => [
31
+ 'facebook-instantarticles-traverser' => [
32
+ 'class' => 'LoggerAppenderConsole',
33
+ 'threshold' => 'INFO',
34
+ 'layout' => [
35
+ 'class' => 'LoggerLayoutSimple'
36
+ ]
37
+ ]
38
+ ]
39
+ ]
40
+ );
41
+ }
42
+
43
+ private function genInstantArticle()
44
+ {
45
+ return InstantArticle::create()
46
+ ->withHeader(
47
+ Header::create()
48
+ ->withTitle('Big Top Title')
49
+ ->withSubTitle('Smaller SubTitle')
50
+ ->withPublishTime(
51
+ Time::create(Time::PUBLISHED)
52
+ ->withDatetime(
53
+ \DateTime::createFromFormat(
54
+ 'j-M-Y G:i:s',
55
+ '14-Aug-1984 19:30:00'
56
+ )
57
+ )
58
+ )
59
+ ->addAuthor(
60
+ Author::create()
61
+ ->withName('Author One')
62
+ ->withDescription('Passionate coder and mountain biker')
63
+ )
64
+ ->addAuthor(
65
+ Author::create()
66
+ ->withName('Author Two')
67
+ ->withDescription('Weend surfer with heavy weight coding skils')
68
+ ->withURL('http://facebook.com/author')
69
+ )
70
+ ->withKicker('Some kicker of this article')
71
+ ->withCover(
72
+ Image::create()
73
+ ->withURL('http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg')
74
+ )
75
+ );
76
+ }
77
+
78
+ private function genContext($document, $instantArticle)
79
+ {
80
+ $context = AMPContext::create($document, $instantArticle);
81
+
82
+ $mediaSizes = array();
83
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
84
+ $enableDownloadForMediaSizing = false;
85
+ $defaultWidth = 1000;
86
+ $defaultHeight = 900;
87
+
88
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
89
+
90
+ return $context;
91
+ }
92
+
93
+ public function testBuildCoverWithCaption()
94
+ {
95
+ $expected =
96
+ '<div class="ia2amp-cover-image">'.
97
+ '<figure class="ia2amp-figure">'.
98
+ '<amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg" width="422" height="240"/>'.
99
+ '<figcaption class="ia2amp-figcaption ia2amp-op-small">Some caption to the image</figcaption>'.
100
+ '</figure>'.
101
+ '</div>';
102
+ $instantArticle = $this->genInstantArticle();
103
+ $instantArticle->getHeader()->getCover()->withCaption(
104
+ Caption::create()
105
+ ->appendText('Some caption to the image')
106
+ );
107
+
108
+ $document = new \DOMDocument();
109
+ $context = $this->genContext($document, $instantArticle);
110
+
111
+ $result = AMPCoverImage::create($instantArticle->getHeader()->getCover(), $context, 'cover-image')->build();
112
+ $this->assertEquals($expected, $result->ownerDocument->saveXML($result));
113
+ }
114
+
115
+ public function testBuildCoverWithoutCaption()
116
+ {
117
+ $expected =
118
+ '<div class="ia2amp-cover-image">'.
119
+ '<amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg" width="422" height="240"/>'.
120
+ '</div>';
121
+ $instantArticle = $this->genInstantArticle();
122
+
123
+ $document = new \DOMDocument();
124
+ $context = $this->genContext($document, $instantArticle);
125
+
126
+ $result = AMPCoverImage::create($instantArticle->getHeader()->getCover(), $context, 'cover-image')->build();
127
+ $this->assertEquals($expected, $result->ownerDocument->saveXML($result));
128
+ }
129
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/AMPHeaderTest.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\AMP;
10
+
11
+ use Facebook\InstantArticles\Utils\FileUtilsPHPUnitTestCase;
12
+
13
+ class AMPHeaderTest extends FileUtilsPHPUnitTestCase
14
+ {
15
+ private $logo;
16
+ private $testHeader;
17
+
18
+ protected function setUp()
19
+ {
20
+ $url = 'http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png';
21
+ $width = 600;
22
+ $height = 60;
23
+ $this->logo = new AMPImage($url, $width, $height);
24
+ }
25
+
26
+ private function getRenderer($test, $customProperties = null)
27
+ {
28
+ $instantArticle = $this->loadInstantArticle(__DIR__ . '/articles/'.$test.'-instant-article.html');
29
+ $properties = array(
30
+ 'lang' => 'en-US',
31
+ AMPArticle::STYLES_FOLDER_KEY => __DIR__,
32
+ AMPArticle::ENABLE_DOWNLOAD_FOR_MEDIA_SIZING_KEY => false,
33
+ );
34
+ if (!is_null($customProperties)) {
35
+ $properties = array_merge($properties, $customProperties);
36
+ }
37
+
38
+ return AMPArticle::create($instantArticle, $properties);
39
+ }
40
+
41
+ private function genContext()
42
+ {
43
+ $renderer = $this->getRenderer('test1', null);
44
+ $context = AMPContext::create(new \DOMDocument('1.0'), $renderer->getInstantArticle());
45
+
46
+ $mediaSizes = array();
47
+ $mediaCacheFolder = __DIR__ . '/articles/media-cache';
48
+ $enableDownloadForMediaSizing = false;
49
+ $defaultWidth = 1000;
50
+ $defaultHeight = 900;
51
+
52
+ $context->withMediaSizingSetup($mediaSizes, $mediaCacheFolder, $enableDownloadForMediaSizing, $defaultWidth, $defaultHeight);
53
+
54
+ return $context;
55
+ }
56
+
57
+ private function genTestingHeader()
58
+ {
59
+ $context = $this->genContext();
60
+
61
+ $this->testHeader = new AMPHeader($context);
62
+ $target = $this->testHeader->build();
63
+ $this->testHeader->genHeaderLogo($this->logo);
64
+
65
+ $document = new \DOMDocument;
66
+ $document->appendChild($document->importNode($target, true));
67
+
68
+ return new \DOMXPath($document);
69
+ }
70
+
71
+ public function testBuild()
72
+ {
73
+ $testingHeader = $this->genTestingHeader();
74
+
75
+ $publicationDateFetch = $testingHeader->query('//h3[@class="ia2amp-header-date"][1]')->item(0);
76
+ $titleFetch = $testingHeader->query('//h1[@class="ia2amp-header-h1"][1]')->item(0);
77
+ $byLineFetch = $testingHeader->query('//h3[@class="ia2amp-header-author"][1]')->item(0);
78
+ $kickerFetch = $testingHeader->query('//h2[@class="ia2amp-header-category"][1]')->item(0);
79
+ $logo = $testingHeader->query('//div[@class="ia2amp-header-bar-img-container"]/amp-img[1]')->item(0);
80
+
81
+ $publicationDate = $publicationDateFetch->textContent;
82
+ $title = $titleFetch->textContent;
83
+ $byLine = $byLineFetch->textContent;
84
+ $kicker = $kickerFetch->textContent;
85
+
86
+ $this->assertEquals("http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png", $logo->getAttribute("src"));
87
+ $this->assertEquals(600, $logo->getAttribute("width"));
88
+ $this->assertEquals(60, $logo->getAttribute("height"));
89
+ $this->assertEquals("motivational", $kicker);
90
+ $this->assertEquals("Very First WOD!", $title);
91
+ //$this->assertEquals("May 10, 2016", $publicationDate);
92
+ $this->assertEquals("By Éverton Rosário", $byLine);
93
+
94
+ $spaceNodes = array(
95
+ '//div[@class="ia2amp-header-bar"][1]',
96
+ '//h2[@class="ia2amp-spacing after-header-date"][1]',
97
+ '//h2[@class="ia2amp-spacing after-header-author before-header-date"][1]',
98
+ '//div[@class="ia2amp-spacing after-header-category before-header-h1"][1]',
99
+ '//div[@class="ia2amp-spacing after-header-h1 before-header-author"]',
100
+ '//div[@class="ia2amp-spacing after-header-bar before-header-category"]',
101
+ );
102
+
103
+ foreach ($spaceNodes as $currentNode) {
104
+ $this->assertNotEmpty($testingHeader->query($currentNode));
105
+ }
106
+ }
107
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/amp-converted.html ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <style amp-custom>html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue; color: #000000; text-align: LEFT; display: INLINE; text-transform: uppercase; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-header-h1 {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-header-h2 {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue; color: #000000; text-align: LEFT; display: INLINE; text-transform: uppercase; margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-header-bar {background-color: #666666;}.ia2amp-h1 {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-h2 {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-p {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-article a {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; text-decoration: underline; margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-blockquote {font-family: Georgia; color: #000000; text-align: LEFT; display: BLOCK; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 32px 0 46px; border-top-color: rgb(0,0,0); border-right-color: rgb(0,0,0); border-bottom-color: rgb(0,0,0); border-left-color: rgb(0,0,0); border-width: 0 0 0 2px; border-style: solid;}.ia2amp-pullquote {font-family: Georgia; color: #000000; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue; color: #000000; text-align: LEFT; display: INLINE; text-transform: uppercase; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}figcaption h1 {font-family: Helvetica Neue Bold; color: #808080; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}figcaption h2 {font-family: Helvetica Neue; color: #808080; text-align: LEFT; display: INLINE; text-transform: none; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}figcaption cite {font-family: Helvetica Neue; color: #BFBFBF; text-align: LEFT; display: INLINE; text-transform: uppercase; background-color: rgba(255,255,255,0); margin: 0 15px 0 15px; padding: 0 0 0 0; border-width: 0 0 0 0; border-style: solid;}/*Global Styles*/ .ia2amp-header { margin-bottom: 26.4px; } .ia2amp-header-bar { margin: -5px 0 12px 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 15px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; margin: 18.8px 16.4px 0 16.4px; } .ia2amp-header-h1 { font-size: 30px; line-height: 30px; display: block; font-weight: normal; margin: 13.2px 16.4px 13.2px 16.4px; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; margin: 0 16.4px 18.8px 16.4px; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; margin: 0 16.4px 0 16.4px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; margin: 18.8px 16.4px 18.8px 16.4px; } /* Custom CSS for wod-gray style goes here */ /* p { background-color: rgb(255,00,00); } */ </style>
11
+ <link rel="canonical" href="http://blog.wod.expert/very-first-wod/"/>
12
+ <title>Very First WOD!</title>
13
+ <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
14
+ <script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>
15
+ </head>
16
+ <body class="ia2amp-body">
17
+ <header class="ia2amp-header">
18
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg" width="380" height="215"></amp-img>
19
+ <div class="ia2amp-header-bar">
20
+ <div class="ia2amp-header-bar-img-container">
21
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/wod-expert-horizontal@033x.png" width="200" height="40"></amp-img>
22
+ </div>
23
+ </div>
24
+ <h2 class="ia2amp-header-category">motivational</h2>
25
+ <div class"ia2amp-separator ia2amp-sep-category ia2amp-sep-h1"></div>
26
+ <h1 class="ia2amp-header-h1">Very First WOD!</h1>
27
+ <h3 class="ia2amp-header-author">BY Éverton Rosário</h3>
28
+ <h3 class="ia2amp-header-date">May 10, 2016</h3>
29
+ </header>
30
+ <div class"ia2amp-separator ia2amp-sep-category ia2amp-sep-h1"></div>
31
+ <article class="ia2amp-article">
32
+ <p class="ia2amp-p">The first WOD we never forget! Just to be sure we are talking about same thing, WOD stands for “Workout of the Day”.  You feel you’re already gone on the warm up session.</p>
33
+ <blockquote class="ia2amp-blockquote">“WOD stands for Workout of the Day”</blockquote>
34
+ <p class="ia2amp-p">Most likely you won’t be the only one in that training session, so it might be your first, but you will feel that others on your side are lightyears above and in front of you. You look at those faces, and they seem to be feeling nothing, but you are dying to run 100 meters sprint, unable to do 10 air squats and completely unable to perform 10 pushups.  One thing I gotta say to you: you’re not alone!</p>
35
+ <div class="ia2amp-slideshow">
36
+ <amp-carousel width="380" height="240">
37
+ <div class="ia2amp-slideshow-image">
38
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail2.jpg" width="380" height="243"></amp-img>
39
+ </div>
40
+ <div class="ia2amp-slideshow-image">
41
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail3.jpg" width="380" height="252"></amp-img>
42
+ </div>
43
+ </amp-carousel>
44
+ </div>
45
+ <p class="ia2amp-p">No matter which will be your very first workout. It can be one of the benchmark’s fancy named workouts or any unnamed workout, it doesn’t matter: you will “complete”, or better to say: you will suffer on it even just doing with the lightest weight on the box, using rubber, doing half of the repetitions, but still you will suck on performing it! Don’t feel ashamed of that!</p>
46
+ <div class="ia2amp-interactive">
47
+ <amp-iframe src="https://www.youtube.com/embed/P_uDhI-5FqE?start=258&amp;feature=oembed" width="600" height="480" sandbox="allow-scripts allow-same-origin" layout="responsive" frameborder="0"></amp-iframe>
48
+ </div>
49
+ <p class="ia2amp-p">Have you made thru it? What was your feeling by the end, even not finishing, or doing half of workout? You will pick one side here: Either you will get addicted and return every day, or you will just drop out. Which one you took?</p>
50
+ <p class="ia2amp-p">I guess I already know your answer, once you are coming here!</p>
51
+ <p class="ia2amp-p">Welcome, crossfitter!</p>
52
+ </article>
53
+ </body>
54
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/amp-example.html ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async=""></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <style amp-custom>h1 { color: #000; }</style>
11
+ <link rel="canonical" href="http://blog.wod.expert/very-first-wod/"/>
12
+ <title>Very First WOD!</title>
13
+ <script custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js" async></script>
14
+ <script custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js" async></script>
15
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic">
16
+ <script type="application/ld+json">{"@context":"http:\/\/schema.org","@type":"BlogPosting","mainEntityOfPage":"http:\/\/blog.wod.expert\/very-first-wod\/","publisher":{"@type":"Organization","name":"Wod Expert"},"headline":"Very First WOD!","datePublished":"2016-05-10T18:05:36+00:00","dateModified":"2017-03-17T16:46:07+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http:\/\/blog.wod.expert\/wp-content\/uploads\/2017\/03\/fail1.jpg","width":800,"height":454}}</script>
17
+ <style amp-custom>.alignright{float:right}.alignleft{float:left}.aligncenter{display:block;margin-left:auto;margin-right:auto}.amp-wp-enforced-sizes{max-width:100%;margin:0 auto}.amp-wp-unknown-size img{object-fit:contain}.amp-wp-content,.amp-wp-title-bar div{margin:0 auto;max-width:525px}html{background:#0a89c0}body{background:#fff;color:#353535;font-family:'Merriweather','Times New Roman',Times,serif;font-weight:300;line-height:1.75em}p,ol,ul,figure{margin:0 0 1em;padding:0}a,a:visited{color:#0a89c0}a:hover,a:active,a:focus{color:#353535}blockquote{color:#353535;background:rgba(127,127,127,.125);border-left:2px solid #0a89c0;margin:8px 0 24px 0;padding:16px}blockquote p:last-child{margin-bottom:0}.amp-wp-meta,.amp-wp-header div,.amp-wp-title,.wp-caption-text,.amp-wp-tax-category,.amp-wp-tax-tag,.amp-wp-comments-link,.amp-wp-footer p,.back-to-top{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif}.amp-wp-header{background-color:#0a89c0}.amp-wp-header div{color:#fff;font-size:1em;font-weight:400;margin:0 auto;max-width:calc(840px - 32px);padding:.875em 16px;position:relative}.amp-wp-header a{color:#fff;text-decoration:none}.amp-wp-header .amp-wp-site-icon{background-color:#fff;border:1px solid #fff;border-radius:50%;position:absolute;right:18px;top:10px}.amp-wp-article{color:#353535;font-weight:400;margin:1.5em auto;max-width:840px;overflow-wrap:break-word;word-wrap:break-word}.amp-wp-article-header{align-items:center;align-content:stretch;display:flex;flex-wrap:wrap;justify-content:space-between;margin:1.5em 16px 1.5em}.amp-wp-title{color:#353535;display:block;flex:1 0 100%;font-weight:900;margin:0 0 .625em;width:100%}.amp-wp-meta{color:#696969;display:inline-block;flex:2 1 50%;font-size:.875em;line-height:1.5em;margin:0;padding:0}.amp-wp-article-header .amp-wp-meta:last-of-type{text-align:right}.amp-wp-article-header .amp-wp-meta:first-of-type{text-align:left}.amp-wp-byline amp-img,.amp-wp-byline .amp-wp-author{display:inline-block;vertical-align:middle}.amp-wp-byline amp-img{border:1px solid #0a89c0;border-radius:50%;position:relative;margin-right:6px}.amp-wp-posted-on{text-align:right}.amp-wp-article-featured-image{margin:0 0 1em}.amp-wp-article-featured-image amp-img{margin:0 auto}.amp-wp-article-featured-image.wp-caption .wp-caption-text{margin:0 18px}.amp-wp-article-content{margin:0 16px}.amp-wp-article-content ul,.amp-wp-article-content ol{margin-left:1em}.amp-wp-article-content amp-img{margin:0 auto}.amp-wp-article-content amp-img.alignright{margin:0 0 1em 16px}.amp-wp-article-content amp-img.alignleft{margin:0 16px 1em 0}.wp-caption{padding:0}.wp-caption.alignleft{margin-right:16px}.wp-caption.alignright{margin-left:16px}.wp-caption .wp-caption-text{border-bottom:1px solid #c2c2c2;color:#696969;font-size:.875em;line-height:1.5em;margin:0;padding:.66em 10px .75em}amp-carousel{background:#c2c2c2;margin:0 -16px 1.5em}amp-iframe,amp-youtube,amp-instagram,amp-vine{background:#c2c2c2;margin:0 -16px 1.5em}.amp-wp-article-content amp-carousel amp-img{border:none}amp-carousel>amp-img>img{object-fit:contain}.amp-wp-iframe-placeholder{background:#c2c2c2 url(http://blog.wod.expert/wp-content/plugins/amp/assets/images/placeholder-icon.png) no-repeat center 40%;background-size:48px 48px;min-height:48px}.amp-wp-article-footer .amp-wp-meta{display:block}.amp-wp-tax-category,.amp-wp-tax-tag{color:#696969;font-size:.875em;line-height:1.5em;margin:1.5em 16px}.amp-wp-comments-link{color:#696969;font-size:.875em;line-height:1.5em;text-align:center;margin:2.25em 0 1.5em}.amp-wp-comments-link a{border-style:solid;border-color:#c2c2c2;border-width:1px 1px 2px;border-radius:4px;background-color:transparent;color:#0a89c0;cursor:pointer;display:block;font-size:14px;font-weight:600;line-height:18px;margin:0 auto;max-width:200px;padding:11px 16px;text-decoration:none;width:50%;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.amp-wp-footer{border-top:1px solid #c2c2c2;margin:calc(1.5em - 1px) 0 0}.amp-wp-footer div{margin:0 auto;max-width:calc(840px - 32px);padding:1.25em 16px 1.25em;position:relative}.amp-wp-footer h2{font-size:1em;line-height:1.375em;margin:0 0 .5em}.amp-wp-footer p{color:#696969;font-size:.8em;line-height:1.5em;margin:0 85px 0 0}.amp-wp-footer a{text-decoration:none}.back-to-top{bottom:1.275em;font-size:.8em;font-weight:600;line-height:2em;position:absolute;right:16px}</style>
18
+ </head>
19
+
20
+ <body class="">
21
+
22
+ <header id="#top" class="amp-wp-header">
23
+ <div>
24
+ <a href="http://blog.wod.expert">
25
+ Wod Expert </a>
26
+ </div>
27
+ </header>
28
+
29
+ <article class="amp-wp-article">
30
+
31
+ <header class="amp-wp-article-header">
32
+ <h1 class="amp-wp-title">Very First WOD!</h1>
33
+ <div class="amp-wp-meta amp-wp-byline">
34
+ <amp-img src="http://2.gravatar.com/avatar/ef460d8dfc54e64030b8230184b590b0?s=24&#038;d=mm&#038;r=g" width="24" height="24" layout="fixed"></amp-img>
35
+ <span class="amp-wp-author author vcard">Éverton Rosário</span>
36
+ </div>
37
+ <div class="amp-wp-meta amp-wp-posted-on">
38
+ <time datetime="2016-05-10T18:05:36+00:00">
39
+ 11 months ago </time>
40
+ </div>
41
+ </header>
42
+
43
+ <figure class="amp-wp-article-featured-image wp-caption">
44
+ <amp-img width="525" height="298" src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg" class="attachment-large size-large wp-post-image amp-wp-enforced-sizes" alt="" srcset="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg 800w, http://blog.wod.expert/wp-content/uploads/2017/03/fail1-300x170.jpg 300w, http://blog.wod.expert/wp-content/uploads/2017/03/fail1-768x436.jpg 768w" sizes="(min-width: 525px) 525px, 100vw"></amp-img> <p class="wp-caption-text">
45
+ Flickr/crossfitpaleodietfitnessclassess </p>
46
+ </figure>
47
+
48
+ <div class="amp-wp-article-content">
49
+ <p>The first WOD we never forget! Just to be sure we are talking about same thing, WOD stands for “Workout of the Day”. You feel you’re already gone on the warm up session.</p>
50
+ <blockquote><p>“WOD stands for Workout of the Day”</p></blockquote>
51
+ <p>Most likely you won’t be the only one in that training session, so it might be your first, but you will feel that others on your side are lightyears above and in front of you. You look at those faces, and they seem to be feeling nothing, but you are dying to run 100 meters sprint, unable to do 10 air squats and completely unable to perform 10 pushups. One thing I gotta say to you: you’re not alone!</p>
52
+ <amp-carousel width="600" height="480" type="slides" layout="responsive"><amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail2.jpg" width="507" height="325" layout="responsive"></amp-img><amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail3.jpg" width="600" height="399" layout="responsive"></amp-img></amp-carousel><p>No matter which will be your very first workout. It can be one of the benchmark’s fancy named workouts or any unnamed workout, it doesn’t matter: you will “complete”, or better to say: you will suffer on it even just doing with the lightest weight on the box, using rubber, doing half of the repetitions, but still you will suck on performing it! Don’t feel ashamed of that!</p>
53
+ <p><amp-youtube data-videoid="P_uDhI-5FqE" layout="responsive" width="525" height="295"></amp-youtube></p>
54
+ <p>Have you made thru it? What was your feeling by the end, even not finishing, or doing half of workout? You will pick one side here: Either you will get addicted and return every day, or you will just drop out. Which one you took?</p>
55
+ <p>I guess I already know your answer, once you are coming here!</p>
56
+ <p>Welcome, crossfitter!</p>
57
+ </div>
58
+
59
+ <footer class="amp-wp-article-footer">
60
+ <div class="amp-wp-meta amp-wp-tax-category">
61
+ Categories: <a href="http://blog.wod.expert/category/motivational/" rel="category tag">motivational</a> </div>
62
+
63
+ </footer>
64
+
65
+ </article>
66
+
67
+ <footer class="amp-wp-footer">
68
+ <div>
69
+ <h2>Wod Expert</h2>
70
+ <p>
71
+ <a href="https://wordpress.org/">Powered by WordPress</a>
72
+ </p>
73
+ <a href="#top" class="back-to-top">Back to top</a>
74
+ </div>
75
+ </footer>
76
+
77
+
78
+ </body>
79
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/fail1.jpg ADDED
Binary file
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/fb_icon_325x325.png ADDED
Binary file
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/heart-rate-age-300x182.gif ADDED
Binary file
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/media-cache/timelapse-final-4x3.mp4 ADDED
Binary file
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test1-amp-converted.html ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/very-first-wod/"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(-21px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;text-transform: uppercase;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-header-bar {background-color: rgb(102,102,102);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;text-transform: none;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-article a {font-family: Georgia;text-decoration: underline;color: rgb(0,0,0);}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: BLOCK;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;display: INLINE;text-transform: none;background-color: rgb(0,255,255);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/*Global Styles*/ .ia2amp-header-bar { margin: -5px 0 0 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 16.4px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-header-h1 { font-size: 24px; line-height: 30px; display: block; font-weight: normal; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 { display: block; font-weight: normal; } .ia2amp-h1 { font-size: 19px; line-height: 23px; } .ia2amp-h2 { font-size: 16px; line-height: 20px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-p a { margin: 0; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; } .ia2amp-spacing { display: block; height: 18.8px; margin: 0 16.4px 0 16.4px; } header figure figcaption { display: none; } .ia2amp-figure { margin: 0; } .ia2amp-op-small h1, .ia2amp-op-small h2 { font-size: 10px; display: block; } .ia2amp-op-medium h1, .ia2amp-op-medium h2 { font-size: 14px; display: block; } .ia2amp-op-large h1, .ia2amp-op-large h2 { font-size: 16px; display: block; } .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 { font-size: 23px; display: block; } .ia2amp-figcaption cite { font-size: 8px; display: block; } .ia2amp-op-left { text-align: left; } .ia2amp-op-center { text-align: center; } .ia2amp-op-right { text-align: right; } .ia2amp-figure { position: relative; } figcaption.ia2amp-op-vertical-center { position: absolute; z-index: 1000; } .ia2amp-footer { display: block; font-size: 12px; line-height: 17px; } .ia2amp-footer aside p { margin: 0; } .ia2amp-spacing.after-header-bar.before-header-category { height: 18.8px; } .ia2amp-spacing.after-header-category.before-header-h1, .ia2amp-spacing.after-header-h1.before-header-h2 { height: 13.2px; } .ia2amp-spacing.after-h1.before-h2 { height: 13.2px; } .ia2amp-spacing.after-li.before-li { height: 13.2px; } .ia2amp-spacing.after-footer.before-footer { height: 18.8px; } .ia2amp-spacing.after-header-h1.before-header-author, .ia2amp-spacing.after-header-h2.before-header-author { height: 18.8px; } .ia2amp-spacing.after-header-author.before-header-date { height: 0; } .ia2amp-spacing.after-header-date.before-h1, .ia2amp-spacing.after-header-date.before-h2, .ia2amp-spacing.after-header-date.before-p { height: 26.4px; } .ia2amp-spacing.after-h1.before-p, .ia2amp-spacing.after-h2.before-p, .ia2amp-spacing.after-h3.before-p { height: 18.8px; } .ia2amp-spacing.after-blockquote.before-p { height: 18.8px; } .ia2amp-spacing.after-slideshow, .ia2amp-spacing.before-slideshow, .ia2amp-spacing.after-interactive, .ia2amp-spacing.before-interactive, .ia2amp-spacing.after-image, .ia2amp-spacing.before-image, .ia2amp-spacing.after-figcaption-small, .ia2amp-spacing.after-figcaption-medium, .ia2amp-spacing.after-figcaption-large, .ia2amp-spacing.after-figcaption-extra-large { height: 26.4px; } </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/very-first-wod/","headline":"Very First WOD!","datePublished":"2016-05-10T18:05:36+00:00","description":"The first WOD we never forget! Just to be sure we are talking about same thing, WOD stands for \u201cWorkout of the Day\u201d. \u00a0You feel you\u2019re already gone on the warm up session.","dateModified":"2017-03-17T16:46:07+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg","width":800,"height":454},"publisher":{"@type":"Organization","name":"WOD Expert","logo":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png","width":600,"height":60}}}</script>
13
+ <title>Very First WOD!</title>
14
+ <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
15
+ <script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>
16
+ </head>
17
+ <body class="ia2amp-body">
18
+ <header class="ia2amp-header">
19
+ <div class="ia2amp-cover-image">
20
+ <figure class="ia2amp-figure">
21
+ <amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg" width="422" height="240"></amp-img>
22
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">Flickr/crossfitpaleodietfitnessclassess</figcaption>
23
+ </figure>
24
+ </div>
25
+ <div class="ia2amp-header-bar">
26
+ <div class="ia2amp-header-bar-img-container">
27
+ <amp-img src="https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&amp;oh=c8337650a88e7fdb6d31088a15a7d9d8&amp;oe=599B24B5&amp;__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8" width="223" height="44"></amp-img>
28
+ </div>
29
+ </div>
30
+ <div class="ia2amp-spacing after-header-bar before-header-category"></div>
31
+ <h2 class="ia2amp-header-category">motivational</h2>
32
+ <div class="ia2amp-spacing after-header-category before-header-h1"></div>
33
+ <h1 class="ia2amp-header-h1">Very First WOD!</h1>
34
+ <div class="ia2amp-spacing after-header-h1 before-header-h2"></div>
35
+ <h2 class="ia2amp-header-h2">It's great to see you here</h2>
36
+ <div class="ia2amp-spacing after-header-h2 before-header-author"></div>
37
+ <h3 class="ia2amp-header-author">By Éverton Rosário</h3>
38
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
39
+ <h3 class="ia2amp-header-date">May 10, 2016</h3>
40
+ <div class="ia2amp-spacing after-header-date before-p"></div>
41
+ </header>
42
+ <article class="ia2amp-article">
43
+ <p class="ia2amp-p">The first <em>WOD</em> we never forget! Just to be sure we are talking about same thing, WOD stands for “Workout of the Day”.  You feel you’re already gone on the warm up session.</p>
44
+ <div class="ia2amp-spacing after-p before-blockquote"></div>
45
+ <blockquote class="ia2amp-blockquote">“WOD stands for Workout of the Day”</blockquote>
46
+ <div class="ia2amp-spacing after-blockquote before-p"></div>
47
+ <p class="ia2amp-p">Most likely you won’t be the only one in that training session, so it might be your first, but you will feel that others on your side are lightyears above and in front of you. You look at those faces, and they seem to be feeling nothing, but you are dying to run 100 meters sprint, unable to do 10 air squats and completely unable to perform 10 pushups.  One thing I gotta say to you: you’re not alone!</p>
48
+ <div class="ia2amp-spacing after-p before-slideshow"></div>
49
+ <div class="ia2amp-slideshow">
50
+ <amp-carousel width="380" height="240">
51
+ <div class="ia2amp-slideshow-image">
52
+ <figure class="ia2amp-figure">
53
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail2.jpg" width="380" height="240"></amp-img>
54
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>
55
+ twopalswiththoughts
56
+ </h1></figcaption>
57
+ </figure>
58
+ </div>
59
+ <div class="ia2amp-slideshow-image">
60
+ <figure class="ia2amp-figure">
61
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail3.jpg" width="380" height="240"></amp-img>
62
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>
63
+ Flickr: crossfitpaleodietfitnessclasses
64
+ </h1></figcaption>
65
+ </figure>
66
+ </div>
67
+ </amp-carousel>
68
+ </div>
69
+ <div class="ia2amp-spacing after-slideshow before-p"></div>
70
+ <p class="ia2amp-p">No matter which will be your very first workout. It can be one of the benchmark’s fancy named workouts or any unnamed workout, it doesn’t matter: you will “complete”, or better to say: you will suffer on it even just doing with the lightest weight on the box, using rubber, doing half of the repetitions, but still you will suck on performing it! Don’t feel ashamed of that!</p>
71
+ <div class="ia2amp-spacing after-p before-interactive"></div>
72
+ <div class="ia2amp-interactive">
73
+ <amp-iframe src="https://www.youtube.com/embed/P_uDhI-5FqE?start=258&amp;feature=oembed" width="380" height="240" sandbox="allow-scripts allow-same-origin" layout="responsive" frameborder="0"></amp-iframe>
74
+ </div>
75
+ <div class="ia2amp-spacing after-interactive before-p"></div>
76
+ <p class="ia2amp-p">Have you made thru it? What was your feeling by the end, even not finishing, or doing half of workout? You will pick one side here: Either you will get addicted and return every day, or you will just drop out. Which one you took?</p>
77
+ <div class="ia2amp-spacing after-p before-p"></div>
78
+ <p class="ia2amp-p">I guess I already know your answer, once you are coming here!</p>
79
+ <div class="ia2amp-spacing after-p before-p"></div>
80
+ <p class="ia2amp-p">Welcome, crossfitter!</p>
81
+ <div class="ia2amp-spacing after-p"></div>
82
+ <footer class="ia2amp-footer">
83
+ <aside>
84
+ <p>WOD Expert</p>
85
+ </aside>
86
+ <small>© 2017 WOD Expert</small>
87
+ </footer>
88
+ </article>
89
+ </body>
90
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test1-instant-article.html ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <link rel="canonical" href="http://blog.wod.expert/very-first-wod/"/>
4
+ <meta charset="utf-8"/>
5
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
6
+ <meta property="op:generator:version" content="1.0.0"/>
7
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
8
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
9
+ <meta property="op:markup_version" content="v1.0"/>
10
+ <meta property="fb:article_style" content="wod-gray"/>
11
+ </head>
12
+ <body>
13
+ <article>
14
+ <header>
15
+ <figure>
16
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail1.jpg"/>
17
+ <figcaption>Flickr/crossfitpaleodietfitnessclassess</figcaption>
18
+ </figure>
19
+ <h1>Very First WOD!</h1>
20
+ <h2>It's great to see you here</h2>
21
+ <time class="op-published" datetime="2016-05-10T18:05:36+00:00">May 10th, 6:05pm</time>
22
+ <time class="op-modified" datetime="2017-03-17T16:46:07+00:00">March 17th, 4:46pm</time>
23
+ <address><a>Éverton Rosário</a></address>
24
+ <h3 class="op-kicker">motivational</h3>
25
+ </header>
26
+ <p>The first <em>WOD</em> we never forget! Just to be sure we are talking about same thing, WOD stands for “Workout of the Day”.  You feel you’re already gone on the warm up session.</p>
27
+ <blockquote>“WOD stands for Workout of the Day”</blockquote>
28
+ <p>Most likely you won’t be the only one in that training session, so it might be your first, but you will feel that others on your side are lightyears above and in front of you. You look at those faces, and they seem to be feeling nothing, but you are dying to run 100 meters sprint, unable to do 10 air squats and completely unable to perform 10 pushups.  One thing I gotta say to you: you’re not alone!</p>
29
+ <figure class="op-slideshow">
30
+ <figure>
31
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail2.jpg"/>
32
+ <figcaption>
33
+ twopalswiththoughts
34
+ </figcaption>
35
+ </figure>
36
+ <figure>
37
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/fail3.jpg"/>
38
+ <figcaption>
39
+ Flickr: crossfitpaleodietfitnessclasses
40
+ </figcaption>
41
+ </figure>
42
+ </figure>
43
+ <p>No matter which will be your very first workout. It can be one of the benchmark’s fancy named workouts or any unnamed workout, it doesn’t matter: you will “complete”, or better to say: you will suffer on it even just doing with the lightest weight on the box, using rubber, doing half of the repetitions, but still you will suck on performing it! Don’t feel ashamed of that!</p>
44
+ <figure class="op-interactive">
45
+ <iframe src="https://www.youtube.com/embed/P_uDhI-5FqE?start=258&amp;feature=oembed" class="no-margin" width="525" height="295"></iframe>
46
+ </figure>
47
+ <p>Have you made thru it? What was your feeling by the end, even not finishing, or doing half of workout? You will pick one side here: Either you will get addicted and return every day, or you will just drop out. Which one you took?</p>
48
+ <p>I guess I already know your answer, once you are coming here!</p>
49
+ <p>Welcome, crossfitter!</p>
50
+ <footer>
51
+ <aside>
52
+ <p>WOD Expert</p>
53
+ </aside>
54
+ <small>© 2017 WOD Expert</small>
55
+ </footer>
56
+ </article>
57
+ </body>
58
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test2-amp-converted.html ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/break-your-reps-before-you-die/"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(0px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;text-transform: uppercase;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-header-bar {background-color: rgb(102,102,102);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;text-transform: none;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-article a {font-family: Georgia;text-decoration: underline;color: rgb(0,0,0);}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: BLOCK;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;display: INLINE;text-transform: none;background-color: rgb(0,255,255);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/*Global Styles*/ .ia2amp-header-bar { margin: -5px 0 0 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 16.4px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-header-h1 { font-size: 24px; line-height: 30px; display: block; font-weight: normal; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 { display: block; font-weight: normal; } .ia2amp-h1 { font-size: 19px; line-height: 23px; } .ia2amp-h2 { font-size: 16px; line-height: 20px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-p a { margin: 0; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; } .ia2amp-spacing { display: block; height: 18.8px; margin: 0 16.4px 0 16.4px; } header figure figcaption { display: none; } .ia2amp-figure { margin: 0; } .ia2amp-op-small h1, .ia2amp-op-small h2 { font-size: 10px; display: block; } .ia2amp-op-medium h1, .ia2amp-op-medium h2 { font-size: 14px; display: block; } .ia2amp-op-large h1, .ia2amp-op-large h2 { font-size: 16px; display: block; } .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 { font-size: 23px; display: block; } .ia2amp-figcaption cite { font-size: 8px; display: block; } .ia2amp-op-left { text-align: left; } .ia2amp-op-center { text-align: center; } .ia2amp-op-right { text-align: right; } .ia2amp-figure { position: relative; } figcaption.ia2amp-op-vertical-center { position: absolute; z-index: 1000; } .ia2amp-footer { display: block; font-size: 12px; line-height: 17px; } .ia2amp-footer aside p { margin: 0; } .ia2amp-spacing.after-header-bar.before-header-category { height: 18.8px; } .ia2amp-spacing.after-header-category.before-header-h1, .ia2amp-spacing.after-header-h1.before-header-h2 { height: 13.2px; } .ia2amp-spacing.after-h1.before-h2 { height: 13.2px; } .ia2amp-spacing.after-li.before-li { height: 13.2px; } .ia2amp-spacing.after-footer.before-footer { height: 18.8px; } .ia2amp-spacing.after-header-h1.before-header-author, .ia2amp-spacing.after-header-h2.before-header-author { height: 18.8px; } .ia2amp-spacing.after-header-author.before-header-date { height: 0; } .ia2amp-spacing.after-header-date.before-h1, .ia2amp-spacing.after-header-date.before-h2, .ia2amp-spacing.after-header-date.before-p { height: 26.4px; } .ia2amp-spacing.after-h1.before-p, .ia2amp-spacing.after-h2.before-p, .ia2amp-spacing.after-h3.before-p { height: 18.8px; } .ia2amp-spacing.after-blockquote.before-p { height: 18.8px; } .ia2amp-spacing.after-slideshow, .ia2amp-spacing.before-slideshow, .ia2amp-spacing.after-interactive, .ia2amp-spacing.before-interactive, .ia2amp-spacing.after-image, .ia2amp-spacing.before-image, .ia2amp-spacing.after-figcaption-small, .ia2amp-spacing.after-figcaption-medium, .ia2amp-spacing.after-figcaption-large, .ia2amp-spacing.after-figcaption-extra-large { height: 26.4px; } </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/break-your-reps-before-you-die/","headline":"Break your reps, before you die!","datePublished":"2016-05-17T12:47:46+00:00","description":"Having a good strategy to tackle the series in WODs are fundamental to achieve the best result given your particular physical condition. Comparing yourself to the top athletes, or trying to use their strategy probably won\u2019t work well, unless you are a top athlete! By good strategy I mean planing basically how fast you will perform your movements and how you will play your pauses. There is no better person in the world to know you better than yourself.","dateModified":"2017-03-17T16:45:18+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/03/wod-break.jpg","width":380,"height":240},"publisher":{"@type":"Organization","name":"WOD Expert","logo":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png","width":600,"height":60}}}</script>
13
+ <title>Break your reps, before you die!</title>
14
+ </head>
15
+ <body class="ia2amp-body">
16
+ <header class="ia2amp-header">
17
+ <div class="ia2amp-cover-image">
18
+ <amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/03/wod-break.jpg" width="380" height="240"></amp-img>
19
+ </div>
20
+ <div class="ia2amp-header-bar">
21
+ <div class="ia2amp-header-bar-img-container">
22
+ <amp-img src="https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&amp;oh=c8337650a88e7fdb6d31088a15a7d9d8&amp;oe=599B24B5&amp;__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8" width="223" height="44"></amp-img>
23
+ </div>
24
+ </div>
25
+ <div class="ia2amp-spacing after-header-bar before-header-category"></div>
26
+ <h2 class="ia2amp-header-category">exercise</h2>
27
+ <div class="ia2amp-spacing after-header-category before-header-h1"></div>
28
+ <h1 class="ia2amp-header-h1">Break your reps, before you die!</h1>
29
+ <div class="ia2amp-spacing after-header-h1 before-header-author"></div>
30
+ <h3 class="ia2amp-header-author">By Éverton Rosário</h3>
31
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
32
+ <h3 class="ia2amp-header-date">May 17, 2016</h3>
33
+ <div class="ia2amp-spacing after-header-date before-p"></div>
34
+ </header>
35
+ <article class="ia2amp-article">
36
+ <p class="ia2amp-p">Having a good strategy to tackle the series in WODs are fundamental to achieve the best result given your particular physical condition. Comparing yourself to the top athletes, or trying to use their strategy probably won’t work well, unless you are a top athlete! By good strategy I mean planing basically how fast you will perform your movements and how you will play your pauses. There is no better person in the world to know you better than yourself.</p>
37
+ <div class="ia2amp-spacing after-p before-p"></div>
38
+ <p class="ia2amp-p">But firstly you gotta understand better how your body responds to exercise and how you gotta plan given your body symptoms.</p>
39
+ <div class="ia2amp-spacing after-p before-p"></div>
40
+ <p class="ia2amp-p">One of the three main areas to observe here are: heart rate, breathing and muscle energy.</p>
41
+ <div class="ia2amp-spacing after-p before-h2"></div>
42
+ <h2 class="ia2amp-h2">Heart Rate</h2>
43
+ <div class="ia2amp-spacing after-h2 before-p"></div>
44
+ <p class="ia2amp-p">Heart rate is commonly measured in beats per minute and it measures how fast your heart is pumping blood to your body. When performing your exercises in the WOD your body is moving lots of muscles, so heart needs to keep oxygen level to your muscles, so it keeps working well.</p>
45
+ <div class="ia2amp-spacing after-p before-p"></div>
46
+ <p class="ia2amp-p">Few characteristics influence how efficient you heart works, as more prepared you are, more efficient you heart works. Good to mention that you heart is also a muscle that by exercising in your WODs will also improve your heart condition. The heart beat at rest is one of good indicators on how well you are prepared, as top athletes have rest heart rate slightly slower than regular people.</p>
47
+ <div class="ia2amp-spacing after-p before-figcaption-small"></div>
48
+ <div class="ia2amp-image">
49
+ <figure class="ia2amp-figure">
50
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2017/03/heart-rate-age-300x182.gif" width="380" height="240"></amp-img>
51
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">The heart rate per age</figcaption>
52
+ </figure>
53
+ </div>
54
+ <div class="ia2amp-spacing after-figcaption-small before-p"></div>
55
+ <p class="ia2amp-p">Warning about heart rate is that, if in only few reps you get your heart rate close to maximum and this is going to be a long series. Example: your heart rate skyrocket getting close to the max at your age with only 5 reps, but the workout is about performing 50 reps, so you seriously need to review and lower the weights you will use.</p>
56
+ <div class="ia2amp-spacing after-p before-p"></div>
57
+ <p class="ia2amp-p">During training you gotta keep close attention to your heart rate, and if you are getting into your red zone, you definitely will need a pause. But pause before you get there, otherwise it will be slower to recover once you are close to the max.</p>
58
+ <div class="ia2amp-spacing after-p before-p"></div>
59
+ <p class="ia2amp-p">Using heart monitors will be a good aid by checking how your heart rating changes during your workout. As higher your heart goes, higher your breathing frequency goes</p>
60
+ <div class="ia2amp-spacing after-p before-h2"></div>
61
+ <h2 class="ia2amp-h2">Breathing</h2>
62
+ <div class="ia2amp-spacing after-h2 before-p"></div>
63
+ <p class="ia2amp-p">During your series you will feel and observe yourself catching your breath in between the reps. This happens once you get closer to the max heart beat and you need to keep your oxygen levels in your body good enough so you keep contracting your muscles.</p>
64
+ <div class="ia2amp-spacing after-p before-p"></div>
65
+ <p class="ia2amp-p">When you reach that respiration frequency, where it is too fast inhaling and exhaling, you will waste too much time catching your breath. Plan to break your workout few reps before you reach that level. This will make your recovering faster.</p>
66
+ <div class="ia2amp-spacing after-p before-p"></div>
67
+ <p class="ia2amp-p">Once you reach this situation of inhale exhale to fast, and probably this will happen frequently, enforce yourself to exhale with more power, this will make your lungs go empty and inhaling more fresh air, thus, being more efficient about taking oxygen to your body, then your heart beat will slow down. Respiration frequency is really attached to your heart rate, and the influence occurs in both ways: heart beating influencing breathing frequency and vice-versa.</p>
68
+ <div class="ia2amp-spacing after-p before-h2"></div>
69
+ <h2 class="ia2amp-h2">Muscle energy</h2>
70
+ <div class="ia2amp-spacing after-h2 before-p"></div>
71
+ <p class="ia2amp-p">By muscle energy I mean how ready your muscle is to perform one more contraction, with what power. To lift a weight or to perform the exercises during your WOD you will have lots of muscle contractions. Going deeper and understand what it takes for a muscle to contract, it will basically need to have your celular respiration and ATP working well. Just to remember it requires glucose, oxygen and strong muscle fibers. Once all requirements are met, you will successfully contract that muscle, thus executing the rep. Those three are fundamental.</p>
72
+ <div class="ia2amp-spacing after-p before-image"></div>
73
+ <div class="ia2amp-image">
74
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2017/03/muscles-300x255.jpg" width="380" height="240"></amp-img>
75
+ </div>
76
+ <div class="ia2amp-spacing after-image before-p"></div>
77
+ <p class="ia2amp-p">Glucose -&amp;gt; connected to your nutrition quality and how well you are eating before your workouts</p>
78
+ <div class="ia2amp-spacing after-p before-p"></div>
79
+ <p class="ia2amp-p">Oxygen -&amp;gt; How efficiency your breathing is and how well your heart rate is pumping the oxygen thru your blood.</p>
80
+ <div class="ia2amp-spacing after-p before-p"></div>
81
+ <p class="ia2amp-p">Strong muscle fibers -&amp;gt; That weight shouldn’t be heavier than your max for that movement.</p>
82
+ <div class="ia2amp-spacing after-p before-p"></div>
83
+ <p class="ia2amp-p">As you exercise during your workout, you will feel your breathing go faster, and this is something you should try to avoid while contracting your muscles, because once you are contracting your muscles without the proper oxygen levels, you start the glycolysis process, which generates lactic acid causing your muscle fatigue.</p>
84
+ <div class="ia2amp-spacing after-p before-h2"></div>
85
+ <h2 class="ia2amp-h2">All connected</h2>
86
+ <div class="ia2amp-spacing after-h2 before-p"></div>
87
+ <p class="ia2amp-p">As we can see, the 3 are all deeply connected. Getting more fitness prepared includes being stronger, good VO2 max and faster heart rating recovering. Being stronger will play one of the key differences here, since you will need less effort to perform the same exercise, thus keeping lower heart rate and breathing frequency. Once maybe you are not really strong you gotta keep checking your heart beat and breathing so you can stop before you get to the dying zone near your maximum. Once you get to your max, it is slower to recover.</p>
88
+ <div class="ia2amp-spacing after-p before-image"></div>
89
+ <div class="ia2amp-image">
90
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2017/03/running-fatigue-277x300.jpg" width="380" height="240"></amp-img>
91
+ </div>
92
+ <div class="ia2amp-spacing after-image"></div>
93
+ </article>
94
+ </body>
95
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test2-instant-article.html ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <html>
3
+ <head>
4
+ <link rel="canonical" href="http://blog.wod.expert/break-your-reps-before-you-die/" />
5
+ <meta charset="utf-8" />
6
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
7
+ <meta property="op:generator:version" content="1.0.0"/>
8
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
9
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
10
+ <meta property="op:markup_version" content="v1.0"/>
11
+ <meta property="fb:article_style" content="wod-gray"/>
12
+ </head>
13
+ <body>
14
+ <article>
15
+ <header>
16
+ <figure>
17
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/wod-break.jpg" />
18
+ </figure>
19
+ <h1>Break your reps, before you die!</h1>
20
+ <time class="op-published" datetime="2016-05-17T12:47:46+00:00">May 17th, 12:47pm</time>
21
+ <time class="op-modified" datetime="2017-03-17T16:45:18+00:00">March 17th, 4:45pm</time>
22
+ <address>
23
+ <a>Éverton Rosário</a>
24
+ </address>
25
+ <h3 class="op-kicker">exercise</h3>
26
+ </header>
27
+ <p>Having a good strategy to tackle the series in WODs are fundamental to achieve the best result given your particular physical condition. Comparing yourself to the top athletes, or trying to use their strategy probably won’t work well, unless you are a top athlete! By good strategy I mean planing basically how fast you will perform your movements and how you will play your pauses. There is no better person in the world to know you better than yourself.</p>
28
+ <p>But firstly you gotta understand better how your body responds to exercise and how you gotta plan given your body symptoms.</p>
29
+ <p>One of the three main areas to observe here are: heart rate, breathing and muscle energy.</p>
30
+ <h2>Heart Rate</h2>
31
+ <p>Heart rate is commonly measured in beats per minute and it measures how fast your heart is pumping blood to your body. When performing your exercises in the WOD your body is moving lots of muscles, so heart needs to keep oxygen level to your muscles, so it keeps working well.</p>
32
+ <p>Few characteristics influence how efficient you heart works, as more prepared you are, more efficient you heart works. Good to mention that you heart is also a muscle that by exercising in your WODs will also improve your heart condition. The heart beat at rest is one of good indicators on how well you are prepared, as top athletes have rest heart rate slightly slower than regular people.</p>
33
+ <figure>
34
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/heart-rate-age-300x182.gif" />
35
+ <figcaption>The heart rate per age</figcaption>
36
+ </figure>
37
+ <p>Warning about heart rate is that, if in only few reps you get your heart rate close to maximum and this is going to be a long series. Example: your heart rate skyrocket getting close to the max at your age with only 5 reps, but the workout is about performing 50 reps, so you seriously need to review and lower the weights you will use.</p>
38
+ <p>During training you gotta keep close attention to your heart rate, and if you are getting into your red zone, you definitely will need a pause. But pause before you get there, otherwise it will be slower to recover once you are close to the max.</p>
39
+ <p>Using heart monitors will be a good aid by checking how your heart rating changes during your workout. As higher your heart goes, higher your breathing frequency goes</p>
40
+ <h2>Breathing</h2>
41
+ <p>During your series you will feel and observe yourself catching your breath in between the reps. This happens once you get closer to the max heart beat and you need to keep your oxygen levels in your body good enough so you keep contracting your muscles.</p>
42
+ <p>When you reach that respiration frequency, where it is too fast inhaling and exhaling, you will waste too much time catching your breath. Plan to break your workout few reps before you reach that level. This will make your recovering faster.</p>
43
+ <p>Once you reach this situation of inhale exhale to fast, and probably this will happen frequently, enforce yourself to exhale with more power, this will make your lungs go empty and inhaling more fresh air, thus, being more efficient about taking oxygen to your body, then your heart beat will slow down. Respiration frequency is really attached to your heart rate, and the influence occurs in both ways: heart beating influencing breathing frequency and vice-versa.</p>
44
+ <h2>Muscle energy</h2>
45
+ <p>By muscle energy I mean how ready your muscle is to perform one more contraction, with what power. To lift a weight or to perform the exercises during your WOD you will have lots of muscle contractions. Going deeper and understand what it takes for a muscle to contract, it will basically need to have your celular respiration and ATP working well. Just to remember it requires glucose, oxygen and strong muscle fibers. Once all requirements are met, you will successfully contract that muscle, thus executing the rep. Those three are fundamental.</p>
46
+ <figure>
47
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/muscles-300x255.jpg" />
48
+ </figure>
49
+ <p>Glucose -&amp;gt; connected to your nutrition quality and how well you are eating before your workouts</p>
50
+ <p>Oxygen -&amp;gt; How efficiency your breathing is and how well your heart rate is pumping the oxygen thru your blood.</p>
51
+ <p>Strong muscle fibers -&amp;gt; That weight shouldn’t be heavier than your max for that movement.</p>
52
+ <p>As you exercise during your workout, you will feel your breathing go faster, and this is something you should try to avoid while contracting your muscles, because once you are contracting your muscles without the proper oxygen levels, you start the glycolysis process, which generates lactic acid causing your muscle fatigue.</p>
53
+ <h2>All connected</h2>
54
+ <p>As we can see, the 3 are all deeply connected. Getting more fitness prepared includes being stronger, good VO2 max and faster heart rating recovering. Being stronger will play one of the key differences here, since you will need less effort to perform the same exercise, thus keeping lower heart rate and breathing frequency. Once maybe you are not really strong you gotta keep checking your heart beat and breathing so you can stop before you get to the dying zone near your maximum. Once you get to your max, it is slower to recover.</p>
55
+ <figure>
56
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/running-fatigue-277x300.jpg" />
57
+ </figure>
58
+ </article>
59
+ </body>
60
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test3-amp-converted.html ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/open-2017/"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(0px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;text-transform: uppercase;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-header-bar {background-color: rgb(102,102,102);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;text-transform: none;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-article a {font-family: Georgia;text-decoration: underline;color: rgb(0,0,0);}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: BLOCK;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;display: INLINE;text-transform: none;background-color: rgb(0,255,255);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/*Global Styles*/ .ia2amp-header-bar { margin: -5px 0 0 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 16.4px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-header-h1 { font-size: 24px; line-height: 30px; display: block; font-weight: normal; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 { display: block; font-weight: normal; } .ia2amp-h1 { font-size: 19px; line-height: 23px; } .ia2amp-h2 { font-size: 16px; line-height: 20px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-p a { margin: 0; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; } .ia2amp-spacing { display: block; height: 18.8px; margin: 0 16.4px 0 16.4px; } header figure figcaption { display: none; } .ia2amp-figure { margin: 0; } .ia2amp-op-small h1, .ia2amp-op-small h2 { font-size: 10px; display: block; } .ia2amp-op-medium h1, .ia2amp-op-medium h2 { font-size: 14px; display: block; } .ia2amp-op-large h1, .ia2amp-op-large h2 { font-size: 16px; display: block; } .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 { font-size: 23px; display: block; } .ia2amp-figcaption cite { font-size: 8px; display: block; } .ia2amp-op-left { text-align: left; } .ia2amp-op-center { text-align: center; } .ia2amp-op-right { text-align: right; } .ia2amp-figure { position: relative; } figcaption.ia2amp-op-vertical-center { position: absolute; z-index: 1000; } .ia2amp-footer { display: block; font-size: 12px; line-height: 17px; } .ia2amp-footer aside p { margin: 0; } .ia2amp-spacing.after-header-bar.before-header-category { height: 18.8px; } .ia2amp-spacing.after-header-category.before-header-h1, .ia2amp-spacing.after-header-h1.before-header-h2 { height: 13.2px; } .ia2amp-spacing.after-h1.before-h2 { height: 13.2px; } .ia2amp-spacing.after-li.before-li { height: 13.2px; } .ia2amp-spacing.after-footer.before-footer { height: 18.8px; } .ia2amp-spacing.after-header-h1.before-header-author, .ia2amp-spacing.after-header-h2.before-header-author { height: 18.8px; } .ia2amp-spacing.after-header-author.before-header-date { height: 0; } .ia2amp-spacing.after-header-date.before-h1, .ia2amp-spacing.after-header-date.before-h2, .ia2amp-spacing.after-header-date.before-p { height: 26.4px; } .ia2amp-spacing.after-h1.before-p, .ia2amp-spacing.after-h2.before-p, .ia2amp-spacing.after-h3.before-p { height: 18.8px; } .ia2amp-spacing.after-blockquote.before-p { height: 18.8px; } .ia2amp-spacing.after-slideshow, .ia2amp-spacing.before-slideshow, .ia2amp-spacing.after-interactive, .ia2amp-spacing.before-interactive, .ia2amp-spacing.after-image, .ia2amp-spacing.before-image, .ia2amp-spacing.after-figcaption-small, .ia2amp-spacing.after-figcaption-medium, .ia2amp-spacing.after-figcaption-large, .ia2amp-spacing.after-figcaption-extra-large { height: 26.4px; } </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/open-2017/","headline":"Open 2017","datePublished":"2017-02-24T22:30:40+00:00","description":"\n The\n CrossFit Games\n are coming and the Open is the very first step for anyone try to fight for a spot on the regionals, then on the games! Pretty much almost all other sport modalities have a pre-selected group of athletes, teams or league affiliates. Sometimes the path is simply impossible: Try to get your football team to play on the NFL, it will be simply something near impossible, no matter how good that team is. Of course if your team is not part of the League you simply can\u2019t. Not going into the merits of having a team on NFL, since this is not the point here.\n ","dateModified":"2017-04-05T17:57:54+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/02/CrossFitGamesLogo-wide.png","width":380,"height":240},"publisher":{"@type":"Organization","name":"WOD Expert","logo":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png","width":600,"height":60}}}</script>
13
+ <title>Open 2017</title>
14
+ <script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
15
+ </head>
16
+ <body class="ia2amp-body">
17
+ <header class="ia2amp-header">
18
+ <div class="ia2amp-cover-image">
19
+ <figure class="ia2amp-figure">
20
+ <amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/02/CrossFitGamesLogo-wide.png" width="380" height="240"></amp-img>
21
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">CrossFit Games 2017 Logo</figcaption>
22
+ </figure>
23
+ </div>
24
+ <div class="ia2amp-header-bar">
25
+ <div class="ia2amp-header-bar-img-container">
26
+ <amp-img src="https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&amp;oh=c8337650a88e7fdb6d31088a15a7d9d8&amp;oe=599B24B5&amp;__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8" width="223" height="44"></amp-img>
27
+ </div>
28
+ </div>
29
+ <div class="ia2amp-spacing after-header-bar before-header-h1"></div>
30
+ <h1 class="ia2amp-header-h1">Open 2017</h1>
31
+ <div class="ia2amp-spacing after-header-h1 before-header-author"></div>
32
+ <h3 class="ia2amp-header-author">By Éverton Rosário</h3>
33
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
34
+ <h3 class="ia2amp-header-date">February 24, 2017</h3>
35
+ <div class="ia2amp-spacing after-header-date before-p"></div>
36
+ </header>
37
+ <article class="ia2amp-article">
38
+ <p class="ia2amp-p">
39
+ The
40
+ <a href="http://games.crossfit.com">CrossFit Games</a>
41
+ are coming and the Open is the very first step for anyone try to fight for a spot on the regionals, then on the games! Pretty much almost all other sport modalities have a pre-selected group of athletes, teams or league affiliates. Sometimes the path is simply impossible: Try to get your football team to play on the NFL, it will be simply something near impossible, no matter how good that team is. Of course if your team is not part of the League you simply can’t. Not going into the merits of having a team on NFL, since this is not the point here.
42
+ </p>
43
+ <div class="ia2amp-spacing after-p before-p"></div>
44
+ <p class="ia2amp-p">What I’m claiming is that is really hard for most of the athletes, no matter the modality to get a spot on the highlight competition from that sport. This goes from olympic sports to any worldwide league.</p>
45
+ <div class="ia2amp-spacing after-p before-p"></div>
46
+ <p class="ia2amp-p">In the CrossFit Games, there is no such a thing. And the Open is the very first step in, to fight for your spot to shine. It relies only on you and your results. Once you get your spot on the regionals, you are one step closer to the Games.</p>
47
+ <div class="ia2amp-spacing after-p before-p"></div>
48
+ <p class="ia2amp-p">Let the Open begin! Here you will follow and have easy access to all content needed to follow up about the Open. Keep posted, since this is a dynamic post and will be regularly update once a week after each announcement and results pops out.</p>
49
+ <div class="ia2amp-spacing after-p before-p"></div>
50
+ <p class="ia2amp-p">Are you competing? Please make sure you will survive, and good luck! 😉</p>
51
+ <div class="ia2amp-spacing after-p before-h2"></div>
52
+ <h2 class="ia2amp-h2">17.1</h2>
53
+ <div class="ia2amp-spacing after-h2 before-figcaption-small"></div>
54
+ <div class="ia2amp-video">
55
+ <figure class="ia2amp-figure">
56
+ <amp-video src="https://www.facebook.com/CrossFitGames/videos/1423437551031432/" width="380" height="240"></amp-video>
57
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">17.1 Announcement</figcaption>
58
+ </figure>
59
+ </div>
60
+ <div class="ia2amp-spacing after-figcaption-small before-h2"></div>
61
+ <h2 class="ia2amp-h2">17.2</h2>
62
+ <div class="ia2amp-spacing after-h2 before-figcaption-small"></div>
63
+ <div class="ia2amp-video">
64
+ <figure class="ia2amp-figure">
65
+ <amp-video src="https://www.facebook.com/CrossFitGames/videos/1431391013569419/" width="380" height="240"></amp-video>
66
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">17.2 Announcement</figcaption>
67
+ </figure>
68
+ </div>
69
+ <div class="ia2amp-spacing after-figcaption-small before-h2"></div>
70
+ <h2 class="ia2amp-h2">17.3</h2>
71
+ <div class="ia2amp-spacing after-h2 before-figcaption-small"></div>
72
+ <div class="ia2amp-video">
73
+ <figure class="ia2amp-figure">
74
+ <amp-video src="https://www.facebook.com/CrossFitGames/videos/1439636189411568/" width="380" height="240"></amp-video>
75
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">17.3 Announcement</figcaption>
76
+ </figure>
77
+ </div>
78
+ <div class="ia2amp-spacing after-figcaption-small before-h2"></div>
79
+ <h2 class="ia2amp-h2">17.4</h2>
80
+ <div class="ia2amp-spacing after-h2 before-figcaption-small"></div>
81
+ <div class="ia2amp-video">
82
+ <figure class="ia2amp-figure">
83
+ <amp-video src="https://www.facebook.com/CrossFitGames/videos/1447649318610255/" width="380" height="240"></amp-video>
84
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">17.4 Announcement</figcaption>
85
+ </figure>
86
+ </div>
87
+ <div class="ia2amp-spacing after-figcaption-small before-h2"></div>
88
+ <h2 class="ia2amp-h2">17.5</h2>
89
+ <div class="ia2amp-spacing after-h2 before-figcaption-small"></div>
90
+ <div class="ia2amp-video">
91
+ <figure class="ia2amp-figure">
92
+ <amp-video src="https://www.facebook.com/CrossFitGames/videos/1456025707772616/" width="380" height="240"></amp-video>
93
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">17.5 Announcement</figcaption>
94
+ </figure>
95
+ </div>
96
+ <div class="ia2amp-spacing after-figcaption-small"></div>
97
+ </article>
98
+ </body>
99
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test3-instant-article.html ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <html>
3
+ <head>
4
+ <link rel="canonical" href="http://blog.wod.expert/open-2017/" />
5
+ <meta charset="utf-8" />
6
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
7
+ <meta property="op:generator:version" content="1.0.0"/>
8
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
9
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
10
+ <meta property="op:markup_version" content="v1.0"/>
11
+ <meta property="fb:article_style" content="wod-gray"/>
12
+ </head>
13
+ <body>
14
+ <article>
15
+ <header>
16
+ <figure>
17
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/02/CrossFitGamesLogo-wide.png" />
18
+ <figcaption>CrossFit Games 2017 Logo</figcaption>
19
+ </figure>
20
+ <h1>Open 2017</h1>
21
+ <time class="op-published" datetime="2017-02-24T22:30:40+00:00">February 24th, 10:30pm</time>
22
+ <time class="op-modified" datetime="2017-04-05T17:57:54+00:00">April 5th, 5:57pm</time>
23
+ <address>
24
+ <a>Éverton Rosário</a>
25
+ </address>
26
+ </header>
27
+ <p>
28
+ The
29
+ <a href="http://games.crossfit.com">CrossFit Games</a>
30
+ are coming and the Open is the very first step for anyone try to fight for a spot on the regionals, then on the games! Pretty much almost all other sport modalities have a pre-selected group of athletes, teams or league affiliates. Sometimes the path is simply impossible: Try to get your football team to play on the NFL, it will be simply something near impossible, no matter how good that team is. Of course if your team is not part of the League you simply can’t. Not going into the merits of having a team on NFL, since this is not the point here.
31
+ </p>
32
+ <p>What I’m claiming is that is really hard for most of the athletes, no matter the modality to get a spot on the highlight competition from that sport. This goes from olympic sports to any worldwide league.</p>
33
+ <p>In the CrossFit Games, there is no such a thing. And the Open is the very first step in, to fight for your spot to shine. It relies only on you and your results. Once you get your spot on the regionals, you are one step closer to the Games.</p>
34
+ <p>Let the Open begin! Here you will follow and have easy access to all content needed to follow up about the Open. Keep posted, since this is a dynamic post and will be regularly update once a week after each announcement and results pops out.</p>
35
+ <p>Are you competing? Please make sure you will survive, and good luck! &#x1f609;</p>
36
+ <h2>17.1</h2>
37
+ <figure>
38
+ <video>
39
+ <source src="https://www.facebook.com/CrossFitGames/videos/1423437551031432/" type="video/mp4" />
40
+ </video>
41
+ <figcaption>17.1 Announcement</figcaption>
42
+ </figure>
43
+ <h2>17.2</h2>
44
+ <figure>
45
+ <video>
46
+ <source src="https://www.facebook.com/CrossFitGames/videos/1431391013569419/" type="video/mp4" />
47
+ </video>
48
+ <figcaption>17.2 Announcement</figcaption>
49
+ </figure>
50
+ <h2>17.3</h2>
51
+ <figure>
52
+ <video>
53
+ <source src="https://www.facebook.com/CrossFitGames/videos/1439636189411568/" type="video/mp4" />
54
+ </video>
55
+ <figcaption>17.3 Announcement</figcaption>
56
+ </figure>
57
+ <h2>17.4</h2>
58
+ <figure>
59
+ <video>
60
+ <source src="https://www.facebook.com/CrossFitGames/videos/1447649318610255/" type="video/mp4" />
61
+ </video>
62
+ <figcaption>17.4 Announcement</figcaption>
63
+ </figure>
64
+ <h2>17.5</h2>
65
+ <figure>
66
+ <video>
67
+ <source src="https://www.facebook.com/CrossFitGames/videos/1456025707772616/" type="video/mp4" />
68
+ </video>
69
+ <figcaption>17.5 Announcement</figcaption>
70
+ </figure>
71
+ </article>
72
+ </body>
73
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test4-amp-converted.html ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/du-damm-u-double-unders/"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(0px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;text-transform: uppercase;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-header-bar {background-color: rgb(102,102,102);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;text-transform: none;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-article a {font-family: Georgia;text-decoration: underline;color: rgb(0,0,0);}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: BLOCK;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;display: INLINE;text-transform: none;background-color: rgb(0,255,255);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/*Global Styles*/ .ia2amp-header-bar { margin: -5px 0 0 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 16.4px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-header-h1 { font-size: 24px; line-height: 30px; display: block; font-weight: normal; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 { display: block; font-weight: normal; } .ia2amp-h1 { font-size: 19px; line-height: 23px; } .ia2amp-h2 { font-size: 16px; line-height: 20px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-p a { margin: 0; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; } .ia2amp-spacing { display: block; height: 18.8px; margin: 0 16.4px 0 16.4px; } header figure figcaption { display: none; } .ia2amp-figure { margin: 0; } .ia2amp-op-small h1, .ia2amp-op-small h2 { font-size: 10px; display: block; } .ia2amp-op-medium h1, .ia2amp-op-medium h2 { font-size: 14px; display: block; } .ia2amp-op-large h1, .ia2amp-op-large h2 { font-size: 16px; display: block; } .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 { font-size: 23px; display: block; } .ia2amp-figcaption cite { font-size: 8px; display: block; } .ia2amp-op-left { text-align: left; } .ia2amp-op-center { text-align: center; } .ia2amp-op-right { text-align: right; } .ia2amp-figure { position: relative; } figcaption.ia2amp-op-vertical-center { position: absolute; z-index: 1000; } .ia2amp-footer { display: block; font-size: 12px; line-height: 17px; } .ia2amp-footer aside p { margin: 0; } .ia2amp-spacing.after-header-bar.before-header-category { height: 18.8px; } .ia2amp-spacing.after-header-category.before-header-h1, .ia2amp-spacing.after-header-h1.before-header-h2 { height: 13.2px; } .ia2amp-spacing.after-h1.before-h2 { height: 13.2px; } .ia2amp-spacing.after-li.before-li { height: 13.2px; } .ia2amp-spacing.after-footer.before-footer { height: 18.8px; } .ia2amp-spacing.after-header-h1.before-header-author, .ia2amp-spacing.after-header-h2.before-header-author { height: 18.8px; } .ia2amp-spacing.after-header-author.before-header-date { height: 0; } .ia2amp-spacing.after-header-date.before-h1, .ia2amp-spacing.after-header-date.before-h2, .ia2amp-spacing.after-header-date.before-p { height: 26.4px; } .ia2amp-spacing.after-h1.before-p, .ia2amp-spacing.after-h2.before-p, .ia2amp-spacing.after-h3.before-p { height: 18.8px; } .ia2amp-spacing.after-blockquote.before-p { height: 18.8px; } .ia2amp-spacing.after-slideshow, .ia2amp-spacing.before-slideshow, .ia2amp-spacing.after-interactive, .ia2amp-spacing.before-interactive, .ia2amp-spacing.after-image, .ia2amp-spacing.before-image, .ia2amp-spacing.after-figcaption-small, .ia2amp-spacing.after-figcaption-medium, .ia2amp-spacing.after-figcaption-large, .ia2amp-spacing.after-figcaption-extra-large { height: 26.4px; } </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/du-damm-u-double-unders/","headline":"DU \u2013 Damm U (Double Unders)!","datePublished":"2016-05-15T20:57:00+00:00","description":"Damm you Double Unders (DU)! I guess lots of people will agree with the DAMM part\u2026 But why the Double Unders are so problematic since it is just a simple jumping rope? Well, maybe not that simple! \ud83d\ude09","dateModified":"2017-03-17T15:40:25+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2016/05/jumprope.jpg","width":380,"height":240},"publisher":{"@type":"Organization","name":"WOD Expert","logo":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png","width":600,"height":60}}}</script>
13
+ <title>DU – Damm U (Double Unders)!</title>
14
+ </head>
15
+ <body class="ia2amp-body">
16
+ <header class="ia2amp-header">
17
+ <div class="ia2amp-cover-image">
18
+ <amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2016/05/jumprope.jpg" width="380" height="240"></amp-img>
19
+ </div>
20
+ <div class="ia2amp-header-bar">
21
+ <div class="ia2amp-header-bar-img-container">
22
+ <amp-img src="https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&amp;oh=c8337650a88e7fdb6d31088a15a7d9d8&amp;oe=599B24B5&amp;__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8" width="223" height="44"></amp-img>
23
+ </div>
24
+ </div>
25
+ <div class="ia2amp-spacing after-header-bar before-header-category"></div>
26
+ <h2 class="ia2amp-header-category">double under</h2>
27
+ <div class="ia2amp-spacing after-header-category before-header-h1"></div>
28
+ <h1 class="ia2amp-header-h1">DU – Damm U (Double Unders)!</h1>
29
+ <div class="ia2amp-spacing after-header-h1 before-header-author"></div>
30
+ <h3 class="ia2amp-header-author">By Éverton Rosário</h3>
31
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
32
+ <h3 class="ia2amp-header-date">May 15, 2016</h3>
33
+ <div class="ia2amp-spacing after-header-date before-p"></div>
34
+ </header>
35
+ <article class="ia2amp-article">
36
+ <p class="ia2amp-p">Damm you Double Unders (DU)! I guess lots of people will agree with the DAMM part… But why the Double Unders are so problematic since it is just a simple jumping rope? Well, maybe not that simple! 😉</p>
37
+ <div class="ia2amp-spacing after-p before-figcaption-small"></div>
38
+ <div class="ia2amp-image">
39
+ <figure class="ia2amp-figure">
40
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2017/03/elephant-jump-rope-300x233.gif" width="380" height="240"></amp-img>
41
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">@MrWhaite</figcaption>
42
+ </figure>
43
+ </div>
44
+ <div class="ia2amp-spacing after-figcaption-small before-p"></div>
45
+ <p class="ia2amp-p">Jumping rope might be simple as most people were used to do it during school years. And by jumping rope I mean the single unders.</p>
46
+ <div class="ia2amp-spacing after-p before-blockquote"></div>
47
+ <blockquote class="ia2amp-blockquote">
48
+ “A
49
+ <b>double under</b>
50
+ is a popular exercise done on a
51
+ <a href="http://athletics.wikia.com/wiki/Jump_rope">jump rope</a>
52
+ in which the rope makes two passes per jump instead of just one.”
53
+ <a href="http://athletics.wikia.com/wiki/Double_Unders">Athlepedia</a>
54
+ </blockquote>
55
+ <div class="ia2amp-spacing after-blockquote before-p"></div>
56
+ <p class="ia2amp-p">One of the key characteristics comparing the double unders to the single unders are 2:</p>
57
+ <div class="ia2amp-spacing after-p before-list"></div>
58
+ <ul class="ia2amp-list">
59
+ <li>the speed you spin the rope; and</li>
60
+ <li>how high the jump is.</li>
61
+ </ul>
62
+ <div class="ia2amp-spacing after-list before-p"></div>
63
+ <p class="ia2amp-p">In simple math therms, if you jump twice as high from your single under would be enough to perfectly accomplish the double unders. Another possibility is spinning twice as fast the rope, thus not needing to change how high you jump. The actual answer here is that none of the situations will be the correct answer, otherwise you will burn your wrists and your handle power, or you will burn your legs more than necessary. Combining the DU into a more complex WOD will make these 2 initial extreme options even more useless, since probably you will have any other exercise that will demand your handle or your legs, or even worst: both.</p>
64
+ <div class="ia2amp-spacing after-p before-image"></div>
65
+ <div class="ia2amp-image">
66
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2016/05/JumpROpe-copy-300x188.jpg" width="380" height="240"></amp-img>
67
+ </div>
68
+ <div class="ia2amp-spacing after-image before-h2"></div>
69
+ <h2 class="ia2amp-h2">Progression</h2>
70
+ <div class="ia2amp-spacing after-h2 before-p"></div>
71
+ <p class="ia2amp-p">A good progression to perform your double unders if you still didn’t make it is to start without any rope! “Are you crazy?” you might be wondering. But no, Im not crazy or out of my mind. The point to start here is to start jumping consistently on your toes, not on your hills, and bending minimally as possible your knees. Once you are jumping consistently high, and by high, try jumping twice as high of your single under, or maybe even higher if you can. Once you can perform at least 10 sequence jumps high enough with not much difference between the jumps. At this high you can perform the “double tap” on your hips using your free hands (remember, you are not using hands so far). Also remember to jump straight, without high knees nor rising your feet. Once you completed all these steps, you are good to move forward.</p>
72
+ <div class="ia2amp-spacing after-p before-p"></div>
73
+ <p class="ia2amp-p">You will start using a rope, consider buying one for you or make sure you will have yours reserved every time on your box. Otherwise mixing different ropes with different specs you make this process more difficult.</p>
74
+ <div class="ia2amp-spacing after-p before-p"></div>
75
+ <p class="ia2amp-p">Now it is time to start using a rope, but still, it is not time to try to perform the double under. You need to keep jumping as high as the previous step, but performing only a single under. You will notice that you will be jumping really high and will need to slow down a lot the rope speed, otherwise you will be landing and the rope will be arriving at your feet at same time. Slow down and get used to the high jumps. Try to keep as high as you did before without the rope. Once you perform 10 unbroken high jumps with slow rope speed, is time to move forward.</p>
76
+ <div class="ia2amp-spacing after-p before-p"></div>
77
+ <p class="ia2amp-p">Now you will be jumping as high as you did in both previous steps, but now you will speed up your rope trying to perform the double under. Performing these steps will raise your odds to accomplish the regular double unders.</p>
78
+ <div class="ia2amp-spacing after-p before-p"></div>
79
+ <p class="ia2amp-p">Once you start performing more regularly your double unders, is practice time. And by practice I mean: exhaustive practicing. Try to perform at least 200 double unders. This will definitely make you get more feeling and understand your body balance, jumping and wrist skills.</p>
80
+ <div class="ia2amp-spacing after-p before-h2"></div>
81
+ <h2 class="ia2amp-h2">The hidden characteristics of Double Unders</h2>
82
+ <div class="ia2amp-spacing after-h2 before-p"></div>
83
+ <p class="ia2amp-p">Double unders are hard to get, but once you get used to it, you will perform it really smoothly. By looking to a more complex WOD where you have DU in it, you might underestimate how heavy the DU’s might be because it will:</p>
84
+ <div class="ia2amp-spacing after-p before-list"></div>
85
+ <ul class="ia2amp-list">
86
+ <li>burn your wrists/handle</li>
87
+ <li>exhaust your legs</li>
88
+ <li>raise/keep high your heart beat</li>
89
+ </ul>
90
+ <div class="ia2amp-spacing after-list before-p"></div>
91
+ <p class="ia2amp-p">These three might sound inoffensive but don’t mis-judge this. They will make you suffer, suffer hard depending on the WOD. If the WOD mixes some hang moves, pull ups, muscle ups or any other exercise that burns your grip, the rope might feel harder to spin. This will be the perfect timing to jump a little higher and save your wrists a little bit. On the other hand, if your WOD is really burning your legs, might be a good opportunity to save some energies by jumping little lower and spinning faster. If your WOD burns your grip + legs, try to keep a balance with the 50-50 strategy, and know that by the end of this WOD you’ll be supplicating for your life, I mean, your breath! 😛</p>
92
+ <div class="ia2amp-spacing after-p before-h2"></div>
93
+ <h2 class="ia2amp-h2">Hints for warming up</h2>
94
+ <div class="ia2amp-spacing after-h2 before-list"></div>
95
+ <ul class="ia2amp-list">
96
+ <li>Perform sets of single unders</li>
97
+ <li>Run some short sprints (100m is enough)</li>
98
+ <li>Few box jump</li>
99
+ </ul>
100
+ <div class="ia2amp-spacing after-list"></div>
101
+ </article>
102
+ </body>
103
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test4-instant-article.html ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <html>
3
+ <head>
4
+ <link rel="canonical" href="http://blog.wod.expert/du-damm-u-double-unders/" />
5
+ <meta charset="utf-8" />
6
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
7
+ <meta property="op:generator:version" content="1.0.0"/>
8
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
9
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
10
+ <meta property="op:markup_version" content="v1.0"/>
11
+ <meta property="fb:article_style" content="wod-gray"/>
12
+ </head>
13
+ <body>
14
+ <article>
15
+ <header>
16
+ <figure>
17
+ <img src="http://blog.wod.expert/wp-content/uploads/2016/05/jumprope.jpg" />
18
+ </figure>
19
+ <h1>DU – Damm U (Double Unders)!</h1>
20
+ <time class="op-published" datetime="2016-05-15T20:57:00+00:00">May 15th, 8:57pm</time>
21
+ <time class="op-modified" datetime="2017-03-17T15:40:25+00:00">March 17th, 3:40pm</time>
22
+ <address>
23
+ <a>Éverton Rosário</a>
24
+ </address>
25
+ <h3 class="op-kicker">double under</h3>
26
+ </header>
27
+ <p>Damm you Double Unders (DU)! I guess lots of people will agree with the DAMM part… But why the Double Unders are so problematic since it is just a simple jumping rope? Well, maybe not that simple! &#x1f609;</p>
28
+ <figure>
29
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/elephant-jump-rope-300x233.gif" />
30
+ <figcaption>@MrWhaite</figcaption>
31
+ </figure>
32
+ <p>Jumping rope might be simple as most people were used to do it during school years. And by jumping rope I mean the single unders.</p>
33
+ <blockquote>
34
+ “A
35
+ <b>double under</b>
36
+ is a popular exercise done on a
37
+ <a href="http://athletics.wikia.com/wiki/Jump_rope">jump rope</a>
38
+ in which the rope makes two passes per jump instead of just one.”
39
+ <br />
40
+ <a href="http://athletics.wikia.com/wiki/Double_Unders">Athlepedia</a>
41
+ </blockquote>
42
+ <p>One of the key characteristics comparing the double unders to the single unders are 2:</p>
43
+ <ul>
44
+ <li>the speed you spin the rope; and</li>
45
+ <li>how high the jump is.</li>
46
+ </ul>
47
+ <p>In simple math therms, if you jump twice as high from your single under would be enough to perfectly accomplish the double unders. Another possibility is spinning twice as fast the rope, thus not needing to change how high you jump. The actual answer here is that none of the situations will be the correct answer, otherwise you will burn your wrists and your handle power, or you will burn your legs more than necessary. Combining the DU into a more complex WOD will make these 2 initial extreme options even more useless, since probably you will have any other exercise that will demand your handle or your legs, or even worst: both.</p>
48
+ <figure>
49
+ <img src="http://blog.wod.expert/wp-content/uploads/2016/05/JumpROpe-copy-300x188.jpg" />
50
+ </figure>
51
+ <h2>Progression</h2>
52
+ <p>A good progression to perform your double unders if you still didn’t make it is to start without any rope! “Are you crazy?” you might be wondering. But no, Im not crazy or out of my mind. The point to start here is to start jumping consistently on your toes, not on your hills, and bending minimally as possible your knees. Once you are jumping consistently high, and by high, try jumping twice as high of your single under, or maybe even higher if you can. Once you can perform at least 10 sequence jumps high enough with not much difference between the jumps. At this high you can perform the “double tap” on your hips using your free hands (remember, you are not using hands so far). Also remember to jump straight, without high knees nor rising your feet. Once you completed all these steps, you are good to move forward.</p>
53
+ <p>You will start using a rope, consider buying one for you or make sure you will have yours reserved every time on your box. Otherwise mixing different ropes with different specs you make this process more difficult.</p>
54
+ <p>Now it is time to start using a rope, but still, it is not time to try to perform the double under. You need to keep jumping as high as the previous step, but performing only a single under. You will notice that you will be jumping really high and will need to slow down a lot the rope speed, otherwise you will be landing and the rope will be arriving at your feet at same time. Slow down and get used to the high jumps. Try to keep as high as you did before without the rope. Once you perform 10 unbroken high jumps with slow rope speed, is time to move forward.</p>
55
+ <p>Now you will be jumping as high as you did in both previous steps, but now you will speed up your rope trying to perform the double under. Performing these steps will raise your odds to accomplish the regular double unders.</p>
56
+ <p>Once you start performing more regularly your double unders, is practice time. And by practice I mean: exhaustive practicing. Try to perform at least 200 double unders. This will definitely make you get more feeling and understand your body balance, jumping and wrist skills.</p>
57
+ <h2>The hidden characteristics of Double Unders</h2>
58
+ <p>Double unders are hard to get, but once you get used to it, you will perform it really smoothly. By looking to a more complex WOD where you have DU in it, you might underestimate how heavy the DU’s might be because it will:</p>
59
+ <ul>
60
+ <li>burn your wrists/handle</li>
61
+ <li>exhaust your legs</li>
62
+ <li>raise/keep high your heart beat</li>
63
+ </ul>
64
+ <p>These three might sound inoffensive but don’t mis-judge this. They will make you suffer, suffer hard depending on the WOD. If the WOD mixes some hang moves, pull ups, muscle ups or any other exercise that burns your grip, the rope might feel harder to spin. This will be the perfect timing to jump a little higher and save your wrists a little bit. On the other hand, if your WOD is really burning your legs, might be a good opportunity to save some energies by jumping little lower and spinning faster. If your WOD burns your grip + legs, try to keep a balance with the 50-50 strategy, and know that by the end of this WOD you’ll be supplicating for your life, I mean, your breath! &#x1f61b;</p>
65
+ <h2>Hints for warming up</h2>
66
+ <ul>
67
+ <li>Perform sets of single unders</li>
68
+ <li>Run some short sprints (100m is enough)</li>
69
+ <li>Few box jump</li>
70
+ </ul>
71
+ </article>
72
+ </body>
73
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test5-amp-converted.html ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/wall-ball-or-ball-shot/"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(0px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(238,238,238);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;text-transform: uppercase;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-header-bar {background-color: rgb(102,102,102);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;text-transform: none;color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;}.ia2amp-article a {font-family: Georgia;text-decoration: underline;color: rgb(0,0,0);}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: BLOCK;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;display: INLINE;text-transform: none;background-color: rgb(0,255,255);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/*Global Styles*/ .ia2amp-header-bar { margin: -5px 0 0 0; height: 55px; font: 0/0 a; } .ia2amp-header-bar:before { content: ' '; display: inline-block; vertical-align: middle; height: 100%; width: 16.4px; } .ia2amp-header-bar-img-container { display: inline-block; vertical-align: middle; } .ia2amp-header-category { font-size: 10px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-header-h1 { font-size: 24px; line-height: 30px; display: block; font-weight: normal; } .ia2amp-header-h2 { font-size: 16px; line-height: 20px; display: block; font-weight: normal; } .ia2amp-header h3 { font-size: 8px; line-height: 12px; display: block; font-weight: normal; } .ia2amp-h1, .ia2amp-h2, .ia2amp-h3 { display: block; font-weight: normal; } .ia2amp-h1 { font-size: 19px; line-height: 23px; } .ia2amp-h2 { font-size: 16px; line-height: 20px; } .ia2amp-p { font-size: 14px; line-height: 20px; display: inline-block; } .ia2amp-p a { margin: 0; } .ia2amp-blockquote { font-size: 14px; line-height: 20px; padding: 0px 13.2px 0px 18.8px; } .ia2amp-spacing { display: block; height: 18.8px; margin: 0 16.4px 0 16.4px; } header figure figcaption { display: none; } .ia2amp-figure { margin: 0; } .ia2amp-op-small h1, .ia2amp-op-small h2 { font-size: 10px; display: block; } .ia2amp-op-medium h1, .ia2amp-op-medium h2 { font-size: 14px; display: block; } .ia2amp-op-large h1, .ia2amp-op-large h2 { font-size: 16px; display: block; } .ia2amp-op-extra-large h1, .ia2amp-op-extra-large h2 { font-size: 23px; display: block; } .ia2amp-figcaption cite { font-size: 8px; display: block; } .ia2amp-op-left { text-align: left; } .ia2amp-op-center { text-align: center; } .ia2amp-op-right { text-align: right; } .ia2amp-figure { position: relative; } figcaption.ia2amp-op-vertical-center { position: absolute; z-index: 1000; } .ia2amp-footer { display: block; font-size: 12px; line-height: 17px; } .ia2amp-footer aside p { margin: 0; } .ia2amp-spacing.after-header-bar.before-header-category { height: 18.8px; } .ia2amp-spacing.after-header-category.before-header-h1, .ia2amp-spacing.after-header-h1.before-header-h2 { height: 13.2px; } .ia2amp-spacing.after-h1.before-h2 { height: 13.2px; } .ia2amp-spacing.after-li.before-li { height: 13.2px; } .ia2amp-spacing.after-footer.before-footer { height: 18.8px; } .ia2amp-spacing.after-header-h1.before-header-author, .ia2amp-spacing.after-header-h2.before-header-author { height: 18.8px; } .ia2amp-spacing.after-header-author.before-header-date { height: 0; } .ia2amp-spacing.after-header-date.before-h1, .ia2amp-spacing.after-header-date.before-h2, .ia2amp-spacing.after-header-date.before-p { height: 26.4px; } .ia2amp-spacing.after-h1.before-p, .ia2amp-spacing.after-h2.before-p, .ia2amp-spacing.after-h3.before-p { height: 18.8px; } .ia2amp-spacing.after-blockquote.before-p { height: 18.8px; } .ia2amp-spacing.after-slideshow, .ia2amp-spacing.before-slideshow, .ia2amp-spacing.after-interactive, .ia2amp-spacing.before-interactive, .ia2amp-spacing.after-image, .ia2amp-spacing.before-image, .ia2amp-spacing.after-figcaption-small, .ia2amp-spacing.after-figcaption-medium, .ia2amp-spacing.after-figcaption-large, .ia2amp-spacing.after-figcaption-extra-large { height: 26.4px; } </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/wall-ball-or-ball-shot/","headline":"Wall Ball or Ball Shot?","datePublished":"2016-05-20T13:48:38+00:00","description":"\n Both expressions seems correct and in common shares the requisite of\n breaking parallel line\n while squatting. Just for correctness, the Wall Ball Shot is the best title to use.\n ","dateModified":"2017-03-17T15:38:31+00:00","author":{"@type":"Person","name":"\u00c9verton Ros\u00e1rio"},"image":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/03/rich-wallball.jpg","width":380,"height":240},"publisher":{"@type":"Organization","name":"WOD Expert","logo":{"@type":"ImageObject","url":"http://blog.wod.expert/wp-content/uploads/2017/04/wod-expert-amp-org-logo.png","width":600,"height":60}}}</script>
13
+ <title>Wall Ball or Ball Shot?</title>
14
+ <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
15
+ </head>
16
+ <body class="ia2amp-body">
17
+ <header class="ia2amp-header">
18
+ <div class="ia2amp-cover-image">
19
+ <figure class="ia2amp-figure">
20
+ <amp-img class="ia2amp-header-cover-img" src="http://blog.wod.expert/wp-content/uploads/2017/03/rich-wallball.jpg" width="380" height="240"></amp-img>
21
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">Rich Froning at Wall Ball Shot</figcaption>
22
+ </figure>
23
+ </div>
24
+ <div class="ia2amp-header-bar">
25
+ <div class="ia2amp-header-bar-img-container">
26
+ <amp-img src="https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&amp;oh=c8337650a88e7fdb6d31088a15a7d9d8&amp;oe=599B24B5&amp;__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8" width="223" height="44"></amp-img>
27
+ </div>
28
+ </div>
29
+ <div class="ia2amp-spacing after-header-bar before-header-category"></div>
30
+ <h2 class="ia2amp-header-category">exercise</h2>
31
+ <div class="ia2amp-spacing after-header-category before-header-h1"></div>
32
+ <h1 class="ia2amp-header-h1">Wall Ball or Ball Shot?</h1>
33
+ <div class="ia2amp-spacing after-header-h1 before-header-author"></div>
34
+ <h3 class="ia2amp-header-author">By Éverton Rosário</h3>
35
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
36
+ <h3 class="ia2amp-header-date">May 20, 2016</h3>
37
+ <div class="ia2amp-spacing after-header-date before-p"></div>
38
+ </header>
39
+ <article class="ia2amp-article">
40
+ <p class="ia2amp-p">
41
+ Both expressions seems correct and in common shares the requisite of
42
+ <a href="http://blog.wod.expert/2016/05/01/breaking-parallel-line">breaking parallel line</a>
43
+ while squatting. Just for correctness, the Wall Ball Shot is the best title to use.
44
+ </p>
45
+ <div class="ia2amp-spacing after-p before-p"></div>
46
+ <p class="ia2amp-p">One thing that comes to mind is that when thinking about wall ball It reminds me of only one constraint to make it a valid movement. So if you throw the ball below the limit line it is a “no-rep”, otherwise +1 to your reps. 😉</p>
47
+ <div class="ia2amp-spacing after-p before-p"></div>
48
+ <p class="ia2amp-p">Looking to the wall ball shot perspective, not only the bottom limit is important, but also there is a top, left and right limits. In other words: you gotta hit the target.</p>
49
+ <div class="ia2amp-spacing after-p before-figcaption-small"></div>
50
+ <div class="ia2amp-image">
51
+ <figure class="ia2amp-figure">
52
+ <amp-img layout="responsive" src="http://blog.wod.expert/wp-content/uploads/2017/03/wallballshot-mark-rogue-300x189.jpg" width="380" height="240"></amp-img>
53
+ <figcaption class="ia2amp-figcaption ia2amp-op-small">Target used on most of competitions</figcaption>
54
+ </figure>
55
+ </div>
56
+ <div class="ia2amp-spacing after-figcaption-small before-p"></div>
57
+ <p class="ia2amp-p">CrossFit isn’t just about being strong and fast, but also precise. Always consider yourself doing your wall balls hitting at same target always. If you compete into any fitness competition, the odds of using a ball shot exercise increases, since the ball shot are easier equipment to have on open spaces. The wall, save for your box 😉</p>
58
+ <div class="ia2amp-spacing after-p before-h2"></div>
59
+ <h2 class="ia2amp-h2">Hints for the exercise</h2>
60
+ <div class="ia2amp-spacing after-h2 before-p"></div>
61
+ <p class="ia2amp-p">Never stop looking at your target, the piece of metal, circle, line or the imaginary “X” mark on the wall. This will make your body foresee where you need to hit, and just throw there, you’ll gonna hit it!</p>
62
+ <div class="ia2amp-spacing after-p before-p"></div>
63
+ <p class="ia2amp-p">
64
+ Never forget to break the parallel, and while going down, don’t try to slow your descent, this will make you burn your muscles. Always remember, if you want to perform better on the WODs
65
+ <a href="http://blog.wod.expert/2016/06/06/always-save-energy">always think about saving energy</a>
66
+ .
67
+ </p>
68
+ <div class="ia2amp-spacing after-p before-p"></div>
69
+ <p class="ia2amp-p">Thinking about doing the wallball shots, never forget to use all your body as lever to accomplish the movement with the minimal effort possible. By this I mean:</p>
70
+ <div class="ia2amp-spacing after-p before-list"></div>
71
+ <ol class="ia2amp-list">
72
+ <li>Start movement by performing a “deadlift”getting the ball from floor</li>
73
+ <li>Go down as fast as you can, holding the ball at your face level, holding by the bottom of the ball</li>
74
+ <li>Break the parallel and then explode as fast as you can your legs</li>
75
+ <li>By the moment you are straight up, your ball will move up without any force</li>
76
+ <li>Push the ball up, like setting a volleyball ball, never forgetting to use your wrists, this will save some shoulders and legs energy</li>
77
+ <li>You HIT the target! Add one to your counting sequence, never forget this 😉 !</li>
78
+ <li>If your counting comes to the correct number, jump to number 11.</li>
79
+ <li>The ball will start to descend, keep your arms straight up waiting for the contact</li>
80
+ <li>Absorb the ball with your arms and wrists and start the descend, using the less amount of energy possible</li>
81
+ <li>Repeat from step 2!</li>
82
+ <li>You are done!</li>
83
+ </ol>
84
+ <div class="ia2amp-spacing after-list before-slideshow"></div>
85
+ <div class="ia2amp-slideshow">
86
+ <amp-carousel width="380" height="240">
87
+ <div class="ia2amp-slideshow-image">
88
+ <figure class="ia2amp-figure">
89
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/wallball-squat-150x150.jpg" width="380" height="240"></amp-img>
90
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>Squat preparing to throw</h1></figcaption>
91
+ </figure>
92
+ </div>
93
+ <div class="ia2amp-slideshow-image">
94
+ <figure class="ia2amp-figure">
95
+ <amp-img src="http://blog.wod.expert/wp-content/uploads/2017/03/wallball-throw-volleyball-150x150.jpg" width="380" height="240"></amp-img>
96
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>The wall ball throw using the wrists power, just like volleyball setting</h1></figcaption>
97
+ </figure>
98
+ </div>
99
+ </amp-carousel>
100
+ </div>
101
+ <div class="ia2amp-spacing after-slideshow before-h2"></div>
102
+ <h2 class="ia2amp-h2">Hints for warming up</h2>
103
+ <div class="ia2amp-spacing after-h2 before-list"></div>
104
+ <ul class="ia2amp-list">
105
+ <li>Perform sets of air squats</li>
106
+ <li>Use lighter med ball to perform few shots</li>
107
+ <li>Perform some sets of walking lunges</li>
108
+ </ul>
109
+ <div class="ia2amp-spacing after-list"></div>
110
+ </article>
111
+ </body>
112
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/test5-instant-article.html ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <html>
3
+ <head>
4
+ <link rel="canonical" href="http://blog.wod.expert/wall-ball-or-ball-shot/" />
5
+ <meta charset="utf-8" />
6
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
7
+ <meta property="op:generator:version" content="1.0.0"/>
8
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
9
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
10
+ <meta property="op:markup_version" content="v1.0"/>
11
+ <meta property="fb:article_style" content="wod-gray"/>
12
+ </head>
13
+ <body>
14
+ <article>
15
+ <header>
16
+ <figure>
17
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/rich-wallball.jpg" />
18
+ <figcaption>Rich Froning at Wall Ball Shot</figcaption>
19
+ </figure>
20
+ <h1>Wall Ball or Ball Shot?</h1>
21
+ <time class="op-published" datetime="2016-05-20T13:48:38+00:00">May 20th, 1:48pm</time>
22
+ <time class="op-modified" datetime="2017-03-17T15:38:31+00:00">March 17th, 3:38pm</time>
23
+ <address>
24
+ <a>Éverton Rosário</a>
25
+ </address>
26
+ <h3 class="op-kicker">exercise</h3>
27
+ </header>
28
+ <p>
29
+ Both expressions seems correct and in common shares the requisite of
30
+ <a href="http://blog.wod.expert/2016/05/01/breaking-parallel-line">breaking parallel line</a>
31
+ while squatting. Just for correctness, the Wall Ball Shot is the best title to use.
32
+ </p>
33
+ <p>One thing that comes to mind is that when thinking about wall ball It reminds me of only one constraint to make it a valid movement. So if you throw the ball below the limit line it is a “no-rep”, otherwise +1 to your reps. &#x1f609;</p>
34
+ <p>Looking to the wall ball shot perspective, not only the bottom limit is important, but also there is a top, left and right limits. In other words: you gotta hit the target.</p>
35
+ <figure>
36
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/wallballshot-mark-rogue-300x189.jpg" />
37
+ <figcaption>Target used on most of competitions</figcaption>
38
+ </figure>
39
+ <p>CrossFit isn’t just about being strong and fast, but also precise. Always consider yourself doing your wall balls hitting at same target always. If you compete into any fitness competition, the odds of using a ball shot exercise increases, since the ball shot are easier equipment to have on open spaces. The wall, save for your box &#x1f609;</p>
40
+ <h2>Hints for the exercise</h2>
41
+ <p>Never stop looking at your target, the piece of metal, circle, line or the imaginary “X” mark on the wall. This will make your body foresee where you need to hit, and just throw there, you’ll gonna hit it!</p>
42
+ <p>
43
+ Never forget to break the parallel, and while going down, don’t try to slow your descent, this will make you burn your muscles. Always remember, if you want to perform better on the WODs
44
+ <a href="http://blog.wod.expert/2016/06/06/always-save-energy">always think about saving energy</a>
45
+ .
46
+ </p>
47
+ <p>Thinking about doing the wallball shots, never forget to use all your body as lever to accomplish the movement with the minimal effort possible. By this I mean:</p>
48
+ <ol>
49
+ <li>Start movement by performing a “deadlift”getting the ball from floor</li>
50
+ <li>Go down as fast as you can, holding the ball at your face level, holding by the bottom of the ball</li>
51
+ <li>Break the parallel and then explode as fast as you can your legs</li>
52
+ <li>By the moment you are straight up, your ball will move up without any force</li>
53
+ <li>Push the ball up, like setting a volleyball ball, never forgetting to use your wrists, this will save some shoulders and legs energy</li>
54
+ <li>You HIT the target! Add one to your counting sequence, never forget this &#x1f609; !</li>
55
+ <li>If your counting comes to the correct number, jump to number 11.</li>
56
+ <li>The ball will start to descend, keep your arms straight up waiting for the contact</li>
57
+ <li>Absorb the ball with your arms and wrists and start the descend, using the less amount of energy possible</li>
58
+ <li>Repeat from step 2!</li>
59
+ <li>You are done!</li>
60
+ </ol>
61
+ <figure class="op-slideshow">
62
+ <figure>
63
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/wallball-squat-150x150.jpg" />
64
+ <figcaption>Squat preparing to throw</figcaption>
65
+ </figure>
66
+ <figure>
67
+ <img src="http://blog.wod.expert/wp-content/uploads/2017/03/wallball-throw-volleyball-150x150.jpg" />
68
+ <figcaption>The wall ball throw using the wrists power, just like volleyball setting</figcaption>
69
+ </figure>
70
+ </figure>
71
+ <h2>Hints for warming up</h2>
72
+ <ul>
73
+ <li>Perform sets of air squats</li>
74
+ <li>Use lighter med ball to perform few shots</li>
75
+ <li>Perform some sets of walking lunges</li>
76
+ </ul>
77
+ <p />
78
+ </article>
79
+ </body>
80
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/tutorial-amp-converted.html ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html amp lang="en-US">
2
+ <head>
3
+ <meta charset="utf-8"/>
4
+ <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
5
+ <script src="https://cdn.ampproject.org/v0.js" async></script>
6
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
7
+ <noscript>
8
+ <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style>
9
+ </noscript>
10
+ <link rel="canonical" href="http://blog.wod.expert/example1"/>
11
+ <style amp-custom>amp-img.ia2amp-header-cover-img {transform: translate(0px, 0px);}div.ia2amp-cover-image {width: 380px;height: 240px;overflow: hidden;}html {background-color: rgb(255,255,255);}.ia2amp-header-category {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header h3 {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-header-bar {background-color: rgb(255,255,255);}.ia2amp-h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-p {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-article a {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;text-decoration: underline;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-blockquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 32px 0 46px;border-top-color: rgb(0,0,0);border-right-color: rgb(0,0,0);border-bottom-color: rgb(0,0,0);border-left-color: rgb(0,0,0);border-width: 0 0 0 2px;border-style: solid;}.ia2amp-pullquote {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-pullquote cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h1 {font-family: Helvetica Neue Bold;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-small h2 {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-medium h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-large h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h1 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-op-extra-large h2 {font-family: Georgia;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(128,128,128);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-figcaption cite {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: uppercase;background-color: rgba(255,255,255,0);color: rgb(191,191,191);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}.ia2amp-footer {font-family: Helvetica Neue;text-align: LEFT;display: INLINE;text-transform: none;background-color: rgba(255,255,255,0);color: rgb(0,0,0);margin: 0 16.4px 0 16.4px;padding: 0 0 0 0;border-width: 0 0 0 0;border-style: solid;}/* Custom CSS for default style goes here */ /* p { background-color: rgb(255,00,00); } */ </style>
12
+ <script type="application/ld+json">{"@context":"http://schema.org","@type":"NewsArticle","mainEntityOfPage":"http://blog.wod.expert/example1","headline":" Instant Articles ","datePublished":"2016-02-04T08:00:00-08:00","description":"Yes, it\u2019s true. Instant Articles open on mobile devices really quickly.","dateModified":"2016-02-04T08:00:00-08:00","author":{"@type":"Person","name":"\n Instant Articles Team\n "},"image":{"@type":"ImageObject","url":"https://s3.amazonaws.com/instantarticles/examples/fb_beach_flower.jpg","width":380,"height":240}}</script>
13
+ <title> Instant Articles </title>
14
+ <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
15
+ <script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
16
+ <script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>
17
+ </head>
18
+ <body class="ia2amp-body">
19
+ <header class="ia2amp-header">
20
+ <div class="ia2amp-cover-image">
21
+ <amp-img class="ia2amp-header-cover-img" src="https://s3.amazonaws.com/instantarticles/examples/fb_beach_flower.jpg" width="380" height="240"></amp-img>
22
+ </div>
23
+ <div class="ia2amp-header-bar"></div>
24
+ <div class="ia2amp-spacing after-header-bar before-header-category"></div>
25
+ <h2 class="ia2amp-header-category">
26
+ Introduction
27
+ </h2>
28
+ <div class="ia2amp-spacing after-header-category before-header-h1"></div>
29
+ <h1 class="ia2amp-header-h1"> Instant Articles </h1>
30
+ <div class="ia2amp-spacing after-header-h1 before-header-h2"></div>
31
+ <h2 class="ia2amp-header-h2">Get familiar with your new storytelling tools. Make your media come alive, and keep readers coming back for more</h2>
32
+ <div class="ia2amp-spacing after-header-h2 before-header-author"></div>
33
+ <h3 class="ia2amp-header-author">By
34
+ Instant Articles Team
35
+ </h3>
36
+ <div class="ia2amp-spacing after-header-author before-header-date"></div>
37
+ <h3 class="ia2amp-header-date">February 04, 2016</h3>
38
+ <div class="ia2amp-spacing after-header-date before-p"></div>
39
+ </header>
40
+ <article class="ia2amp-article">
41
+ <p class="ia2amp-p">Yes, it’s true. Instant Articles open on mobile devices really quickly.</p>
42
+ <div class="ia2amp-spacing after-p before-p"></div>
43
+ <p class="ia2amp-p">But that’s just the beginning of it. Instant Articles are buttery smooth and addictive. Once you’ve read a few, you’ll never want to go back.</p>
44
+ <div class="ia2amp-spacing after-p before-p"></div>
45
+ <p class="ia2amp-p">The Facebook-native format is packed with innovative ways to tell deeply engaging, interactive stories. Thanks to the powerful, built-in media features and customizable typographic elements, Instant Articles gives you awesome new editorial tools to use while delivering a decidedly superior experience for your readers.</p>
46
+ <div class="ia2amp-spacing after-p before-p"></div>
47
+ <p class="ia2amp-p">More than half of Instant Articles readers scroll 90% of the way through their articles, while, historically, 38% of web readers haven’t made it past the first line of other online media.</p>
48
+ <div class="ia2amp-spacing after-p before-p"></div>
49
+ <p class="ia2amp-p">This article gives you a quick highlight tour of Instant Articles features and shows you how to make magic with the format. You’ll be happy to find that Instant Articles are not only delightful but surprisingly easy to create.</p>
50
+ <div class="ia2amp-spacing after-p before-h1"></div>
51
+ <h1 class="ia2amp-h1"> Photography </h1>
52
+ <div class="ia2amp-spacing after-h1 before-p"></div>
53
+ <p class="ia2amp-p">All photographs are interactive by default. When tapped an image will expand to fill the screen, then readers can tilt the phone back and forth to explore the margins.</p>
54
+ <div class="ia2amp-spacing after-p"></div>
55
+ <div class="ia2amp-image">
56
+ <figure class="ia2amp-figure">
57
+ <amp-img layout="responsive" src="https://s3.amazonaws.com/instantarticles/examples/fb_rails.jpg" width="380" height="240"></amp-img>
58
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>Photograph Example</h1>
59
+ Tap this image to make it expand. Tilt the phone right and left and see what happens.
60
+
61
+ <cite>Eduardo Tardin/Facebook</cite></figcaption>
62
+ </figure>
63
+ </div>
64
+ <div class="ia2amp-spacing before-p"></div>
65
+ <p class="ia2amp-p">To return to the article, tap the image again. The interactive mode works best with high-definition photos containing rich visual information. For low-resolution media, we recommend using the non-interactive setting so that it will remain in-line in the correct aspect ratio and your readers won’t tap into a mushy, pixelated experience.</p>
66
+ <div class="ia2amp-spacing after-p before-h2"></div>
67
+ <h2 class="ia2amp-h2">Social Feedback</h2>
68
+ <div class="ia2amp-spacing after-h2 before-p"></div>
69
+ <p class="ia2amp-p">You can add native Facebook Likes and Comments buttons to images, giving readers extra opportunities to engage with individual elements in your stories. This feature currently works for photographs and videos.</p>
70
+ <div class="ia2amp-spacing after-p before-h2"></div>
71
+ <h2 class="ia2amp-h2">Slideshow</h2>
72
+ <div class="ia2amp-spacing after-h2 before-p"></div>
73
+ <p class="ia2amp-p">You can also group collections of images into slideshows that scroll horizontally.</p>
74
+ <div class="ia2amp-spacing after-p before-slideshow"></div>
75
+ <div class="ia2amp-slideshow">
76
+ <figure class="ia2amp-figure">
77
+ <amp-carousel width="380" height="240">
78
+ <div class="ia2amp-slideshow-image">
79
+ <figure class="ia2amp-figure">
80
+ <amp-img src="https://s3.amazonaws.com/instantarticles/examples/fb_beach_flower.jpg" width="380" height="240"></amp-img>
81
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 1/5
82
+ This caption becomes visible once you enter the slideshow by tapping the first image.
83
+ Eduardo Tardin/Facebook
84
+ </h1></figcaption>
85
+ </figure>
86
+ </div>
87
+ <div class="ia2amp-slideshow-image">
88
+ <figure class="ia2amp-figure">
89
+ <amp-img src="https://s3.amazonaws.com/instantarticles/examples/fb_rocks.jpg" width="380" height="240"></amp-img>
90
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 2/5
91
+ Each photo in a slideshow can have its own caption.
92
+ Eduardo Tardin/Facebook
93
+ </h1></figcaption>
94
+ </figure>
95
+ </div>
96
+ <div class="ia2amp-slideshow-image">
97
+ <figure class="ia2amp-figure">
98
+ <amp-img src="https://s3.amazonaws.com/instantarticles/examples/fb_sunset.jpg" width="380" height="240"></amp-img>
99
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 3/5
100
+ This is the third photo of the slideshow.
101
+ Eduardo Tardin/Facebook
102
+ </h1></figcaption>
103
+ </figure>
104
+ </div>
105
+ <div class="ia2amp-slideshow-image">
106
+ <figure class="ia2amp-figure">
107
+ <amp-img src="https://s3.amazonaws.com/instantarticles/examples/fb_cave_ocean.jpg" width="380" height="240"></amp-img>
108
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 4/5
109
+ The fourth photo of the slideshow.
110
+ Eduardo Tardin/Facebook
111
+ </h1></figcaption>
112
+ </figure>
113
+ </div>
114
+ <div class="ia2amp-slideshow-image">
115
+ <figure class="ia2amp-figure">
116
+ <amp-img src="https://s3.amazonaws.com/instantarticles/examples/fb_boat.jpg" width="380" height="240"></amp-img>
117
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 5/5
118
+ The fifth photo of the slideshow.
119
+ Eduardo Tardin/Facebook
120
+ </h1></figcaption>
121
+ </figure>
122
+ </div>
123
+ </amp-carousel>
124
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>Slideshow Example</h1>
125
+ The slideshow caption is visible in-line in the main body of the story. You can also add individual captions for each image in the gallery, which become visible only after entering the slideshow. Tap on the first image to open it.
126
+ </figcaption>
127
+ </figure>
128
+ </div>
129
+ <div class="ia2amp-spacing after-slideshow"></div>
130
+ <div class="ia2amp-video">
131
+ <figure class="ia2amp-figure">
132
+ <amp-video src="https://s3.amazonaws.com/instantarticles/examples/fb_movie_pt.mov" width="380" height="240"></amp-video>
133
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1> 6+ </h1>
134
+ Adendum and mixed video + image in a slideshow.
135
+
136
+ <cite>Instant Articles/Facebook</cite></figcaption>
137
+ </figure>
138
+ </div>
139
+ <div class="ia2amp-spacing before-h1"></div>
140
+ <h1 class="ia2amp-h1">Video</h1>
141
+ <div class="ia2amp-spacing after-h1 before-p"></div>
142
+ <p class="ia2amp-p">Native videos in Instant Articles play automatically, by default, as soon as they scroll into view on the reader’s screen—a powerful way to make the page come to life. You have many options for presenting videos. Here’s an interactive one with play controls. </p>
143
+ <div class="ia2amp-spacing after-p"></div>
144
+ <div class="ia2amp-video">
145
+ <figure class="ia2amp-figure">
146
+ <amp-video src="https://s3.amazonaws.com/instantarticles/examples/fb_hiperlapse_sp.mp4" width="380" height="240"></amp-video>
147
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1><b>2:57</b> | Interactive Video Example</h1>
148
+ When this video first scrolls into sight, it appears in-line in its correct aspect ratio and plays automatically with the volume off. By tapping it, the video expands to fill the screen and can be turned to view horizontally. The soundtrack becomes audible, and play controls, with scrubber, are accessible.
149
+ </figcaption>
150
+ </figure>
151
+ </div>
152
+ <div class="ia2amp-spacing before-p"></div>
153
+ <p class="ia2amp-p"> To hide play controls, tap the video again; the pause/play icons and scrubber can be toggled on and off this way. You can also rotate the phone sideways while the video is in-line to view it in landscape mode.</p>
154
+ <div class="ia2amp-spacing after-p before-p"></div>
155
+ <p class="ia2amp-p">Alternately, try using a short video to add color and mood to a story. Disable the play controls and set it to loop with a cross-fade.</p>
156
+ <div class="ia2amp-spacing after-p"></div>
157
+ <div class="ia2amp-video">
158
+ <figure class="ia2amp-figure">
159
+ <amp-video src="https://s3.amazonaws.com/instantarticles/examples/fb_hiperlapse_sp.mp4" width="380" height="240"></amp-video>
160
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>Ambient Video Example</h1>
161
+ Tap the video to expand and then tilt to explore. Think of this kind of interactive video as a moving photograph. It gives curious readers an opportunity to explore a living scene and become immersed in a new way. Looping continuously, the video adds atmosphere to an article and can be used to emphasize a section break.
162
+ <cite>Eduardo Tardin/Facebook</cite></figcaption>
163
+ </figure>
164
+ </div>
165
+ <div class="ia2amp-spacing before-p"></div>
166
+ <p class="ia2amp-p">You can also ingest GIFs natively—no need for third-party players.</p>
167
+ <div class="ia2amp-spacing after-p"></div>
168
+ <div class="ia2amp-image">
169
+ <figure class="ia2amp-figure">
170
+ <amp-img layout="responsive" src="https://s3.amazonaws.com/instantarticles/examples/fb_cat.gif" width="380" height="240"></amp-img>
171
+ <figcaption class="ia2amp-figcaption ia2amp-op-large ia2amp-op-vertical-below">
172
+ We know GIFs are exciting, but please try to calm down.
173
+
174
+ <cite>
175
+ Eduardo Tardin/Facebook
176
+ </cite></figcaption>
177
+ </figure>
178
+ </div>
179
+ <div class="ia2amp-spacing before-h1"></div>
180
+ <h1 class="ia2amp-h1"> Cartography </h1>
181
+ <div class="ia2amp-spacing after-h1 before-p"></div>
182
+ <p class="ia2amp-p">Another great way to add information and texture to your stories: maps! Instant Articles has two cartographic features that deliver additional context to news and help readers situate it in the wider world.</p>
183
+ <div class="ia2amp-spacing after-p"></div>
184
+ <div class="ia2amp-image">
185
+ <figure class="ia2amp-figure">
186
+ <amp-img layout="responsive" src="https://s3.amazonaws.com/instantarticles/examples/fb_volcano.jpg" width="380" height="240"></amp-img>
187
+ <figcaption class="ia2amp-figcaption ia2amp-op-small"><h1>Geotagging Example</h1>
188
+ Major news events often occur in locations unfamiliar to readers. Photos and videos in Instant Articles can easily be geotagged, such as this image of Mount Etna, so that readers can tap the globe icon to see where the action is happening. By pinching this map, you can zoom in to see details on the snow-capped slopes of the volcano or zoom out far enough to see the boot of Italy—and beyond.
189
+
190
+ <cite>gnuckx/Flickr</cite></figcaption>
191
+ </figure>
192
+ </div>
193
+ <div class="ia2amp-spacing before-p"></div>
194
+ <p class="ia2amp-p">Rotating contour maps can be inserted in stories with a simple code block, giving readers a bird’s-eye view of topography and the ability to pinch and zoom in or out.</p>
195
+ <div class="ia2amp-spacing after-p"></div>
196
+ <div></div>
197
+ <div class="ia2amp-spacing before-h1"></div>
198
+ <h1 class="ia2amp-h1">Embeds</h1>
199
+ <div class="ia2amp-spacing after-h1 before-p"></div>
200
+ <p class="ia2amp-p">Instant Articles deliver rich, multimedia stories even when you don’t own all the source media files. You might want to publish evolving news about an incident captured in video on YouTube. Or a listicle made up entirely of Tweets, Facebook posts, Instagrams and Vines. Instant Articles seamlessly integrate all types of web-based embeds, including your own interactive graphics, video players, ads and social media, such as this post from Mark Zuckerberg.</p>
201
+ <div class="ia2amp-spacing after-p before-h1"></div>
202
+ <h1 class="ia2amp-h1">Typography</h1>
203
+ <div class="ia2amp-spacing after-h1 before-p"></div>
204
+ <p class="ia2amp-p">Don’t forget to make use of pull quotes and block quotes. Give the quote extra punch by customizing its color using the <a href="https://developers.facebook.com/docs/instant-articles/design/creating-styles">Style Editor</a>. </p>
205
+ <div class="ia2amp-spacing after-p before-pullquote"></div>
206
+ <aside class="ia2amp-pullquote">
207
+ Being connected means having opportunity. We’re connecting the world so one day everyone can fulfill their dreams.
208
+
209
+ <cite>Mark Zuckerberg</cite></aside>
210
+ <div class="ia2amp-spacing after-pullquote before-p"></div>
211
+ <p class="ia2amp-p">To include a long excerpt from another source, such as the following example from Sheryl Sandberg’s <em>Lean In: Women, Work, and the Will to Lead</em>, use a block quote. It’s in the same style as the body text but set off with a rule on the left margin.</p>
212
+ <div class="ia2amp-spacing after-p before-blockquote"></div>
213
+ <blockquote class="ia2amp-blockquote">
214
+ But knowing that things could be worse should not stop us from trying to make them better. When the suffragettes marched in the streets, they envisioned a century later, men and women would be truly equal. A century later, we are still squinting, trying to bring that vision into focus.
215
+ </blockquote>
216
+ <div class="ia2amp-spacing after-blockquote before-h1"></div>
217
+ <h1 class="ia2amp-h1">In-line Related Articles</h1>
218
+ <div class="ia2amp-spacing after-h1 before-p"></div>
219
+ <div class="ia2amp-spacing after-p before-spacing after-p"></div>
220
+ <p class="ia2amp-related-articles">Pique reader interest in more articles from your publication with an in-line related articles element. Choose up to 3 stories and guide readers to other engaging articles. </p>
221
+ <div class="ia2amp-spacing after-spacing after-p before-p"></div>
222
+ <p class="ia2amp-p">You can also add a related articles element in the footer. Scroll down to the bottom of the story to see that feature in action.</p>
223
+ <div class="ia2amp-spacing after-p before-h1"></div>
224
+ <h1 class="ia2amp-h1">Customizing the Formatting</h1>
225
+ <div class="ia2amp-spacing after-h1 before-p"></div>
226
+ <p class="ia2amp-p">To create advanced effects, you can play with different layout settings on your media elements. To create full-bleed layouts with a magazine-like feel, for example, you can crop a series of photos vertically and stack them in-line without spacing or text in between.</p>
227
+ <div class="ia2amp-spacing after-p before-h2"></div>
228
+ <h2 class="ia2amp-h2">Fullscreen Media</h2>
229
+ <div class="ia2amp-spacing after-h2 before-p"></div>
230
+ <p class="ia2amp-p"> Another option is to set images or videos to fullscreen mode, in which case the art crops automatically so that it bleeds off the screen frame and snaps gently into place. It’s kind of like a digital gatefold, giving readers a chance to enjoy a special moment in the story. See how this next image pauses briefly when you scroll it into view.</p>
231
+ <div class="ia2amp-spacing after-p"></div>
232
+ <div class="ia2amp-image">
233
+ <figure class="ia2amp-figure">
234
+ <amp-img layout="responsive" src="https://s3.amazonaws.com/instantarticles/examples/fb_station.jpg" width="380" height="240"></amp-img>
235
+ <figcaption class="ia2amp-figcaption ia2amp-op-large"><h1> “I want to stay as close to the edge as I can without going over. Out on the edge you see all kinds of things you can’t see from the center.” </h1>
236
+ Kurt Vonnegut
237
+ </figcaption>
238
+ </figure>
239
+ </div>
240
+ <div class="ia2amp-spacing before-p"></div>
241
+ <p class="ia2amp-p">Visit the <a href="https://developers.facebook.com/docs/instant-articles/guides/design">Instant Articles Design Guide</a> to learn how to customize your typography and layout. The <a href="https://developers.facebook.com/docs/instant-articles/reference">Format Reference</a> describes the HTML-5 markup used to set interactive features and vary the presentation modes for media.</p>
242
+ <div class="ia2amp-spacing after-p before-h1"></div>
243
+ <h1 class="ia2amp-h1">Twitter embed</h1>
244
+ <div class="ia2amp-spacing after-h1 before-p"></div>
245
+ <p class="ia2amp-p">You can create any embed for other social networks as well. <a href="https://twitter.com/theellenshow/status/440322224407314432">Ellen #oscar</a>. </p>
246
+ <div class="ia2amp-spacing after-p before-h1"></div>
247
+ <h1 class="ia2amp-h1">Next</h1>
248
+ <div class="ia2amp-spacing after-h1 before-p"></div>
249
+ <p class="ia2amp-p">Get inspired by some of the incredible showcase articles that we’ve posted on the <a href="https://www.facebook.com/instantArticles/?fref=ts">Instant Articles Facebook page</a>. Whether you want to create a specially designed long read filled with multimedia elements or to quickly publish an on-the-scene video connected to an evolving news story, Instant Articles has the features and flexibility to help you deliver stories that not only load fast but are hard to forget.</p>
250
+ <div class="ia2amp-spacing after-p before-p"></div>
251
+ <p class="ia2amp-p">Look at this format as a tool box. How you choose to use Instant Articles and what you make with them are limited only by your imagination. We plan on continuously adding tools to the kit, based on your experiences and feedback. Our team is eager to work with publishers, bloggers and independent journalists to help you deliver your stories to new audiences with the most impact and multimedia goodness possible.</p>
252
+ <div class="ia2amp-spacing after-p"></div>
253
+ <footer class="ia2amp-footer">
254
+ <small>© Facebook</small>
255
+ </footer>
256
+ </article>
257
+ </body>
258
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/articles/tutorial-instant-article.html ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html lang="en">
2
+ <head>
3
+ <meta charset="utf-8">
4
+ <link rel="canonical" href="http://blog.wod.expert/example1">
5
+ <link rel="stylesheet" title="default" href="#">
6
+ <title>Instant Articles</title>
7
+ <meta property="fb:article_style" content="default">
8
+ </head>
9
+ <body>
10
+ <article>
11
+ <header>
12
+ <!-- The header image shown inside your article -->
13
+ <figure>
14
+ <figure data-feedback="fb:likes,fb:comments">
15
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_beach_flower.jpg"/>
16
+ <figcaption class="op-vertical-bottom">
17
+ <h1 class="op-vertical-bottom"> 1/5 </h1>
18
+ This caption becomes visible once you enter the slideshow by tapping the first image.
19
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
20
+ </figcaption>
21
+ </figure>
22
+ </figure>
23
+ <!-- The title and subtitle shown in your article -->
24
+ <h1> Instant Articles </h1>
25
+ <h2>Get familiar with your new storytelling tools. Make your media come alive, and keep readers coming back for more</h2>
26
+ <!-- A kicker for your article -->
27
+ <h3 class="op-kicker">
28
+ Introduction
29
+ </h3>
30
+ <!-- The author of your article -->
31
+ <address>
32
+ Instant Articles Team
33
+ </address>
34
+ <!-- The published and last modified time stamps -->
35
+ <time class="op-published" dateTime="2016-2-04T08:00">February 4th 2016, 8:00 AM</time>
36
+ <time class="op-modified" dateTime="2016-2-04T08:00">February 4th 2016, 8:00 AM</time>
37
+ </header>
38
+ <p>Yes, it’s true. Instant Articles open on mobile devices really quickly.</p>
39
+ <p>But that’s just the beginning of it. Instant Articles are buttery smooth and addictive. Once you’ve read a few, you’ll never want to go back.</p>
40
+ <p>The Facebook-native format is packed with innovative ways to tell deeply engaging, interactive stories. Thanks to the powerful, built-in media features and customizable typographic elements, Instant Articles gives you awesome new editorial tools to use while delivering a decidedly superior experience for your readers.</p>
41
+ <p>More than half of Instant Articles readers scroll 90% of the way through their articles, while, historically, 38% of web readers haven’t made it past the first line of other online media.</p>
42
+ <p>This article gives you a quick highlight tour of Instant Articles features and shows you how to make magic with the format. You’ll be happy to find that Instant Articles are not only delightful but surprisingly easy to create.</p>
43
+ <h1> Photography </h1>
44
+ <p>All photographs are interactive by default. When tapped an image will expand to fill the screen, then readers can tilt the phone back and forth to explore the margins.</p>
45
+ <!-- Photo with caption -->
46
+ <figure data-feedback="fb:likes, fb:comments">
47
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_rails.jpg" />
48
+ <figcaption>
49
+ <h1>Photograph Example</h1>
50
+ Tap this image to make it expand. Tilt the phone right and left and see what happens.
51
+ <cite>Eduardo Tardin/Facebook</cite>
52
+ </figcaption>
53
+ </figure>
54
+ <p>To return to the article, tap the image again. The interactive mode works best with high-definition photos containing rich visual information. For low-resolution media, we recommend using the non-interactive setting so that it will remain in-line in the correct aspect ratio and your readers won’t tap into a mushy, pixelated experience.</p>
55
+ <h2>Social Feedback</h2>
56
+ <p>You can add native Facebook Likes and Comments buttons to images, giving readers extra opportunities to engage with individual elements in your stories. This feature currently works for photographs and videos.</p>
57
+ <h2>Slideshow</h2>
58
+ <p>You can also group collections of images into slideshows that scroll horizontally.</p>
59
+ <!-- Slideshow with multiple captions-->
60
+ <figure class="op-slideshow">
61
+ <figure data-feedback="fb:likes,fb:comments">
62
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_beach_flower.jpg"/>
63
+ <figcaption class="op-vertical-bottom">
64
+ <h1 class="op-vertical-bottom"> 1/5 </h1>
65
+ This caption becomes visible once you enter the slideshow by tapping the first image.
66
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
67
+ </figcaption>
68
+ </figure>
69
+ <figure data-feedback="fb:likes,fb:comments">
70
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_rocks.jpg" />
71
+ <figcaption class="op-vertical-bottom">
72
+ <h1 class=op-vertical-bottom> 2/5 </h1>
73
+ Each photo in a slideshow can have its own caption.
74
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
75
+ </figcaption>
76
+ </figure>
77
+ <figure data-feedback="fb:likes,fb:comments">
78
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_sunset.jpg" />
79
+ <figcaption class="op-vertical-bottom">
80
+ <h1 class="op-vertical-bottom"> 3/5 </h1>
81
+ This is the third photo of the slideshow.
82
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
83
+ </figcaption>
84
+ </figure>
85
+ <figure data-feedback="fb:likes,fb:comments">
86
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_cave_ocean.jpg" />
87
+ <figcaption class="op-vertical-bottom">
88
+ <h1 class=op-vertical-bottom> 4/5 </h1>
89
+ The fourth photo of the slideshow.
90
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
91
+ </figcaption>
92
+ </figure>
93
+ <figure data-feedback="fb:likes,fb:comments">
94
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_boat.jpg" />
95
+ <figcaption class="op-vertical-bottom">
96
+ <h1 class=op-vertical-bottom> 5/5 </h1>
97
+ The fifth photo of the slideshow.
98
+ <cite class="op-vertical-bottom">Eduardo Tardin/Facebook</cite>
99
+ </figcaption>
100
+ </figure>
101
+ <figcaption>
102
+ <h1>Slideshow Example</h1>
103
+ The slideshow caption is visible in-line in the main body of the story. You can also add individual captions for each image in the gallery, which become visible only after entering the slideshow. Tap on the first image to open it.
104
+ </figcaption>
105
+ </figure>
106
+ <figure data-mode=aspect-fit>
107
+ <video loop>
108
+ <source src="https://s3.amazonaws.com/instantarticles/examples/fb_movie_pt.mov" type="video/mov" />
109
+ </video>
110
+ <figcaption class="op-vertical-bottom">
111
+ <h1 class=op-vertical-bottom> 6+ </h1>
112
+ Adendum and mixed video + image in a slideshow.
113
+ <cite class="op-vertical-bottom">Instant Articles/Facebook</cite>
114
+ </figcaption>
115
+ </figure>
116
+ <h1>Video</h1>
117
+ <p>Native videos in Instant Articles play automatically, by default, as soon as they scroll into view on the reader’s screen—a powerful way to make the page come to life. You have many options for presenting videos. Here’s an interactive one with play controls. </p>
118
+ <!-- An interactive video with play controls -->
119
+ <figure data-feedback="fb:likes, fb:comments">
120
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_night.jpg" />
121
+ <video controls>
122
+ <source src="https://s3.amazonaws.com/instantarticles/examples/fb_hiperlapse_sp.mp4" />
123
+ </video>
124
+ <figcaption>
125
+ <h1><b>2:57</b> | Interactive Video Example</h1>
126
+ When this video first scrolls into sight, it appears in-line in its correct aspect ratio and plays automatically with the volume off. By tapping it, the video expands to fill the screen and can be turned to view horizontally. The soundtrack becomes audible, and play controls, with scrubber, are accessible.
127
+ </figcaption>
128
+ </figure>
129
+ <p> To hide play controls, tap the video again; the pause/play icons and scrubber can be toggled on and off this way. You can also rotate the phone sideways while the video is in-line to view it in landscape mode.</p>
130
+ <p>Alternately, try using a short video to add color and mood to a story. Disable the play controls and set it to loop with a cross-fade.</p>
131
+ <!-- A video set to loop and cross-fade with play controls disabled -->
132
+ <figure data-feedback="fb:likes, fb:comments" data-mode="aspect-fit">
133
+ <video loop data-fade>
134
+ <source src="https://s3.amazonaws.com/instantarticles/examples/fb_hiperlapse_sp.mp4" />
135
+ </video>
136
+ <figcaption>
137
+ <h1>Ambient Video Example</h1>
138
+ Tap the video to expand and then tilt to explore. Think of this kind of interactive video as a moving photograph. It gives curious readers an opportunity to explore a living scene and become immersed in a new way. Looping continuously, the video adds atmosphere to an article and can be used to emphasize a section break. <cite>Eduardo Tardin/Facebook</cite>
139
+ </figcaption>
140
+ </figure>
141
+ <p>You can also ingest GIFs natively—no need for third-party players.</p>
142
+ <!-- Native GIF example -->
143
+ <figure data-feedback="fb:likes, fb:comments">
144
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_cat.gif" />
145
+ <figcaption class="op-vertical-below op-large">
146
+ We know GIFs are exciting, but please try to calm down.
147
+ <cite>
148
+ Eduardo Tardin/Facebook
149
+ </cite>
150
+ </figcaption>
151
+ </figure>
152
+ <h1> Cartography </h1>
153
+ <p>Another great way to add information and texture to your stories: maps! Instant Articles has two cartographic features that deliver additional context to news and help readers situate it in the wider world.</p>
154
+ <!-- A geotagged image within your article -->
155
+ <figure data-feedback="fb:likes, fb:comments">
156
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_volcano.jpg" />
157
+ <figcaption>
158
+ <h1>Geotagging Example</h1>
159
+ Major news events often occur in locations unfamiliar to readers. Photos and videos in Instant Articles can easily be geotagged, such as this image of Mount Etna, so that readers can tap the globe icon to see where the action is happening. By pinching this map, you can zoom in to see details on the snow-capped slopes of the volcano or zoom out far enough to see the boot of Italy—and beyond.
160
+ <cite>gnuckx/Flickr</cite>
161
+ </figcaption>
162
+ <script type="application/json" class="op-geotag">
163
+ {
164
+ "type": "Feature",
165
+ "geometry":{
166
+ "type": "Point",
167
+ "coordinates":[37.7550, 14.9950] },
168
+ "properties":{
169
+ "title": "Mount Etna, Sicily",
170
+ "style": "hybrid",
171
+ "radius": 10000
172
+ }
173
+ }
174
+ </script>
175
+ </figure>
176
+ <p>Rotating contour maps can be inserted in stories with a simple code block, giving readers a bird’s-eye view of topography and the ability to pinch and zoom in or out.</p>
177
+ <!-- A map within your article -->
178
+ <figure class="op-map">
179
+ <figcaption>
180
+ <h1>Map Example</h1>
181
+ The pin on this map designates Facebook Media Central’s offices in New York City.
182
+ </figcaption>
183
+ <script type="application/json" class="op-geotag">
184
+ {
185
+ "type": "Feature",
186
+ "geometry":
187
+ {
188
+ "type": "Point",
189
+ "coordinates": [ [40.730852, -73.991364], [40.730852, -73.991364] ]
190
+ },
191
+ "properties":
192
+ {
193
+ "title": "770 Broadway, Manhattan, New York",
194
+ "radius": 100000,
195
+ "pivot": true,
196
+ "style": "satellite",
197
+ }
198
+ }
199
+ </script>
200
+ </figure>
201
+ <h1>Embeds</h1>
202
+ <p>Instant Articles deliver rich, multimedia stories even when you don’t own all the source media files. You might want to publish evolving news about an incident captured in video on YouTube. Or a listicle made up entirely of Tweets, Facebook posts, Instagrams and Vines. Instant Articles seamlessly integrate all types of web-based embeds, including your own interactive graphics, video players, ads and social media, such as this post from Mark Zuckerberg.</p>
203
+ <!-- Embedded social media example -->
204
+ <figure class="op-interactive">
205
+ <iframe>
206
+ <!-- Include social media embed code here -->
207
+ <div id="fb-root"></div>
208
+ <script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3"; fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
209
+ <div class="fb-post" data-href="https://www.facebook.com/zuck/posts/10102531565693851" data-width="500">
210
+ <div class="fb-xfbml-parse-ignore">
211
+ <blockquote cite="https://www.facebook.com/zuck/posts/10102531565693851">
212
+ <p>The force is strong with this one.</p>
213
+ Posted by <a href="https://www.facebook.com/zuck">Mark Zuckerberg</a> on <a href="https://www.facebook.com/zuck/posts/10102531565693851">Thursday, December 17, 2015</a>
214
+ </blockquote>
215
+ </div>
216
+ </div>
217
+ </iframe>
218
+ </figure>
219
+ <h1>Typography</h1>
220
+ <p>Don’t forget to make use of pull quotes and block quotes. Give the quote extra punch by customizing its color using the <a href="https://developers.facebook.com/docs/instant-articles/design/creating-styles">Style Editor</a>. </p>
221
+ <!-- A pull quote within your article -->
222
+ <aside>
223
+ Being connected means having opportunity. We’re connecting the world so one day everyone can fulfill their dreams.
224
+ <cite>Mark Zuckerberg</cite>
225
+ </aside>
226
+ <p>To include a long excerpt from another source, such as the following example from Sheryl Sandberg’s <em>Lean In: Women, Work, and the Will to Lead</em>, use a block quote. It’s in the same style as the body text but set off with a rule on the left margin.</p>
227
+ <!-- A block quote within your article -->
228
+ <blockquote>
229
+ But knowing that things could be worse should not stop us from trying to make them better. When the suffragettes marched in the streets, they envisioned a century later, men and women would be truly equal. A century later, we are still squinting, trying to bring that vision into focus.
230
+ </blockquote>
231
+ <h1>In-line Related Articles</h1>
232
+ <p>Pique reader interest in more articles from your publication with an in-line related articles element. Choose up to 3 stories and guide readers to other engaging articles. </p>
233
+ <ul class="op-related-articles" title="Learn more about Instant Articles">
234
+ <li><a href="http://instantarticles.fb.com"></a></li>
235
+ <li><a href="https://www.facebook.com/facebookmedia"></a></li>
236
+ </ul>
237
+ <p>You can also add a related articles element in the footer. Scroll down to the bottom of the story to see that feature in action.</p>
238
+ <h1>Customizing the Formatting</h1>
239
+ <p>To create advanced effects, you can play with different layout settings on your media elements. To create full-bleed layouts with a magazine-like feel, for example, you can crop a series of photos vertically and stack them in-line without spacing or text in between.</p>
240
+ <h2>Fullscreen Media</h2>
241
+ <p> Another option is to set images or videos to fullscreen mode, in which case the art crops automatically so that it bleeds off the screen frame and snaps gently into place. It’s kind of like a digital gatefold, giving readers a chance to enjoy a special moment in the story. See how this next image pauses briefly when you scroll it into view.</p>
242
+ <!-- A fullscreen image that snaps into place -->
243
+ <figure data-mode="fullscreen">
244
+ <img src="https://s3.amazonaws.com/instantarticles/examples/fb_station.jpg" />
245
+ <figcaption class="op-vertical-bottom op-large">
246
+ <h1 class="op-vertical-bottom op-extra-large"> “I want to stay as close to the edge as I can without going over. Out on the edge you see all kinds of things you can’t see from the center.” </h1>
247
+ Kurt Vonnegut
248
+ </figcaption>
249
+ </figure>
250
+ <p>Visit the <a href="https://developers.facebook.com/docs/instant-articles/guides/design">Instant Articles Design Guide</a> to learn how to customize your typography and layout. The <a href="https://developers.facebook.com/docs/instant-articles/reference">Format Reference</a> describes the HTML-5 markup used to set interactive features and vary the presentation modes for media.</p>
251
+ <h1>Twitter embed</h1>
252
+ <p>You can create any embed for other social networks as well. <a href="https://twitter.com/theellenshow/status/440322224407314432">Ellen #oscar</a>. </p>
253
+ <figure class="op-interactive">
254
+ <iframe>
255
+ <blockquote class="twitter-tweet" data-lang="pt">
256
+ <p lang="en" dir="ltr">If only Bradley&#39;s arm was longer. Best photo ever. <a href="https://twitter.com/hashtag/oscars?src=hash">#oscars</a> <a href="http://t.co/C9U5NOtGap">pic.twitter.com/C9U5NOtGap</a></p>
257
+ &mdash; Ellen DeGeneres (@TheEllenShow) <a href="https://twitter.com/TheEllenShow/status/440322224407314432">3 de março de 2014</a>
258
+ </blockquote>
259
+ <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
260
+ </iframe>
261
+ </figure>
262
+ <h1>Next</h1>
263
+ <p>Get inspired by some of the incredible showcase articles that we’ve posted on the <a href="https://www.facebook.com/instantArticles/?fref=ts">Instant Articles Facebook page</a>. Whether you want to create a specially designed long read filled with multimedia elements or to quickly publish an on-the-scene video connected to an evolving news story, Instant Articles has the features and flexibility to help you deliver stories that not only load fast but are hard to forget.</p>
264
+ <p>Look at this format as a tool box. How you choose to use Instant Articles and what you make with them are limited only by your imagination. We plan on continuously adding tools to the kit, based on your experiences and feedback. Our team is eager to work with publishers, bloggers and independent journalists to help you deliver your stories to new audiences with the most impact and multimedia goodness possible.</p>
265
+ <footer>
266
+ <ul class="op-related-articles">
267
+ <li><a href="https://media.fb.com/2016/10/20/bringing-360-videos-and-photos-into-instant-articles"></a></li>
268
+ <li><a href="https://media.fb.com/2014/08/25/2014-emmys/"></a></li>
269
+ </ul>
270
+ <!-- Credits for your article -->
271
+ <aside>The footer section can be used for acknowledgements, author bios, related articles, or any other supplemental information.</aside>
272
+ <!-- Copyright details for your article -->
273
+ <small>© Facebook</small>
274
+ </footer>
275
+ </article>
276
+ </body>
277
+ </html>
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/default.amp-custom.css ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Custom CSS for default style goes here
3
+ */
4
+
5
+ /*
6
+ p {
7
+ background-color: rgb(255,00,00);
8
+ }
9
+ */
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/default.style.json ADDED
@@ -0,0 +1,1128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#FFFFFF",
3
+ "title": {
4
+ "background_color": "#00FFFFFF",
5
+ "border": {
6
+ "bottom": {
7
+ "width": 0
8
+ },
9
+ "left": {
10
+ "width": 0
11
+ },
12
+ "right": {
13
+ "width": 0
14
+ },
15
+ "top": {
16
+ "width": 0
17
+ }
18
+ },
19
+ "capitalization": "NONE",
20
+ "color": "#000000",
21
+ "display": "INLINE",
22
+ "font": "Georgia",
23
+ "line_height_scale": 1,
24
+ "margin": {
25
+ "left": {
26
+ "scaling_factor": 1,
27
+ "size": "DOCUMENT_MARGIN"
28
+ },
29
+ "right": {
30
+ "scaling_factor": 1,
31
+ "size": "DOCUMENT_MARGIN"
32
+ }
33
+ },
34
+ "padding": {
35
+ "bottom": {
36
+ "scaling_factor": 1,
37
+ "size": "NONE"
38
+ },
39
+ "left": {
40
+ "scaling_factor": 1,
41
+ "size": "NONE"
42
+ },
43
+ "right": {
44
+ "scaling_factor": 1,
45
+ "size": "NONE"
46
+ },
47
+ "top": {
48
+ "scaling_factor": 1,
49
+ "size": "NONE"
50
+ }
51
+ },
52
+ "text_alignment": "LEFT",
53
+ "text_size_scale": 1,
54
+ "underline": "NONE"
55
+ },
56
+ "subtitle": {
57
+ "background_color": "#00FFFFFF",
58
+ "border": {
59
+ "bottom": {
60
+ "width": 0
61
+ },
62
+ "left": {
63
+ "width": 0
64
+ },
65
+ "right": {
66
+ "width": 0
67
+ },
68
+ "top": {
69
+ "width": 0
70
+ }
71
+ },
72
+ "capitalization": "NONE",
73
+ "color": "#000000",
74
+ "display": "INLINE",
75
+ "font": "Georgia",
76
+ "line_height_scale": 1,
77
+ "margin": {
78
+ "left": {
79
+ "scaling_factor": 1,
80
+ "size": "DOCUMENT_MARGIN"
81
+ },
82
+ "right": {
83
+ "scaling_factor": 1,
84
+ "size": "DOCUMENT_MARGIN"
85
+ }
86
+ },
87
+ "padding": {
88
+ "bottom": {
89
+ "scaling_factor": 1,
90
+ "size": "NONE"
91
+ },
92
+ "left": {
93
+ "scaling_factor": 1,
94
+ "size": "NONE"
95
+ },
96
+ "right": {
97
+ "scaling_factor": 1,
98
+ "size": "NONE"
99
+ },
100
+ "top": {
101
+ "scaling_factor": 1,
102
+ "size": "NONE"
103
+ }
104
+ },
105
+ "text_alignment": "LEFT",
106
+ "text_size_scale": 1,
107
+ "underline": "NONE"
108
+ },
109
+ "kicker": {
110
+ "background_color": "#00FFFFFF",
111
+ "border": {
112
+ "bottom": {
113
+ "width": 0
114
+ },
115
+ "left": {
116
+ "width": 0
117
+ },
118
+ "right": {
119
+ "width": 0
120
+ },
121
+ "top": {
122
+ "width": 0
123
+ }
124
+ },
125
+ "capitalization": "ALL_CAPS",
126
+ "color": "#000000",
127
+ "display": "INLINE",
128
+ "font": "Helvetica Neue",
129
+ "line_height_scale": 1,
130
+ "margin": {
131
+ "left": {
132
+ "scaling_factor": 1,
133
+ "size": "DOCUMENT_MARGIN"
134
+ },
135
+ "right": {
136
+ "scaling_factor": 1,
137
+ "size": "DOCUMENT_MARGIN"
138
+ }
139
+ },
140
+ "padding": {
141
+ "bottom": {
142
+ "scaling_factor": 1,
143
+ "size": "NONE"
144
+ },
145
+ "left": {
146
+ "scaling_factor": 1,
147
+ "size": "NONE"
148
+ },
149
+ "right": {
150
+ "scaling_factor": 1,
151
+ "size": "NONE"
152
+ },
153
+ "top": {
154
+ "scaling_factor": 1,
155
+ "size": "NONE"
156
+ }
157
+ },
158
+ "text_alignment": "LEFT",
159
+ "text_size_scale": 1,
160
+ "underline": "NONE"
161
+ },
162
+ "byline": {
163
+ "background_color": "#00FFFFFF",
164
+ "border": {
165
+ "bottom": {
166
+ "width": 0
167
+ },
168
+ "left": {
169
+ "width": 0
170
+ },
171
+ "right": {
172
+ "width": 0
173
+ },
174
+ "top": {
175
+ "width": 0
176
+ }
177
+ },
178
+ "capitalization": "ALL_CAPS",
179
+ "color": "#000000",
180
+ "display": "INLINE",
181
+ "font": "Helvetica Neue",
182
+ "line_height_scale": 1,
183
+ "margin": {
184
+ "left": {
185
+ "scaling_factor": 1,
186
+ "size": "DOCUMENT_MARGIN"
187
+ },
188
+ "right": {
189
+ "scaling_factor": 1,
190
+ "size": "DOCUMENT_MARGIN"
191
+ }
192
+ },
193
+ "padding": {
194
+ "bottom": {
195
+ "scaling_factor": 1,
196
+ "size": "NONE"
197
+ },
198
+ "left": {
199
+ "scaling_factor": 1,
200
+ "size": "NONE"
201
+ },
202
+ "right": {
203
+ "scaling_factor": 1,
204
+ "size": "NONE"
205
+ },
206
+ "top": {
207
+ "scaling_factor": 1,
208
+ "size": "NONE"
209
+ }
210
+ },
211
+ "text_alignment": "LEFT",
212
+ "text_size_scale": 1,
213
+ "underline": "NONE"
214
+ },
215
+ "date_style": "MONTH_DAY_YEAR",
216
+ "primary_heading": {
217
+ "background_color": "#00FFFFFF",
218
+ "border": {
219
+ "bottom": {
220
+ "width": 0
221
+ },
222
+ "left": {
223
+ "width": 0
224
+ },
225
+ "right": {
226
+ "width": 0
227
+ },
228
+ "top": {
229
+ "width": 0
230
+ }
231
+ },
232
+ "capitalization": "NONE",
233
+ "color": "#000000",
234
+ "display": "INLINE",
235
+ "font": "Georgia",
236
+ "line_height_scale": 1,
237
+ "margin": {
238
+ "left": {
239
+ "scaling_factor": 1,
240
+ "size": "DOCUMENT_MARGIN"
241
+ },
242
+ "right": {
243
+ "scaling_factor": 1,
244
+ "size": "DOCUMENT_MARGIN"
245
+ }
246
+ },
247
+ "padding": {
248
+ "bottom": {
249
+ "scaling_factor": 1,
250
+ "size": "NONE"
251
+ },
252
+ "left": {
253
+ "scaling_factor": 1,
254
+ "size": "NONE"
255
+ },
256
+ "right": {
257
+ "scaling_factor": 1,
258
+ "size": "NONE"
259
+ },
260
+ "top": {
261
+ "scaling_factor": 1,
262
+ "size": "NONE"
263
+ }
264
+ },
265
+ "text_alignment": "LEFT",
266
+ "text_size_scale": 1,
267
+ "underline": "NONE"
268
+ },
269
+ "secondary_heading": {
270
+ "background_color": "#00FFFFFF",
271
+ "border": {
272
+ "bottom": {
273
+ "width": 0
274
+ },
275
+ "left": {
276
+ "width": 0
277
+ },
278
+ "right": {
279
+ "width": 0
280
+ },
281
+ "top": {
282
+ "width": 0
283
+ }
284
+ },
285
+ "capitalization": "NONE",
286
+ "color": "#000000",
287
+ "display": "INLINE",
288
+ "font": "Georgia",
289
+ "line_height_scale": 1,
290
+ "margin": {
291
+ "left": {
292
+ "scaling_factor": 1,
293
+ "size": "DOCUMENT_MARGIN"
294
+ },
295
+ "right": {
296
+ "scaling_factor": 1,
297
+ "size": "DOCUMENT_MARGIN"
298
+ }
299
+ },
300
+ "padding": {
301
+ "bottom": {
302
+ "scaling_factor": 1,
303
+ "size": "NONE"
304
+ },
305
+ "left": {
306
+ "scaling_factor": 1,
307
+ "size": "NONE"
308
+ },
309
+ "right": {
310
+ "scaling_factor": 1,
311
+ "size": "NONE"
312
+ },
313
+ "top": {
314
+ "scaling_factor": 1,
315
+ "size": "NONE"
316
+ }
317
+ },
318
+ "text_alignment": "LEFT",
319
+ "text_size_scale": 1,
320
+ "underline": "NONE"
321
+ },
322
+ "body_text": {
323
+ "background_color": "#00FFFFFF",
324
+ "border": {
325
+ "bottom": {
326
+ "width": 0
327
+ },
328
+ "left": {
329
+ "width": 0
330
+ },
331
+ "right": {
332
+ "width": 0
333
+ },
334
+ "top": {
335
+ "width": 0
336
+ }
337
+ },
338
+ "capitalization": "NONE",
339
+ "color": "#000000",
340
+ "display": "INLINE",
341
+ "font": "Georgia",
342
+ "line_height_scale": 1,
343
+ "margin": {
344
+ "left": {
345
+ "scaling_factor": 1,
346
+ "size": "DOCUMENT_MARGIN"
347
+ },
348
+ "right": {
349
+ "scaling_factor": 1,
350
+ "size": "DOCUMENT_MARGIN"
351
+ }
352
+ },
353
+ "padding": {
354
+ "bottom": {
355
+ "scaling_factor": 1,
356
+ "size": "NONE"
357
+ },
358
+ "left": {
359
+ "scaling_factor": 1,
360
+ "size": "NONE"
361
+ },
362
+ "right": {
363
+ "scaling_factor": 1,
364
+ "size": "NONE"
365
+ },
366
+ "top": {
367
+ "scaling_factor": 1,
368
+ "size": "NONE"
369
+ }
370
+ },
371
+ "text_alignment": "LEFT",
372
+ "text_size_scale": 1,
373
+ "underline": "NONE"
374
+ },
375
+ "inline_link": {
376
+ "background_color": "#00FFFFFF",
377
+ "border": {
378
+ "bottom": {
379
+ "width": 0
380
+ },
381
+ "left": {
382
+ "width": 0
383
+ },
384
+ "right": {
385
+ "width": 0
386
+ },
387
+ "top": {
388
+ "width": 0
389
+ }
390
+ },
391
+ "capitalization": "NONE",
392
+ "color": "#000000",
393
+ "display": "INLINE",
394
+ "font": "Georgia",
395
+ "line_height_scale": 1,
396
+ "margin": {
397
+ "left": {
398
+ "scaling_factor": 1,
399
+ "size": "DOCUMENT_MARGIN"
400
+ },
401
+ "right": {
402
+ "scaling_factor": 1,
403
+ "size": "DOCUMENT_MARGIN"
404
+ }
405
+ },
406
+ "padding": {
407
+ "bottom": {
408
+ "scaling_factor": 1,
409
+ "size": "NONE"
410
+ },
411
+ "left": {
412
+ "scaling_factor": 1,
413
+ "size": "NONE"
414
+ },
415
+ "right": {
416
+ "scaling_factor": 1,
417
+ "size": "NONE"
418
+ },
419
+ "top": {
420
+ "scaling_factor": 1,
421
+ "size": "NONE"
422
+ }
423
+ },
424
+ "text_alignment": "LEFT",
425
+ "text_size_scale": 1,
426
+ "underline": "SIMPLE_UNDERLINE"
427
+ },
428
+ "block_quote": {
429
+ "background_color": "#00FFFFFF",
430
+ "border": {
431
+ "bottom": {
432
+ "color": "#000000",
433
+ "width": 0
434
+ },
435
+ "left": {
436
+ "color": "#000000",
437
+ "width": 2
438
+ },
439
+ "right": {
440
+ "color": "#000000",
441
+ "width": 0
442
+ },
443
+ "top": {
444
+ "color": "#000000",
445
+ "width": 0
446
+ }
447
+ },
448
+ "capitalization": "NONE",
449
+ "color": "#000000",
450
+ "display": "INLINE",
451
+ "font": "Georgia",
452
+ "line_height_scale": 1,
453
+ "margin": {
454
+ "left": {
455
+ "scaling_factor": 1,
456
+ "size": "DOCUMENT_MARGIN"
457
+ },
458
+ "right": {
459
+ "scaling_factor": 1,
460
+ "size": "DOCUMENT_MARGIN"
461
+ }
462
+ },
463
+ "padding": {
464
+ "bottom": {
465
+ "scaling_factor": 1,
466
+ "size": "NONE"
467
+ },
468
+ "left": {
469
+ "scaling_factor": 1,
470
+ "size": "MEDIUM"
471
+ },
472
+ "right": {
473
+ "scaling_factor": 1,
474
+ "size": "SMALL"
475
+ },
476
+ "top": {
477
+ "scaling_factor": 1,
478
+ "size": "NONE"
479
+ }
480
+ },
481
+ "text_alignment": "LEFT",
482
+ "text_size_scale": 1,
483
+ "underline": "NONE"
484
+ },
485
+ "pull_quote": {
486
+ "background_color": "#00FFFFFF",
487
+ "border": {
488
+ "bottom": {
489
+ "width": 0
490
+ },
491
+ "left": {
492
+ "width": 0
493
+ },
494
+ "right": {
495
+ "width": 0
496
+ },
497
+ "top": {
498
+ "width": 0
499
+ }
500
+ },
501
+ "capitalization": "NONE",
502
+ "color": "#000000",
503
+ "display": "INLINE",
504
+ "font": "Georgia",
505
+ "line_height_scale": 1,
506
+ "margin": {
507
+ "left": {
508
+ "scaling_factor": 1,
509
+ "size": "DOCUMENT_MARGIN"
510
+ },
511
+ "right": {
512
+ "scaling_factor": 1,
513
+ "size": "DOCUMENT_MARGIN"
514
+ }
515
+ },
516
+ "padding": {
517
+ "bottom": {
518
+ "scaling_factor": 1,
519
+ "size": "NONE"
520
+ },
521
+ "left": {
522
+ "scaling_factor": 1,
523
+ "size": "NONE"
524
+ },
525
+ "right": {
526
+ "scaling_factor": 1,
527
+ "size": "NONE"
528
+ },
529
+ "top": {
530
+ "scaling_factor": 1,
531
+ "size": "NONE"
532
+ }
533
+ },
534
+ "text_alignment": "LEFT",
535
+ "text_size_scale": 1,
536
+ "underline": "NONE"
537
+ },
538
+ "pull_quote_attribution": {
539
+ "background_color": "#00FFFFFF",
540
+ "border": {
541
+ "bottom": {
542
+ "width": 0
543
+ },
544
+ "left": {
545
+ "width": 0
546
+ },
547
+ "right": {
548
+ "width": 0
549
+ },
550
+ "top": {
551
+ "width": 0
552
+ }
553
+ },
554
+ "capitalization": "ALL_CAPS",
555
+ "color": "#000000",
556
+ "display": "INLINE",
557
+ "font": "Helvetica Neue",
558
+ "line_height_scale": 1,
559
+ "margin": {
560
+ "left": {
561
+ "scaling_factor": 1,
562
+ "size": "DOCUMENT_MARGIN"
563
+ },
564
+ "right": {
565
+ "scaling_factor": 1,
566
+ "size": "DOCUMENT_MARGIN"
567
+ }
568
+ },
569
+ "padding": {
570
+ "bottom": {
571
+ "scaling_factor": 1,
572
+ "size": "NONE"
573
+ },
574
+ "left": {
575
+ "scaling_factor": 1,
576
+ "size": "NONE"
577
+ },
578
+ "right": {
579
+ "scaling_factor": 1,
580
+ "size": "NONE"
581
+ },
582
+ "top": {
583
+ "scaling_factor": 1,
584
+ "size": "NONE"
585
+ }
586
+ },
587
+ "text_alignment": "LEFT",
588
+ "text_size_scale": 1,
589
+ "underline": "NONE"
590
+ },
591
+ "caption_title_small": {
592
+ "background_color": "#00FFFFFF",
593
+ "border": {
594
+ "bottom": {
595
+ "width": 0
596
+ },
597
+ "left": {
598
+ "width": 0
599
+ },
600
+ "right": {
601
+ "width": 0
602
+ },
603
+ "top": {
604
+ "width": 0
605
+ }
606
+ },
607
+ "capitalization": "NONE",
608
+ "color": "#808080",
609
+ "display": "INLINE",
610
+ "font": "Helvetica Neue Bold",
611
+ "line_height_scale": 1,
612
+ "margin": {
613
+ "left": {
614
+ "scaling_factor": 1,
615
+ "size": "DOCUMENT_MARGIN"
616
+ },
617
+ "right": {
618
+ "scaling_factor": 1,
619
+ "size": "DOCUMENT_MARGIN"
620
+ }
621
+ },
622
+ "padding": {
623
+ "bottom": {
624
+ "scaling_factor": 1,
625
+ "size": "NONE"
626
+ },
627
+ "left": {
628
+ "scaling_factor": 1,
629
+ "size": "NONE"
630
+ },
631
+ "right": {
632
+ "scaling_factor": 1,
633
+ "size": "NONE"
634
+ },
635
+ "top": {
636
+ "scaling_factor": 1,
637
+ "size": "NONE"
638
+ }
639
+ },
640
+ "text_alignment": "LEFT",
641
+ "text_size_scale": 1,
642
+ "underline": "NONE"
643
+ },
644
+ "caption_title": {
645
+ "background_color": "#00FFFFFF",
646
+ "border": {
647
+ "bottom": {
648
+ "width": 0
649
+ },
650
+ "left": {
651
+ "width": 0
652
+ },
653
+ "right": {
654
+ "width": 0
655
+ },
656
+ "top": {
657
+ "width": 0
658
+ }
659
+ },
660
+ "capitalization": "NONE",
661
+ "color": "#808080",
662
+ "display": "INLINE",
663
+ "font": "Georgia",
664
+ "line_height_scale": 1,
665
+ "margin": {
666
+ "left": {
667
+ "scaling_factor": 1,
668
+ "size": "DOCUMENT_MARGIN"
669
+ },
670
+ "right": {
671
+ "scaling_factor": 1,
672
+ "size": "DOCUMENT_MARGIN"
673
+ }
674
+ },
675
+ "padding": {
676
+ "bottom": {
677
+ "scaling_factor": 1,
678
+ "size": "NONE"
679
+ },
680
+ "left": {
681
+ "scaling_factor": 1,
682
+ "size": "NONE"
683
+ },
684
+ "right": {
685
+ "scaling_factor": 1,
686
+ "size": "NONE"
687
+ },
688
+ "top": {
689
+ "scaling_factor": 1,
690
+ "size": "NONE"
691
+ }
692
+ },
693
+ "text_alignment": "LEFT",
694
+ "text_size_scale": 1,
695
+ "underline": "NONE"
696
+ },
697
+ "caption_title_large": {
698
+ "background_color": "#00FFFFFF",
699
+ "border": {
700
+ "bottom": {
701
+ "width": 0
702
+ },
703
+ "left": {
704
+ "width": 0
705
+ },
706
+ "right": {
707
+ "width": 0
708
+ },
709
+ "top": {
710
+ "width": 0
711
+ }
712
+ },
713
+ "capitalization": "NONE",
714
+ "color": "#808080",
715
+ "display": "INLINE",
716
+ "font": "Georgia",
717
+ "line_height_scale": 1,
718
+ "margin": {
719
+ "left": {
720
+ "scaling_factor": 1,
721
+ "size": "DOCUMENT_MARGIN"
722
+ },
723
+ "right": {
724
+ "scaling_factor": 1,
725
+ "size": "DOCUMENT_MARGIN"
726
+ }
727
+ },
728
+ "padding": {
729
+ "bottom": {
730
+ "scaling_factor": 1,
731
+ "size": "NONE"
732
+ },
733
+ "left": {
734
+ "scaling_factor": 1,
735
+ "size": "NONE"
736
+ },
737
+ "right": {
738
+ "scaling_factor": 1,
739
+ "size": "NONE"
740
+ },
741
+ "top": {
742
+ "scaling_factor": 1,
743
+ "size": "NONE"
744
+ }
745
+ },
746
+ "text_alignment": "LEFT",
747
+ "text_size_scale": 1,
748
+ "underline": "NONE"
749
+ },
750
+ "caption_title_extra_large": {
751
+ "background_color": "#00FFFFFF",
752
+ "border": {
753
+ "bottom": {
754
+ "width": 0
755
+ },
756
+ "left": {
757
+ "width": 0
758
+ },
759
+ "right": {
760
+ "width": 0
761
+ },
762
+ "top": {
763
+ "width": 0
764
+ }
765
+ },
766
+ "capitalization": "NONE",
767
+ "color": "#808080",
768
+ "display": "INLINE",
769
+ "font": "Georgia",
770
+ "line_height_scale": 1,
771
+ "margin": {
772
+ "left": {
773
+ "scaling_factor": 1,
774
+ "size": "DOCUMENT_MARGIN"
775
+ },
776
+ "right": {
777
+ "scaling_factor": 1,
778
+ "size": "DOCUMENT_MARGIN"
779
+ }
780
+ },
781
+ "padding": {
782
+ "bottom": {
783
+ "scaling_factor": 1,
784
+ "size": "NONE"
785
+ },
786
+ "left": {
787
+ "scaling_factor": 1,
788
+ "size": "NONE"
789
+ },
790
+ "right": {
791
+ "scaling_factor": 1,
792
+ "size": "NONE"
793
+ },
794
+ "top": {
795
+ "scaling_factor": 1,
796
+ "size": "NONE"
797
+ }
798
+ },
799
+ "text_alignment": "LEFT",
800
+ "text_size_scale": 1,
801
+ "underline": "NONE"
802
+ },
803
+ "caption_credit": {
804
+ "background_color": "#00FFFFFF",
805
+ "border": {
806
+ "bottom": {
807
+ "width": 0
808
+ },
809
+ "left": {
810
+ "width": 0
811
+ },
812
+ "right": {
813
+ "width": 0
814
+ },
815
+ "top": {
816
+ "width": 0
817
+ }
818
+ },
819
+ "capitalization": "ALL_CAPS",
820
+ "color": "#BFBFBF",
821
+ "display": "INLINE",
822
+ "font": "Helvetica Neue",
823
+ "line_height_scale": 1,
824
+ "margin": {
825
+ "left": {
826
+ "scaling_factor": 1,
827
+ "size": "DOCUMENT_MARGIN"
828
+ },
829
+ "right": {
830
+ "scaling_factor": 1,
831
+ "size": "DOCUMENT_MARGIN"
832
+ }
833
+ },
834
+ "padding": {
835
+ "bottom": {
836
+ "scaling_factor": 1,
837
+ "size": "NONE"
838
+ },
839
+ "left": {
840
+ "scaling_factor": 1,
841
+ "size": "NONE"
842
+ },
843
+ "right": {
844
+ "scaling_factor": 1,
845
+ "size": "NONE"
846
+ },
847
+ "top": {
848
+ "scaling_factor": 1,
849
+ "size": "NONE"
850
+ }
851
+ },
852
+ "text_alignment": "LEFT",
853
+ "text_size_scale": 1,
854
+ "underline": "NONE"
855
+ },
856
+ "caption_description_small": {
857
+ "background_color": "#00FFFFFF",
858
+ "border": {
859
+ "bottom": {
860
+ "width": 0
861
+ },
862
+ "left": {
863
+ "width": 0
864
+ },
865
+ "right": {
866
+ "width": 0
867
+ },
868
+ "top": {
869
+ "width": 0
870
+ }
871
+ },
872
+ "capitalization": "NONE",
873
+ "color": "#808080",
874
+ "display": "INLINE",
875
+ "font": "Helvetica Neue",
876
+ "line_height_scale": 1,
877
+ "margin": {
878
+ "left": {
879
+ "scaling_factor": 1,
880
+ "size": "DOCUMENT_MARGIN"
881
+ },
882
+ "right": {
883
+ "scaling_factor": 1,
884
+ "size": "DOCUMENT_MARGIN"
885
+ }
886
+ },
887
+ "padding": {
888
+ "bottom": {
889
+ "scaling_factor": 1,
890
+ "size": "NONE"
891
+ },
892
+ "left": {
893
+ "scaling_factor": 1,
894
+ "size": "NONE"
895
+ },
896
+ "right": {
897
+ "scaling_factor": 1,
898
+ "size": "NONE"
899
+ },
900
+ "top": {
901
+ "scaling_factor": 1,
902
+ "size": "NONE"
903
+ }
904
+ },
905
+ "text_alignment": "LEFT",
906
+ "text_size_scale": 1,
907
+ "underline": "NONE"
908
+ },
909
+ "caption_description": {
910
+ "background_color": "#00FFFFFF",
911
+ "border": {
912
+ "bottom": {
913
+ "width": 0
914
+ },
915
+ "left": {
916
+ "width": 0
917
+ },
918
+ "right": {
919
+ "width": 0
920
+ },
921
+ "top": {
922
+ "width": 0
923
+ }
924
+ },
925
+ "capitalization": "NONE",
926
+ "color": "#808080",
927
+ "display": "INLINE",
928
+ "font": "Georgia",
929
+ "line_height_scale": 1,
930
+ "margin": {
931
+ "left": {
932
+ "scaling_factor": 1,
933
+ "size": "DOCUMENT_MARGIN"
934
+ },
935
+ "right": {
936
+ "scaling_factor": 1,
937
+ "size": "DOCUMENT_MARGIN"
938
+ }
939
+ },
940
+ "padding": {
941
+ "bottom": {
942
+ "scaling_factor": 1,
943
+ "size": "NONE"
944
+ },
945
+ "left": {
946
+ "scaling_factor": 1,
947
+ "size": "NONE"
948
+ },
949
+ "right": {
950
+ "scaling_factor": 1,
951
+ "size": "NONE"
952
+ },
953
+ "top": {
954
+ "scaling_factor": 1,
955
+ "size": "NONE"
956
+ }
957
+ },
958
+ "text_alignment": "LEFT",
959
+ "text_size_scale": 1,
960
+ "underline": "NONE"
961
+ },
962
+ "caption_description_large": {
963
+ "background_color": "#00FFFFFF",
964
+ "border": {
965
+ "bottom": {
966
+ "width": 0
967
+ },
968
+ "left": {
969
+ "width": 0
970
+ },
971
+ "right": {
972
+ "width": 0
973
+ },
974
+ "top": {
975
+ "width": 0
976
+ }
977
+ },
978
+ "capitalization": "NONE",
979
+ "color": "#808080",
980
+ "display": "INLINE",
981
+ "font": "Georgia",
982
+ "line_height_scale": 1,
983
+ "margin": {
984
+ "left": {
985
+ "scaling_factor": 1,
986
+ "size": "DOCUMENT_MARGIN"
987
+ },
988
+ "right": {
989
+ "scaling_factor": 1,
990
+ "size": "DOCUMENT_MARGIN"
991
+ }
992
+ },
993
+ "padding": {
994
+ "bottom": {
995
+ "scaling_factor": 1,
996
+ "size": "NONE"
997
+ },
998
+ "left": {
999
+ "scaling_factor": 1,
1000
+ "size": "NONE"
1001
+ },
1002
+ "right": {
1003
+ "scaling_factor": 1,
1004
+ "size": "NONE"
1005
+ },
1006
+ "top": {
1007
+ "scaling_factor": 1,
1008
+ "size": "NONE"
1009
+ }
1010
+ },
1011
+ "text_alignment": "LEFT",
1012
+ "text_size_scale": 1,
1013
+ "underline": "NONE"
1014
+ },
1015
+ "caption_description_extra_large": {
1016
+ "background_color": "#00FFFFFF",
1017
+ "border": {
1018
+ "bottom": {
1019
+ "width": 0
1020
+ },
1021
+ "left": {
1022
+ "width": 0
1023
+ },
1024
+ "right": {
1025
+ "width": 0
1026
+ },
1027
+ "top": {
1028
+ "width": 0
1029
+ }
1030
+ },
1031
+ "capitalization": "NONE",
1032
+ "color": "#808080",
1033
+ "display": "INLINE",
1034
+ "font": "Georgia",
1035
+ "line_height_scale": 1,
1036
+ "margin": {
1037
+ "left": {
1038
+ "scaling_factor": 1,
1039
+ "size": "DOCUMENT_MARGIN"
1040
+ },
1041
+ "right": {
1042
+ "scaling_factor": 1,
1043
+ "size": "DOCUMENT_MARGIN"
1044
+ }
1045
+ },
1046
+ "padding": {
1047
+ "bottom": {
1048
+ "scaling_factor": 1,
1049
+ "size": "NONE"
1050
+ },
1051
+ "left": {
1052
+ "scaling_factor": 1,
1053
+ "size": "NONE"
1054
+ },
1055
+ "right": {
1056
+ "scaling_factor": 1,
1057
+ "size": "NONE"
1058
+ },
1059
+ "top": {
1060
+ "scaling_factor": 1,
1061
+ "size": "NONE"
1062
+ }
1063
+ },
1064
+ "text_alignment": "LEFT",
1065
+ "text_size_scale": 1,
1066
+ "underline": "NONE"
1067
+ },
1068
+ "footer": {
1069
+ "background_color": "#00FFFFFF",
1070
+ "border": {
1071
+ "bottom": {
1072
+ "width": 0
1073
+ },
1074
+ "left": {
1075
+ "width": 0
1076
+ },
1077
+ "right": {
1078
+ "width": 0
1079
+ },
1080
+ "top": {
1081
+ "width": 0
1082
+ }
1083
+ },
1084
+ "capitalization": "NONE",
1085
+ "color": "#000000",
1086
+ "display": "INLINE",
1087
+ "font": "Helvetica Neue",
1088
+ "line_height_scale": 1,
1089
+ "margin": {
1090
+ "left": {
1091
+ "scaling_factor": 1,
1092
+ "size": "DOCUMENT_MARGIN"
1093
+ },
1094
+ "right": {
1095
+ "scaling_factor": 1,
1096
+ "size": "DOCUMENT_MARGIN"
1097
+ }
1098
+ },
1099
+ "padding": {
1100
+ "bottom": {
1101
+ "scaling_factor": 1,
1102
+ "size": "NONE"
1103
+ },
1104
+ "left": {
1105
+ "scaling_factor": 1,
1106
+ "size": "NONE"
1107
+ },
1108
+ "right": {
1109
+ "scaling_factor": 1,
1110
+ "size": "NONE"
1111
+ },
1112
+ "top": {
1113
+ "scaling_factor": 1,
1114
+ "size": "NONE"
1115
+ }
1116
+ },
1117
+ "text_alignment": "LEFT",
1118
+ "text_size_scale": 1,
1119
+ "underline": "NONE"
1120
+ },
1121
+ "id": "1282952941794244",
1122
+ "name": "default",
1123
+ "is_default": true,
1124
+ "header": {
1125
+ "accent_color": "#989898",
1126
+ "background_color": "#FFFFFF"
1127
+ }
1128
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/AMP/wod-gray.style.json ADDED
@@ -0,0 +1,993 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#EEEEEE",
3
+ "header": {
4
+ "logo": {
5
+ "dataURL": null,
6
+ "id": "1229084557204785",
7
+ "full_resolution_url": "https://fb-s-c-a.akamaihd.net/h-ak-xpa1/v/t39.5687-6/17351511_1229084560538118_5982709905105092608_n.png?_nc_log=1&oh=c8337650a88e7fdb6d31088a15a7d9d8&oe=599B24B5&__gda__=1502041799_7139cf314c7cdaa52fa44ba26fd253f8",
8
+ "full_resolution_width": 2600,
9
+ "full_resolution_height": 512,
10
+ "thumbnail_url": "https://fb-s-d-a.akamaihd.net/h-ak-xpf1/v/t39.5687-6/17634152_1374280939304404_1278222734471462912_n.png?_nc_log=1&oh=d3e95b10e960a9527ad643c47d821160&oe=598664D5&__gda__=1498346669_5ee6f5a2bd8d17474bfb46398d9b888a",
11
+ "article_scaling_factor": 1
12
+ },
13
+ "logo_scale": 1,
14
+ "accent_color": "#000000",
15
+ "background_color": "#666666",
16
+ "bar_color": null
17
+ },
18
+ "kicker": {
19
+ "font": "Helvetica Neue",
20
+ "color": "#000000",
21
+ "background_color": "#00FFFFFF",
22
+ "capitalization": "ALL_CAPS",
23
+ "text_alignment": "LEFT",
24
+ "display": "INLINE",
25
+ "line_height_scale": 1,
26
+ "text_size_scale": 1,
27
+ "margin": {
28
+ "right": {
29
+ "scaling_factor": 1,
30
+ "size": "DOCUMENT_MARGIN"
31
+ },
32
+ "left": {
33
+ "scaling_factor": 1,
34
+ "size": "DOCUMENT_MARGIN"
35
+ }
36
+ },
37
+ "border": {
38
+ "top": {
39
+ "width": 0
40
+ },
41
+ "right": {
42
+ "width": 0
43
+ },
44
+ "bottom": {
45
+ "width": 0
46
+ },
47
+ "left": {
48
+ "width": 0
49
+ }
50
+ },
51
+ "padding": {
52
+ "top": {
53
+ "scaling_factor": 1,
54
+ "size": "NONE"
55
+ },
56
+ "right": {
57
+ "scaling_factor": 1,
58
+ "size": "NONE"
59
+ },
60
+ "bottom": {
61
+ "scaling_factor": 1,
62
+ "size": "NONE"
63
+ },
64
+ "left": {
65
+ "scaling_factor": 1,
66
+ "size": "NONE"
67
+ }
68
+ }
69
+ },
70
+ "title": {
71
+ "font": "Georgia",
72
+ "color": "#000000",
73
+ "background_color": "#00FFFFFF",
74
+ "capitalization": "NONE",
75
+ "text_alignment": "LEFT",
76
+ "display": "INLINE",
77
+ "line_height_scale": 1,
78
+ "text_size_scale": 1,
79
+ "margin": {
80
+ "right": {
81
+ "scaling_factor": 1,
82
+ "size": "DOCUMENT_MARGIN"
83
+ },
84
+ "left": {
85
+ "scaling_factor": 1,
86
+ "size": "DOCUMENT_MARGIN"
87
+ }
88
+ },
89
+ "border": {
90
+ "top": {
91
+ "width": 0
92
+ },
93
+ "right": {
94
+ "width": 0
95
+ },
96
+ "bottom": {
97
+ "width": 0
98
+ },
99
+ "left": {
100
+ "width": 0
101
+ }
102
+ },
103
+ "padding": {
104
+ "top": {
105
+ "scaling_factor": 1,
106
+ "size": "NONE"
107
+ },
108
+ "right": {
109
+ "scaling_factor": 1,
110
+ "size": "NONE"
111
+ },
112
+ "bottom": {
113
+ "scaling_factor": 1,
114
+ "size": "NONE"
115
+ },
116
+ "left": {
117
+ "scaling_factor": 1,
118
+ "size": "NONE"
119
+ }
120
+ }
121
+ },
122
+ "subtitle": {
123
+ "font": "Georgia",
124
+ "color": "#000000",
125
+ "background_color": "#00FFFFFF",
126
+ "capitalization": "NONE",
127
+ "text_alignment": "LEFT",
128
+ "display": "INLINE",
129
+ "line_height_scale": 1,
130
+ "text_size_scale": 1,
131
+ "margin": {
132
+ "right": {
133
+ "scaling_factor": 1,
134
+ "size": "DOCUMENT_MARGIN"
135
+ },
136
+ "left": {
137
+ "scaling_factor": 1,
138
+ "size": "DOCUMENT_MARGIN"
139
+ }
140
+ },
141
+ "border": {
142
+ "top": {
143
+ "width": 0
144
+ },
145
+ "right": {
146
+ "width": 0
147
+ },
148
+ "bottom": {
149
+ "width": 0
150
+ },
151
+ "left": {
152
+ "width": 0
153
+ }
154
+ },
155
+ "padding": {
156
+ "top": {
157
+ "scaling_factor": 1,
158
+ "size": "NONE"
159
+ },
160
+ "right": {
161
+ "scaling_factor": 1,
162
+ "size": "NONE"
163
+ },
164
+ "bottom": {
165
+ "scaling_factor": 1,
166
+ "size": "NONE"
167
+ },
168
+ "left": {
169
+ "scaling_factor": 1,
170
+ "size": "NONE"
171
+ }
172
+ }
173
+ },
174
+ "byline": {
175
+ "font": "Helvetica Neue",
176
+ "color": "#000000",
177
+ "capitalization": "ALL_CAPS",
178
+ "text_alignment": "LEFT",
179
+ "line_height_scale": 1,
180
+ "text_size_scale": 1,
181
+ "margin": {
182
+ "right": {
183
+ "scaling_factor": 1,
184
+ "size": "DOCUMENT_MARGIN"
185
+ },
186
+ "left": {
187
+ "scaling_factor": 1,
188
+ "size": "DOCUMENT_MARGIN"
189
+ }
190
+ }
191
+ },
192
+ "date_style": "MONTH_DAY_YEAR",
193
+ "primary_heading": {
194
+ "font": "Georgia",
195
+ "color": "#000000",
196
+ "background_color": "#00FFFFFF",
197
+ "capitalization": "NONE",
198
+ "text_alignment": "LEFT",
199
+ "display": "INLINE",
200
+ "line_height_scale": 1,
201
+ "text_size_scale": 1,
202
+ "margin": {
203
+ "right": {
204
+ "scaling_factor": 1,
205
+ "size": "DOCUMENT_MARGIN"
206
+ },
207
+ "left": {
208
+ "scaling_factor": 1,
209
+ "size": "DOCUMENT_MARGIN"
210
+ }
211
+ },
212
+ "border": {
213
+ "top": {
214
+ "width": 0
215
+ },
216
+ "right": {
217
+ "width": 0
218
+ },
219
+ "bottom": {
220
+ "width": 0
221
+ },
222
+ "left": {
223
+ "width": 0
224
+ }
225
+ },
226
+ "padding": {
227
+ "top": {
228
+ "scaling_factor": 1,
229
+ "size": "NONE"
230
+ },
231
+ "right": {
232
+ "scaling_factor": 1,
233
+ "size": "NONE"
234
+ },
235
+ "bottom": {
236
+ "scaling_factor": 1,
237
+ "size": "NONE"
238
+ },
239
+ "left": {
240
+ "scaling_factor": 1,
241
+ "size": "NONE"
242
+ }
243
+ }
244
+ },
245
+ "secondary_heading": {
246
+ "font": "Georgia",
247
+ "color": "#000000",
248
+ "background_color": "#00FFFFFF",
249
+ "capitalization": "NONE",
250
+ "text_alignment": "LEFT",
251
+ "display": "INLINE",
252
+ "line_height_scale": 1,
253
+ "text_size_scale": 1,
254
+ "margin": {
255
+ "right": {
256
+ "scaling_factor": 1,
257
+ "size": "DOCUMENT_MARGIN"
258
+ },
259
+ "left": {
260
+ "scaling_factor": 1,
261
+ "size": "DOCUMENT_MARGIN"
262
+ }
263
+ },
264
+ "border": {
265
+ "top": {
266
+ "width": 0
267
+ },
268
+ "right": {
269
+ "width": 0
270
+ },
271
+ "bottom": {
272
+ "width": 0
273
+ },
274
+ "left": {
275
+ "width": 0
276
+ }
277
+ },
278
+ "padding": {
279
+ "top": {
280
+ "scaling_factor": 1,
281
+ "size": "NONE"
282
+ },
283
+ "right": {
284
+ "scaling_factor": 1,
285
+ "size": "NONE"
286
+ },
287
+ "bottom": {
288
+ "scaling_factor": 1,
289
+ "size": "NONE"
290
+ },
291
+ "left": {
292
+ "scaling_factor": 1,
293
+ "size": "NONE"
294
+ }
295
+ }
296
+ },
297
+ "body_text": {
298
+ "font": "Georgia",
299
+ "color": "#000000",
300
+ "capitalization": "NONE",
301
+ "text_alignment": "LEFT",
302
+ "line_height_scale": 1,
303
+ "text_size_scale": 1,
304
+ "margin": {
305
+ "right": {
306
+ "scaling_factor": 1,
307
+ "size": "DOCUMENT_MARGIN"
308
+ },
309
+ "left": {
310
+ "scaling_factor": 1,
311
+ "size": "DOCUMENT_MARGIN"
312
+ }
313
+ }
314
+ },
315
+ "inline_link": {
316
+ "color": "#000000",
317
+ "underline": "SIMPLE_UNDERLINE",
318
+ "font": "Georgia"
319
+ },
320
+ "block_quote": {
321
+ "font": "Georgia",
322
+ "color": "#000000",
323
+ "background_color": "#00FFFFFF",
324
+ "capitalization": "NONE",
325
+ "text_alignment": "LEFT",
326
+ "display": "BLOCK",
327
+ "line_height_scale": 1,
328
+ "text_size_scale": 1,
329
+ "margin": {
330
+ "right": {
331
+ "scaling_factor": 1,
332
+ "size": "DOCUMENT_MARGIN"
333
+ },
334
+ "left": {
335
+ "scaling_factor": 1,
336
+ "size": "DOCUMENT_MARGIN"
337
+ }
338
+ },
339
+ "border": {
340
+ "top": {
341
+ "color": "#000000",
342
+ "width": 0
343
+ },
344
+ "right": {
345
+ "color": "#000000",
346
+ "width": 0
347
+ },
348
+ "bottom": {
349
+ "color": "#000000",
350
+ "width": 0
351
+ },
352
+ "left": {
353
+ "color": "#000000",
354
+ "width": 2
355
+ }
356
+ },
357
+ "padding": {
358
+ "top": {
359
+ "scaling_factor": 1,
360
+ "size": "NONE"
361
+ },
362
+ "right": {
363
+ "scaling_factor": 1,
364
+ "size": "SMALL"
365
+ },
366
+ "bottom": {
367
+ "scaling_factor": 1,
368
+ "size": "NONE"
369
+ },
370
+ "left": {
371
+ "scaling_factor": 1,
372
+ "size": "MEDIUM"
373
+ }
374
+ }
375
+ },
376
+ "pull_quote": {
377
+ "font": "Georgia",
378
+ "color": "#000000",
379
+ "background_color": "#00FFFFFF",
380
+ "capitalization": "NONE",
381
+ "text_alignment": "LEFT",
382
+ "display": "INLINE",
383
+ "line_height_scale": 1,
384
+ "text_size_scale": 1,
385
+ "margin": {
386
+ "right": {
387
+ "scaling_factor": 1,
388
+ "size": "DOCUMENT_MARGIN"
389
+ },
390
+ "left": {
391
+ "scaling_factor": 1,
392
+ "size": "DOCUMENT_MARGIN"
393
+ }
394
+ },
395
+ "border": {
396
+ "top": {
397
+ "width": 0
398
+ },
399
+ "right": {
400
+ "width": 0
401
+ },
402
+ "bottom": {
403
+ "width": 0
404
+ },
405
+ "left": {
406
+ "width": 0
407
+ }
408
+ },
409
+ "padding": {
410
+ "top": {
411
+ "scaling_factor": 1,
412
+ "size": "NONE"
413
+ },
414
+ "right": {
415
+ "scaling_factor": 1,
416
+ "size": "NONE"
417
+ },
418
+ "bottom": {
419
+ "scaling_factor": 1,
420
+ "size": "NONE"
421
+ },
422
+ "left": {
423
+ "scaling_factor": 1,
424
+ "size": "NONE"
425
+ }
426
+ }
427
+ },
428
+ "pull_quote_attribution": {
429
+ "font": "Helvetica Neue",
430
+ "color": "#000000",
431
+ "background_color": "#00FFFFFF",
432
+ "capitalization": "ALL_CAPS",
433
+ "text_alignment": "LEFT",
434
+ "display": "INLINE",
435
+ "line_height_scale": 1,
436
+ "text_size_scale": 1,
437
+ "margin": {
438
+ "right": {
439
+ "scaling_factor": 1,
440
+ "size": "DOCUMENT_MARGIN"
441
+ },
442
+ "left": {
443
+ "scaling_factor": 1,
444
+ "size": "DOCUMENT_MARGIN"
445
+ }
446
+ },
447
+ "border": {
448
+ "top": {
449
+ "width": 0
450
+ },
451
+ "right": {
452
+ "width": 0
453
+ },
454
+ "bottom": {
455
+ "width": 0
456
+ },
457
+ "left": {
458
+ "width": 0
459
+ }
460
+ },
461
+ "padding": {
462
+ "top": {
463
+ "scaling_factor": 1,
464
+ "size": "NONE"
465
+ },
466
+ "right": {
467
+ "scaling_factor": 1,
468
+ "size": "NONE"
469
+ },
470
+ "bottom": {
471
+ "scaling_factor": 1,
472
+ "size": "NONE"
473
+ },
474
+ "left": {
475
+ "scaling_factor": 1,
476
+ "size": "NONE"
477
+ }
478
+ }
479
+ },
480
+ "caption_title_small": {
481
+ "font": "Helvetica Neue Bold",
482
+ "color": "#808080",
483
+ "background_color": "#00FFFF",
484
+ "capitalization": "NONE",
485
+ "display": "INLINE",
486
+ "line_height_scale": 1,
487
+ "text_size_scale": 1,
488
+ "margin": {
489
+ "right": {
490
+ "scaling_factor": 1,
491
+ "size": "DOCUMENT_MARGIN"
492
+ },
493
+ "left": {
494
+ "scaling_factor": 1,
495
+ "size": "DOCUMENT_MARGIN"
496
+ }
497
+ },
498
+ "border": {
499
+ "top": {
500
+ "width": 0
501
+ },
502
+ "right": {
503
+ "width": 0
504
+ },
505
+ "bottom": {
506
+ "width": 0
507
+ },
508
+ "left": {
509
+ "width": 0
510
+ }
511
+ },
512
+ "padding": {
513
+ "top": {
514
+ "scaling_factor": 1,
515
+ "size": "NONE"
516
+ },
517
+ "right": {
518
+ "scaling_factor": 1,
519
+ "size": "NONE"
520
+ },
521
+ "bottom": {
522
+ "scaling_factor": 1,
523
+ "size": "NONE"
524
+ },
525
+ "left": {
526
+ "scaling_factor": 1,
527
+ "size": "NONE"
528
+ }
529
+ }
530
+ },
531
+ "caption_description_small": {
532
+ "font": "Helvetica Neue",
533
+ "color": "#808080",
534
+ "background_color": "#00FFFFFF",
535
+ "capitalization": "NONE",
536
+ "display": "INLINE",
537
+ "line_height_scale": 1,
538
+ "text_size_scale": 1,
539
+ "margin": {
540
+ "right": {
541
+ "scaling_factor": 1,
542
+ "size": "DOCUMENT_MARGIN"
543
+ },
544
+ "left": {
545
+ "scaling_factor": 1,
546
+ "size": "DOCUMENT_MARGIN"
547
+ }
548
+ },
549
+ "border": {
550
+ "top": {
551
+ "width": 0
552
+ },
553
+ "right": {
554
+ "width": 0
555
+ },
556
+ "bottom": {
557
+ "width": 0
558
+ },
559
+ "left": {
560
+ "width": 0
561
+ }
562
+ },
563
+ "padding": {
564
+ "top": {
565
+ "scaling_factor": 1,
566
+ "size": "NONE"
567
+ },
568
+ "right": {
569
+ "scaling_factor": 1,
570
+ "size": "NONE"
571
+ },
572
+ "bottom": {
573
+ "scaling_factor": 1,
574
+ "size": "NONE"
575
+ },
576
+ "left": {
577
+ "scaling_factor": 1,
578
+ "size": "NONE"
579
+ }
580
+ }
581
+ },
582
+ "caption_credit": {
583
+ "font": "Helvetica Neue",
584
+ "color": "#BFBFBF",
585
+ "background_color": "#00FFFFFF",
586
+ "capitalization": "ALL_CAPS",
587
+ "display": "INLINE",
588
+ "line_height_scale": 1,
589
+ "text_size_scale": 1,
590
+ "margin": {
591
+ "right": {
592
+ "scaling_factor": 1,
593
+ "size": "DOCUMENT_MARGIN"
594
+ },
595
+ "left": {
596
+ "scaling_factor": 1,
597
+ "size": "DOCUMENT_MARGIN"
598
+ }
599
+ },
600
+ "border": {
601
+ "top": {
602
+ "width": 0
603
+ },
604
+ "right": {
605
+ "width": 0
606
+ },
607
+ "bottom": {
608
+ "width": 0
609
+ },
610
+ "left": {
611
+ "width": 0
612
+ }
613
+ },
614
+ "padding": {
615
+ "top": {
616
+ "scaling_factor": 1,
617
+ "size": "NONE"
618
+ },
619
+ "right": {
620
+ "scaling_factor": 1,
621
+ "size": "NONE"
622
+ },
623
+ "bottom": {
624
+ "scaling_factor": 1,
625
+ "size": "NONE"
626
+ },
627
+ "left": {
628
+ "scaling_factor": 1,
629
+ "size": "NONE"
630
+ }
631
+ }
632
+ },
633
+ "caption_title": {
634
+ "font": "Georgia",
635
+ "color": "#808080",
636
+ "background_color": "#00FFFFFF",
637
+ "capitalization": "NONE",
638
+ "display": "INLINE",
639
+ "line_height_scale": 1,
640
+ "text_size_scale": 1,
641
+ "margin": {
642
+ "right": {
643
+ "scaling_factor": 1,
644
+ "size": "DOCUMENT_MARGIN"
645
+ },
646
+ "left": {
647
+ "scaling_factor": 1,
648
+ "size": "DOCUMENT_MARGIN"
649
+ }
650
+ },
651
+ "border": {
652
+ "top": {
653
+ "width": 0
654
+ },
655
+ "right": {
656
+ "width": 0
657
+ },
658
+ "bottom": {
659
+ "width": 0
660
+ },
661
+ "left": {
662
+ "width": 0
663
+ }
664
+ },
665
+ "padding": {
666
+ "top": {
667
+ "scaling_factor": 1,
668
+ "size": "NONE"
669
+ },
670
+ "right": {
671
+ "scaling_factor": 1,
672
+ "size": "NONE"
673
+ },
674
+ "bottom": {
675
+ "scaling_factor": 1,
676
+ "size": "NONE"
677
+ },
678
+ "left": {
679
+ "scaling_factor": 1,
680
+ "size": "NONE"
681
+ }
682
+ }
683
+ },
684
+ "caption_description": {
685
+ "font": "Georgia",
686
+ "color": "#808080",
687
+ "background_color": "#00FFFFFF",
688
+ "capitalization": "NONE",
689
+ "display": "INLINE",
690
+ "line_height_scale": 1,
691
+ "text_size_scale": 1,
692
+ "margin": {
693
+ "right": {
694
+ "scaling_factor": 1,
695
+ "size": "DOCUMENT_MARGIN"
696
+ },
697
+ "left": {
698
+ "scaling_factor": 1,
699
+ "size": "DOCUMENT_MARGIN"
700
+ }
701
+ },
702
+ "border": {
703
+ "top": {
704
+ "width": 0
705
+ },
706
+ "right": {
707
+ "width": 0
708
+ },
709
+ "bottom": {
710
+ "width": 0
711
+ },
712
+ "left": {
713
+ "width": 0
714
+ }
715
+ },
716
+ "padding": {
717
+ "top": {
718
+ "scaling_factor": 1,
719
+ "size": "NONE"
720
+ },
721
+ "right": {
722
+ "scaling_factor": 1,
723
+ "size": "NONE"
724
+ },
725
+ "bottom": {
726
+ "scaling_factor": 1,
727
+ "size": "NONE"
728
+ },
729
+ "left": {
730
+ "scaling_factor": 1,
731
+ "size": "NONE"
732
+ }
733
+ }
734
+ },
735
+ "caption_title_large": {
736
+ "font": "Georgia",
737
+ "color": "#808080",
738
+ "background_color": "#00FFFFFF",
739
+ "capitalization": "NONE",
740
+ "display": "INLINE",
741
+ "line_height_scale": 1,
742
+ "text_size_scale": 1,
743
+ "margin": {
744
+ "right": {
745
+ "scaling_factor": 1,
746
+ "size": "DOCUMENT_MARGIN"
747
+ },
748
+ "left": {
749
+ "scaling_factor": 1,
750
+ "size": "DOCUMENT_MARGIN"
751
+ }
752
+ },
753
+ "border": {
754
+ "top": {
755
+ "width": 0
756
+ },
757
+ "right": {
758
+ "width": 0
759
+ },
760
+ "bottom": {
761
+ "width": 0
762
+ },
763
+ "left": {
764
+ "width": 0
765
+ }
766
+ },
767
+ "padding": {
768
+ "top": {
769
+ "scaling_factor": 1,
770
+ "size": "NONE"
771
+ },
772
+ "right": {
773
+ "scaling_factor": 1,
774
+ "size": "NONE"
775
+ },
776
+ "bottom": {
777
+ "scaling_factor": 1,
778
+ "size": "NONE"
779
+ },
780
+ "left": {
781
+ "scaling_factor": 1,
782
+ "size": "NONE"
783
+ }
784
+ }
785
+ },
786
+ "caption_description_large": {
787
+ "font": "Georgia",
788
+ "color": "#808080",
789
+ "background_color": "#00FFFFFF",
790
+ "capitalization": "NONE",
791
+ "display": "INLINE",
792
+ "line_height_scale": 1,
793
+ "text_size_scale": 1,
794
+ "margin": {
795
+ "right": {
796
+ "scaling_factor": 1,
797
+ "size": "DOCUMENT_MARGIN"
798
+ },
799
+ "left": {
800
+ "scaling_factor": 1,
801
+ "size": "DOCUMENT_MARGIN"
802
+ }
803
+ },
804
+ "border": {
805
+ "top": {
806
+ "width": 0
807
+ },
808
+ "right": {
809
+ "width": 0
810
+ },
811
+ "bottom": {
812
+ "width": 0
813
+ },
814
+ "left": {
815
+ "width": 0
816
+ }
817
+ },
818
+ "padding": {
819
+ "top": {
820
+ "scaling_factor": 1,
821
+ "size": "NONE"
822
+ },
823
+ "right": {
824
+ "scaling_factor": 1,
825
+ "size": "NONE"
826
+ },
827
+ "bottom": {
828
+ "scaling_factor": 1,
829
+ "size": "NONE"
830
+ },
831
+ "left": {
832
+ "scaling_factor": 1,
833
+ "size": "NONE"
834
+ }
835
+ }
836
+ },
837
+ "caption_title_extra_large": {
838
+ "font": "Georgia",
839
+ "color": "#808080",
840
+ "background_color": "#00FFFFFF",
841
+ "capitalization": "NONE",
842
+ "display": "INLINE",
843
+ "line_height_scale": 1,
844
+ "text_size_scale": 1,
845
+ "margin": {
846
+ "right": {
847
+ "scaling_factor": 1,
848
+ "size": "DOCUMENT_MARGIN"
849
+ },
850
+ "left": {
851
+ "scaling_factor": 1,
852
+ "size": "DOCUMENT_MARGIN"
853
+ }
854
+ },
855
+ "border": {
856
+ "top": {
857
+ "width": 0
858
+ },
859
+ "right": {
860
+ "width": 0
861
+ },
862
+ "bottom": {
863
+ "width": 0
864
+ },
865
+ "left": {
866
+ "width": 0
867
+ }
868
+ },
869
+ "padding": {
870
+ "top": {
871
+ "scaling_factor": 1,
872
+ "size": "NONE"
873
+ },
874
+ "right": {
875
+ "scaling_factor": 1,
876
+ "size": "NONE"
877
+ },
878
+ "bottom": {
879
+ "scaling_factor": 1,
880
+ "size": "NONE"
881
+ },
882
+ "left": {
883
+ "scaling_factor": 1,
884
+ "size": "NONE"
885
+ }
886
+ }
887
+ },
888
+ "caption_description_extra_large": {
889
+ "font": "Georgia",
890
+ "color": "#808080",
891
+ "background_color": "#00FFFFFF",
892
+ "capitalization": "NONE",
893
+ "display": "INLINE",
894
+ "line_height_scale": 1,
895
+ "text_size_scale": 1,
896
+ "margin": {
897
+ "right": {
898
+ "scaling_factor": 1,
899
+ "size": "DOCUMENT_MARGIN"
900
+ },
901
+ "left": {
902
+ "scaling_factor": 1,
903
+ "size": "DOCUMENT_MARGIN"
904
+ }
905
+ },
906
+ "border": {
907
+ "top": {
908
+ "width": 0
909
+ },
910
+ "right": {
911
+ "width": 0
912
+ },
913
+ "bottom": {
914
+ "width": 0
915
+ },
916
+ "left": {
917
+ "width": 0
918
+ }
919
+ },
920
+ "padding": {
921
+ "top": {
922
+ "scaling_factor": 1,
923
+ "size": "NONE"
924
+ },
925
+ "right": {
926
+ "scaling_factor": 1,
927
+ "size": "NONE"
928
+ },
929
+ "bottom": {
930
+ "scaling_factor": 1,
931
+ "size": "NONE"
932
+ },
933
+ "left": {
934
+ "scaling_factor": 1,
935
+ "size": "NONE"
936
+ }
937
+ }
938
+ },
939
+ "footer": {
940
+ "font": "Helvetica Neue",
941
+ "color": "#000000",
942
+ "background_color": "#00FFFFFF",
943
+ "capitalization": "NONE",
944
+ "text_alignment": "LEFT",
945
+ "display": "INLINE",
946
+ "line_height_scale": 1,
947
+ "text_size_scale": 1,
948
+ "margin": {
949
+ "right": {
950
+ "scaling_factor": 1,
951
+ "size": "DOCUMENT_MARGIN"
952
+ },
953
+ "left": {
954
+ "scaling_factor": 1,
955
+ "size": "DOCUMENT_MARGIN"
956
+ }
957
+ },
958
+ "border": {
959
+ "top": {
960
+ "width": 0
961
+ },
962
+ "right": {
963
+ "width": 0
964
+ },
965
+ "bottom": {
966
+ "width": 0
967
+ },
968
+ "left": {
969
+ "width": 0
970
+ }
971
+ },
972
+ "padding": {
973
+ "top": {
974
+ "scaling_factor": 1,
975
+ "size": "NONE"
976
+ },
977
+ "right": {
978
+ "scaling_factor": 1,
979
+ "size": "NONE"
980
+ },
981
+ "bottom": {
982
+ "scaling_factor": 1,
983
+ "size": "NONE"
984
+ },
985
+ "left": {
986
+ "scaling_factor": 1,
987
+ "size": "NONE"
988
+ }
989
+ }
990
+ },
991
+ "id": "1755859684428101",
992
+ "name": "wod-gray"
993
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/CSSBuilderTest.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ use PHPUnit\Framework;
12
+
13
+ class CSSBuilderTest extends Framework\TestCase
14
+ {
15
+ protected function setUp()
16
+ {
17
+ \Logger::configure(
18
+ [
19
+ 'rootLogger' => [
20
+ 'appenders' => ['facebook-instantarticles-traverser']
21
+ ],
22
+ 'appenders' => [
23
+ 'facebook-instantarticles-traverser' => [
24
+ 'class' => 'LoggerAppenderConsole',
25
+ 'threshold' => 'INFO',
26
+ 'layout' => [
27
+ 'class' => 'LoggerLayoutSimple'
28
+ ]
29
+ ]
30
+ ]
31
+ ]
32
+ );
33
+ }
34
+
35
+ public function genSimpleCSSFormatted($prefix = '')
36
+ {
37
+ return
38
+ ".{$prefix}someClass {\n".
39
+ " width: 300px;\n".
40
+ " height: 400px;\n".
41
+ "}";
42
+ }
43
+
44
+ public function genSpacingCSSFormatted($prefix = '')
45
+ {
46
+ return
47
+ ".{$prefix}someClass {\n".
48
+ " width: 300px;\n".
49
+ " height: 400px;\n".
50
+ "}\n".
51
+ "\n".
52
+ ".{$prefix}someClass + .{$prefix}spacing {\n".
53
+ " height: 18px;\n".
54
+ "}";
55
+ }
56
+
57
+ public function genMarginCSSFormatted($prefix = '')
58
+ {
59
+ return
60
+ ".{$prefix}someClass {\n".
61
+ " margin: 0 10px 5px 0;\n".
62
+ " height: 400px;\n".
63
+ "}";
64
+ }
65
+
66
+ public function genArrayCSSFormatted($prefix = '')
67
+ {
68
+ return
69
+ ".{$prefix}someClass1, .{$prefix}someClass2 {\n".
70
+ " width: 300px;\n".
71
+ " height: 400px;\n".
72
+ "}\n".
73
+ "\n".
74
+ ".{$prefix}someClass1 {\n".
75
+ " color: #fff;\n".
76
+ "}";
77
+ }
78
+
79
+ public function genOtherCSSFormatted($prefix = '')
80
+ {
81
+ return
82
+ ".{$prefix}otherClass {\n".
83
+ " background-color: #aabbcc;\n".
84
+ " border-width: 2px;\n".
85
+ "}";
86
+ }
87
+
88
+ public function genSimpleCSS($prefix = '')
89
+ {
90
+ return
91
+ ".{$prefix}someClass {".
92
+ "width: 300px;".
93
+ "height: 400px;".
94
+ "}";
95
+ }
96
+
97
+
98
+
99
+ public function testSimpleCSS()
100
+ {
101
+ $expected = $this->genSimpleCSS();
102
+
103
+ $cssBuilder = new CSSBuilder();
104
+ $cssBuilder->addProperty('.someClass', 'width', '300px')
105
+ ->addProperty('.someClass', 'height', '400px');
106
+ $result = $cssBuilder->build(false);
107
+ $this->assertEquals($expected, $result);
108
+ }
109
+
110
+ public function testSimpleCSSFormatted()
111
+ {
112
+ $expected = $this->genSimpleCSSFormatted();
113
+
114
+ $cssBuilder = new CSSBuilder('');
115
+ $cssBuilder->addProperty('.someClass', 'width', '300px')
116
+ ->addProperty('.someClass', 'height', '400px');
117
+ $result = $cssBuilder->build(true);
118
+ $this->assertEquals($expected, $result);
119
+ }
120
+
121
+ public function testMultipleCSSFormatted()
122
+ {
123
+ $expected = $this->genSimpleCSSFormatted()."\n\n".$this->genOtherCSSFormatted();
124
+
125
+ $cssBuilder = new CSSBuilder('');
126
+ $cssBuilder->addProperty('.someClass', 'width', '300px')
127
+ ->addProperty('.someClass', 'height', '400px')
128
+ ->addProperty('.otherClass', 'background-color', '#aabbcc')
129
+ ->addProperty('.otherClass', 'border-width', '2px');
130
+ $result = $cssBuilder->build(true);
131
+ $this->assertEquals($expected, $result);
132
+ }
133
+
134
+ public function testMultipleCSSFormattedWithPrefix()
135
+ {
136
+ $expected = $this->genSimpleCSSFormatted('myprefix-');
137
+
138
+ $cssBuilder = new CSSBuilder('myprefix-');
139
+ $cssBuilder->addToSelector('someClass', 'width', '300px')
140
+ ->addToSelector('someClass', 'height', '400px');
141
+ $result = $cssBuilder->build(true);
142
+ $this->assertEquals($expected, $result);
143
+ }
144
+
145
+ public function testMultipleDimmensionCSSFormattedWithPrefix()
146
+ {
147
+ $expected = $this->genSimpleCSSFormatted('myprefix-');
148
+
149
+ $cssBuilder = new CSSBuilder('myprefix-');
150
+ $cssBuilder->addDimensionToSelector('someClass', 'width', '300', 'px')
151
+ ->addDimensionToSelector('someClass', 'height', '400', 'px');
152
+ $result = $cssBuilder->build(true);
153
+ $this->assertEquals($expected, $result);
154
+ }
155
+
156
+ public function testSpacingCSSFormattedWithPrefix()
157
+ {
158
+ $expected = $this->genSpacingCSSFormatted('myprefix-');
159
+
160
+ $cssBuilder = new CSSBuilder('myprefix-');
161
+ $cssBuilder->addDimensionToSelector('someClass', 'width', '300', 'px')
162
+ ->addDimensionToSelector('someClass', 'height', '400', 'px')
163
+ ->addHeightSpacingToSelector('someClass', '18');
164
+ $result = $cssBuilder->build(true);
165
+ $this->assertEquals($expected, $result);
166
+ }
167
+
168
+ public function testTopRightBottomLeftCSSFormattedWithPrefix()
169
+ {
170
+ $expected = $this->genMarginCSSFormatted('myprefix-');
171
+
172
+ $cssBuilder = new CSSBuilder('myprefix-');
173
+ $cssBuilder->addTopRightBottomLeftToSelector('someClass', 'margin', null, '10', 5, 0, 'px')
174
+ ->addDimensionToSelector('someClass', 'height', '400', 'px');
175
+ $result = $cssBuilder->build(true);
176
+ $this->assertEquals($expected, $result);
177
+ }
178
+
179
+ public function testArrayCSSFormattedWithPrefix()
180
+ {
181
+ $expected = $this->genArrayCSSFormatted('myprefix-');
182
+
183
+ $cssBuilder = new CSSBuilder('myprefix-');
184
+ $cssBuilder->addToSelector(array('someClass1', 'someClass2'), 'width', '300px')
185
+ ->addToSelector(array('someClass1', 'someClass2'), 'height', '400px')
186
+ ->addToSelector('someClass1', 'color', '#fff');
187
+ $result = $cssBuilder->build(true);
188
+ $this->assertEquals($expected, $result);
189
+ }
190
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/FileUtilsPHPUnitTestCase.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ use Facebook\InstantArticles\Parser\Parser;
12
+ use PHPUnit\Framework;
13
+
14
+ class FileUtilsPHPUnitTestCase extends Framework\TestCase
15
+ {
16
+ protected function setUp()
17
+ {
18
+ \Logger::configure(
19
+ [
20
+ 'rootLogger' => [
21
+ 'appenders' => ['facebook-instantarticles-traverser']
22
+ ],
23
+ 'appenders' => [
24
+ 'facebook-instantarticles-traverser' => [
25
+ 'class' => 'LoggerAppenderConsole',
26
+ 'threshold' => 'INFO',
27
+ 'layout' => [
28
+ 'class' => 'LoggerLayoutSimple'
29
+ ]
30
+ ]
31
+ ]
32
+ ]
33
+ );
34
+ }
35
+
36
+ /**
37
+ * Loads HTML file using by default file_get_contents
38
+ */
39
+ public function loadHTMLFile($file)
40
+ {
41
+ return file_get_contents($file);
42
+ }
43
+
44
+ /**
45
+ * Helper method that loads HTML file into DOMDocument instance, encoding as HTML-ENTITIES and using by default utf-8.
46
+ * @param string $file The file name/path that will be loaded
47
+ * @param string $encoding "utf-8" by default. Supports the format informed.
48
+ */
49
+ public function loadDOMDocument($file, $encoding = 'utf-8')
50
+ {
51
+ $fileContent = $this->loadHTMLFile($file, $encoding);
52
+ return $this->loadDOMDocumentFromString($fileContent, $encoding);
53
+ }
54
+
55
+ /**
56
+ * Helper method that loads HTML file into DOMDocument instance, encoding as HTML-ENTITIES and using by default utf-8.
57
+ * @param string $fileContent The file content
58
+ * @param string $encoding "utf-8" by default. Supports the format informed.
59
+ */
60
+ public function loadDOMDocumentFromString($fileContent, $encoding = 'utf-8')
61
+ {
62
+ libxml_use_internal_errors(true);
63
+ $document = new \DOMDocument('1.0');
64
+ $document->loadHTML('<?xml encoding="' . $encoding. '"?>'.$fileContent);
65
+ libxml_use_internal_errors(false);
66
+ return $document;
67
+ }
68
+
69
+ /**
70
+ * Helper method that will load file, parse as Instant Article and return the element.
71
+ * @param string $file File name to be loaded/parsed as InstantArticle.
72
+ * @param string $encoding "utf-8" by default. Supports and loads the instant article treating file with the informed encoding.
73
+ */
74
+ public function loadInstantArticle($file, $encoding = 'utf-8')
75
+ {
76
+ $document = $this->loadDOMDocument($file, $encoding);
77
+ $parser = new Parser();
78
+ return $parser->parse($document);
79
+ }
80
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/Greeting.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+
12
+ /*
13
+ * Sample class used for testing the Observer.
14
+ */
15
+ class Greeting
16
+ {
17
+ private $greeting;
18
+
19
+ public function __construct($greeting)
20
+ {
21
+ $this->greeting = $greeting;
22
+ }
23
+
24
+ /**
25
+ * Says hello to someone
26
+ */
27
+ public static function hello($name)
28
+ {
29
+ return "Hello $name";
30
+ }
31
+
32
+ /**
33
+ * Method that returns a string greeting someone
34
+ */
35
+ public function greet($name, $middleName = null, $lastName = null)
36
+ {
37
+ $name = ($this->greeting).' '.$name;
38
+ if ($middleName) {
39
+ $name = $name.' '.$middleName;
40
+ }
41
+ if ($lastName) {
42
+ $name = $name.' '.$lastName;
43
+ }
44
+ return $name;
45
+ }
46
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/HookTest.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ use Facebook\InstantArticles\Validators\Type;
12
+ use PHPUnit\Framework;
13
+
14
+ class HookTest extends Framework\TestCase
15
+ {
16
+ protected function setUp()
17
+ {
18
+ \Logger::configure(
19
+ [
20
+ 'rootLogger' => [
21
+ 'appenders' => ['facebook-instantarticles-traverser']
22
+ ],
23
+ 'appenders' => [
24
+ 'facebook-instantarticles-traverser' => [
25
+ 'class' => 'LoggerAppenderConsole',
26
+ 'threshold' => 'INFO',
27
+ 'layout' => [
28
+ 'class' => 'LoggerLayoutSimple'
29
+ ]
30
+ ]
31
+ ]
32
+ ]
33
+ );
34
+ }
35
+
36
+ public function methodHook()
37
+ {
38
+ return 'result';
39
+ }
40
+
41
+ public function methodHookReplacing($param1 = null, $param2 = null)
42
+ {
43
+ return 'REPLACED' . (isset($param1) && !Type::isTextEmpty($param1) ? '-'.$param1.'-'.$param2 : '');
44
+ }
45
+
46
+ public static function staticMethodHook()
47
+ {
48
+ return 'STATIC';
49
+ }
50
+
51
+ public function methodHookBefore1($objToChange)
52
+ {
53
+ $objToChange->first = '1st';
54
+ }
55
+
56
+ public function methodHookTestingBefore($objToChange)
57
+ {
58
+ return 'MAIN-WITH-BEFORE-'.$objToChange->first.'-'.$objToChange->second;
59
+ }
60
+
61
+ public function methodHookAfter2($objToChange)
62
+ {
63
+ $objToChange->second = '2nd';
64
+ }
65
+
66
+ public function methodHookTestingAfter($objToChange)
67
+ {
68
+ return 'MAIN-WITH-AFTER-'.$objToChange->first.'-'.$objToChange->second;
69
+ }
70
+
71
+ public static function staticMethodHookParams($arg1, $arg2)
72
+ {
73
+ return 'STATIC-with-params-'.$arg1.'-'.$arg2;
74
+ }
75
+
76
+ public function testHookDefault()
77
+ {
78
+ $hook = Hook::create();
79
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
80
+ $this->assertEquals('result', $result);
81
+ }
82
+
83
+ public function testHookReplacingDefault()
84
+ {
85
+ $hook = Hook::create();
86
+ $hook->setHook('hook_name', array($this, 'methodHookReplacing'));
87
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
88
+ $this->assertEquals('REPLACED', $result);
89
+ }
90
+
91
+ public function testHookReplacingDefaultRemoved()
92
+ {
93
+ $hook = Hook::create();
94
+ $hook->setHook('hook_name', array($this, 'methodHookReplacing'));
95
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
96
+ $this->assertEquals('REPLACED', $result);
97
+
98
+ $hook->removeHook('hook_name');
99
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
100
+ $this->assertEquals('result', $result);
101
+ }
102
+
103
+ public function testHookRemovingSomethingNeverAdded()
104
+ {
105
+ $hook = Hook::create();
106
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
107
+ $this->assertEquals('result', $result);
108
+
109
+ $hook->removeHook('hook_name');
110
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
111
+ $this->assertEquals('result', $result);
112
+ }
113
+
114
+ public function testHookDefaultBefore()
115
+ {
116
+ $hook = Hook::create();
117
+ $objToChange = new \StdClass;
118
+ $objToChange->first = '1';
119
+ $objToChange->second = '2';
120
+
121
+ // Calls method without overriding the value, so the return should be 1
122
+ $objToChange->first = '1';
123
+ $objToChange->second = '2';
124
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingBefore'), array($objToChange));
125
+ $this->assertEquals('MAIN-WITH-BEFORE-1-2', $result);
126
+
127
+ // Calls method overriding the value, so the return should be 1st
128
+ $objToChange->first = '1';
129
+ $objToChange->second = '2';
130
+ $hook->setBeforeHook('hook_name', array($this, 'methodHookBefore1'), array($objToChange));
131
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingBefore'), array($objToChange));
132
+ $this->assertEquals('MAIN-WITH-BEFORE-1st-2', $result);
133
+ }
134
+
135
+ public function testHookDefaultAfter()
136
+ {
137
+ $hook = Hook::create();
138
+ $objToChange = new \StdClass;
139
+ $objToChange->first = '1';
140
+ $objToChange->second = '2';
141
+
142
+ // Calls method without overriding the value, so the return should be 1
143
+ $objToChange->first = '1';
144
+ $objToChange->second = '2';
145
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingAfter'), array($objToChange));
146
+ $this->assertEquals('MAIN-WITH-AFTER-1-2', $result);
147
+
148
+ // Calls method overriding the value, so the return should be 2nd
149
+ $objToChange->first = '1';
150
+ $objToChange->second = '2';
151
+ $hook->setAfterHook('hook_name', array($this, 'methodHookAfter2'), array($objToChange));
152
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingAfter'), array($objToChange));
153
+ $this->assertEquals('MAIN-WITH-AFTER-1-2', $result);
154
+ $this->assertEquals('2nd', $objToChange->second);
155
+ }
156
+
157
+ public function testHookDefaultBeforeAndAfter()
158
+ {
159
+ $hook = Hook::create();
160
+ $objToChange = new \StdClass;
161
+ $objToChange->first = '1';
162
+ $objToChange->second = '2';
163
+
164
+ // Calls method without overriding the value, so the return should be 1
165
+ $objToChange->first = '1';
166
+ $objToChange->second = '2';
167
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingBefore'), array($objToChange));
168
+ $this->assertEquals('MAIN-WITH-BEFORE-1-2', $result);
169
+
170
+ // Calls method overriding the value, so the return should be 1st
171
+ $objToChange->first = '1';
172
+ $objToChange->second = '2';
173
+ $hook->setBeforeHook('hook_name', array($this, 'methodHookBefore1'), array($objToChange));
174
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingBefore'), array($objToChange));
175
+ $this->assertEquals('MAIN-WITH-BEFORE-1st-2', $result);
176
+
177
+ // Calls method overriding the value, so the return should be 2nd
178
+ $objToChange->first = '1';
179
+ $objToChange->second = '2';
180
+ $hook->setAfterHook('hook_name', array($this, 'methodHookAfter2'), array($objToChange));
181
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingAfter'), array($objToChange));
182
+ $this->assertEquals('MAIN-WITH-AFTER-1st-2', $result);
183
+ $this->assertEquals('2nd', $objToChange->second);
184
+ }
185
+
186
+ public function testHookDefaultBeforeAndAfterRemoved()
187
+ {
188
+ $hook = Hook::create();
189
+ $objToChange = new \StdClass;
190
+
191
+ // Calls method without overriding the value, so the return should be 1
192
+ $objToChange->first = '1';
193
+ $objToChange->second = '2';
194
+ $hook->setBeforeHook('hook_name', array($this, 'methodHookBefore1'), array($objToChange));
195
+ $hook->setAfterHook('hook_name', array($this, 'methodHookAfter2'), array($objToChange));
196
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingAfter'), array($objToChange));
197
+ $this->assertEquals('MAIN-WITH-AFTER-1st-2', $result);
198
+ $this->assertEquals('2nd', $objToChange->second);
199
+
200
+ $objToChange->first = '1';
201
+ $objToChange->second = '2';
202
+ $hook->clearHooks('hook_name');
203
+ $result = $hook->call('hook_name', array($this, 'methodHookTestingBefore'), array($objToChange));
204
+ $this->assertEquals('MAIN-WITH-BEFORE-1-2', $result);
205
+ }
206
+
207
+ public function testHookReplacingDefaultParams()
208
+ {
209
+ $hook = Hook::create();
210
+ $hook->setHook('hook_name', array($this, 'methodHookReplacing'), array('param1', 'param2'));
211
+ $result = $hook->call('hook_name', array($this, 'methodHook'));
212
+ $this->assertEquals('REPLACED-param1-param2', $result);
213
+ }
214
+
215
+ public function testHookStaticMethod()
216
+ {
217
+ $hook = Hook::create();
218
+ $result = $hook->call('hook_name', array('Facebook\InstantArticles\Utils\HookTest', 'staticMethodHook'));
219
+ $this->assertEquals('STATIC', $result);
220
+ }
221
+
222
+ public function testHookStaticMethodParams()
223
+ {
224
+ $hook = Hook::create();
225
+ $result = $hook->call('hook_name', array('Facebook\InstantArticles\Utils\HookTest', 'staticMethodHookParams'), array('param1', 'param2'));
226
+ $this->assertEquals('STATIC-with-params-param1-param2', $result);
227
+ }
228
+
229
+ public function testHookFunctionNoClass()
230
+ {
231
+ $hook = Hook::create();
232
+ $result = $hook->call('hook_name', 'Facebook\InstantArticles\Utils\functionOutsideClass');
233
+ $this->assertEquals('OUTSIDER', $result);
234
+ }
235
+
236
+ public function testHookFunctionNoClassWithParam()
237
+ {
238
+ $hook = Hook::create();
239
+ $result = $hook->call('hook_name', 'Facebook\InstantArticles\Utils\functionOutsideClassWithParams', array('param1'));
240
+ $this->assertEquals('OUTSIDER-with-param-param1', $result);
241
+ }
242
+ }
243
+
244
+ function functionOutsideClass()
245
+ {
246
+ return 'OUTSIDER';
247
+ }
248
+
249
+ function functionOutsideClassWithParams($arg1)
250
+ {
251
+ return 'OUTSIDER-with-param-'.$arg1;
252
+ }
vendor/facebook/facebook-instant-articles-sdk-extensions-in-php/tests/Facebook/InstantArticles/Utils/ObserverTest.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2017-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Utils;
10
+
11
+ use PHPUnit\Framework;
12
+
13
+ class ObserverTest extends Framework\TestCase
14
+ {
15
+ protected function setUp()
16
+ {
17
+ \Logger::configure(
18
+ [
19
+ 'rootLogger' => [
20
+ 'appenders' => ['facebook-instantarticles-traverser']
21
+ ],
22
+ 'appenders' => [
23
+ 'facebook-instantarticles-traverser' => [
24
+ 'class' => 'LoggerAppenderConsole',
25
+ 'threshold' => 'INFO',
26
+ 'layout' => [
27
+ 'class' => 'LoggerLayoutSimple'
28
+ ]
29
+ ]
30
+ ]
31
+ ]
32
+ );
33
+ }
34
+
35
+ public function testNoFilter()
36
+ {
37
+ $observererver = Observer::create();
38
+ $name = $observererver->applyFilters('name', "Bob");
39
+ $this->assertEquals('Bob', $name);
40
+ }
41
+
42
+ public function testSingleFilter()
43
+ {
44
+ $observer = Observer::create();
45
+ $observer->addFilter('name', function ($name) {
46
+ return "$name-san";
47
+
48
+ });
49
+ $name = $observer->applyFilters('name', "Bob");
50
+ $this->assertEquals('Bob-san', $name);
51
+ }
52
+
53
+ public function testStaticFilter()
54
+ {
55
+ $observer = Observer::create();
56
+ $observer->addFilter('name', array("Facebook\InstantArticles\Utils\Greeting", "hello"));
57
+
58
+ $name = $observer->applyFilters('name', "Bob");
59
+ $this->assertEquals('Hello Bob', $name);
60
+ }
61
+
62
+ public function testFilterWithReferences()
63
+ {
64
+ $mr = new Greeting("Mr.");
65
+ $hello = new Greeting("Hello");
66
+
67
+ $observer = Observer::create();
68
+ $observer->addFilter('name', array(&$mr, "greet"));
69
+ $observer->addFilter('name', array(&$hello, "greet"));
70
+
71
+ $name = $observer->applyFilters('name', "Bob");
72
+ $this->assertEquals('Hello Mr. Bob', $name);
73
+ }
74
+
75
+ public function testFilterWithParameters()
76
+ {
77
+ $hello = new Greeting("Hello");
78
+
79
+ $observer = Observer::create();
80
+ $observer->addFilter('name', array(&$hello, "greet"), 10, 4);
81
+
82
+ $name = $observer->applyFilters('name', "Spongebob", "Square", "Pants");
83
+ $this->assertEquals('Hello Spongebob Square Pants', $name);
84
+ }
85
+
86
+ public function testFilterWithReferencesAndParameters()
87
+ {
88
+ $hello = new Greeting("Hello");
89
+ $mr = new Greeting("Mr.");
90
+
91
+ $observer = Observer::create();
92
+ $observer->addFilter('name', array(&$hello, "greet"), 11, 2);
93
+ $observer->addFilter('name', array(&$mr, "greet"), 10, 1);
94
+
95
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
96
+ $this->assertEquals('Hello Mr. Bob Bobby', $name);
97
+ }
98
+
99
+ public function testRemoveFilterWithReferencesParameters()
100
+ {
101
+ $hello = new Greeting("Hello");
102
+ $mr = new Greeting("Mr.");
103
+
104
+ $observer = Observer::create();
105
+ $observer->addFilter('name', array(&$hello, "greet"), 11, 2);
106
+ $observer->addFilter('name', array(&$mr, "greet"), 10, 1);
107
+
108
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
109
+ $this->assertEquals('Hello Mr. Bob Bobby', $name);
110
+
111
+ $observer->removeFilter('name', array(&$mr, "greet"), 10);
112
+
113
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
114
+ $this->assertEquals('Hello Bob Bobby', $name);
115
+ }
116
+
117
+ public function testRemoveAllFiltersWithReferencesAndParameters()
118
+ {
119
+ $hello = new Greeting("Hello");
120
+ $mr = new Greeting("Mr.");
121
+
122
+ $observer = Observer::create();
123
+ $observer->addFilter('name', array(&$hello, "greet"), 11, 2);
124
+ $observer->addFilter('name', array(&$mr, "greet"), 10, 1);
125
+
126
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
127
+ $this->assertEquals('Hello Mr. Bob Bobby', $name);
128
+
129
+ $observer->removeAllFilters('name', 11);
130
+
131
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
132
+ $this->assertEquals('Mr. Bob', $name);
133
+
134
+ $observer->removeAllFilters('name');
135
+
136
+ $name = $observer->applyFilters('name', "Bob", "Bobby");
137
+ $this->assertEquals('Bob', $name);
138
+ }
139
+
140
+ public function testHasFilter()
141
+ {
142
+ $hello = new Greeting("Hello");
143
+ $mr = new Greeting("Mr.");
144
+ $mrs = new Greeting("Mrs.");
145
+
146
+ $observer = Observer::create();
147
+ $observer->addFilter('name', array(&$hello, "greet"), 11, 2);
148
+ $observer->addFilter('name', array(&$mr, "greet"), 10, 1);
149
+
150
+ $this->assertEquals(11, $observer->hasFilter('name', array(&$hello, "greet")));
151
+ $this->assertEquals(10, $observer->hasFilter('name', array(&$mr, "greet")));
152
+ $this->assertFalse($observer->hasFilter('name', array(&$mrs, "greet")));
153
+ $this->assertTrue($observer->hasFilter('name'));
154
+ }
155
+ }
vendor/facebook/facebook-instant-articles-sdk-php/.travis.yml CHANGED
@@ -6,6 +6,7 @@ matrix:
6
  - php: 5.5
7
  - php: 5.6
8
  - php: 7
 
9
  env: WITH_CS=true
10
 
11
  cache:
6
  - php: 5.5
7
  - php: 5.6
8
  - php: 7
9
+ - php: 7.1
10
  env: WITH_CS=true
11
 
12
  cache:
vendor/facebook/facebook-instant-articles-sdk-php/README.md CHANGED
@@ -11,19 +11,31 @@ The SDK consists of three components:
11
  - **Client**: A simple wrapper around the [Instant Articles API](https://developers.facebook.com/docs/instant-articles/api), which can be used for publishing Instant Articles on Facebook. The client provides a CRUD interface for Instant Articles as well as a helper for authentication. The client depends on the main [Facebook SDK for PHP](https://github.com/facebook/facebook-php-sdk-v4) as an interface to the Graph API and Facebook Login.
12
 
13
  ## Quick Start
14
- You can find examples on how to use the different components of this SDK to integrate with your CMS in the [Getting Started section](https://developers.facebook.com/docs/instant-articles/sdk/#getting-started) of the documentation.
15
 
16
- ## Installation
17
 
18
- The Facebook Instant Articles PHP SDK can be installed with [Composer](https://getcomposer.org/). Run this command:
 
 
 
 
 
 
 
 
 
 
 
19
 
 
 
 
20
  ```sh
21
- composer require facebook/facebook-instant-articles-sdk-php
22
  ```
23
 
24
- ## Testing and Developing ##
25
 
26
- [Composer](https://getcomposer.org/) is a prerequisite for testing and developing. [Install composer globally](https://getcomposer.org/doc/00-intro.md#globally), then install project dependencies by running this command in the project root directory:
27
  ```sh
28
  $ composer install
29
  ```
@@ -53,6 +65,10 @@ If you change structure, paths, namespaces, etc., make sure you run the [autoloa
53
  $ composer dump-autoload
54
  ```
55
 
 
 
 
 
56
  ## Troubleshooting
57
 
58
  If you are encountering problems, the following tips may help in troubleshooting issues:
@@ -65,10 +81,6 @@ If you are encountering problems, the following tips may help in troubleshooting
65
 
66
  - Refer to the existing [tests of the `Elements`](https://github.com/facebook/facebook-instant-articles-sdk-php/tree/master/tests/Facebook/InstantArticles/Elements) for examples of what is required of each and to potentially create your own tests (which can be run with `$ composer test`).
67
 
68
- ## Contributing
69
-
70
- For us to accept contributions you will have to first have signed the [Contributor License Agreement](https://code.facebook.com/cla). Please see [CONTRIBUTING](https://github.com/facebook/facebook-instant-articles-sdk-php/blob/master/CONTRIBUTING.md) for details.
71
-
72
  ## License
73
 
74
  Please see the [license file](https://github.com/facebook/facebook-instant-articles-sdk-php/blob/master/LICENSE) for more information.
11
  - **Client**: A simple wrapper around the [Instant Articles API](https://developers.facebook.com/docs/instant-articles/api), which can be used for publishing Instant Articles on Facebook. The client provides a CRUD interface for Instant Articles as well as a helper for authentication. The client depends on the main [Facebook SDK for PHP](https://github.com/facebook/facebook-php-sdk-v4) as an interface to the Graph API and Facebook Login.
12
 
13
  ## Quick Start
 
14
 
15
+ The Facebook Instant Articles PHP SDK can be installed with the [Composer](https://getcomposer.org/) dependency manager by running this command on your project's root folder:
16
 
17
+ ```sh
18
+ $ composer require facebook/facebook-instant-articles-sdk-php
19
+ ```
20
+
21
+ After the installation, you can include the auto loader script in your source with:
22
+
23
+ ```PHP
24
+ require_once('vendor/autoload.php');
25
+ ```
26
+
27
+ ## Official Documentation
28
+ You can find examples on how to use the different components of this SDK to integrate it with your CMS in the [Getting Started](https://developers.facebook.com/docs/instant-articles/sdk/#getting-started) section of the documentation.
29
 
30
+ ## Contributing
31
+
32
+ Clone the repository
33
  ```sh
34
+ $ git clone https://github.com/facebook/facebook-instant-articles-sdk-php.git
35
  ```
36
 
37
+ [Composer](https://getcomposer.org/) is a prerequisite for testing and developing. [Install composer globally](https://getcomposer.org/doc/00-intro.md#globally), then install project dependencies by running this command in the project's root directory:
38
 
 
39
  ```sh
40
  $ composer install
41
  ```
65
  $ composer dump-autoload
66
  ```
67
 
68
+ ___
69
+ **For us to accept contributions you will have to first sign the [Contributor License Agreement](https://code.facebook.com/cla). Please see [CONTRIBUTING](https://github.com/facebook/facebook-instant-articles-sdk-php/blob/master/CONTRIBUTING.md) for details.**
70
+ ___
71
+
72
  ## Troubleshooting
73
 
74
  If you are encountering problems, the following tips may help in troubleshooting issues:
81
 
82
  - Refer to the existing [tests of the `Elements`](https://github.com/facebook/facebook-instant-articles-sdk-php/tree/master/tests/Facebook/InstantArticles/Elements) for examples of what is required of each and to potentially create your own tests (which can be run with `$ composer test`).
83
 
 
 
 
 
84
  ## License
85
 
86
  Please see the [license file](https://github.com/facebook/facebook-instant-articles-sdk-php/blob/master/LICENSE) for more information.
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Analytics.php CHANGED
@@ -45,7 +45,7 @@ class Analytics extends ElementWithHTML
45
  }
46
 
47
  /**
48
- * Sets the source for the ad.
49
  *
50
  * @param string $source The source of the content for your ad.
51
  *
45
  }
46
 
47
  /**
48
+ * Sets the source for the analytics.
49
  *
50
  * @param string $source The source of the content for your ad.
51
  *
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/Emphasized.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2016-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Elements;
10
+
11
+ /**
12
+ * An emphasized text.
13
+ *
14
+ * @see {link:https://developers.facebook.com/docs/instant-articles/reference/body-text}
15
+ */
16
+ class Emphasized extends FormattedText
17
+ {
18
+ private function __construct()
19
+ {
20
+ }
21
+
22
+ /**
23
+ * @return Emphasized
24
+ */
25
+ public static function create()
26
+ {
27
+ return new self();
28
+ }
29
+
30
+ /**
31
+ * Structure and create <em> node.
32
+ *
33
+ * @param \DOMDocument $document - The document where this element will be appended (optional).
34
+ *
35
+ * @return \DOMElement
36
+ */
37
+ public function toDOMElement($document = null)
38
+ {
39
+ if (!$document) {
40
+ $document = new \DOMDocument();
41
+ }
42
+
43
+ if (!$this->isValid()) {
44
+ return $this->emptyElement($document);
45
+ }
46
+
47
+ $emphasized = $document->createElement('em');
48
+
49
+ $emphasized->appendChild($this->textToDOMDocumentFragment($document));
50
+
51
+ return $emphasized;
52
+ }
53
+ }
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/InstantArticle.php CHANGED
@@ -34,7 +34,7 @@ use Facebook\InstantArticles\Validators\Type;
34
 
35
  class InstantArticle extends Element implements Container, InstantArticleInterface
36
  {
37
- const CURRENT_VERSION = '1.5.7';
38
 
39
  /**
40
  * The meta properties that are used on <head>
@@ -56,6 +56,11 @@ class InstantArticle extends Element implements Container, InstantArticleInterfa
56
  */
57
  private $isAutomaticAdPlaced = true;
58
 
 
 
 
 
 
59
  /**
60
  * @var string The charset that will be used. "utf-8" by default.
61
  */
@@ -98,7 +103,6 @@ class InstantArticle extends Element implements Container, InstantArticleInterfa
98
  /**
99
  * Private constructor. It must be used the Factory method
100
  * @see InstantArticle#create() For building objects
101
- * @return InstantArticle object.
102
  */
103
  private function __construct()
104
  {
@@ -170,6 +174,21 @@ class InstantArticle extends Element implements Container, InstantArticleInterfa
170
  return $this;
171
  }
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  /**
174
  * Updates article to use RTL orientation.
175
  */
@@ -449,10 +468,14 @@ class InstantArticle extends Element implements Container, InstantArticleInterfa
449
 
450
  $this->addMetaProperty('op:markup_version', $this->markupVersion);
451
  if ($this->header && count($this->header->getAds()) > 0) {
452
- $this->addMetaProperty(
453
- 'fb:use_automatic_ad_placement',
454
- $this->isAutomaticAdPlaced ? 'true' : 'false'
455
- );
 
 
 
 
456
  }
457
 
458
  if ($this->style) {
34
 
35
  class InstantArticle extends Element implements Container, InstantArticleInterface
36
  {
37
+ const CURRENT_VERSION = '1.6.1';
38
 
39
  /**
40
  * The meta properties that are used on <head>
56
  */
57
  private $isAutomaticAdPlaced = true;
58
 
59
+ /**
60
+ * @var string The ad density that will be used. "default" by default
61
+ */
62
+ private $adDensity = 'default';
63
+
64
  /**
65
  * @var string The charset that will be used. "utf-8" by default.
66
  */
103
  /**
104
  * Private constructor. It must be used the Factory method
105
  * @see InstantArticle#create() For building objects
 
106
  */
107
  private function __construct()
108
  {
174
  return $this;
175
  }
176
 
177
+ /**
178
+ * Sets the ad density to be used for auto ad placement
179
+ *
180
+ * @param string $adDensity Ad density
181
+ *
182
+ * @return $this
183
+ */
184
+ public function withAdDensity($adDensity)
185
+ {
186
+ Type::enforce($adDensity, Type::STRING);
187
+ $this->adDensity = $adDensity;
188
+
189
+ return $this;
190
+ }
191
+
192
  /**
193
  * Updates article to use RTL orientation.
194
  */
468
 
469
  $this->addMetaProperty('op:markup_version', $this->markupVersion);
470
  if ($this->header && count($this->header->getAds()) > 0) {
471
+ if ($this->isAutomaticAdPlaced) {
472
+ $this->addMetaProperty(
473
+ 'fb:use_automatic_ad_placement',
474
+ 'enable=true ad_density=' . $this->adDensity
475
+ );
476
+ } else {
477
+ $this->addMetaProperty('fb:use_automatic_ad_placement', 'false');
478
+ }
479
  }
480
 
481
  if ($this->style) {
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Elements/TextContainer.php CHANGED
@@ -23,7 +23,7 @@ abstract class TextContainer extends Element implements Container
23
  /**
24
  * @var array The content is a list of strings and FormattingElements
25
  */
26
- private $textChildren = [];
27
 
28
  /**
29
  * Adds content to the formatted text.
@@ -40,6 +40,14 @@ abstract class TextContainer extends Element implements Container
40
  return $this;
41
  }
42
 
 
 
 
 
 
 
 
 
43
  /**
44
  * @return string[]|FormattedText[]|TextContainer[] All text token for this text container.
45
  */
23
  /**
24
  * @var array The content is a list of strings and FormattingElements
25
  */
26
+ private $textChildren = array();
27
 
28
  /**
29
  * Adds content to the formatted text.
40
  return $this;
41
  }
42
 
43
+ /**
44
+ * Clears the text.
45
+ */
46
+ public function clearText()
47
+ {
48
+ $this->textChildren = array();
49
+ }
50
+
51
  /**
52
  * @return string[]|FormattedText[]|TextContainer[] All text token for this text container.
53
  */
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Parser/Parser.php CHANGED
@@ -14,12 +14,14 @@ use Facebook\InstantArticles\Validators\Type;
14
 
15
  class Parser
16
  {
 
17
  /**
18
  * @param string|DOMDocument $document The document html of an Instant Article
 
19
  *
20
  * @return InstantArticle filled element that was parsed from the DOMDocument parameter
21
  */
22
- public function parse($content)
23
  {
24
  if (Type::is($content, Type::STRING)) {
25
  libxml_use_internal_errors(true);
@@ -33,9 +35,11 @@ class Parser
33
  $json_file = file_get_contents(__DIR__ . '/instant-articles-rules.json');
34
 
35
  $instant_article = InstantArticle::create();
36
- $transformer = new Transformer();
37
- $transformer->loadRules($json_file);
38
 
 
 
 
 
39
  $transformer->transform($instant_article, $document);
40
 
41
  return $instant_article;
14
 
15
  class Parser
16
  {
17
+
18
  /**
19
  * @param string|DOMDocument $document The document html of an Instant Article
20
+ * @param Transformer $transformer The Transformer instance to use. A fresh one will be created by default.
21
  *
22
  * @return InstantArticle filled element that was parsed from the DOMDocument parameter
23
  */
24
+ public function parse($content, $transformer = null)
25
  {
26
  if (Type::is($content, Type::STRING)) {
27
  libxml_use_internal_errors(true);
35
  $json_file = file_get_contents(__DIR__ . '/instant-articles-rules.json');
36
 
37
  $instant_article = InstantArticle::create();
 
 
38
 
39
+ if ($transformer === null) {
40
+ $transformer = new Transformer();
41
+ }
42
+ $transformer->loadRules($json_file);
43
  $transformer->transform($instant_article, $document);
44
 
45
  return $instant_article;
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Parser/instant-articles-rules.json CHANGED
@@ -56,6 +56,10 @@
56
  "class": "ItalicRule",
57
  "selector" : "i"
58
  },
 
 
 
 
59
  {
60
  "class": "BoldRule",
61
  "selector" : "b"
@@ -245,6 +249,15 @@
245
  {
246
  "class": "AuthorRule",
247
  "selector" : "address",
 
 
 
 
 
 
 
 
 
248
  "properties" : {
249
  "author.url" : {
250
  "type" : "string",
@@ -534,7 +547,7 @@
534
  },
535
  {
536
  "class": "GeoTagRule",
537
- "selector" : "script.op-geotag",
538
  "properties" : {
539
  "map.geotag" : {
540
  "type" : "string",
56
  "class": "ItalicRule",
57
  "selector" : "i"
58
  },
59
+ {
60
+ "class": "EmphasizedRule",
61
+ "selector" : "em"
62
+ },
63
  {
64
  "class": "BoldRule",
65
  "selector" : "b"
249
  {
250
  "class": "AuthorRule",
251
  "selector" : "address",
252
+ "properties" : {
253
+ "author.name" : {
254
+ "type" : "string"
255
+ }
256
+ }
257
+ },
258
+ {
259
+ "class": "AuthorRule",
260
+ "selector" : "//header/address[a]",
261
  "properties" : {
262
  "author.url" : {
263
  "type" : "string",
547
  },
548
  {
549
  "class": "GeoTagRule",
550
+ "selector" : "script",
551
  "properties" : {
552
  "map.geotag" : {
553
  "type" : "string",
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/EmphasizedRule.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2016-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ namespace Facebook\InstantArticles\Transformer\Rules;
10
+
11
+ use Facebook\InstantArticles\Elements\TextContainer;
12
+ use Facebook\InstantArticles\Elements\Emphasized;
13
+
14
+ class EmphasizedRule extends ConfigurationSelectorRule
15
+ {
16
+ public function getContextClass()
17
+ {
18
+ return TextContainer::getClassName();
19
+ }
20
+
21
+ public static function create()
22
+ {
23
+ return new EmphasizedRule();
24
+ }
25
+
26
+ public static function createFrom($configuration)
27
+ {
28
+ return self::create()->withSelector($configuration['selector']);
29
+ }
30
+
31
+ public function apply($transformer, $text_container, $element)
32
+ {
33
+ $emphasized = Emphasized::create();
34
+ $text_container->appendText($emphasized);
35
+ $transformer->transform($emphasized, $element);
36
+ return $text_container;
37
+ }
38
+ }
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/InstantArticleRule.php CHANGED
@@ -78,6 +78,13 @@ class InstantArticleRule extends ConfigurationSelectorRule
78
  $auto_ad_placement = $this->getProperty(self::PROPERTY_AUTO_AD_PLACEMENT, $node);
79
  if ($auto_ad_placement === 'false') {
80
  $instant_article->disableAutomaticAdPlacement();
 
 
 
 
 
 
 
81
  }
82
 
83
  $style = $this->getProperty(self::PROPERTY_STYLE, $node);
78
  $auto_ad_placement = $this->getProperty(self::PROPERTY_AUTO_AD_PLACEMENT, $node);
79
  if ($auto_ad_placement === 'false') {
80
  $instant_article->disableAutomaticAdPlacement();
81
+ } else {
82
+ $instant_article->enableAutomaticAdPlacement();
83
+ $pairs = explode(' ', $auto_ad_placement, 2);
84
+ if (count($pairs) === 2) {
85
+ list($name, $value) = explode('=', $pairs[1], 2);
86
+ $instant_article->withAdDensity($value);
87
+ }
88
  }
89
 
90
  $style = $this->getProperty(self::PROPERTY_STYLE, $node);
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Rules/TimeRule.php CHANGED
@@ -12,6 +12,13 @@ use Facebook\InstantArticles\Elements\Time;
12
  use Facebook\InstantArticles\Elements\Header;
13
  use Facebook\InstantArticles\Transformer\Warnings\InvalidSelector;
14
 
 
 
 
 
 
 
 
15
  class TimeRule extends ConfigurationSelectorRule
16
  {
17
  const PROPERTY_TIME_TYPE_DEPRECATED = 'article.time_type';
@@ -62,7 +69,7 @@ class TimeRule extends ConfigurationSelectorRule
62
  $time_string = $this->getProperty(self::PROPERTY_TIME, $node);
63
  if ($time_string) {
64
  $time = Time::create($this->type);
65
- $time->withDatetime(new \DateTime($time_string));
66
  $header->withTime($time);
67
  } else {
68
  $transformer->addWarning(
12
  use Facebook\InstantArticles\Elements\Header;
13
  use Facebook\InstantArticles\Transformer\Warnings\InvalidSelector;
14
 
15
+ /**
16
+ * Rule to parse dates from the document.
17
+ *
18
+ * The time zone used will be the default time zone defined on the Transformer.
19
+ *
20
+ * @see Transformer::getDefaultDateTimeZone()
21
+ */
22
  class TimeRule extends ConfigurationSelectorRule
23
  {
24
  const PROPERTY_TIME_TYPE_DEPRECATED = 'article.time_type';
69
  $time_string = $this->getProperty(self::PROPERTY_TIME, $node);
70
  if ($time_string) {
71
  $time = Time::create($this->type);
72
+ $time->withDatetime(new \DateTime($time_string, $transformer->getDefaultDateTimeZone()));
73
  $header->withTime($time);
74
  } else {
75
  $transformer->addWarning(
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Transformer/Transformer.php CHANGED
@@ -46,12 +46,25 @@ class Transformer
46
  */
47
  private $instantArticle;
48
 
 
 
 
 
 
49
  /**
50
  * Flag attribute added to elements processed by a getter, so they
51
  * are not processed again by other rules.
52
  */
53
  const INSTANT_ARTICLES_PARSED_FLAG = 'data-instant-articles-element-processed';
54
 
 
 
 
 
 
 
 
 
55
  /**
56
  * Clones a node for appending to raw-html containing Elements like Interactive.
57
  *
@@ -337,7 +350,7 @@ class Transformer
337
  /**
338
  * Overrides all rules already set in this transformer instance.
339
  *
340
- * @return Rule[] List of configured rules.
341
  */
342
  public function setRules($rules)
343
  {
@@ -349,4 +362,25 @@ class Transformer
349
  $this->addRule($rule);
350
  }
351
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  }
46
  */
47
  private $instantArticle;
48
 
49
+ /**
50
+ * @var DateTimeZone the timezone for parsing dates. It defaults to 'America/Los_Angeles', but can be customized.
51
+ */
52
+ private $defaultDateTimeZone;
53
+
54
  /**
55
  * Flag attribute added to elements processed by a getter, so they
56
  * are not processed again by other rules.
57
  */
58
  const INSTANT_ARTICLES_PARSED_FLAG = 'data-instant-articles-element-processed';
59
 
60
+ /**
61
+ * Initializes default values.
62
+ */
63
+ public function __construct()
64
+ {
65
+ $this->defaultDateTimeZone = new \DateTimeZone('America/Los_Angeles');
66
+ }
67
+
68
  /**
69
  * Clones a node for appending to raw-html containing Elements like Interactive.
70
  *
350
  /**
351
  * Overrides all rules already set in this transformer instance.
352
  *
353
+ * @param Rule[] $rules List of configured rules.
354
  */
355
  public function setRules($rules)
356
  {
362
  $this->addRule($rule);
363
  }
364
  }
365
+
366
+ /**
367
+ * Sets the default timezone for parsing dates.
368
+ *
369
+ * @param DateTimeZone $dateTimeZone
370
+ */
371
+ public function setDefaultDateTimeZone($dateTimeZone)
372
+ {
373
+ Type::enforce($dateTimeZone, 'DateTimeZone');
374
+ $this->defaultDateTimeZone = $dateTimeZone;
375
+ }
376
+
377
+ /**
378
+ * Gets the default timezone for parsing dates.
379
+ *
380
+ * @return DateTimeZone
381
+ */
382
+ public function getDefaultDateTimeZone()
383
+ {
384
+ return $this->defaultDateTimeZone;
385
+ }
386
  }
vendor/facebook/facebook-instant-articles-sdk-php/src/Facebook/InstantArticles/Validators/Type.php CHANGED
@@ -386,6 +386,7 @@ class Type
386
  * "\n" => true
387
  * "a" => false
388
  * " a " => false
 
389
  *
390
  * @param string $text The text that will be checked.
391
  * @return true if empty, false otherwise.
@@ -396,8 +397,7 @@ class Type
396
  return true;
397
  }
398
  // Stripes empty spaces, &nbsp;, <br/>, new lines
399
- $text = strip_tags($text);
400
- $text = preg_replace("/[\r\n\s]+/", "", $text);
401
  $text = str_replace("&nbsp;", "", $text);
402
 
403
  return empty($text);
386
  * "\n" => true
387
  * "a" => false
388
  * " a " => false
389
+ * "&nbsp;" => true
390
  *
391
  * @param string $text The text that will be checked.
392
  * @return true if empty, false otherwise.
397
  return true;
398
  }
399
  // Stripes empty spaces, &nbsp;, <br/>, new lines
400
+ $text = preg_replace("/\s+/", "", $text);
 
401
  $text = str_replace("&nbsp;", "", $text);
402
 
403
  return empty($text);
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/ImageTest.php CHANGED
@@ -42,13 +42,13 @@ class ImageTest extends \PHPUnit_Framework_TestCase
42
  ->withURL('https://jpeg.org/images/jpegls-home.jpg')
43
  ->withCaption(
44
  Caption::create()
45
- ->appendText('Some caption to the image')
46
  );
47
 
48
  $expected =
49
  '<figure>'.
50
  '<img src="https://jpeg.org/images/jpegls-home.jpg"/>'.
51
- '<figcaption>Some caption to the image</figcaption>'.
52
  '</figure>';
53
 
54
  $rendered = $image->render();
42
  ->withURL('https://jpeg.org/images/jpegls-home.jpg')
43
  ->withCaption(
44
  Caption::create()
45
+ ->appendText('<3 some caption to the image')
46
  );
47
 
48
  $expected =
49
  '<figure>'.
50
  '<img src="https://jpeg.org/images/jpegls-home.jpg"/>'.
51
+ '<figcaption>&lt;3 some caption to the image</figcaption>'.
52
  '</figure>';
53
 
54
  $rendered = $image->render();
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/InstantArticleTest.php CHANGED
@@ -221,7 +221,7 @@ class InstantArticleTest extends \PHPUnit_Framework_TestCase
221
  '<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>'.
222
  '<meta property="op:generator:version" content="'.InstantArticle::CURRENT_VERSION.'"/>'.
223
  '<meta property="op:markup_version" content="v1.0"/>'.
224
- '<meta property="fb:use_automatic_ad_placement" content="true"/>'.
225
  '<meta property="fb:article_style" content="myarticlestyle"/>'.
226
  '</head>'.
227
  '<body>'.
@@ -282,6 +282,38 @@ class InstantArticleTest extends \PHPUnit_Framework_TestCase
282
  $this->assertEquals($expected, $this->article->render());
283
  }
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  public function testInstantArticleAlmostEmpty()
286
  {
287
  $article =
221
  '<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>'.
222
  '<meta property="op:generator:version" content="'.InstantArticle::CURRENT_VERSION.'"/>'.
223
  '<meta property="op:markup_version" content="v1.0"/>'.
224
+ '<meta property="fb:use_automatic_ad_placement" content="enable=true ad_density=default"/>'.
225
  '<meta property="fb:article_style" content="myarticlestyle"/>'.
226
  '</head>'.
227
  '<body>'.
282
  $this->assertEquals($expected, $this->article->render());
283
  }
284
 
285
+ public function testRenderWithoutAds()
286
+ {
287
+ $article =
288
+ InstantArticle::create()
289
+ ->disableAutomaticAdPlacement()
290
+ ->withHeader(
291
+ Header::create()
292
+ ->addAd(
293
+ Ad::create()
294
+ )
295
+ );
296
+ $result = $article->render();
297
+ $expected =
298
+ '<!doctype html>'.
299
+ '<html>'.
300
+ '<head>'.
301
+ '<link rel="canonical" href=""/>'.
302
+ '<meta charset="utf-8"/>'.
303
+ '<meta property="op:generator" content="facebook-instant-articles-sdk-php"/>'.
304
+ '<meta property="op:generator:version" content="'.InstantArticle::CURRENT_VERSION.'"/>'.
305
+ '<meta property="op:markup_version" content="v1.0"/>'.
306
+ '<meta property="fb:use_automatic_ad_placement" content="false"/>'.
307
+ '</head>'.
308
+ '<body>'.
309
+ '<article>'.
310
+ '</article>'.
311
+ '</body>'.
312
+ '</html>';
313
+
314
+ $this->assertEquals($expected, $result);
315
+ }
316
+
317
  public function testInstantArticleAlmostEmpty()
318
  {
319
  $article =
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/ParagraphTest.php CHANGED
@@ -48,11 +48,13 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase
48
  ->appendText(' a ')
49
  ->appendText(Italic::create()->appendText('paragraph'))
50
  ->appendText(' for ')
 
 
51
  ->appendText(Bold::create()->appendText('testing.'));
52
 
53
  $expected =
54
  '<p>'.
55
- '<b>Some</b> text to be <i>within</i> a <i>paragraph</i> for <b>testing.</b>'.
56
  '</p>';
57
 
58
  $rendered = $paragraph->render();
48
  ->appendText(' a ')
49
  ->appendText(Italic::create()->appendText('paragraph'))
50
  ->appendText(' for ')
51
+ ->appendText(Emphasized::create()->appendText('additional'))
52
+ ->appendText(' ')
53
  ->appendText(Bold::create()->appendText('testing.'));
54
 
55
  $expected =
56
  '<p>'.
57
+ '<b>Some</b> text to be <i>within</i> a <i>paragraph</i> for <em>additional</em> <b>testing.</b>'.
58
  '</p>';
59
 
60
  $rendered = $paragraph->render();
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/Validators/InstantArticleValidatorTest.php CHANGED
@@ -113,7 +113,7 @@ class InstantArticleValidatorTest extends \PHPUnit_Framework_TestCase
113
  $this->assertEquals($expected, $result);
114
 
115
  $warnings = InstantArticleValidator::check($article);
116
- $this->assertEquals(9, count($warnings));
117
  }
118
 
119
  public function testFooter()
@@ -125,7 +125,7 @@ class InstantArticleValidatorTest extends \PHPUnit_Framework_TestCase
125
 
126
  $warnings = array();
127
  InstantArticleValidator::getReport(array($footer), $warnings);
128
- $this->assertEquals(1, count($warnings));
129
  $this->assertContains('Footer must have at least one of the', $warnings[0]->__toString());
130
  }
131
  }
113
  $this->assertEquals($expected, $result);
114
 
115
  $warnings = InstantArticleValidator::check($article);
116
+ $this->assertCount(9, $warnings);
117
  }
118
 
119
  public function testFooter()
125
 
126
  $warnings = array();
127
  InstantArticleValidator::getReport(array($footer), $warnings);
128
+ $this->assertCount(1, $warnings);
129
  $this->assertContains('Footer must have at least one of the', $warnings[0]->__toString());
130
  }
131
  }
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Elements/Validators/TypeTest.php CHANGED
@@ -340,13 +340,15 @@ class TypeTest extends \PHPUnit_Framework_TestCase
340
  $this->assertFalse(Type::isTextEmpty("\nnot empty\t"));
341
  $this->assertFalse(Type::isTextEmpty(" not empty "));
342
  $this->assertFalse(Type::isTextEmpty("&nbsp;not empty"));
 
 
343
  }
344
 
345
  public function testStringEmpty()
346
  {
347
  $this->assertTrue(Type::isTextEmpty(""));
348
  $this->assertTrue(Type::isTextEmpty(" "));
349
- $this->assertTrue(Type::isTextEmpty("\t\t"));
350
  $this->assertTrue(Type::isTextEmpty("&nbsp;"));
351
  $this->assertTrue(Type::isTextEmpty("\n"));
352
  }
340
  $this->assertFalse(Type::isTextEmpty("\nnot empty\t"));
341
  $this->assertFalse(Type::isTextEmpty(" not empty "));
342
  $this->assertFalse(Type::isTextEmpty("&nbsp;not empty"));
343
+ $this->assertFalse(Type::isTextEmpty("<3 strings"));
344
+ $this->assertFalse(Type::isTextEmpty("<br />"));
345
  }
346
 
347
  public function testStringEmpty()
348
  {
349
  $this->assertTrue(Type::isTextEmpty(""));
350
  $this->assertTrue(Type::isTextEmpty(" "));
351
+ $this->assertTrue(Type::isTextEmpty("\t\n\r"));
352
  $this->assertTrue(Type::isTextEmpty("&nbsp;"));
353
  $this->assertTrue(Type::isTextEmpty("\n"));
354
  }
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/ParserTest.php CHANGED
@@ -8,6 +8,8 @@
8
  */
9
  namespace Facebook\InstantArticles\Parser;
10
 
 
 
11
  class ParserTest extends \PHPUnit_Framework_TestCase
12
  {
13
  protected function setUp()
@@ -60,4 +62,54 @@ class ParserTest extends \PHPUnit_Framework_TestCase
60
 
61
  $this->assertEquals($html_file, $result);
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
8
  */
9
  namespace Facebook\InstantArticles\Parser;
10
 
11
+ use Facebook\InstantArticles\Transformer\Transformer;
12
+
13
  class ParserTest extends \PHPUnit_Framework_TestCase
14
  {
15
  protected function setUp()
62
 
63
  $this->assertEquals($html_file, $result);
64
  }
65
+
66
+ public function testSelfParseStringNoTimezone()
67
+ {
68
+ $html_file_no_timezone = file_get_contents(__DIR__ . '/instant-article-example-no-timezone.html');
69
+ $html_file_standard_timezone = file_get_contents(__DIR__ . '/instant-article-example-standard-timezone.html');
70
+
71
+ $parser = new Parser();
72
+ $instant_article = $parser->parse($html_file_no_timezone);
73
+ $instant_article->addMetaProperty('op:generator:version', '1.0.0');
74
+ $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
75
+ $result = $instant_article->render('', true)."\n";
76
+
77
+ $this->assertEquals($html_file_standard_timezone, $result);
78
+ }
79
+
80
+ public function testSelfParseStringNoTimezoneWithDefaultNYC()
81
+ {
82
+ $html_file_no_timezone = file_get_contents(__DIR__ . '/instant-article-example-no-timezone.html');
83
+ $html_file_standard_timezone = file_get_contents(__DIR__ . '/instant-article-example-nyc-timezone.html');
84
+
85
+ $transformer = new Transformer();
86
+ $transformer->setDefaultDateTimeZone(new \DateTimeZone('America/New_York'));
87
+
88
+ $parser = new Parser();
89
+ $instant_article = $parser->parse($html_file_no_timezone, $transformer);
90
+ $instant_article->addMetaProperty('op:generator:version', '1.0.0');
91
+ $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
92
+ $result = $instant_article->render('', true)."\n";
93
+
94
+ $this->assertEquals($html_file_standard_timezone, $result);
95
+ }
96
+
97
+ public function testSelfParseAdPlacementOptions()
98
+ {
99
+ $html_file = file_get_contents(__DIR__ . '/instant-article-example-ads.html');
100
+
101
+ libxml_use_internal_errors(true);
102
+ $document = new \DOMDocument();
103
+ $document->loadHTML($html_file);
104
+ libxml_use_internal_errors(false);
105
+
106
+ $parser = new Parser();
107
+ $instant_article = $parser->parse($document);
108
+ $instant_article->addMetaProperty('op:generator:version', '1.0.0');
109
+ $instant_article->addMetaProperty('op:generator:transformer:version', '1.0.0');
110
+
111
+ $result = $instant_article->render('', true)."\n";
112
+
113
+ $this->assertEquals($html_file, $result);
114
+ }
115
  }
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-ads.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <link rel="canonical" href="http://foo.com/article.html"/>
4
+ <meta charset="utf-8"/>
5
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
6
+ <meta property="op:generator:version" content="1.0.0"/>
7
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
8
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
9
+ <meta property="op:markup_version" content="v1.0"/>
10
+ <meta property="fb:use_automatic_ad_placement" content="enable=true ad_density=medium"/>
11
+ <meta property="fb:article_style" content="myarticlestyle"/>
12
+ </head>
13
+ <body>
14
+ <article>
15
+ <header>
16
+ <figure>
17
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
18
+ <figcaption>Some caption to the image</figcaption>
19
+ </figure>
20
+ <h1>Big Top Title</h1>
21
+ <h2>Smaller SubTitle</h2>
22
+ <time class="op-published" datetime="1984-08-14T19:30:00+00:00">August 14th, 7:30pm</time>
23
+ <time class="op-modified" datetime="2016-02-10T10:00:00+00:00">February 10th, 10:00am</time>
24
+ <address><a>Author Name</a>Author more detailed description</address>
25
+ <address><a href="http://facebook.com/author" rel="facebook">Author in FB</a>Author user in facebook</address>
26
+ <h3 class="op-kicker">Some kicker of this article</h3>
27
+ <figure class="op-ad">
28
+ <iframe src="http://foo.com"></iframe>
29
+ </figure>
30
+ </header>
31
+ <p>Some text to be within a paragraph for testing.</p>
32
+ <figure class="op-ad">
33
+ <iframe src="http://foo.com"></iframe>
34
+ </figure>
35
+ <p>Other text to be within a second paragraph for testing.</p>
36
+ </article>
37
+ </body>
38
+ </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-no-timezone.html ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <link rel="canonical" href="http://foo.com/article.html"/>
4
+ <meta charset="utf-8"/>
5
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
6
+ <meta property="op:generator:version" content="1.0.0"/>
7
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
8
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
9
+ <meta property="op:markup_version" content="v1.0"/>
10
+ </head>
11
+ <body>
12
+ <article>
13
+ <header>
14
+ <figure>
15
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
16
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
17
+ </figure>
18
+ <h1>Big Top <b>Title</b></h1>
19
+ <h2>Smaller <b>SubTitle</b></h2>
20
+ <time class="op-published" datetime="1984-08-14T19:30:00">August 14th, 7:30pm</time>
21
+ <time class="op-modified" datetime="2016-02-10T10:00:00">February 10th, 10:00am</time>
22
+ <address><a href="#" title="Title of author">Author Name</a>
23
+ Author more detailed description
24
+ Even more
25
+ </address>
26
+ <address><a href="http://facebook.com/author" rel="facebook">Author in FB</a>
27
+ Author user in facebook
28
+ </address>
29
+ <address><a title="PHP Programmer">Developer</a>
30
+ </address>
31
+ <h3 class="op-kicker">Some kicker of this article</h3>
32
+ </header>
33
+ <p>Some text to be within a paragraph for testing.</p>
34
+ <figure data-feedback="fb:likes">
35
+ <img src="http://mydomain.com/path/to/img.jpg"/>
36
+ <audio title="audio title" autoplay="autoplay" muted="muted">
37
+ <source src="http://foo.com/mp3"/>
38
+ </audio>
39
+ </figure>
40
+ <figure data-feedback="fb:comments">
41
+ <img src="http://mydomain.com/path/to/img.jpg"/>
42
+ <script type="application/json" class="op-geotag">
43
+ {
44
+ "type": "Feature",
45
+ "geometry": {
46
+ "type": "Point",
47
+ "coordinates": [23.166667, 89.216667]
48
+ },
49
+ "properties": {
50
+ "title": "Jessore, Bangladesh",
51
+ "radius": 750000,
52
+ "pivot": true,
53
+ "style": "satellite",
54
+ }
55
+ }
56
+ </script>
57
+ <audio title="audio title" autoplay="autoplay" muted="muted">
58
+ <source src="http://foo.com/mp3"/>
59
+ </audio>
60
+ </figure>
61
+ <figure data-feedback="fb:likes,fb:comments">
62
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
63
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
64
+ </figure>
65
+ <p>Other text to be within a second paragraph for testing.</p>
66
+ <figure class="op-slideshow">
67
+ <figure>
68
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
69
+ </figure>
70
+ <figure>
71
+ <img src="https://jpeg.org/images/jpegls-home2.jpg"/>
72
+ </figure>
73
+ <figure>
74
+ <img src="https://jpeg.org/images/jpegls-home3.jpg"/>
75
+ </figure>
76
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
77
+ <audio title="audio title" autoplay="autoplay" muted="muted">
78
+ <source src="http://foo.com/mp3"/>
79
+ </audio>
80
+ </figure>
81
+ <ol>
82
+ <li>First list item</li>
83
+ <li>One paragraph on the list</li>
84
+ <li>On the span</li>
85
+ <li>Text inside div?</li>
86
+ <li>Other <a href="#">paragraph</a> on the li</li>
87
+ <li>Last list item</li>
88
+ </ol>
89
+ <p>Some text to be within a paragraph for testing.</p>
90
+ <figure class="op-interactive">
91
+ <iframe src="http://example.com/custom-interactive" class="column-width" height="60">
92
+ <h1>Some custom code</h1>
93
+ <script>alert("test & more test");</script></iframe>
94
+ <figcaption>This graphic is awesome.</figcaption>
95
+ </figure>
96
+ <figure class="op-ad">
97
+ <iframe src="http://foo.com"></iframe>
98
+ </figure>
99
+ <blockquote>Some blockquotes creates <b>magic</b> in an article</blockquote>
100
+ <figure class="op-map">
101
+ <script type="application/json" class="op-geotag">
102
+ {
103
+ "type": "Feature",
104
+ "geometry":
105
+ {
106
+ "type": "Point",
107
+ "coordinates": [23.166667, 89.216667]
108
+ },
109
+ "properties":
110
+ {
111
+ "title": "Jessore, Bangladesh",
112
+ "radius": 750000,
113
+ "pivot": true,
114
+ "style": "satellite",
115
+ }
116
+ }
117
+ </script>
118
+ <figcaption class="op-vertical-above"><h1 class="op-vertical-above op-center">title for caption</h1><h2 class="op-vertical-below op-right">sub title for caption</h2>
119
+
120
+
121
+ <cite class="op-vertical-center op-left">credit within caption</cite></figcaption>
122
+ <audio title="audio title" autoplay="autoplay" muted="muted">
123
+ <source src="http://foo.com/mp3"/>
124
+ </audio>
125
+ </figure>
126
+ <aside>
127
+ We can be more efficient about where we grow, what we grow, and how we grow.
128
+ <cite>Fruit Store Company</cite></aside>
129
+ <p>Other text to be within a second paragraph for testing.</p>
130
+ <figure class="op-tracker">
131
+ <iframe>
132
+ <h1>Some custom code</h1>
133
+ <script>alert("test & more test");</script></iframe>
134
+ </figure>
135
+ <figure class="op-tracker">
136
+ <iframe>
137
+ <h1>Tracker with enclosing on the script</h1>
138
+ <div><script>alert("test & more test");</script></div>
139
+ </iframe>
140
+ </figure>
141
+ <figure class="op-interactive">
142
+ <iframe class="no-margin">
143
+ <h1>Custom code for your social embed</h1>
144
+ <script>alert("test & more test");</script></iframe>
145
+ </figure>
146
+ <figure data-mode="fullscreen" data-feedback="fb:likes,fb:comments">
147
+ <video data-fb-disable-autoplay="data-fb-disable-autoplay" controls="controls">
148
+ <source src="http://mydomain.com/path/to/video.mp4" type="video/mp4"/>
149
+ </video>
150
+ <figcaption class="op-vertical-below"><h1>Video 1 Title</h1>
151
+
152
+ <cite>Attribution Source</cite></figcaption>
153
+ <script type="application/json" class="op-geotag">
154
+ {
155
+ "type": "Feature",
156
+ "geometry": {
157
+ "type": "Point",
158
+ "coordinates": [ [23.166667, 89.216667], [23.166667, 89.216667] ]
159
+ },
160
+ "properties": {
161
+ "title": "Jessore, Bangladesh",
162
+ "radius": 750000,
163
+ "pivot": true,
164
+ "style": "satellite",
165
+ }
166
+ }
167
+ </script>
168
+ </figure>
169
+ <ul class="op-related-articles" title="The related ones in the middle">
170
+ <li>
171
+ <a href="http://example.com/article.html"></a>
172
+ </li>
173
+ <li data-sponsored="true">
174
+ <a href="http://example.com/sponsored-article.html"></a>
175
+ </li>
176
+ <li>
177
+ <a href="http://example.com/another-article.html"></a>
178
+ </li>
179
+ </ul>
180
+ <footer>
181
+ <aside>
182
+ <p>Some plaintext credits to<a href="http://facebook.com/author" rel="facebook">Author</a></p>
183
+ <p>Paragraph text as credits</p>
184
+ </aside>
185
+ <ul class="op-related-articles">
186
+ <li>
187
+ <a href="http://example.com/article.html"></a>
188
+ </li>
189
+ <li data-sponsored="true">
190
+ <a href="http://example.com/sponsored-article.html"></a>
191
+ </li>
192
+ <li>
193
+ <a href="http://example.com/another-article.html"></a>
194
+ </li>
195
+ </ul>
196
+ </footer>
197
+ </article>
198
+ </body>
199
+ </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-nyc-timezone.html ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <link rel="canonical" href="http://foo.com/article.html"/>
4
+ <meta charset="utf-8"/>
5
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
6
+ <meta property="op:generator:version" content="1.0.0"/>
7
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
8
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
9
+ <meta property="op:markup_version" content="v1.0"/>
10
+ </head>
11
+ <body>
12
+ <article>
13
+ <header>
14
+ <figure>
15
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
16
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
17
+ </figure>
18
+ <h1>Big Top <b>Title</b></h1>
19
+ <h2>Smaller <b>SubTitle</b></h2>
20
+ <time class="op-published" datetime="1984-08-14T19:30:00-04:00">August 14th, 7:30pm</time>
21
+ <time class="op-modified" datetime="2016-02-10T10:00:00-05:00">February 10th, 10:00am</time>
22
+ <address><a href="#" title="Title of author">Author Name</a>
23
+ Author more detailed description
24
+ Even more
25
+ </address>
26
+ <address><a href="http://facebook.com/author" rel="facebook">Author in FB</a>
27
+ Author user in facebook
28
+ </address>
29
+ <address><a title="PHP Programmer">Developer</a>
30
+ </address>
31
+ <h3 class="op-kicker">Some kicker of this article</h3>
32
+ </header>
33
+ <p>Some text to be within a paragraph for testing.</p>
34
+ <figure data-feedback="fb:likes">
35
+ <img src="http://mydomain.com/path/to/img.jpg"/>
36
+ <audio title="audio title" autoplay="autoplay" muted="muted">
37
+ <source src="http://foo.com/mp3"/>
38
+ </audio>
39
+ </figure>
40
+ <figure data-feedback="fb:comments">
41
+ <img src="http://mydomain.com/path/to/img.jpg"/>
42
+ <script type="application/json" class="op-geotag">
43
+ {
44
+ "type": "Feature",
45
+ "geometry": {
46
+ "type": "Point",
47
+ "coordinates": [23.166667, 89.216667]
48
+ },
49
+ "properties": {
50
+ "title": "Jessore, Bangladesh",
51
+ "radius": 750000,
52
+ "pivot": true,
53
+ "style": "satellite",
54
+ }
55
+ }
56
+ </script>
57
+ <audio title="audio title" autoplay="autoplay" muted="muted">
58
+ <source src="http://foo.com/mp3"/>
59
+ </audio>
60
+ </figure>
61
+ <figure data-feedback="fb:likes,fb:comments">
62
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
63
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
64
+ </figure>
65
+ <p>Other text to be within a second paragraph for testing.</p>
66
+ <figure class="op-slideshow">
67
+ <figure>
68
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
69
+ </figure>
70
+ <figure>
71
+ <img src="https://jpeg.org/images/jpegls-home2.jpg"/>
72
+ </figure>
73
+ <figure>
74
+ <img src="https://jpeg.org/images/jpegls-home3.jpg"/>
75
+ </figure>
76
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
77
+ <audio title="audio title" autoplay="autoplay" muted="muted">
78
+ <source src="http://foo.com/mp3"/>
79
+ </audio>
80
+ </figure>
81
+ <ol>
82
+ <li>First list item</li>
83
+ <li>One paragraph on the list</li>
84
+ <li>On the span</li>
85
+ <li>Text inside div?</li>
86
+ <li>Other <a href="#">paragraph</a> on the li</li>
87
+ <li>Last list item</li>
88
+ </ol>
89
+ <p>Some text to be within a paragraph for testing.</p>
90
+ <figure class="op-interactive">
91
+ <iframe src="http://example.com/custom-interactive" class="column-width" height="60">
92
+ <h1>Some custom code</h1>
93
+ <script>alert("test & more test");</script></iframe>
94
+ <figcaption>This graphic is awesome.</figcaption>
95
+ </figure>
96
+ <figure class="op-ad">
97
+ <iframe src="http://foo.com"></iframe>
98
+ </figure>
99
+ <blockquote>Some blockquotes creates <b>magic</b> in an article</blockquote>
100
+ <figure class="op-map">
101
+ <script type="application/json" class="op-geotag">
102
+ {
103
+ "type": "Feature",
104
+ "geometry":
105
+ {
106
+ "type": "Point",
107
+ "coordinates": [23.166667, 89.216667]
108
+ },
109
+ "properties":
110
+ {
111
+ "title": "Jessore, Bangladesh",
112
+ "radius": 750000,
113
+ "pivot": true,
114
+ "style": "satellite",
115
+ }
116
+ }
117
+ </script>
118
+ <figcaption class="op-vertical-above"><h1 class="op-vertical-above op-center">title for caption</h1><h2 class="op-vertical-below op-right">sub title for caption</h2>
119
+
120
+
121
+ <cite class="op-vertical-center op-left">credit within caption</cite></figcaption>
122
+ <audio title="audio title" autoplay="autoplay" muted="muted">
123
+ <source src="http://foo.com/mp3"/>
124
+ </audio>
125
+ </figure>
126
+ <aside>
127
+ We can be more efficient about where we grow, what we grow, and how we grow.
128
+ <cite>Fruit Store Company</cite></aside>
129
+ <p>Other text to be within a second paragraph for testing.</p>
130
+ <figure class="op-tracker">
131
+ <iframe>
132
+ <h1>Some custom code</h1>
133
+ <script>alert("test & more test");</script></iframe>
134
+ </figure>
135
+ <figure class="op-tracker">
136
+ <iframe>
137
+ <h1>Tracker with enclosing on the script</h1>
138
+ <div><script>alert("test & more test");</script></div>
139
+ </iframe>
140
+ </figure>
141
+ <figure class="op-interactive">
142
+ <iframe class="no-margin">
143
+ <h1>Custom code for your social embed</h1>
144
+ <script>alert("test & more test");</script></iframe>
145
+ </figure>
146
+ <figure data-mode="fullscreen" data-feedback="fb:likes,fb:comments">
147
+ <video data-fb-disable-autoplay="data-fb-disable-autoplay" controls="controls">
148
+ <source src="http://mydomain.com/path/to/video.mp4" type="video/mp4"/>
149
+ </video>
150
+ <figcaption class="op-vertical-below"><h1>Video 1 Title</h1>
151
+
152
+ <cite>Attribution Source</cite></figcaption>
153
+ <script type="application/json" class="op-geotag">
154
+ {
155
+ "type": "Feature",
156
+ "geometry": {
157
+ "type": "Point",
158
+ "coordinates": [ [23.166667, 89.216667], [23.166667, 89.216667] ]
159
+ },
160
+ "properties": {
161
+ "title": "Jessore, Bangladesh",
162
+ "radius": 750000,
163
+ "pivot": true,
164
+ "style": "satellite",
165
+ }
166
+ }
167
+ </script>
168
+ </figure>
169
+ <ul class="op-related-articles" title="The related ones in the middle">
170
+ <li>
171
+ <a href="http://example.com/article.html"></a>
172
+ </li>
173
+ <li data-sponsored="true">
174
+ <a href="http://example.com/sponsored-article.html"></a>
175
+ </li>
176
+ <li>
177
+ <a href="http://example.com/another-article.html"></a>
178
+ </li>
179
+ </ul>
180
+ <footer>
181
+ <aside>
182
+ <p>Some plaintext credits to<a href="http://facebook.com/author" rel="facebook">Author</a></p>
183
+ <p>Paragraph text as credits</p>
184
+ </aside>
185
+ <ul class="op-related-articles">
186
+ <li>
187
+ <a href="http://example.com/article.html"></a>
188
+ </li>
189
+ <li data-sponsored="true">
190
+ <a href="http://example.com/sponsored-article.html"></a>
191
+ </li>
192
+ <li>
193
+ <a href="http://example.com/another-article.html"></a>
194
+ </li>
195
+ </ul>
196
+ </footer>
197
+ </article>
198
+ </body>
199
+ </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example-standard-timezone.html ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <link rel="canonical" href="http://foo.com/article.html"/>
4
+ <meta charset="utf-8"/>
5
+ <meta property="op:generator" content="facebook-instant-articles-sdk-php"/>
6
+ <meta property="op:generator:version" content="1.0.0"/>
7
+ <meta property="op:generator:transformer" content="facebook-instant-articles-sdk-php"/>
8
+ <meta property="op:generator:transformer:version" content="1.0.0"/>
9
+ <meta property="op:markup_version" content="v1.0"/>
10
+ </head>
11
+ <body>
12
+ <article>
13
+ <header>
14
+ <figure>
15
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
16
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
17
+ </figure>
18
+ <h1>Big Top <b>Title</b></h1>
19
+ <h2>Smaller <b>SubTitle</b></h2>
20
+ <time class="op-published" datetime="1984-08-14T19:30:00-07:00">August 14th, 7:30pm</time>
21
+ <time class="op-modified" datetime="2016-02-10T10:00:00-08:00">February 10th, 10:00am</time>
22
+ <address><a href="#" title="Title of author">Author Name</a>
23
+ Author more detailed description
24
+ Even more
25
+ </address>
26
+ <address><a href="http://facebook.com/author" rel="facebook">Author in FB</a>
27
+ Author user in facebook
28
+ </address>
29
+ <address><a title="PHP Programmer">Developer</a>
30
+ </address>
31
+ <h3 class="op-kicker">Some kicker of this article</h3>
32
+ </header>
33
+ <p>Some text to be within a paragraph for testing.</p>
34
+ <figure data-feedback="fb:likes">
35
+ <img src="http://mydomain.com/path/to/img.jpg"/>
36
+ <audio title="audio title" autoplay="autoplay" muted="muted">
37
+ <source src="http://foo.com/mp3"/>
38
+ </audio>
39
+ </figure>
40
+ <figure data-feedback="fb:comments">
41
+ <img src="http://mydomain.com/path/to/img.jpg"/>
42
+ <script type="application/json" class="op-geotag">
43
+ {
44
+ "type": "Feature",
45
+ "geometry": {
46
+ "type": "Point",
47
+ "coordinates": [23.166667, 89.216667]
48
+ },
49
+ "properties": {
50
+ "title": "Jessore, Bangladesh",
51
+ "radius": 750000,
52
+ "pivot": true,
53
+ "style": "satellite",
54
+ }
55
+ }
56
+ </script>
57
+ <audio title="audio title" autoplay="autoplay" muted="muted">
58
+ <source src="http://foo.com/mp3"/>
59
+ </audio>
60
+ </figure>
61
+ <figure data-feedback="fb:likes,fb:comments">
62
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
63
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
64
+ </figure>
65
+ <p>Other text to be within a second paragraph for testing.</p>
66
+ <figure class="op-slideshow">
67
+ <figure>
68
+ <img src="https://jpeg.org/images/jpegls-home.jpg"/>
69
+ </figure>
70
+ <figure>
71
+ <img src="https://jpeg.org/images/jpegls-home2.jpg"/>
72
+ </figure>
73
+ <figure>
74
+ <img src="https://jpeg.org/images/jpegls-home3.jpg"/>
75
+ </figure>
76
+ <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
77
+ <audio title="audio title" autoplay="autoplay" muted="muted">
78
+ <source src="http://foo.com/mp3"/>
79
+ </audio>
80
+ </figure>
81
+ <ol>
82
+ <li>First list item</li>
83
+ <li>One paragraph on the list</li>
84
+ <li>On the span</li>
85
+ <li>Text inside div?</li>
86
+ <li>Other <a href="#">paragraph</a> on the li</li>
87
+ <li>Last list item</li>
88
+ </ol>
89
+ <p>Some text to be within a paragraph for testing.</p>
90
+ <figure class="op-interactive">
91
+ <iframe src="http://example.com/custom-interactive" class="column-width" height="60">
92
+ <h1>Some custom code</h1>
93
+ <script>alert("test & more test");</script></iframe>
94
+ <figcaption>This graphic is awesome.</figcaption>
95
+ </figure>
96
+ <figure class="op-ad">
97
+ <iframe src="http://foo.com"></iframe>
98
+ </figure>
99
+ <blockquote>Some blockquotes creates <b>magic</b> in an article</blockquote>
100
+ <figure class="op-map">
101
+ <script type="application/json" class="op-geotag">
102
+ {
103
+ "type": "Feature",
104
+ "geometry":
105
+ {
106
+ "type": "Point",
107
+ "coordinates": [23.166667, 89.216667]
108
+ },
109
+ "properties":
110
+ {
111
+ "title": "Jessore, Bangladesh",
112
+ "radius": 750000,
113
+ "pivot": true,
114
+ "style": "satellite",
115
+ }
116
+ }
117
+ </script>
118
+ <figcaption class="op-vertical-above"><h1 class="op-vertical-above op-center">title for caption</h1><h2 class="op-vertical-below op-right">sub title for caption</h2>
119
+
120
+
121
+ <cite class="op-vertical-center op-left">credit within caption</cite></figcaption>
122
+ <audio title="audio title" autoplay="autoplay" muted="muted">
123
+ <source src="http://foo.com/mp3"/>
124
+ </audio>
125
+ </figure>
126
+ <aside>
127
+ We can be more efficient about where we grow, what we grow, and how we grow.
128
+ <cite>Fruit Store Company</cite></aside>
129
+ <p>Other text to be within a second paragraph for testing.</p>
130
+ <figure class="op-tracker">
131
+ <iframe>
132
+ <h1>Some custom code</h1>
133
+ <script>alert("test & more test");</script></iframe>
134
+ </figure>
135
+ <figure class="op-tracker">
136
+ <iframe>
137
+ <h1>Tracker with enclosing on the script</h1>
138
+ <div><script>alert("test & more test");</script></div>
139
+ </iframe>
140
+ </figure>
141
+ <figure class="op-interactive">
142
+ <iframe class="no-margin">
143
+ <h1>Custom code for your social embed</h1>
144
+ <script>alert("test & more test");</script></iframe>
145
+ </figure>
146
+ <figure data-mode="fullscreen" data-feedback="fb:likes,fb:comments">
147
+ <video data-fb-disable-autoplay="data-fb-disable-autoplay" controls="controls">
148
+ <source src="http://mydomain.com/path/to/video.mp4" type="video/mp4"/>
149
+ </video>
150
+ <figcaption class="op-vertical-below"><h1>Video 1 Title</h1>
151
+
152
+ <cite>Attribution Source</cite></figcaption>
153
+ <script type="application/json" class="op-geotag">
154
+ {
155
+ "type": "Feature",
156
+ "geometry": {
157
+ "type": "Point",
158
+ "coordinates": [ [23.166667, 89.216667], [23.166667, 89.216667] ]
159
+ },
160
+ "properties": {
161
+ "title": "Jessore, Bangladesh",
162
+ "radius": 750000,
163
+ "pivot": true,
164
+ "style": "satellite",
165
+ }
166
+ }
167
+ </script>
168
+ </figure>
169
+ <ul class="op-related-articles" title="The related ones in the middle">
170
+ <li>
171
+ <a href="http://example.com/article.html"></a>
172
+ </li>
173
+ <li data-sponsored="true">
174
+ <a href="http://example.com/sponsored-article.html"></a>
175
+ </li>
176
+ <li>
177
+ <a href="http://example.com/another-article.html"></a>
178
+ </li>
179
+ </ul>
180
+ <footer>
181
+ <aside>
182
+ <p>Some plaintext credits to<a href="http://facebook.com/author" rel="facebook">Author</a></p>
183
+ <p>Paragraph text as credits</p>
184
+ </aside>
185
+ <ul class="op-related-articles">
186
+ <li>
187
+ <a href="http://example.com/article.html"></a>
188
+ </li>
189
+ <li data-sponsored="true">
190
+ <a href="http://example.com/sponsored-article.html"></a>
191
+ </li>
192
+ <li>
193
+ <a href="http://example.com/another-article.html"></a>
194
+ </li>
195
+ </ul>
196
+ </footer>
197
+ </article>
198
+ </body>
199
+ </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Parser/instant-article-example.html CHANGED
@@ -63,7 +63,7 @@
63
  <img src="https://jpeg.org/images/jpegls-home.jpg"/>
64
  <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
65
  </figure>
66
- <p>Other text to be within a second paragraph for testing.</p>
67
  <figure class="op-slideshow">
68
  <figure>
69
  <img src="https://jpeg.org/images/jpegls-home.jpg"/>
63
  <img src="https://jpeg.org/images/jpegls-home.jpg"/>
64
  <figcaption><h1>Image Name</h1>Some text on text node<cite>Some caption to the image</cite></figcaption>
65
  </figure>
66
+ <p>Other text to be within a <em>second paragraph</em> for testing.</p>
67
  <figure class="op-slideshow">
68
  <figure>
69
  <img src="https://jpeg.org/images/jpegls-home.jpg"/>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/CustomHTMLTransformerTest.php CHANGED
@@ -73,6 +73,6 @@ class CustomHTMLTransformerTest extends \PHPUnit_Framework_TestCase
73
 
74
  $this->assertEquals($expected, $result);
75
  // there must be 3 warnings related to <img> inside <li> that is not supported by IA
76
- $this->assertEquals(3, count($transformer->getWarnings()));
77
  }
78
  }
73
 
74
  $this->assertEquals($expected, $result);
75
  // there must be 3 warnings related to <img> inside <li> that is not supported by IA
76
+ $this->assertCount(3, $transformer->getWarnings());
77
  }
78
  }
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple-ia.html CHANGED
@@ -11,56 +11,13 @@
11
  <body>
12
  <article>
13
  <header>
14
- <figure>
15
- <img src="http://domain.com/image-header.png"/>
16
- <figcaption>Some amazing moment captured by Photographer</figcaption>
17
- </figure>
18
- <h1>The article <b>title</b></h1>
19
- <h2>Sub <b>Title</b></h2>
20
- <address><a>Author name</a></address>
21
  </header>
22
- <p>Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit. Sed eu arcu porta, ultrices massa ut, porttitor diam. Integer id auctor augue.</p>
23
- <p>Vivamus mattis, sem id consequat dapibus, odio urna fermentum risus, in blandit dolor justo vel ex. Curabitur a neque bibendum, hendrerit sem in, congue lectus.</p>
24
  <figure>
25
  <img src="http://domain.com/image-body.png"/>
26
  <figcaption>Photographer</figcaption>
27
  </figure>
28
- <p>Curabitur vulputate odio eu justo <i>venenatis</i>, a pretium orci placerat. Nam sed neque quis eros vestibulum mattis. Donec vitae mi egestas, laoreet massa et, fringilla libero.</p>
29
- <figure class="op-interactive">
30
- <iframe>
31
- <iframe width="620" height="349" src="https://www.youtube.com/embed/s1tN0ggNreA?feature=oembed" frameborder="0" allowfullscreen=""></iframe>
32
- </iframe>
33
- </figure>
34
- <figure class="op-interactive">
35
- <iframe>
36
- <h1>Custom code for your social embed</h1>
37
- <script>alert("test & more test");</script></iframe>
38
- </figure>
39
- <figure>
40
- <img src="http://domain.com/image-header.png"/>
41
- <figcaption>Some amazing moment captured by Photographer</figcaption>
42
- </figure>
43
- <figure>
44
- <img src="http://domain.com/image-header.png?suffix=yes"/>
45
- <figcaption>Some amazing moment captured by Photographer</figcaption>
46
- </figure>
47
- <figure>
48
- <img src="http://domain.com/image-header.png?suffix=yes"/>
49
- <figcaption>Some amazing moment captured by Photographer</figcaption>
50
- </figure>
51
- <footer>
52
- <ul class="op-related-articles">
53
- <li>
54
- <a href="http://example.com/article.html"></a>
55
- </li>
56
- <li data-sponsored="true">
57
- <a href="http://example.com/sponsored-article.html"></a>
58
- </li>
59
- <li>
60
- <a href="http://example.com/another-article.html"></a>
61
- </li>
62
- </ul>
63
- </footer>
64
  </article>
65
  </body>
66
  </html>
11
  <body>
12
  <article>
13
  <header>
14
+ <h1>The article title</h1>
 
 
 
 
 
 
15
  </header>
16
+ <p>Lorem <b>ipsum</b> dolor sit amet.</p>
 
17
  <figure>
18
  <img src="http://domain.com/image-body.png"/>
19
  <figcaption>Photographer</figcaption>
20
  </figure>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  </article>
22
  </body>
23
  </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Example/simple.html CHANGED
@@ -4,51 +4,11 @@
4
  </head>
5
  <body>
6
  <div class="header">
7
- <h1>The article <b>title</b></h1>
8
- <h2>Sub <b>Title</b></h2>
9
- <span class="author">Author name</span>
10
- <div class="hero-image">
11
- <img src="http://domain.com/image-header.png" />
12
- <div class="image-caption">Some amazing moment captured by Photographer</div>
13
- </div>
14
  </div>
15
- <p>Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit. Sed eu arcu porta, ultrices massa ut, porttitor diam. Integer id auctor augue.</p>
16
- <p>Vivamus mattis, sem id consequat dapibus, odio urna fermentum risus, in blandit dolor justo vel ex. Curabitur a neque bibendum, hendrerit sem in, congue lectus.</p>
17
  <div class="image">
18
  <img src="http://domain.com/image-body.png" alt="Photographer"/>
19
  </div>
20
- <p>Curabitur vulputate odio eu justo <i>venenatis</i>, a pretium orci placerat. Nam sed neque quis eros vestibulum mattis. Donec vitae mi egestas, laoreet massa et, fringilla libero.</p>
21
- <div class="embed">
22
- <iframe width="620" height="349" src="https://www.youtube.com/embed/s1tN0ggNreA?feature=oembed" frameborder="0" allowfullscreen></iframe>
23
- </div>
24
- <div class="embed">
25
- <h1>Custom code for your social embed</h1>
26
- <script>alert("test & more test");</script>
27
- </div>
28
- <div class="prefix">
29
- <img src="//domain.com/image-header.png" />
30
- <div class="image-caption">Some amazing moment captured by Photographer</div>
31
- </div>
32
- <div class="suffix">
33
- <img src="http://domain.com/image-header.png" />
34
- <div class="image-caption">Some amazing moment captured by Photographer</div>
35
- </div>
36
- <div class="prefixsuffix">
37
- <img src="//domain.com/image-header.png" />
38
- <div class="image-caption">Some amazing moment captured by Photographer</div>
39
- </div>
40
- <footer>
41
- <ul class="op-related-articles">
42
- <li>
43
- <a href="http://example.com/article.html"></a>
44
- </li>
45
- <li data-sponsored="true">
46
- <a href="http://example.com/sponsored-article.html"></a>
47
- </li>
48
- <li>
49
- <a href="http://example.com/another-article.html"></a>
50
- </li>
51
- </ul>
52
- </footer>
53
  </body>
54
  </html>
4
  </head>
5
  <body>
6
  <div class="header">
7
+ <h1>The article title</h1>
 
 
 
 
 
 
8
  </div>
9
+ <p>Lorem <b>ipsum</b> dolor sit amet.</p>
 
10
  <div class="image">
11
  <img src="http://domain.com/image-body.png" alt="Photographer"/>
12
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  </body>
14
  </html>
vendor/facebook/facebook-instant-articles-sdk-php/tests/Facebook/InstantArticles/Transformer/Rules/AuthorRuleTest.php CHANGED
@@ -8,6 +8,8 @@
8
  */
9
  namespace Facebook\InstantArticles\Transformer\Rules;
10
 
 
 
11
  class AuthorRuleTest extends \PHPUnit_Framework_TestCase
12
  {
13
  public function testCreateFromProperties()
@@ -53,4 +55,38 @@ class AuthorRuleTest extends \PHPUnit_Framework_TestCase
53
  );
54
  $this->assertEquals(get_class($author_rule), AuthorRule::getClassName());
55
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  }
8
  */
9
  namespace Facebook\InstantArticles\Transformer\Rules;
10
 
11
+ use Facebook\InstantArticles\Parser\Parser;
12
+
13
  class AuthorRuleTest extends \PHPUnit_Framework_TestCase
14
  {
15
  public function testCreateFromProperties()
55
  );
56
  $this->assertEquals(get_class($author_rule), AuthorRule::getClassName());
57
  }
58
+
59
+ public function testExpectedNameWithLink()
60
+ {
61
+ $expectedName = "The Author";
62
+ $html =
63
+ '<header>'.
64
+ '<h1>Article Title</h1>'.
65
+ // The name is inside an <a> element
66
+ "<address><a>$expectedName</a></address>".
67
+ '</header>';
68
+
69
+ $parser = new Parser();
70
+ $instantArticle = $parser->parse($html);
71
+ $author = $instantArticle->getHeader()->getAuthors()[0];
72
+
73
+ $this->assertEquals($expectedName, $author->getName());
74
+ }
75
+
76
+ public function testExpectedNameWithoutLink()
77
+ {
78
+ $expectedName = "The Other Author";
79
+ $html =
80
+ '<header>'.
81
+ '<h1>Article Title</h1>'.
82
+ // The name is inside the <address> element
83
+ "<address>$expectedName</address>".
84
+ '</header>';
85
+
86
+ $parser = new Parser();
87
+ $instantArticle = $parser->parse($html);
88
+ $author = $instantArticle->getHeader()->getAuthors()[0];
89
+
90
+ $this->assertEquals($expectedName, $author->getName());
91
+ }
92
  }
vendor/squizlabs/php_codesniffer/.gitattributes ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /tests export-ignore
2
+ /CodeSniffer/Standards/Generic/Tests export-ignore
3
+ /CodeSniffer/Standards/MySource/Tests export-ignore
4
+ /CodeSniffer/Standards/PEAR/Tests export-ignore
5
+ /CodeSniffer/Standards/PSR1/Tests export-ignore
6
+ /CodeSniffer/Standards/PSR2/Tests export-ignore
7
+ /CodeSniffer/Standards/Squiz/Tests export-ignore
8
+ /CodeSniffer/Standards/Zend/Tests export-ignore
9
+ .travis.yml export-ignore
10
+ package.xml export-ignore
11
+ phpunit.xml.dist export-ignore
12
+ php5-testingConfig.ini export-ignore
13
+ php7-testingConfig.ini export-ignore
vendor/squizlabs/php_codesniffer/.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ /CodeSniffer.conf
2
+ /phpcs.xml
3
+ /phpunit.xml
4
+ .idea/*
5
+ /vendor/
6
+ composer.lock
vendor/squizlabs/php_codesniffer/CONTRIBUTING.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Contributing
2
+ -------------
3
+
4
+ Before you contribute code to PHP\_CodeSniffer, please make sure it conforms to the PHPCS coding standard and that the PHP\_CodeSniffer unit tests still pass. The easiest way to contribute is to work on a checkout of the repository, or your own fork, rather than an installed PEAR version. If you do this, you can run the following commands to check if everything is ready to submit:
5
+
6
+ cd PHP_CodeSniffer
7
+ php scripts/phpcs
8
+
9
+ Which should give you no output, indicating that there are no coding standard errors. And then:
10
+
11
+ phpunit
12
+
13
+ Which should give you no failures or errors. You can ignore any skipped tests as these are for external tools.
vendor/squizlabs/php_codesniffer/CodeSniffer.conf.dist ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $phpCodeSnifferConfig = array (
3
+ 'default_standard' => 'PSR2',
4
+ 'report_format' => 'summary',
5
+ 'show_warnings' => '0',
6
+ 'show_progress' => '1',
7
+ 'report_width' => '120',
8
+ )
9
+ ?>
vendor/squizlabs/php_codesniffer/CodeSniffer.php ADDED
@@ -0,0 +1,2578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHP_CodeSniffer tokenizes PHP code and detects violations of a
4
+ * defined set of coding standards.
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * @category PHP
9
+ * @package PHP_CodeSniffer
10
+ * @author Greg Sherwood <gsherwood@squiz.net>
11
+ * @author Marc McIntyre <mmcintyre@squiz.net>
12
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
13
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
14
+ * @link http://pear.php.net/package/PHP_CodeSniffer
15
+ */
16
+
17
+ spl_autoload_register(array('PHP_CodeSniffer', 'autoload'));
18
+
19
+ if (class_exists('PHP_CodeSniffer_Exception', true) === false) {
20
+ throw new Exception('Class PHP_CodeSniffer_Exception not found');
21
+ }
22
+
23
+ if (class_exists('PHP_CodeSniffer_File', true) === false) {
24
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_File not found');
25
+ }
26
+
27
+ if (class_exists('PHP_CodeSniffer_Fixer', true) === false) {
28
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Fixer not found');
29
+ }
30
+
31
+ if (class_exists('PHP_CodeSniffer_Tokens', true) === false) {
32
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Tokens not found');
33
+ }
34
+
35
+ if (class_exists('PHP_CodeSniffer_CLI', true) === false) {
36
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CLI not found');
37
+ }
38
+
39
+ if (interface_exists('PHP_CodeSniffer_Sniff', true) === false) {
40
+ throw new PHP_CodeSniffer_Exception('Interface PHP_CodeSniffer_Sniff not found');
41
+ }
42
+
43
+ /**
44
+ * PHP_CodeSniffer tokenizes PHP code and detects violations of a
45
+ * defined set of coding standards.
46
+ *
47
+ * Standards are specified by classes that implement the PHP_CodeSniffer_Sniff
48
+ * interface. A sniff registers what token types it wishes to listen for, then
49
+ * PHP_CodeSniffer encounters that token, the sniff is invoked and passed
50
+ * information about where the token was found in the stack, and the token stack
51
+ * itself.
52
+ *
53
+ * Sniff files and their containing class must be prefixed with Sniff, and
54
+ * have an extension of .php.
55
+ *
56
+ * Multiple PHP_CodeSniffer operations can be performed by re-calling the
57
+ * process function with different parameters.
58
+ *
59
+ * @category PHP
60
+ * @package PHP_CodeSniffer
61
+ * @author Greg Sherwood <gsherwood@squiz.net>
62
+ * @author Marc McIntyre <mmcintyre@squiz.net>
63
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
64
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
65
+ * @version Release: @package_version@
66
+ * @link http://pear.php.net/package/PHP_CodeSniffer
67
+ */
68
+ class PHP_CodeSniffer
69
+ {
70
+
71
+ /**
72
+ * The current version.
73
+ *
74
+ * @var string
75
+ */
76
+ const VERSION = '2.9.1';
77
+
78
+ /**
79
+ * Package stability; either stable, beta or alpha.
80
+ *
81
+ * @var string
82
+ */
83
+ const STABILITY = 'stable';
84
+
85
+ /**
86
+ * The file or directory that is currently being processed.
87
+ *
88
+ * @var string
89
+ */
90
+ protected $file = '';
91
+
92
+ /**
93
+ * The directories that the processed rulesets are in.
94
+ *
95
+ * This is declared static because it is also used in the
96
+ * autoloader to look for sniffs outside the PHPCS install.
97
+ * This way, standards designed to be installed inside PHPCS can
98
+ * also be used from outside the PHPCS Standards directory.
99
+ *
100
+ * @var string
101
+ */
102
+ protected static $rulesetDirs = array();
103
+
104
+ /**
105
+ * The CLI object controlling the run.
106
+ *
107
+ * @var PHP_CodeSniffer_CLI
108
+ */
109
+ public $cli = null;
110
+
111
+ /**
112
+ * The Reporting object controlling report generation.
113
+ *
114
+ * @var PHP_CodeSniffer_Reporting
115
+ */
116
+ public $reporting = null;
117
+
118
+ /**
119
+ * An array of sniff objects that are being used to check files.
120
+ *
121
+ * @var array(PHP_CodeSniffer_Sniff)
122
+ */
123
+ protected $listeners = array();
124
+
125
+ /**
126
+ * An array of sniffs that are being used to check files.
127
+ *
128
+ * @var array(string)
129
+ */
130
+ protected $sniffs = array();
131
+
132
+ /**
133
+ * A mapping of sniff codes to fully qualified class names.
134
+ *
135
+ * The key is the sniff code and the value
136
+ * is the fully qualified name of the sniff class.
137
+ *
138
+ * @var array<string, string>
139
+ */
140
+ public $sniffCodes = array();
141
+
142
+ /**
143
+ * The listeners array, indexed by token type.
144
+ *
145
+ * @var array
146
+ */
147
+ private $_tokenListeners = array();
148
+
149
+ /**
150
+ * An array of rules from the ruleset.xml file.
151
+ *
152
+ * It may be empty, indicating that the ruleset does not override
153
+ * any of the default sniff settings.
154
+ *
155
+ * @var array
156
+ */
157
+ protected $ruleset = array();
158
+
159
+ /**
160
+ * An array of patterns to use for skipping files.
161
+ *
162
+ * @var array
163
+ */
164
+ protected $ignorePatterns = array();
165
+
166
+ /**
167
+ * An array of extensions for files we will check.
168
+ *
169
+ * @var array
170
+ */
171
+ public $allowedFileExtensions = array();
172
+
173
+ /**
174
+ * An array of default extensions and associated tokenizers.
175
+ *
176
+ * If no extensions are set, these will be used as the defaults.
177
+ * If extensions are set, these will be used when the correct tokenizer
178
+ * can not be determined, such as when checking a passed filename instead
179
+ * of files in a directory.
180
+ *
181
+ * @var array
182
+ */
183
+ public $defaultFileExtensions = array(
184
+ 'php' => 'PHP',
185
+ 'inc' => 'PHP',
186
+ 'js' => 'JS',
187
+ 'css' => 'CSS',
188
+ );
189
+
190
+ /**
191
+ * An array of variable types for param/var we will check.
192
+ *
193
+ * @var array(string)
194
+ */
195
+ public static $allowedTypes = array(
196
+ 'array',
197
+ 'boolean',
198
+ 'float',
199
+ 'integer',
200
+ 'mixed',
201
+ 'object',
202
+ 'string',
203
+ 'resource',
204
+ 'callable',
205
+ );
206
+
207
+
208
+ /**
209
+ * Constructs a PHP_CodeSniffer object.
210
+ *
211
+ * @param int $verbosity The verbosity level.
212
+ * 1: Print progress information.
213
+ * 2: Print tokenizer debug information.
214
+ * 3: Print sniff debug information.
215
+ * @param int $tabWidth The number of spaces each tab represents.
216
+ * If greater than zero, tabs will be replaced
217
+ * by spaces before testing each file.
218
+ * @param string $encoding The charset of the sniffed files.
219
+ * This is important for some reports that output
220
+ * with utf-8 encoding as you don't want it double
221
+ * encoding messages.
222
+ * @param bool $interactive If TRUE, will stop after each file with errors
223
+ * and wait for user input.
224
+ *
225
+ * @see process()
226
+ */
227
+ public function __construct(
228
+ $verbosity=0,
229
+ $tabWidth=0,
230
+ $encoding='iso-8859-1',
231
+ $interactive=false
232
+ ) {
233
+ if ($verbosity !== null) {
234
+ $this->setVerbosity($verbosity);
235
+ }
236
+
237
+ if ($tabWidth !== null) {
238
+ $this->setTabWidth($tabWidth);
239
+ }
240
+
241
+ if ($encoding !== null) {
242
+ $this->setEncoding($encoding);
243
+ }
244
+
245
+ if ($interactive !== null) {
246
+ $this->setInteractive($interactive);
247
+ }
248
+
249
+ if (defined('PHPCS_DEFAULT_ERROR_SEV') === false) {
250
+ define('PHPCS_DEFAULT_ERROR_SEV', 5);
251
+ }
252
+
253
+ if (defined('PHPCS_DEFAULT_WARN_SEV') === false) {
254
+ define('PHPCS_DEFAULT_WARN_SEV', 5);
255
+ }
256
+
257
+ if (defined('PHP_CODESNIFFER_CBF') === false) {
258
+ define('PHP_CODESNIFFER_CBF', false);
259
+ }
260
+
261
+ // Set default CLI object in case someone is running us
262
+ // without using the command line script.
263
+ $this->cli = new PHP_CodeSniffer_CLI();
264
+ $this->cli->errorSeverity = PHPCS_DEFAULT_ERROR_SEV;
265
+ $this->cli->warningSeverity = PHPCS_DEFAULT_WARN_SEV;
266
+ $this->cli->dieOnUnknownArg = false;
267
+
268
+ $this->reporting = new PHP_CodeSniffer_Reporting();
269
+
270
+ }//end __construct()
271
+
272
+
273
+ /**
274
+ * Autoload static method for loading classes and interfaces.
275
+ *
276
+ * @param string $className The name of the class or interface.
277
+ *
278
+ * @return void
279
+ */
280
+ public static function autoload($className)
281
+ {
282
+ if (substr($className, 0, 4) === 'PHP_') {
283
+ $newClassName = substr($className, 4);
284
+ } else {
285
+ $newClassName = $className;
286
+ }
287
+
288
+ $path = str_replace(array('_', '\\'), DIRECTORY_SEPARATOR, $newClassName).'.php';
289
+
290
+ if (is_file(dirname(__FILE__).DIRECTORY_SEPARATOR.$path) === true) {
291
+ // Check standard file locations based on class name.
292
+ include dirname(__FILE__).DIRECTORY_SEPARATOR.$path;
293
+ return;
294
+ } else {
295
+ // Check for included sniffs.
296
+ $installedPaths = PHP_CodeSniffer::getInstalledStandardPaths();
297
+ foreach ($installedPaths as $installedPath) {
298
+ if (is_file($installedPath.DIRECTORY_SEPARATOR.$path) === true) {
299
+ include $installedPath.DIRECTORY_SEPARATOR.$path;
300
+ return;
301
+ }
302
+ }
303
+
304
+ // Check standard file locations based on the loaded rulesets.
305
+ foreach (self::$rulesetDirs as $rulesetDir) {
306
+ if (is_file(dirname($rulesetDir).DIRECTORY_SEPARATOR.$path) === true) {
307
+ include_once dirname($rulesetDir).DIRECTORY_SEPARATOR.$path;
308
+ return;
309
+ }
310
+ }
311
+ }//end if
312
+
313
+ // Everything else.
314
+ @include $path;
315
+
316
+ }//end autoload()
317
+
318
+
319
+ /**
320
+ * Sets the verbosity level.
321
+ *
322
+ * @param int $verbosity The verbosity level.
323
+ * 1: Print progress information.
324
+ * 2: Print tokenizer debug information.
325
+ * 3: Print sniff debug information.
326
+ *
327
+ * @return void
328
+ */
329
+ public function setVerbosity($verbosity)
330
+ {
331
+ if (defined('PHP_CODESNIFFER_VERBOSITY') === false) {
332
+ define('PHP_CODESNIFFER_VERBOSITY', $verbosity);
333
+ }
334
+
335
+ }//end setVerbosity()
336
+
337
+
338
+ /**
339
+ * Sets the tab width.
340
+ *
341
+ * @param int $tabWidth The number of spaces each tab represents.
342
+ * If greater than zero, tabs will be replaced
343
+ * by spaces before testing each file.
344
+ *
345
+ * @return void
346
+ */
347
+ public function setTabWidth($tabWidth)
348
+ {
349
+ if (defined('PHP_CODESNIFFER_TAB_WIDTH') === false) {
350
+ define('PHP_CODESNIFFER_TAB_WIDTH', $tabWidth);
351
+ }
352
+
353
+ }//end setTabWidth()
354
+
355
+
356
+ /**
357
+ * Sets the encoding.
358
+ *
359
+ * @param string $encoding The charset of the sniffed files.
360
+ * This is important for some reports that output
361
+ * with utf-8 encoding as you don't want it double
362
+ * encoding messages.
363
+ *
364
+ * @return void
365
+ */
366
+ public function setEncoding($encoding)
367
+ {
368
+ if (defined('PHP_CODESNIFFER_ENCODING') === false) {
369
+ define('PHP_CODESNIFFER_ENCODING', $encoding);
370
+ }
371
+
372
+ }//end setEncoding()
373
+
374
+
375
+ /**
376
+ * Sets the interactive flag.
377
+ *
378
+ * @param bool $interactive If TRUE, will stop after each file with errors
379
+ * and wait for user input.
380
+ *
381
+ * @return void
382
+ */
383
+ public function setInteractive($interactive)
384
+ {
385
+ if (defined('PHP_CODESNIFFER_INTERACTIVE') === false) {
386
+ define('PHP_CODESNIFFER_INTERACTIVE', $interactive);
387
+ }
388
+
389
+ }//end setInteractive()
390
+
391
+
392
+ /**
393
+ * Sets an array of file extensions that we will allow checking of.
394
+ *
395
+ * If the extension is one of the defaults, a specific tokenizer
396
+ * will be used. Otherwise, the PHP tokenizer will be used for
397
+ * all extensions passed.
398
+ *
399
+ * @param array $extensions An array of file extensions.
400
+ *
401
+ * @return void
402
+ */
403
+ public function setAllowedFileExtensions(array $extensions)
404
+ {
405
+ $newExtensions = array();
406
+ foreach ($extensions as $ext) {
407
+ $slash = strpos($ext, '/');
408
+ if ($slash !== false) {
409
+ // They specified the tokenizer too.
410
+ list($ext, $tokenizer) = explode('/', $ext);
411
+ $newExtensions[$ext] = strtoupper($tokenizer);
412
+ continue;
413
+ }
414
+
415
+ if (isset($this->allowedFileExtensions[$ext]) === true) {
416
+ $newExtensions[$ext] = $this->allowedFileExtensions[$ext];
417
+ } else if (isset($this->defaultFileExtensions[$ext]) === true) {
418
+ $newExtensions[$ext] = $this->defaultFileExtensions[$ext];
419
+ } else {
420
+ $newExtensions[$ext] = 'PHP';
421
+ }
422
+ }
423
+
424
+ $this->allowedFileExtensions = $newExtensions;
425
+
426
+ }//end setAllowedFileExtensions()
427
+
428
+
429
+ /**
430
+ * Sets an array of ignore patterns that we use to skip files and folders.
431
+ *
432
+ * Patterns are not case sensitive.
433
+ *
434
+ * @param array $patterns An array of ignore patterns. The pattern is the key
435
+ * and the value is either "absolute" or "relative",
436
+ * depending on how the pattern should be applied to a
437
+ * file path.
438
+ *
439
+ * @return void
440
+ */
441
+ public function setIgnorePatterns(array $patterns)
442
+ {
443
+ $this->ignorePatterns = $patterns;
444
+
445
+ }//end setIgnorePatterns()
446
+
447
+
448
+ /**
449
+ * Gets the array of ignore patterns.
450
+ *
451
+ * Optionally takes a listener to get ignore patterns specified
452
+ * for that sniff only.
453
+ *
454
+ * @param string $listener The listener to get patterns for. If NULL, all
455
+ * patterns are returned.
456
+ *
457
+ * @return array
458
+ */
459
+ public function getIgnorePatterns($listener=null)
460
+ {
461
+ if ($listener === null) {
462
+ return $this->ignorePatterns;
463
+ }
464
+
465
+ if (isset($this->ignorePatterns[$listener]) === true) {
466
+ return $this->ignorePatterns[$listener];
467
+ }
468
+
469
+ return array();
470
+
471
+ }//end getIgnorePatterns()
472
+
473
+
474
+ /**
475
+ * Sets the internal CLI object.
476
+ *
477
+ * @param object $cli The CLI object controlling the run.
478
+ *
479
+ * @return void
480
+ */
481
+ public function setCli($cli)
482
+ {
483
+ $this->cli = $cli;
484
+
485
+ }//end setCli()
486
+
487
+
488
+ /**
489
+ * Start a PHP_CodeSniffer run.
490
+ *
491
+ * @param string|array $files The files and directories to process. For
492
+ * directories, each sub directory will also
493
+ * be traversed for source files.
494
+ * @param string|array $standards The set of code sniffs we are testing
495
+ * against.
496
+ * @param array $restrictions The sniff codes to restrict the
497
+ * violations to.
498
+ * @param boolean $local If true, don't recurse into directories.
499
+ *
500
+ * @return void
501
+ */
502
+ public function process($files, $standards, array $restrictions=array(), $local=false)
503
+ {
504
+ $files = (array) $files;
505
+ $this->initStandard($standards, $restrictions);
506
+ $this->processFiles($files, $local);
507
+
508
+ }//end process()
509
+
510
+
511
+ /**
512
+ * Initialise the standard that the run will use.
513
+ *
514
+ * @param string|array $standards The set of code sniffs we are testing
515
+ * against.
516
+ * @param array $restrictions The sniff codes to restrict the testing to.
517
+ * @param array $exclusions The sniff codes to exclude from testing.
518
+ *
519
+ * @return void
520
+ */
521
+ public function initStandard($standards, array $restrictions=array(), array $exclusions=array())
522
+ {
523
+ $standards = (array) $standards;
524
+
525
+ // Reset the members.
526
+ $this->listeners = array();
527
+ $this->sniffs = array();
528
+ $this->ruleset = array();
529
+ $this->_tokenListeners = array();
530
+ self::$rulesetDirs = array();
531
+
532
+ // Ensure this option is enabled or else line endings will not always
533
+ // be detected properly for files created on a Mac with the /r line ending.
534
+ ini_set('auto_detect_line_endings', true);
535
+
536
+ if (defined('PHP_CODESNIFFER_IN_TESTS') === true && empty($restrictions) === false) {
537
+ // Should be one standard and one sniff being tested at a time.
538
+ $installed = $this->getInstalledStandardPath($standards[0]);
539
+ if ($installed !== null) {
540
+ $standard = $installed;
541
+ } else {
542
+ $standard = self::realpath($standards[0]);
543
+ if (is_dir($standard) === true
544
+ && is_file(self::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml')) === true
545
+ ) {
546
+ $standard = self::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml');
547
+ }
548
+ }
549
+
550
+ $sniffs = $this->_expandRulesetReference($restrictions[0], dirname($standard));
551
+ } else {
552
+ $sniffs = array();
553
+ foreach ($standards as $standard) {
554
+ $installed = $this->getInstalledStandardPath($standard);
555
+ if ($installed !== null) {
556
+ $standard = $installed;
557
+ } else {
558
+ $standard = self::realpath($standard);
559
+ if (is_dir($standard) === true
560
+ && is_file(self::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml')) === true
561
+ ) {
562
+ $standard = self::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml');
563
+ }
564
+ }
565
+
566
+ if (PHP_CODESNIFFER_VERBOSITY === 1) {
567
+ $ruleset = simplexml_load_string(file_get_contents($standard));
568
+ if ($ruleset !== false) {
569
+ $standardName = (string) $ruleset['name'];
570
+ }
571
+
572
+ echo "Registering sniffs in the $standardName standard... ";
573
+ if (count($standards) > 1 || PHP_CODESNIFFER_VERBOSITY > 2) {
574
+ echo PHP_EOL;
575
+ }
576
+ }
577
+
578
+ $sniffs = array_merge($sniffs, $this->processRuleset($standard));
579
+ }//end foreach
580
+ }//end if
581
+
582
+ $sniffRestrictions = array();
583
+ foreach ($restrictions as $sniffCode) {
584
+ $parts = explode('.', strtolower($sniffCode));
585
+ $sniffRestrictions[] = $parts[0].'_sniffs_'.$parts[1].'_'.$parts[2].'sniff';
586
+ }
587
+
588
+ $sniffExclusions = array();
589
+ foreach ($exclusions as $sniffCode) {
590
+ $parts = explode('.', strtolower($sniffCode));
591
+ $sniffExclusions[] = $parts[0].'_sniffs_'.$parts[1].'_'.$parts[2].'sniff';
592
+ }
593
+
594
+ $this->registerSniffs($sniffs, $sniffRestrictions, $sniffExclusions);
595
+ $this->populateTokenListeners();
596
+
597
+ if (PHP_CODESNIFFER_VERBOSITY === 1) {
598
+ $numSniffs = count($this->sniffs);
599
+ echo "DONE ($numSniffs sniffs registered)".PHP_EOL;
600
+ }
601
+
602
+ }//end initStandard()
603
+
604
+
605
+ /**
606
+ * Processes the files/directories that PHP_CodeSniffer was constructed with.
607
+ *
608
+ * @param string|array $files The files and directories to process. For
609
+ * directories, each sub directory will also
610
+ * be traversed for source files.
611
+ * @param boolean $local If true, don't recurse into directories.
612
+ *
613
+ * @return void
614
+ * @throws PHP_CodeSniffer_Exception If files are invalid.
615
+ */
616
+ public function processFiles($files, $local=false)
617
+ {
618
+ $files = (array) $files;
619
+ $cliValues = $this->cli->getCommandLineValues();
620
+ $showProgress = $cliValues['showProgress'];
621
+ $useColors = $cliValues['colors'];
622
+
623
+ if (PHP_CODESNIFFER_VERBOSITY > 0) {
624
+ echo 'Creating file list... ';
625
+ }
626
+
627
+ if (empty($this->allowedFileExtensions) === true) {
628
+ $this->allowedFileExtensions = $this->defaultFileExtensions;
629
+ }
630
+
631
+ $todo = $this->getFilesToProcess($files, $local);
632
+ $numFiles = count($todo);
633
+
634
+ if (PHP_CODESNIFFER_VERBOSITY > 0) {
635
+ echo "DONE ($numFiles files in queue)".PHP_EOL;
636
+ }
637
+
638
+ $numProcessed = 0;
639
+ $dots = 0;
640
+ $maxLength = strlen($numFiles);
641
+ $lastDir = '';
642
+ foreach ($todo as $file) {
643
+ $this->file = $file;
644
+ $currDir = dirname($file);
645
+ if ($lastDir !== $currDir) {
646
+ if (PHP_CODESNIFFER_VERBOSITY > 0 || PHP_CODESNIFFER_CBF === true) {
647
+ echo 'Changing into directory '.$currDir.PHP_EOL;
648
+ }
649
+
650
+ $lastDir = $currDir;
651
+ }
652
+
653
+ $phpcsFile = $this->processFile($file, null);
654
+ $numProcessed++;
655
+
656
+ if (PHP_CODESNIFFER_VERBOSITY > 0
657
+ || PHP_CODESNIFFER_INTERACTIVE === true
658
+ || $showProgress === false
659
+ ) {
660
+ continue;
661
+ }
662
+
663
+ // Show progress information.
664
+ if ($phpcsFile === null) {
665
+ echo 'S';
666
+ } else {
667
+ $errors = $phpcsFile->getErrorCount();
668
+ $warnings = $phpcsFile->getWarningCount();
669
+ if ($errors > 0) {
670
+ if ($useColors === true) {
671
+ echo "\033[31m";
672
+ }
673
+
674
+ echo 'E';
675
+ } else if ($warnings > 0) {
676
+ if ($useColors === true) {
677
+ echo "\033[33m";
678
+ }
679
+
680
+ echo 'W';
681
+ } else {
682
+ echo '.';
683
+ }
684
+
685
+ if ($useColors === true) {
686
+ echo "\033[0m";
687
+ }
688
+ }//end if
689
+
690
+ $dots++;
691
+ if ($dots === 60) {
692
+ $padding = ($maxLength - strlen($numProcessed));
693
+ echo str_repeat(' ', $padding);
694
+ $percent = round(($numProcessed / $numFiles) * 100);
695
+ echo " $numProcessed / $numFiles ($percent%)".PHP_EOL;
696
+ $dots = 0;
697
+ }
698
+ }//end foreach
699
+
700
+ if (PHP_CODESNIFFER_VERBOSITY === 0
701
+ && PHP_CODESNIFFER_INTERACTIVE === false
702
+ && $showProgress === true
703
+ ) {
704
+ echo PHP_EOL.PHP_EOL;
705
+ }
706
+
707
+ }//end processFiles()
708
+
709
+
710
+ /**
711
+ * Processes a single ruleset and returns a list of the sniffs it represents.
712
+ *
713
+ * Rules founds within the ruleset are processed immediately, but sniff classes
714
+ * are not registered by this method.
715
+ *
716
+ * @param string $rulesetPath The path to a ruleset XML file.
717
+ * @param int $depth How many nested processing steps we are in. This
718
+ * is only used for debug output.
719
+ *
720
+ * @return array
721
+ * @throws PHP_CodeSniffer_Exception If the ruleset path is invalid.
722
+ */
723
+ public function processRuleset($rulesetPath, $depth=0)
724
+ {
725
+ $rulesetPath = self::realpath($rulesetPath);
726
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
727
+ echo str_repeat("\t", $depth);
728
+ echo "Processing ruleset $rulesetPath".PHP_EOL;
729
+ }
730
+
731
+ $ruleset = simplexml_load_string(file_get_contents($rulesetPath));
732
+ if ($ruleset === false) {
733
+ throw new PHP_CodeSniffer_Exception("Ruleset $rulesetPath is not valid");
734
+ }
735
+
736
+ $ownSniffs = array();
737
+ $includedSniffs = array();
738
+ $excludedSniffs = array();
739
+ $cliValues = $this->cli->getCommandLineValues();
740
+
741
+ $rulesetDir = dirname($rulesetPath);
742
+ self::$rulesetDirs[] = $rulesetDir;
743
+
744
+ if (is_dir($rulesetDir.DIRECTORY_SEPARATOR.'Sniffs') === true) {
745
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
746
+ echo str_repeat("\t", $depth);
747
+ echo "\tAdding sniff files from \"/.../".basename($rulesetDir)."/Sniffs/\" directory".PHP_EOL;
748
+ }
749
+
750
+ $ownSniffs = $this->_expandSniffDirectory($rulesetDir.DIRECTORY_SEPARATOR.'Sniffs', $depth);
751
+ }
752
+
753
+ // Process custom sniff config settings.
754
+ foreach ($ruleset->{'config'} as $config) {
755
+ if ($this->_shouldProcessElement($config) === false) {
756
+ continue;
757
+ }
758
+
759
+ $this->setConfigData((string) $config['name'], (string) $config['value'], true);
760
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
761
+ echo str_repeat("\t", $depth);
762
+ echo "\t=> set config value ".(string) $config['name'].': '.(string) $config['value'].PHP_EOL;
763
+ }
764
+ }
765
+
766
+ foreach ($ruleset->rule as $rule) {
767
+ if (isset($rule['ref']) === false
768
+ || $this->_shouldProcessElement($rule) === false
769
+ ) {
770
+ continue;
771
+ }
772
+
773
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
774
+ echo str_repeat("\t", $depth);
775
+ echo "\tProcessing rule \"".$rule['ref'].'"'.PHP_EOL;
776
+ }
777
+
778
+ $includedSniffs = array_merge(
779
+ $includedSniffs,
780
+ $this->_expandRulesetReference($rule['ref'], $rulesetDir, $depth)
781
+ );
782
+
783
+ if (isset($rule->exclude) === true) {
784
+ foreach ($rule->exclude as $exclude) {
785
+ if ($this->_shouldProcessElement($exclude) === false) {
786
+ continue;
787
+ }
788
+
789
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
790
+ echo str_repeat("\t", $depth);
791
+ echo "\t\tExcluding rule \"".$exclude['name'].'"'.PHP_EOL;
792
+ }
793
+
794
+ // Check if a single code is being excluded, which is a shortcut
795
+ // for setting the severity of the message to 0.
796
+ $parts = explode('.', $exclude['name']);
797
+ if (count($parts) === 4) {
798
+ $this->ruleset[(string) $exclude['name']]['severity'] = 0;
799
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
800
+ echo str_repeat("\t", $depth);
801
+ echo "\t\t=> severity set to 0".PHP_EOL;
802
+ }
803
+ } else {
804
+ $excludedSniffs = array_merge(
805
+ $excludedSniffs,
806
+ $this->_expandRulesetReference($exclude['name'], $rulesetDir, ($depth + 1))
807
+ );
808
+ }
809
+ }//end foreach
810
+ }//end if
811
+
812
+ $this->_processRule($rule, $depth);
813
+ }//end foreach
814
+
815
+ // Process custom command line arguments.
816
+ $cliArgs = array();
817
+ foreach ($ruleset->{'arg'} as $arg) {
818
+ if ($this->_shouldProcessElement($arg) === false) {
819
+ continue;
820
+ }
821
+
822
+ if (isset($arg['name']) === true) {
823
+ $argString = '--'.(string) $arg['name'];
824
+ if (isset($arg['value']) === true) {
825
+ $argString .= '='.(string) $arg['value'];
826
+ }
827
+ } else {
828
+ $argString = '-'.(string) $arg['value'];
829
+ }
830
+
831
+ $cliArgs[] = $argString;
832
+
833
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
834
+ echo str_repeat("\t", $depth);
835
+ echo "\t=> set command line value $argString".PHP_EOL;
836
+ }
837
+ }//end foreach
838
+
839
+ // Set custom php ini values as CLI args.
840
+ foreach ($ruleset->{'ini'} as $arg) {
841
+ if ($this->_shouldProcessElement($arg) === false) {
842
+ continue;
843
+ }
844
+
845
+ if (isset($arg['name']) === false) {
846
+ continue;
847
+ }
848
+
849
+ $name = (string) $arg['name'];
850
+ $argString = $name;
851
+ if (isset($arg['value']) === true) {
852
+ $value = (string) $arg['value'];
853
+ $argString .= "=$value";
854
+ } else {
855
+ $value = 'true';
856
+ }
857
+
858
+ $cliArgs[] = '-d';
859
+ $cliArgs[] = $argString;
860
+
861
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
862
+ echo str_repeat("\t", $depth);
863
+ echo "\t=> set PHP ini value $name to $value".PHP_EOL;
864
+ }
865
+ }//end foreach
866
+
867
+ if (empty($cliValues['files']) === true && $cliValues['stdin'] === null) {
868
+ // Process hard-coded file paths.
869
+ foreach ($ruleset->{'file'} as $file) {
870
+ $file = (string) $file;
871
+ $cliArgs[] = $file;
872
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
873
+ echo str_repeat("\t", $depth);
874
+ echo "\t=> added \"$file\" to the file list".PHP_EOL;
875
+ }
876
+ }
877
+ }
878
+
879
+ if (empty($cliArgs) === false) {
880
+ // Change the directory so all relative paths are worked
881
+ // out based on the location of the ruleset instead of
882
+ // the location of the user.
883
+ $inPhar = self::isPharFile($rulesetDir);
884
+ if ($inPhar === false) {
885
+ $currentDir = getcwd();
886
+ chdir($rulesetDir);
887
+ }
888
+
889
+ $this->cli->setCommandLineValues($cliArgs);
890
+
891
+ if ($inPhar === false) {
892
+ chdir($currentDir);
893
+ }
894
+ }
895
+
896
+ // Process custom ignore pattern rules.
897
+ foreach ($ruleset->{'exclude-pattern'} as $pattern) {
898
+ if ($this->_shouldProcessElement($pattern) === false) {
899
+ continue;
900
+ }
901
+
902
+ if (isset($pattern['type']) === false) {
903
+ $pattern['type'] = 'absolute';
904
+ }
905
+
906
+ $this->ignorePatterns[(string) $pattern] = (string) $pattern['type'];
907
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
908
+ echo str_repeat("\t", $depth);
909
+ echo "\t=> added global ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL;
910
+ }
911
+ }
912
+
913
+ $includedSniffs = array_unique(array_merge($ownSniffs, $includedSniffs));
914
+ $excludedSniffs = array_unique($excludedSniffs);
915
+
916
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
917
+ $included = count($includedSniffs);
918
+ $excluded = count($excludedSniffs);
919
+ echo str_repeat("\t", $depth);
920
+ echo "=> Ruleset processing complete; included $included sniffs and excluded $excluded".PHP_EOL;
921
+ }
922
+
923
+ // Merge our own sniff list with our externally included
924
+ // sniff list, but filter out any excluded sniffs.
925
+ $files = array();
926
+ foreach ($includedSniffs as $sniff) {
927
+ if (in_array($sniff, $excludedSniffs) === true) {
928
+ continue;
929
+ } else {
930
+ $files[] = self::realpath($sniff);
931
+ }
932
+ }
933
+
934
+ return $files;
935
+
936
+ }//end processRuleset()
937
+
938
+
939
+ /**
940
+ * Expands a directory into a list of sniff files within.
941
+ *
942
+ * @param string $directory The path to a directory.
943
+ * @param int $depth How many nested processing steps we are in. This
944
+ * is only used for debug output.
945
+ *
946
+ * @return array
947
+ */
948
+ private function _expandSniffDirectory($directory, $depth=0)
949
+ {
950
+ $sniffs = array();
951
+
952
+ if (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') === true) {
953
+ $rdi = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
954
+ } else {
955
+ $rdi = new RecursiveDirectoryIterator($directory);
956
+ }
957
+
958
+ $di = new RecursiveIteratorIterator($rdi, 0, RecursiveIteratorIterator::CATCH_GET_CHILD);
959
+
960
+ $dirLen = strlen($directory);
961
+
962
+ foreach ($di as $file) {
963
+ $filename = $file->getFilename();
964
+
965
+ // Skip hidden files.
966
+ if (substr($filename, 0, 1) === '.') {
967
+ continue;
968
+ }
969
+
970
+ // We are only interested in PHP and sniff files.
971
+ $fileParts = explode('.', $filename);
972
+ if (array_pop($fileParts) !== 'php') {
973
+ continue;
974
+ }
975
+
976
+ $basename = basename($filename, '.php');
977
+ if (substr($basename, -5) !== 'Sniff') {
978
+ continue;
979
+ }
980
+
981
+ $path = $file->getPathname();
982
+
983
+ // Skip files in hidden directories within the Sniffs directory of this
984
+ // standard. We use the offset with strpos() to allow hidden directories
985
+ // before, valid example:
986
+ // /home/foo/.composer/vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/...
987
+ if (strpos($path, DIRECTORY_SEPARATOR.'.', $dirLen) !== false) {
988
+ continue;
989
+ }
990
+
991
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
992
+ echo str_repeat("\t", $depth);
993
+ echo "\t\t=> $path".PHP_EOL;
994
+ }
995
+
996
+ $sniffs[] = $path;
997
+ }//end foreach
998
+
999
+ return $sniffs;
1000
+
1001
+ }//end _expandSniffDirectory()
1002
+
1003
+
1004
+ /**
1005
+ * Expands a ruleset reference into a list of sniff files.
1006
+ *
1007
+ * @param string $ref The reference from the ruleset XML file.
1008
+ * @param string $rulesetDir The directory of the ruleset XML file, used to
1009
+ * evaluate relative paths.
1010
+ * @param int $depth How many nested processing steps we are in. This
1011
+ * is only used for debug output.
1012
+ *
1013
+ * @return array
1014
+ * @throws PHP_CodeSniffer_Exception If the reference is invalid.
1015
+ */
1016
+ private function _expandRulesetReference($ref, $rulesetDir, $depth=0)
1017
+ {
1018
+ // Ignore internal sniffs codes as they are used to only
1019
+ // hide and change internal messages.
1020
+ if (substr($ref, 0, 9) === 'Internal.') {
1021
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1022
+ echo str_repeat("\t", $depth);
1023
+ echo "\t\t* ignoring internal sniff code *".PHP_EOL;
1024
+ }
1025
+
1026
+ return array();
1027
+ }
1028
+
1029
+ // As sniffs can't begin with a full stop, assume references in
1030
+ // this format are relative paths and attempt to convert them
1031
+ // to absolute paths. If this fails, let the reference run through
1032
+ // the normal checks and have it fail as normal.
1033
+ if (substr($ref, 0, 1) === '.') {
1034
+ $realpath = self::realpath($rulesetDir.'/'.$ref);
1035
+ if ($realpath !== false) {
1036
+ $ref = $realpath;
1037
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1038
+ echo str_repeat("\t", $depth);
1039
+ echo "\t\t=> $ref".PHP_EOL;
1040
+ }
1041
+ }
1042
+ }
1043
+
1044
+ // As sniffs can't begin with a tilde, assume references in
1045
+ // this format at relative to the user's home directory.
1046
+ if (substr($ref, 0, 2) === '~/') {
1047
+ $realpath = self::realpath($ref);
1048
+ if ($realpath !== false) {
1049
+ $ref = $realpath;
1050
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1051
+ echo str_repeat("\t", $depth);
1052
+ echo "\t\t=> $ref".PHP_EOL;
1053
+ }
1054
+ }
1055
+ }
1056
+
1057
+ if (is_file($ref) === true) {
1058
+ if (substr($ref, -9) === 'Sniff.php') {
1059
+ // A single external sniff.
1060
+ self::$rulesetDirs[] = dirname(dirname(dirname($ref)));
1061
+ return array($ref);
1062
+ }
1063
+ } else {
1064
+ // See if this is a whole standard being referenced.
1065
+ $path = $this->getInstalledStandardPath($ref);
1066
+ if (self::isPharFile($path) === true && strpos($path, 'ruleset.xml') === false) {
1067
+ // If the ruleset exists inside the phar file, use it.
1068
+ if (file_exists($path.DIRECTORY_SEPARATOR.'ruleset.xml') === true) {
1069
+ $path = $path.DIRECTORY_SEPARATOR.'ruleset.xml';
1070
+ } else {
1071
+ $path = null;
1072
+ }
1073
+ }
1074
+
1075
+ if ($path !== null) {
1076
+ $ref = $path;
1077
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1078
+ echo str_repeat("\t", $depth);
1079
+ echo "\t\t=> $ref".PHP_EOL;
1080
+ }
1081
+ } else if (is_dir($ref) === false) {
1082
+ // Work out the sniff path.
1083
+ $sepPos = strpos($ref, DIRECTORY_SEPARATOR);
1084
+ if ($sepPos !== false) {
1085
+ $stdName = substr($ref, 0, $sepPos);
1086
+ $path = substr($ref, $sepPos);
1087
+ } else {
1088
+ $parts = explode('.', $ref);
1089
+ $stdName = $parts[0];
1090
+ if (count($parts) === 1) {
1091
+ // A whole standard?
1092
+ $path = '';
1093
+ } else if (count($parts) === 2) {
1094
+ // A directory of sniffs?
1095
+ $path = DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR.$parts[1];
1096
+ } else {
1097
+ // A single sniff?
1098
+ $path = DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR.$parts[1].DIRECTORY_SEPARATOR.$parts[2].'Sniff.php';
1099
+ }
1100
+ }
1101
+
1102
+ $newRef = false;
1103
+ $stdPath = $this->getInstalledStandardPath($stdName);
1104
+ if ($stdPath !== null && $path !== '') {
1105
+ if (self::isPharFile($stdPath) === true
1106
+ && strpos($stdPath, 'ruleset.xml') === false
1107
+ ) {
1108
+ // Phar files can only return the directory,
1109
+ // since ruleset can be omitted if building one standard.
1110
+ $newRef = self::realpath($stdPath.$path);
1111
+ } else {
1112
+ $newRef = self::realpath(dirname($stdPath).$path);
1113
+ }
1114
+ }
1115
+
1116
+ if ($newRef === false) {
1117
+ // The sniff is not locally installed, so check if it is being
1118
+ // referenced as a remote sniff outside the install. We do this
1119
+ // by looking through all directories where we have found ruleset
1120
+ // files before, looking for ones for this particular standard,
1121
+ // and seeing if it is in there.
1122
+ foreach (self::$rulesetDirs as $dir) {
1123
+ if (strtolower(basename($dir)) !== strtolower($stdName)) {
1124
+ continue;
1125
+ }
1126
+
1127
+ $newRef = self::realpath($dir.$path);
1128
+
1129
+ if ($newRef !== false) {
1130
+ $ref = $newRef;
1131
+ }
1132
+ }
1133
+ } else {
1134
+ $ref = $newRef;
1135
+ }
1136
+
1137
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1138
+ echo str_repeat("\t", $depth);
1139
+ echo "\t\t=> $ref".PHP_EOL;
1140
+ }
1141
+ }//end if
1142
+ }//end if
1143
+
1144
+ if (is_dir($ref) === true) {
1145
+ if (is_file($ref.DIRECTORY_SEPARATOR.'ruleset.xml') === true) {
1146
+ // We are referencing an external coding standard.
1147
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1148
+ echo str_repeat("\t", $depth);
1149
+ echo "\t\t* rule is referencing a standard using directory name; processing *".PHP_EOL;
1150
+ }
1151
+
1152
+ return $this->processRuleset($ref.DIRECTORY_SEPARATOR.'ruleset.xml', ($depth + 2));
1153
+ } else {
1154
+ // We are referencing a whole directory of sniffs.
1155
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1156
+ echo str_repeat("\t", $depth);
1157
+ echo "\t\t* rule is referencing a directory of sniffs *".PHP_EOL;
1158
+ echo str_repeat("\t", $depth);
1159
+ echo "\t\tAdding sniff files from directory".PHP_EOL;
1160
+ }
1161
+
1162
+ return $this->_expandSniffDirectory($ref, ($depth + 1));
1163
+ }
1164
+ } else {
1165
+ if (is_file($ref) === false) {
1166
+ $error = "Referenced sniff \"$ref\" does not exist";
1167
+ throw new PHP_CodeSniffer_Exception($error);
1168
+ }
1169
+
1170
+ if (substr($ref, -9) === 'Sniff.php') {
1171
+ // A single sniff.
1172
+ return array($ref);
1173
+ } else {
1174
+ // Assume an external ruleset.xml file.
1175
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1176
+ echo str_repeat("\t", $depth);
1177
+ echo "\t\t* rule is referencing a standard using ruleset path; processing *".PHP_EOL;
1178
+ }
1179
+
1180
+ return $this->processRuleset($ref, ($depth + 2));
1181
+ }
1182
+ }//end if
1183
+
1184
+ }//end _expandRulesetReference()
1185
+
1186
+
1187
+ /**
1188
+ * Processes a rule from a ruleset XML file, overriding built-in defaults.
1189
+ *
1190
+ * @param SimpleXMLElement $rule The rule object from a ruleset XML file.
1191
+ * @param int $depth How many nested processing steps we are in.
1192
+ * This is only used for debug output.
1193
+ *
1194
+ * @return void
1195
+ */
1196
+ private function _processRule($rule, $depth=0)
1197
+ {
1198
+ $code = (string) $rule['ref'];
1199
+
1200
+ // Custom severity.
1201
+ if (isset($rule->severity) === true
1202
+ && $this->_shouldProcessElement($rule->severity) === true
1203
+ ) {
1204
+ if (isset($this->ruleset[$code]) === false) {
1205
+ $this->ruleset[$code] = array();
1206
+ }
1207
+
1208
+ $this->ruleset[$code]['severity'] = (int) $rule->severity;
1209
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1210
+ echo str_repeat("\t", $depth);
1211
+ echo "\t\t=> severity set to ".(int) $rule->severity.PHP_EOL;
1212
+ }
1213
+ }
1214
+
1215
+ // Custom message type.
1216
+ if (isset($rule->type) === true
1217
+ && $this->_shouldProcessElement($rule->type) === true
1218
+ ) {
1219
+ if (isset($this->ruleset[$code]) === false) {
1220
+ $this->ruleset[$code] = array();
1221
+ }
1222
+
1223
+ $this->ruleset[$code]['type'] = (string) $rule->type;
1224
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1225
+ echo str_repeat("\t", $depth);
1226
+ echo "\t\t=> message type set to ".(string) $rule->type.PHP_EOL;
1227
+ }
1228
+ }
1229
+
1230
+ // Custom message.
1231
+ if (isset($rule->message) === true
1232
+ && $this->_shouldProcessElement($rule->message) === true
1233
+ ) {
1234
+ if (isset($this->ruleset[$code]) === false) {
1235
+ $this->ruleset[$code] = array();
1236
+ }
1237
+
1238
+ $this->ruleset[$code]['message'] = (string) $rule->message;
1239
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1240
+ echo str_repeat("\t", $depth);
1241
+ echo "\t\t=> message set to ".(string) $rule->message.PHP_EOL;
1242
+ }
1243
+ }
1244
+
1245
+ // Custom properties.
1246
+ if (isset($rule->properties) === true
1247
+ && $this->_shouldProcessElement($rule->properties) === true
1248
+ ) {
1249
+ foreach ($rule->properties->property as $prop) {
1250
+ if ($this->_shouldProcessElement($prop) === false) {
1251
+ continue;
1252
+ }
1253
+
1254
+ if (isset($this->ruleset[$code]) === false) {
1255
+ $this->ruleset[$code] = array(
1256
+ 'properties' => array(),
1257
+ );
1258
+ } else if (isset($this->ruleset[$code]['properties']) === false) {
1259
+ $this->ruleset[$code]['properties'] = array();
1260
+ }
1261
+
1262
+ $name = (string) $prop['name'];
1263
+ if (isset($prop['type']) === true
1264
+ && (string) $prop['type'] === 'array'
1265
+ ) {
1266
+ $value = (string) $prop['value'];
1267
+ $values = array();
1268
+ foreach (explode(',', $value) as $val) {
1269
+ $v = '';
1270
+
1271
+ list($k,$v) = explode('=>', $val.'=>');
1272
+ if ($v !== '') {
1273
+ $values[$k] = $v;
1274
+ } else {
1275
+ $values[] = $k;
1276
+ }
1277
+ }
1278
+
1279
+ $this->ruleset[$code]['properties'][$name] = $values;
1280
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1281
+ echo str_repeat("\t", $depth);
1282
+ echo "\t\t=> array property \"$name\" set to \"$value\"".PHP_EOL;
1283
+ }
1284
+ } else {
1285
+ $this->ruleset[$code]['properties'][$name] = (string) $prop['value'];
1286
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1287
+ echo str_repeat("\t", $depth);
1288
+ echo "\t\t=> property \"$name\" set to \"".(string) $prop['value'].'"'.PHP_EOL;
1289
+ }
1290
+ }//end if
1291
+ }//end foreach
1292
+ }//end if
1293
+
1294
+ // Ignore patterns.
1295
+ foreach ($rule->{'exclude-pattern'} as $pattern) {
1296
+ if ($this->_shouldProcessElement($pattern) === false) {
1297
+ continue;
1298
+ }
1299
+
1300
+ if (isset($this->ignorePatterns[$code]) === false) {
1301
+ $this->ignorePatterns[$code] = array();
1302
+ }
1303
+
1304
+ if (isset($pattern['type']) === false) {
1305
+ $pattern['type'] = 'absolute';
1306
+ }
1307
+
1308
+ $this->ignorePatterns[$code][(string) $pattern] = (string) $pattern['type'];
1309
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1310
+ echo str_repeat("\t", $depth);
1311
+ echo "\t\t=> added sniff-specific ".(string) $pattern['type'].' ignore pattern: '.(string) $pattern.PHP_EOL;
1312
+ }
1313
+ }
1314
+
1315
+ }//end _processRule()
1316
+
1317
+
1318
+ /**
1319
+ * Determine if an element should be processed or ignored.
1320
+ *
1321
+ * @param SimpleXMLElement $element An object from a ruleset XML file.
1322
+ * @param int $depth How many nested processing steps we are in.
1323
+ * This is only used for debug output.
1324
+ *
1325
+ * @return bool
1326
+ */
1327
+ private function _shouldProcessElement($element, $depth=0)
1328
+ {
1329
+ if (isset($element['phpcbf-only']) === false
1330
+ && isset($element['phpcs-only']) === false
1331
+ ) {
1332
+ // No exceptions are being made.
1333
+ return true;
1334
+ }
1335
+
1336
+ if (PHP_CODESNIFFER_CBF === true
1337
+ && isset($element['phpcbf-only']) === true
1338
+ && (string) $element['phpcbf-only'] === 'true'
1339
+ ) {
1340
+ return true;
1341
+ }
1342
+
1343
+ if (PHP_CODESNIFFER_CBF === false
1344
+ && isset($element['phpcs-only']) === true
1345
+ && (string) $element['phpcs-only'] === 'true'
1346
+ ) {
1347
+ return true;
1348
+ }
1349
+
1350
+ return false;
1351
+
1352
+ }//end _shouldProcessElement()
1353
+
1354
+
1355
+ /**
1356
+ * Loads and stores sniffs objects used for sniffing files.
1357
+ *
1358
+ * @param array $files Paths to the sniff files to register.
1359
+ * @param array $restrictions The sniff class names to restrict the allowed
1360
+ * listeners to.
1361
+ * @param array $exclusions The sniff class names to exclude from the
1362
+ * listeners list.
1363
+ *
1364
+ * @return void
1365
+ * @throws PHP_CodeSniffer_Exception If a sniff file path is invalid.
1366
+ */
1367
+ public function registerSniffs($files, $restrictions, $exclusions)
1368
+ {
1369
+ $listeners = array();
1370
+
1371
+ foreach ($files as $file) {
1372
+ // Work out where the position of /StandardName/Sniffs/... is
1373
+ // so we can determine what the class will be called.
1374
+ $sniffPos = strrpos($file, DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR);
1375
+ if ($sniffPos === false) {
1376
+ continue;
1377
+ }
1378
+
1379
+ $slashPos = strrpos(substr($file, 0, $sniffPos), DIRECTORY_SEPARATOR);
1380
+ if ($slashPos === false) {
1381
+ continue;
1382
+ }
1383
+
1384
+ $className = substr($file, ($slashPos + 1));
1385
+
1386
+ if (substr_count($className, DIRECTORY_SEPARATOR) !== 3) {
1387
+ throw new PHP_CodeSniffer_Exception("Sniff file $className is not valid; sniff files must be located in a .../StandardName/Sniffs/CategoryName/ directory");
1388
+ }
1389
+
1390
+ $className = substr($className, 0, -4);
1391
+ $className = str_replace(DIRECTORY_SEPARATOR, '_', $className);
1392
+
1393
+ // If they have specified a list of sniffs to restrict to, check
1394
+ // to see if this sniff is allowed.
1395
+ if (empty($restrictions) === false
1396
+ && in_array(strtolower($className), $restrictions) === false
1397
+ ) {
1398
+ continue;
1399
+ }
1400
+
1401
+ // If they have specified a list of sniffs to exclude, check
1402
+ // to see if this sniff is allowed.
1403
+ if (empty($exclusions) === false
1404
+ && in_array(strtolower($className), $exclusions) === true
1405
+ ) {
1406
+ continue;
1407
+ }
1408
+
1409
+ include_once $file;
1410
+
1411
+ // Support the use of PHP namespaces. If the class name we included
1412
+ // contains namespace separators instead of underscores, use this as the
1413
+ // class name from now on.
1414
+ $classNameNS = str_replace('_', '\\', $className);
1415
+ if (class_exists($classNameNS, false) === true) {
1416
+ $className = $classNameNS;
1417
+ }
1418
+
1419
+ // Skip abstract classes.
1420
+ $reflection = new ReflectionClass($className);
1421
+ if ($reflection->isAbstract() === true) {
1422
+ continue;
1423
+ }
1424
+
1425
+ $listeners[$className] = $className;
1426
+
1427
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
1428
+ echo "Registered $className".PHP_EOL;
1429
+ }
1430
+ }//end foreach
1431
+
1432
+ $this->sniffs = $listeners;
1433
+
1434
+ }//end registerSniffs()
1435
+
1436
+
1437
+ /**
1438
+ * Populates the array of PHP_CodeSniffer_Sniff's for this file.
1439
+ *
1440
+ * @return void
1441
+ * @throws PHP_CodeSniffer_Exception If sniff registration fails.
1442
+ */
1443
+ public function populateTokenListeners()
1444
+ {
1445
+ // Construct a list of listeners indexed by token being listened for.
1446
+ $this->_tokenListeners = array();
1447
+
1448
+ foreach ($this->sniffs as $listenerClass) {
1449
+ // Work out the internal code for this sniff. Detect usage of namespace
1450
+ // separators instead of underscores to support PHP namespaces.
1451
+ if (strstr($listenerClass, '\\') === false) {
1452
+ $parts = explode('_', $listenerClass);
1453
+ } else {
1454
+ $parts = explode('\\', $listenerClass);
1455
+ }
1456
+
1457
+ $code = $parts[0].'.'.$parts[2].'.'.$parts[3];
1458
+ $code = substr($code, 0, -5);
1459
+
1460
+ $this->listeners[$listenerClass] = new $listenerClass();
1461
+ $this->sniffCodes[$code] = $listenerClass;
1462
+
1463
+ // Set custom properties.
1464
+ if (isset($this->ruleset[$code]['properties']) === true) {
1465
+ foreach ($this->ruleset[$code]['properties'] as $name => $value) {
1466
+ $this->setSniffProperty($listenerClass, $name, $value);
1467
+ }
1468
+ }
1469
+
1470
+ $tokenizers = array();
1471
+ $vars = get_class_vars($listenerClass);
1472
+ if (isset($vars['supportedTokenizers']) === true) {
1473
+ foreach ($vars['supportedTokenizers'] as $tokenizer) {
1474
+ $tokenizers[$tokenizer] = $tokenizer;
1475
+ }
1476
+ } else {
1477
+ $tokenizers = array('PHP' => 'PHP');
1478
+ }
1479
+
1480
+ $tokens = $this->listeners[$listenerClass]->register();
1481
+ if (is_array($tokens) === false) {
1482
+ $msg = "Sniff $listenerClass register() method must return an array";
1483
+ throw new PHP_CodeSniffer_Exception($msg);
1484
+ }
1485
+
1486
+ $parts = explode('_', str_replace('\\', '_', $listenerClass));
1487
+ $listenerSource = $parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5);
1488
+ $ignorePatterns = array();
1489
+ $patterns = $this->getIgnorePatterns($listenerSource);
1490
+ foreach ($patterns as $pattern => $type) {
1491
+ // While there is support for a type of each pattern
1492
+ // (absolute or relative) we don't actually support it here.
1493
+ $replacements = array(
1494
+ '\\,' => ',',
1495
+ '*' => '.*',
1496
+ );
1497
+
1498
+ $ignorePatterns[] = strtr($pattern, $replacements);
1499
+ }
1500
+
1501
+ foreach ($tokens as $token) {
1502
+ if (isset($this->_tokenListeners[$token]) === false) {
1503
+ $this->_tokenListeners[$token] = array();
1504
+ }
1505
+
1506
+ if (isset($this->_tokenListeners[$token][$listenerClass]) === false) {
1507
+ $this->_tokenListeners[$token][$listenerClass] = array(
1508
+ 'class' => $listenerClass,
1509
+ 'source' => $listenerSource,
1510
+ 'tokenizers' => $tokenizers,
1511
+ 'ignore' => $ignorePatterns,
1512
+ );
1513
+ }
1514
+ }
1515
+ }//end foreach
1516
+
1517
+ }//end populateTokenListeners()
1518
+
1519
+
1520
+ /**
1521
+ * Set a single property for a sniff.
1522
+ *
1523
+ * @param string $listenerClass The class name of the sniff.
1524
+ * @param string $name The name of the property to change.
1525
+ * @param string $value The new value of the property.
1526
+ *
1527
+ * @return void
1528
+ */
1529
+ public function setSniffProperty($listenerClass, $name, $value)
1530
+ {
1531
+ // Setting a property for a sniff we are not using.
1532
+ if (isset($this->listeners[$listenerClass]) === false) {
1533
+ return;
1534
+ }
1535
+
1536
+ $name = trim($name);
1537
+ if (is_string($value) === true) {
1538
+ $value = trim($value);
1539
+ }
1540
+
1541
+ // Special case for booleans.
1542
+ if ($value === 'true') {
1543
+ $value = true;
1544
+ } else if ($value === 'false') {
1545
+ $value = false;
1546
+ }
1547
+
1548
+ $this->listeners[$listenerClass]->$name = $value;
1549
+
1550
+ }//end setSniffProperty()
1551
+
1552
+
1553
+ /**
1554
+ * Get a list of files that will be processed.
1555
+ *
1556
+ * If passed directories, this method will find all files within them.
1557
+ * The method will also perform file extension and ignore pattern filtering.
1558
+ *
1559
+ * @param string $paths A list of file or directory paths to process.
1560
+ * @param boolean $local If true, only process 1 level of files in directories
1561
+ *
1562
+ * @return array
1563
+ * @throws Exception If there was an error opening a directory.
1564
+ * @see shouldProcessFile()
1565
+ */
1566
+ public function getFilesToProcess($paths, $local=false)
1567
+ {
1568
+ $files = array();
1569
+
1570
+ foreach ($paths as $path) {
1571
+ if (is_dir($path) === true || self::isPharFile($path) === true) {
1572
+ if (self::isPharFile($path) === true) {
1573
+ $path = 'phar://'.$path;
1574
+ }
1575
+
1576
+ if ($local === true) {
1577
+ $di = new DirectoryIterator($path);
1578
+ } else {
1579
+ $di = new RecursiveIteratorIterator(
1580
+ new RecursiveDirectoryIterator($path),
1581
+ 0,
1582
+ RecursiveIteratorIterator::CATCH_GET_CHILD
1583
+ );
1584
+ }
1585
+
1586
+ foreach ($di as $file) {
1587
+ // Check if the file exists after all symlinks are resolved.
1588
+ $filePath = self::realpath($file->getPathname());
1589
+ if ($filePath === false) {
1590
+ continue;
1591
+ }
1592
+
1593
+ if (is_dir($filePath) === true) {
1594
+ continue;
1595
+ }
1596
+
1597
+ if ($this->shouldProcessFile($file->getPathname(), $path) === false) {
1598
+ continue;
1599
+ }
1600
+
1601
+ $files[] = $file->getPathname();
1602
+ }//end foreach
1603
+ } else {
1604
+ if ($this->shouldIgnoreFile($path, dirname($path)) === true) {
1605
+ continue;
1606
+ }
1607
+
1608
+ $files[] = $path;
1609
+ }//end if
1610
+ }//end foreach
1611
+
1612
+ return $files;
1613
+
1614
+ }//end getFilesToProcess()
1615
+
1616
+
1617
+ /**
1618
+ * Checks filtering rules to see if a file should be checked.
1619
+ *
1620
+ * Checks both file extension filters and path ignore filters.
1621
+ *
1622
+ * @param string $path The path to the file being checked.
1623
+ * @param string $basedir The directory to use for relative path checks.
1624
+ *
1625
+ * @return bool
1626
+ */
1627
+ public function shouldProcessFile($path, $basedir)
1628
+ {
1629
+ // Check that the file's extension is one we are checking.
1630
+ // We are strict about checking the extension and we don't
1631
+ // let files through with no extension or that start with a dot.
1632
+ $fileName = basename($path);
1633
+ $fileParts = explode('.', $fileName);
1634
+ if ($fileParts[0] === $fileName || $fileParts[0] === '') {
1635
+ return false;
1636
+ }
1637
+
1638
+ // Checking multi-part file extensions, so need to create a
1639
+ // complete extension list and make sure one is allowed.
1640
+ $extensions = array();
1641
+ array_shift($fileParts);
1642
+ foreach ($fileParts as $part) {
1643
+ $extensions[implode('.', $fileParts)] = 1;
1644
+ array_shift($fileParts);
1645
+ }
1646
+
1647
+ $matches = array_intersect_key($extensions, $this->allowedFileExtensions);
1648
+ if (empty($matches) === true) {
1649
+ return false;
1650
+ }
1651
+
1652
+ // If the file's path matches one of our ignore patterns, skip it.
1653
+ if ($this->shouldIgnoreFile($path, $basedir) === true) {
1654
+ return false;
1655
+ }
1656
+
1657
+ return true;
1658
+
1659
+ }//end shouldProcessFile()
1660
+
1661
+
1662
+ /**
1663
+ * Checks filtering rules to see if a file should be ignored.
1664
+ *
1665
+ * @param string $path The path to the file being checked.
1666
+ * @param string $basedir The directory to use for relative path checks.
1667
+ *
1668
+ * @return bool
1669
+ */
1670
+ public function shouldIgnoreFile($path, $basedir)
1671
+ {
1672
+ $relativePath = $path;
1673
+ if (strpos($path, $basedir) === 0) {
1674
+ // The +1 cuts off the directory separator as well.
1675
+ $relativePath = substr($path, (strlen($basedir) + 1));
1676
+ }
1677
+
1678
+ foreach ($this->ignorePatterns as $pattern => $type) {
1679
+ if (is_array($type) === true) {
1680
+ // A sniff specific ignore pattern.
1681
+ continue;
1682
+ }
1683
+
1684
+ // Maintains backwards compatibility in case the ignore pattern does
1685
+ // not have a relative/absolute value.
1686
+ if (is_int($pattern) === true) {
1687
+ $pattern = $type;
1688
+ $type = 'absolute';
1689
+ }
1690
+
1691
+ $replacements = array(
1692
+ '\\,' => ',',
1693
+ '*' => '.*',
1694
+ );
1695
+
1696
+ // We assume a / directory separator, as do the exclude rules
1697
+ // most developers write, so we need a special case for any system
1698
+ // that is different.
1699
+ if (DIRECTORY_SEPARATOR === '\\') {
1700
+ $replacements['/'] = '\\\\';
1701
+ }
1702
+
1703
+ $pattern = strtr($pattern, $replacements);
1704
+
1705
+ if ($type === 'relative') {
1706
+ $testPath = $relativePath;
1707
+ } else {
1708
+ $testPath = $path;
1709
+ }
1710
+
1711
+ $pattern = '`'.$pattern.'`i';
1712
+ if (preg_match($pattern, $testPath) === 1) {
1713
+ return true;
1714
+ }
1715
+ }//end foreach
1716
+
1717
+ return false;
1718
+
1719
+ }//end shouldIgnoreFile()
1720
+
1721
+
1722
+ /**
1723
+ * Run the code sniffs over a single given file.
1724
+ *
1725
+ * Processes the file and runs the PHP_CodeSniffer sniffs to verify that it
1726
+ * conforms with the standard. Returns the processed file object, or NULL
1727
+ * if no file was processed due to error.
1728
+ *
1729
+ * @param string $file The file to process.
1730
+ * @param string $contents The contents to parse. If NULL, the content
1731
+ * is taken from the file system.
1732
+ *
1733
+ * @return PHP_CodeSniffer_File
1734
+ * @throws PHP_CodeSniffer_Exception If the file could not be processed.
1735
+ * @see _processFile()
1736
+ */
1737
+ public function processFile($file, $contents=null)
1738
+ {
1739
+ if ($contents === null && file_exists($file) === false) {
1740
+ throw new PHP_CodeSniffer_Exception("Source file $file does not exist");
1741
+ }
1742
+
1743
+ $filePath = self::realpath($file);
1744
+ if ($filePath === false) {
1745
+ $filePath = $file;
1746
+ }
1747
+
1748
+ // Before we go and spend time tokenizing this file, just check
1749
+ // to see if there is a tag up top to indicate that the whole
1750
+ // file should be ignored. It must be on one of the first two lines.
1751
+ $firstContent = $contents;
1752
+ if ($contents === null && is_readable($filePath) === true) {
1753
+ $handle = fopen($filePath, 'r');
1754
+ stream_set_blocking($handle, true);
1755
+ if ($handle !== false) {
1756
+ $firstContent = fgets($handle);
1757
+ $firstContent .= fgets($handle);
1758
+ fclose($handle);
1759
+
1760
+ if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false) {
1761
+ // We are ignoring the whole file.
1762
+ if (PHP_CODESNIFFER_VERBOSITY > 0) {
1763
+ echo 'Ignoring '.basename($filePath).PHP_EOL;
1764
+ }
1765
+
1766
+ return null;
1767
+ }
1768
+ }
1769
+ }//end if
1770
+
1771
+ try {
1772
+ $phpcsFile = $this->_processFile($file, $contents);
1773
+ } catch (Exception $e) {
1774
+ $trace = $e->getTrace();
1775
+
1776
+ $filename = $trace[0]['args'][0];
1777
+ if (is_object($filename) === true
1778
+ && get_class($filename) === 'PHP_CodeSniffer_File'
1779
+ ) {
1780
+ $filename = $filename->getFilename();
1781
+ } else if (is_numeric($filename) === true) {
1782
+ // See if we can find the PHP_CodeSniffer_File object.
1783
+ foreach ($trace as $data) {
1784
+ if (isset($data['args'][0]) === true
1785
+ && ($data['args'][0] instanceof PHP_CodeSniffer_File) === true
1786
+ ) {
1787
+ $filename = $data['args'][0]->getFilename();
1788
+ }
1789
+ }
1790
+ } else if (is_string($filename) === false) {
1791
+ $filename = (string) $filename;
1792
+ }
1793
+
1794
+ $errorMessage = '"'.$e->getMessage().'" at '.$e->getFile().':'.$e->getLine();
1795
+ $error = "An error occurred during processing; checking has been aborted. The error message was: $errorMessage";
1796
+
1797
+ $phpcsFile = new PHP_CodeSniffer_File(
1798
+ $filename,
1799
+ $this->_tokenListeners,
1800
+ $this->ruleset,
1801
+ $this
1802
+ );
1803
+
1804
+ $phpcsFile->addError($error, null, 'Internal.Exception');
1805
+ }//end try
1806
+
1807
+ $cliValues = $this->cli->getCommandLineValues();
1808
+
1809
+ if (PHP_CODESNIFFER_INTERACTIVE === false) {
1810
+ // Cache the report data for this file so we can unset it to save memory.
1811
+ $this->reporting->cacheFileReport($phpcsFile, $cliValues);
1812
+ $phpcsFile->cleanUp();
1813
+ return $phpcsFile;
1814
+ }
1815
+
1816
+ /*
1817
+ Running interactively.
1818
+ Print the error report for the current file and then wait for user input.
1819
+ */
1820
+
1821
+ // Get current violations and then clear the list to make sure
1822
+ // we only print violations for a single file each time.
1823
+ $numErrors = null;
1824
+ while ($numErrors !== 0) {
1825
+ $numErrors = ($phpcsFile->getErrorCount() + $phpcsFile->getWarningCount());
1826
+ if ($numErrors === 0) {
1827
+ continue;
1828
+ }
1829
+
1830
+ $reportClass = $this->reporting->factory('full');
1831
+ $reportData = $this->reporting->prepareFileReport($phpcsFile);
1832
+ $reportClass->generateFileReport($reportData, $phpcsFile, $cliValues['showSources'], $cliValues['reportWidth']);
1833
+
1834
+ echo '<ENTER> to recheck, [s] to skip or [q] to quit : ';
1835
+ $input = fgets(STDIN);
1836
+ $input = trim($input);
1837
+
1838
+ switch ($input) {
1839
+ case 's':
1840
+ break(2);
1841
+ case 'q':
1842
+ exit(0);
1843
+ break;
1844
+ default:
1845
+ // Repopulate the sniffs because some of them save their state
1846
+ // and only clear it when the file changes, but we are rechecking
1847
+ // the same file.
1848
+ $this->populateTokenListeners();
1849
+ $phpcsFile = $this->_processFile($file, $contents);
1850
+ break;
1851
+ }
1852
+ }//end while
1853
+
1854
+ return $phpcsFile;
1855
+
1856
+ }//end processFile()
1857
+
1858
+
1859
+ /**
1860
+ * Process the sniffs for a single file.
1861
+ *
1862
+ * Does raw processing only. No interactive support or error checking.
1863
+ *
1864
+ * @param string $file The file to process.
1865
+ * @param string $contents The contents to parse. If NULL, the content
1866
+ * is taken from the file system.
1867
+ *
1868
+ * @return PHP_CodeSniffer_File
1869
+ * @see processFile()
1870
+ */
1871
+ private function _processFile($file, $contents)
1872
+ {
1873
+ $stdin = false;
1874
+ $cliValues = $this->cli->getCommandLineValues();
1875
+ if (empty($cliValues['files']) === true) {
1876
+ $stdin = true;
1877
+ }
1878
+
1879
+ if (PHP_CODESNIFFER_VERBOSITY > 0 || (PHP_CODESNIFFER_CBF === true && $stdin === false)) {
1880
+ $startTime = microtime(true);
1881
+ echo 'Processing '.basename($file).' ';
1882
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
1883
+ echo PHP_EOL;
1884
+ }
1885
+ }
1886
+
1887
+ $phpcsFile = new PHP_CodeSniffer_File(
1888
+ $file,
1889
+ $this->_tokenListeners,
1890
+ $this->ruleset,
1891
+ $this
1892
+ );
1893
+
1894
+ $phpcsFile->start($contents);
1895
+
1896
+ if (PHP_CODESNIFFER_VERBOSITY > 0 || (PHP_CODESNIFFER_CBF === true && $stdin === false)) {
1897
+ $timeTaken = ((microtime(true) - $startTime) * 1000);
1898
+ if ($timeTaken < 1000) {
1899
+ $timeTaken = round($timeTaken);
1900
+ echo "DONE in {$timeTaken}ms";
1901
+ } else {
1902
+ $timeTaken = round(($timeTaken / 1000), 2);
1903
+ echo "DONE in $timeTaken secs";
1904
+ }
1905
+
1906
+ if (PHP_CODESNIFFER_CBF === true) {
1907
+ $errors = $phpcsFile->getFixableCount();
1908
+ echo " ($errors fixable violations)".PHP_EOL;
1909
+ } else {
1910
+ $errors = $phpcsFile->getErrorCount();
1911
+ $warnings = $phpcsFile->getWarningCount();
1912
+ echo " ($errors errors, $warnings warnings)".PHP_EOL;
1913
+ }
1914
+ }
1915
+
1916
+ return $phpcsFile;
1917
+
1918
+ }//end _processFile()
1919
+
1920
+
1921
+ /**
1922
+ * Generates documentation for a coding standard.
1923
+ *
1924
+ * @param string $standard The standard to generate docs for
1925
+ * @param array $sniffs A list of sniffs to limit the docs to.
1926
+ * @param string $generator The name of the generator class to use.
1927
+ *
1928
+ * @return void
1929
+ */
1930
+ public function generateDocs($standard, array $sniffs=array(), $generator='Text')
1931
+ {
1932
+ if (class_exists('PHP_CodeSniffer_DocGenerators_'.$generator, true) === false) {
1933
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_'.$generator.' not found');
1934
+ }
1935
+
1936
+ $class = "PHP_CodeSniffer_DocGenerators_$generator";
1937
+ $generator = new $class($standard, $sniffs);
1938
+
1939
+ $generator->generate();
1940
+
1941
+ }//end generateDocs()
1942
+
1943
+
1944
+ /**
1945
+ * Gets the array of PHP_CodeSniffer_Sniff's.
1946
+ *
1947
+ * @return PHP_CodeSniffer_Sniff[]
1948
+ */
1949
+ public function getSniffs()
1950
+ {
1951
+ return $this->listeners;
1952
+
1953
+ }//end getSniffs()
1954
+
1955
+
1956
+ /**
1957
+ * Gets the array of PHP_CodeSniffer_Sniff's indexed by token type.
1958
+ *
1959
+ * @return array
1960
+ */
1961
+ public function getTokenSniffs()
1962
+ {
1963
+ return $this->_tokenListeners;
1964
+
1965
+ }//end getTokenSniffs()
1966
+
1967
+
1968
+ /**
1969
+ * Returns true if the specified string is in the camel caps format.
1970
+ *
1971
+ * @param string $string The string the verify.
1972
+ * @param boolean $classFormat If true, check to see if the string is in the
1973
+ * class format. Class format strings must start
1974
+ * with a capital letter and contain no
1975
+ * underscores.
1976
+ * @param boolean $public If true, the first character in the string
1977
+ * must be an a-z character. If false, the
1978
+ * character must be an underscore. This
1979
+ * argument is only applicable if $classFormat
1980
+ * is false.
1981
+ * @param boolean $strict If true, the string must not have two capital
1982
+ * letters next to each other. If false, a
1983
+ * relaxed camel caps policy is used to allow
1984
+ * for acronyms.
1985
+ *
1986
+ * @return boolean
1987
+ */
1988
+ public static function isCamelCaps(
1989
+ $string,
1990
+ $classFormat=false,
1991
+ $public=true,
1992
+ $strict=true
1993
+ ) {
1994
+ // Check the first character first.
1995
+ if ($classFormat === false) {
1996
+ $legalFirstChar = '';
1997
+ if ($public === false) {
1998
+ $legalFirstChar = '[_]';
1999
+ }
2000
+
2001
+ if ($strict === false) {
2002
+ // Can either start with a lowercase letter, or multiple uppercase
2003
+ // in a row, representing an acronym.
2004
+ $legalFirstChar .= '([A-Z]{2,}|[a-z])';
2005
+ } else {
2006
+ $legalFirstChar .= '[a-z]';
2007
+ }
2008
+ } else {
2009
+ $legalFirstChar = '[A-Z]';
2010
+ }
2011
+
2012
+ if (preg_match("/^$legalFirstChar/", $string) === 0) {
2013
+ return false;
2014
+ }
2015
+
2016
+ // Check that the name only contains legal characters.
2017
+ $legalChars = 'a-zA-Z0-9';
2018
+ if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) {
2019
+ return false;
2020
+ }
2021
+
2022
+ if ($strict === true) {
2023
+ // Check that there are not two capital letters next to each other.
2024
+ $length = strlen($string);
2025
+ $lastCharWasCaps = $classFormat;
2026
+
2027
+ for ($i = 1; $i < $length; $i++) {
2028
+ $ascii = ord($string{$i});
2029
+ if ($ascii >= 48 && $ascii <= 57) {
2030
+ // The character is a number, so it cant be a capital.
2031
+ $isCaps = false;
2032
+ } else {
2033
+ if (strtoupper($string{$i}) === $string{$i}) {
2034
+ $isCaps = true;
2035
+ } else {
2036
+ $isCaps = false;
2037
+ }
2038
+ }
2039
+
2040
+ if ($isCaps === true && $lastCharWasCaps === true) {
2041
+ return false;
2042
+ }
2043
+
2044
+ $lastCharWasCaps = $isCaps;
2045
+ }
2046
+ }//end if
2047
+
2048
+ return true;
2049
+
2050
+ }//end isCamelCaps()
2051
+
2052
+
2053
+ /**
2054
+ * Returns true if the specified string is in the underscore caps format.
2055
+ *
2056
+ * @param string $string The string to verify.
2057
+ *
2058
+ * @return boolean
2059
+ */
2060
+ public static function isUnderscoreName($string)
2061
+ {
2062
+ // If there are space in the name, it can't be valid.
2063
+ if (strpos($string, ' ') !== false) {
2064
+ return false;
2065
+ }
2066
+
2067
+ $validName = true;
2068
+ $nameBits = explode('_', $string);
2069
+
2070
+ if (preg_match('|^[A-Z]|', $string) === 0) {
2071
+ // Name does not begin with a capital letter.
2072
+ $validName = false;
2073
+ } else {
2074
+ foreach ($nameBits as $bit) {
2075
+ if ($bit === '') {
2076
+ continue;
2077
+ }
2078
+
2079
+ if ($bit{0} !== strtoupper($bit{0})) {
2080
+ $validName = false;
2081
+ break;
2082
+ }
2083
+ }
2084
+ }
2085
+
2086
+ return $validName;
2087
+
2088
+ }//end isUnderscoreName()
2089
+
2090
+
2091
+ /**
2092
+ * Returns a valid variable type for param/var tag.
2093
+ *
2094
+ * If type is not one of the standard type, it must be a custom type.
2095
+ * Returns the correct type name suggestion if type name is invalid.
2096
+ *
2097
+ * @param string $varType The variable type to process.
2098
+ *
2099
+ * @return string
2100
+ */
2101
+ public static function suggestType($varType)
2102
+ {
2103
+ if ($varType === '') {
2104
+ return '';
2105
+ }
2106
+
2107
+ if (in_array($varType, self::$allowedTypes) === true) {
2108
+ return $varType;
2109
+ } else {
2110
+ $lowerVarType = strtolower($varType);
2111
+ switch ($lowerVarType) {
2112
+ case 'bool':
2113
+ case 'boolean':
2114
+ return 'boolean';
2115
+ case 'double':
2116
+ case 'real':
2117
+ case 'float':
2118
+ return 'float';
2119
+ case 'int':
2120
+ case 'integer':
2121
+ return 'integer';
2122
+ case 'array()':
2123
+ case 'array':
2124
+ return 'array';
2125
+ }//end switch
2126
+
2127
+ if (strpos($lowerVarType, 'array(') !== false) {
2128
+ // Valid array declaration:
2129
+ // array, array(type), array(type1 => type2).
2130
+ $matches = array();
2131
+ $pattern = '/^array\(\s*([^\s^=^>]*)(\s*=>\s*(.*))?\s*\)/i';
2132
+ if (preg_match($pattern, $varType, $matches) !== 0) {
2133
+ $type1 = '';
2134
+ if (isset($matches[1]) === true) {
2135
+ $type1 = $matches[1];
2136
+ }
2137
+
2138
+ $type2 = '';
2139
+ if (isset($matches[3]) === true) {
2140
+ $type2 = $matches[3];
2141
+ }
2142
+
2143
+ $type1 = self::suggestType($type1);
2144
+ $type2 = self::suggestType($type2);
2145
+ if ($type2 !== '') {
2146
+ $type2 = ' => '.$type2;
2147
+ }
2148
+
2149
+ return "array($type1$type2)";
2150
+ } else {
2151
+ return 'array';
2152
+ }//end if
2153
+ } else if (in_array($lowerVarType, self::$allowedTypes) === true) {
2154
+ // A valid type, but not lower cased.
2155
+ return $lowerVarType;
2156
+ } else {
2157
+ // Must be a custom type name.
2158
+ return $varType;
2159
+ }//end if
2160
+ }//end if
2161
+
2162
+ }//end suggestType()
2163
+
2164
+
2165
+ /**
2166
+ * Prepares token content for output to screen.
2167
+ *
2168
+ * Replaces invisible characters so they are visible. On non-Windows
2169
+ * OSes it will also colour the invisible characters.
2170
+ *
2171
+ * @param string $content The content to prepare.
2172
+ *
2173
+ * @return string
2174
+ */
2175
+ public static function prepareForOutput($content)
2176
+ {
2177
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
2178
+ $content = str_replace("\r", '\r', $content);
2179
+ $content = str_replace("\n", '\n', $content);
2180
+ $content = str_replace("\t", '\t', $content);
2181
+ } else {
2182
+ $content = str_replace("\r", "\033[30;1m\\r\033[0m", $content);
2183
+ $content = str_replace("\n", "\033[30;1m\\n\033[0m", $content);
2184
+ $content = str_replace("\t", "\033[30;1m\\t\033[0m", $content);
2185
+ $content = str_replace(' ', "\033[30;1m·\033[0m", $content);
2186
+ }
2187
+
2188
+ return $content;
2189
+
2190
+ }//end prepareForOutput()
2191
+
2192
+
2193
+ /**
2194
+ * Get a list paths where standards are installed.
2195
+ *
2196
+ * @return array
2197
+ */
2198
+ public static function getInstalledStandardPaths()
2199
+ {
2200
+ $installedPaths = array(dirname(__FILE__).DIRECTORY_SEPARATOR.'CodeSniffer'.DIRECTORY_SEPARATOR.'Standards');
2201
+ $configPaths = PHP_CodeSniffer::getConfigData('installed_paths');
2202
+ if ($configPaths !== null) {
2203
+ $installedPaths = array_merge($installedPaths, explode(',', $configPaths));
2204
+ }
2205
+
2206
+ $resolvedInstalledPaths = array();
2207
+ foreach ($installedPaths as $installedPath) {
2208
+ if (substr($installedPath, 0, 1) === '.') {
2209
+ $installedPath = dirname(__FILE__).DIRECTORY_SEPARATOR.$installedPath;
2210
+ }
2211
+
2212
+ $resolvedInstalledPaths[] = $installedPath;
2213
+ }
2214
+
2215
+ return $resolvedInstalledPaths;
2216
+
2217
+ }//end getInstalledStandardPaths()
2218
+
2219
+
2220
+ /**
2221
+ * Get a list of all coding standards installed.
2222
+ *
2223
+ * Coding standards are directories located in the
2224
+ * CodeSniffer/Standards directory. Valid coding standards
2225
+ * include a Sniffs subdirectory.
2226
+ *
2227
+ * @param boolean $includeGeneric If true, the special "Generic"
2228
+ * coding standard will be included
2229
+ * if installed.
2230
+ * @param string $standardsDir A specific directory to look for standards
2231
+ * in. If not specified, PHP_CodeSniffer will
2232
+ * look in its default locations.
2233
+ *
2234
+ * @return array
2235
+ * @see isInstalledStandard()
2236
+ */
2237
+ public static function getInstalledStandards(
2238
+ $includeGeneric=false,
2239
+ $standardsDir=''
2240
+ ) {
2241
+ $installedStandards = array();
2242
+
2243
+ if ($standardsDir === '') {
2244
+ $installedPaths = self::getInstalledStandardPaths();
2245
+ } else {
2246
+ $installedPaths = array($standardsDir);
2247
+ }
2248
+
2249
+ foreach ($installedPaths as $standardsDir) {
2250
+ $di = new DirectoryIterator($standardsDir);
2251
+ foreach ($di as $file) {
2252
+ if ($file->isDir() === true && $file->isDot() === false) {
2253
+ $filename = $file->getFilename();
2254
+
2255
+ // Ignore the special "Generic" standard.
2256
+ if ($includeGeneric === false && $filename === 'Generic') {
2257
+ continue;
2258
+ }
2259
+
2260
+ // Valid coding standard dirs include a ruleset.
2261
+ $csFile = $file->getPathname().'/ruleset.xml';
2262
+ if (is_file($csFile) === true) {
2263
+ $installedStandards[] = $filename;
2264
+ }
2265
+ }
2266
+ }
2267
+ }//end foreach
2268
+
2269
+ return $installedStandards;
2270
+
2271
+ }//end getInstalledStandards()
2272
+
2273
+
2274
+ /**
2275
+ * Determine if a standard is installed.
2276
+ *
2277
+ * Coding standards are directories located in the
2278
+ * CodeSniffer/Standards directory. Valid coding standards
2279
+ * include a ruleset.xml file.
2280
+ *
2281
+ * @param string $standard The name of the coding standard.
2282
+ *
2283
+ * @return boolean
2284
+ * @see getInstalledStandards()
2285
+ */
2286
+ public static function isInstalledStandard($standard)
2287
+ {
2288
+ $path = self::getInstalledStandardPath($standard);
2289
+ if ($path !== null && strpos($path, 'ruleset.xml') !== false) {
2290
+ return true;
2291
+ } else {
2292
+ // This could be a custom standard, installed outside our
2293
+ // standards directory.
2294
+ $standard = self::realPath($standard);
2295
+
2296
+ // Might be an actual ruleset file itself.
2297
+ // If it has an XML extension, let's at least try it.
2298
+ if (is_file($standard) === true
2299
+ && (substr(strtolower($standard), -4) === '.xml'
2300
+ || substr(strtolower($standard), -9) === '.xml.dist')
2301
+ ) {
2302
+ return true;
2303
+ }
2304
+
2305
+ // If it is a directory with a ruleset.xml file in it,
2306
+ // it is a standard.
2307
+ $ruleset = rtrim($standard, ' /\\').DIRECTORY_SEPARATOR.'ruleset.xml';
2308
+ if (is_file($ruleset) === true) {
2309
+ return true;
2310
+ }
2311
+ }//end if
2312
+
2313
+ return false;
2314
+
2315
+ }//end isInstalledStandard()
2316
+
2317
+
2318
+ /**
2319
+ * Return the path of an installed coding standard.
2320
+ *
2321
+ * Coding standards are directories located in the
2322
+ * CodeSniffer/Standards directory. Valid coding standards
2323
+ * include a ruleset.xml file.
2324
+ *
2325
+ * @param string $standard The name of the coding standard.
2326
+ *
2327
+ * @return string|null
2328
+ */
2329
+ public static function getInstalledStandardPath($standard)
2330
+ {
2331
+ $installedPaths = self::getInstalledStandardPaths();
2332
+ foreach ($installedPaths as $installedPath) {
2333
+ $standardPath = $installedPath.DIRECTORY_SEPARATOR.$standard;
2334
+ $path = self::realpath($standardPath.DIRECTORY_SEPARATOR.'ruleset.xml');
2335
+ if (is_file($path) === true) {
2336
+ return $path;
2337
+ } else if (self::isPharFile($standardPath) === true) {
2338
+ $path = self::realpath($standardPath);
2339
+ if ($path !== false) {
2340
+ return $path;
2341
+ }
2342
+ }
2343
+ }
2344
+
2345
+ return null;
2346
+
2347
+ }//end getInstalledStandardPath()
2348
+
2349
+
2350
+ /**
2351
+ * Get a single config value.
2352
+ *
2353
+ * Config data is stored in the data dir, in a file called
2354
+ * CodeSniffer.conf. It is a simple PHP array.
2355
+ *
2356
+ * @param string $key The name of the config value.
2357
+ *
2358
+ * @return string|null
2359
+ * @see setConfigData()
2360
+ * @see getAllConfigData()
2361
+ */
2362
+ public static function getConfigData($key)
2363
+ {
2364
+ $phpCodeSnifferConfig = self::getAllConfigData();
2365
+
2366
+ if ($phpCodeSnifferConfig === null) {
2367
+ return null;
2368
+ }
2369
+
2370
+ if (isset($phpCodeSnifferConfig[$key]) === false) {
2371
+ return null;
2372
+ }
2373
+
2374
+ return $phpCodeSnifferConfig[$key];
2375
+
2376
+ }//end getConfigData()
2377
+
2378
+
2379
+ /**
2380
+ * Set a single config value.
2381
+ *
2382
+ * Config data is stored in the data dir, in a file called
2383
+ * CodeSniffer.conf. It is a simple PHP array.
2384
+ *
2385
+ * @param string $key The name of the config value.
2386
+ * @param string|null $value The value to set. If null, the config
2387
+ * entry is deleted, reverting it to the
2388
+ * default value.
2389
+ * @param boolean $temp Set this config data temporarily for this
2390
+ * script run. This will not write the config
2391
+ * data to the config file.
2392
+ *
2393
+ * @return boolean
2394
+ * @see getConfigData()
2395
+ * @throws PHP_CodeSniffer_Exception If the config file can not be written.
2396
+ */
2397
+ public static function setConfigData($key, $value, $temp=false)
2398
+ {
2399
+ if ($temp === false) {
2400
+ $path = '';
2401
+ if (is_callable('Phar::running') === true) {
2402
+ $path = Phar::running(false);
2403
+ }
2404
+
2405
+ if ($path !== '') {
2406
+ $configFile = dirname($path).'/CodeSniffer.conf';
2407
+ } else {
2408
+ $configFile = dirname(__FILE__).'/CodeSniffer.conf';
2409
+ if (is_file($configFile) === false
2410
+ && strpos('@data_dir@', '@data_dir') === false
2411
+ ) {
2412
+ // If data_dir was replaced, this is a PEAR install and we can
2413
+ // use the PEAR data dir to store the conf file.
2414
+ $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf';
2415
+ }
2416
+ }
2417
+
2418
+ if (is_file($configFile) === true
2419
+ && is_writable($configFile) === false
2420
+ ) {
2421
+ $error = 'Config file '.$configFile.' is not writable';
2422
+ throw new PHP_CodeSniffer_Exception($error);
2423
+ }
2424
+ }//end if
2425
+
2426
+ $phpCodeSnifferConfig = self::getAllConfigData();
2427
+
2428
+ if ($value === null) {
2429
+ if (isset($phpCodeSnifferConfig[$key]) === true) {
2430
+ unset($phpCodeSnifferConfig[$key]);
2431
+ }
2432
+ } else {
2433
+ $phpCodeSnifferConfig[$key] = $value;
2434
+ }
2435
+
2436
+ if ($temp === false) {
2437
+ $output = '<'.'?php'."\n".' $phpCodeSnifferConfig = ';
2438
+ $output .= var_export($phpCodeSnifferConfig, true);
2439
+ $output .= "\n?".'>';
2440
+
2441
+ if (file_put_contents($configFile, $output) === false) {
2442
+ return false;
2443
+ }
2444
+ }
2445
+
2446
+ $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig;
2447
+
2448
+ return true;
2449
+
2450
+ }//end setConfigData()
2451
+
2452
+
2453
+ /**
2454
+ * Get all config data in an array.
2455
+ *
2456
+ * @return array<string, string>
2457
+ * @see getConfigData()
2458
+ */
2459
+ public static function getAllConfigData()
2460
+ {
2461
+ if (isset($GLOBALS['PHP_CODESNIFFER_CONFIG_DATA']) === true) {
2462
+ return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'];
2463
+ }
2464
+
2465
+ $path = '';
2466
+ if (is_callable('Phar::running') === true) {
2467
+ $path = Phar::running(false);
2468
+ }
2469
+
2470
+ if ($path !== '') {
2471
+ $configFile = dirname($path).'/CodeSniffer.conf';
2472
+ } else {
2473
+ $configFile = dirname(__FILE__).'/CodeSniffer.conf';
2474
+ if (is_file($configFile) === false) {
2475
+ $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf';
2476
+ }
2477
+ }
2478
+
2479
+ if (is_file($configFile) === false) {
2480
+ $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = array();
2481
+ return array();
2482
+ }
2483
+
2484
+ include $configFile;
2485
+ $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'] = $phpCodeSnifferConfig;
2486
+ return $GLOBALS['PHP_CODESNIFFER_CONFIG_DATA'];
2487
+
2488
+ }//end getAllConfigData()
2489
+
2490
+
2491
+ /**
2492
+ * Return TRUE, if the path is a phar file.
2493
+ *
2494
+ * @param string $path The path to use.
2495
+ *
2496
+ * @return mixed
2497
+ */
2498
+ public static function isPharFile($path)
2499
+ {
2500
+ if (strpos($path, 'phar://') === 0) {
2501
+ return true;
2502
+ }
2503
+
2504
+ return false;
2505
+
2506
+ }//end isPharFile()
2507
+
2508
+
2509
+ /**
2510
+ * CodeSniffer alternative for realpath.
2511
+ *
2512
+ * Allows for phar support.
2513
+ *
2514
+ * @param string $path The path to use.
2515
+ *
2516
+ * @return mixed
2517
+ */
2518
+ public static function realpath($path)
2519
+ {
2520
+ // Support the path replacement of ~ with the user's home directory.
2521
+ if (substr($path, 0, 2) === '~/') {
2522
+ $homeDir = getenv('HOME');
2523
+ if ($homeDir !== false) {
2524
+ $path = $homeDir.substr($path, 1);
2525
+ }
2526
+ }
2527
+
2528
+ // No extra work needed if this is not a phar file.
2529
+ if (self::isPharFile($path) === false) {
2530
+ return realpath($path);
2531
+ }
2532
+
2533
+ // Before trying to break down the file path,
2534
+ // check if it exists first because it will mostly not
2535
+ // change after running the below code.
2536
+ if (file_exists($path) === true) {
2537
+ return $path;
2538
+ }
2539
+
2540
+ $phar = Phar::running(false);
2541
+ $extra = str_replace('phar://'.$phar, '', $path);
2542
+ $path = realpath($phar);
2543
+ if ($path === false) {
2544
+ return false;
2545
+ }
2546
+
2547
+ $path = 'phar://'.$path.$extra;
2548
+ if (file_exists($path) === true) {
2549
+ return $path;
2550
+ }
2551
+
2552
+ return false;
2553
+
2554
+ }//end realpath()
2555
+
2556
+
2557
+ /**
2558
+ * CodeSniffer alternative for chdir().
2559
+ *
2560
+ * Allows for phar support.
2561
+ *
2562
+ * @param string $path The path to use.
2563
+ *
2564
+ * @return void
2565
+ */
2566
+ public static function chdir($path)
2567
+ {
2568
+ if (self::isPharFile($path) === true) {
2569
+ $phar = Phar::running(false);
2570
+ chdir(dirname($phar));
2571
+ } else {
2572
+ chdir($path);
2573
+ }
2574
+
2575
+ }//end chdir()
2576
+
2577
+
2578
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/CLI.php ADDED
@@ -0,0 +1,1444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A class to process command line phpcs scripts.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Greg Sherwood <gsherwood@squiz.net>
10
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
11
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12
+ * @link http://pear.php.net/package/PHP_CodeSniffer
13
+ */
14
+
15
+ error_reporting(E_ALL | E_STRICT);
16
+
17
+ // Make sure version id constant is available.
18
+ if (defined('PHP_VERSION_ID') === false) {
19
+ $version = explode('.', PHP_VERSION);
20
+ define('PHP_VERSION_ID', (int) (($version[0] * 10000) + ($version[1] * 100) + $version[2]));
21
+ unset($version);
22
+ }
23
+
24
+ // Make sure that we autoload all dependencies if running via Composer.
25
+ if (PHP_VERSION_ID >= 50302) {
26
+ if (file_exists($a = dirname(__FILE__).'/../../../autoload.php') === true) {
27
+ include_once $a;
28
+ } else if (file_exists($a = dirname(__FILE__).'/../vendor/autoload.php') === true) {
29
+ include_once $a;
30
+ }
31
+ }
32
+
33
+ if (file_exists($a = dirname(__FILE__).'/../CodeSniffer.php') === true) {
34
+ // Running from a git clone.
35
+ include_once $a;
36
+ } else {
37
+ // PEAR installed.
38
+ include_once 'PHP/CodeSniffer.php';
39
+ }
40
+
41
+ /**
42
+ * A class to process command line phpcs scripts.
43
+ *
44
+ * @category PHP
45
+ * @package PHP_CodeSniffer
46
+ * @author Greg Sherwood <gsherwood@squiz.net>
47
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
48
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
49
+ * @version Release: @package_version@
50
+ * @link http://pear.php.net/package/PHP_CodeSniffer
51
+ */
52
+ class PHP_CodeSniffer_CLI
53
+ {
54
+
55
+ /**
56
+ * An array of all values specified on the command line.
57
+ *
58
+ * @var array
59
+ */
60
+ protected $values = array();
61
+
62
+ /**
63
+ * The minimum severity level errors must have to be displayed.
64
+ *
65
+ * @var bool
66
+ */
67
+ public $errorSeverity = 0;
68
+
69
+ /**
70
+ * The minimum severity level warnings must have to be displayed.
71
+ *
72
+ * @var bool
73
+ */
74
+ public $warningSeverity = 0;
75
+
76
+ /**
77
+ * Whether or not to kill the process when an unknown command line arg is found.
78
+ *
79
+ * If FALSE, arguments that are not command line options or file/directory paths
80
+ * will be ignored and execution will continue.
81
+ *
82
+ * @var bool
83
+ */
84
+ public $dieOnUnknownArg = true;
85
+
86
+ /**
87
+ * An array of the current command line arguments we are processing.
88
+ *
89
+ * @var array
90
+ */
91
+ private $_cliArgs = array();
92
+
93
+
94
+ /**
95
+ * Run the PHPCS script.
96
+ *
97
+ * @return array
98
+ */
99
+ public function runphpcs()
100
+ {
101
+ if (defined('PHP_CODESNIFFER_CBF') === false) {
102
+ define('PHP_CODESNIFFER_CBF', false);
103
+ }
104
+
105
+ if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) {
106
+ include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php';
107
+ } else {
108
+ include_once 'PHP/CodeSniffer/Reporting.php';
109
+ }
110
+
111
+ PHP_CodeSniffer_Reporting::startTiming();
112
+ $this->checkRequirements();
113
+ $numErrors = $this->process();
114
+ if ($numErrors === 0) {
115
+ exit(0);
116
+ } else {
117
+ exit(1);
118
+ }
119
+
120
+ }//end runphpcs()
121
+
122
+
123
+ /**
124
+ * Run the PHPCBF script.
125
+ *
126
+ * @return array
127
+ */
128
+ public function runphpcbf()
129
+ {
130
+ if (defined('PHP_CODESNIFFER_CBF') === false) {
131
+ define('PHP_CODESNIFFER_CBF', true);
132
+ }
133
+
134
+ if (is_file(dirname(__FILE__).'/../CodeSniffer/Reporting.php') === true) {
135
+ include_once dirname(__FILE__).'/../CodeSniffer/Reporting.php';
136
+ } else {
137
+ include_once 'PHP/CodeSniffer/Reporting.php';
138
+ }
139
+
140
+ PHP_CodeSniffer_Reporting::startTiming();
141
+ $this->checkRequirements();
142
+
143
+ $this->dieOnUnknownArg = false;
144
+
145
+ // Override some of the command line settings that might break the fixes.
146
+ $cliValues = $this->getCommandLineValues();
147
+ $cliValues['verbosity'] = 0;
148
+ $cliValues['showProgress'] = false;
149
+ $cliValues['generator'] = '';
150
+ $cliValues['explain'] = false;
151
+ $cliValues['interactive'] = false;
152
+ $cliValues['showSources'] = false;
153
+ $cliValues['reportFile'] = null;
154
+ $cliValues['reports'] = array();
155
+
156
+ $suffix = '';
157
+ if (isset($cliValues['suffix']) === true) {
158
+ $suffix = $cliValues['suffix'];
159
+ }
160
+
161
+ $allowPatch = true;
162
+ if (isset($cliValues['no-patch']) === true || empty($cliValues['files']) === true) {
163
+ // They either asked for this,
164
+ // or they are using STDIN, which can't use diff.
165
+ $allowPatch = false;
166
+ }
167
+
168
+ if ($suffix === '' && $allowPatch === true) {
169
+ // Using the diff/patch tools.
170
+ $diffFile = getcwd().'/phpcbf-fixed.diff';
171
+ $cliValues['reports'] = array('diff' => $diffFile);
172
+ if (file_exists($diffFile) === true) {
173
+ unlink($diffFile);
174
+ }
175
+ } else {
176
+ // Replace the file without the patch command
177
+ // or writing to a file with a new suffix.
178
+ $cliValues['reports'] = array('cbf' => null);
179
+ $cliValues['phpcbf-suffix'] = $suffix;
180
+ }
181
+
182
+ $numErrors = $this->process($cliValues);
183
+
184
+ if ($suffix === '' && $allowPatch === true) {
185
+ if (file_exists($diffFile) === false) {
186
+ // Nothing to fix.
187
+ if ($numErrors === 0) {
188
+ // And no errors reported.
189
+ $exit = 0;
190
+ } else {
191
+ // Errors we can't fix.
192
+ $exit = 2;
193
+ }
194
+ } else {
195
+ if (filesize($diffFile) < 10) {
196
+ // Empty or bad diff file.
197
+ if ($numErrors === 0) {
198
+ // And no errors reported.
199
+ $exit = 0;
200
+ } else {
201
+ // Errors we can't fix.
202
+ $exit = 2;
203
+ }
204
+ } else {
205
+ $cmd = "patch -p0 -ui \"$diffFile\"";
206
+ $output = array();
207
+ $retVal = null;
208
+ exec($cmd, $output, $retVal);
209
+
210
+ if ($retVal === 0) {
211
+ // Everything went well.
212
+ $filesPatched = count($output);
213
+ echo "Patched $filesPatched file";
214
+ if ($filesPatched > 1) {
215
+ echo 's';
216
+ }
217
+
218
+ echo PHP_EOL;
219
+ $exit = 1;
220
+ } else {
221
+ print_r($output);
222
+ echo "Returned: $retVal".PHP_EOL;
223
+ $exit = 3;
224
+ }
225
+ }//end if
226
+
227
+ unlink($diffFile);
228
+ }//end if
229
+ } else {
230
+ // File are being patched manually, so we can't tell
231
+ // how many errors were fixed.
232
+ $exit = 1;
233
+ }//end if
234
+
235
+ if ($exit === 0) {
236
+ echo 'No fixable errors were found'.PHP_EOL;
237
+ } else if ($exit === 2) {
238
+ echo 'PHPCBF could not fix all the errors found'.PHP_EOL;
239
+ }
240
+
241
+ PHP_CodeSniffer_Reporting::printRunTime();
242
+ exit($exit);
243
+
244
+ }//end runphpcbf()
245
+
246
+
247
+ /**
248
+ * Exits if the minimum requirements of PHP_CodSniffer are not met.
249
+ *
250
+ * @return array
251
+ */
252
+ public function checkRequirements()
253
+ {
254
+ // Check the PHP version.
255
+ if (PHP_VERSION_ID < 50102) {
256
+ echo 'ERROR: PHP_CodeSniffer requires PHP version 5.1.2 or greater.'.PHP_EOL;
257
+ exit(2);
258
+ }
259
+
260
+ if (extension_loaded('tokenizer') === false) {
261
+ echo 'ERROR: PHP_CodeSniffer requires the tokenizer extension to be enabled.'.PHP_EOL;
262
+ exit(2);
263
+ }
264
+
265
+ }//end checkRequirements()
266
+
267
+
268
+ /**
269
+ * Get a list of default values for all possible command line arguments.
270
+ *
271
+ * @return array
272
+ */
273
+ public function getDefaults()
274
+ {
275
+ if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
276
+ return array();
277
+ }
278
+
279
+ // The default values for config settings.
280
+ $defaults['files'] = array();
281
+ $defaults['standard'] = null;
282
+ $defaults['verbosity'] = 0;
283
+ $defaults['interactive'] = false;
284
+ $defaults['colors'] = false;
285
+ $defaults['explain'] = false;
286
+ $defaults['local'] = false;
287
+ $defaults['showSources'] = false;
288
+ $defaults['extensions'] = array();
289
+ $defaults['sniffs'] = array();
290
+ $defaults['exclude'] = array();
291
+ $defaults['ignored'] = array();
292
+ $defaults['reportFile'] = null;
293
+ $defaults['generator'] = '';
294
+ $defaults['reports'] = array();
295
+ $defaults['bootstrap'] = array();
296
+ $defaults['errorSeverity'] = null;
297
+ $defaults['warningSeverity'] = null;
298
+ $defaults['stdin'] = null;
299
+ $defaults['stdinPath'] = '';
300
+
301
+ $reportFormat = PHP_CodeSniffer::getConfigData('report_format');
302
+ if ($reportFormat !== null) {
303
+ $defaults['reports'][$reportFormat] = null;
304
+ }
305
+
306
+ $tabWidth = PHP_CodeSniffer::getConfigData('tab_width');
307
+ if ($tabWidth === null) {
308
+ $defaults['tabWidth'] = 0;
309
+ } else {
310
+ $defaults['tabWidth'] = (int) $tabWidth;
311
+ }
312
+
313
+ $encoding = PHP_CodeSniffer::getConfigData('encoding');
314
+ if ($encoding === null) {
315
+ $defaults['encoding'] = 'iso-8859-1';
316
+ } else {
317
+ $defaults['encoding'] = strtolower($encoding);
318
+ }
319
+
320
+ $severity = PHP_CodeSniffer::getConfigData('severity');
321
+ if ($severity !== null) {
322
+ $defaults['errorSeverity'] = (int) $severity;
323
+ $defaults['warningSeverity'] = (int) $severity;
324
+ }
325
+
326
+ $severity = PHP_CodeSniffer::getConfigData('error_severity');
327
+ if ($severity !== null) {
328
+ $defaults['errorSeverity'] = (int) $severity;
329
+ }
330
+
331
+ $severity = PHP_CodeSniffer::getConfigData('warning_severity');
332
+ if ($severity !== null) {
333
+ $defaults['warningSeverity'] = (int) $severity;
334
+ }
335
+
336
+ $showWarnings = PHP_CodeSniffer::getConfigData('show_warnings');
337
+ if ($showWarnings !== null) {
338
+ $showWarnings = (bool) $showWarnings;
339
+ if ($showWarnings === false) {
340
+ $defaults['warningSeverity'] = 0;
341
+ }
342
+ }
343
+
344
+ $reportWidth = PHP_CodeSniffer::getConfigData('report_width');
345
+ if ($reportWidth !== null) {
346
+ $defaults['reportWidth'] = $this->_validateReportWidth($reportWidth);
347
+ } else {
348
+ // Use function defaults.
349
+ $defaults['reportWidth'] = null;
350
+ }
351
+
352
+ $showProgress = PHP_CodeSniffer::getConfigData('show_progress');
353
+ if ($showProgress === null) {
354
+ $defaults['showProgress'] = false;
355
+ } else {
356
+ $defaults['showProgress'] = (bool) $showProgress;
357
+ }
358
+
359
+ $quiet = PHP_CodeSniffer::getConfigData('quiet');
360
+ if ($quiet === null) {
361
+ $defaults['quiet'] = false;
362
+ } else {
363
+ $defaults['quiet'] = (bool) $quiet;
364
+ }
365
+
366
+ $colors = PHP_CodeSniffer::getConfigData('colors');
367
+ if ($colors === null) {
368
+ $defaults['colors'] = false;
369
+ } else {
370
+ $defaults['colors'] = (bool) $colors;
371
+ }
372
+
373
+ if (PHP_CodeSniffer::isPharFile(dirname(dirname(__FILE__))) === true) {
374
+ // If this is a phar file, check for the standard in the config.
375
+ $standard = PHP_CodeSniffer::getConfigData('standard');
376
+ if ($standard !== null) {
377
+ $defaults['standard'] = $standard;
378
+ }
379
+ }
380
+
381
+ return $defaults;
382
+
383
+ }//end getDefaults()
384
+
385
+
386
+ /**
387
+ * Gets the processed command line values.
388
+ *
389
+ * If the values have not yet been set, the values will be sourced
390
+ * from the command line arguments.
391
+ *
392
+ * @return array
393
+ */
394
+ public function getCommandLineValues()
395
+ {
396
+ if (empty($this->values) === false) {
397
+ return $this->values;
398
+ }
399
+
400
+ $args = $_SERVER['argv'];
401
+ array_shift($args);
402
+
403
+ $this->setCommandLineValues($args);
404
+
405
+ // Check for content on STDIN.
406
+ $handle = fopen('php://stdin', 'r');
407
+ if (stream_set_blocking($handle, false) === true) {
408
+ $fileContents = '';
409
+ while (($line = fgets($handle)) !== false) {
410
+ $fileContents .= $line;
411
+ usleep(10);
412
+ }
413
+
414
+ stream_set_blocking($handle, true);
415
+ fclose($handle);
416
+ if (trim($fileContents) !== '') {
417
+ $this->values['stdin'] = $fileContents;
418
+ }
419
+ }
420
+
421
+ return $this->values;
422
+
423
+ }//end getCommandLineValues()
424
+
425
+
426
+ /**
427
+ * Set the command line values.
428
+ *
429
+ * @param array $args An array of command line arguments to process.
430
+ *
431
+ * @return void
432
+ */
433
+ public function setCommandLineValues($args)
434
+ {
435
+ if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
436
+ $this->values = array(
437
+ 'stdin' => null,
438
+ 'quiet' => true,
439
+ );
440
+ } else if (empty($this->values) === true) {
441
+ $this->values = $this->getDefaults();
442
+ }
443
+
444
+ $this->_cliArgs = $args;
445
+ $numArgs = count($args);
446
+
447
+ for ($i = 0; $i < $numArgs; $i++) {
448
+ $arg = $this->_cliArgs[$i];
449
+ if ($arg === '') {
450
+ continue;
451
+ }
452
+
453
+ if ($arg{0} === '-') {
454
+ if ($arg === '-' || $arg === '--') {
455
+ // Empty argument, ignore it.
456
+ continue;
457
+ }
458
+
459
+ if ($arg{1} === '-') {
460
+ $this->processLongArgument(substr($arg, 2), $i);
461
+ } else {
462
+ $switches = str_split($arg);
463
+ foreach ($switches as $switch) {
464
+ if ($switch === '-') {
465
+ continue;
466
+ }
467
+
468
+ $this->processShortArgument($switch, $i);
469
+ }
470
+ }
471
+ } else {
472
+ $this->processUnknownArgument($arg, $i);
473
+ }//end if
474
+ }//end for
475
+
476
+ }//end setCommandLineValues()
477
+
478
+
479
+ /**
480
+ * Processes a short (-e) command line argument.
481
+ *
482
+ * @param string $arg The command line argument.
483
+ * @param int $pos The position of the argument on the command line.
484
+ *
485
+ * @return void
486
+ */
487
+ public function processShortArgument($arg, $pos)
488
+ {
489
+ switch ($arg) {
490
+ case 'h':
491
+ case '?':
492
+ $this->printUsage();
493
+ exit(0);
494
+ case 'i' :
495
+ $this->printInstalledStandards();
496
+ exit(0);
497
+ case 'v' :
498
+ if ($this->values['quiet'] === true) {
499
+ // Ignore when quiet mode is enabled.
500
+ break;
501
+ }
502
+
503
+ if (isset($this->values['verbosity']) === false) {
504
+ $this->values['verbosity'] = 1;
505
+ } else {
506
+ $this->values['verbosity']++;
507
+ }
508
+ break;
509
+ case 'l' :
510
+ $this->values['local'] = true;
511
+ break;
512
+ case 's' :
513
+ $this->values['showSources'] = true;
514
+ break;
515
+ case 'a' :
516
+ $this->values['interactive'] = true;
517
+ break;
518
+ case 'e':
519
+ $this->values['explain'] = true;
520
+ break;
521
+ case 'p' :
522
+ if ($this->values['quiet'] === true) {
523
+ // Ignore when quiet mode is enabled.
524
+ break;
525
+ }
526
+
527
+ $this->values['showProgress'] = true;
528
+ break;
529
+ case 'q' :
530
+ // Quiet mode disables a few other settings as well.
531
+ $this->values['quiet'] = true;
532
+ $this->values['showProgress'] = false;
533
+ $this->values['verbosity'] = 0;
534
+ break;
535
+ case 'd' :
536
+ $ini = explode('=', $this->_cliArgs[($pos + 1)]);
537
+ $this->_cliArgs[($pos + 1)] = '';
538
+ if (isset($ini[1]) === true) {
539
+ ini_set($ini[0], $ini[1]);
540
+ } else {
541
+ ini_set($ini[0], true);
542
+ }
543
+ break;
544
+ case 'n' :
545
+ $this->values['warningSeverity'] = 0;
546
+ break;
547
+ case 'w' :
548
+ $this->values['warningSeverity'] = null;
549
+ break;
550
+ default:
551
+ if ($this->dieOnUnknownArg === false) {
552
+ $this->values[$arg] = $arg;
553
+ } else {
554
+ $this->processUnknownArgument('-'.$arg, $pos);
555
+ }
556
+ }//end switch
557
+
558
+ }//end processShortArgument()
559
+
560
+
561
+ /**
562
+ * Processes a long (--example) command line argument.
563
+ *
564
+ * @param string $arg The command line argument.
565
+ * @param int $pos The position of the argument on the command line.
566
+ *
567
+ * @return void
568
+ */
569
+ public function processLongArgument($arg, $pos)
570
+ {
571
+ switch ($arg) {
572
+ case 'help':
573
+ $this->printUsage();
574
+ exit(0);
575
+ case 'version':
576
+ echo 'PHP_CodeSniffer version '.PHP_CodeSniffer::VERSION.' ('.PHP_CodeSniffer::STABILITY.') ';
577
+ echo 'by Squiz (http://www.squiz.net)'.PHP_EOL;
578
+ exit(0);
579
+ case 'colors':
580
+ $this->values['colors'] = true;
581
+ break;
582
+ case 'no-colors':
583
+ $this->values['colors'] = false;
584
+ break;
585
+ case 'config-set':
586
+ if (isset($this->_cliArgs[($pos + 1)]) === false
587
+ || isset($this->_cliArgs[($pos + 2)]) === false
588
+ ) {
589
+ echo 'ERROR: Setting a config option requires a name and value'.PHP_EOL.PHP_EOL;
590
+ $this->printUsage();
591
+ exit(0);
592
+ }
593
+
594
+ $key = $this->_cliArgs[($pos + 1)];
595
+ $value = $this->_cliArgs[($pos + 2)];
596
+ $current = PHP_CodeSniffer::getConfigData($key);
597
+
598
+ try {
599
+ PHP_CodeSniffer::setConfigData($key, $value);
600
+ } catch (Exception $e) {
601
+ echo $e->getMessage().PHP_EOL;
602
+ exit(2);
603
+ }
604
+
605
+ if ($current === null) {
606
+ echo "Config value \"$key\" added successfully".PHP_EOL;
607
+ } else {
608
+ echo "Config value \"$key\" updated successfully; old value was \"$current\"".PHP_EOL;
609
+ }
610
+ exit(0);
611
+ case 'config-delete':
612
+ if (isset($this->_cliArgs[($pos + 1)]) === false) {
613
+ echo 'ERROR: Deleting a config option requires the name of the option'.PHP_EOL.PHP_EOL;
614
+ $this->printUsage();
615
+ exit(0);
616
+ }
617
+
618
+ $key = $this->_cliArgs[($pos + 1)];
619
+ $current = PHP_CodeSniffer::getConfigData($key);
620
+ if ($current === null) {
621
+ echo "Config value \"$key\" has not been set".PHP_EOL;
622
+ } else {
623
+ try {
624
+ PHP_CodeSniffer::setConfigData($key, null);
625
+ } catch (Exception $e) {
626
+ echo $e->getMessage().PHP_EOL;
627
+ exit(2);
628
+ }
629
+
630
+ echo "Config value \"$key\" removed successfully; old value was \"$current\"".PHP_EOL;
631
+ }
632
+ exit(0);
633
+ case 'config-show':
634
+ $data = PHP_CodeSniffer::getAllConfigData();
635
+ $this->printConfigData($data);
636
+ exit(0);
637
+ case 'runtime-set':
638
+ if (isset($this->_cliArgs[($pos + 1)]) === false
639
+ || isset($this->_cliArgs[($pos + 2)]) === false
640
+ ) {
641
+ echo 'ERROR: Setting a runtime config option requires a name and value'.PHP_EOL.PHP_EOL;
642
+ $this->printUsage();
643
+ exit(0);
644
+ }
645
+
646
+ $key = $this->_cliArgs[($pos + 1)];
647
+ $value = $this->_cliArgs[($pos + 2)];
648
+ $this->_cliArgs[($pos + 1)] = '';
649
+ $this->_cliArgs[($pos + 2)] = '';
650
+ PHP_CodeSniffer::setConfigData($key, $value, true);
651
+ break;
652
+ default:
653
+ if (substr($arg, 0, 7) === 'sniffs=') {
654
+ $sniffs = explode(',', substr($arg, 7));
655
+ foreach ($sniffs as $sniff) {
656
+ if (substr_count($sniff, '.') !== 2) {
657
+ echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
658
+ $this->printUsage();
659
+ exit(2);
660
+ }
661
+ }
662
+
663
+ $this->values['sniffs'] = $sniffs;
664
+ } else if (substr($arg, 0, 8) === 'exclude=') {
665
+ $sniffs = explode(',', substr($arg, 8));
666
+ foreach ($sniffs as $sniff) {
667
+ if (substr_count($sniff, '.') !== 2) {
668
+ echo 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
669
+ $this->printUsage();
670
+ exit(2);
671
+ }
672
+ }
673
+
674
+ $this->values['exclude'] = $sniffs;
675
+ } else if (substr($arg, 0, 10) === 'bootstrap=') {
676
+ $files = explode(',', substr($arg, 10));
677
+ foreach ($files as $file) {
678
+ $path = PHP_CodeSniffer::realpath($file);
679
+ if ($path === false) {
680
+ echo 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
681
+ $this->printUsage();
682
+ exit(2);
683
+ }
684
+
685
+ $this->values['bootstrap'][] = $path;
686
+ }
687
+ } else if (substr($arg, 0, 10) === 'file-list=') {
688
+ $fileList = substr($arg, 10);
689
+ $path = PHP_CodeSniffer::realpath($fileList);
690
+ if ($path === false) {
691
+ echo 'ERROR: The specified file list "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
692
+ $this->printUsage();
693
+ exit(2);
694
+ }
695
+
696
+ $files = file($path);
697
+ foreach ($files as $inputFile) {
698
+ $inputFile = trim($inputFile);
699
+
700
+ // Skip empty lines.
701
+ if ($inputFile === '') {
702
+ continue;
703
+ }
704
+
705
+ $realFile = PHP_CodeSniffer::realpath($inputFile);
706
+ if ($realFile === false) {
707
+ echo 'ERROR: The specified file "'.$inputFile.'" does not exist'.PHP_EOL.PHP_EOL;
708
+ $this->printUsage();
709
+ exit(2);
710
+ }
711
+
712
+ $this->values['files'][] = $realFile;
713
+ }
714
+ } else if (substr($arg, 0, 11) === 'stdin-path=') {
715
+ $this->values['stdinPath'] = PHP_CodeSniffer::realpath(substr($arg, 11));
716
+
717
+ // It may not exist and return false instead, so just use whatever they gave us.
718
+ if ($this->values['stdinPath'] === false) {
719
+ $this->values['stdinPath'] = trim(substr($arg, 11));
720
+ }
721
+ } else if (substr($arg, 0, 12) === 'report-file=') {
722
+ $this->values['reportFile'] = PHP_CodeSniffer::realpath(substr($arg, 12));
723
+
724
+ // It may not exist and return false instead.
725
+ if ($this->values['reportFile'] === false) {
726
+ $this->values['reportFile'] = substr($arg, 12);
727
+
728
+ $dir = dirname($this->values['reportFile']);
729
+ if (is_dir($dir) === false) {
730
+ echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
731
+ $this->printUsage();
732
+ exit(2);
733
+ }
734
+
735
+ if ($dir === '.') {
736
+ // Passed report file is a file in the current directory.
737
+ $this->values['reportFile'] = getcwd().'/'.basename($this->values['reportFile']);
738
+ } else {
739
+ if ($dir{0} === '/') {
740
+ // An absolute path.
741
+ $dir = PHP_CodeSniffer::realpath($dir);
742
+ } else {
743
+ $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir);
744
+ }
745
+
746
+ if ($dir !== false) {
747
+ // Report file path is relative.
748
+ $this->values['reportFile'] = $dir.'/'.basename($this->values['reportFile']);
749
+ }
750
+ }
751
+ }//end if
752
+
753
+ if (is_dir($this->values['reportFile']) === true) {
754
+ echo 'ERROR: The specified report file path "'.$this->values['reportFile'].'" is a directory'.PHP_EOL.PHP_EOL;
755
+ $this->printUsage();
756
+ exit(2);
757
+ }
758
+ } else if (substr($arg, 0, 13) === 'report-width=') {
759
+ $this->values['reportWidth'] = $this->_validateReportWidth(substr($arg, 13));
760
+ } else if (substr($arg, 0, 7) === 'report='
761
+ || substr($arg, 0, 7) === 'report-'
762
+ ) {
763
+ if ($arg[6] === '-') {
764
+ // This is a report with file output.
765
+ $split = strpos($arg, '=');
766
+ if ($split === false) {
767
+ $report = substr($arg, 7);
768
+ $output = null;
769
+ } else {
770
+ $report = substr($arg, 7, ($split - 7));
771
+ $output = substr($arg, ($split + 1));
772
+ if ($output === false) {
773
+ $output = null;
774
+ } else {
775
+ $dir = dirname($output);
776
+ if ($dir === '.') {
777
+ // Passed report file is a filename in the current directory.
778
+ $output = getcwd().'/'.basename($output);
779
+ } else {
780
+ if ($dir{0} === '/') {
781
+ // An absolute path.
782
+ $dir = PHP_CodeSniffer::realpath($dir);
783
+ } else {
784
+ $dir = PHP_CodeSniffer::realpath(getcwd().'/'.$dir);
785
+ }
786
+
787
+ if ($dir !== false) {
788
+ // Report file path is relative.
789
+ $output = $dir.'/'.basename($output);
790
+ }
791
+ }
792
+ }//end if
793
+ }//end if
794
+ } else {
795
+ // This is a single report.
796
+ $report = substr($arg, 7);
797
+ $output = null;
798
+ }//end if
799
+
800
+ $this->values['reports'][$report] = $output;
801
+ } else if (substr($arg, 0, 9) === 'standard=') {
802
+ $standards = trim(substr($arg, 9));
803
+ if ($standards !== '') {
804
+ $this->values['standard'] = explode(',', $standards);
805
+ }
806
+ } else if (substr($arg, 0, 11) === 'extensions=') {
807
+ if (isset($this->values['extensions']) === false) {
808
+ $this->values['extensions'] = array();
809
+ }
810
+
811
+ $this->values['extensions'] = array_merge($this->values['extensions'], explode(',', substr($arg, 11)));
812
+ } else if (substr($arg, 0, 9) === 'severity=') {
813
+ $this->values['errorSeverity'] = (int) substr($arg, 9);
814
+ $this->values['warningSeverity'] = $this->values['errorSeverity'];
815
+ } else if (substr($arg, 0, 15) === 'error-severity=') {
816
+ $this->values['errorSeverity'] = (int) substr($arg, 15);
817
+ } else if (substr($arg, 0, 17) === 'warning-severity=') {
818
+ $this->values['warningSeverity'] = (int) substr($arg, 17);
819
+ } else if (substr($arg, 0, 7) === 'ignore=') {
820
+ // Split the ignore string on commas, unless the comma is escaped
821
+ // using 1 or 3 slashes (\, or \\\,).
822
+ $ignored = preg_split(
823
+ '/(?<=(?<!\\\\)\\\\\\\\),|(?<!\\\\),/',
824
+ substr($arg, 7)
825
+ );
826
+ foreach ($ignored as $pattern) {
827
+ $pattern = trim($pattern);
828
+ if ($pattern === '') {
829
+ continue;
830
+ }
831
+
832
+ $this->values['ignored'][$pattern] = 'absolute';
833
+ }
834
+ } else if (substr($arg, 0, 10) === 'generator=') {
835
+ $this->values['generator'] = substr($arg, 10);
836
+ } else if (substr($arg, 0, 9) === 'encoding=') {
837
+ $this->values['encoding'] = strtolower(substr($arg, 9));
838
+ } else if (substr($arg, 0, 10) === 'tab-width=') {
839
+ $this->values['tabWidth'] = (int) substr($arg, 10);
840
+ } else {
841
+ if ($this->dieOnUnknownArg === false) {
842
+ $eqPos = strpos($arg, '=');
843
+ if ($eqPos === false) {
844
+ $this->values[$arg] = $arg;
845
+ } else {
846
+ $value = substr($arg, ($eqPos + 1));
847
+ $arg = substr($arg, 0, $eqPos);
848
+ $this->values[$arg] = $value;
849
+ }
850
+ } else {
851
+ $this->processUnknownArgument('--'.$arg, $pos);
852
+ }
853
+ }//end if
854
+
855
+ break;
856
+ }//end switch
857
+
858
+ }//end processLongArgument()
859
+
860
+
861
+ /**
862
+ * Processes an unknown command line argument.
863
+ *
864
+ * Assumes all unknown arguments are files and folders to check.
865
+ *
866
+ * @param string $arg The command line argument.
867
+ * @param int $pos The position of the argument on the command line.
868
+ *
869
+ * @return void
870
+ */
871
+ public function processUnknownArgument($arg, $pos)
872
+ {
873
+ // We don't know about any additional switches; just files.
874
+ if ($arg{0} === '-') {
875
+ if ($this->dieOnUnknownArg === false) {
876
+ return;
877
+ }
878
+
879
+ echo 'ERROR: option "'.$arg.'" not known.'.PHP_EOL.PHP_EOL;
880
+ $this->printUsage();
881
+ exit(2);
882
+ }
883
+
884
+ $file = PHP_CodeSniffer::realpath($arg);
885
+ if (file_exists($file) === false) {
886
+ if ($this->dieOnUnknownArg === false) {
887
+ return;
888
+ }
889
+
890
+ echo 'ERROR: The file "'.$arg.'" does not exist.'.PHP_EOL.PHP_EOL;
891
+ $this->printUsage();
892
+ exit(2);
893
+ } else {
894
+ $this->values['files'][] = $file;
895
+ }
896
+
897
+ }//end processUnknownArgument()
898
+
899
+
900
+ /**
901
+ * Runs PHP_CodeSniffer over files and directories.
902
+ *
903
+ * @param array $values An array of values determined from CLI args.
904
+ *
905
+ * @return int The number of error and warning messages shown.
906
+ * @see getCommandLineValues()
907
+ */
908
+ public function process($values=array())
909
+ {
910
+ if (empty($values) === true) {
911
+ $values = $this->getCommandLineValues();
912
+ } else {
913
+ $values = array_merge($this->getDefaults(), $values);
914
+ $this->values = $values;
915
+ }
916
+
917
+ if ($values['generator'] !== '') {
918
+ $phpcs = new PHP_CodeSniffer($values['verbosity']);
919
+ if ($values['standard'] === null) {
920
+ $values['standard'] = $this->validateStandard(null);
921
+ }
922
+
923
+ foreach ($values['standard'] as $standard) {
924
+ $phpcs->generateDocs(
925
+ $standard,
926
+ $values['sniffs'],
927
+ $values['generator']
928
+ );
929
+ }
930
+
931
+ exit(0);
932
+ }
933
+
934
+ // If no standard is supplied, get the default.
935
+ $values['standard'] = $this->validateStandard($values['standard']);
936
+ foreach ($values['standard'] as $standard) {
937
+ if (PHP_CodeSniffer::isInstalledStandard($standard) === false) {
938
+ // They didn't select a valid coding standard, so help them
939
+ // out by letting them know which standards are installed.
940
+ echo 'ERROR: the "'.$standard.'" coding standard is not installed. ';
941
+ $this->printInstalledStandards();
942
+ exit(2);
943
+ }
944
+ }
945
+
946
+ if ($values['explain'] === true) {
947
+ foreach ($values['standard'] as $standard) {
948
+ $this->explainStandard($standard);
949
+ }
950
+
951
+ exit(0);
952
+ }
953
+
954
+ $phpcs = new PHP_CodeSniffer($values['verbosity'], null, null, null);
955
+ $phpcs->setCli($this);
956
+ $phpcs->initStandard($values['standard'], $values['sniffs'], $values['exclude']);
957
+ $values = $this->values;
958
+
959
+ $phpcs->setTabWidth($values['tabWidth']);
960
+ $phpcs->setEncoding($values['encoding']);
961
+ $phpcs->setInteractive($values['interactive']);
962
+
963
+ // Set file extensions if they were specified. Otherwise,
964
+ // let PHP_CodeSniffer decide on the defaults.
965
+ if (empty($values['extensions']) === false) {
966
+ $phpcs->setAllowedFileExtensions($values['extensions']);
967
+ }
968
+
969
+ // Set ignore patterns if they were specified.
970
+ if (empty($values['ignored']) === false) {
971
+ $ignorePatterns = array_merge($phpcs->getIgnorePatterns(), $values['ignored']);
972
+ $phpcs->setIgnorePatterns($ignorePatterns);
973
+ }
974
+
975
+ // Set some convenience member vars.
976
+ if ($values['errorSeverity'] === null) {
977
+ $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV;
978
+ } else {
979
+ $this->errorSeverity = $values['errorSeverity'];
980
+ }
981
+
982
+ if ($values['warningSeverity'] === null) {
983
+ $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV;
984
+ } else {
985
+ $this->warningSeverity = $values['warningSeverity'];
986
+ }
987
+
988
+ if (empty($values['reports']) === true) {
989
+ $values['reports']['full'] = $values['reportFile'];
990
+ $this->values['reports'] = $values['reports'];
991
+ }
992
+
993
+ // Include bootstrap files.
994
+ foreach ($values['bootstrap'] as $bootstrap) {
995
+ include $bootstrap;
996
+ }
997
+
998
+ $phpcs->processFiles($values['files'], $values['local']);
999
+
1000
+ if (empty($values['files']) === true || $values['stdin'] !== null) {
1001
+ $fileContents = $values['stdin'];
1002
+ if ($fileContents === null) {
1003
+ // Check if they are passing in the file contents.
1004
+ $handle = fopen('php://stdin', 'r');
1005
+ stream_set_blocking($handle, true);
1006
+ $fileContents = stream_get_contents($handle);
1007
+ fclose($handle);
1008
+ }
1009
+
1010
+ if ($fileContents === '') {
1011
+ // No files and no content passed in.
1012
+ echo 'ERROR: You must supply at least one file or directory to process.'.PHP_EOL.PHP_EOL;
1013
+ $this->printUsage();
1014
+ exit(2);
1015
+ } else {
1016
+ $this->values['stdin'] = $fileContents;
1017
+ $phpcs->processFile('STDIN', $fileContents);
1018
+ }
1019
+ }
1020
+
1021
+ // Interactive runs don't require a final report and it doesn't really
1022
+ // matter what the retun value is because we know it isn't being read
1023
+ // by a script.
1024
+ if ($values['interactive'] === true) {
1025
+ return 0;
1026
+ }
1027
+
1028
+ return $this->printErrorReport(
1029
+ $phpcs,
1030
+ $values['reports'],
1031
+ $values['showSources'],
1032
+ $values['reportFile'],
1033
+ $values['reportWidth']
1034
+ );
1035
+
1036
+ }//end process()
1037
+
1038
+
1039
+ /**
1040
+ * Prints the error report for the run.
1041
+ *
1042
+ * Note that this function may actually print multiple reports
1043
+ * as the user may have specified a number of output formats.
1044
+ *
1045
+ * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing
1046
+ * the errors.
1047
+ * @param array $reports A list of reports to print.
1048
+ * @param bool $showSources TRUE if report should show error sources
1049
+ * (not used by all reports).
1050
+ * @param string $reportFile A default file to log report output to.
1051
+ * @param int $reportWidth How wide the screen reports should be.
1052
+ *
1053
+ * @return int The number of error and warning messages shown.
1054
+ */
1055
+ public function printErrorReport(
1056
+ PHP_CodeSniffer $phpcs,
1057
+ $reports,
1058
+ $showSources,
1059
+ $reportFile,
1060
+ $reportWidth
1061
+ ) {
1062
+ if (empty($reports) === true) {
1063
+ $reports['full'] = $reportFile;
1064
+ }
1065
+
1066
+ $errors = 0;
1067
+ $warnings = 0;
1068
+ $toScreen = false;
1069
+
1070
+ foreach ($reports as $report => $output) {
1071
+ if ($output === null) {
1072
+ $output = $reportFile;
1073
+ }
1074
+
1075
+ if ($reportFile === null) {
1076
+ $toScreen = true;
1077
+ }
1078
+
1079
+ // We don't add errors here because the number of
1080
+ // errors reported by each report type will always be the
1081
+ // same, so we really just need 1 number.
1082
+ $result = $phpcs->reporting->printReport(
1083
+ $report,
1084
+ $showSources,
1085
+ $this->values,
1086
+ $output,
1087
+ $reportWidth
1088
+ );
1089
+
1090
+ $errors = $result['errors'];
1091
+ $warnings = $result['warnings'];
1092
+ }//end foreach
1093
+
1094
+ // Only print timer output if no reports were
1095
+ // printed to the screen so we don't put additional output
1096
+ // in something like an XML report. If we are printing to screen,
1097
+ // the report types would have already worked out who should
1098
+ // print the timer info.
1099
+ if (PHP_CODESNIFFER_INTERACTIVE === false
1100
+ && ($toScreen === false
1101
+ || (($errors + $warnings) === 0 && $this->values['showProgress'] === true))
1102
+ ) {
1103
+ PHP_CodeSniffer_Reporting::printRunTime();
1104
+ }
1105
+
1106
+ // They should all return the same value, so it
1107
+ // doesn't matter which return value we end up using.
1108
+ $ignoreWarnings = PHP_CodeSniffer::getConfigData('ignore_warnings_on_exit');
1109
+ $ignoreErrors = PHP_CodeSniffer::getConfigData('ignore_errors_on_exit');
1110
+
1111
+ $return = ($errors + $warnings);
1112
+ if ($ignoreErrors !== null) {
1113
+ $ignoreErrors = (bool) $ignoreErrors;
1114
+ if ($ignoreErrors === true) {
1115
+ $return -= $errors;
1116
+ }
1117
+ }
1118
+
1119
+ if ($ignoreWarnings !== null) {
1120
+ $ignoreWarnings = (bool) $ignoreWarnings;
1121
+ if ($ignoreWarnings === true) {
1122
+ $return -= $warnings;
1123
+ }
1124
+ }
1125
+
1126
+ return $return;
1127
+
1128
+ }//end printErrorReport()
1129
+
1130
+
1131
+ /**
1132
+ * Convert the passed standards into valid standards.
1133
+ *
1134
+ * Checks things like default values and case.
1135
+ *
1136
+ * @param array $standards The standards to validate.
1137
+ *
1138
+ * @return array
1139
+ */
1140
+ public function validateStandard($standards)
1141
+ {
1142
+ if ($standards === null) {
1143
+ // They did not supply a standard to use.
1144
+ // Look for a default ruleset in the current directory or higher.
1145
+ $currentDir = getcwd();
1146
+
1147
+ do {
1148
+ $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml';
1149
+ if (is_file($default) === true) {
1150
+ return array($default);
1151
+ }
1152
+
1153
+ $default = $currentDir.DIRECTORY_SEPARATOR.'phpcs.xml.dist';
1154
+ if (is_file($default) === true) {
1155
+ return array($default);
1156
+ }
1157
+
1158
+ $lastDir = $currentDir;
1159
+ $currentDir = dirname($currentDir);
1160
+ } while ($currentDir !== '.' && $currentDir !== $lastDir);
1161
+
1162
+ // Try to get the default from the config system.
1163
+ $standard = PHP_CodeSniffer::getConfigData('default_standard');
1164
+ if ($standard === null) {
1165
+ // Product default standard.
1166
+ $standard = 'PEAR';
1167
+ }
1168
+
1169
+ return explode(',', $standard);
1170
+ }//end if
1171
+
1172
+ $cleaned = array();
1173
+ $standards = (array) $standards;
1174
+
1175
+ // Check if the standard name is valid, or if the case is invalid.
1176
+ $installedStandards = PHP_CodeSniffer::getInstalledStandards();
1177
+ foreach ($standards as $standard) {
1178
+ foreach ($installedStandards as $validStandard) {
1179
+ if (strtolower($standard) === strtolower($validStandard)) {
1180
+ $standard = $validStandard;
1181
+ break;
1182
+ }
1183
+ }
1184
+
1185
+ $cleaned[] = $standard;
1186
+ }
1187
+
1188
+ return $cleaned;
1189
+
1190
+ }//end validateStandard()
1191
+
1192
+
1193
+ /**
1194
+ * Prints a report showing the sniffs contained in a standard.
1195
+ *
1196
+ * @param string $standard The standard to validate.
1197
+ *
1198
+ * @return void
1199
+ */
1200
+ public function explainStandard($standard)
1201
+ {
1202
+ $phpcs = new PHP_CodeSniffer();
1203
+ $phpcs->process(array(), $standard);
1204
+ $sniffs = $phpcs->getSniffs();
1205
+ $sniffs = array_keys($sniffs);
1206
+ sort($sniffs);
1207
+
1208
+ ob_start();
1209
+
1210
+ $lastStandard = '';
1211
+ $lastCount = '';
1212
+ $sniffCount = count($sniffs);
1213
+ $sniffs[] = '___';
1214
+
1215
+ echo PHP_EOL."The $standard standard contains $sniffCount sniffs".PHP_EOL;
1216
+
1217
+ ob_start();
1218
+
1219
+ foreach ($sniffs as $sniff) {
1220
+ $parts = explode('_', str_replace('\\', '_', $sniff));
1221
+ if ($lastStandard === '') {
1222
+ $lastStandard = $parts[0];
1223
+ }
1224
+
1225
+ if ($parts[0] !== $lastStandard) {
1226
+ $sniffList = ob_get_contents();
1227
+ ob_end_clean();
1228
+
1229
+ echo PHP_EOL.$lastStandard.' ('.$lastCount.' sniffs)'.PHP_EOL;
1230
+ echo str_repeat('-', (strlen($lastStandard.$lastCount) + 10));
1231
+ echo PHP_EOL;
1232
+ echo $sniffList;
1233
+
1234
+ $lastStandard = $parts[0];
1235
+ $lastCount = 0;
1236
+
1237
+ ob_start();
1238
+ }
1239
+
1240
+ echo ' '.$parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5).PHP_EOL;
1241
+ $lastCount++;
1242
+ }//end foreach
1243
+
1244
+ ob_end_clean();
1245
+
1246
+ }//end explainStandard()
1247
+
1248
+
1249
+ /**
1250
+ * Prints out the gathered config data.
1251
+ *
1252
+ * @param array $data The config data to print.
1253
+ *
1254
+ * @return void
1255
+ */
1256
+ public function printConfigData($data)
1257
+ {
1258
+ $max = 0;
1259
+ $keys = array_keys($data);
1260
+ foreach ($keys as $key) {
1261
+ $len = strlen($key);
1262
+ if (strlen($key) > $max) {
1263
+ $max = $len;
1264
+ }
1265
+ }
1266
+
1267
+ if ($max === 0) {
1268
+ return;
1269
+ }
1270
+
1271
+ $max += 2;
1272
+ ksort($data);
1273
+ foreach ($data as $name => $value) {
1274
+ echo str_pad($name.': ', $max).$value.PHP_EOL;
1275
+ }
1276
+
1277
+ }//end printConfigData()
1278
+
1279
+
1280
+ /**
1281
+ * Prints out the usage information for this script.
1282
+ *
1283
+ * @return void
1284
+ */
1285
+ public function printUsage()
1286
+ {
1287
+ if (PHP_CODESNIFFER_CBF === true) {
1288
+ $this->printPHPCBFUsage();
1289
+ } else {
1290
+ $this->printPHPCSUsage();
1291
+ }
1292
+
1293
+ }//end printUsage()
1294
+
1295
+
1296
+ /**
1297
+ * Prints out the usage information for PHPCS.
1298
+ *
1299
+ * @return void
1300
+ */
1301
+ public function printPHPCSUsage()
1302
+ {
1303
+ echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors] [--stdin-path=<stdinPath>]'.PHP_EOL;
1304
+ echo ' [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>] ...'.PHP_EOL;
1305
+ echo ' [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>]'.PHP_EOL;
1306
+ echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
1307
+ echo ' [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
1308
+ echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--encoding=<encoding>]'.PHP_EOL;
1309
+ echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL;
1310
+ echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL;
1311
+ echo ' Set runtime value (see --config-set) '.PHP_EOL;
1312
+ echo ' -n Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL;
1313
+ echo ' -w Print both warnings and errors (this is the default)'.PHP_EOL;
1314
+ echo ' -l Local directory only, no recursion'.PHP_EOL;
1315
+ echo ' -s Show sniff codes in all reports'.PHP_EOL;
1316
+ echo ' -a Run interactively'.PHP_EOL;
1317
+ echo ' -e Explain a standard by showing the sniffs it includes'.PHP_EOL;
1318
+ echo ' -p Show progress of the run'.PHP_EOL;
1319
+ echo ' -q Quiet mode; disables progress and verbose output'.PHP_EOL;
1320
+ echo ' -v[v][v] Print verbose output'.PHP_EOL;
1321
+ echo ' -i Show a list of installed coding standards'.PHP_EOL;
1322
+ echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
1323
+ echo ' --help Print this help message'.PHP_EOL;
1324
+ echo ' --version Print version information'.PHP_EOL;
1325
+ echo ' --colors Use colors in output'.PHP_EOL;
1326
+ echo ' --no-colors Do not use colors in output (this is the default)'.PHP_EOL;
1327
+ echo ' <file> One or more files and/or directories to check'.PHP_EOL;
1328
+ echo ' <fileList> A file containing a list of files and/or directories to check (one per line)'.PHP_EOL;
1329
+ echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL;
1330
+ echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL;
1331
+ echo ' <encoding> The encoding of the files being checked (default is iso-8859-1)'.PHP_EOL;
1332
+ echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL;
1333
+ echo ' (extension filtering only valid when checking a directory)'.PHP_EOL;
1334
+ echo ' The type of the file can be specified using: ext/type'.PHP_EOL;
1335
+ echo ' e.g., module/php,es/js'.PHP_EOL;
1336
+ echo ' <generator> Uses either the "HTML", "Markdown" or "Text" generator'.PHP_EOL;
1337
+ echo ' (forces documentation generation instead of checking)'.PHP_EOL;
1338
+ echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL;
1339
+ echo ' <report> Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL;
1340
+ echo ' "json", "emacs", "source", "summary", "diff", "junit"'.PHP_EOL;
1341
+ echo ' "svnblame", "gitblame", "hgblame" or "notifysend" report'.PHP_EOL;
1342
+ echo ' (the "full" report is printed by default)'.PHP_EOL;
1343
+ echo ' <reportFile> Write the report to the specified file path'.PHP_EOL;
1344
+ echo ' <reportWidth> How many columns wide screen reports should be printed'.PHP_EOL;
1345
+ echo ' or set to "auto" to use current screen width, where supported'.PHP_EOL;
1346
+ echo ' <sniffs> A comma separated list of sniff codes to include or exclude during checking'.PHP_EOL;
1347
+ echo ' (all sniffs must be part of the specified standard)'.PHP_EOL;
1348
+ echo ' <severity> The minimum severity required to display an error or warning'.PHP_EOL;
1349
+ echo ' <standard> The name or path of the coding standard to use'.PHP_EOL;
1350
+ echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL;
1351
+
1352
+ }//end printPHPCSUsage()
1353
+
1354
+
1355
+ /**
1356
+ * Prints out the usage information for PHPCBF.
1357
+ *
1358
+ * @return void
1359
+ */
1360
+ public function printPHPCBFUsage()
1361
+ {
1362
+ echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--stdin-path=<stdinPath>]'.PHP_EOL;
1363
+ echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>] [--suffix=<suffix>]'.PHP_EOL;
1364
+ echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
1365
+ echo ' [--tab-width=<tabWidth>] [--encoding=<encoding>]'.PHP_EOL;
1366
+ echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--bootstrap=<bootstrap>]'.PHP_EOL;
1367
+ echo ' [--file-list=<fileList>] <file> ...'.PHP_EOL;
1368
+ echo ' -n Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL;
1369
+ echo ' -w Fix both warnings and errors (on by default)'.PHP_EOL;
1370
+ echo ' -l Local directory only, no recursion'.PHP_EOL;
1371
+ echo ' -i Show a list of installed coding standards'.PHP_EOL;
1372
+ echo ' -d Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
1373
+ echo ' --help Print this help message'.PHP_EOL;
1374
+ echo ' --version Print version information'.PHP_EOL;
1375
+ echo ' --no-patch Do not make use of the "diff" or "patch" programs'.PHP_EOL;
1376
+ echo ' <file> One or more files and/or directories to fix'.PHP_EOL;
1377
+ echo ' <fileList> A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL;
1378
+ echo ' <stdinPath> If processing STDIN, the file path that STDIN will be processed as '.PHP_EOL;
1379
+ echo ' <bootstrap> A comma separated list of files to run before processing starts'.PHP_EOL;
1380
+ echo ' <encoding> The encoding of the files being fixed (default is iso-8859-1)'.PHP_EOL;
1381
+ echo ' <extensions> A comma separated list of file extensions to fix'.PHP_EOL;
1382
+ echo ' (extension filtering only valid when checking a directory)'.PHP_EOL;
1383
+ echo ' The type of the file can be specified using: ext/type'.PHP_EOL;
1384
+ echo ' e.g., module/php,es/js'.PHP_EOL;
1385
+ echo ' <patterns> A comma separated list of patterns to ignore files and directories'.PHP_EOL;
1386
+ echo ' <sniffs> A comma separated list of sniff codes to include or exclude during fixing'.PHP_EOL;
1387
+ echo ' (all sniffs must be part of the specified standard)'.PHP_EOL;
1388
+ echo ' <severity> The minimum severity required to fix an error or warning'.PHP_EOL;
1389
+ echo ' <standard> The name or path of the coding standard to use'.PHP_EOL;
1390
+ echo ' <suffix> Write modified files to a filename using this suffix'.PHP_EOL;
1391
+ echo ' ("diff" and "patch" are not used in this mode)'.PHP_EOL;
1392
+ echo ' <tabWidth> The number of spaces each tab represents'.PHP_EOL;
1393
+
1394
+ }//end printPHPCBFUsage()
1395
+
1396
+
1397
+ /**
1398
+ * Prints out a list of installed coding standards.
1399
+ *
1400
+ * @return void
1401
+ */
1402
+ public function printInstalledStandards()
1403
+ {
1404
+ $installedStandards = PHP_CodeSniffer::getInstalledStandards();
1405
+ $numStandards = count($installedStandards);
1406
+
1407
+ if ($numStandards === 0) {
1408
+ echo 'No coding standards are installed.'.PHP_EOL;
1409
+ } else {
1410
+ $lastStandard = array_pop($installedStandards);
1411
+ if ($numStandards === 1) {
1412
+ echo "The only coding standard installed is $lastStandard".PHP_EOL;
1413
+ } else {
1414
+ $standardList = implode(', ', $installedStandards);
1415
+ $standardList .= ' and '.$lastStandard;
1416
+ echo 'The installed coding standards are '.$standardList.PHP_EOL;
1417
+ }
1418
+ }
1419
+
1420
+ }//end printInstalledStandards()
1421
+
1422
+
1423
+ /**
1424
+ * Set report width based on terminal width.
1425
+ *
1426
+ * @param int $width The width of the report. If "auto" then will
1427
+ * be replaced by the terminal width.
1428
+ *
1429
+ * @return int
1430
+ */
1431
+ private function _validateReportWidth($width)
1432
+ {
1433
+ if ($width === 'auto'
1434
+ && preg_match('|\d+ (\d+)|', shell_exec('stty size 2>&1'), $matches) === 1
1435
+ ) {
1436
+ return (int) $matches[1];
1437
+ }
1438
+
1439
+ return (int) $width;
1440
+
1441
+ }//end _validateReportWidth()
1442
+
1443
+
1444
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Generator.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The base class for all PHP_CodeSniffer documentation generators.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Greg Sherwood <gsherwood@squiz.net>
10
+ * @author Marc McIntyre <mmcintyre@squiz.net>
11
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
+ * @link http://pear.php.net/package/PHP_CodeSniffer
14
+ */
15
+
16
+ /**
17
+ * The base class for all PHP_CodeSniffer documentation generators.
18
+ *
19
+ * Documentation generators are used to print documentation about code sniffs
20
+ * in a standard.
21
+ *
22
+ * @category PHP
23
+ * @package PHP_CodeSniffer
24
+ * @author Greg Sherwood <gsherwood@squiz.net>
25
+ * @author Marc McIntyre <mmcintyre@squiz.net>
26
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
27
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
28
+ * @version Release: @package_version@
29
+ * @link http://pear.php.net/package/PHP_CodeSniffer
30
+ */
31
+ abstract class PHP_CodeSniffer_DocGenerators_Generator
32
+ {
33
+
34
+ /**
35
+ * The name of the coding standard we are generating docs for.
36
+ *
37
+ * @var string
38
+ */
39
+ private $_standard = '';
40
+
41
+ /**
42
+ * An array of sniffs that we are limiting the generated docs to.
43
+ *
44
+ * If this array is empty, docs are generated for all sniffs in the
45
+ * supplied coding standard.
46
+ *
47
+ * @var string
48
+ */
49
+ private $_sniffs = array();
50
+
51
+
52
+ /**
53
+ * Constructs a PHP_CodeSniffer_DocGenerators_Generator object.
54
+ *
55
+ * @param string $standard The name of the coding standard to generate
56
+ * docs for.
57
+ * @param array $sniffs An array of sniffs that we are limiting the
58
+ * generated docs to.
59
+ *
60
+ * @see generate()
61
+ */
62
+ public function __construct($standard, array $sniffs=array())
63
+ {
64
+ $this->_standard = $standard;
65
+ $this->_sniffs = $sniffs;
66
+
67
+ }//end __construct()
68
+
69
+
70
+ /**
71
+ * Retrieves the title of the sniff from the DOMNode supplied.
72
+ *
73
+ * @param DOMNode $doc The DOMNode object for the sniff.
74
+ * It represents the "documentation" tag in the XML
75
+ * standard file.
76
+ *
77
+ * @return string
78
+ */
79
+ protected function getTitle(DOMNode $doc)
80
+ {
81
+ return $doc->getAttribute('title');
82
+
83
+ }//end getTitle()
84
+
85
+
86
+ /**
87
+ * Retrieves the name of the standard we are generating docs for.
88
+ *
89
+ * @return string
90
+ */
91
+ protected function getStandard()
92
+ {
93
+ return $this->_standard;
94
+
95
+ }//end getStandard()
96
+
97
+
98
+ /**
99
+ * Generates the documentation for a standard.
100
+ *
101
+ * It's probably wise for doc generators to override this method so they
102
+ * have control over how the docs are produced. Otherwise, the processSniff
103
+ * method should be overridden to output content for each sniff.
104
+ *
105
+ * @return void
106
+ * @see processSniff()
107
+ */
108
+ public function generate()
109
+ {
110
+ $standardFiles = $this->getStandardFiles();
111
+
112
+ foreach ($standardFiles as $standard) {
113
+ $doc = new DOMDocument();
114
+ $doc->load($standard);
115
+ $documentation = $doc->getElementsByTagName('documentation')->item(0);
116
+ $this->processSniff($documentation);
117
+ }
118
+
119
+ }//end generate()
120
+
121
+
122
+ /**
123
+ * Returns a list of paths to XML standard files for all sniffs in a standard.
124
+ *
125
+ * Any sniffs that do not have an XML standard file are obviously not included
126
+ * in the returned array. If documentation is only being generated for some
127
+ * sniffs (ie. $this->_sniffs is not empty) then all others sniffs will
128
+ * be filtered from the results as well.
129
+ *
130
+ * @return string[]
131
+ */
132
+ protected function getStandardFiles()
133
+ {
134
+ $phpcs = new PHP_CodeSniffer();
135
+ $phpcs->process(array(), $this->_standard);
136
+ $sniffs = $phpcs->getSniffs();
137
+
138
+ $standardFiles = array();
139
+ foreach ($sniffs as $className => $sniffClass) {
140
+ $object = new ReflectionObject($sniffClass);
141
+ $sniff = $object->getFilename();
142
+ if (empty($this->_sniffs) === false) {
143
+ // We are limiting the docs to certain sniffs only, so filter
144
+ // out any unwanted sniffs.
145
+ $parts = explode('_', $className);
146
+ $sniffName = $parts[0].'.'.$parts[2].'.'.substr($parts[3], 0, -5);
147
+ if (in_array($sniffName, $this->_sniffs) === false) {
148
+ continue;
149
+ }
150
+ }
151
+
152
+ $standardFile = str_replace(
153
+ DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR,
154
+ DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR,
155
+ $sniff
156
+ );
157
+ $standardFile = str_replace('Sniff.php', 'Standard.xml', $standardFile);
158
+
159
+ if (is_file($standardFile) === true) {
160
+ $standardFiles[] = $standardFile;
161
+ }
162
+ }//end foreach
163
+
164
+ return $standardFiles;
165
+
166
+ }//end getStandardFiles()
167
+
168
+
169
+ /**
170
+ * Process the documentation for a single sniff.
171
+ *
172
+ * Doc generators must implement this function to produce output.
173
+ *
174
+ * @param DOMNode $doc The DOMNode object for the sniff.
175
+ * It represents the "documentation" tag in the XML
176
+ * standard file.
177
+ *
178
+ * @return void
179
+ * @see generate()
180
+ */
181
+ protected abstract function processSniff(DOMNode $doc);
182
+
183
+
184
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/HTML.php ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A doc generator that outputs documentation in one big HTML file.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Greg Sherwood <gsherwood@squiz.net>
10
+ * @author Marc McIntyre <mmcintyre@squiz.net>
11
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
+ * @link http://pear.php.net/package/PHP_CodeSniffer
14
+ */
15
+
16
+ if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
17
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
18
+ }
19
+
20
+ /**
21
+ * A doc generator that outputs documentation in one big HTML file.
22
+ *
23
+ * Output is in one large HTML file and is designed for you to style with
24
+ * your own stylesheet. It contains a table of contents at the top with anchors
25
+ * to each sniff.
26
+ *
27
+ * @category PHP
28
+ * @package PHP_CodeSniffer
29
+ * @author Greg Sherwood <gsherwood@squiz.net>
30
+ * @author Marc McIntyre <mmcintyre@squiz.net>
31
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
32
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
33
+ * @version Release: @package_version@
34
+ * @link http://pear.php.net/package/PHP_CodeSniffer
35
+ */
36
+ class PHP_CodeSniffer_DocGenerators_HTML extends PHP_CodeSniffer_DocGenerators_Generator
37
+ {
38
+
39
+
40
+ /**
41
+ * Generates the documentation for a standard.
42
+ *
43
+ * @return void
44
+ * @see processSniff()
45
+ */
46
+ public function generate()
47
+ {
48
+ ob_start();
49
+ $this->printHeader();
50
+
51
+ $standardFiles = $this->getStandardFiles();
52
+ $this->printToc($standardFiles);
53
+
54
+ foreach ($standardFiles as $standard) {
55
+ $doc = new DOMDocument();
56
+ $doc->load($standard);
57
+ $documentation = $doc->getElementsByTagName('documentation')->item(0);
58
+ $this->processSniff($documentation);
59
+ }
60
+
61
+ $this->printFooter();
62
+
63
+ $content = ob_get_contents();
64
+ ob_end_clean();
65
+
66
+ echo $content;
67
+
68
+ }//end generate()
69
+
70
+
71
+ /**
72
+ * Print the header of the HTML page.
73
+ *
74
+ * @return void
75
+ */
76
+ protected function printHeader()
77
+ {
78
+ $standard = $this->getStandard();
79
+ echo '<html>'.PHP_EOL;
80
+ echo ' <head>'.PHP_EOL;
81
+ echo " <title>$standard Coding Standards</title>".PHP_EOL;
82
+ echo ' <style>
83
+ body {
84
+ background-color: #FFFFFF;
85
+ font-size: 14px;
86
+ font-family: Arial, Helvetica, sans-serif;
87
+ color: #000000;
88
+ }
89
+
90
+ h1 {
91
+ color: #666666;
92
+ font-size: 20px;
93
+ font-weight: bold;
94
+ margin-top: 0px;
95
+ background-color: #E6E7E8;
96
+ padding: 20px;
97
+ border: 1px solid #BBBBBB;
98
+ }
99
+
100
+ h2 {
101
+ color: #00A5E3;
102
+ font-size: 16px;
103
+ font-weight: normal;
104
+ margin-top: 50px;
105
+ }
106
+
107
+ .code-comparison {
108
+ width: 100%;
109
+ }
110
+
111
+ .code-comparison td {
112
+ border: 1px solid #CCCCCC;
113
+ }
114
+
115
+ .code-comparison-title, .code-comparison-code {
116
+ font-family: Arial, Helvetica, sans-serif;
117
+ font-size: 12px;
118
+ color: #000000;
119
+ vertical-align: top;
120
+ padding: 4px;
121
+ width: 50%;
122
+ background-color: #F1F1F1;
123
+ line-height: 15px;
124
+ }
125
+
126
+ .code-comparison-code {
127
+ font-family: Courier;
128
+ background-color: #F9F9F9;
129
+ }
130
+
131
+ .code-comparison-highlight {
132
+ background-color: #DDF1F7;
133
+ border: 1px solid #00A5E3;
134
+ line-height: 15px;
135
+ }
136
+
137
+ .tag-line {
138
+ text-align: center;
139
+ width: 100%;
140
+ margin-top: 30px;
141
+ font-size: 12px;
142
+ }
143
+
144
+ .tag-line a {
145
+ color: #000000;
146
+ }
147
+ </style>'.PHP_EOL;
148
+ echo ' </head>'.PHP_EOL;
149
+ echo ' <body>'.PHP_EOL;
150
+ echo " <h1>$standard Coding Standards</h1>".PHP_EOL;
151
+
152
+ }//end printHeader()
153
+
154
+
155
+ /**
156
+ * Print the table of contents for the standard.
157
+ *
158
+ * The TOC is just an unordered list of bookmarks to sniffs on the page.
159
+ *
160
+ * @param array $standardFiles An array of paths to the XML standard files.
161
+ *
162
+ * @return void
163
+ */
164
+ protected function printToc($standardFiles)
165
+ {
166
+ echo ' <h2>Table of Contents</h2>'.PHP_EOL;
167
+ echo ' <ul class="toc">'.PHP_EOL;
168
+
169
+ foreach ($standardFiles as $standard) {
170
+ $doc = new DOMDocument();
171
+ $doc->load($standard);
172
+ $documentation = $doc->getElementsByTagName('documentation')->item(0);
173
+ $title = $this->getTitle($documentation);
174
+ echo ' <li><a href="#'.str_replace(' ', '-', $title)."\">$title</a></li>".PHP_EOL;
175
+ }
176
+
177
+ echo ' </ul>'.PHP_EOL;
178
+
179
+ }//end printToc()
180
+
181
+
182
+ /**
183
+ * Print the footer of the HTML page.
184
+ *
185
+ * @return void
186
+ */
187
+ protected function printFooter()
188
+ {
189
+ // Turn off errors so we don't get timezone warnings if people
190
+ // don't have their timezone set.
191
+ $errorLevel = error_reporting(0);
192
+ echo ' <div class="tag-line">';
193
+ echo 'Documentation generated on '.date('r');
194
+ echo ' by <a href="https://github.com/squizlabs/PHP_CodeSniffer">PHP_CodeSniffer '.PHP_CodeSniffer::VERSION.'</a>';
195
+ echo '</div>'.PHP_EOL;
196
+ error_reporting($errorLevel);
197
+
198
+ echo ' </body>'.PHP_EOL;
199
+ echo '</html>'.PHP_EOL;
200
+
201
+ }//end printFooter()
202
+
203
+
204
+ /**
205
+ * Process the documentation for a single sniff.
206
+ *
207
+ * @param DOMNode $doc The DOMNode object for the sniff.
208
+ * It represents the "documentation" tag in the XML
209
+ * standard file.
210
+ *
211
+ * @return void
212
+ */
213
+ public function processSniff(DOMNode $doc)
214
+ {
215
+ $title = $this->getTitle($doc);
216
+ echo ' <a name="'.str_replace(' ', '-', $title).'" />'.PHP_EOL;
217
+ echo " <h2>$title</h2>".PHP_EOL;
218
+
219
+ foreach ($doc->childNodes as $node) {
220
+ if ($node->nodeName === 'standard') {
221
+ $this->printTextBlock($node);
222
+ } else if ($node->nodeName === 'code_comparison') {
223
+ $this->printCodeComparisonBlock($node);
224
+ }
225
+ }
226
+
227
+ }//end processSniff()
228
+
229
+
230
+ /**
231
+ * Print a text block found in a standard.
232
+ *
233
+ * @param DOMNode $node The DOMNode object for the text block.
234
+ *
235
+ * @return void
236
+ */
237
+ protected function printTextBlock($node)
238
+ {
239
+ $content = trim($node->nodeValue);
240
+ $content = htmlspecialchars($content);
241
+
242
+ // Allow em tags only.
243
+ $content = str_replace('&lt;em&gt;', '<em>', $content);
244
+ $content = str_replace('&lt;/em&gt;', '</em>', $content);
245
+
246
+ echo " <p class=\"text\">$content</p>".PHP_EOL;
247
+
248
+ }//end printTextBlock()
249
+
250
+
251
+ /**
252
+ * Print a code comparison block found in a standard.
253
+ *
254
+ * @param DOMNode $node The DOMNode object for the code comparison block.
255
+ *
256
+ * @return void
257
+ */
258
+ protected function printCodeComparisonBlock($node)
259
+ {
260
+ $codeBlocks = $node->getElementsByTagName('code');
261
+
262
+ $firstTitle = $codeBlocks->item(0)->getAttribute('title');
263
+ $first = trim($codeBlocks->item(0)->nodeValue);
264
+ $first = str_replace('<?php', '&lt;?php', $first);
265
+ $first = str_replace("\n", '</br>', $first);
266
+ $first = str_replace(' ', '&nbsp;', $first);
267
+ $first = str_replace('<em>', '<span class="code-comparison-highlight">', $first);
268
+ $first = str_replace('</em>', '</span>', $first);
269
+
270
+ $secondTitle = $codeBlocks->item(1)->getAttribute('title');
271
+ $second = trim($codeBlocks->item(1)->nodeValue);
272
+ $second = str_replace('<?php', '&lt;?php', $second);
273
+ $second = str_replace("\n", '</br>', $second);
274
+ $second = str_replace(' ', '&nbsp;', $second);
275
+ $second = str_replace('<em>', '<span class="code-comparison-highlight">', $second);
276
+ $second = str_replace('</em>', '</span>', $second);
277
+
278
+ echo ' <table class="code-comparison">'.PHP_EOL;
279
+ echo ' <tr>'.PHP_EOL;
280
+ echo " <td class=\"code-comparison-title\">$firstTitle</td>".PHP_EOL;
281
+ echo " <td class=\"code-comparison-title\">$secondTitle</td>".PHP_EOL;
282
+ echo ' </tr>'.PHP_EOL;
283
+ echo ' <tr>'.PHP_EOL;
284
+ echo " <td class=\"code-comparison-code\">$first</td>".PHP_EOL;
285
+ echo " <td class=\"code-comparison-code\">$second</td>".PHP_EOL;
286
+ echo ' </tr>'.PHP_EOL;
287
+ echo ' </table>'.PHP_EOL;
288
+
289
+ }//end printCodeComparisonBlock()
290
+
291
+
292
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Markdown.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A doc generator that outputs documentation in Markdown format.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Stefano Kowalke <blueduck@gmx.net>
10
+ * @copyright 2014 Arroba IT
11
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12
+ * @link http://pear.php.net/package/PHP_CodeSniffer
13
+ */
14
+
15
+ if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
16
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
17
+ }
18
+
19
+ /**
20
+ * A doc generator that outputs documentation in Markdown format.
21
+ *
22
+ * @category PHP
23
+ * @package PHP_CodeSniffer
24
+ * @author Stefano Kowalke <blueduck@gmx.net>
25
+ * @copyright 2014 Arroba IT
26
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
27
+ * @version Release: @package_version@
28
+ * @link http://pear.php.net/package/PHP_CodeSniffer
29
+ */
30
+ class PHP_CodeSniffer_DocGenerators_Markdown extends PHP_CodeSniffer_DocGenerators_Generator
31
+ {
32
+
33
+
34
+ /**
35
+ * Generates the documentation for a standard.
36
+ *
37
+ * @return void
38
+ * @see processSniff()
39
+ */
40
+ public function generate()
41
+ {
42
+ ob_start();
43
+ $this->printHeader();
44
+
45
+ $standardFiles = $this->getStandardFiles();
46
+
47
+ foreach ($standardFiles as $standard) {
48
+ $doc = new DOMDocument();
49
+ $doc->load($standard);
50
+ $documentation = $doc->getElementsByTagName('documentation')->item(0);
51
+ $this->processSniff($documentation);
52
+ }
53
+
54
+ $this->printFooter();
55
+ $content = ob_get_contents();
56
+ ob_end_clean();
57
+
58
+ echo $content;
59
+
60
+ }//end generate()
61
+
62
+
63
+ /**
64
+ * Print the markdown header.
65
+ *
66
+ * @return void
67
+ */
68
+ protected function printHeader()
69
+ {
70
+ $standard = $this->getStandard();
71
+
72
+ echo "# $standard Coding Standard".PHP_EOL;
73
+
74
+ }//end printHeader()
75
+
76
+
77
+ /**
78
+ * Print the markdown footer.
79
+ *
80
+ * @return void
81
+ */
82
+ protected function printFooter()
83
+ {
84
+ // Turn off errors so we don't get timezone warnings if people
85
+ // don't have their timezone set.
86
+ error_reporting(0);
87
+ echo 'Documentation generated on '.date('r');
88
+ echo ' by [PHP_CodeSniffer '.PHP_CodeSniffer::VERSION.'](https://github.com/squizlabs/PHP_CodeSniffer)';
89
+
90
+ }//end printFooter()
91
+
92
+
93
+ /**
94
+ * Process the documentation for a single sniff.
95
+ *
96
+ * @param DOMNode $doc The DOMNode object for the sniff.
97
+ * It represents the "documentation" tag in the XML
98
+ * standard file.
99
+ *
100
+ * @return void
101
+ */
102
+ protected function processSniff(DOMNode $doc)
103
+ {
104
+ $title = $this->getTitle($doc);
105
+ echo "## $title".PHP_EOL;
106
+
107
+ foreach ($doc->childNodes as $node) {
108
+ if ($node->nodeName === 'standard') {
109
+ $this->printTextBlock($node);
110
+ } else if ($node->nodeName === 'code_comparison') {
111
+ $this->printCodeComparisonBlock($node);
112
+ }
113
+ }
114
+
115
+ }//end processSniff()
116
+
117
+
118
+ /**
119
+ * Print a text block found in a standard.
120
+ *
121
+ * @param DOMNode $node The DOMNode object for the text block.
122
+ *
123
+ * @return void
124
+ */
125
+ protected function printTextBlock(DOMNode $node)
126
+ {
127
+ $content = trim($node->nodeValue);
128
+ $content = htmlspecialchars($content);
129
+
130
+ $content = str_replace('&lt;em&gt;', '*', $content);
131
+ $content = str_replace('&lt;/em&gt;', '*', $content);
132
+
133
+ echo $content.PHP_EOL;
134
+
135
+ }//end printTextBlock()
136
+
137
+
138
+ /**
139
+ * Print a code comparison block found in a standard.
140
+ *
141
+ * @param DOMNode $node The DOMNode object for the code comparison block.
142
+ *
143
+ * @return void
144
+ */
145
+ protected function printCodeComparisonBlock(DOMNode $node)
146
+ {
147
+ $codeBlocks = $node->getElementsByTagName('code');
148
+
149
+ $firstTitle = $codeBlocks->item(0)->getAttribute('title');
150
+ $first = trim($codeBlocks->item(0)->nodeValue);
151
+ $first = str_replace("\n", "\n ", $first);
152
+ $first = str_replace('<em>', '', $first);
153
+ $first = str_replace('</em>', '', $first);
154
+
155
+ $secondTitle = $codeBlocks->item(1)->getAttribute('title');
156
+ $second = trim($codeBlocks->item(1)->nodeValue);
157
+ $second = str_replace("\n", "\n ", $second);
158
+ $second = str_replace('<em>', '', $second);
159
+ $second = str_replace('</em>', '', $second);
160
+
161
+ echo ' <table>'.PHP_EOL;
162
+ echo ' <tr>'.PHP_EOL;
163
+ echo " <th>$firstTitle</th>".PHP_EOL;
164
+ echo " <th>$secondTitle</th>".PHP_EOL;
165
+ echo ' </tr>'.PHP_EOL;
166
+ echo ' <tr>'.PHP_EOL;
167
+ echo '<td>'.PHP_EOL.PHP_EOL;
168
+ echo " $first".PHP_EOL.PHP_EOL;
169
+ echo '</td>'.PHP_EOL;
170
+ echo '<td>'.PHP_EOL.PHP_EOL;
171
+ echo " $second".PHP_EOL.PHP_EOL;
172
+ echo '</td>'.PHP_EOL;
173
+ echo ' </tr>'.PHP_EOL;
174
+ echo ' </table>'.PHP_EOL;
175
+
176
+ }//end printCodeComparisonBlock()
177
+
178
+
179
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/DocGenerators/Text.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A doc generator that outputs text-based documentation.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Greg Sherwood <gsherwood@squiz.net>
10
+ * @author Marc McIntyre <mmcintyre@squiz.net>
11
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
+ * @link http://pear.php.net/package/PHP_CodeSniffer
14
+ */
15
+
16
+ if (class_exists('PHP_CodeSniffer_DocGenerators_Generator', true) === false) {
17
+ throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_DocGenerators_Generator not found');
18
+ }
19
+
20
+ /**
21
+ * A doc generator that outputs text-based documentation.
22
+ *
23
+ * Output is designed to be displayed in a terminal and is wrapped to 100 characters.
24
+ *
25
+ * @category PHP
26
+ * @package PHP_CodeSniffer
27
+ * @author Greg Sherwood <gsherwood@squiz.net>
28
+ * @author Marc McIntyre <mmcintyre@squiz.net>
29
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
30
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
31
+ * @version Release: @package_version@
32
+ * @link http://pear.php.net/package/PHP_CodeSniffer
33
+ */
34
+ class PHP_CodeSniffer_DocGenerators_Text extends PHP_CodeSniffer_DocGenerators_Generator
35
+ {
36
+
37
+
38
+ /**
39
+ * Process the documentation for a single sniff.
40
+ *
41
+ * @param DOMNode $doc The DOMNode object for the sniff.
42
+ * It represents the "documentation" tag in the XML
43
+ * standard file.
44
+ *
45
+ * @return void
46
+ */
47
+ public function processSniff(DOMNode $doc)
48
+ {
49
+ $this->printTitle($doc);
50
+
51
+ foreach ($doc->childNodes as $node) {
52
+ if ($node->nodeName === 'standard') {
53
+ $this->printTextBlock($node);
54
+ } else if ($node->nodeName === 'code_comparison') {
55
+ $this->printCodeComparisonBlock($node);
56
+ }
57
+ }
58
+
59
+ }//end processSniff()
60
+
61
+
62
+ /**
63
+ * Prints the title area for a single sniff.
64
+ *
65
+ * @param DOMNode $doc The DOMNode object for the sniff.
66
+ * It represents the "documentation" tag in the XML
67
+ * standard file.
68
+ *
69
+ * @return void
70
+ */
71
+ protected function printTitle(DOMNode $doc)
72
+ {
73
+ $title = $this->getTitle($doc);
74
+ $standard = $this->getStandard();
75
+
76
+ echo PHP_EOL;
77
+ echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4));
78
+ echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL);
79
+ echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4));
80
+ echo PHP_EOL.PHP_EOL;
81
+
82
+ }//end printTitle()
83
+
84
+
85
+ /**
86
+ * Print a text block found in a standard.
87
+ *
88
+ * @param DOMNode $node The DOMNode object for the text block.
89
+ *
90
+ * @return void
91
+ */
92
+ protected function printTextBlock($node)
93
+ {
94
+ $text = trim($node->nodeValue);
95
+ $text = str_replace('<em>', '*', $text);
96
+ $text = str_replace('</em>', '*', $text);
97
+
98
+ $lines = array();
99
+ $tempLine = '';
100
+ $words = explode(' ', $text);
101
+
102
+ foreach ($words as $word) {
103
+ if (strlen($tempLine.$word) >= 99) {
104
+ if (strlen($tempLine.$word) === 99) {
105
+ // Adding the extra space will push us to the edge
106
+ // so we are done.
107
+ $lines[] = $tempLine.$word;
108
+ $tempLine = '';
109
+ } else if (strlen($tempLine.$word) === 100) {
110
+ // We are already at the edge, so we are done.
111
+ $lines[] = $tempLine.$word;
112
+ $tempLine = '';
113
+ } else {
114
+ $lines[] = rtrim($tempLine);
115
+ $tempLine = $word.' ';
116
+ }
117
+ } else {
118
+ $tempLine .= $word.' ';
119
+ }
120
+ }//end foreach
121
+
122
+ if ($tempLine !== '') {
123
+ $lines[] = rtrim($tempLine);
124
+ }
125
+
126
+ echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL;
127
+
128
+ }//end printTextBlock()
129
+
130
+
131
+ /**
132
+ * Print a code comparison block found in a standard.
133
+ *
134
+ * @param DOMNode $node The DOMNode object for the code comparison block.
135
+ *
136
+ * @return void
137
+ */
138
+ protected function printCodeComparisonBlock($node)
139
+ {
140
+ $codeBlocks = $node->getElementsByTagName('code');
141
+ $first = trim($codeBlocks->item(0)->nodeValue);
142
+ $firstTitle = $codeBlocks->item(0)->getAttribute('title');
143
+
144
+ $firstTitleLines = array();
145
+ $tempTitle = '';
146
+ $words = explode(' ', $firstTitle);
147
+
148
+ foreach ($words as $word) {
149
+ if (strlen($tempTitle.$word) >= 45) {
150
+ if (strlen($tempTitle.$word) === 45) {
151
+ // Adding the extra space will push us to the edge
152
+ // so we are done.
153
+ $firstTitleLines[] = $tempTitle.$word;
154
+ $tempTitle = '';
155
+ } else if (strlen($tempTitle.$word) === 46) {
156
+ // We are already at the edge, so we are done.
157
+ $firstTitleLines[] = $tempTitle.$word;
158
+ $tempTitle = '';
159
+ } else {
160
+ $firstTitleLines[] = $tempTitle;
161
+ $tempTitle = $word;
162
+ }
163
+ } else {
164
+ $tempTitle .= $word.' ';
165
+ }
166
+ }//end foreach
167
+
168
+ if ($tempTitle !== '') {
169
+ $firstTitleLines[] = $tempTitle;
170
+ }
171
+
172
+ $first = str_replace('<em>', '', $first);
173
+ $first = str_replace('</em>', '', $first);
174
+ $firstLines = explode("\n", $first);
175
+
176
+ $second = trim($codeBlocks->item(1)->nodeValue);
177
+ $secondTitle = $codeBlocks->item(1)->getAttribute('title');
178
+
179
+ $secondTitleLines = array();
180
+ $tempTitle = '';
181
+ $words = explode(' ', $secondTitle);
182
+
183
+ foreach ($words as $word) {
184
+ if (strlen($tempTitle.$word) >= 45) {
185
+ if (strlen($tempTitle.$word) === 45) {
186
+ // Adding the extra space will push us to the edge
187
+ // so we are done.
188
+ $secondTitleLines[] = $tempTitle.$word;
189
+ $tempTitle = '';
190
+ } else if (strlen($tempTitle.$word) === 46) {
191
+ // We are already at the edge, so we are done.
192
+ $secondTitleLines[] = $tempTitle.$word;
193
+ $tempTitle = '';
194
+ } else {
195
+ $secondTitleLines[] = $tempTitle;
196
+ $tempTitle = $word;
197
+ }
198
+ } else {
199
+ $tempTitle .= $word.' ';
200
+ }
201
+ }//end foreach
202
+
203
+ if ($tempTitle !== '') {
204
+ $secondTitleLines[] = $tempTitle;
205
+ }
206
+
207
+ $second = str_replace('<em>', '', $second);
208
+ $second = str_replace('</em>', '', $second);
209
+ $secondLines = explode("\n", $second);
210
+
211
+ $maxCodeLines = max(count($firstLines), count($secondLines));
212
+ $maxTitleLines = max(count($firstTitleLines), count($secondTitleLines));
213
+
214
+ echo str_repeat('-', 41);
215
+ echo ' CODE COMPARISON ';
216
+ echo str_repeat('-', 42).PHP_EOL;
217
+
218
+ for ($i = 0; $i < $maxTitleLines; $i++) {
219
+ if (isset($firstTitleLines[$i]) === true) {
220
+ $firstLineText = $firstTitleLines[$i];
221
+ } else {
222
+ $firstLineText = '';
223
+ }
224
+
225
+ if (isset($secondTitleLines[$i]) === true) {
226
+ $secondLineText = $secondTitleLines[$i];
227
+ } else {
228
+ $secondLineText = '';
229
+ }
230
+
231
+ echo '| ';
232
+ echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText)));
233
+ echo ' | ';
234
+ echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText)));
235
+ echo ' |'.PHP_EOL;
236
+ }//end for
237
+
238
+ echo str_repeat('-', 100).PHP_EOL;
239
+
240
+ for ($i = 0; $i < $maxCodeLines; $i++) {
241
+ if (isset($firstLines[$i]) === true) {
242
+ $firstLineText = $firstLines[$i];
243
+ } else {
244
+ $firstLineText = '';
245
+ }
246
+
247
+ if (isset($secondLines[$i]) === true) {
248
+ $secondLineText = $secondLines[$i];
249
+ } else {
250
+ $secondLineText = '';
251
+ }
252
+
253
+ echo '| ';
254
+ echo $firstLineText.str_repeat(' ', (47 - strlen($firstLineText)));
255
+ echo '| ';
256
+ echo $secondLineText.str_repeat(' ', (48 - strlen($secondLineText)));
257
+ echo '|'.PHP_EOL;
258
+ }//end for
259
+
260
+ echo str_repeat('-', 100).PHP_EOL.PHP_EOL;
261
+
262
+ }//end printCodeComparisonBlock()
263
+
264
+
265
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/Exception.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error.
4
+ *
5
+ * PHP version 5
6
+ *
7
+ * @category PHP
8
+ * @package PHP_CodeSniffer
9
+ * @author Greg Sherwood <gsherwood@squiz.net>
10
+ * @author Marc McIntyre <mmcintyre@squiz.net>
11
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
+ * @link http://pear.php.net/package/PHP_CodeSniffer
14
+ */
15
+
16
+ /**
17
+ * An exception thrown by PHP_CodeSniffer when it encounters an unrecoverable error.
18
+ *
19
+ * @category PHP
20
+ * @package PHP_CodeSniffer
21
+ * @author Greg Sherwood <gsherwood@squiz.net>
22
+ * @author Marc McIntyre <mmcintyre@squiz.net>
23
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
24
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
25
+ * @version Release: @package_version@
26
+ * @link http://pear.php.net/package/PHP_CodeSniffer
27
+ */
28
+ class PHP_CodeSniffer_Exception extends Exception
29
+ {
30
+
31
+ }//end class
vendor/squizlabs/php_codesniffer/CodeSniffer/File.php ADDED
@@ -0,0 +1,3814 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A PHP_CodeSniffer_File object represents a PHP source file and the tokens
4
+ * associated with it.
5
+ *
6
+ * PHP version 5
7
+ *
8
+ * @category PHP
9
+ * @package PHP_CodeSniffer
10
+ * @author Greg Sherwood <gsherwood@squiz.net>
11
+ * @author Marc McIntyre <mmcintyre@squiz.net>
12
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
13
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
14
+ * @link http://pear.php.net/package/PHP_CodeSniffer
15
+ */
16
+
17
+ /**
18
+ * A PHP_CodeSniffer_File object represents a PHP source file and the tokens
19
+ * associated with it.
20
+ *
21
+ * It provides a means for traversing the token stack, along with
22
+ * other token related operations. If a PHP_CodeSniffer_Sniff finds and error or
23
+ * warning within a PHP_CodeSniffer_File, you can raise an error using the
24
+ * addError() or addWarning() methods.
25
+ *
26
+ * <b>Token Information</b>
27
+ *
28
+ * Each token within the stack contains information about itself:
29
+ *
30
+ * <code>
31
+ * array(
32
+ * 'code' => 301, // the token type code (see token_get_all())
33
+ * 'content' => 'if', // the token content
34
+ * 'type' => 'T_IF', // the token name
35
+ * 'line' => 56, // the line number when the token is located
36
+ * 'column' => 12, // the column in the line where this token
37
+ * // starts (starts from 1)
38
+ * 'level' => 2 // the depth a token is within the scopes open
39
+ * 'conditions' => array( // a list of scope condition token
40
+ * // positions => codes that
41
+ * 2 => 50, // opened the scopes that this token exists
42
+ * 9 => 353, // in (see conditional tokens section below)
43
+ * ),
44
+ * );
45
+ * </code>
46
+ *
47
+ * <b>Conditional Tokens</b>
48
+ *
49
+ * In addition to the standard token fields, conditions contain information to
50
+ * determine where their scope begins and ends:
51
+ *
52
+ * <code>
53
+ * array(
54
+ * 'scope_condition' => 38, // the token position of the condition
55
+ * 'scope_opener' => 41, // the token position that started the scope
56
+ * 'scope_closer' => 70, // the token position that ended the scope
57
+ * );
58
+ * </code>
59
+ *
60
+ * The condition, the scope opener and the scope closer each contain this
61
+ * information.
62
+ *
63
+ * <b>Parenthesis Tokens</b>
64
+ *
65
+ * Each parenthesis token (T_OPEN_PARENTHESIS and T_CLOSE_PARENTHESIS) has a
66
+ * reference to their opening and closing parenthesis, one being itself, the
67
+ * other being its opposite.
68
+ *
69
+ * <code>
70
+ * array(
71
+ * 'parenthesis_opener' => 34,
72
+ * 'parenthesis_closer' => 40,
73
+ * );
74
+ * </code>
75
+ *
76
+ * Some tokens can "own" a set of parenthesis. For example a T_FUNCTION token
77
+ * has parenthesis around its argument list. These tokens also have the
78
+ * parenthesis_opener and and parenthesis_closer indices. Not all parenthesis
79
+ * have owners, for example parenthesis used for arithmetic operations and
80
+ * function calls. The parenthesis tokens that have an owner have the following
81
+ * auxiliary array indices.
82
+ *
83
+ * <code>
84
+ * array(
85
+ * 'parenthesis_opener' => 34,
86
+ * 'parenthesis_closer' => 40,
87
+ * 'parenthesis_owner' => 33,
88
+ * );
89
+ * </code>
90
+ *
91
+ * Each token within a set of parenthesis also has an array index
92
+ * 'nested_parenthesis' which is an array of the
93
+ * left parenthesis => right parenthesis token positions.
94
+ *
95
+ * <code>
96
+ * 'nested_parenthesis' => array(
97
+ * 12 => 15
98
+ * 11 => 14
99
+ * );
100
+ * </code>
101
+ *
102
+ * <b>Extended Tokens</b>
103
+ *
104
+ * PHP_CodeSniffer extends and augments some of the tokens created by
105
+ * <i>token_get_all()</i>. A full list of these tokens can be seen in the
106
+ * <i>Tokens.php</i> file.
107
+ *
108
+ * @category PHP
109
+ * @package PHP_CodeSniffer
110
+ * @author Greg Sherwood <gsherwood@squiz.net>
111
+ * @author Marc McIntyre <mmcintyre@squiz.net>
112
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
113
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
114
+ * @version Release: @package_version@
115
+ * @link http://pear.php.net/package/PHP_CodeSniffer
116
+ */
117
+ class PHP_CodeSniffer_File
118
+ {
119
+
120
+ /**
121
+ * The absolute path to the file associated with this object.
122
+ *
123
+ * @var string
124
+ */
125
+ private $_file = '';
126
+
127
+ /**
128
+ * The EOL character this file uses.
129
+ *
130
+ * @var string
131
+ */
132
+ public $eolChar = '';
133
+
134
+ /**
135
+ * The PHP_CodeSniffer object controlling this run.
136
+ *
137
+ * @var PHP_CodeSniffer
138
+ */
139
+ public $phpcs = null;
140
+
141
+ /**
142
+ * The Fixer object to control fixing errors.
143
+ *
144
+ * @var PHP_CodeSniffer_Fixer
145
+ */
146
+ public $fixer = null;
147
+
148
+ /**
149
+ * The tokenizer being used for this file.
150
+ *
151
+ * @var object
152
+ */
153
+ public $tokenizer = null;
154
+
155
+ /**
156
+ * The tokenizer being used for this file.
157
+ *
158
+ * @var string
159
+ */
160
+ public $tokenizerType = 'PHP';
161
+
162
+ /**
163
+ * The number of tokens in this file.
164
+ *
165
+ * Stored here to save calling count() everywhere.
166
+ *
167
+ * @var int
168
+ */
169
+ public $numTokens = 0;
170
+
171
+ /**
172
+ * The tokens stack map.
173
+ *
174
+ * Note that the tokens in this array differ in format to the tokens
175
+ * produced by token_get_all(). Tokens are initially produced with
176
+ * token_get_all(), then augmented so that it's easier to process them.
177
+ *
178
+ * @var array()
179
+ * @see Tokens.php
180
+ */
181
+ private $_tokens = array();
182
+
183
+ /**
184
+ * The errors raised from PHP_CodeSniffer_Sniffs.
185
+ *
186
+ * @var array()
187
+ * @see getErrors()
188
+ */
189
+ private $_errors = array();
190
+
191
+ /**
192
+ * The warnings raised from PHP_CodeSniffer_Sniffs.
193
+ *
194
+ * @var array()
195
+ * @see getWarnings()
196
+ */
197
+ private $_warnings = array();
198
+
199
+ /**
200
+ * The metrics recorded from PHP_CodeSniffer_Sniffs.
201
+ *
202
+ * @var array()
203
+ * @see getMetrics()
204
+ */
205
+ private $_metrics = array();
206
+
207
+ /**
208
+ * Record the errors and warnings raised.
209
+ *
210
+ * @var bool
211
+ */
212
+ private $_recordErrors = true;
213
+
214
+ /**
215
+ * An array of lines that are being ignored.
216
+ *
217
+ * @var array()
218
+ */
219
+ private static $_ignoredLines = array();
220
+
221
+ /**
222
+ * An array of sniffs that are being ignored.
223
+ *
224
+ * @var array()
225
+ */
226
+ private $_ignoredListeners = array();
227
+
228
+ /**
229
+ * An array of message codes that are being ignored.
230
+ *
231
+ * @var array()
232
+ */
233
+ private $_ignoredCodes = array();
234
+
235
+ /**
236
+ * The total number of errors raised.
237
+ *
238
+ * @var int
239
+ */
240
+ private $_errorCount = 0;
241
+
242
+ /**
243
+ * The total number of warnings raised.
244
+ *
245
+ * @var int
246
+ */
247
+ private $_warningCount = 0;
248
+
249
+ /**
250
+ * The total number of errors/warnings that can be fixed.
251
+ *
252
+ * @var int
253
+ */
254
+ private $_fixableCount = 0;
255
+
256
+ /**
257
+ * An array of sniffs listening to this file's processing.
258
+ *
259
+ * @var array(PHP_CodeSniffer_Sniff)
260
+ */
261
+ private $_listeners = array();
262
+
263
+ /**
264
+ * The class name of the sniff currently processing the file.
265
+ *
266
+ * @var string
267
+ */
268
+ private $_activeListener = '';
269
+
270
+ /**
271
+ * An array of sniffs being processed and how long they took.
272
+ *
273
+ * @var array()
274
+ */
275
+ private $_listenerTimes = array();
276
+
277
+ /**
278
+ * An array of rules from the ruleset.xml file.
279
+ *
280
+ * This value gets set by PHP_CodeSniffer when the object is created.
281
+ * It may be empty, indicating that the ruleset does not override
282
+ * any of the default sniff settings.
283
+ *
284
+ * @var array
285
+ */
286
+ protected $ruleset = array();
287
+
288
+
289
+ /**
290
+ * Constructs a PHP_CodeSniffer_File.
291
+ *
292
+ * @param string $file The absolute path to the file to process.
293
+ * @param array(string) $listeners The initial listeners listening to processing of this file.
294
+ * to processing of this file.
295
+ * @param array $ruleset An array of rules from the ruleset.xml file.
296
+ * ruleset.xml file.
297
+ * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object controlling this run.
298
+ * this run.
299
+ *
300
+ * @throws PHP_CodeSniffer_Exception If the register() method does
301
+ * not return an array.
302
+ */
303
+ public function __construct(
304
+ $file,
305
+ array $listeners,
306
+ array $ruleset,
307
+ PHP_CodeSniffer $phpcs
308
+ ) {
309
+ $this->_file = trim($file);
310
+ $this->_listeners = $listeners;
311
+ $this->ruleset = $ruleset;
312
+ $this->phpcs = $phpcs;
313
+ $this->fixer = new PHP_CodeSniffer_Fixer();
314
+
315
+ if (PHP_CODESNIFFER_INTERACTIVE === false) {
316
+ $cliValues = $phpcs->cli->getCommandLineValues();
317
+ if (isset($cliValues['showSources']) === true
318
+ && $cliValues['showSources'] !== true
319
+ ) {
320
+ $recordErrors = false;
321
+ foreach ($cliValues['reports'] as $report => $output) {
322
+ $reportClass = $phpcs->reporting->factory($report);
323
+ if (property_exists($reportClass, 'recordErrors') === false
324
+ || $reportClass->recordErrors === true
325
+ ) {
326
+ $recordErrors = true;
327
+ break;
328
+ }
329
+ }
330
+
331
+ $this->_recordErrors = $recordErrors;
332
+ }
333
+ }
334
+
335
+ }//end __construct()
336
+
337
+
338
+ /**
339
+ * Sets the name of the currently active sniff.
340
+ *
341
+ * @param string $activeListener The class name of the current sniff.
342
+ *
343
+ * @return void
344
+ */
345
+ public function setActiveListener($activeListener)
346
+ {
347
+ $this->_activeListener = $activeListener;
348
+
349
+ }//end setActiveListener()
350
+
351
+
352
+ /**
353
+ * Adds a listener to the token stack that listens to the specific tokens.
354
+ *
355
+ * When PHP_CodeSniffer encounters on the the tokens specified in $tokens,
356
+ * it invokes the process method of the sniff.
357
+ *
358
+ * @param PHP_CodeSniffer_Sniff $listener The listener to add to the
359
+ * listener stack.
360
+ * @param array(int) $tokens The token types the listener wishes to
361
+ * listen to.
362
+ *
363
+ * @return void
364
+ */
365
+ public function addTokenListener(PHP_CodeSniffer_Sniff $listener, array $tokens)
366
+ {
367
+ $class = get_class($listener);
368
+ foreach ($tokens as $token) {
369
+ if (isset($this->_listeners[$token]) === false) {
370
+ $this->_listeners[$token] = array();
371
+ }
372
+
373
+ if (isset($this->_listeners[$token][$class]) === false) {
374
+ $this->_listeners[$token][$class] = $listener;
375
+ }
376
+ }
377
+
378
+ }//end addTokenListener()
379
+
380
+
381
+ /**
382
+ * Removes a listener from listening from the specified tokens.
383
+ *
384
+ * @param PHP_CodeSniffer_Sniff $listener The listener to remove from the
385
+ * listener stack.
386
+ * @param array(int) $tokens The token types the listener wishes to
387
+ * stop listen to.
388
+ *
389
+ * @return void
390
+ */
391
+ public function removeTokenListener(
392
+ PHP_CodeSniffer_Sniff $listener,
393
+ array $tokens
394
+ ) {
395
+ $class = get_class($listener);
396
+ foreach ($tokens as $token) {
397
+ if (isset($this->_listeners[$token]) === false) {
398
+ continue;
399
+ }
400
+
401
+ unset($this->_listeners[$token][$class]);
402
+ }
403
+
404
+ }//end removeTokenListener()
405
+
406
+
407
+ /**
408
+ * Rebuilds the list of listeners to ensure their state is cleared.
409
+ *
410
+ * @return void
411
+ */
412
+ public function refreshTokenListeners()
413
+ {
414
+ $this->phpcs->populateTokenListeners();
415
+ $this->_listeners = $this->phpcs->getTokenSniffs();
416
+
417
+ }//end refreshTokenListeners()
418
+
419
+
420
+ /**
421
+ * Returns the token stack for this file.
422
+ *
423
+ * @return array
424
+ */
425
+ public function getTokens()
426
+ {
427
+ return $this->_tokens;
428
+
429
+ }//end getTokens()
430
+
431
+
432
+ /**
433
+ * Starts the stack traversal and tells listeners when tokens are found.
434
+ *
435
+ * @param string $contents The contents to parse. If NULL, the content
436
+ * is taken from the file system.
437
+ *
438
+ * @return void
439
+ */
440
+ public function start($contents=null)
441
+ {
442
+ $this->_errors = array();
443
+ $this->_warnings = array();
444
+ $this->_errorCount = 0;
445
+ $this->_warningCount = 0;
446
+ $this->_fixableCount = 0;
447
+
448
+ // Reset the ignored lines because lines numbers may have changed
449
+ // if we are fixing this file.
450
+ self::$_ignoredLines = array();
451
+
452
+ try {
453
+ $this->eolChar = self::detectLineEndings($this->_file, $contents);
454
+ } catch (PHP_CodeSniffer_Exception $e) {
455
+ $this->addWarning($e->getMessage(), null, 'Internal.DetectLineEndings');
456
+ return;
457
+ }
458
+
459
+ // If this is standard input, see if a filename was passed in as well.
460
+ // This is done by including: phpcs_input_file: [file path]
461
+ // as the first line of content.
462
+ if ($this->_file === 'STDIN') {
463
+ $cliValues = $this->phpcs->cli->getCommandLineValues();
464
+ if ($cliValues['stdinPath'] !== '') {
465
+ $this->_file = $cliValues['stdinPath'];
466
+ } else if ($contents !== null && substr($contents, 0, 17) === 'phpcs_input_file:') {
467
+ $eolPos = strpos($contents, $this->eolChar);
468
+ $filename = trim(substr($contents, 17, ($eolPos - 17)));
469
+ $contents = substr($contents, ($eolPos + strlen($this->eolChar)));
470
+ $this->_file = $filename;
471
+ }
472
+ }
473
+
474
+ $this->_parse($contents);
475
+ $this->fixer->startFile($this);
476
+
477
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
478
+ echo "\t*** START TOKEN PROCESSING ***".PHP_EOL;
479
+ }
480
+
481
+ $foundCode = false;
482
+ $listeners = $this->phpcs->getSniffs();
483
+ $listenerIgnoreTo = array();
484
+ $inTests = defined('PHP_CODESNIFFER_IN_TESTS');
485
+
486
+ // Foreach of the listeners that have registered to listen for this
487
+ // token, get them to process it.
488
+ foreach ($this->_tokens as $stackPtr => $token) {
489
+ // Check for ignored lines.
490
+ if ($token['code'] === T_COMMENT
491
+ || $token['code'] === T_DOC_COMMENT_TAG
492
+ || ($inTests === true && $token['code'] === T_INLINE_HTML)
493
+ ) {
494
+ if (strpos($token['content'], '@codingStandards') !== false) {
495
+ if (strpos($token['content'], '@codingStandardsIgnoreFile') !== false) {
496
+ // Ignoring the whole file, just a little late.
497
+ $this->_errors = array();
498
+ $this->_warnings = array();
499
+ $this->_errorCount = 0;
500
+ $this->_warningCount = 0;
501
+ $this->_fixableCount = 0;
502
+ return;
503
+ } else if (strpos($token['content'], '@codingStandardsChangeSetting') !== false) {
504
+ $start = strpos($token['content'], '@codingStandardsChangeSetting');
505
+ $comment = substr($token['content'], ($start + 30));
506
+ $parts = explode(' ', $comment);
507
+ if (count($parts) >= 3
508
+ && isset($this->phpcs->sniffCodes[$parts[0]]) === true
509
+ ) {
510
+ $listenerCode = array_shift($parts);
511
+ $propertyCode = array_shift($parts);
512
+ $propertyValue = rtrim(implode(' ', $parts), " */\r\n");
513
+ $listenerClass = $this->phpcs->sniffCodes[$listenerCode];
514
+ $this->phpcs->setSniffProperty($listenerClass, $propertyCode, $propertyValue);
515
+ }
516
+ }//end if
517
+ }//end if
518
+ }//end if
519
+
520
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
521
+ $type = $token['type'];
522
+ $content = PHP_CodeSniffer::prepareForOutput($token['content']);
523
+ echo "\t\tProcess token $stackPtr: $type => $content".PHP_EOL;
524
+ }
525
+
526
+ if ($token['code'] !== T_INLINE_HTML) {
527
+ $foundCode = true;
528
+ }
529
+
530
+ if (isset($this->_listeners[$token['code']]) === false) {
531
+ continue;
532
+ }
533
+
534
+ foreach ($this->_listeners[$token['code']] as $listenerData) {
535
+ if (isset($this->_ignoredListeners[$listenerData['class']]) === true
536
+ || (isset($listenerIgnoreTo[$listenerData['class']]) === true
537
+ && $listenerIgnoreTo[$listenerData['class']] > $stackPtr)
538
+ ) {
539
+ // This sniff is ignoring past this token, or the whole file.
540
+ continue;
541
+ }
542
+
543
+ // Make sure this sniff supports the tokenizer
544
+ // we are currently using.
545
+ $class = $listenerData['class'];
546
+
547
+ if (isset($listenerData['tokenizers'][$this->tokenizerType]) === false) {
548
+ continue;
549
+ }
550
+
551
+ // If the file path matches one of our ignore patterns, skip it.
552
+ // While there is support for a type of each pattern
553
+ // (absolute or relative) we don't actually support it here.
554
+ foreach ($listenerData['ignore'] as $pattern) {
555
+ // We assume a / directory separator, as do the exclude rules
556
+ // most developers write, so we need a special case for any system
557
+ // that is different.
558
+ if (DIRECTORY_SEPARATOR === '\\') {
559
+ $pattern = str_replace('/', '\\\\', $pattern);
560
+ }
561
+
562
+ $pattern = '`'.$pattern.'`i';
563
+ if (preg_match($pattern, $this->_file) === 1) {
564
+ $this->_ignoredListeners[$class] = true;
565
+ continue(2);
566
+ }
567
+ }
568
+
569
+ $this->_activeListener = $class;
570
+
571
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
572
+ $startTime = microtime(true);
573
+ echo "\t\t\tProcessing ".$this->_activeListener.'... ';
574
+ }
575
+
576
+ $ignoreTo = $listeners[$class]->process($this, $stackPtr);
577
+ if ($ignoreTo !== null) {
578
+ $listenerIgnoreTo[$this->_activeListener] = $ignoreTo;
579
+ }
580
+
581
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
582
+ $timeTaken = (microtime(true) - $startTime);
583
+ if (isset($this->_listenerTimes[$this->_activeListener]) === false) {
584
+ $this->_listenerTimes[$this->_activeListener] = 0;
585
+ }
586
+
587
+ $this->_listenerTimes[$this->_activeListener] += $timeTaken;
588
+
589
+ $timeTaken = round(($timeTaken), 4);
590
+ echo "DONE in $timeTaken seconds".PHP_EOL;
591
+ }
592
+
593
+ $this->_activeListener = '';
594
+ }//end foreach
595
+ }//end foreach
596
+
597
+ if ($this->_recordErrors === false) {
598
+ $this->_errors = array();
599
+ $this->_warnings = array();
600
+ }
601
+
602
+ // If short open tags are off but the file being checked uses
603
+ // short open tags, the whole content will be inline HTML
604
+ // and nothing will be checked. So try and handle this case.
605
+ // We don't show this error for STDIN because we can't be sure the content
606
+ // actually came directly from the user. It could be something like
607
+ // refs from a Git pre-push hook.
608
+ if ($foundCode === false && $this->tokenizerType === 'PHP' && $this->_file !== 'STDIN') {
609
+ $shortTags = (bool) ini_get('short_open_tag');
610
+ if ($shortTags === false) {
611
+ $error = 'No PHP code was found in this file and short open tags are not allowed by this install of PHP. This file may be using short open tags but PHP does not allow them.';
612
+ $this->addWarning($error, null, 'Internal.NoCodeFound');
613
+ }
614
+ }
615
+
616
+ if (PHP_CODESNIFFER_VERBOSITY > 2) {
617
+ echo "\t*** END TOKEN PROCESSING ***".PHP_EOL;
618
+ echo "\t*** START SNIFF PROCESSING REPORT ***".PHP_EOL;
619
+
620
+ asort($this->_listenerTimes, SORT_NUMERIC);
621
+ $this->_listenerTimes = array_reverse($this->_listenerTimes, true);
622
+ foreach ($this->_listenerTimes as $listener => $timeTaken) {
623
+ echo "\t$listener: ".round(($timeTaken), 4).' secs'.PHP_EOL;
624
+ }
625
+
626
+ echo "\t*** END SNIFF PROCESSING REPORT ***".PHP_EOL;
627
+ }
628
+
629
+ }//end start()
630
+
631
+
632
+ /**
633
+ * Remove vars stored in this file that are no longer required.
634
+ *
635
+ * @return void
636
+ */
637
+ public function cleanUp()
638
+ {
639
+ $this->_tokens = null;
640
+ $this->_listeners = null;
641
+
642
+ }//end cleanUp()
643
+
644
+
645
+ /**
646
+ * Tokenizes the file and prepares it for the test run.
647
+ *
648
+ * @param string $contents The contents to parse. If NULL, the content
649
+ * is taken from the file system.
650
+ *
651
+ * @return void
652
+ */
653
+ private function _parse($contents=null)
654
+ {
655
+ if ($contents === null && empty($this->_tokens) === false) {
656
+ // File has already been parsed.
657
+ return;
658
+ }
659
+
660
+ $stdin = false;
661
+ $cliValues = $this->phpcs->cli->getCommandLineValues();
662
+ if (empty($cliValues['files']) === true) {
663
+ $stdin = true;
664
+ }
665
+
666
+ // Determine the tokenizer from the file extension.
667
+ $fileParts = explode('.', $this->_file);
668
+ $extension = array_pop($fileParts);
669
+ if (isset($this->phpcs->allowedFileExtensions[$extension]) === true) {
670
+ $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->phpcs->allowedFileExtensions[$extension];
671
+ $this->tokenizerType = $this->phpcs->allowedFileExtensions[$extension];
672
+ } else if (isset($this->phpcs->defaultFileExtensions[$extension]) === true) {
673
+ $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->phpcs->defaultFileExtensions[$extension];
674
+ $this->tokenizerType = $this->phpcs->defaultFileExtensions[$extension];
675
+ } else {
676
+ // Revert to default.
677
+ $tokenizerClass = 'PHP_CodeSniffer_Tokenizers_'.$this->tokenizerType;
678
+ }
679
+
680
+ $tokenizer = new $tokenizerClass();
681
+ $this->tokenizer = $tokenizer;
682
+
683
+ if ($contents === null) {
684
+ $contents = file_get_contents($this->_file);
685
+ }
686
+
687
+ try {
688
+ $tabWidth = null;
689
+ $encoding = null;
690
+ if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
691
+ $cliValues = $this->phpcs->cli->getCommandLineValues();
692
+ if (isset($cliValues['tabWidth']) === true) {
693
+ $tabWidth = $cliValues['tabWidth'];
694
+ }
695
+
696
+ if (isset($cliValues['encoding']) === true) {
697
+ $encoding = $cliValues['encoding'];
698
+ }
699
+ }
700
+
701
+ $this->_tokens = self::tokenizeString($contents, $tokenizer, $this->eolChar, $tabWidth, $encoding);
702
+ } catch (PHP_CodeSniffer_Exception $e) {
703
+ $this->addWarning($e->getMessage(), null, 'Internal.Tokenizer.Exception');
704
+ if (PHP_CODESNIFFER_VERBOSITY > 0 || (PHP_CODESNIFFER_CBF === true && $stdin === false)) {
705
+ echo "[$this->tokenizerType => tokenizer error]... ";
706
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
707
+ echo PHP_EOL;
708
+ }
709
+ }
710
+
711
+ return;
712
+ }//end try
713
+
714
+ $this->numTokens = count($this->_tokens);
715
+
716
+ // Check for mixed line endings as these can cause tokenizer errors and we
717
+ // should let the user know that the results they get may be incorrect.
718
+ // This is done by removing all backslashes, removing the newline char we
719
+ // detected, then converting newlines chars into text. If any backslashes
720
+ // are left at the end, we have additional newline chars in use.
721
+ $contents = str_replace('\\', '', $contents);
722
+ $contents = str_replace($this->eolChar, '', $contents);
723
+ $contents = str_replace("\n", '\n', $contents);
724
+ $contents = str_replace("\r", '\r', $contents);
725
+ if (strpos($contents, '\\') !== false) {
726
+ $error = 'File has mixed line endings; this may cause incorrect results';
727
+ $this->addWarning($error, 0, 'Internal.LineEndings.Mixed');
728
+ }
729
+
730
+ if (PHP_CODESNIFFER_VERBOSITY > 0 || (PHP_CODESNIFFER_CBF === true && $stdin === false)) {
731
+ if ($this->numTokens === 0) {
732
+ $numLines = 0;
733
+ } else {
734
+ $numLines = $this->_tokens[($this->numTokens - 1)]['line'];
735
+ }
736
+
737
+ echo "[$this->tokenizerType => $this->numTokens tokens in $numLines lines]... ";
738
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
739
+ echo PHP_EOL;
740
+ }
741
+ }
742
+
743
+ }//end _parse()
744
+
745
+
746
+ /**
747
+ * Opens a file and detects the EOL character being used.
748
+ *
749
+ * @param string $file The full path to the file.
750
+ * @param string $contents The contents to parse. If NULL, the content
751
+ * is taken from the file system.
752
+ *
753
+ * @return string
754
+ * @throws PHP_CodeSniffer_Exception If $file could not be opened.
755
+ */
756
+ public static function detectLineEndings($file, $contents=null)
757
+ {
758
+ if ($contents === null) {
759
+ // Determine the newline character being used in this file.
760
+ // Will be either \r, \r\n or \n.
761
+ if (is_readable($file) === false) {
762
+ $error = 'Error opening file; file no longer exists or you do not have access to read the file';
763
+ throw new PHP_CodeSniffer_Exception($error);
764
+ } else {
765
+ $handle = fopen($file, 'r');
766
+ if ($handle === false) {
767
+ $error = 'Error opening file; could not auto-detect line endings';
768
+ throw new PHP_CodeSniffer_Exception($error);
769
+ }
770
+ }
771
+
772
+ $firstLine = fgets($handle);
773
+ fclose($handle);
774
+
775
+ $eolChar = substr($firstLine, -1);
776
+ if ($eolChar === "\n") {
777
+ $secondLastChar = substr($firstLine, -2, 1);
778
+ if ($secondLastChar === "\r") {
779
+ $eolChar = "\r\n";
780
+ }
781
+ } else if ($eolChar !== "\r") {
782
+ // Must not be an EOL char at the end of the line.
783
+ // Probably a one-line file, so assume \n as it really
784
+ // doesn't matter considering there are no newlines.
785
+ $eolChar = "\n";
786
+ }
787
+ } else {
788
+ if (preg_match("/\r\n?|\n/", $contents, $matches) !== 1) {
789
+ // Assuming there are no newlines.
790
+ $eolChar = "\n";
791
+ } else {
792
+ $eolChar = $matches[0];
793
+ }
794
+ }//end if
795
+
796
+ return $eolChar;
797
+
798
+ }//end detectLineEndings()
799
+
800
+
801
+ /**
802
+ * Records an error against a specific token in the file.
803
+ *
804
+ * @param string $error The error message.
805
+ * @param int $stackPtr The stack position where the error occurred.
806
+ * @param string $code A violation code unique to the sniff message.
807
+ * @param array $data Replacements for the error message.
808
+ * @param int $severity The severity level for this error. A value of 0
809
+ * will be converted into the default severity level.
810
+ * @param boolean $fixable Can the error be fixed by the sniff?
811
+ *
812
+ * @return boolean
813
+ */
814
+ public function addError(
815
+ $error,
816
+ $stackPtr,
817
+ $code='',
818
+ $data=array(),
819
+ $severity=0,
820
+ $fixable=false
821
+ ) {
822
+ if ($stackPtr === null) {
823
+ $line = 1;
824
+ $column = 1;
825
+ } else {
826
+ $line = $this->_tokens[$stackPtr]['line'];
827
+ $column = $this->_tokens[$stackPtr]['column'];
828
+ }
829
+
830
+ return $this->_addError($error, $line, $column, $code, $data, $severity, $fixable);
831
+
832
+ }//end addError()
833
+
834
+
835
+ /**
836
+ * Records a warning against a specific token in the file.
837
+ *
838
+ * @param string $warning The error message.
839
+ * @param int $stackPtr The stack position where the error occurred.
840
+ * @param string $code A violation code unique to the sniff message.
841
+ * @param array $data Replacements for the warning message.
842
+ * @param int $severity The severity level for this warning. A value of 0
843
+ * will be converted into the default severity level.
844
+ * @param boolean $fixable Can the warning be fixed by the sniff?
845
+ *
846
+ * @return boolean
847
+ */
848
+ public function addWarning(
849
+ $warning,
850
+ $stackPtr,
851
+ $code='',
852
+ $data=array(),
853
+ $severity=0,
854
+ $fixable=false
855
+ ) {
856
+ if ($stackPtr === null) {
857
+ $line = 1;
858
+ $column = 1;
859
+ } else {
860
+ $line = $this->_tokens[$stackPtr]['line'];
861
+ $column = $this->_tokens[$stackPtr]['column'];
862
+ }
863
+
864
+ return $this->_addWarning($warning, $line, $column, $code, $data, $severity, $fixable);
865
+
866
+ }//end addWarning()
867
+
868
+
869
+ /**
870
+ * Records an error against a specific line in the file.
871
+ *
872
+ * @param string $error The error message.
873
+ * @param int $line The line on which the error occurred.
874
+ * @param string $code A violation code unique to the sniff message.
875
+ * @param array $data Replacements for the error message.
876
+ * @param int $severity The severity level for this error. A value of 0
877
+ * will be converted into the default severity level.
878
+ *
879
+ * @return boolean
880
+ */
881
+ public function addErrorOnLine(
882
+ $error,
883
+ $line,
884
+ $code='',
885
+ $data=array(),
886
+ $severity=0
887
+ ) {
888
+ return $this->_addError($error, $line, 1, $code, $data, $severity, false);
889
+
890
+ }//end addErrorOnLine()
891
+
892
+
893
+ /**
894
+ * Records a warning against a specific token in the file.
895
+ *
896
+ * @param string $warning The error message.
897
+ * @param int $line The line on which the warning occurred.
898
+ * @param string $code A violation code unique to the sniff message.
899
+ * @param array $data Replacements for the warning message.
900
+ * @param int $severity The severity level for this warning. A value of 0
901
+ * will be converted into the default severity level.
902
+ *
903
+ * @return boolean
904
+ */
905
+ public function addWarningOnLine(
906
+ $warning,
907
+ $line,
908
+ $code='',
909
+ $data=array(),
910
+ $severity=0
911
+ ) {
912
+ return $this->_addWarning($warning, $line, 1, $code, $data, $severity, false);
913
+
914
+ }//end addWarningOnLine()
915
+
916
+
917
+ /**
918
+ * Records a fixable error against a specific token in the file.
919
+ *
920
+ * Returns true if the error was recorded and should be fixed.
921
+ *
922
+ * @param string $error The error message.
923
+ * @param int $stackPtr The stack position where the error occurred.
924
+ * @param string $code A violation code unique to the sniff message.
925
+ * @param array $data Replacements for the error message.
926
+ * @param int $severity The severity level for this error. A value of 0
927
+ * will be converted into the default severity level.
928
+ *
929
+ * @return boolean
930
+ */
931
+ public function addFixableError(
932
+ $error,
933
+ $stackPtr,
934
+ $code='',
935
+ $data=array(),
936
+ $severity=0
937
+ ) {
938
+ $recorded = $this->addError($error, $stackPtr, $code, $data, $severity, true);
939
+ if ($recorded === true && $this->fixer->enabled === true) {
940
+ return true;
941
+ }
942
+
943
+ return false;
944
+
945
+ }//end addFixableError()
946
+
947
+
948
+ /**
949
+ * Records a fixable warning against a specific token in the file.
950
+ *
951
+ * Returns true if the warning was recorded and should be fixed.
952
+ *
953
+ * @param string $warning The error message.
954
+ * @param int $stackPtr The stack position where the error occurred.
955
+ * @param string $code A violation code unique to the sniff message.
956
+ * @param array $data Replacements for the warning message.
957
+ * @param int $severity The severity level for this warning. A value of 0
958
+ * will be converted into the default severity level.
959
+ *
960
+ * @return boolean
961
+ */
962
+ public function addFixableWarning(
963
+ $warning,
964
+ $stackPtr,
965
+ $code='',
966
+ $data=array(),
967
+ $severity=0
968
+ ) {
969
+ $recorded = $this->addWarning($warning, $stackPtr, $code, $data, $severity, true);
970
+ if ($recorded === true && $this->fixer->enabled === true) {
971
+ return true;
972
+ }
973
+
974
+ return false;
975
+
976
+ }//end addFixableWarning()
977
+
978
+
979
+ /**
980
+ * Adds an error to the error stack.
981
+ *
982
+ * @param string $error The error message.
983
+ * @param int $line The line on which the error occurred.
984
+ * @param int $column The column at which the error occurred.
985
+ * @param string $code A violation code unique to the sniff message.
986
+ * @param array $data Replacements for the error message.
987
+ * @param int $severity The severity level for this error. A value of 0
988
+ * will be converted into the default severity level.
989
+ * @param boolean $fixable Can the error be fixed by the sniff?
990
+ *
991
+ * @return boolean
992
+ */
993
+ private function _addError($error, $line, $column, $code, $data, $severity, $fixable)
994
+ {
995
+ if (isset(self::$_ignoredLines[$line]) === true) {
996
+ return false;
997
+ }
998
+
999
+ // Work out which sniff generated the error.
1000
+ if (substr($code, 0, 9) === 'Internal.') {
1001
+ // Any internal message.
1002
+ $sniffCode = $code;
1003
+ } else {
1004
+ $parts = explode('_', str_replace('\\', '_', $this->_activeListener));
1005
+ if (isset($parts[3]) === true) {
1006
+ $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3];
1007
+
1008
+ // Remove "Sniff" from the end.
1009
+ $sniff = substr($sniff, 0, -5);
1010
+ } else {
1011
+ $sniff = 'unknownSniff';
1012
+ }
1013
+
1014
+ $sniffCode = $sniff;
1015
+ if ($code !== '') {
1016
+ $sniffCode .= '.'.$code;
1017
+ }
1018
+ }//end if
1019
+
1020
+ // If we know this sniff code is being ignored for this file, return early.
1021
+ if (isset($this->_ignoredCodes[$sniffCode]) === true) {
1022
+ return false;
1023
+ }
1024
+
1025
+ // Make sure this message type has not been set to "warning".
1026
+ if (isset($this->ruleset[$sniffCode]['type']) === true
1027
+ && $this->ruleset[$sniffCode]['type'] === 'warning'
1028
+ ) {
1029
+ // Pass this off to the warning handler.
1030
+ return $this->_addWarning($error, $line, $column, $code, $data, $severity, $fixable);
1031
+ } else if ($this->phpcs->cli->errorSeverity === 0) {
1032
+ // Don't bother doing any processing as errors are just going to
1033
+ // be hidden in the reports anyway.
1034
+ return false;
1035
+ }
1036
+
1037
+ // Make sure we are interested in this severity level.
1038
+ if (isset($this->ruleset[$sniffCode]['severity']) === true) {
1039
+ $severity = $this->ruleset[$sniffCode]['severity'];
1040
+ } else if ($severity === 0) {
1041
+ $severity = PHPCS_DEFAULT_ERROR_SEV;
1042
+ }
1043
+
1044
+ if ($this->phpcs->cli->errorSeverity > $severity) {
1045
+ return false;
1046
+ }
1047
+
1048
+ // Make sure we are not ignoring this file.
1049
+ $patterns = $this->phpcs->getIgnorePatterns($sniffCode);
1050
+ foreach ($patterns as $pattern => $type) {
1051
+ // While there is support for a type of each pattern
1052
+ // (absolute or relative) we don't actually support it here.
1053
+ $replacements = array(
1054
+ '\\,' => ',',
1055
+ '*' => '.*',
1056
+ );
1057
+
1058
+ // We assume a / directory separator, as do the exclude rules
1059
+ // most developers write, so we need a special case for any system
1060
+ // that is different.
1061
+ if (DIRECTORY_SEPARATOR === '\\') {
1062
+ $replacements['/'] = '\\\\';
1063
+ }
1064
+
1065
+ $pattern = '`'.strtr($pattern, $replacements).'`i';
1066
+ if (preg_match($pattern, $this->_file) === 1) {
1067
+ $this->_ignoredCodes[$sniffCode] = true;
1068
+ return false;
1069
+ }
1070
+ }//end foreach
1071
+
1072
+ $this->_errorCount++;
1073
+ if ($fixable === true) {
1074
+ $this->_fixableCount++;
1075
+ }
1076
+
1077
+ if ($this->_recordErrors === false) {
1078
+ if (isset($this->_errors[$line]) === false) {
1079
+ $this->_errors[$line] = 0;
1080
+ }
1081
+
1082
+ $this->_errors[$line]++;
1083
+ return true;
1084
+ }
1085
+
1086
+ // Work out the error message.
1087
+ if (isset($this->ruleset[$sniffCode]['message']) === true) {
1088
+ $error = $this->ruleset[$sniffCode]['message'];
1089
+ }
1090
+
1091
+ if (empty($data) === true) {
1092
+ $message = $error;
1093
+ } else {
1094
+ $message = vsprintf($error, $data);
1095
+ }
1096
+
1097
+ if (isset($this->_errors[$line]) === false) {
1098
+ $this->_errors[$line] = array();
1099
+ }
1100
+
1101
+ if (isset($this->_errors[$line][$column]) === false) {
1102
+ $this->_errors[$line][$column] = array();
1103
+ }
1104
+
1105
+ $this->_errors[$line][$column][] = array(
1106
+ 'message' => $message,
1107
+ 'source' => $sniffCode,
1108
+ 'severity' => $severity,
1109
+ 'fixable' => $fixable,
1110
+ );
1111
+
1112
+ if (PHP_CODESNIFFER_VERBOSITY > 1
1113
+ && $this->fixer->enabled === true
1114
+ && $fixable === true
1115
+ ) {
1116
+ @ob_end_clean();
1117
+ echo "\tE: [Line $line] $message ($sniffCode)".PHP_EOL;
1118
+ ob_start();
1119
+ }
1120
+
1121
+ return true;
1122
+
1123
+ }//end _addError()
1124
+
1125
+
1126
+ /**
1127
+ * Adds an warning to the warning stack.
1128
+ *
1129
+ * @param string $warning The error message.
1130
+ * @param int $line The line on which the warning occurred.
1131
+ * @param int $column The column at which the warning occurred.
1132
+ * @param string $code A violation code unique to the sniff message.
1133
+ * @param array $data Replacements for the warning message.
1134
+ * @param int $severity The severity level for this warning. A value of 0
1135
+ * will be converted into the default severity level.
1136
+ * @param boolean $fixable Can the warning be fixed by the sniff?
1137
+ *
1138
+ * @return boolean
1139
+ */
1140
+ private function _addWarning($warning, $line, $column, $code, $data, $severity, $fixable)
1141
+ {
1142
+ if (isset(self::$_ignoredLines[$line]) === true) {
1143
+ return false;
1144
+ }
1145
+
1146
+ // Work out which sniff generated the warning.
1147
+ if (substr($code, 0, 9) === 'Internal.') {
1148
+ // Any internal message.
1149
+ $sniffCode = $code;
1150
+ } else {
1151
+ $parts = explode('_', str_replace('\\', '_', $this->_activeListener));
1152
+ if (isset($parts[3]) === true) {
1153
+ $sniff = $parts[0].'.'.$parts[2].'.'.$parts[3];
1154
+
1155
+ // Remove "Sniff" from the end.
1156
+ $sniff = substr($sniff, 0, -5);
1157
+ } else {
1158
+ $sniff = 'unknownSniff';
1159
+ }
1160
+
1161
+ $sniffCode = $sniff;
1162
+ if ($code !== '') {
1163
+ $sniffCode .= '.'.$code;
1164
+ }
1165
+ }//end if
1166
+
1167
+ // If we know this sniff code is being ignored for this file, return early.
1168
+ if (isset($this->_ignoredCodes[$sniffCode]) === true) {
1169
+ return false;
1170
+ }
1171
+
1172
+ // Make sure this message type has not been set to "error".
1173
+ if (isset($this->ruleset[$sniffCode]['type']) === true
1174
+ && $this->ruleset[$sniffCode]['type'] === 'error'
1175
+ ) {
1176
+ // Pass this off to the error handler.
1177
+ return $this->_addError($warning, $line, $column, $code, $data, $severity, $fixable);
1178
+ } else if ($this->phpcs->cli->warningSeverity === 0) {
1179
+ // Don't bother doing any processing as warnings are just going to
1180
+ // be hidden in the reports anyway.
1181
+ return false;
1182
+ }
1183
+
1184
+ // Make sure we are interested in this severity level.
1185
+ if (isset($this->ruleset[$sniffCode]['severity']) === true) {
1186
+ $severity = $this->ruleset[$sniffCode]['severity'];
1187
+ } else if ($severity === 0) {
1188
+ $severity = PHPCS_DEFAULT_WARN_SEV;
1189
+ }
1190
+
1191
+ if ($this->phpcs->cli->warningSeverity > $severity) {
1192
+ return false;
1193
+ }
1194
+
1195
+ // Make sure we are not ignoring this file.
1196
+ $patterns = $this->phpcs->getIgnorePatterns($sniffCode);
1197
+ foreach ($patterns as $pattern => $type) {
1198
+ // While there is support for a type of each pattern
1199
+ // (absolute or relative) we don't actually support it here.
1200
+ $replacements = array(
1201
+ '\\,' => ',',
1202
+ '*' => '.*',
1203
+ );
1204
+
1205
+ // We assume a / directory separator, as do the exclude rules
1206
+ // most developers write, so we need a special case for any system
1207
+ // that is different.
1208
+ if (DIRECTORY_SEPARATOR === '\\') {
1209
+ $replacements['/'] = '\\\\';
1210
+ }
1211
+
1212
+ $pattern = '`'.strtr($pattern, $replacements).'`i';
1213
+ if (preg_match($pattern, $this->_file) === 1) {
1214
+ $this->_ignoredCodes[$sniffCode] = true;
1215
+ return false;
1216
+ }
1217
+ }//end foreach
1218
+
1219
+ $this->_warningCount++;
1220
+ if ($fixable === true) {
1221
+ $this->_fixableCount++;
1222
+ }
1223
+
1224
+ if ($this->_recordErrors === false) {
1225
+ if (isset($this->_warnings[$line]) === false) {
1226
+ $this->_warnings[$line] = 0;
1227
+ }
1228
+
1229
+ $this->_warnings[$line]++;
1230
+ return true;
1231
+ }
1232
+
1233
+ // Work out the warning message.
1234
+ if (isset($this->ruleset[$sniffCode]['message']) === true) {
1235
+ $warning = $this->ruleset[$sniffCode]['message'];
1236
+ }
1237
+
1238
+ if (empty($data) === true) {
1239
+ $message = $warning;
1240
+ } else {
1241
+ $message = vsprintf($warning, $data);
1242
+ }
1243
+
1244
+ if (isset($this->_warnings[$line]) === false) {
1245
+ $this->_warnings[$line] = array();
1246
+ }
1247
+
1248
+ if (isset($this->_warnings[$line][$column]) === false) {
1249
+ $this->_warnings[$line][$column] = array();
1250
+ }
1251
+
1252
+ $this->_warnings[$line][$column][] = array(
1253
+ 'message' => $message,
1254
+ 'source' => $sniffCode,
1255
+ 'severity' => $severity,
1256
+ 'fixable' => $fixable,
1257
+ );
1258
+
1259
+ if (PHP_CODESNIFFER_VERBOSITY > 1
1260
+ && $this->fixer->enabled === true
1261
+ && $fixable === true
1262
+ ) {
1263
+ @ob_end_clean();
1264
+ echo "\tW: $message ($sniffCode)".PHP_EOL;
1265
+ ob_start();
1266
+ }
1267
+
1268
+ return true;
1269
+
1270
+ }//end _addWarning()
1271
+
1272
+
1273
+ /**
1274
+ * Adds an warning to the warning stack.
1275
+ *
1276
+ * @param int $stackPtr The stack position where the metric was recorded.
1277
+ * @param string $metric The name of the metric being recorded.
1278
+ * @param string $value The value of the metric being recorded.
1279
+ *
1280
+ * @return boolean
1281
+ */
1282
+ public function recordMetric($stackPtr, $metric, $value)
1283
+ {
1284
+ if (isset($this->_metrics[$metric]) === false) {
1285
+ $this->_metrics[$metric] = array(
1286
+ 'values' => array(
1287
+ $value => array($stackPtr),
1288
+ ),
1289
+ );
1290
+ } else {
1291
+ if (isset($this->_metrics[$metric]['values'][$value]) === false) {
1292
+ $this->_metrics[$metric]['values'][$value] = array($stackPtr);
1293
+ } else {
1294
+ $this->_metrics[$metric]['values'][$value][] = $stackPtr;
1295
+ }
1296
+ }
1297
+
1298
+ return true;
1299
+
1300
+ }//end recordMetric()
1301
+
1302
+
1303
+ /**
1304
+ * Returns the number of errors raised.
1305
+ *
1306
+ * @return int
1307
+ */
1308
+ public function getErrorCount()
1309
+ {
1310
+ return $this->_errorCount;
1311
+
1312
+ }//end getErrorCount()
1313
+
1314
+
1315
+ /**
1316
+ * Returns the number of warnings raised.
1317
+ *
1318
+ * @return int
1319
+ */
1320
+ public function getWarningCount()
1321
+ {
1322
+ return $this->_warningCount;
1323
+
1324
+ }//end getWarningCount()
1325
+
1326
+
1327
+ /**
1328
+ * Returns the number of successes recorded.
1329
+ *
1330
+ * @return int
1331
+ */
1332
+ public function getSuccessCount()
1333
+ {
1334
+ return $this->_successCount;
1335
+
1336
+ }//end getSuccessCount()
1337
+
1338
+
1339
+ /**
1340
+ * Returns the number of fixable errors/warnings raised.
1341
+ *
1342
+ * @return int
1343
+ */
1344
+ public function getFixableCount()
1345
+ {
1346
+ return $this->_fixableCount;
1347
+
1348
+ }//end getFixableCount()
1349
+
1350
+
1351
+ /**
1352
+ * Returns the list of ignored lines.
1353
+ *
1354
+ * @return array
1355
+ */
1356
+ public function getIgnoredLines()
1357
+ {
1358
+ return self::$_ignoredLines;
1359
+
1360
+ }//end getIgnoredLines()
1361
+
1362
+
1363
+ /**
1364
+ * Returns the errors raised from processing this file.
1365
+ *
1366
+ * @return array
1367
+ */
1368
+ public function getErrors()
1369
+ {
1370
+ return $this->_errors;
1371
+
1372
+ }//end getErrors()
1373
+
1374
+
1375
+ /**
1376
+ * Returns the warnings raised from processing this file.
1377
+ *
1378
+ * @return array
1379
+ */
1380
+ public function getWarnings()
1381
+ {
1382
+ return $this->_warnings;
1383
+
1384
+ }//end getWarnings()
1385
+
1386
+
1387
+ /**
1388
+ * Returns the metrics found while processing this file.
1389
+ *
1390
+ * @return array
1391
+ */
1392
+ public function getMetrics()
1393
+ {
1394
+ return $this->_metrics;
1395
+
1396
+ }//end getMetrics()
1397
+
1398
+
1399
+ /**
1400
+ * Returns the absolute filename of this file.
1401
+ *
1402
+ * @return string
1403
+ */
1404
+ public function getFilename()
1405
+ {
1406
+ return $this->_file;
1407
+
1408
+ }//end getFilename()
1409
+
1410
+
1411
+ /**
1412
+ * Creates an array of tokens when given some PHP code.
1413
+ *
1414
+ * Starts by using token_get_all() but does a lot of extra processing
1415
+ * to insert information about the context of the token.
1416
+ *
1417
+ * @param string $string The string to tokenize.
1418
+ * @param object $tokenizer A tokenizer class to use to tokenize the string.
1419
+ * @param string $eolChar The EOL character to use for splitting strings.
1420
+ * @param int $tabWidth The number of spaces each tab respresents.
1421
+ * @param string $encoding The charset of the sniffed file.
1422
+ *
1423
+ * @throws PHP_CodeSniffer_Exception If the file cannot be processed.
1424
+ * @return array
1425
+ */
1426
+ public static function tokenizeString($string, $tokenizer, $eolChar='\n', $tabWidth=null, $encoding=null)
1427
+ {
1428
+ // Minified files often have a very large number of characters per line
1429
+ // and cause issues when tokenizing.
1430
+ if (property_exists($tokenizer, 'skipMinified') === true
1431
+ && $tokenizer->skipMinified === true
1432
+ ) {
1433
+ $numChars = strlen($string);
1434
+ $numLines = (substr_count($string, $eolChar) + 1);
1435
+ $average = ($numChars / $numLines);
1436
+ if ($average > 100) {
1437
+ throw new PHP_CodeSniffer_Exception('File appears to be minified and cannot be processed');
1438
+ }
1439
+ }
1440
+
1441
+ $tokens = $tokenizer->tokenizeString($string, $eolChar);
1442
+
1443
+ if ($tabWidth === null) {
1444
+ $tabWidth = PHP_CODESNIFFER_TAB_WIDTH;
1445
+ }
1446
+
1447
+ if ($encoding === null) {
1448
+ $encoding = PHP_CODESNIFFER_ENCODING;
1449
+ }
1450
+
1451
+ self::_createPositionMap($tokens, $tokenizer, $eolChar, $encoding, $tabWidth);
1452
+ self::_createTokenMap($tokens, $tokenizer, $eolChar);
1453
+ self::_createParenthesisNestingMap($tokens, $tokenizer, $eolChar);
1454
+ self::_createScopeMap($tokens, $tokenizer, $eolChar);
1455
+
1456
+ self::_createLevelMap($tokens, $tokenizer, $eolChar);
1457
+
1458
+ // Allow the tokenizer to do additional processing if required.
1459
+ $tokenizer->processAdditional($tokens, $eolChar);
1460
+
1461
+ return $tokens;
1462
+
1463
+ }//end tokenizeString()
1464
+
1465
+
1466
+ /**
1467
+ * Sets token position information.
1468
+ *
1469
+ * Can also convert tabs into spaces. Each tab can represent between
1470
+ * 1 and $width spaces, so this cannot be a straight string replace.
1471
+ *
1472
+ * @param array $tokens The array of tokens to process.
1473
+ * @param object $tokenizer The tokenizer being used to process this file.
1474
+ * @param string $eolChar The EOL character to use for splitting strings.
1475
+ * @param string $encoding The charset of the sniffed file.
1476
+ * @param int $tabWidth The number of spaces that each tab represents.
1477
+ * Set to 0 to disable tab replacement.
1478
+ *
1479
+ * @return void
1480
+ */
1481
+ private static function _createPositionMap(&$tokens, $tokenizer, $eolChar, $encoding, $tabWidth)
1482
+ {
1483
+ $currColumn = 1;
1484
+ $lineNumber = 1;
1485
+ $eolLen = (strlen($eolChar) * -1);
1486
+ $tokenizerType = get_class($tokenizer);
1487
+ $ignoring = false;
1488
+ $inTests = defined('PHP_CODESNIFFER_IN_TESTS');
1489
+
1490
+ $checkEncoding = false;
1491
+ if ($encoding !== 'iso-8859-1' && function_exists('iconv_strlen') === true) {
1492
+ $checkEncoding = true;
1493
+ }
1494
+
1495
+ $tokensWithTabs = array(
1496
+ T_WHITESPACE => true,
1497
+ T_COMMENT => true,
1498
+ T_DOC_COMMENT => true,
1499
+ T_DOC_COMMENT_WHITESPACE => true,
1500
+ T_DOC_COMMENT_STRING => true,
1501
+ T_CONSTANT_ENCAPSED_STRING => true,
1502
+ T_DOUBLE