From 79b37a9959a3e9bf1803368eeff6e0c0854b4cbb Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 21 Nov 2018 15:02:00 +0000 Subject: [PATCH 01/35] Updated api changes on Masterminds/html5-php --- composer.json | 2 +- src/Utility/AMPDOMTreeBuilder.php | 7 +++---- src/Utility/AMPHTML5.php | 7 +++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 9ccfbc5f..1092ca31 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "querypath/QueryPath": ">=3.0.4", "sebastian/diff": "^1.2 || ^2 || ^3", "marc1706/fast-image-size": "1.*", - "masterminds/html5": "^2.2.0", + "masterminds/html5": "^2.4.0", "sabberworm/php-css-parser": "^8.0.0", "guzzlehttp/guzzle": "~6.1" }, diff --git a/src/Utility/AMPDOMTreeBuilder.php b/src/Utility/AMPDOMTreeBuilder.php index 4e9c4546..24c66ac9 100644 --- a/src/Utility/AMPDOMTreeBuilder.php +++ b/src/Utility/AMPDOMTreeBuilder.php @@ -18,7 +18,6 @@ namespace Lullabot\AMP\Utility; use Masterminds\HTML5\Parser\DOMTreeBuilder; -use Masterminds\HTML5\Parser\InputStream; use Masterminds\HTML5\Parser\Scanner; use Lullabot\AMP\AMP; @@ -46,13 +45,13 @@ public function getEmbeddedScanner() /** * AMPDOMTreeBuilder constructor. - * @param InputStream $inputstream + * @param String $data * @param array $options */ - public function __construct(InputStream $inputstream, array $options = []) + public function __construct($data, array $options = []) { // We embed a scanner so that $this->startTag() knows the current line number - $this->scanner = new Scanner($inputstream); + $this->scanner = new Scanner($data); parent::__construct(false, $options); } diff --git a/src/Utility/AMPHTML5.php b/src/Utility/AMPHTML5.php index e494f284..8349d52d 100644 --- a/src/Utility/AMPHTML5.php +++ b/src/Utility/AMPHTML5.php @@ -18,7 +18,6 @@ namespace Lullabot\AMP\Utility; use Masterminds\HTML5; -use Masterminds\HTML5\Parser\InputStream; /** * Class AMPHTML5 @@ -39,15 +38,15 @@ class AMPHTML5 extends HTML5 * Similar to \Masterminds\HTML5::parse() method in superclass but we use our custom (sub-classed) tokenizer and DOM tree * builder to achieve desired effect of adding a line number attribute to each tag of the output DOM document. * - * @param InputStream $inputstream + * @param String $data * @param array $options * @return \DOMDocument */ - public function parse(InputStream $inputstream, array $options = []) + public function parse($data, array $options = []) { // User options override default options in $this->options $final_options = array_merge($this->options, $options); - $amp_tree_builder = new AMPDOMTreeBuilder($inputstream, $final_options); + $amp_tree_builder = new AMPDOMTreeBuilder($data, $final_options); $amp_tokenizer = new AMPTokenizer($amp_tree_builder); // Start reading the input stream and build the DOM tree by triggering events in the AMPDOMTreeBuilder From 84f8849821feb2ca4cbecabb53f31593c445a17b Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 21 Nov 2018 15:37:12 +0000 Subject: [PATCH 02/35] Updated variable name --- src/Validate/ParsedTagSpec.php | 4 ++-- src/Validate/ParsedValidatorRules.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Validate/ParsedTagSpec.php b/src/Validate/ParsedTagSpec.php index 32981647..aa6d9e56 100644 --- a/src/Validate/ParsedTagSpec.php +++ b/src/Validate/ParsedTagSpec.php @@ -106,8 +106,8 @@ public function __construct($template_spec_url, array $attr_lists_by_name, array } } - /** @var string $also_require_tag */ - foreach ($tag_spec->also_requires_tag as $also_require_tag) { + /** @var string $also_requires_tag_warning */ + foreach ($tag_spec->also_requires_tag_warning as $also_require_tag) { $this->also_requires_tagspec[] = $tagspec_by_detail_or_name[$also_require_tag]; } } diff --git a/src/Validate/ParsedValidatorRules.php b/src/Validate/ParsedValidatorRules.php index 7c25fc5a..78f1518b 100644 --- a/src/Validate/ParsedValidatorRules.php +++ b/src/Validate/ParsedValidatorRules.php @@ -93,12 +93,12 @@ protected function __construct(ValidatorRules $rules) assert(empty($tagspec_by_detail_or_name[ParsedTagSpec::getTagSpecName($tagspec)])); $tagspec_by_detail_or_name[ParsedTagSpec::getTagSpecName($tagspec)] = $tagspec; - if (!empty($tagspec->also_requires_tag)) { + if (!empty($tagspec->also_requires_tag_warning)) { $detail_or_names_to_track[ParsedTagSpec::getTagSpecName($tagspec)] = 1; } /** @var string $require */ - foreach ($tagspec->also_requires_tag as $require) { + foreach ($tagspec->also_requires_tag_warning as $require) { $detail_or_names_to_track[$require] = 1; } } From 5c833ab33c032712d6e2713e4408ef9d10d1fe22 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 21 Nov 2018 16:09:51 +0000 Subject: [PATCH 03/35] Updated css error constant --- src/Validate/RenderValidationResult.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Validate/RenderValidationResult.php b/src/Validate/RenderValidationResult.php index 5c040e82..b1fefffa 100644 --- a/src/Validate/RenderValidationResult.php +++ b/src/Validate/RenderValidationResult.php @@ -294,7 +294,7 @@ public function categorizeError(ValidationError $error) return ErrorCategoryCode::AUTHOR_STYLESHEET_PROBLEM; } - if ($error->code === ValidationErrorCode::CSS_SYNTAX && + if ($error->code === ValidationErrorCode::CSS_SYNTAX_INVALID_AT_RULE && isset($error->params[0]) && $error->params[0] === 'style amp-custom' ) { return ErrorCategoryCode::AUTHOR_STYLESHEET_PROBLEM; From 5b35317fa3aaba74825f3ace32fe991604c7c72d Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 21 Nov 2018 16:14:21 +0000 Subject: [PATCH 04/35] Updated css error constant --- src/Validate/CdataMatcher.php | 2 +- src/Validate/SValidationResult.php | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Validate/CdataMatcher.php b/src/Validate/CdataMatcher.php index 69345fcb..54e33094 100644 --- a/src/Validate/CdataMatcher.php +++ b/src/Validate/CdataMatcher.php @@ -91,7 +91,7 @@ public function match($cdata, Context $context, SValidationResult $result) try { $this->validateCssSpec($cdata, $context, $result, $cdata_spec); } catch (\Exception $e) { - $context->addError(ValidationErrorCode::CSS_SYNTAX, + $context->addError(ValidationErrorCode::CSS_SYNTAX_INVALID_AT_RULE, [ParsedTagSpec::getTagSpecName($this->tag_spec), 'CSS Parser Error: ' . $e->getMessage()], $this->tag_spec->spec_url, $result); } } diff --git a/src/Validate/SValidationResult.php b/src/Validate/SValidationResult.php index 932019ef..47ed6334 100644 --- a/src/Validate/SValidationResult.php +++ b/src/Validate/SValidationResult.php @@ -115,8 +115,6 @@ public static function specificity($code) return 17; case ValidationErrorCode::STYLESHEET_TOO_LONG: return 18; - case ValidationErrorCode::CSS_SYNTAX: - return 19; case ValidationErrorCode::CSS_SYNTAX_INVALID_AT_RULE: return 20; case ValidationErrorCode::MANDATORY_PROPERTY_MISSING_FROM_ATTR_VALUE: @@ -220,4 +218,4 @@ public function mergeFrom(SValidationResult $other) } } -} \ No newline at end of file +} From acd3ed69c3766f54cfc6f662888f5ac084dbb93f Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 21 Nov 2018 17:12:57 +0000 Subject: [PATCH 05/35] Attributes can be arrays --- src/Validate/TagSpecDispatch.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Validate/TagSpecDispatch.php b/src/Validate/TagSpecDispatch.php index 67ee1a8b..c66234b3 100644 --- a/src/Validate/TagSpecDispatch.php +++ b/src/Validate/TagSpecDispatch.php @@ -83,6 +83,9 @@ public function matchingDispatchKey($attr_name, $attr_value, $mandatory_parent) */ public static function makeDispatchKey($attr_name, $attr_value, $mandatory_parent) { + if (is_array($attr_value)) { + $attr_value = implode('^', $attr_value); + } return "$attr_name^$attr_value^$mandatory_parent"; } From 7835c7f5a93ff3227f02ec39b2beeb800759f19e Mon Sep 17 00:00:00 2001 From: Karen Stevenson Date: Thu, 29 Nov 2018 05:58:03 -0600 Subject: [PATCH 06/35] Lock masterminds/html5 to prevent jumping to 2.4 version which changes API for parse(). --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9ccfbc5f..768a0a2c 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "querypath/QueryPath": ">=3.0.4", "sebastian/diff": "^1.2 || ^2 || ^3", "marc1706/fast-image-size": "1.*", - "masterminds/html5": "^2.2.0", + "masterminds/html5": "~2.3", "sabberworm/php-css-parser": "^8.0.0", "guzzlehttp/guzzle": "~6.1" }, From 071ce5f86aeffe5d1febd8f4a35821cb093eb90a Mon Sep 17 00:00:00 2001 From: Karen Stevenson Date: Thu, 29 Nov 2018 06:11:00 -0600 Subject: [PATCH 07/35] Need last digit --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 768a0a2c..51906ce5 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "querypath/QueryPath": ">=3.0.4", "sebastian/diff": "^1.2 || ^2 || ^3", "marc1706/fast-image-size": "1.*", - "masterminds/html5": "~2.3", + "masterminds/html5": "~2.3.0", "sabberworm/php-css-parser": "^8.0.0", "guzzlehttp/guzzle": "~6.1" }, From 55cef3d28148ab1b2e5f25cb695337c6909be7b2 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 5 Dec 2018 09:44:19 +0000 Subject: [PATCH 08/35] Fixing autoload --- amp-console | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/amp-console b/amp-console index 63984b80..507bbaad 100755 --- a/amp-console +++ b/amp-console @@ -18,11 +18,20 @@ // amp-console.php error_reporting(E_ALL ^ E_NOTICE); -require __DIR__.'/vendor/autoload.php'; + +// Include autoloader. +foreach ([getcwd(), __DIR__] as $dir) { + chdir($dir . '/../../'); + $autoload = getcwd() . '/autoload.php'; + if (file_exists($autoload)) { + require_once ($autoload); + break; + } +} use Lullabot\AMP\AmpCommand; use Symfony\Component\Console\Application; $application = new Application(); -$application->add(new AmpCommand()); -$application->run(); +$application>add(new AmpCommand()); +$application>run(); From 41e1017f87851f2b6b3946b5635fc4a69a20e378 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 5 Dec 2018 09:46:02 +0000 Subject: [PATCH 09/35] Typo --- amp-console | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amp-console b/amp-console index 507bbaad..b90d7848 100755 --- a/amp-console +++ b/amp-console @@ -33,5 +33,5 @@ use Lullabot\AMP\AmpCommand; use Symfony\Component\Console\Application; $application = new Application(); -$application>add(new AmpCommand()); -$application>run(); +$application->add(new AmpCommand()); +$application->run(); From ffd3478a7426976ebb99dce7ace8f6caeebaa040 Mon Sep 17 00:00:00 2001 From: Marcelo Vani Date: Wed, 5 Dec 2018 13:28:12 +0000 Subject: [PATCH 10/35] Moved scripts from amphtml to here --- bin/amphtml-update-wp.py | 648 + bin/build.sh | 53 + bin/validator_gen_php.py | 382 + src/Spec/class-amp-allowed-tags-generated.php | 14609 ++++++++++++++ src/Spec/validator-generated.php | 15846 +++++++++++----- 5 files changed, 27238 insertions(+), 4300 deletions(-) create mode 100644 bin/amphtml-update-wp.py create mode 100644 bin/build.sh create mode 100644 bin/validator_gen_php.py create mode 100644 src/Spec/class-amp-allowed-tags-generated.php diff --git a/bin/amphtml-update-wp.py b/bin/amphtml-update-wp.py new file mode 100644 index 00000000..02eb7459 --- /dev/null +++ b/bin/amphtml-update-wp.py @@ -0,0 +1,648 @@ +""" +This script is used to generate the 'class-amp-allowed-tags-generated.php' +file that is used by the class AMP_Tag_And_Attribute_Sanitizer. + +A bash script, amphtml-update.sh, is provided to automatically run this script. To run the bash script, type: + +`bash amphtml-update.sh` + +from within a Linux environment such as VVV. + +See the Updating Allowed Tags and Attributes section of the Contributing guide +https://github.com/Automattic/amp-wp/blob/develop/contributing.md#updating-allowed-tags-and-attributes. + +Then have fun sanitizing your AMP posts! +""" + +import glob +import logging +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +import collections +import json +import google + +def Die(msg): + print >> sys.stderr, msg + sys.exit(1) + + +def SetupOutDir(out_dir): + """Sets up a clean output directory. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + if os.path.exists(out_dir): + subprocess.check_call(['rm', '-rf', out_dir]) + os.mkdir(out_dir) + logging.info('... done') + + +def GenValidatorPb2Py(out_dir): + """Calls the proto compiler to generate validator_pb2.py. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + subprocess.check_call(['protoc', 'validator.proto', + '--python_out=%s' % out_dir]) + open('%s/__init__.py' % out_dir, 'w').close() + logging.info('... done') + + +def GenValidatorProtoascii(out_dir): + """Assembles the validator protoascii file from the main and extensions. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + protoascii_segments = [open('validator-main.protoascii').read()] + extensions = glob.glob('extensions/*/validator-*.protoascii') + # In the Github project, the extensions are located in a sibling directory + # to the validator rather than a child directory. + if not extensions: + extensions = glob.glob('../extensions/*/validator-*.protoascii') + extensions.sort() + for extension in extensions: + protoascii_segments.append(open(extension).read()) + f = open('%s/validator.protoascii' % out_dir, 'w') + f.write(''.join(protoascii_segments)) + f.close() + + logging.info('... done') + + +def GeneratePHP(out_dir): + """Generates PHP for WordPress AMP plugin to consume. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + allowed_tags, attr_lists, reference_points, versions = ParseRules(out_dir) + + #Generate the output + out = [] + GenerateHeaderPHP(out) + GenerateSpecVersionPHP(out, versions) + GenerateAllowedTagsPHP(out, allowed_tags) + GenerateLayoutAttributesPHP(out, attr_lists) + GenerateGlobalAttributesPHP(out, attr_lists) + GenerateReferencePointsPHP(out, reference_points) + GenerateFooterPHP(out) + + # join out array into a single string and remove unneeded whitespace + output = re.sub("\\(\\s*\\)", "()", '\n'.join(out)) + + # replace 'True' with true and 'False' with false + output = re.sub("'True'", "true", output) + output = re.sub("'False'", "false", output) + + # Write the php file to disk. + f = open('%s/class-amp-allowed-tags-generated.php' % out_dir, 'w') + # f.write('\n'.join(out)) + f.write(output) + f.close() + logging.info('... done') + + +def GenerateHeaderPHP(out): + logging.info('entering ...') + + # Output the file's header + out.append(' 0: + tag_spec_dict['cdata'] = cdata_dict + + return tag_spec_dict + + +def GetTagRules(tag_spec): + logging.info('entering ...') + + tag_rules = {} + + if hasattr(tag_spec, 'also_requires_tag') and tag_spec.also_requires_tag: + also_requires_tag_list = [] + for also_requires_tag in tag_spec.also_requires_tag: + also_requires_tag_list.append(UnicodeEscape(also_requires_tag)) + tag_rules['also_requires_tag'] = also_requires_tag_list + + if hasattr(tag_spec, 'requires_extension') and len( tag_spec.requires_extension ) != 0: + requires_extension_list = [] + for requires_extension in tag_spec.requires_extension: + requires_extension_list.append(requires_extension) + tag_rules['requires_extension'] = requires_extension_list + + if hasattr(tag_spec, 'reference_points') and len( tag_spec.reference_points ) != 0: + tag_reference_points = {} + for reference_point_spec in tag_spec.reference_points: + tag_reference_points[ reference_point_spec.tag_spec_name ] = { + "mandatory": reference_point_spec.mandatory, + "unique": reference_point_spec.unique + } + if len( tag_reference_points ) > 0: + tag_rules['reference_points'] = tag_reference_points + + if hasattr(tag_spec, 'also_requires_tag_warning') and len( tag_spec.also_requires_tag_warning ) != 0: + also_requires_tag_warning_list = [] + for also_requires_tag_warning in tag_spec.also_requires_tag_warning: + also_requires_tag_warning_list.append(also_requires_tag_warning) + tag_rules['also_requires_tag_warning'] = also_requires_tag_warning_list + + if tag_spec.disallowed_ancestor: + disallowed_ancestor_list = [] + for disallowed_ancestor in tag_spec.disallowed_ancestor: + disallowed_ancestor_list.append(UnicodeEscape(disallowed_ancestor).lower()) + tag_rules['disallowed_ancestor'] = disallowed_ancestor_list + + if tag_spec.html_format: + html_format_list = [] + has_amp_format = False + for html_format in tag_spec.html_format: + if 1 == html_format: + has_amp_format = True + if not has_amp_format: + return None + + if tag_spec.HasField('extension_spec'): + extension_spec = {} + for field in tag_spec.extension_spec.ListFields(): + if isinstance(field[1], (list, google.protobuf.internal.containers.RepeatedScalarFieldContainer)): + extension_spec[ field[0].name ] = [] + for val in field[1]: + extension_spec[ field[0].name ].append( val ) + else: + extension_spec[ field[0].name ] = field[1] + tag_rules['extension_spec'] = extension_spec + + if tag_spec.HasField('mandatory'): + tag_rules['mandatory'] = tag_spec.mandatory + + if tag_spec.HasField('mandatory_alternatives'): + tag_rules['mandatory_alternatives'] = UnicodeEscape(tag_spec.mandatory_alternatives) + + if tag_spec.HasField('mandatory_ancestor'): + tag_rules['mandatory_ancestor'] = UnicodeEscape(tag_spec.mandatory_ancestor).lower() + + if tag_spec.HasField('mandatory_ancestor_suggested_alternative'): + tag_rules['mandatory_ancestor_suggested_alternative'] = UnicodeEscape(tag_spec.mandatory_ancestor_suggested_alternative).lower() + + if tag_spec.HasField('mandatory_parent'): + tag_rules['mandatory_parent'] = UnicodeEscape(tag_spec.mandatory_parent).lower() + + if tag_spec.HasField('spec_name'): + tag_rules['spec_name'] = UnicodeEscape(tag_spec.spec_name) + + if tag_spec.HasField('spec_url'): + tag_rules['spec_url'] = UnicodeEscape(tag_spec.spec_url) + + if tag_spec.HasField('unique'): + tag_rules['unique'] = tag_spec.unique + + if tag_spec.HasField('unique_warning'): + tag_rules['unique_warning'] = tag_spec.unique_warning + + if tag_spec.HasField('amp_layout'): + amp_layout = {} + for field in tag_spec.amp_layout.ListFields(): + if 'supported_layouts' == field[0].name: + amp_layout['supported_layouts'] = [ val for val in field[1] ] + else: + amp_layout[ field[0].name ] = field[1] + tag_rules['amp_layout'] = amp_layout + + logging.info('... done') + return tag_rules + + +def GetAttrs(attrs): + logging.info('entering ...') + + attr_dict = {} + for attr_spec in attrs: + + value_dict = GetValues(attr_spec) + + # Add attribute name and alternative_names + attr_dict[UnicodeEscape(attr_spec.name)] = value_dict + + logging.info('... done') + return attr_dict + + +def GetValues(attr_spec): + logging.info('entering ...') + + value_dict = {} + + # Add alternative names + if attr_spec.alternative_names: + alt_names_list = [] + for alternative_name in attr_spec.alternative_names: + alt_names_list.append(UnicodeEscape(alternative_name)) + value_dict['alternative_names'] = alt_names_list + + # Add blacklisted value regex + if attr_spec.HasField('blacklisted_value_regex'): + value_dict['blacklisted_value_regex'] = attr_spec.blacklisted_value_regex + + # dispatch_key is an int + if attr_spec.HasField('dispatch_key'): + value_dict['dispatch_key'] = attr_spec.dispatch_key + + # mandatory is a boolean + if attr_spec.HasField('mandatory'): + value_dict['mandatory'] = attr_spec.mandatory + + # Add allowed value + if attr_spec.value: + value_dict['value'] = list( attr_spec.value ) + + # value_casei + if attr_spec.value_casei: + value_dict['value_casei'] = list( attr_spec.value_casei ) + + # value_regex + if attr_spec.HasField('value_regex'): + value_dict['value_regex'] = attr_spec.value_regex + + # value_regex_casei + if attr_spec.HasField('value_regex_casei'): + value_dict['value_regex_casei'] = attr_spec.value_regex_casei + + #value_properties is a dictionary of dictionaries + if attr_spec.HasField('value_properties'): + value_properties_dict = {} + for (value_properties_key, value_properties_val) in attr_spec.value_properties.ListFields(): + for value_property in value_properties_val: + property_dict = {} + # print 'value_property.name: %s' % value_property.name + for (key,val) in value_property.ListFields(): + if val != value_property.name: + if isinstance(val, unicode): + val = UnicodeEscape(val) + property_dict[UnicodeEscape(key.name)] = val + value_properties_dict[UnicodeEscape(value_property.name)] = property_dict + value_dict['value_properties'] = value_properties_dict + + # value_url is a dictionary + if attr_spec.HasField('value_url'): + value_url_dict = {} + for (value_url_key, value_url_val) in attr_spec.value_url.ListFields(): + if isinstance(value_url_val, (list, collections.Sequence, google.protobuf.internal.containers.RepeatedScalarFieldContainer)): + value_url_val_val = [] + for val in value_url_val: + value_url_val_val.append(UnicodeEscape(val)) + else: + value_url_val_val = value_url_val + value_url_dict[value_url_key.name] = value_url_val_val + value_dict['value_url'] = value_url_dict + + logging.info('... done') + return value_dict + + +def UnicodeEscape(string): + """Helper function which escapes unicode characters. + + Args: + string: A string which may contain unicode characters. + Returns: + An escaped string. + """ + return ('' + string).encode('unicode-escape') + +def Phpize(data, indent=0): + """Helper function to convert JSON-serializable data into PHP literals. + + Args: + data: Any JSON-serializable. + Returns: + String formatted as PHP literal. + """ + json_string = json.dumps(data, sort_keys=True, ensure_ascii=False) + + pipe = subprocess.Popen(['php', '-r', 'var_export( json_decode( file_get_contents( "php://stdin" ), true ) );'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) + php_stdout = pipe.communicate(input=json_string)[0] + php_exported = php_stdout.decode() + + # Clean up formatting. + # TODO: Just use PHPCBF for this. + php_exported = re.sub( r'^ +', lambda match: ( len(match.group(0))/2 ) * '\t', php_exported, flags=re.MULTILINE ) + php_exported = php_exported.replace( 'array (', 'array(' ) + php_exported = re.sub( r' => \n\s+', ' => ', php_exported, flags=re.MULTILINE ) + php_exported = re.sub( r'^(\s+)\d+ =>\s*', r'\1', php_exported, flags=re.MULTILINE ) + + # Add additional indents. + if indent > 0: + php_exported = re.sub( r'^', '\t' * indent, php_exported, flags=re.MULTILINE ) + return php_exported + +def Main(): + """The main method, which executes all build steps and runs the tests.""" + logging.basicConfig( + format='[[%(filename)s %(funcName)s]] - %(message)s', level=logging.INFO) + + out_dir = 'dist' + + SetupOutDir(out_dir) + GenValidatorProtoascii(out_dir) + GenValidatorPb2Py(out_dir) + GenValidatorProtoascii(out_dir) + GeneratePHP(out_dir) + +if __name__ == '__main__': + Main() diff --git a/bin/build.sh b/bin/build.sh new file mode 100644 index 00000000..78cc4557 --- /dev/null +++ b/bin/build.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -e +set -x + +# Go to the right location. +cd "$(dirname "$0")" + +BIN_PATH="$(pwd)" +PROJECT_PATH=$(dirname $PWD) +VENDOR_PATH=$PROJECT_PATH/vendor + +if ! command -v apt-get >/dev/null 2>&1; then + echo "The AMP HTML uses apt-get, make sure to run this script in a Linux environment" + exit 1 +fi + +# Install dependencies. +sudo apt-get install git python protobuf-compiler python-protobuf + +# Create and go to vendor. +if [ ! -e $VENDOR_PATH ]; then + mkdir $VENDOR_PATH +fi +cd $VENDOR_PATH + +# Clone amphtml repo. +if [ ! -e $VENDOR_PATH/amphtml ]; then + git clone https://github.com/ampproject/amphtml amphtml +else + cd $VENDOR_PATH/amphtml/validator + git fetch --tags +fi + +# Check out the latest tag. +cd $VENDOR_PATH/amphtml +LATEST_TAG=$( git describe --abbrev=0 --tags ) +git checkout $LATEST_TAG + +cp $BIN_PATH/*.py $VENDOR_PATH/amphtml/validator +cd $VENDOR_PATH/amphtml/validator + +# Create dist folder. +if [ ! -e dist ]; then + mkdir dist +fi + +# Run script. +python amphtml-update-wp.py +python validator_gen_php.py +cp dist/validator-generated.php ../../../src/Spec/ +cp dist/class-amp-allowed-tags-generated.php ../../../src/Spec/ + +echo "Generated from tag $LATEST_TAG" diff --git a/bin/validator_gen_php.py b/bin/validator_gen_php.py new file mode 100644 index 00000000..bd8c99e8 --- /dev/null +++ b/bin/validator_gen_php.py @@ -0,0 +1,382 @@ +# +# Copyright 2015 The AMP HTML Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the license. +# + +"""Generates validator-generated.php. + +Please note that this file (validator_gen_php.py) is derived from +validator_gen.py (and very similar to it). Please do a diff between +them to see the similarities/differences. + +validator_gen.py generates javascript code while, this file, +validator_gen_php.py generates PHP code. + +This script reads validator.protoascii and reflects over its contents +to generate PHP. This PHP consists of PHP classes and enums, as well +as a createRules function which instantiates the data structures +specified in validator.protoascii - the validator rules. + +From a PHP perspective, this approach looks elaborate - you may +wonder why we're not just writing PHP directly, or why we're +not encoding our rules in JSON or YAML or even, gasp, XML? Besides the +additional type safety that we gain from our approach, it allows us to +share the rule specifications, error codes, etc. between multiple +validator implemenations, including an implementation in C++. This +makes it much easier to keep otherwise likely divergent behavior in +sync. +""" + +import glob +import logging +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +import collections +import json +import google + +def ProperPHPClassName(name): + # omit the first two names, usually amp.validator + return ''.join(name.split('.')[2:]) + +def FindDescriptors(validator_pb2, msg_desc_by_name, enum_desc_by_name): + """Finds the message and enum descriptors in the file. + + This method finds the message and enum descriptors from a file descriptor; + it will visit the top-level messages, and within those the enums. + + Args: + validator_pb2: The proto2 Python module generated from validator.proto. + msg_desc_by_name: A map of message descriptors, keyed by full_name. + enum_desc_by_name: A map of enum descriptors, keyed by full name. + """ + for msg_type in validator_pb2.DESCRIPTOR.message_types_by_name.values(): + msg_desc_by_name[msg_type.full_name] = msg_type + for enum_type in msg_type.enum_types: + enum_desc_by_name[enum_type.full_name] = enum_type + + +def FieldTypeFor(descriptor, field_desc): + """Returns the PHP type for a given field descriptor. + + Args: + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + field_desc: A field descriptor for a particular field in a message. + Returns: + The PHP type for the given field descriptor. + """ + element_type = { + descriptor.FieldDescriptor.TYPE_DOUBLE: lambda: 'number', + descriptor.FieldDescriptor.TYPE_INT32: lambda: 'number', + descriptor.FieldDescriptor.TYPE_BOOL: lambda: 'boolean', + descriptor.FieldDescriptor.TYPE_STRING: lambda: 'string', + descriptor.FieldDescriptor.TYPE_ENUM: ( + lambda: field_desc.enum_type.full_name), + descriptor.FieldDescriptor.TYPE_MESSAGE: ( + lambda: field_desc.message_type.full_name), + }[field_desc.type]() + if field_desc.label == descriptor.FieldDescriptor.LABEL_REPEATED: + return '!Array' % element_type + else: + return element_type + + +def NonRepeatedValueToString(descriptor, field_desc, value): + """For a non-repeated field, renders the value as a PHP literal. + + Helper function for ValueToString. + + Args: + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + field_desc: The type descriptor for the field value to be rendered. + value: The value of the non-repeated field to be rendered. + Returns: + A PHP literal for the provided non-repeated value. + """ + if field_desc.type == descriptor.FieldDescriptor.TYPE_STRING: + escaped = ('' + value).encode('unicode-escape') + return "'%s'" % escaped.replace("'", "\\'") + if field_desc.type == descriptor.FieldDescriptor.TYPE_BOOL: + if value: + return 'true' + return 'false' + if field_desc.type == descriptor.FieldDescriptor.TYPE_ENUM: + enum_value_name = field_desc.enum_type.values_by_number[value].name + return '%s::%s' % (ProperPHPClassName(field_desc.enum_type.full_name), enum_value_name) + if value is None: + return 'null' + return str(value) + + +def ValueToString(descriptor, field_desc, value): + """Renders a field value as a PHP literal. + + Args: + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + field_desc: The type descriptor for the field value to be rendered. + value: The value of the field to be rendered. + Returns: + A PHP literal for the provided value. + """ + if field_desc.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if value: + return '[%s]' % ', '.join([NonRepeatedValueToString(descriptor, + field_desc, s) + for s in value]) + return '[]' + return NonRepeatedValueToString(descriptor, field_desc, value) + + +def PrintClassFor(descriptor, msg_desc, out): + """Prints a PHP class for the given proto message. + + This method emits a PHP for the given + proto message to sys.stdout. + + Args: + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + msg_desc: The descriptor for a particular message type. + out: a list of lines to output (without the newline characters), to + which this function will append. + """ + out.append('class %s {' % ProperPHPClassName(msg_desc.full_name)) + for field in msg_desc.fields: + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + out.append(' public $%s = [];' % field.name) + else: + out.append(' public $%s = null;' % field.name) + out.append('}') + out.append('') + + +def PrintEnumFor(enum_desc, out): + """Prints a PHP enum for the given enum descriptor. + + Args: + enum_desc: The descriptor for a particular enum type. + out: a list of lines to output (without the newline characters), to + which this function will append. + """ + out.append('class %s {' % ProperPHPClassName(enum_desc.full_name)) + str = '' + for v in enum_desc.values: + str += " const %s = '%s';\n" % (v.name, v.name) + out.append(str) + out.append('}') + + +def PrintObject(descriptor, msg, this_id, out): + """Prints an object, by recursively constructing it. + + This routine emits PHP which will construct an object modeling + the provided message (in practice the ValidatorRules message). + It references the classes and enums enitted by PrintClassFor and PrintEnumFor. + + Args: + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + msg: A protocol message instance. + this_id: The id for the object being printed (all variables have the form + o_${num} with ${num} being increasing integers + out: a list of lines to output (without the newline characters), to + which this function will append. + Returns: + The next object id, that is, next variable available for creating objects. + """ + out.append(' $o_%d = new %s();' % (this_id, ProperPHPClassName(msg.DESCRIPTOR.full_name))) + next_id = this_id + 1 + for (field_desc, field_val) in msg.ListFields(): + if field_desc.type == descriptor.FieldDescriptor.TYPE_MESSAGE: + if field_desc.label == descriptor.FieldDescriptor.LABEL_REPEATED: + for val in field_val: + field_id = next_id + next_id = PrintObject(descriptor, val, field_id, out) + out.append(' $o_%d->%s[] = $o_%d;' % (this_id, field_desc.name, field_id)) + else: + field_id = next_id + next_id = PrintObject(descriptor, field_val, field_id, out) + out.append(' $o_%d->%s = $o_%d;' % (this_id, field_desc.name, field_id)) + else: + out.append(' $o_%d->%s = %s;' % ( + this_id, field_desc.name, + ValueToString(descriptor, field_desc, field_val))) + return next_id + + +def GenValidatorPb2Py(out_dir): + """Calls the proto compiler to generate validator_pb2.py. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + subprocess.check_call(['protoc', 'validator.proto', + '--python_out=%s' % out_dir]) + open('%s/__init__.py' % out_dir, 'w').close() + logging.info('... done') + + +def GenValidatorProtoascii(out_dir): + """Assembles the validator protoascii file from the main and extensions. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + protoascii_segments = [open('validator-main.protoascii').read()] + extensions = glob.glob('extensions/*/validator-*.protoascii') + # In the Github project, the extensions are located in a sibling directory + # to the validator rather than a child directory. + if not extensions: + extensions = glob.glob('../extensions/*/validator-*.protoascii') + extensions.sort() + for extension in extensions: + protoascii_segments.append(open(extension).read()) + f = open('%s/validator.protoascii' % out_dir, 'w') + f.write(''.join(protoascii_segments)) + f.close() + + logging.info('... done') + +def GeneratePHP(out_dir): + """Calls validator_gen to generate validator-generated.php. + + Args: + out_dir: directory name of the output directory. Must not have slashes, + dots, etc. + """ + logging.info('entering ...') + assert re.match(r'^[a-zA-Z_\-0-9]+$', out_dir), 'bad out_dir: %s' % out_dir + + # These imports happen late, within this method because they don't necessarily + # exist when the module starts running, and the ones that probably do + # are checked by CheckPrereqs. + from google.protobuf import text_format + from google.protobuf import descriptor + from dist import validator_pb2 + import validator_gen_php + out = [] + GenerateValidatorGeneratedPHP(specfile='%s/validator.protoascii' % out_dir, + validator_pb2=validator_pb2, + text_format=text_format, + descriptor=descriptor, + out=out) + out.append('') + f = open('%s/validator-generated.php' % out_dir, 'w') + f.write('\n'.join(out)) + f.close() + logging.info('... done') + +def GenerateValidatorGeneratedPHP(specfile, validator_pb2, text_format, + descriptor, out): + """Main method for the code generator. + + This method reads the specfile and emits PHP to sys.stdout. + + Args: + specfile: Path to validator.protoascii, the specfile to generate + PHP from. + validator_pb2: The proto2 Python module generated from validator.proto. + text_format: The text_format module from the protobuf package, e.g. + google.protobuf.text_format. + descriptor: The descriptor module from the protobuf package, e.g. + google.protobuf.descriptor. + out: a list of lines to output (without the newline characters), to + which this function will append. + """ + # First, find the descriptors and enums and generate PHP + # classes and enums. + msg_desc_by_name = {} + enum_desc_by_name = {} + FindDescriptors(validator_pb2, msg_desc_by_name, enum_desc_by_name) + + rules_obj = '%s.RULES' % validator_pb2.DESCRIPTOR.package + all_names = [rules_obj] + msg_desc_by_name.keys() + enum_desc_by_name.keys() + all_names.sort() + + output_header = """ array( + array( + 'attr_spec_list' => array( + '[href]' => array(), + 'border' => array(), + 'download' => array(), + 'href' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'ftp', + 'geo', + 'http', + 'https', + 'mailto', + 'maps', + 'bip', + 'bbmi', + 'fb-messenger', + 'intent', + 'line', + 'skype', + 'sms', + 'snapchat', + 'tel', + 'tg', + 'threema', + 'twitter', + 'viber', + 'webcal', + 'web+mastodon', + 'whatsapp', + ), + ), + ), + 'hreflang' => array(), + 'media' => array(), + 'name' => array(), + 'referrerpolicy' => array(), + 'rel' => array( + 'blacklisted_value_regex' => '(^|\\s)(components|dns-prefetch|import|manifest|preconnect|prefetch|preload|prerender|serviceworker|stylesheet|subresource|)(\\s|$)', + ), + 'role' => array(), + 'tabindex' => array(), + 'target' => array( + 'value' => array( + '_blank', + '_self', + '_top', + ), + ), + 'type' => array( + 'value_casei' => array( + 'text/html', + ), + ), + ), + 'tag_spec' => array( + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#links', + ), + ), + ), + 'abbr' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'acronym' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'address' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'amp-3d-gltf' => array( + array( + 'attr_spec_list' => array( + 'alpha' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'antialiasing' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'autorotate' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'clearcolor' => array(), + 'enablezoom' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'maxpixelratio' => array( + 'value_regex' => '[+-]?(\\d*\\.)?\\d+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-3d-gltf', + ), + ), + ), + ), + 'amp-3q-player' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'data-id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-3q-player', + ), + ), + ), + ), + 'amp-accordion' => array( + array( + 'attr_spec_list' => array( + 'animate' => array( + 'value' => array( + '', + ), + ), + 'disable-session-states' => array( + 'value' => array( + '', + ), + ), + 'expand-single-section' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + ), + ), + 'requires_extension' => array( + 'amp-accordion', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-accordion', + ), + ), + ), + 'amp-ad' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'json' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rtc-config' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'template' => array(), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-ad extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 8, + 9, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + ), + 'requires_extension' => array( + 'amp-ad', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'data-multi-size' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'json' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rtc-config' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-ad extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 8, + 9, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + 'amp-carousel', + 'amp-fx-flying-carpet', + 'amp-lightbox', + 'amp-sticky-ad', + ), + 'requires_extension' => array( + 'amp-ad', + ), + 'spec_name' => 'amp-ad with data-multi-size attribute', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'data-enable-refresh' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'json' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-ad extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 8, + 9, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + 'amp-fx-flying-carpet', + 'amp-lightbox', + ), + 'requires_extension' => array( + 'amp-ad', + ), + 'spec_name' => 'amp-ad with data-enable-refresh attribute', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + ), + 'amp-addthis' => array( + array( + 'attr_spec_list' => array( + 'data-pub-id' => array( + 'mandatory' => true, + ), + 'data-share-media' => array( + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'data-share-url' => array( + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'data-widget-id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-addthis', + ), + ), + ), + ), + 'amp-analytics' => array( + array( + 'attr_spec_list' => array( + 'config' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'type' => array(), + ), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-analytics', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-analytics', + ), + ), + ), + 'amp-anim' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'attribution' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'alternative_names' => array( + 'srcset', + ), + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'data', + 'http', + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-anim', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-anim', + ), + ), + ), + 'amp-animation' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'trigger' => array( + 'value' => array( + 'visibility', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-animation', + ), + ), + ), + ), + 'amp-apester-media' => array( + array( + 'attr_spec_list' => array( + 'data-apester-channel-token' => array( + 'value_regex' => '[0-9a-zA-Z]+', + ), + 'data-apester-media-id' => array( + 'value_regex' => '[0-9a-zA-Z]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-apester-media', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-apester-media', + ), + ), + ), + 'amp-app-banner' => array( + array( + 'attr_spec_list' => array( + 'id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'mandatory_parent' => 'body', + 'requires_extension' => array( + 'amp-app-banner', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-app-banner', + 'unique' => true, + ), + ), + ), + 'amp-audio' => array( + array( + 'attr_spec_list' => array( + 'album' => array(), + 'artist' => array(), + 'artwork' => array(), + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'controls' => array(), + 'controlslist' => array(), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'muted' => array( + 'value' => array( + '', + ), + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'preload' => array( + 'value_casei' => array( + 'auto', + 'metadata', + 'none', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'defines_default_height' => true, + 'defines_default_width' => true, + 'supported_layouts' => array( + 2, + 3, + 1, + ), + ), + 'disallowed_ancestor' => array( + 'amp-story', + ), + 'requires_extension' => array( + 'amp-audio', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio', + ), + ), + array( + 'attr_spec_list' => array( + 'album' => array(), + 'artist' => array(), + 'artwork' => array(), + 'autoplay' => array( + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'controls' => array(), + 'controlslist' => array(), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'muted' => array( + 'value' => array( + '', + ), + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'defines_default_height' => true, + 'defines_default_width' => true, + 'supported_layouts' => array( + 2, + 3, + 1, + ), + ), + 'mandatory_ancestor' => 'amp-story', + 'requires_extension' => array( + 'amp-audio', + ), + 'spec_name' => 'amp-story >> amp-audio', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio', + ), + ), + ), + 'amp-auto-ads' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'amp-auto-ads', + ), + 'requires_extension' => array( + 'amp-auto-ads', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-auto-ads', + ), + ), + ), + 'amp-beopinion' => array( + array( + 'attr_spec_list' => array( + 'data-account' => array( + 'mandatory' => true, + 'value_regex_casei' => '[0-9a-f]{24}', + ), + 'data-content' => array( + 'value_regex_casei' => '[0-9a-f]{24}', + ), + 'data-my-content' => array( + 'value' => array( + '0', + '1', + ), + ), + 'data-name' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-beopinion', + ), + ), + ), + ), + 'amp-bind-macro' => array( + array( + 'attr_spec_list' => array( + 'arguments' => array(), + 'expression' => array( + 'mandatory' => true, + ), + 'id' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-bind', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind', + ), + ), + ), + 'amp-bodymovin-animation' => array( + array( + 'attr_spec_list' => array( + 'loop' => array( + 'value_casei' => array( + 'false', + 'number', + 'true', + ), + ), + 'noautoplay' => array( + 'value' => array( + '', + ), + ), + 'renderer' => array( + 'value_casei' => array( + 'svg', + 'html', + ), + ), + 'src' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-bodymovin-animation', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bodymovin-animation', + ), + ), + ), + 'amp-brid-player' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'data-outstream' => array( + 'value_regex' => '[0-9]+', + ), + 'data-partner' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'data-player' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'data-playlist' => array( + 'value_regex' => '[0-9]+', + ), + 'data-video' => array( + 'value_regex' => '[0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-brid-player', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brid-player', + ), + ), + ), + 'amp-brightcove' => array( + array( + 'attr_spec_list' => array( + '[data-account]' => array(), + '[data-embed]' => array(), + '[data-player-id]' => array(), + '[data-player]' => array(), + '[data-playlist-id]' => array(), + '[data-referrer]' => array(), + '[data-video-id]' => array(), + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'data-account' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-brightcove', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-brightcove', + ), + ), + ), + 'amp-byside-content' => array( + array( + 'attr_spec_list' => array( + 'data-label' => array( + 'mandatory' => true, + ), + 'data-webcare-id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-byside-content', + ), + ), + ), + ), + 'amp-call-tracking' => array( + array( + 'attr_spec_list' => array( + 'config' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-call-tracking', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-call-tracking', + ), + ), + ), + 'amp-carousel' => array( + array( + 'attr_spec_list' => array( + '[slide]' => array(), + 'arrows' => array( + 'value' => array( + '', + ), + ), + 'autoplay' => array( + 'value_regex' => '(|[0-9]+)', + ), + 'controls' => array(), + 'delay' => array( + 'value_regex' => '[0-9]+', + ), + 'dots' => array( + 'value' => array( + '', + ), + ), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'value' => array( + 'slides', + 'carousel', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-carousel', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-carousel', + ), + ), + array( + 'attr_spec_list' => array( + '[slide]' => array(), + 'arrows' => array( + 'value' => array( + '', + ), + ), + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'controls' => array(), + 'delay' => array( + 'value_regex' => '[0-9]+', + ), + 'dots' => array( + 'value' => array( + '', + ), + ), + 'lightbox' => array( + 'mandatory' => true, + ), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'value' => array( + 'slides', + 'carousel', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'reference_points' => array( + 'AMP-CAROUSEL lightbox [child]' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-CAROUSEL lightbox [lightbox-exclude]' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'requires_extension' => array( + 'amp-carousel', + 'amp-lightbox-gallery', + ), + 'spec_name' => 'AMP-CAROUSEL [lightbox]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-carousel', + ), + ), + ), + 'amp-consent' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-consent', + ), + 'unique' => true, + ), + ), + ), + 'amp-dailymotion' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'data-endscreen-enable' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'data-info' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'data-mute' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'data-sharing-enable' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'data-start' => array( + 'value_regex' => '[0-9]+', + ), + 'data-ui-highlight' => array( + 'value_regex_casei' => '([0-9a-f]{3}){1,2}', + ), + 'data-ui-logo' => array( + 'value' => array( + 'false', + 'true', + ), + ), + 'data-videoid' => array( + 'mandatory' => true, + 'value_regex_casei' => '[a-z0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-dailymotion', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-dailymotion', + ), + ), + ), + 'amp-date-countdown' => array( + array( + 'attr_spec_list' => array( + 'biggest-unit' => array( + 'value_casei' => array( + 'days', + 'hours', + 'minutes', + 'seconds', + ), + ), + 'end-date' => array( + 'value_regex' => '\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d(:[0-5]\\d(\\.\\d+)?)?(Z|[+-][0-1][0-9]:[0-5][0-9])', + ), + 'locale' => array( + 'value_casei' => array( + 'de', + 'en', + 'es', + 'fr', + 'id', + 'it', + 'ja', + 'ko', + 'nl', + 'pt', + 'ru', + 'th', + 'tr', + 'vi', + 'zh-cn', + 'zh-tw', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'offset-seconds' => array( + 'value_regex' => '-?\\d+', + ), + 'template' => array(), + 'timeleft-ms' => array( + 'value_regex' => '\\d+', + ), + 'timestamp-ms' => array( + 'value_regex' => '\\d{13}', + ), + 'timestamp-seconds' => array( + 'value_regex' => '\\d{10}', + ), + 'when-ended' => array( + 'value_casei' => array( + 'continue', + 'stop', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-date-countdown', + ), + ), + ), + ), + 'amp-date-picker' => array( + array( + 'attr_spec_list' => array( + '[max]' => array(), + '[min]' => array(), + 'allow-blocked-ranges' => array( + 'value' => array( + '', + ), + ), + 'blocked' => array(), + 'date' => array(), + 'day-size' => array( + 'value_regex' => '[0-9]+', + ), + 'first-day-of-week' => array( + 'value_regex' => '[0-6]', + ), + 'format' => array(), + 'fullscreen' => array( + 'value' => array( + '', + ), + ), + 'highlighted' => array(), + 'input-selector' => array(), + 'locale' => array(), + 'max' => array(), + 'media' => array(), + 'min' => array(), + 'mode' => array( + 'value_casei' => array( + 'static', + ), + ), + 'month-format' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'number-of-months' => array( + 'value_regex' => '[0-9]+', + ), + 'open-after-clear' => array( + 'value' => array( + '', + ), + ), + 'open-after-select' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'type' => array( + 'value_casei' => array( + 'single', + ), + ), + 'week-day-format' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-date-picker', + ), + 'spec_name' => 'amp-date-picker[type=single][mode=static]', + ), + ), + array( + 'attr_spec_list' => array( + '[max]' => array(), + '[min]' => array(), + 'allow-blocked-ranges' => array( + 'value' => array( + '', + ), + ), + 'blocked' => array(), + 'date' => array(), + 'day-size' => array( + 'value_regex' => '[0-9]+', + ), + 'first-day-of-week' => array( + 'value_regex' => '[0-6]', + ), + 'format' => array(), + 'highlighted' => array(), + 'input-selector' => array(), + 'locale' => array(), + 'max' => array(), + 'media' => array(), + 'min' => array(), + 'mode' => array( + 'mandatory' => true, + 'value_casei' => array( + 'overlay', + ), + ), + 'month-format' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'number-of-months' => array( + 'value_regex' => '[0-9]+', + ), + 'open-after-clear' => array( + 'value' => array( + '', + ), + ), + 'open-after-select' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'touch-keyboard-editable' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'value_casei' => array( + 'single', + ), + ), + 'week-day-format' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + 1, + ), + ), + 'requires_extension' => array( + 'amp-date-picker', + ), + 'spec_name' => 'amp-date-picker[type=single][mode=overlay]', + ), + ), + array( + 'attr_spec_list' => array( + '[max]' => array(), + '[min]' => array(), + 'allow-blocked-ranges' => array( + 'value' => array( + '', + ), + ), + 'blocked' => array(), + 'day-size' => array( + 'value_regex' => '[0-9]+', + ), + 'end-date' => array(), + 'end-input-selector' => array(), + 'first-day-of-week' => array( + 'value_regex' => '[0-6]', + ), + 'format' => array(), + 'fullscreen' => array( + 'value' => array( + '', + ), + ), + 'highlighted' => array(), + 'locale' => array(), + 'max' => array(), + 'media' => array(), + 'min' => array(), + 'minimum-nights' => array( + 'value_regex' => '[0-9]+', + ), + 'mode' => array( + 'value_casei' => array( + 'static', + ), + ), + 'month-format' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'number-of-months' => array( + 'value_regex' => '[0-9]+', + ), + 'open-after-clear' => array( + 'value' => array( + '', + ), + ), + 'open-after-select' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'start-date' => array(), + 'start-input-selector' => array(), + 'type' => array( + 'mandatory' => true, + 'value_casei' => array( + 'range', + ), + ), + 'week-day-format' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-date-picker', + ), + 'spec_name' => 'amp-date-picker[type=range][mode=static]', + ), + ), + array( + 'attr_spec_list' => array( + '[max]' => array(), + '[min]' => array(), + 'allow-blocked-ranges' => array( + 'value' => array( + '', + ), + ), + 'blocked' => array(), + 'day-size' => array( + 'value_regex' => '[0-9]+', + ), + 'end-date' => array(), + 'end-input-selector' => array(), + 'first-day-of-week' => array( + 'value_regex' => '[0-6]', + ), + 'format' => array(), + 'highlighted' => array(), + 'locale' => array(), + 'max' => array(), + 'media' => array(), + 'min' => array(), + 'minimum-nights' => array( + 'value_regex' => '[0-9]+', + ), + 'mode' => array( + 'mandatory' => true, + 'value_casei' => array( + 'overlay', + ), + ), + 'month-format' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'number-of-months' => array( + 'value_regex' => '[0-9]+', + ), + 'open-after-clear' => array( + 'value' => array( + '', + ), + ), + 'open-after-select' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'start-date' => array(), + 'start-input-selector' => array(), + 'touch-keyboard-editable' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'mandatory' => true, + 'value_casei' => array( + 'range', + ), + ), + 'week-day-format' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + 1, + ), + ), + 'requires_extension' => array( + 'amp-date-picker', + ), + 'spec_name' => 'amp-date-picker[type=range][mode=overlay]', + ), + ), + ), + 'amp-delight-player' => array( + array( + 'attr_spec_list' => array( + 'data-content-id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-delight-player', + ), + ), + ), + ), + 'amp-embed' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'json' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rtc-config' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'template' => array(), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-ad extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 8, + 9, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + ), + 'requires_extension' => array( + 'amp-ad', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'data-multi-size' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'json' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rtc-config' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-ad extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 8, + 9, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + 'amp-carousel', + 'amp-fx-flying-carpet', + 'amp-lightbox', + 'amp-sticky-ad', + ), + 'requires_extension' => array( + 'amp-ad', + ), + 'spec_name' => 'amp-embed with data-multi-size attribute', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + ), + 'amp-embedly-card' => array( + array( + 'attr_spec_list' => array( + 'data-url' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 4, + ), + ), + 'requires_extension' => array( + 'amp-embedly-card', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-embedly-card', + ), + ), + ), + 'amp-embedly-key' => array( + array( + 'attr_spec_list' => array( + 'value' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-embedly-card', + ), + 'unique' => true, + ), + ), + ), + 'amp-experiment' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-experiment', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-experiment', + 'unique' => true, + ), + ), + ), + 'amp-facebook' => array( + array( + 'attr_spec_list' => array( + 'data-href' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-facebook', + ), + ), + ), + ), + 'amp-facebook-comments' => array( + array( + 'attr_spec_list' => array( + 'data-href' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-facebook-comments', + ), + ), + ), + ), + 'amp-facebook-like' => array( + array( + 'attr_spec_list' => array( + 'data-href' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-facebook-like', + ), + ), + ), + ), + 'amp-facebook-page' => array( + array( + 'attr_spec_list' => array( + 'data-href' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-facebook-page', + ), + ), + ), + ), + 'amp-fit-text' => array( + array( + 'attr_spec_list' => array( + 'max-font-size' => array(), + 'media' => array(), + 'min-font-size' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-fit-text', + ), + ), + ), + ), + 'amp-font' => array( + array( + 'attr_spec_list' => array( + 'font-family' => array( + 'mandatory' => true, + ), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'on-error-add-class' => array(), + 'on-error-remove-class' => array(), + 'on-load-add-class' => array(), + 'on-load-remove-class' => array(), + 'timeout' => array( + 'value_regex' => '[0-9]+', + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-font', + ), + ), + ), + ), + 'amp-fx-flying-carpet' => array( + array( + 'attr_spec_list' => array( + 'height' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-fx-flying-carpet', + ), + ), + ), + ), + 'amp-geo' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-geo', + ), + 'unique' => true, + ), + ), + ), + 'amp-gfycat' => array( + array( + 'attr_spec_list' => array( + 'data-gfyid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noautoplay' => array( + 'value' => array( + '', + ), + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-gfycat', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gfycat', + ), + ), + ), + 'amp-gist' => array( + array( + 'attr_spec_list' => array( + 'data-gistid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 3, + ), + ), + 'requires_extension' => array( + 'amp-gist', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-gist', + ), + ), + ), + 'amp-google-document-embed' => array( + array( + 'attr_spec_list' => array( + '[src]' => array(), + '[title]' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-google-document-embed', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-google-document-embed', + ), + ), + ), + 'amp-hulu' => array( + array( + 'attr_spec_list' => array( + 'data-eid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-hulu', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-hulu', + ), + ), + ), + 'amp-iframe' => array( + array( + 'attr_spec_list' => array( + '[src]' => array(), + 'allow' => array(), + 'allowfullscreen' => array( + 'value' => array( + '', + ), + ), + 'allowpaymentrequest' => array( + 'value' => array( + '', + ), + ), + 'allowtransparency' => array( + 'value' => array( + '', + ), + ), + 'frameborder' => array( + 'value' => array( + '0', + '1', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'referrerpolicy' => array(), + 'resizable' => array( + 'value' => array( + '', + ), + ), + 'sandbox' => array(), + 'scrolling' => array( + 'value' => array( + 'auto', + 'no', + 'yes', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'data', + 'https', + ), + ), + ), + 'srcdoc' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-iframe', + ), + ), + ), + ), + 'amp-ima-video' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'data-src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'data-tag' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rotate-to-fullscreen' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-ima-video', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ima-video', + ), + ), + ), + 'amp-image-lightbox' => array( + array( + 'attr_spec_list' => array( + 'controls' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-image-lightbox', + ), + ), + ), + ), + 'amp-image-slider' => array( + array( + 'attr_spec_list' => array( + 'disable-hint-reappear' => array(), + 'initial-slider-position' => array( + 'value_regex' => '0(\\.[0-9]+)?|1(\\.0+)?', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'step-size' => array( + 'value_regex' => '0(\\.[0-9]+)?|1(\\.0+)?', + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 2, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-image-slider', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), + ), + 'amp-img' => array( + array( + 'attr_spec_list' => array( + '[alt]' => array(), + '[attribution]' => array(), + '[src]' => array(), + '[srcset]' => array(), + 'alt' => array(), + 'attribution' => array(), + 'lightbox' => array(), + 'lightbox-thumbnail-id' => array( + 'value_regex_casei' => '^[a-z][a-z\\d_-]*', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'placeholder' => array(), + 'src' => array( + 'alternative_names' => array( + 'srcset', + ), + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'data', + 'http', + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img', + ), + ), + ), + 'amp-imgur' => array( + array( + 'attr_spec_list' => array( + 'data-imgur-id' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-imgur', + ), + ), + ), + ), + 'amp-instagram' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'data-shortcode' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-instagram', + ), + ), + ), + ), + 'amp-install-serviceworker' => array( + array( + 'attr_spec_list' => array( + 'data-iframe-src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-install-serviceworker', + ), + ), + ), + ), + 'amp-izlesene' => array( + array( + 'attr_spec_list' => array( + 'data-videoid' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-izlesene', + ), + ), + ), + ), + 'amp-jwplayer' => array( + array( + 'attr_spec_list' => array( + 'data-media-id' => array( + 'value_regex_casei' => '[0-9a-z]{8}', + ), + 'data-player-id' => array( + 'mandatory' => true, + 'value_regex_casei' => '[0-9a-z]{8}', + ), + 'data-playlist-id' => array( + 'value_regex_casei' => '[0-9a-z]{8}', + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-jwplayer', + ), + ), + ), + ), + 'amp-kaltura-player' => array( + array( + 'attr_spec_list' => array( + 'data-partner' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-kaltura-player', + ), + ), + ), + ), + 'amp-layout' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + 5, + ), + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-layout', + ), + ), + ), + 'amp-lightbox' => array( + array( + 'attr_spec_list' => array( + '[open]' => array(), + 'animate-in' => array( + 'value_casei' => array( + 'fade-in', + 'fly-in-bottom', + 'fly-in-top', + ), + ), + 'controls' => array(), + 'from' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'scrollable' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-lightbox', + ), + ), + ), + ), + 'amp-list' => array( + array( + 'attr_spec_list' => array( + '[src]' => array(), + '[state]' => array(), + 'auto-resize' => array( + 'value' => array( + '', + ), + ), + 'binding' => array( + 'value' => array( + 'always', + 'no', + 'refresh', + ), + ), + 'credentials' => array(), + 'items' => array(), + 'max-items' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'reset-on-refresh' => array( + 'value' => array( + '', + 'always', + 'fetch', + ), + ), + 'single-item' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + 'template' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-list', + ), + ), + ), + ), + 'amp-live-list' => array( + array( + 'attr_spec_list' => array( + 'data-max-items-per-page' => array( + 'mandatory' => true, + 'value_regex' => '\\d+', + ), + 'data-poll-interval' => array( + 'value_regex' => '\\d{5,}', + ), + 'disabled' => array( + 'value' => array( + '', + ), + ), + 'id' => array( + 'mandatory' => true, + ), + 'sort' => array( + 'value' => array( + 'ascending', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + 3, + ), + ), + 'reference_points' => array( + 'AMP-LIVE-LIST [items]' => array( + 'mandatory' => true, + 'unique' => true, + ), + 'AMP-LIVE-LIST [pagination]' => array( + 'mandatory' => false, + 'unique' => true, + ), + 'AMP-LIVE-LIST [update]' => array( + 'mandatory' => true, + 'unique' => true, + ), + ), + 'requires_extension' => array( + 'amp-live-list', + ), + ), + ), + ), + 'amp-mathml' => array( + array( + 'attr_spec_list' => array( + 'data-formula' => array( + 'mandatory' => true, + ), + 'inline' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + ), + ), + 'requires_extension' => array( + 'amp-mathml', + ), + ), + ), + ), + 'amp-mowplayer' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'data-mediaid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-mowplayer', + ), + ), + ), + ), + 'amp-next-page' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-NEXT-PAGE > [separator]' => array( + 'mandatory' => false, + 'unique' => true, + ), + 'amp-next-page extension .json configuration' => array( + 'mandatory' => true, + 'unique' => true, + ), + ), + 'requires_extension' => array( + 'amp-next-page', + ), + 'spec_name' => 'amp-next-page with inline config', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-next-page', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-NEXT-PAGE > [separator]' => array( + 'mandatory' => false, + 'unique' => true, + ), + ), + 'requires_extension' => array( + 'amp-next-page', + ), + 'spec_name' => 'amp-next-page with src attribute', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-next-page', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'data-client' => array( + 'mandatory' => true, + ), + 'data-slot' => array( + 'mandatory' => true, + ), + 'type' => array( + 'mandatory' => true, + 'value' => array( + 'adsense', + ), + ), + ), + 'tag_spec' => array( + 'reference_points' => array( + 'AMP-NEXT-PAGE > [separator]' => array( + 'mandatory' => false, + 'unique' => true, + ), + ), + 'requires_extension' => array( + 'amp-next-page', + ), + 'spec_name' => 'amp-next-page [type=adsense]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-next-page', + 'unique' => true, + ), + ), + ), + 'amp-nexxtv-player' => array( + array( + 'attr_spec_list' => array( + 'data-client' => array( + 'mandatory' => true, + ), + 'data-mediaid' => array( + 'mandatory' => true, + 'value_regex' => '[^=/?:]+', + ), + 'data-mode' => array( + 'value' => array( + 'api', + 'static', + ), + ), + 'data-origin' => array( + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'https', + 'http', + ), + ), + ), + 'data-streamtype' => array( + 'value' => array( + 'album', + 'audio', + 'live', + 'playlist', + 'playlist-marked', + 'video', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-nexxtv-player', + ), + ), + ), + ), + 'amp-o2-player' => array( + array( + 'attr_spec_list' => array( + 'data-bcid' => array( + 'mandatory' => true, + ), + 'data-pid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-o2-player', + ), + ), + ), + ), + 'amp-ooyala-player' => array( + array( + 'attr_spec_list' => array( + 'data-embedcode' => array( + 'mandatory' => true, + ), + 'data-pcode' => array( + 'mandatory' => true, + ), + 'data-playerid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-ooyala-player', + ), + ), + ), + ), + 'amp-orientation-observer' => array( + array( + 'attr_spec_list' => array( + 'alpha-range' => array( + 'value_regex' => '(\\d+)\\s{1}(\\d+)', + ), + 'beta-range' => array( + 'value_regex' => '(\\d+)\\s{1}(\\d+)', + ), + 'gamma-range' => array( + 'value_regex' => '(\\d+)\\s{1}(\\d+)', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-orientation-observer', + ), + ), + ), + ), + 'amp-pan-zoom' => array( + array( + 'attr_spec_list' => array( + 'disable-double-tap' => array( + 'value' => array( + '', + ), + ), + 'initial-scale' => array( + 'value_regex' => '[0-9]+(\\.[0-9]+)?', + ), + 'initial-x' => array( + 'value_regex' => '[0-9]+', + ), + 'initial-y' => array( + 'value_regex' => '[0-9]+', + ), + 'max-scale' => array( + 'value_regex' => '[0-9]+(\\.[0-9]+)?', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'reset-on-resize' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 4, + ), + ), + 'requires_extension' => array( + 'amp-pan-zoom', + ), + ), + ), + ), + 'amp-pinterest' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'data-do' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-pinterest', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pinterest', + ), + ), + ), + 'amp-pixel' => array( + array( + 'attr_spec_list' => array( + 'allow-ssr-img' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'referrerpolicy' => array( + 'value' => array( + 'no-referrer', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_empty' => true, + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'defines_default_height' => true, + 'defines_default_width' => true, + 'supported_layouts' => array( + 2, + 1, + ), + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-pixel', + ), + ), + ), + 'amp-playbuzz' => array( + array( + 'attr_spec_list' => array( + 'data-comments' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'data-item' => array(), + 'data-item-info' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'data-share-buttons' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'src' => array(), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 4, + 3, + ), + ), + 'requires_extension' => array( + 'amp-playbuzz', + ), + ), + ), + ), + 'amp-position-observer' => array( + array( + 'attr_spec_list' => array( + 'intersection-ratios' => array( + 'value_regex' => '^([0]*?\\.\\d*$|1$|0$)|([0]*?\\.\\d*|1|0)\\s{1}([0]*?\\.\\d*$|1$|0$)', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'once' => array( + 'value' => array( + '', + ), + ), + 'target' => array(), + 'viewport-margins' => array( + 'value_regex' => '^(\\d+$|\\d+px$|\\d+vh$)|((\\d+|\\d+px|\\d+vh)\\s{1}(\\d+$|\\d+px$|\\d+vh$))', + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-position-observer', + ), + ), + ), + ), + 'amp-powr-player' => array( + array( + 'attr_spec_list' => array( + '[data-referrer]' => array(), + 'autoplay' => array(), + 'data-account' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-zA-Z-]+', + ), + 'data-player' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-zA-Z-]+', + ), + 'data-terms' => array(), + 'data-video' => array( + 'value_regex' => '[0-9a-zA-Z-]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-powr-player', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-powr-player', + ), + ), + ), + 'amp-reach-player' => array( + array( + 'attr_spec_list' => array( + 'data-embed-id' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-z-]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-reach-player', + ), + ), + ), + ), + 'amp-reddit' => array( + array( + 'attr_spec_list' => array( + 'data-embedlive' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'data-embedparent' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'data-embedtype' => array( + 'mandatory' => true, + 'value_casei' => array( + 'comment', + 'post', + ), + ), + 'data-src' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-reddit', + ), + ), + ), + ), + 'amp-riddle-quiz' => array( + array( + 'attr_spec_list' => array( + 'data-riddle-id' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 4, + ), + ), + 'requires_extension' => array( + 'amp-riddle-quiz', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-riddle-quiz', + ), + ), + ), + 'amp-selector' => array( + array( + 'attr_spec_list' => array( + '[disabled]' => array(), + '[selected]' => array(), + 'disabled' => array( + 'value' => array( + '', + ), + ), + 'form' => array(), + 'keyboard-select-mode' => array( + 'value_casei' => array( + 'focus', + 'none', + 'select', + ), + ), + 'media' => array(), + 'multiple' => array( + 'value' => array( + '', + ), + ), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 1, + 4, + 5, + ), + ), + 'disallowed_ancestor' => array( + 'amp-selector', + ), + 'reference_points' => array( + 'AMP-SELECTOR child' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-SELECTOR option' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + 'requires_extension' => array( + 'amp-selector', + ), + ), + ), + ), + 'amp-sidebar' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'side' => array( + 'value' => array( + 'left', + 'right', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'mandatory_parent' => 'body', + 'requires_extension' => array( + 'amp-sidebar', + ), + ), + ), + ), + 'amp-skimlinks' => array( + array( + 'attr_spec_list' => array( + 'custom-tracking-id' => array( + 'value_regex_casei' => '^.{0,50}$', + ), + 'excluded-domains' => array(), + 'link-selector' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'publisher-code' => array( + 'mandatory' => true, + 'value_regex_casei' => '^[0-9]+X[0-9]+$', + ), + 'tracking' => array( + 'value' => array( + 'false', + 'true', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-skimlinks', + ), + ), + ), + ), + 'amp-social-share' => array( + array( + 'attr_spec_list' => array( + 'data-share-endpoint' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'ftp', + 'http', + 'https', + 'mailto', + 'bbmi', + 'fb-messenger', + 'intent', + 'line', + 'skype', + 'sms', + 'snapchat', + 'tel', + 'tg', + 'threema', + 'viber', + 'whatsapp', + ), + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 5, + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-social-share', + ), + ), + ), + ), + 'amp-soundcloud' => array( + array( + 'attr_spec_list' => array( + 'data-color' => array( + 'value_regex_casei' => '([0-9a-f]{3}){1,2}', + ), + 'data-playlistid' => array( + 'value_regex' => '[0-9]+', + ), + 'data-secret-token' => array( + 'value_regex' => '[A-Za-z0-9_-]+', + ), + 'data-trackid' => array( + 'value_regex' => '[0-9]+', + ), + 'data-visual' => array( + 'value_casei' => array( + 'false', + 'true', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 3, + ), + ), + 'requires_extension' => array( + 'amp-soundcloud', + ), + ), + ), + ), + 'amp-springboard-player' => array( + array( + 'attr_spec_list' => array( + 'data-content-id' => array( + 'mandatory' => true, + ), + 'data-domain' => array( + 'mandatory' => true, + ), + 'data-items' => array( + 'mandatory' => true, + ), + 'data-mode' => array( + 'mandatory' => true, + 'value_casei' => array( + 'playlist', + 'video', + ), + ), + 'data-player-id' => array( + 'mandatory' => true, + 'value_regex_casei' => '[a-z0-9]+', + ), + 'data-site-id' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-springboard-player', + ), + ), + ), + ), + 'amp-state' => array( + array( + 'attr_spec_list' => array( + '[src]' => array(), + 'credentials' => array(), + 'id' => array( + 'mandatory' => true, + ), + 'overridable' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-bind', + ), + 'spec_name' => 'amp-state', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-bind', + ), + ), + ), + 'amp-sticky-ad' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'disallowed_ancestor' => array( + 'amp-app-banner', + ), + 'requires_extension' => array( + 'amp-sticky-ad', + ), + 'unique' => true, + ), + ), + ), + 'amp-story' => array( + array( + 'attr_spec_list' => array( + 'background-audio' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'bookend-config-src' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'poster-landscape-src' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'poster-portrait-src' => array( + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'poster-square-src' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'publisher' => array( + 'mandatory' => true, + ), + 'publisher-logo-src' => array( + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'standalone' => array( + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'title' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'body', + 'requires_extension' => array( + 'amp-story', + ), + ), + ), + ), + 'amp-story-access' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'type' => array( + 'value' => array( + 'blocking', + 'notification', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-story', + 'requires_extension' => array( + 'amp-access', + ), + ), + ), + ), + 'amp-story-auto-ads' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-story', + 'requires_extension' => array( + 'amp-story-auto-ads', + ), + 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/extensions/amp-story/amp-story-auto-ads.md', + 'unique' => true, + ), + ), + ), + 'amp-story-bookend' => array( + array( + 'attr_spec_list' => array( + 'layout' => array( + 'mandatory' => true, + 'value' => array( + 'nodisplay', + ), + ), + 'src' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'amp-story', + ), + ), + ), + 'amp-story-consent' => array( + array( + 'attr_spec_list' => array( + 'id' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'mandatory_parent' => 'amp-consent', + 'requires_extension' => array( + 'amp-consent', + 'amp-story', + ), + ), + ), + ), + 'amp-story-cta-layer' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory_ancestor' => 'amp-story-page', + 'reference_points' => array( + 'AMP-STORY-CTA-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + ), + ), + ), + 'amp-story-grid-layer' => array( + array( + 'attr_spec_list' => array( + 'template' => array( + 'mandatory' => true, + 'value' => array( + 'fill', + 'horizontal', + 'thirds', + 'vertical', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'amp-story-page', + 'reference_points' => array( + 'AMP-STORY-GRID-LAYER animate-in' => array( + 'mandatory' => false, + 'unique' => false, + ), + 'AMP-STORY-GRID-LAYER default' => array( + 'mandatory' => false, + 'unique' => false, + ), + ), + ), + ), + ), + 'amp-story-page' => array( + array( + 'attr_spec_list' => array( + 'auto-advance-after' => array(), + 'background-audio' => array( + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'id' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-story', + 'requires_extension' => array( + 'amp-story', + ), + ), + ), + ), + 'amp-timeago' => array( + array( + 'attr_spec_list' => array( + '[datetime]' => array(), + '[title]' => array(), + 'cutoff' => array( + 'value_regex' => '\\d+', + ), + 'datetime' => array( + 'mandatory' => true, + 'value_regex' => '\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d(:[0-5]\\d(\\.\\d+)?)?(Z|[+-][0-1][0-9]:[0-5][0-9])', + ), + 'locale' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 2, + 3, + 4, + ), + ), + 'requires_extension' => array( + 'amp-timeago', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-timeago', + ), + ), + ), + 'amp-twitter' => array( + array( + 'attr_spec_list' => array( + 'data-cards' => array(), + 'data-conversation' => array(), + 'data-limit' => array(), + 'data-link-color' => array(), + 'data-momentid' => array( + 'value_regex' => '\\d+', + ), + 'data-theme' => array(), + 'data-timeline-id' => array( + 'value_regex' => '\\d+', + ), + 'data-timeline-owner-screen-name' => array(), + 'data-timeline-screen-name' => array(), + 'data-timeline-slug' => array(), + 'data-timeline-source-type' => array(), + 'data-timeline-url' => array( + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'data-timeline-user-id' => array( + 'value_regex' => '\\d+', + ), + 'data-tweetid' => array(), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 9, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-twitter', + ), + ), + ), + ), + 'amp-user-notification' => array( + array( + 'attr_spec_list' => array( + 'data-dismiss-href' => array( + 'value_url' => array( + 'allow_empty' => false, + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'data-show-if-href' => array( + 'value_url' => array( + 'allow_empty' => false, + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'enctype' => array( + 'value' => array( + 'application/x-www-form-urlencoded', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-user-notification', + ), + ), + ), + ), + 'amp-video' => array( + array( + 'attr_spec_list' => array( + '[album]' => array(), + '[alt]' => array(), + '[artist]' => array(), + '[artwork]' => array(), + '[attribution]' => array(), + '[controls]' => array(), + '[controlslist]' => array(), + '[loop]' => array(), + '[poster]' => array(), + '[preload]' => array(), + '[src]' => array(), + '[title]' => array(), + 'album' => array(), + 'alt' => array(), + 'artist' => array(), + 'artwork' => array(), + 'attribution' => array(), + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'controls' => array( + 'value' => array( + '', + ), + ), + 'controlslist' => array(), + 'crossorigin' => array(), + 'disableremoteplayback' => array( + 'value' => array( + '', + ), + ), + 'dock' => array(), + 'lightbox' => array(), + 'lightbox-thumbnail-id' => array( + 'value_regex_casei' => '^[a-z][a-z\\d_-]*', + ), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'muted' => array( + 'value' => array( + '', + ), + ), + 'noaudio' => array( + 'value' => array( + '', + ), + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'placeholder' => array(), + 'poster' => array(), + 'preload' => array( + 'value' => array( + 'auto', + 'metadata', + 'none', + '', + ), + ), + 'rotate-to-fullscreen' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'also_requires_tag_warning' => array( + 'amp-video extension .js script', + ), + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'disallowed_ancestor' => array( + 'amp-story', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video', + ), + ), + array( + 'attr_spec_list' => array( + '[album]' => array(), + '[alt]' => array(), + '[artist]' => array(), + '[artwork]' => array(), + '[attribution]' => array(), + '[controls]' => array(), + '[controlslist]' => array(), + '[loop]' => array(), + '[poster]' => array(), + '[preload]' => array(), + '[src]' => array(), + '[title]' => array(), + 'album' => array(), + 'alt' => array(), + 'artist' => array(), + 'artwork' => array(), + 'attribution' => array(), + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'controls' => array( + 'value' => array( + '', + ), + ), + 'controlslist' => array(), + 'crossorigin' => array(), + 'disableremoteplayback' => array( + 'value' => array( + '', + ), + ), + 'dock' => array(), + 'loop' => array( + 'value' => array( + '', + ), + ), + 'media' => array(), + 'muted' => array( + 'value' => array( + '', + ), + ), + 'noaudio' => array( + 'value' => array( + '', + ), + ), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'placeholder' => array(), + 'poster' => array( + 'mandatory' => true, + ), + 'preload' => array( + 'value' => array( + 'auto', + 'metadata', + 'none', + '', + ), + ), + 'rotate-to-fullscreen' => array( + 'value' => array( + '', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'mandatory_ancestor' => 'amp-story', + 'requires_extension' => array( + 'amp-video', + ), + 'spec_name' => 'amp-story >> amp-video', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-video', + ), + ), + ), + 'amp-vimeo' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array( + 'value' => array( + '', + ), + ), + 'data-videoid' => array( + 'mandatory' => true, + 'value_regex' => '[0-9]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-vimeo', + ), + ), + ), + ), + 'amp-vine' => array( + array( + 'attr_spec_list' => array( + 'data-vineid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-vine', + ), + ), + ), + ), + 'amp-viqeo-player' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'data-profileid' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-f]*', + ), + 'data-videoid' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-viqeo-player', + ), + ), + ), + ), + 'amp-vk' => array( + array( + 'attr_spec_list' => array( + 'data-embedtype' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 2, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-vk', + ), + ), + ), + ), + 'amp-web-push' => array( + array( + 'attr_spec_list' => array( + 'helper-iframe-url' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'id' => array( + 'mandatory' => true, + 'value' => array( + 'amp-web-push', + ), + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'permission-dialog-url' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + 'service-worker-url' => array( + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 1, + ), + ), + 'requires_extension' => array( + 'amp-web-push', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push', + ), + ), + ), + 'amp-web-push-widget' => array( + array( + 'attr_spec_list' => array( + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'visibility' => array( + 'mandatory' => true, + 'value' => array( + 'blocked', + 'subscribed', + 'unsubscribed', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 2, + ), + ), + 'requires_extension' => array( + 'amp-web-push', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-web-push', + ), + ), + ), + 'amp-wistia-player' => array( + array( + 'attr_spec_list' => array( + 'data-media-hashed-id' => array( + 'mandatory' => true, + 'value_regex' => '[0-9a-zA-Z]+', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + 'rotate-to-fullscreen' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 4, + ), + ), + 'requires_extension' => array( + 'amp-wistia-player', + ), + ), + ), + ), + 'amp-yotpo' => array( + array( + 'attr_spec_list' => array( + 'data-app-key' => array( + 'mandatory' => true, + ), + 'data-widget-type' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-yotpo', + ), + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-yotpo', + ), + ), + ), + 'amp-youtube' => array( + array( + 'attr_spec_list' => array( + '[data-videoid]' => array(), + 'autoplay' => array(), + 'credentials' => array( + 'value_casei' => array( + 'include', + 'omit', + ), + ), + 'data-live-channelid' => array( + 'value_regex' => '[^=/?:]+', + ), + 'data-videoid' => array( + 'value_regex' => '[^=/?:]+', + ), + 'lightbox' => array(), + 'lightbox-thumbnail-id' => array( + 'value_regex_casei' => '^[a-z][a-z\\d_-]*', + ), + 'media' => array(), + 'noloading' => array( + 'value' => array( + '', + ), + ), + ), + 'tag_spec' => array( + 'amp_layout' => array( + 'supported_layouts' => array( + 6, + 2, + 3, + 7, + 1, + 4, + ), + ), + 'requires_extension' => array( + 'amp-youtube', + ), + ), + ), + ), + 'article' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'aside' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'audio' => array( + array( + 'attr_spec_list' => array( + 'autoplay' => array(), + 'controls' => array(), + 'loop' => array(), + 'muted' => array(), + 'preload' => array(), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'data', + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'noscript', + 'mandatory_ancestor_suggested_alternative' => 'amp-audio', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-audio', + ), + ), + ), + 'b' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'base' => array( + array( + 'attr_spec_list' => array( + 'href' => array( + 'value' => array( + '/', + ), + ), + 'target' => array( + 'value_casei' => array( + '_blank', + '_self', + '_top', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'unique' => true, + ), + ), + ), + 'bdi' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'bdo' => array( + array( + 'attr_spec_list' => array( + 'dir' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'big' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'blockquote' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + 'cite' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + ), + 'tag_spec' => array(), + ), + ), + 'body' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'html', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + ), + 'br' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'button' => array( + array( + 'attr_spec_list' => array( + '[disabled]' => array(), + '[type]' => array(), + '[value]' => array(), + 'disabled' => array( + 'value' => array( + '', + ), + ), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'role' => array(), + 'tabindex' => array(), + 'type' => array(), + 'value' => array(), + ), + 'tag_spec' => array(), + ), + array( + 'attr_spec_list' => array( + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'open-button' => array( + 'value' => array( + '', + ), + ), + 'role' => array(), + 'tabindex' => array(), + 'type' => array(), + 'value' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'amp-app-banner', + 'spec_name' => 'amp-app-banner button[open-button]', + ), + ), + ), + 'caption' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'center' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'circle' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'cx' => array(), + 'cy' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'r' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'cite' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'clippath' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'clippathunits' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'code' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'col' => array( + array( + 'attr_spec_list' => array( + 'span' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'colgroup' => array( + array( + 'attr_spec_list' => array( + 'span' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'data' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'datalist' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + ), + 'dd' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'defs' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'del' => array( + array( + 'attr_spec_list' => array( + 'cite' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'datetime' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'desc' => array( + array( + 'attr_spec_list' => array( + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'dfn' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'dir' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'div' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'verify-error' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [verify-error]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'template' => array( + 'mandatory' => true, + ), + 'verify-error' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [verify-error][template]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submitting' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submitting]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submitting' => array( + 'mandatory' => true, + ), + 'template' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submitting][template]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submit-success' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submit-success]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submit-success' => array( + 'mandatory' => true, + ), + 'template' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submit-success][template]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submit-error' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submit-error]', + ), + ), + array( + 'attr_spec_list' => array( + 'align' => array(), + 'submit-error' => array( + 'mandatory' => true, + ), + 'template' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form', + 'spec_name' => 'FORM DIV [submit-error][template]', + ), + ), + array( + 'attr_spec_list' => array( + 'first' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-image-slider', + 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [first]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), + array( + 'attr_spec_list' => array( + 'second' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-image-slider', + 'spec_name' => 'AMP-IMAGE-SLIDER > DIV [second]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-image-slider', + ), + ), + ), + 'dl' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'dt' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'ellipse' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'cx' => array(), + 'cy' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'rx' => array(), + 'ry' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'em' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'fecolormatrix' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'in' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'type' => array(), + 'unicode-bidi' => array(), + 'values' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'fecomposite' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'in' => array(), + 'in2' => array(), + 'k1' => array(), + 'k2' => array(), + 'k3' => array(), + 'k4' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'operator' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'feflood' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'fegaussianblur' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'edgemode' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'in' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stddeviation' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'femerge' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'femergenode' => array( + array( + 'attr_spec_list' => array( + 'in' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'feoffset' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'dx' => array(), + 'dy' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'in' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'result' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'fieldset' => array( + array( + 'attr_spec_list' => array( + '[disabled]' => array(), + 'disabled' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + ), + 'tag_spec' => array(), + ), + ), + 'figcaption' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'figure' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'filter' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'filterres' => array(), + 'filterunits' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'primitiveunits' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'footer' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'form' => array( + array( + 'attr_spec_list' => array( + 'accept' => array(), + 'accept-charset' => array(), + 'action' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + 'action-xhr' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + 'autocomplete' => array(), + 'custom-validation-reporting' => array( + 'value' => array( + 'as-you-go', + 'interact-and-submit', + 'show-all-on-submit', + 'show-first-on-submit', + ), + ), + 'enctype' => array(), + 'method' => array( + 'value_casei' => array( + 'get', + ), + ), + 'name' => array(), + 'novalidate' => array(), + 'target' => array( + 'mandatory' => true, + 'value_casei' => array( + '_blank', + '_top', + ), + ), + 'verify-xhr' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'amp-app-banner', + ), + 'requires_extension' => array( + 'amp-form', + ), + 'spec_name' => 'FORM [method=GET]', + ), + ), + array( + 'attr_spec_list' => array( + 'accept' => array(), + 'accept-charset' => array(), + 'action-xhr' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + 'autocomplete' => array(), + 'custom-validation-reporting' => array( + 'value' => array( + 'as-you-go', + 'interact-and-submit', + 'show-all-on-submit', + 'show-first-on-submit', + ), + ), + 'enctype' => array(), + 'method' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'post', + ), + ), + 'name' => array(), + 'novalidate' => array(), + 'target' => array( + 'value_casei' => array( + '_blank', + '_top', + ), + ), + 'verify-xhr' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + ), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'amp-app-banner', + ), + 'requires_extension' => array( + 'amp-form', + ), + 'spec_name' => 'FORM [method=POST]', + ), + ), + ), + 'g' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'glyph' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'arabic-form' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'd' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-name' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'horiz-adv-x' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'orientation' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'vert-adv-y' => array(), + 'vert-origin-x' => array(), + 'vert-origin-y' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'glyphref' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'dx' => array(), + 'dy' => array(), + 'enable-background' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'format' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'glyphref' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'h1' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'h2' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'h3' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'h4' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'h5' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'h6' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'head' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'html', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + ), + 'header' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'hgroup' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'hkern' => array( + array( + 'attr_spec_list' => array( + 'g1' => array(), + 'g2' => array(), + 'k' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'u1' => array(), + 'u2' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'hr' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'html' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => '!doctype', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + ), + 'i' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'iframe' => array( + array( + 'attr_spec_list' => array( + 'frameborder' => array( + 'value' => array( + '0', + '1', + ), + ), + 'height' => array(), + 'name' => array(), + 'referrerpolicy' => array(), + 'resizable' => array( + 'value' => array( + '', + ), + ), + 'sandbox' => array(), + 'scrolling' => array( + 'value' => array( + 'auto', + 'yes', + 'no', + ), + ), + 'src' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_relative' => false, + 'protocol' => array( + 'data', + 'https', + ), + ), + ), + 'srcdoc' => array(), + 'width' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'noscript', + 'mandatory_ancestor_suggested_alternative' => 'amp-iframe', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-iframe', + ), + ), + ), + 'image' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'preserveaspectratio' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'blacklisted_value_regex' => '(^|\\s)data:image\\/svg\\+xml', + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'data', + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'img' => array( + array( + 'attr_spec_list' => array( + 'alt' => array(), + 'attribution' => array(), + 'border' => array(), + 'decoding' => array( + 'value' => array( + 'async', + 'auto', + 'sync', + ), + ), + 'height' => array(), + 'ismap' => array(), + 'longdesc' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'sizes' => array(), + 'src' => array( + 'alternative_names' => array( + 'srcset', + ), + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'allow_relative' => true, + 'protocol' => array( + 'data', + 'https', + ), + ), + ), + 'width' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'noscript', + 'mandatory_ancestor_suggested_alternative' => 'amp-img', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img', + ), + ), + ), + 'input' => array( + array( + 'attr_spec_list' => array( + '[accept]' => array(), + '[accesskey]' => array(), + '[autocomplete]' => array(), + '[checked]' => array(), + '[disabled]' => array(), + '[height]' => array(), + '[inputmode]' => array(), + '[max]' => array(), + '[maxlength]' => array(), + '[min]' => array(), + '[minlength]' => array(), + '[multiple]' => array(), + '[pattern]' => array(), + '[placeholder]' => array(), + '[readonly]' => array(), + '[required]' => array(), + '[selectiondirection]' => array(), + '[size]' => array(), + '[spellcheck]' => array(), + '[step]' => array(), + '[type]' => array(), + '[value]' => array(), + '[width]' => array(), + 'accept' => array(), + 'accesskey' => array(), + 'autocomplete' => array(), + 'autofocus' => array(), + 'checked' => array(), + 'disabled' => array(), + 'height' => array(), + 'inputmode' => array(), + 'list' => array(), + 'max' => array(), + 'maxlength' => array(), + 'min' => array(), + 'minlength' => array(), + 'multiple' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'no-verify' => array( + 'value' => array( + '', + ), + ), + 'pattern' => array(), + 'placeholder' => array(), + 'readonly' => array(), + 'required' => array(), + 'selectiondirection' => array(), + 'size' => array(), + 'spellcheck' => array(), + 'step' => array(), + 'tabindex' => array(), + 'type' => array( + 'blacklisted_value_regex' => '(^|\\s)(button|file|image|password|)(\\s|$)', + ), + 'value' => array(), + 'width' => array(), + ), + 'tag_spec' => array( + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + array( + 'attr_spec_list' => array( + '[accept]' => array(), + '[accesskey]' => array(), + '[autocomplete]' => array(), + '[checked]' => array(), + '[disabled]' => array(), + '[height]' => array(), + '[inputmode]' => array(), + '[max]' => array(), + '[maxlength]' => array(), + '[min]' => array(), + '[minlength]' => array(), + '[multiple]' => array(), + '[pattern]' => array(), + '[placeholder]' => array(), + '[readonly]' => array(), + '[required]' => array(), + '[selectiondirection]' => array(), + '[size]' => array(), + '[spellcheck]' => array(), + '[step]' => array(), + '[value]' => array(), + '[width]' => array(), + 'accept' => array(), + 'accesskey' => array(), + 'autocomplete' => array(), + 'autofocus' => array(), + 'checked' => array(), + 'disabled' => array(), + 'height' => array(), + 'inputmode' => array(), + 'list' => array(), + 'max' => array(), + 'maxlength' => array(), + 'min' => array(), + 'minlength' => array(), + 'multiple' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'no-verify' => array( + 'value' => array( + '', + ), + ), + 'pattern' => array(), + 'placeholder' => array(), + 'readonly' => array(), + 'required' => array(), + 'selectiondirection' => array(), + 'size' => array(), + 'spellcheck' => array(), + 'step' => array(), + 'tabindex' => array(), + 'type' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'file', + ), + ), + 'value' => array(), + 'width' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form [method=post]', + 'spec_name' => 'INPUT [type=file]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + array( + 'attr_spec_list' => array( + '[accept]' => array(), + '[accesskey]' => array(), + '[autocomplete]' => array(), + '[checked]' => array(), + '[disabled]' => array(), + '[height]' => array(), + '[inputmode]' => array(), + '[max]' => array(), + '[maxlength]' => array(), + '[min]' => array(), + '[minlength]' => array(), + '[multiple]' => array(), + '[pattern]' => array(), + '[placeholder]' => array(), + '[readonly]' => array(), + '[required]' => array(), + '[selectiondirection]' => array(), + '[size]' => array(), + '[spellcheck]' => array(), + '[step]' => array(), + '[value]' => array(), + '[width]' => array(), + 'accept' => array(), + 'accesskey' => array(), + 'autocomplete' => array(), + 'autofocus' => array(), + 'checked' => array(), + 'disabled' => array(), + 'height' => array(), + 'inputmode' => array(), + 'list' => array(), + 'max' => array(), + 'maxlength' => array(), + 'min' => array(), + 'minlength' => array(), + 'multiple' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'pattern' => array(), + 'placeholder' => array(), + 'readonly' => array(), + 'required' => array(), + 'selectiondirection' => array(), + 'size' => array(), + 'spellcheck' => array(), + 'step' => array(), + 'tabindex' => array(), + 'type' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'password', + ), + ), + 'value' => array(), + 'width' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'form [method=post]', + 'spec_name' => 'INPUT [type=password]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + array( + 'attr_spec_list' => array( + '[accept]' => array(), + '[accesskey]' => array(), + '[autocomplete]' => array(), + '[checked]' => array(), + '[disabled]' => array(), + '[height]' => array(), + '[inputmode]' => array(), + '[max]' => array(), + '[maxlength]' => array(), + '[min]' => array(), + '[minlength]' => array(), + '[multiple]' => array(), + '[pattern]' => array(), + '[placeholder]' => array(), + '[readonly]' => array(), + '[required]' => array(), + '[selectiondirection]' => array(), + '[size]' => array(), + '[spellcheck]' => array(), + '[step]' => array(), + '[type]' => array(), + '[value]' => array(), + '[width]' => array(), + 'accept' => array(), + 'accesskey' => array(), + 'autocomplete' => array(), + 'autofocus' => array(), + 'checked' => array(), + 'disabled' => array(), + 'height' => array(), + 'inputmode' => array(), + 'list' => array(), + 'mask' => array( + 'dispatch_key' => 1, + 'mandatory' => true, + ), + 'mask-output' => array(), + 'max' => array(), + 'maxlength' => array(), + 'min' => array(), + 'minlength' => array(), + 'multiple' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + 'pattern' => array(), + 'placeholder' => array(), + 'readonly' => array(), + 'required' => array(), + 'selectiondirection' => array(), + 'size' => array(), + 'spellcheck' => array(), + 'step' => array(), + 'tabindex' => array(), + 'type' => array( + 'value' => array( + 'text', + 'tel', + 'search', + ), + ), + 'value' => array(), + 'width' => array(), + ), + 'tag_spec' => array( + 'requires_extension' => array( + 'amp-inputmask', + ), + 'spec_name' => 'input [mask]', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-inputmask', + ), + ), + ), + 'ins' => array( + array( + 'attr_spec_list' => array( + 'cite' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'datetime' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'kbd' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'label' => array( + array( + 'attr_spec_list' => array( + 'for' => array(), + ), + 'tag_spec' => array( + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + ), + 'legend' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'li' => array( + array( + 'attr_spec_list' => array( + 'value' => array( + 'value_regex' => '[0-9]*', + ), + ), + 'tag_spec' => array(), + ), + ), + 'line' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x1' => array(), + 'x2' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y1' => array(), + 'y2' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'lineargradient' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'gradienttransform' => array(), + 'gradientunits' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'shape-rendering' => array(), + 'spreadmethod' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x1' => array(), + 'x2' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y1' => array(), + 'y2' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'link' => array( + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array(), + 'hreflang' => array(), + 'media' => array(), + 'rel' => array( + 'blacklisted_value_regex' => '(^|\\s)(canonical|components|import|manifest|preload|serviceworker|stylesheet|subresource|)(\\s|$)', + 'mandatory' => true, + ), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'template', + ), + 'spec_name' => 'link rel=', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'hreflang' => array(), + 'media' => array(), + 'rel' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'canonical', + ), + ), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'head', + 'spec_name' => 'link rel=canonical', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + 'hreflang' => array(), + 'media' => array(), + 'rel' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'manifest', + ), + ), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'link rel=manifest', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'as' => array(), + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array(), + 'hreflang' => array(), + 'media' => array(), + 'rel' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'preload', + ), + ), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'template', + ), + 'spec_name' => 'link rel=preload', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'async' => array(), + 'crossorigin' => array(), + 'href' => array( + 'mandatory' => true, + 'value_regex' => 'https://cdn\\.materialdesignicons\\.com/([0-9]+\\.?)+/css/materialdesignicons\\.min\\.css|https://cloud\\.typography\\.com/[0-9]*/[0-9]*/css/fonts\\.css|https://fast\\.fonts\\.net/.*|https://fonts\\.googleapis\\.com/css\\?.*|https://fonts\\.googleapis\\.com/icon\\?.*|https://fonts\\.googleapis\\.com/earlyaccess/.*\\.css|https://maxcdn\\.bootstrapcdn\\.com/font-awesome/([0-9]+\\.?)+/css/font-awesome\\.min\\.css(\\?.*)?|https://(use|pro)\\.fontawesome\\.com/releases/v([0-9]+\\.?)+/css/(all|brands|solid|regular|light|fontawesome)\\.css|https://(use|pro)\\.fontawesome\\.com/[0-9a-zA-Z]+\\.css|https://use\\.typekit\\.net/[\\w\\p{L}\\p{N}_]+\\.css', + ), + 'integrity' => array(), + 'media' => array(), + 'rel' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'stylesheet', + ), + ), + 'type' => array( + 'value_casei' => array( + 'text/css', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'link rel=stylesheet for fonts', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#custom-fonts', + ), + ), + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array( + 'mandatory' => true, + ), + 'hreflang' => array(), + 'itemprop' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'sameas', + ), + ), + 'media' => array(), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'spec_name' => 'link itemprop=sameAs', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array( + 'mandatory' => true, + ), + 'hreflang' => array(), + 'itemprop' => array( + 'mandatory' => true, + ), + 'media' => array(), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'spec_name' => 'link itemprop=', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'charset' => array( + 'value_casei' => array( + 'utf-8', + ), + ), + 'color' => array(), + 'crossorigin' => array(), + 'href' => array( + 'mandatory' => true, + ), + 'hreflang' => array(), + 'media' => array(), + 'property' => array( + 'mandatory' => true, + ), + 'sizes' => array(), + 'target' => array(), + 'type' => array(), + ), + 'tag_spec' => array( + 'spec_name' => 'link property=', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + ), + 'listing' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'main' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'mark' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'marker' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'markerheight' => array(), + 'markerunits' => array(), + 'markerwidth' => array(), + 'mask' => array(), + 'opacity' => array(), + 'orient' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'preserveaspectratio' => array(), + 'refx' => array(), + 'refy' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'viewbox' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'mask' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'maskcontentunits' => array(), + 'maskunits' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'meta' => array( + array( + 'attr_spec_list' => array( + 'charset' => array( + 'dispatch_key' => 1, + 'mandatory' => true, + 'value_casei' => array( + 'utf-8', + ), + ), + ), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'head', + 'spec_name' => 'meta charset=utf-8', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_properties' => array( + 'height' => array(), + 'initial-scale' => array(), + 'maximum-scale' => array(), + 'minimum-scale' => array(), + 'shrink-to-fit' => array(), + 'user-scalable' => array(), + 'viewport-fit' => array(), + 'width' => array( + 'mandatory' => true, + 'value' => 'device-width', + ), + ), + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value' => array( + 'viewport', + ), + ), + ), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=viewport', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_properties' => array( + 'chrome' => array( + 'value' => '1', + ), + 'ie' => array( + 'value' => 'edge', + ), + ), + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'x-ua-compatible', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=X-UA-Compatible', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_regex' => '.*app-id=.*', + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'apple-itunes-app', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=apple-itunes-app', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-experiments-opt-in', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-experiments-opt-in', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_url' => array( + 'protocol' => array( + 'https', + ), + ), + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-3p-iframe-src', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-3p-iframe-src', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-ad', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-experiment-token', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-experiment-token', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-link-variable-allowed-origin', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-link-variable-allowed-origin', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-google-client-id-api', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-google-clientid-id-api', + ), + ), + array( + 'attr_spec_list' => array( + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-ad-doubleclick-sra', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-ad-doubleclick-sra', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array(), + 'itemprop' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(amp-.*|amp4ads-.*|apple-itunes-app|content-disposition|revisit-after|viewport)(\\s|$)', + ), + 'property' => array(), + 'scheme' => array(), + ), + 'tag_spec' => array( + 'spec_name' => 'meta name= and content=', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_casei' => array( + 'text/html; charset=utf-8', + ), + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'content-type', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=Content-Type', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'content-language', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=content-language', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'pics-label', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=pics-label', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'imagetoolbar', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=imagetoolbar', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_casei' => array( + 'text/css', + ), + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'content-style-type', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=Content-Style-Type', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_casei' => array( + 'text/javascript', + ), + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'content-script-type', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=Content-Script-Type', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'origin-trial', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=origin-trial', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'resource-type', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=resource-type', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + 'value_casei' => array( + 'off', + 'on', + ), + ), + 'http-equiv' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'x-dns-prefetch-control', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta http-equiv=x-dns-prefetch-control', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#html-tags', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-ad-enable-refresh', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'head', + 'spec_name' => 'meta name=amp-ad-enable-refresh', + ), + ), + array( + 'attr_spec_list' => array( + 'content' => array( + 'mandatory' => true, + ), + 'name' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'amp-to-amp-navigation', + ), + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'head', + 'spec_name' => 'meta name=amp-to-amp-navigation', + 'unique' => true, + ), + ), + ), + 'metadata' => array( + array( + 'attr_spec_list' => array( + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'meter' => array( + array( + 'attr_spec_list' => array( + 'high' => array(), + 'low' => array(), + 'max' => array(), + 'min' => array(), + 'optimum' => array(), + 'value' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'multicol' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'nav' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + array( + 'attr_spec_list' => array( + 'toolbar' => array( + 'dispatch_key' => 1, + 'mandatory' => true, + ), + 'toolbar-target' => array( + 'mandatory' => true, + ), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'amp-sidebar', + 'spec_name' => 'amp-sidebar > nav', + ), + ), + ), + 'nextid' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'nobr' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'noscript' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'head', + 'spec_name' => 'noscript enclosure for boilerplate', + 'spec_url' => 'https://github.com/ampproject/amphtml/blob/master/spec/amp-boilerplate.md', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'disallowed_ancestor' => array( + 'noscript', + ), + 'mandatory_ancestor' => 'body', + ), + ), + ), + 'o:p' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'ol' => array( + array( + 'attr_spec_list' => array( + 'reversed' => array( + 'value' => array( + '', + ), + ), + 'start' => array( + 'value_regex' => '[0-9]*', + ), + 'type' => array( + 'value_regex' => '[1AaIi]', + ), + ), + 'tag_spec' => array(), + ), + ), + 'optgroup' => array( + array( + 'attr_spec_list' => array( + '[disabled]' => array(), + '[label]' => array(), + 'disabled' => array(), + 'label' => array(), + ), + 'tag_spec' => array( + 'mandatory_parent' => 'select', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + ), + 'option' => array( + array( + 'attr_spec_list' => array( + '[disabled]' => array(), + '[label]' => array(), + '[selected]' => array(), + '[value]' => array(), + 'disabled' => array(), + 'label' => array(), + 'selected' => array(), + 'value' => array(), + ), + 'tag_spec' => array( + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-form', + ), + ), + ), + 'output' => array( + array( + 'attr_spec_list' => array( + 'for' => array(), + 'form' => array(), + 'name' => array( + 'blacklisted_value_regex' => '(^|\\s)(__amp_\\S*|__count__|__defineGetter__|__defineSetter__|__lookupGetter__|__lookupSetter__|__noSuchMethod__|__parent__|__proto__|__AMP_\\S*|\\$p|\\$proxy|acceptCharset|addEventListener|appendChild|assignedSlot|attachShadow|baseURI|checkValidity|childElementCount|childNodes|classList|className|clientHeight|clientLeft|clientTop|clientWidth|compareDocumentPosition|computedName|computedRole|contentEditable|createShadowRoot|enqueAction|firstChild|firstElementChild|getAnimations|getAttribute|getAttributeNS|getAttributeNode|getAttributeNodeNS|getBoundingClientRect|getClientRects|getDestinationInsertionPoints|getElementsByClassName|getElementsByTagName|getElementsByTagNameNS|getRootNode|hasAttribute|hasAttributeNS|hasAttributes|hasChildNodes|hasPointerCapture|innerHTML|innerText|inputMode|insertAdjacentElement|insertAdjacentHTML|insertAdjacentText|isContentEditable|isDefaultNamespace|isEqualNode|isSameNode|lastChild|lastElementChild|lookupNamespaceURI|namespaceURI|nextElementSibling|nextSibling|nodeName|nodeType|nodeValue|offsetHeight|offsetLeft|offsetParent|offsetTop|offsetWidth|outerHTML|outerText|ownerDocument|parentElement|parentNode|previousElementSibling|previousSibling|querySelector|querySelectorAll|releasePointerCapture|removeAttribute|removeAttributeNS|removeAttributeNode|removeChild|removeEventListener|replaceChild|reportValidity|requestPointerLock|scrollHeight|scrollIntoView|scrollIntoViewIfNeeded|scrollLeft|scrollWidth|setAttribute|setAttributeNS|setAttributeNode|setAttributeNodeNS|setPointerCapture|shadowRoot|styleMap|tabIndex|tagName|textContent|toString|valueOf|(webkit|ms|moz|o)dropzone|(webkit|moz|ms|o)MatchesSelector|(webkit|moz|ms|o)RequestFullScreen|(webkit|moz|ms|o)RequestFullscreen)(\\s|$)', + ), + ), + 'tag_spec' => array(), + ), + ), + 'p' => array( + array( + 'attr_spec_list' => array( + 'align' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'path' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'd' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pathlength' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'pattern' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'patterncontentunits' => array(), + 'patterntransform' => array(), + 'patternunits' => array(), + 'pointer-events' => array(), + 'preserveaspectratio' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'viewbox' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'picture' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array( + 'mandatory_parent' => 'noscript', + 'spec_url' => 'https://www.ampproject.org/docs/reference/components/amp-img', + ), + ), + ), + 'polygon' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'points' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'polyline' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'points' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'pre' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'progress' => array( + array( + 'attr_spec_list' => array( + 'max' => array(), + 'value' => array(), + ), + 'tag_spec' => array(), + ), + ), + 'q' => array( + array( + 'attr_spec_list' => array( + 'cite' => array( + 'blacklisted_value_regex' => '__amp_source_origin', + 'value_url' => array( + 'allow_empty' => true, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + ), + 'tag_spec' => array(), + ), + ), + 'radialgradient' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'cx' => array(), + 'cy' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'fr' => array(), + 'fx' => array(), + 'fy' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'gradienttransform' => array(), + 'gradientunits' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'r' => array(), + 'shape-rendering' => array(), + 'spreadmethod' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'xlink:actuate' => array(), + 'xlink:arcrole' => array(), + 'xlink:href' => array( + 'alternative_names' => array( + 'href', + ), + 'value_url' => array( + 'allow_empty' => false, + 'protocol' => array( + 'http', + 'https', + ), + ), + ), + 'xlink:role' => array(), + 'xlink:show' => array(), + 'xlink:title' => array(), + 'xlink:type' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'rb' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'rect' => array( + array( + 'attr_spec_list' => array( + 'alignment-baseline' => array(), + 'baseline-shift' => array(), + 'clip' => array(), + 'clip-path' => array(), + 'clip-rule' => array(), + 'color' => array(), + 'color-interpolation' => array(), + 'color-interpolation-filters' => array(), + 'color-profile' => array(), + 'color-rendering' => array(), + 'cursor' => array(), + 'direction' => array(), + 'display' => array(), + 'dominant-baseline' => array(), + 'enable-background' => array(), + 'externalresourcesrequired' => array(), + 'fill' => array(), + 'fill-opacity' => array(), + 'fill-rule' => array(), + 'filter' => array(), + 'flood-color' => array(), + 'flood-opacity' => array(), + 'focusable' => array(), + 'font-family' => array(), + 'font-size' => array(), + 'font-size-adjust' => array(), + 'font-stretch' => array(), + 'font-style' => array(), + 'font-variant' => array(), + 'font-weight' => array(), + 'glyph-orientation-horizontal' => array(), + 'glyph-orientation-vertical' => array(), + 'height' => array(), + 'image-rendering' => array(), + 'kerning' => array(), + 'letter-spacing' => array(), + 'lighting-color' => array(), + 'marker-end' => array(), + 'marker-mid' => array(), + 'marker-start' => array(), + 'mask' => array(), + 'opacity' => array(), + 'overflow' => array(), + 'pointer-events' => array(), + 'requiredextensions' => array(), + 'requiredfeatures' => array(), + 'rx' => array(), + 'ry' => array(), + 'shape-rendering' => array(), + 'sketch:type' => array(), + 'stop-color' => array(), + 'stop-opacity' => array(), + 'stroke' => array(), + 'stroke-dasharray' => array(), + 'stroke-dashoffset' => array(), + 'stroke-linecap' => array(), + 'stroke-linejoin' => array(), + 'stroke-miterlimit' => array(), + 'stroke-opacity' => array(), + 'stroke-width' => array(), + 'style' => array( + 'blacklisted_value_regex' => '!important', + ), + 'systemlanguage' => array(), + 'text-anchor' => array(), + 'text-decoration' => array(), + 'text-rendering' => array(), + 'transform' => array(), + 'unicode-bidi' => array(), + 'vector-effect' => array(), + 'visibility' => array(), + 'width' => array(), + 'word-spacing' => array(), + 'writing-mode' => array(), + 'x' => array(), + 'xml:lang' => array(), + 'xml:space' => array(), + 'xmlns' => array(), + 'xmlns:xlink' => array(), + 'y' => array(), + ), + 'tag_spec' => array( + 'mandatory_ancestor' => 'svg', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#svg', + ), + ), + ), + 'rp' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'rt' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'rtc' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'ruby' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 's' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'samp' => array( + array( + 'attr_spec_list' => array(), + 'tag_spec' => array(), + ), + ), + 'script' => array( + array( + 'attr_spec_list' => array( + 'async' => array( + 'mandatory' => true, + 'value' => array( + '', + ), + ), + 'nonce' => array(), + 'src' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value' => array( + 'https://cdn.ampproject.org/v0.js', + ), + ), + 'type' => array( + 'value_casei' => array( + 'text/javascript', + ), + ), + ), + 'cdata' => array( + 'blacklisted_cdata_regex' => array( + 'error_message' => 'contents', + 'regex' => '.', + ), + ), + 'tag_spec' => array( + 'mandatory' => true, + 'mandatory_parent' => 'head', + 'spec_name' => 'amphtml engine v0.js script', + 'spec_url' => 'https://www.ampproject.org/docs/reference/spec#required-markup', + 'unique' => true, + ), + ), + array( + 'attr_spec_list' => array( + 'nonce' => array(), + 'type' => array( + 'dispatch_key' => 2, + 'mandatory' => true, + 'value_casei' => array( + 'application/ld+json', + ), + ), + ), + 'cdata' => array( + 'blacklisted_cdata_regex' => array( + 'error_message' => 'html comments', + 'regex' => '