diff options
author | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-03-18 12:13:54 +0300 |
commit | 705c4d24c9c61edffc82864bf9c24384dc29a8d7 (patch) | |
tree | 4d21f87671db36b99402da3221d45b64c257c1fe /libs/litehtml/src | |
parent | 5784fc3a62b9136c6690ed45ec7b505f35512e08 (diff) |
litehtml - lightweight html renderer
Diffstat (limited to 'libs/litehtml/src')
88 files changed, 50755 insertions, 0 deletions
diff --git a/libs/litehtml/src/codepoint.cpp b/libs/litehtml/src/codepoint.cpp new file mode 100644 index 0000000000..61ff682ada --- /dev/null +++ b/libs/litehtml/src/codepoint.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2020-2021 Primate Labs Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "codepoint.h" + +#include <iostream> + +namespace { + +bool lookup(const uint32_t* table, char c) +{ + return table[c >> 5] & (1 << (c & 0x1f)); +} + +} // namespace + +namespace litehtml { + +bool is_ascii_codepoint(char c) +{ + return ((unsigned char) c < 128); +} + +// https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 +bool is_url_reserved_codepoint(char c) +{ + static const uint32_t reserved_lookup[] = { + 0x00000000, + 0xac009fda, + 0x28000001, + 0x00000000 + }; + + if (!is_ascii_codepoint(c)) { + return false; + } + return lookup(reserved_lookup, c); +} + +// https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 +bool is_url_scheme_codepoint(char c) +{ + static const uint32_t scheme_lookup[] = { + 0x00000000, + 0x03ff6800, + 0x07fffffe, + 0x07fffffe, + }; + + if (!is_ascii_codepoint(c)) { + return false; + } + return lookup(scheme_lookup, c); +} + +} // namespace litehtml diff --git a/libs/litehtml/src/css_borders.cpp b/libs/litehtml/src/css_borders.cpp new file mode 100644 index 0000000000..478e9df5bf --- /dev/null +++ b/libs/litehtml/src/css_borders.cpp @@ -0,0 +1,7 @@ +#include "html.h" +#include "borders.h" + +litehtml::string litehtml::css_border::to_string() const +{ + return width.to_string() + "/" + index_value(style, border_style_strings) + "/" + color.to_string(); +} diff --git a/libs/litehtml/src/css_length.cpp b/libs/litehtml/src/css_length.cpp new file mode 100644 index 0000000000..d1c69d2612 --- /dev/null +++ b/libs/litehtml/src/css_length.cpp @@ -0,0 +1,77 @@ +#include "html.h" +#include "css_length.h" + +void litehtml::css_length::fromString( const string& str, const string& predefs, int defValue ) +{ + // TODO: Make support for calc + if(str.substr(0, 4) == "calc") + { + m_is_predefined = true; + m_predef = defValue; + return; + } + + int predef = value_index(str, predefs, -1); + if(predef >= 0) + { + m_is_predefined = true; + m_predef = predef; + } else + { + m_is_predefined = false; + + string num; + string un; + bool is_unit = false; + for(char chr : str) + { + if(!is_unit) + { + if(t_isdigit(chr) || chr == '.' || chr == '+' || chr == '-') + { + num += chr; + } else + { + is_unit = true; + } + } + if(is_unit) + { + un += chr; + } + } + if(!num.empty()) + { + m_value = t_strtof(num); + m_units = (css_units) value_index(un, css_units_strings, css_units_none); + } else + { + // not a number so it is predefined + m_is_predefined = true; + m_predef = defValue; + } + } +} + +litehtml::css_length litehtml::css_length::from_string(const string& str, const string& predefs, int defValue) +{ + css_length len; + len.fromString(str, predefs, defValue); + return len; +} + +litehtml::string litehtml::css_length::to_string() const +{ + if(m_is_predefined) + { + return "def(" + std::to_string(m_predef) + ")"; + } + return std::to_string(m_value) + "{" + index_value(m_units, css_units_strings) + "}"; +} + +litehtml::css_length litehtml::css_length::predef_value(int val) +{ + css_length len; + len.predef(val); + return len; +} diff --git a/libs/litehtml/src/css_properties.cpp b/libs/litehtml/src/css_properties.cpp new file mode 100644 index 0000000000..a3b458ebfa --- /dev/null +++ b/libs/litehtml/src/css_properties.cpp @@ -0,0 +1,465 @@ +#include "html.h" +#include "css_properties.h" +#include <cmath> + +#define offset(member) ((uint_ptr)&this->member - (uint_ptr)this) + +void litehtml::css_properties::compute(const element* el, const document::ptr& doc) +{ + compute_font(el, doc); + int font_size = get_font_size(); + m_color = el->get_color_property(_color_, true, web_color::black, offset(m_color)); + + m_el_position = (element_position) el->get_enum_property( _position_, false, element_position_static, offset(m_el_position)); + m_display = (style_display) el->get_enum_property( _display_, false, display_inline, offset(m_display)); + m_visibility = (visibility) el->get_enum_property( _visibility_, true, visibility_visible, offset(m_visibility)); + m_float = (element_float) el->get_enum_property( _float_, false, float_none, offset(m_float)); + m_clear = (element_clear) el->get_enum_property( _clear_, false, clear_none, offset(m_clear)); + m_box_sizing = (box_sizing) el->get_enum_property( _box_sizing_, false, box_sizing_content_box, offset(m_box_sizing)); + m_overflow = (overflow) el->get_enum_property( _overflow_, false, overflow_visible, offset(m_overflow)); + m_text_align = (text_align) el->get_enum_property( _text_align_, true, text_align_left, offset(m_text_align)); + m_vertical_align = (vertical_align) el->get_enum_property( _vertical_align_, false, va_baseline, offset(m_vertical_align)); + m_text_transform = (text_transform) el->get_enum_property( _text_transform_, true, text_transform_none, offset(m_text_transform)); + m_white_space = (white_space) el->get_enum_property( _white_space_, true, white_space_normal, offset(m_white_space)); + m_caption_side = (caption_side) el->get_enum_property( _caption_side_, true, caption_side_top, offset(m_caption_side)); + + // https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo + if (m_display == display_none) + { + // 1. If 'display' has the value 'none', then 'position' and 'float' do not apply. In this case, the element + // generates no box. + m_float = float_none; + } else + { + // 2. Otherwise, if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned, + // the computed value of 'float' is 'none', and display is set according to the table below. + // The position of the box will be determined by the 'top', 'right', 'bottom' and 'left' properties + // and the box's containing block. + if (m_el_position == element_position_absolute || m_el_position == element_position_fixed) + { + m_float = float_none; + + if (m_display == display_inline_table) + { + m_display = display_table; + } else if (m_display == display_inline || + m_display == display_table_row_group || + m_display == display_table_column || + m_display == display_table_column_group || + m_display == display_table_header_group || + m_display == display_table_footer_group || + m_display == display_table_row || + m_display == display_table_cell || + m_display == display_table_caption || + m_display == display_inline_block) + { + m_display = display_block; + } + } else if (m_float != float_none) + { + // 3. Otherwise, if 'float' has a value other than 'none', the box is floated and 'display' is set + // according to the table below. + if (m_display == display_inline_table) + { + m_display = display_table; + } else if (m_display == display_inline || + m_display == display_table_row_group || + m_display == display_table_column || + m_display == display_table_column_group || + m_display == display_table_header_group || + m_display == display_table_footer_group || + m_display == display_table_row || + m_display == display_table_cell || + m_display == display_table_caption || + m_display == display_inline_block) + { + m_display = display_block; + } + } else if(el->is_root()) + { + // 4. Otherwise, if the element is the root element, 'display' is set according to the table below, + // except that it is undefined in CSS 2.2 whether a specified value of 'list-item' becomes a + // computed value of 'block' or 'list-item'. + if (m_display == display_inline_table) + { + m_display = display_table; + } else if (m_display == display_inline || + m_display == display_table_row_group || + m_display == display_table_column || + m_display == display_table_column_group || + m_display == display_table_header_group || + m_display == display_table_footer_group || + m_display == display_table_row || + m_display == display_table_cell || + m_display == display_table_caption || + m_display == display_inline_block || + m_display == display_list_item) + { + m_display = display_block; + } + } + } + // 5. Otherwise, the remaining 'display' property values apply as specified. + + const css_length _auto = css_length::predef_value(0); + const css_length none = _auto, normal = _auto; + + m_css_width = el->get_length_property(_width_, false, _auto, offset(m_css_width)); + m_css_height = el->get_length_property(_height_, false, _auto, offset(m_css_height)); + + m_css_min_width = el->get_length_property(_min_width_, false, _auto, offset(m_css_min_width)); + m_css_min_height = el->get_length_property(_min_height_, false, _auto, offset(m_css_min_height)); + + m_css_max_width = el->get_length_property(_max_width_, false, none, offset(m_css_max_width)); + m_css_max_height = el->get_length_property(_max_height_, false, none, offset(m_css_max_height)); + + doc->cvt_units(m_css_width, font_size); + doc->cvt_units(m_css_height, font_size); + + doc->cvt_units(m_css_min_width, font_size); + doc->cvt_units(m_css_min_height, font_size); + + doc->cvt_units(m_css_max_width, font_size); + doc->cvt_units(m_css_max_height, font_size); + + m_css_margins.left = el->get_length_property(_margin_left_, false, 0, offset(m_css_margins.left)); + m_css_margins.right = el->get_length_property(_margin_right_, false, 0, offset(m_css_margins.right)); + m_css_margins.top = el->get_length_property(_margin_top_, false, 0, offset(m_css_margins.top)); + m_css_margins.bottom = el->get_length_property(_margin_bottom_, false, 0, offset(m_css_margins.bottom)); + + doc->cvt_units(m_css_margins.left, font_size); + doc->cvt_units(m_css_margins.right, font_size); + doc->cvt_units(m_css_margins.top, font_size); + doc->cvt_units(m_css_margins.bottom, font_size); + + m_css_padding.left = el->get_length_property(_padding_left_, false, 0, offset(m_css_padding.left)); + m_css_padding.right = el->get_length_property(_padding_right_, false, 0, offset(m_css_padding.right)); + m_css_padding.top = el->get_length_property(_padding_top_, false, 0, offset(m_css_padding.top)); + m_css_padding.bottom = el->get_length_property(_padding_bottom_, false, 0, offset(m_css_padding.bottom)); + + doc->cvt_units(m_css_padding.left, font_size); + doc->cvt_units(m_css_padding.right, font_size); + doc->cvt_units(m_css_padding.top, font_size); + doc->cvt_units(m_css_padding.bottom, font_size); + + m_css_borders.left.color = el->get_color_property(_border_left_color_, false, m_color, offset(m_css_borders.left.color)); + m_css_borders.right.color = el->get_color_property(_border_right_color_, false, m_color, offset(m_css_borders.right.color)); + m_css_borders.top.color = el->get_color_property(_border_top_color_, false, m_color, offset(m_css_borders.top.color)); + m_css_borders.bottom.color = el->get_color_property(_border_bottom_color_, false, m_color, offset(m_css_borders.bottom.color)); + + m_css_borders.left.style = (border_style) el->get_enum_property(_border_left_style_, false, border_style_none, offset(m_css_borders.left.style)); + m_css_borders.right.style = (border_style) el->get_enum_property(_border_right_style_, false, border_style_none, offset(m_css_borders.right.style)); + m_css_borders.top.style = (border_style) el->get_enum_property(_border_top_style_, false, border_style_none, offset(m_css_borders.top.style)); + m_css_borders.bottom.style = (border_style) el->get_enum_property(_border_bottom_style_, false, border_style_none, offset(m_css_borders.bottom.style)); + + m_css_borders.left.width = el->get_length_property(_border_left_width_, false, border_width_medium_value, offset(m_css_borders.left.width)); + m_css_borders.right.width = el->get_length_property(_border_right_width_, false, border_width_medium_value, offset(m_css_borders.right.width)); + m_css_borders.top.width = el->get_length_property(_border_top_width_, false, border_width_medium_value, offset(m_css_borders.top.width)); + m_css_borders.bottom.width = el->get_length_property(_border_bottom_width_, false, border_width_medium_value, offset(m_css_borders.bottom.width)); + + if (m_css_borders.left.style == border_style_none || m_css_borders.left.style == border_style_hidden) + m_css_borders.left.width = 0; + if (m_css_borders.right.style == border_style_none || m_css_borders.right.style == border_style_hidden) + m_css_borders.right.width = 0; + if (m_css_borders.top.style == border_style_none || m_css_borders.top.style == border_style_hidden) + m_css_borders.top.width = 0; + if (m_css_borders.bottom.style == border_style_none || m_css_borders.bottom.style == border_style_hidden) + m_css_borders.bottom.width = 0; + + doc->cvt_units(m_css_borders.left.width, font_size); + doc->cvt_units(m_css_borders.right.width, font_size); + doc->cvt_units(m_css_borders.top.width, font_size); + doc->cvt_units(m_css_borders.bottom.width, font_size); + + m_css_borders.radius.top_left_x = el->get_length_property(_border_top_left_radius_x_, false, 0, offset(m_css_borders.radius.top_left_x)); + m_css_borders.radius.top_left_y = el->get_length_property(_border_top_left_radius_y_, false, 0, offset(m_css_borders.radius.top_left_y)); + + m_css_borders.radius.top_right_x = el->get_length_property(_border_top_right_radius_x_, false, 0, offset(m_css_borders.radius.top_right_x)); + m_css_borders.radius.top_right_y = el->get_length_property(_border_top_right_radius_y_, false, 0, offset(m_css_borders.radius.top_right_y)); + + m_css_borders.radius.bottom_left_x = el->get_length_property(_border_bottom_left_radius_x_, false, 0, offset(m_css_borders.radius.bottom_left_x)); + m_css_borders.radius.bottom_left_y = el->get_length_property(_border_bottom_left_radius_y_, false, 0, offset(m_css_borders.radius.bottom_left_y)); + + m_css_borders.radius.bottom_right_x = el->get_length_property(_border_bottom_right_radius_x_, false, 0, offset(m_css_borders.radius.bottom_right_x)); + m_css_borders.radius.bottom_right_y = el->get_length_property(_border_bottom_right_radius_y_, false, 0, offset(m_css_borders.radius.bottom_right_y)); + + doc->cvt_units( m_css_borders.radius.top_left_x, font_size); + doc->cvt_units( m_css_borders.radius.top_left_y, font_size); + doc->cvt_units( m_css_borders.radius.top_right_x, font_size); + doc->cvt_units( m_css_borders.radius.top_right_y, font_size); + doc->cvt_units( m_css_borders.radius.bottom_left_x, font_size); + doc->cvt_units( m_css_borders.radius.bottom_left_y, font_size); + doc->cvt_units( m_css_borders.radius.bottom_right_x, font_size); + doc->cvt_units( m_css_borders.radius.bottom_right_y, font_size); + + m_border_collapse = (border_collapse) el->get_enum_property(_border_collapse_, true, border_collapse_separate, offset(m_border_collapse)); + + m_css_border_spacing_x = el->get_length_property(__litehtml_border_spacing_x_, true, 0, offset(m_css_border_spacing_x)); + m_css_border_spacing_y = el->get_length_property(__litehtml_border_spacing_y_, true, 0, offset(m_css_border_spacing_y)); + + doc->cvt_units(m_css_border_spacing_x, font_size); + doc->cvt_units(m_css_border_spacing_y, font_size); + + m_css_offsets.left = el->get_length_property(_left_, false, _auto, offset(m_css_offsets.left)); + m_css_offsets.right = el->get_length_property(_right_, false, _auto, offset(m_css_offsets.right)); + m_css_offsets.top = el->get_length_property(_top_, false, _auto, offset(m_css_offsets.top)); + m_css_offsets.bottom = el->get_length_property(_bottom_,false, _auto, offset(m_css_offsets.bottom)); + + doc->cvt_units(m_css_offsets.left, font_size); + doc->cvt_units(m_css_offsets.right, font_size); + doc->cvt_units(m_css_offsets.top, font_size); + doc->cvt_units(m_css_offsets.bottom, font_size); + + m_z_index = el->get_length_property(_z_index_, false, _auto, offset(m_z_index)); + m_content = el->get_string_property(_content_, false, "", offset(m_content)); + m_cursor = el->get_string_property(_cursor_, true, "auto", offset(m_cursor)); + + m_css_text_indent = el->get_length_property(_text_indent_, true, 0, offset(m_css_text_indent)); + doc->cvt_units(m_css_text_indent, font_size); + + m_css_line_height = el->get_length_property(_line_height_, true, normal, offset(m_css_line_height)); + if(m_css_line_height.is_predefined()) + { + m_line_height = m_font_metrics.height; + } else if(m_css_line_height.units() == css_units_none) + { + m_line_height = (int) std::nearbyint(m_css_line_height.val() * font_size); + } else + { + m_line_height = doc->to_pixels(m_css_line_height, font_size, font_size); + m_css_line_height = (float) m_line_height; + } + + m_list_style_type = (list_style_type) el->get_enum_property(_list_style_type_, true, list_style_type_disc, offset(m_list_style_type)); + m_list_style_position = (list_style_position) el->get_enum_property(_list_style_position_, true, list_style_position_outside, offset(m_list_style_position)); + + m_list_style_image = el->get_string_property(_list_style_image_, true, "", offset(m_list_style_image)); + if (!m_list_style_image.empty()) + { + m_list_style_image_baseurl = el->get_string_property(_list_style_image_baseurl_, true, "", offset(m_list_style_image_baseurl)); + doc->container()->load_image(m_list_style_image.c_str(), m_list_style_image_baseurl.c_str(), true); + } + + m_order = el->get_int_property(_order_, false, 0, offset(m_order)); + + compute_background(el, doc); + compute_flex(el, doc); +} + +static const int font_size_table[8][7] = +{ + { 9, 9, 9, 9, 11, 14, 18}, + { 9, 9, 9, 10, 12, 15, 20}, + { 9, 9, 9, 11, 13, 17, 22}, + { 9, 9, 10, 12, 14, 18, 24}, + { 9, 9, 10, 13, 16, 20, 26}, + { 9, 9, 11, 14, 17, 21, 28}, + { 9, 10, 12, 15, 17, 23, 30}, + { 9, 10, 13, 16, 18, 24, 32} +}; + +void litehtml::css_properties::compute_font(const element* el, const document::ptr& doc) +{ + // initialize font size + css_length sz = el->get_length_property(_font_size_, true, css_length::predef_value(font_size_medium), offset(m_font_size)); + + int parent_sz = 0; + int doc_font_size = doc->container()->get_default_font_size(); + element::ptr el_parent = el->parent(); + if (el_parent) + { + parent_sz = el_parent->css().get_font_size(); + } else + { + parent_sz = doc_font_size; + } + + int font_size = parent_sz; + + if(sz.is_predefined()) + { + int idx_in_table = doc_font_size - 9; + if(idx_in_table >= 0 && idx_in_table <= 7) + { + if(sz.predef() >= font_size_xx_small && sz.predef() <= font_size_xx_large) + { + font_size = font_size_table[idx_in_table][sz.predef()]; + } else if(sz.predef() == font_size_smaller) + { + font_size = (int) (parent_sz / 1.2); + } else if(sz.predef() == font_size_larger) + { + font_size = (int) (parent_sz * 1.2); + } else + { + font_size = parent_sz; + } + } else + { + switch(sz.predef()) + { + case font_size_xx_small: + font_size = doc_font_size * 3 / 5; + break; + case font_size_x_small: + font_size = doc_font_size * 3 / 4; + break; + case font_size_small: + font_size = doc_font_size * 8 / 9; + break; + case font_size_large: + font_size = doc_font_size * 6 / 5; + break; + case font_size_x_large: + font_size = doc_font_size * 3 / 2; + break; + case font_size_xx_large: + font_size = doc_font_size * 2; + break; + case font_size_smaller: + font_size = (int) (parent_sz / 1.2); + break; + case font_size_larger: + font_size = (int) (parent_sz * 1.2); + break; + default: + font_size = parent_sz; + break; + } + } + } else + { + if(sz.units() == css_units_percentage) + { + font_size = sz.calc_percent(parent_sz); + } else + { + font_size = doc->to_pixels(sz, parent_sz); + } + } + + m_font_size = (float)font_size; + + // initialize font + m_font_family = el->get_string_property(_font_family_, true, doc->container()->get_default_font_name(), offset(m_font_family)); + m_font_weight = (font_weight) el->get_enum_property( _font_weight_, true, font_weight_normal, offset(m_font_weight)); + m_font_style = (font_style) el->get_enum_property( _font_style_, true, font_style_normal, offset(m_font_style)); + m_text_decoration = el->get_string_property(_text_decoration_, true, "none", offset(m_text_decoration)); + + m_font = doc->get_font( + m_font_family.c_str(), + font_size, + index_value(m_font_weight, font_weight_strings).c_str(), + index_value(m_font_style, font_style_strings).c_str(), + m_text_decoration.c_str(), + &m_font_metrics); +} + +void litehtml::css_properties::compute_background(const element* el, const document::ptr& doc) +{ + int font_size = get_font_size(); + + m_bg.m_color = el->get_color_property(_background_color_, false, web_color::transparent, offset(m_bg.m_color)); + + const css_size auto_auto(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)); + m_bg.m_position_x = el->get_length_vector_property(_background_position_x_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_x)); + m_bg.m_position_y = el->get_length_vector_property(_background_position_y_, false, { css_length(0, css_units_percentage) }, offset(m_bg.m_position_y)); + m_bg.m_size = el->get_size_vector_property (_background_size_, false, { auto_auto }, offset(m_bg.m_size)); + + for (auto& x : m_bg.m_position_x) doc->cvt_units(x, font_size); + for (auto& y : m_bg.m_position_y) doc->cvt_units(y, font_size); + for (auto& size : m_bg.m_size) + { + doc->cvt_units(size.width, font_size); + doc->cvt_units(size.height, font_size); + } + + m_bg.m_attachment = el->get_int_vector_property(_background_attachment_, false, { background_attachment_scroll }, offset(m_bg.m_attachment)); + m_bg.m_repeat = el->get_int_vector_property(_background_repeat_, false, { background_repeat_repeat }, offset(m_bg.m_repeat)); + m_bg.m_clip = el->get_int_vector_property(_background_clip_, false, { background_box_border }, offset(m_bg.m_clip)); + m_bg.m_origin = el->get_int_vector_property(_background_origin_, false, { background_box_padding }, offset(m_bg.m_origin)); + + m_bg.m_image = el->get_string_vector_property(_background_image_, false, {""}, offset(m_bg.m_image)); + m_bg.m_baseurl = el->get_string_property(_background_image_baseurl_, false, "", offset(m_bg.m_baseurl)); + + for (const auto& image : m_bg.m_image) + { + if (!image.empty()) + { + doc->container()->load_image(image.c_str(), m_bg.m_baseurl.c_str(), true); + } + } +} + +void litehtml::css_properties::compute_flex(const element* el, const document::ptr& doc) +{ + if (m_display == display_flex || m_display == display_inline_flex) + { + m_flex_direction = (flex_direction) el->get_enum_property(_flex_direction_, false, flex_direction_row, offset(m_flex_direction)); + m_flex_wrap = (flex_wrap) el->get_enum_property(_flex_wrap_, false, flex_wrap_nowrap, offset(m_flex_wrap)); + + m_flex_justify_content = (flex_justify_content) el->get_enum_property(_justify_content_, false, flex_justify_content_flex_start, offset(m_flex_justify_content)); + m_flex_align_items = (flex_align_items) el->get_enum_property(_align_items_, false, flex_align_items_flex_normal, offset(m_flex_align_items)); + m_flex_align_content = (flex_align_content) el->get_enum_property(_align_content_, false, flex_align_content_stretch, offset(m_flex_align_content)); + } + m_flex_align_self = (flex_align_items) el->get_enum_property(_align_self_, false, flex_align_items_auto, offset(m_flex_align_self)); + auto parent = el->parent(); + if (parent && (parent->css().m_display == display_flex || parent->css().m_display == display_inline_flex)) + { + m_flex_grow = el->get_number_property(_flex_grow_, false, 0, offset(m_flex_grow)); + m_flex_shrink = el->get_number_property(_flex_shrink_, false, 1, offset(m_flex_shrink)); + m_flex_basis = el->get_length_property(_flex_basis_, false, css_length::predef_value(flex_basis_auto), offset(m_flex_basis)); + if(!m_flex_basis.is_predefined() && m_flex_basis.units() == css_units_none && m_flex_basis.val() != 0) + { + // flex-basis property must contain units + m_flex_basis.predef(flex_basis_auto); + } + doc->cvt_units(m_flex_basis, get_font_size()); + if(m_display == display_inline || m_display == display_inline_block) + { + m_display = display_block; + } else if(m_display == display_inline_table) + { + m_display = display_table; + } else if(m_display == display_inline_flex) + { + m_display = display_flex; + } + } +} + +std::vector<std::tuple<litehtml::string, litehtml::string>> litehtml::css_properties::dump_get_attrs() +{ + std::vector<std::tuple<string, string>> ret; + + ret.emplace_back(std::make_tuple("display", index_value(m_display, style_display_strings))); + ret.emplace_back(std::make_tuple("el_position", index_value(m_el_position, element_position_strings))); + ret.emplace_back(std::make_tuple("text_align", index_value(m_text_align, text_align_strings))); + ret.emplace_back(std::make_tuple("font_size", m_font_size.to_string())); + ret.emplace_back(std::make_tuple("overflow", index_value(m_overflow, overflow_strings))); + ret.emplace_back(std::make_tuple("white_space", index_value(m_white_space, white_space_strings))); + ret.emplace_back(std::make_tuple("visibility", index_value(m_visibility, visibility_strings))); + ret.emplace_back(std::make_tuple("box_sizing", index_value(m_box_sizing, box_sizing_strings))); + ret.emplace_back(std::make_tuple("z_index", m_z_index.to_string())); + ret.emplace_back(std::make_tuple("vertical_align", index_value(m_vertical_align, vertical_align_strings))); + ret.emplace_back(std::make_tuple("float", index_value(m_float, element_float_strings))); + ret.emplace_back(std::make_tuple("clear", index_value(m_clear, element_clear_strings))); + ret.emplace_back(std::make_tuple("margins", m_css_margins.to_string())); + ret.emplace_back(std::make_tuple("padding", m_css_padding.to_string())); + ret.emplace_back(std::make_tuple("borders", m_css_borders.to_string())); + ret.emplace_back(std::make_tuple("width", m_css_width.to_string())); + ret.emplace_back(std::make_tuple("height", m_css_height.to_string())); + ret.emplace_back(std::make_tuple("min_width", m_css_min_width.to_string())); + ret.emplace_back(std::make_tuple("min_height", m_css_min_width.to_string())); + ret.emplace_back(std::make_tuple("max_width", m_css_max_width.to_string())); + ret.emplace_back(std::make_tuple("max_height", m_css_max_width.to_string())); + ret.emplace_back(std::make_tuple("offsets", m_css_offsets.to_string())); + ret.emplace_back(std::make_tuple("text_indent", m_css_text_indent.to_string())); + ret.emplace_back(std::make_tuple("line_height", std::to_string(m_line_height))); + ret.emplace_back(std::make_tuple("list_style_type", index_value(m_list_style_type, list_style_type_strings))); + ret.emplace_back(std::make_tuple("list_style_position", index_value(m_list_style_position, list_style_position_strings))); + ret.emplace_back(std::make_tuple("border_spacing_x", m_css_border_spacing_x.to_string())); + ret.emplace_back(std::make_tuple("border_spacing_y", m_css_border_spacing_y.to_string())); + + return ret; +} diff --git a/libs/litehtml/src/css_selector.cpp b/libs/litehtml/src/css_selector.cpp new file mode 100644 index 0000000000..af46892397 --- /dev/null +++ b/libs/litehtml/src/css_selector.cpp @@ -0,0 +1,323 @@ +#include "html.h" +#include "css_selector.h" +#include "document.h" + +void litehtml::css_element_selector::parse_nth_child_params(const string& param, int& num, int& off) +{ + if (param == "odd") + { + num = 2; + off = 1; + } + else if (param == "even") + { + num = 2; + off = 0; + } + else + { + string_vector tokens; + split_string(param, tokens, " n", "n"); + + string s_num; + string s_off; + + string s_int; + for (const auto& token : tokens) + { + if (token == "n") + { + s_num = s_int; + s_int.clear(); + } + else + { + s_int += token; + } + } + s_off = s_int; + + num = atoi(s_num.c_str()); + off = atoi(s_off.c_str()); + } +} + +void litehtml::css_element_selector::parse( const string& txt ) +{ + string::size_type el_end = txt.find_first_of(".#[:"); + string tag = txt.substr(0, el_end); + litehtml::lcase(tag); + if (tag == "") tag = "*"; + m_tag = _id(tag); + + m_attrs.clear(); + while(el_end != string::npos) + { + if(txt[el_end] == '.') + { + css_attribute_selector attribute; + + attribute.type = select_class; + string::size_type pos = txt.find_first_of(".#[:", el_end + 1); + string name = txt.substr(el_end + 1, pos - el_end - 1); + litehtml::lcase(name); + attribute.name = _id(name); + m_attrs.push_back(attribute); + el_end = pos; + } else if(txt[el_end] == '#') + { + css_attribute_selector attribute; + + attribute.type = select_id; + string::size_type pos = txt.find_first_of(".#[:", el_end + 1); + string name = txt.substr(el_end + 1, pos - el_end - 1); + litehtml::lcase(name); + attribute.name = _id(name); + m_attrs.push_back(attribute); + el_end = pos; + } else if(txt[el_end] == ':') + { + css_attribute_selector attribute; + + if(txt[el_end + 1] == ':') + { + attribute.type = select_pseudo_element; + string::size_type pos = txt.find_first_of(".#[:", el_end + 2); + string name = txt.substr(el_end + 2, pos - el_end - 2); + litehtml::lcase(name); + attribute.name = _id(name); + m_attrs.push_back(attribute); + el_end = pos; + } else + { + string::size_type pos = txt.find_first_of(".#[:(", el_end + 1); + string name = txt.substr(el_end + 1, pos - el_end - 1); + lcase(name); + attribute.name = _id(name); + if(attribute.name == _after_ || attribute.name == _before_) + { + attribute.type = select_pseudo_element; + } else + { + attribute.type = select_pseudo_class; + } + + string val; + if(pos != string::npos && txt.at(pos) == '(') + { + auto end = find_close_bracket(txt, pos); + val = txt.substr(pos + 1, end - pos - 1); + if (end != string::npos) pos = end + 1; + } + + switch (attribute.name) + { + case _nth_child_: + case _nth_of_type_: + case _nth_last_child_: + case _nth_last_of_type_: + lcase(val); + parse_nth_child_params(val, attribute.a, attribute.b); + break; + case _not_: + attribute.sel = std::make_shared<css_element_selector>(); + attribute.sel->parse(val); + break; + case _lang_: + trim(val); + lcase(val); + attribute.val = val; + break; + default: + break; + } + + m_attrs.push_back(attribute); + el_end = pos; + } + } else if(txt[el_end] == '[') + { + css_attribute_selector attribute; + + string::size_type pos = txt.find_first_of("]~=|$*^", el_end + 1); + string attr = txt.substr(el_end + 1, pos - el_end - 1); + trim(attr); + litehtml::lcase(attr); + if(pos != string::npos) + { + if(txt[pos] == ']') + { + attribute.type = select_exists; + } else if(txt[pos] == '=') + { + attribute.type = select_equal; + pos++; + } else if(txt.substr(pos, 2) == "~=") + { + attribute.type = select_contain_str; + pos += 2; + } else if(txt.substr(pos, 2) == "|=") + { + attribute.type = select_start_str; + pos += 2; + } else if(txt.substr(pos, 2) == "^=") + { + attribute.type = select_start_str; + pos += 2; + } else if(txt.substr(pos, 2) == "$=") + { + attribute.type = select_end_str; + pos += 2; + } else if(txt.substr(pos, 2) == "*=") + { + attribute.type = select_contain_str; + pos += 2; + } else + { + attribute.type = select_exists; + pos += 1; + } + pos = txt.find_first_not_of(" \t", pos); + if(pos != string::npos) + { + if(txt[pos] == '"') + { + string::size_type pos2 = txt.find_first_of('\"', pos + 1); + attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1)); + pos = pos2 == string::npos ? pos2 : (pos2 + 1); + } else if(txt[pos] == '\'') + { + string::size_type pos2 = txt.find_first_of('\'', pos + 1); + attribute.val = txt.substr(pos + 1, pos2 == string::npos ? pos2 : (pos2 - pos - 1)); + pos = pos2 == string::npos ? pos2 : (pos2 + 1); + } else if(txt[pos] == ']') + { + pos ++; + } else + { + string::size_type pos2 = txt.find_first_of(']', pos + 1); + attribute.val = txt.substr(pos, pos2 == string::npos ? pos2 : (pos2 - pos)); + trim(attribute.val); + pos = pos2 == string::npos ? pos2 : (pos2 + 1); + } + } + } else + { + attribute.type = select_exists; + } + attribute.name = _id(attr); + m_attrs.push_back(attribute); + el_end = pos; + } else + { + el_end++; + } + el_end = txt.find_first_of(".#[:", el_end); + } +} + + +bool litehtml::css_selector::parse( const string& text ) +{ + if(text.empty()) + { + return false; + } + string_vector tokens; + split_string(text, tokens, "", " \t>+~", "(["); + + if(tokens.empty()) + { + return false; + } + + string left; + string right = tokens.back(); + char combinator = 0; + + tokens.pop_back(); + while(!tokens.empty() && (tokens.back() == " " || tokens.back() == "\t" || tokens.back() == "+" || tokens.back() == "~" || tokens.back() == ">")) + { + if(combinator == ' ' || combinator == 0) + { + combinator = tokens.back()[0]; + } + tokens.pop_back(); + } + + for(const auto & token : tokens) + { + left += token; + } + + trim(left); + trim(right); + + if(right.empty()) + { + return false; + } + + m_right.parse(right); + + switch(combinator) + { + case '>': + m_combinator = combinator_child; + break; + case '+': + m_combinator = combinator_adjacent_sibling; + break; + case '~': + m_combinator = combinator_general_sibling; + break; + default: + m_combinator = combinator_descendant; + break; + } + + m_left = nullptr; + + if(!left.empty()) + { + m_left = std::make_shared<css_selector>(); + if(!m_left->parse(left)) + { + return false; + } + } + + return true; +} + +void litehtml::css_selector::calc_specificity() +{ + if(m_right.m_tag != star_id) + { + m_specificity.d = 1; + } + for(const auto& attr : m_right.m_attrs) + { + if(attr.type == select_id) + { + m_specificity.b++; + } else + { + m_specificity.c++; + } + } + if(m_left) + { + m_left->calc_specificity(); + m_specificity += m_left->m_specificity; + } +} + +void litehtml::css_selector::add_media_to_doc( document* doc ) const +{ + if(m_media_query && doc) + { + doc->add_media_list(m_media_query); + } +} + diff --git a/libs/litehtml/src/document.cpp b/libs/litehtml/src/document.cpp new file mode 100644 index 0000000000..e0af355ebe --- /dev/null +++ b/libs/litehtml/src/document.cpp @@ -0,0 +1,1068 @@ +#include "html.h" +#include "document.h" +#include "stylesheet.h" +#include "html_tag.h" +#include "el_text.h" +#include "el_para.h" +#include "el_space.h" +#include "el_body.h" +#include "el_image.h" +#include "el_table.h" +#include "el_td.h" +#include "el_link.h" +#include "el_title.h" +#include "el_style.h" +#include "el_script.h" +#include "el_comment.h" +#include "el_cdata.h" +#include "el_base.h" +#include "el_anchor.h" +#include "el_break.h" +#include "el_div.h" +#include "el_font.h" +#include "el_tr.h" +#include <cmath> +#include <cstdio> +#include <algorithm> +#include "gumbo.h" +#include "utf8_strings.h" +#include "render_item.h" +#include "render_table.h" +#include "render_block.h" + +litehtml::document::document(document_container* objContainer) +{ + m_container = objContainer; +} + +litehtml::document::~document() +{ + m_over_element = nullptr; + if(m_container) + { + for(auto& font : m_fonts) + { + m_container->delete_font(font.second.font); + } + } +} + +litehtml::document::ptr litehtml::document::createFromString( const char* str, document_container* objPainter, const char* master_styles, const char* user_styles ) +{ + // parse document into GumboOutput + GumboOutput* output = gumbo_parse(str); + + // Create litehtml::document + document::ptr doc = std::make_shared<document>(objPainter); + + // Create litehtml::elements. + elements_list root_elements; + doc->create_node(output->root, root_elements, true); + if (!root_elements.empty()) + { + doc->m_root = root_elements.back(); + } + // Destroy GumboOutput + gumbo_destroy_output(&kGumboDefaultOptions, output); + + if (master_styles && *master_styles) + { + doc->m_master_css.parse_stylesheet(master_styles, nullptr, doc, nullptr); + doc->m_master_css.sort_selectors(); + } + if (user_styles && *user_styles) + { + doc->m_user_css.parse_stylesheet(user_styles, nullptr, doc, nullptr); + doc->m_user_css.sort_selectors(); + } + + // Let's process created elements tree + if (doc->m_root) + { + doc->container()->get_media_features(doc->m_media); + + doc->m_root->set_pseudo_class(_root_, true); + + // apply master CSS + doc->m_root->apply_stylesheet(doc->m_master_css); + + // parse elements attributes + doc->m_root->parse_attributes(); + + // parse style sheets linked in document + media_query_list::ptr media; + for (const auto& css : doc->m_css) + { + if (!css.media.empty()) + { + media = media_query_list::create_from_string(css.media, doc); + } + else + { + media = nullptr; + } + doc->m_styles.parse_stylesheet(css.text.c_str(), css.baseurl.c_str(), doc, media); + } + // Sort css selectors using CSS rules. + doc->m_styles.sort_selectors(); + + // get current media features + if (!doc->m_media_lists.empty()) + { + doc->update_media_lists(doc->m_media); + } + + // Apply parsed styles. + doc->m_root->apply_stylesheet(doc->m_styles); + + // Apply user styles if any + doc->m_root->apply_stylesheet(doc->m_user_css); + + // Initialize m_css + doc->m_root->compute_styles(); + + // Create rendering tree + doc->m_root_render = doc->m_root->create_render_item(nullptr); + + // Now the m_tabular_elements is filled with tabular elements. + // We have to check the tabular elements for missing table elements + // and create the anonymous boxes in visual table layout + doc->fix_tables_layout(); + + // Finally initialize elements + // init() return pointer to the render_init element because it can change its type + doc->m_root_render = doc->m_root_render->init(); + } + + return doc; +} + +litehtml::uint_ptr litehtml::document::add_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm ) +{ + uint_ptr ret = 0; + + if(!name) + { + name = m_container->get_default_font_name(); + } + + char strSize[20]; + t_itoa(size, strSize, 20, 10); + + string key = name; + key += ":"; + key += strSize; + key += ":"; + key += weight; + key += ":"; + key += style; + key += ":"; + key += decoration; + + if(m_fonts.find(key) == m_fonts.end()) + { + font_style fs = (font_style) value_index(style, font_style_strings, font_style_normal); + int fw = value_index(weight, font_weight_strings, -1); + if(fw >= 0) + { + switch(fw) + { + case litehtml::font_weight_bold: + fw = 700; + break; + case litehtml::font_weight_bolder: + fw = 600; + break; + case litehtml::font_weight_lighter: + fw = 300; + break; + case litehtml::font_weight_normal: + fw = 400; + break; + case litehtml::font_weight_100: + fw = 100; + break; + case litehtml::font_weight_200: + fw = 200; + break; + case litehtml::font_weight_300: + fw = 300; + break; + case litehtml::font_weight_400: + fw = 400; + break; + case litehtml::font_weight_500: + fw = 500; + break; + case litehtml::font_weight_600: + fw = 600; + break; + case litehtml::font_weight_700: + fw = 700; + break; + case litehtml::font_weight_800: + fw = 800; + break; + case litehtml::font_weight_900: + fw = 900; + break; + } + } else + { + fw = atoi(weight); + if(fw < 100) + { + fw = 400; + } + } + + unsigned int decor = 0; + + if(decoration) + { + std::vector<string> tokens; + split_string(decoration, tokens, " "); + for(auto & token : tokens) + { + if(!t_strcasecmp(token.c_str(), "underline")) + { + decor |= font_decoration_underline; + } else if(!t_strcasecmp(token.c_str(), "line-through")) + { + decor |= font_decoration_linethrough; + } else if(!t_strcasecmp(token.c_str(), "overline")) + { + decor |= font_decoration_overline; + } + } + } + + font_item fi= {0, {}}; + + fi.font = m_container->create_font(name, size, fw, fs, decor, &fi.metrics); + m_fonts[key] = fi; + ret = fi.font; + if(fm) + { + *fm = fi.metrics; + } + } + return ret; +} + +litehtml::uint_ptr litehtml::document::get_font( const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm ) +{ + if(!size) + { + return 0; + } + if(!name) + { + name = m_container->get_default_font_name(); + } + + char strSize[20]; + t_itoa(size, strSize, 20, 10); + + string key = name; + key += ":"; + key += strSize; + key += ":"; + key += weight; + key += ":"; + key += style; + key += ":"; + key += decoration; + + auto el = m_fonts.find(key); + + if(el != m_fonts.end()) + { + if(fm) + { + *fm = el->second.metrics; + } + return el->second.font; + } + return add_font(name, size, weight, style, decoration, fm); +} + +int litehtml::document::render( int max_width, render_type rt ) +{ + int ret = 0; + if(m_root) + { + position client_rc; + m_container->get_client_rect(client_rc); + containing_block_context cb_context; + cb_context.width = max_width; + cb_context.width.type = containing_block_context::cbc_value_type_absolute; + cb_context.height = client_rc.height; + cb_context.height.type = containing_block_context::cbc_value_type_absolute; + + if(rt == render_fixed_only) + { + m_fixed_boxes.clear(); + m_root_render->render_positioned(rt); + } else + { + ret = m_root_render->render(0, 0, cb_context, nullptr); + if(m_root_render->fetch_positioned()) + { + m_fixed_boxes.clear(); + m_root_render->render_positioned(rt); + } + m_size.width = 0; + m_size.height = 0; + m_content_size.width = 0; + m_content_size.height = 0; + m_root_render->calc_document_size(m_size, m_content_size); + } + } + return ret; +} + +void litehtml::document::draw( uint_ptr hdc, int x, int y, const position* clip ) +{ + if(m_root && m_root_render) + { + m_root->draw(hdc, x, y, clip, m_root_render); + m_root_render->draw_stacking_context(hdc, x, y, clip, true); + } +} + +int litehtml::document::to_pixels( const char* str, int fontSize, bool* is_percent/*= 0*/ ) const +{ + if(!str) return 0; + + css_length val; + val.fromString(str); + if(is_percent && val.units() == css_units_percentage && !val.is_predefined()) + { + *is_percent = true; + } + return to_pixels(val, fontSize); +} + +int litehtml::document::to_pixels( const css_length& val, int fontSize, int size ) const +{ + if(val.is_predefined()) + { + return 0; + } + int ret; + switch(val.units()) + { + case css_units_percentage: + ret = val.calc_percent(size); + break; + case css_units_em: + ret = round_f(val.val() * (float) fontSize); + break; + case css_units_pt: + ret = m_container->pt_to_px((int) val.val()); + break; + case css_units_in: + ret = m_container->pt_to_px((int) (val.val() * 72)); + break; + case css_units_cm: + ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72)); + break; + case css_units_mm: + ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10); + break; + case css_units_vw: + ret = (int)((double)m_media.width * (double)val.val() / 100.0); + break; + case css_units_vh: + ret = (int)((double)m_media.height * (double)val.val() / 100.0); + break; + case css_units_vmin: + ret = (int)((double)std::min(m_media.height, m_media.width) * (double)val.val() / 100.0); + break; + case css_units_vmax: + ret = (int)((double)std::max(m_media.height, m_media.width) * (double)val.val() / 100.0); + break; + case css_units_rem: + ret = (int) ((double) m_root->css().get_font_size() * (double) val.val()); + break; + default: + ret = (int) val.val(); + break; + } + return ret; +} + +void litehtml::document::cvt_units( css_length& val, int fontSize, int /*size*/ ) const +{ + if(val.is_predefined()) + { + return; + } + int ret; + switch(val.units()) + { + case css_units_em: + ret = round_f(val.val() * (float) fontSize); + val.set_value((float) ret, css_units_px); + break; + case css_units_pt: + ret = m_container->pt_to_px((int) val.val()); + val.set_value((float) ret, css_units_px); + break; + case css_units_in: + ret = m_container->pt_to_px((int) (val.val() * 72)); + val.set_value((float) ret, css_units_px); + break; + case css_units_cm: + ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72)); + val.set_value((float) ret, css_units_px); + break; + case css_units_mm: + ret = m_container->pt_to_px((int) (val.val() * 0.3937 * 72) / 10); + val.set_value((float) ret, css_units_px); + break; + default: + break; + } +} + +int litehtml::document::width() const +{ + return m_size.width; +} + +int litehtml::document::height() const +{ + return m_size.height; +} + +int litehtml::document::content_width() const +{ + return m_content_size.width; +} + +int litehtml::document::content_height() const +{ + return m_content_size.height; +} + + +void litehtml::document::add_stylesheet( const char* str, const char* baseurl, const char* media ) +{ + if(str && str[0]) + { + m_css.push_back(css_text(str, baseurl, media)); + } +} + +bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes ) +{ + if(!m_root || !m_root_render) + { + return false; + } + + element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y); + + bool state_was_changed = false; + + if(over_el != m_over_element) + { + if(m_over_element) + { + if(m_over_element->on_mouse_leave()) + { + state_was_changed = true; + } + } + m_over_element = over_el; + } + + string cursor; + + if(m_over_element) + { + if(m_over_element->on_mouse_over()) + { + state_was_changed = true; + } + cursor = m_over_element->css().get_cursor(); + } + + m_container->set_cursor(cursor.c_str()); + + if(state_was_changed) + { + return m_root->find_styles_changes(redraw_boxes); + } + return false; +} + +bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes ) +{ + if(!m_root || !m_root_render) + { + return false; + } + if(m_over_element) + { + if(m_over_element->on_mouse_leave()) + { + return m_root->find_styles_changes(redraw_boxes); + } + } + return false; +} + +bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes ) +{ + if(!m_root || !m_root_render) + { + return false; + } + + element::ptr over_el = m_root_render->get_element_by_point(x, y, client_x, client_y); + + bool state_was_changed = false; + + if(over_el != m_over_element) + { + if(m_over_element) + { + if(m_over_element->on_mouse_leave()) + { + state_was_changed = true; + } + } + m_over_element = over_el; + if(m_over_element) + { + if(m_over_element->on_mouse_over()) + { + state_was_changed = true; + } + } + } + + string cursor; + + if(m_over_element) + { + if(m_over_element->on_lbutton_down()) + { + state_was_changed = true; + } + cursor = m_over_element->css().get_cursor(); + } + + m_container->set_cursor(cursor.c_str()); + + if(state_was_changed) + { + return m_root->find_styles_changes(redraw_boxes); + } + + return false; +} + +bool litehtml::document::on_lbutton_up( int /*x*/, int /*y*/, int /*client_x*/, int /*client_y*/, position::vector& redraw_boxes ) +{ + if(!m_root || !m_root_render) + { + return false; + } + if(m_over_element) + { + if(m_over_element->on_lbutton_up()) + { + return m_root->find_styles_changes(redraw_boxes); + } + } + return false; +} + +litehtml::element::ptr litehtml::document::create_element(const char* tag_name, const string_map& attributes) +{ + element::ptr newTag; + document::ptr this_doc = shared_from_this(); + if(m_container) + { + newTag = m_container->create_element(tag_name, attributes, this_doc); + } + if(!newTag) + { + if(!strcmp(tag_name, "br")) + { + newTag = std::make_shared<litehtml::el_break>(this_doc); + } else if(!strcmp(tag_name, "p")) + { + newTag = std::make_shared<litehtml::el_para>(this_doc); + } else if(!strcmp(tag_name, "img")) + { + newTag = std::make_shared<litehtml::el_image>(this_doc); + } else if(!strcmp(tag_name, "table")) + { + newTag = std::make_shared<litehtml::el_table>(this_doc); + } else if(!strcmp(tag_name, "td") || !strcmp(tag_name, "th")) + { + newTag = std::make_shared<litehtml::el_td>(this_doc); + } else if(!strcmp(tag_name, "link")) + { + newTag = std::make_shared<litehtml::el_link>(this_doc); + } else if(!strcmp(tag_name, "title")) + { + newTag = std::make_shared<litehtml::el_title>(this_doc); + } else if(!strcmp(tag_name, "a")) + { + newTag = std::make_shared<litehtml::el_anchor>(this_doc); + } else if(!strcmp(tag_name, "tr")) + { + newTag = std::make_shared<litehtml::el_tr>(this_doc); + } else if(!strcmp(tag_name, "style")) + { + newTag = std::make_shared<litehtml::el_style>(this_doc); + } else if(!strcmp(tag_name, "base")) + { + newTag = std::make_shared<litehtml::el_base>(this_doc); + } else if(!strcmp(tag_name, "body")) + { + newTag = std::make_shared<litehtml::el_body>(this_doc); + } else if(!strcmp(tag_name, "div")) + { + newTag = std::make_shared<litehtml::el_div>(this_doc); + } else if(!strcmp(tag_name, "script")) + { + newTag = std::make_shared<litehtml::el_script>(this_doc); + } else if(!strcmp(tag_name, "font")) + { + newTag = std::make_shared<litehtml::el_font>(this_doc); + } else + { + newTag = std::make_shared<litehtml::html_tag>(this_doc); + } + } + + if(newTag) + { + newTag->set_tagName(tag_name); + for (const auto & attribute : attributes) + { + newTag->set_attr(attribute.first.c_str(), attribute.second.c_str()); + } + } + + return newTag; +} + +void litehtml::document::get_fixed_boxes( position::vector& fixed_boxes ) +{ + fixed_boxes = m_fixed_boxes; +} + +void litehtml::document::add_fixed_box( const position& pos ) +{ + m_fixed_boxes.push_back(pos); +} + +bool litehtml::document::media_changed() +{ + container()->get_media_features(m_media); + if (update_media_lists(m_media)) + { + m_root->refresh_styles(); + m_root->compute_styles(); + return true; + } + return false; +} + +bool litehtml::document::lang_changed() +{ + if(!m_media_lists.empty()) + { + string culture; + container()->get_language(m_lang, culture); + if(!culture.empty()) + { + m_culture = m_lang + '-' + culture; + } + else + { + m_culture.clear(); + } + m_root->refresh_styles(); + m_root->compute_styles(); + return true; + } + return false; +} + +bool litehtml::document::update_media_lists(const media_features& features) +{ + bool update_styles = false; + for(auto & m_media_list : m_media_lists) + { + if(m_media_list->apply_media_features(features)) + { + update_styles = true; + } + } + return update_styles; +} + +void litehtml::document::add_media_list( const media_query_list::ptr& list ) +{ + if(list) + { + if(std::find(m_media_lists.begin(), m_media_lists.end(), list) == m_media_lists.end()) + { + m_media_lists.push_back(list); + } + } +} + +void litehtml::document::create_node(void* gnode, elements_list& elements, bool parseTextNode) +{ + auto* node = (GumboNode*)gnode; + switch (node->type) + { + case GUMBO_NODE_ELEMENT: + { + string_map attrs; + GumboAttribute* attr; + for (unsigned int i = 0; i < node->v.element.attributes.length; i++) + { + attr = (GumboAttribute*)node->v.element.attributes.data[i]; + attrs[attr->name] = attr->value; + } + + + element::ptr ret; + const char* tag = gumbo_normalized_tagname(node->v.element.tag); + if (tag[0]) + { + ret = create_element(tag, attrs); + } + else + { + if (node->v.element.original_tag.data && node->v.element.original_tag.length) + { + std::string strA; + gumbo_tag_from_original_text(&node->v.element.original_tag); + strA.append(node->v.element.original_tag.data, node->v.element.original_tag.length); + ret = create_element(strA.c_str(), attrs); + } + } + if (!strcmp(tag, "script")) + { + parseTextNode = false; + } + if (ret) + { + elements_list child; + for (unsigned int i = 0; i < node->v.element.children.length; i++) + { + child.clear(); + create_node(static_cast<GumboNode*> (node->v.element.children.data[i]), child, parseTextNode); + std::for_each(child.begin(), child.end(), + [&ret](element::ptr& el) + { + ret->appendChild(el); + } + ); + } + elements.push_back(ret); + } + } + break; + case GUMBO_NODE_TEXT: + { + if (!parseTextNode) + { + elements.push_back(std::make_shared<el_text>(node->v.text.text, shared_from_this())); + } + else + { + m_container->split_text(node->v.text.text, + [this, &elements](const char* text) { elements.push_back(std::make_shared<el_text>(text, shared_from_this())); }, + [this, &elements](const char* text) { elements.push_back(std::make_shared<el_space>(text, shared_from_this())); }); + } + } + break; + case GUMBO_NODE_CDATA: + { + element::ptr ret = std::make_shared<el_cdata>(shared_from_this()); + ret->set_data(node->v.text.text); + elements.push_back(ret); + } + break; + case GUMBO_NODE_COMMENT: + { + element::ptr ret = std::make_shared<el_comment>(shared_from_this()); + ret->set_data(node->v.text.text); + elements.push_back(ret); + } + break; + case GUMBO_NODE_WHITESPACE: + { + string str = node->v.text.text; + for (size_t i = 0; i < str.length(); i++) + { + elements.push_back(std::make_shared<el_space>(str.substr(i, 1).c_str(), shared_from_this())); + } + } + break; + default: + break; + } +} + +void litehtml::document::fix_tables_layout() +{ + for (const auto& el_ptr : m_tabular_elements) + { + switch (el_ptr->src_el()->css().get_display()) + { + case display_inline_table: + case display_table: + fix_table_children(el_ptr, display_table_row_group, "table-row-group"); + break; + case display_table_footer_group: + case display_table_row_group: + case display_table_header_group: + { + auto parent = el_ptr->parent(); + if (parent) + { + if (parent->src_el()->css().get_display() != display_inline_table) + fix_table_parent(el_ptr, display_table, "table"); + } + fix_table_children(el_ptr, display_table_row, "table-row"); + } + break; + case display_table_row: + fix_table_parent(el_ptr, display_table_row_group, "table-row-group"); + fix_table_children(el_ptr, display_table_cell, "table-cell"); + break; + case display_table_cell: + fix_table_parent(el_ptr, display_table_row, "table-row"); + break; + // TODO: make table layout fix for table-caption, table-column etc. elements + case display_table_caption: + case display_table_column: + case display_table_column_group: + default: + break; + } + } +} + +void litehtml::document::fix_table_children(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str) +{ + std::list<std::shared_ptr<render_item>> tmp; + auto first_iter = el_ptr->children().begin(); + auto cur_iter = el_ptr->children().begin(); + + auto flush_elements = [&]() + { + element::ptr annon_tag = std::make_shared<html_tag>(el_ptr->src_el(), string("display:") + disp_str); + std::shared_ptr<render_item> annon_ri; + if(annon_tag->css().get_display() == display_table_cell) + { + annon_tag->set_tagName("table_cell"); + annon_ri = std::make_shared<render_item_block>(annon_tag); + } else if(annon_tag->css().get_display() == display_table_row) + { + annon_ri = std::make_shared<render_item_table_row>(annon_tag); + } else + { + annon_ri = std::make_shared<render_item_table_part>(annon_tag); + } + for(const auto& el : tmp) + { + annon_ri->add_child(el); + } + // add annon item as tabular for future processing + add_tabular(annon_ri); + annon_ri->parent(el_ptr); + first_iter = el_ptr->children().insert(first_iter, annon_ri); + cur_iter = std::next(first_iter); + while (cur_iter != el_ptr->children().end() && (*cur_iter)->parent() != el_ptr) + { + cur_iter = el_ptr->children().erase(cur_iter); + } + first_iter = cur_iter; + tmp.clear(); + }; + + while (cur_iter != el_ptr->children().end()) + { + if ((*cur_iter)->src_el()->css().get_display() != disp) + { + if (!(*cur_iter)->src_el()->is_table_skip() || ((*cur_iter)->src_el()->is_table_skip() && !tmp.empty())) + { + if (disp != display_table_row_group || (*cur_iter)->src_el()->css().get_display() != display_table_caption) + { + if (tmp.empty()) + { + first_iter = cur_iter; + } + tmp.push_back((*cur_iter)); + } + } + cur_iter++; + } + else if (!tmp.empty()) + { + flush_elements(); + } + else + { + cur_iter++; + } + } + if (!tmp.empty()) + { + flush_elements(); + } +} + +void litehtml::document::fix_table_parent(const std::shared_ptr<render_item>& el_ptr, style_display disp, const char* disp_str) +{ + auto parent = el_ptr->parent(); + + if (parent->src_el()->css().get_display() != disp) + { + auto this_element = std::find_if(parent->children().begin(), parent->children().end(), + [&](const std::shared_ptr<render_item>& el) + { + if (el == el_ptr) + { + return true; + } + return false; + } + ); + if (this_element != parent->children().end()) + { + style_display el_disp = el_ptr->src_el()->css().get_display(); + auto first = this_element; + auto last = this_element; + auto cur = this_element; + + // find first element with same display + while (true) + { + if (cur == parent->children().begin()) break; + cur--; + if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp) + { + first = cur; + } + else + { + break; + } + } + + // find last element with same display + cur = this_element; + while (true) + { + cur++; + if (cur == parent->children().end()) break; + + if ((*cur)->src_el()->is_table_skip() || (*cur)->src_el()->css().get_display() == el_disp) + { + last = cur; + } + else + { + break; + } + } + + // extract elements with the same display and wrap them with anonymous object + element::ptr annon_tag = std::make_shared<html_tag>(parent->src_el(), string("display:") + disp_str); + std::shared_ptr<render_item> annon_ri; + if(annon_tag->css().get_display() == display_table || annon_tag->css().get_display() == display_inline_table) + { + annon_ri = std::make_shared<render_item_table>(annon_tag); + } else if(annon_tag->css().get_display() == display_table_row) + { + annon_ri = std::make_shared<render_item_table_row>(annon_tag); + } else + { + annon_ri = std::make_shared<render_item_table_part>(annon_tag); + } + std::for_each(first, std::next(last, 1), + [&annon_ri](std::shared_ptr<render_item>& el) + { + annon_ri->add_child(el); + } + ); + first = parent->children().erase(first, std::next(last)); + parent->children().insert(first, annon_ri); + add_tabular(annon_ri); + annon_ri->parent(parent); + } + } +} + +void litehtml::document::append_children_from_string(element& parent, const char* str) +{ + // parent must belong to this document + if (parent.get_document().get() != this) + { + return; + } + + // parse document into GumboOutput + GumboOutput* output = gumbo_parse(str); + + // Create litehtml::elements. + elements_list child_elements; + create_node(output->root, child_elements, true); + + // Destroy GumboOutput + gumbo_destroy_output(&kGumboDefaultOptions, output); + + // Let's process created elements tree + for (const auto& child : child_elements) + { + // Add the child element to parent + parent.appendChild(child); + + // apply master CSS + child->apply_stylesheet(m_master_css); + + // parse elements attributes + child->parse_attributes(); + + // Apply parsed styles. + child->apply_stylesheet(m_styles); + + // Apply user styles if any + child->apply_stylesheet(m_user_css); + + // Initialize m_css + child->compute_styles(); + + // Now the m_tabular_elements is filled with tabular elements. + // We have to check the tabular elements for missing table elements + // and create the anonymous boxes in visual table layout + fix_tables_layout(); + + // Finally initialize elements + //child->init(); + } +} + +void litehtml::document::dump(dumper& cout) +{ + if(m_root_render) + { + m_root_render->dump(cout); + } +} diff --git a/libs/litehtml/src/document_container.cpp b/libs/litehtml/src/document_container.cpp new file mode 100644 index 0000000000..d3802473e1 --- /dev/null +++ b/libs/litehtml/src/document_container.cpp @@ -0,0 +1,44 @@ +#include "html.h" +#include "document_container.h" + +void litehtml::document_container::split_text(const char* text, const std::function<void(const char*)>& on_word, const std::function<void(const char*)>& on_space) +{ + std::wstring str; + std::wstring str_in = (const wchar_t*)utf8_to_wchar(text); + ucode_t c; + for (size_t i = 0; i < str_in.length(); i++) + { + c = (ucode_t)str_in[i]; + if (c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')) + { + if (!str.empty()) + { + on_word(wchar_to_utf8(str.c_str())); + str.clear(); + } + str += c; + on_space(wchar_to_utf8(str.c_str())); + str.clear(); + } + // CJK character range + else if (c >= 0x4E00 && c <= 0x9FCC) + { + if (!str.empty()) + { + on_word(wchar_to_utf8(str.c_str())); + str.clear(); + } + str += c; + on_word(wchar_to_utf8(str.c_str())); + str.clear(); + } + else + { + str += c; + } + } + if (!str.empty()) + { + on_word(wchar_to_utf8(str.c_str())); + } +} diff --git a/libs/litehtml/src/el_anchor.cpp b/libs/litehtml/src/el_anchor.cpp new file mode 100644 index 0000000000..372e4afb50 --- /dev/null +++ b/libs/litehtml/src/el_anchor.cpp @@ -0,0 +1,26 @@ +#include "html.h" +#include "el_anchor.h" +#include "document.h" + +litehtml::el_anchor::el_anchor(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc) +{ +} + +void litehtml::el_anchor::on_click() +{ + const char* href = get_attr("href"); + + if(href) + { + get_document()->container()->on_anchor_click(href, shared_from_this()); + } +} + +void litehtml::el_anchor::apply_stylesheet( const litehtml::css& stylesheet ) +{ + if( get_attr("href") ) + { + m_pseudo_classes.push_back(_link_); + } + html_tag::apply_stylesheet(stylesheet); +} diff --git a/libs/litehtml/src/el_base.cpp b/libs/litehtml/src/el_base.cpp new file mode 100644 index 0000000000..baf0256539 --- /dev/null +++ b/libs/litehtml/src/el_base.cpp @@ -0,0 +1,13 @@ +#include "html.h" +#include "el_base.h" +#include "document.h" + +litehtml::el_base::el_base(const std::shared_ptr<document>& doc) : html_tag(doc) +{ + +} + +void litehtml::el_base::parse_attributes() +{ + get_document()->container()->set_base_url(get_attr("href")); +} diff --git a/libs/litehtml/src/el_before_after.cpp b/libs/litehtml/src/el_before_after.cpp new file mode 100644 index 0000000000..3bb806ba60 --- /dev/null +++ b/libs/litehtml/src/el_before_after.cpp @@ -0,0 +1,214 @@ +#include "html.h" +#include "el_before_after.h" +#include "el_text.h" +#include "el_space.h" +#include "el_image.h" +#include "utf8_strings.h" + +litehtml::el_before_after_base::el_before_after_base(const std::shared_ptr<document>& doc, bool before) : html_tag(doc) +{ + m_tag = before ? __tag_before_ : __tag_after_; +} + +void litehtml::el_before_after_base::add_style(const style& style) +{ + html_tag::add_style(style); + + auto children = m_children; + m_children.clear(); + + const auto& content_property = style.get_property(_content_); + if(content_property.m_type == prop_type_string && !content_property.m_string.empty()) + { + int idx = value_index(content_property.m_string, content_property_string); + if(idx < 0) + { + string fnc; + string::size_type i = 0; + while(i < content_property.m_string.length() && i != string::npos) + { + if(content_property.m_string.at(i) == '"' || content_property.m_string.at(i) == '\'') + { + auto chr = content_property.m_string.at(i); + fnc.clear(); + i++; + string::size_type pos = content_property.m_string.find(chr, i); + string txt; + if(pos == string::npos) + { + txt = content_property.m_string.substr(i); + i = string::npos; + } else + { + txt = content_property.m_string.substr(i, pos - i); + i = pos + 1; + } + add_text(txt); + } else if(content_property.m_string.at(i) == '(') + { + i++; + litehtml::trim(fnc); + litehtml::lcase(fnc); + string::size_type pos = content_property.m_string.find(')', i); + string params; + if(pos == string::npos) + { + params = content_property.m_string.substr(i); + i = string::npos; + } else + { + params = content_property.m_string.substr(i, pos - i); + i = pos + 1; + } + add_function(fnc, params); + fnc.clear(); + } else + { + fnc += content_property.m_string.at(i); + i++; + } + } + } + } + + if(m_children.empty()) + { + m_children = children; + } +} + +void litehtml::el_before_after_base::add_text( const string& txt ) +{ + string word; + string esc; + + for(auto chr : txt) + { + if(chr == '\\' || + (!esc.empty() && esc.length() < 5 && + ( + (chr >= '0' && chr <= '9') || + (chr >= 'A' && chr <= 'Z') || + (chr >= 'a' && chr <= 'z') + ) + )) + { + if(!esc.empty() && chr == '\\') + { + word += convert_escape(esc.c_str() + 1); + esc.clear(); + } + esc += chr; + } else + { + if(!esc.empty()) + { + word += convert_escape(esc.c_str() + 1); + esc.clear(); + } + if(isspace((unsigned char) chr)) + { + if(!word.empty()) + { + element::ptr el = std::make_shared<el_text>(word.c_str(), get_document()); + appendChild(el); + word.clear(); + } + word += chr; + element::ptr el = std::make_shared<el_space>(word.c_str(), get_document()); + appendChild(el); + word.clear(); + } else + { + word += chr; + } + } + } + + if(!esc.empty()) + { + word += convert_escape(esc.c_str() + 1); + } + if(!word.empty()) + { + element::ptr el = std::make_shared<el_text>(word.c_str(), get_document()); + appendChild(el); + word.clear(); + } +} + +void litehtml::el_before_after_base::add_function( const string& fnc, const string& params ) +{ + int idx = value_index(fnc, "attr;counter;counters;url"); + switch(idx) + { + // attr + case 0: + { + string p_name = params; + trim(p_name); + lcase(p_name); + element::ptr el_parent = parent(); + if (el_parent) + { + const char* attr_value = el_parent->get_attr(p_name.c_str()); + if (attr_value) + { + add_text(attr_value); + } + } + } + break; + // counter + case 1: + add_text(get_counter_value(params)); + break; + // counters + case 2: + { + string_vector tokens; + split_string(params, tokens, ","); + add_text(get_counters_value(tokens)); + } + break; + // url + case 3: + { + string p_url = params; + trim(p_url); + if(!p_url.empty()) + { + if(p_url.at(0) == '\'' || p_url.at(0) == '\"') + { + p_url.erase(0, 1); + } + } + if(!p_url.empty()) + { + if(p_url.at(p_url.length() - 1) == '\'' || p_url.at(p_url.length() - 1) == '\"') + { + p_url.erase(p_url.length() - 1, 1); + } + } + if(!p_url.empty()) + { + element::ptr el = std::make_shared<el_image>(get_document()); + el->set_attr("src", p_url.c_str()); + el->set_attr("style", "display:inline-block"); + el->set_tagName("img"); + appendChild(el); + el->parse_attributes(); + } + } + break; + } +} + +litehtml::string litehtml::el_before_after_base::convert_escape( const char* txt ) +{ + char* str_end; + wchar_t u_str[2]; + u_str[0] = (wchar_t) strtol(txt, &str_end, 16); + u_str[1] = 0; + return litehtml::string(litehtml_from_wchar(u_str)); +} diff --git a/libs/litehtml/src/el_body.cpp b/libs/litehtml/src/el_body.cpp new file mode 100644 index 0000000000..3d35f8f758 --- /dev/null +++ b/libs/litehtml/src/el_body.cpp @@ -0,0 +1,12 @@ +#include "html.h" +#include "el_body.h" +#include "document.h" + +litehtml::el_body::el_body(const std::shared_ptr<litehtml::document>& doc) : litehtml::html_tag(doc) +{ +} + +bool litehtml::el_body::is_body() const +{ + return true; +} diff --git a/libs/litehtml/src/el_break.cpp b/libs/litehtml/src/el_break.cpp new file mode 100644 index 0000000000..f13b2e3cf8 --- /dev/null +++ b/libs/litehtml/src/el_break.cpp @@ -0,0 +1,13 @@ +#include "html.h" +#include "el_break.h" + +litehtml::el_break::el_break(const std::shared_ptr<litehtml::document>& doc) : html_tag(doc) +{ + +} + +bool litehtml::el_break::is_break() const +{ + return true; +} + diff --git a/libs/litehtml/src/el_cdata.cpp b/libs/litehtml/src/el_cdata.cpp new file mode 100644 index 0000000000..e5948bff13 --- /dev/null +++ b/libs/litehtml/src/el_cdata.cpp @@ -0,0 +1,20 @@ +#include "html.h" +#include "el_cdata.h" + +litehtml::el_cdata::el_cdata(const std::shared_ptr<document>& doc) : element(doc) +{ + //m_skip = true; +} + +void litehtml::el_cdata::get_text( string& text ) +{ + text += m_text; +} + +void litehtml::el_cdata::set_data( const char* data ) +{ + if(data) + { + m_text += data; + } +} diff --git a/libs/litehtml/src/el_comment.cpp b/libs/litehtml/src/el_comment.cpp new file mode 100644 index 0000000000..1ec934d046 --- /dev/null +++ b/libs/litehtml/src/el_comment.cpp @@ -0,0 +1,25 @@ +#include "html.h" +#include "el_comment.h" + +litehtml::el_comment::el_comment(const std::shared_ptr<document>& doc) : element(doc) +{ + //m_skip = true; +} + +bool litehtml::el_comment::is_comment() const +{ + return true; +} + +void litehtml::el_comment::get_text( string& text ) +{ + text += m_text; +} + +void litehtml::el_comment::set_data( const char* data ) +{ + if(data) + { + m_text += data; + } +} diff --git a/libs/litehtml/src/el_div.cpp b/libs/litehtml/src/el_div.cpp new file mode 100644 index 0000000000..983d45ab2a --- /dev/null +++ b/libs/litehtml/src/el_div.cpp @@ -0,0 +1,18 @@ +#include "html.h" +#include "el_div.h" + + +litehtml::el_div::el_div(const document::ptr& doc) : html_tag(doc) +{ + +} + +void litehtml::el_div::parse_attributes() +{ + const char* str = get_attr("align"); + if(str) + { + m_style.add_property(_text_align_, str); + } + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/el_font.cpp b/libs/litehtml/src/el_font.cpp new file mode 100644 index 0000000000..3d5f6d9f73 --- /dev/null +++ b/libs/litehtml/src/el_font.cpp @@ -0,0 +1,57 @@ +#include "html.h" +#include "el_font.h" + + +litehtml::el_font::el_font(const std::shared_ptr<document>& doc) : html_tag(doc) +{ + +} + +void litehtml::el_font::parse_attributes() +{ + const char* str = get_attr("color"); + if(str) + { + m_style.add_property(_color_, str, "", false, get_document()->container()); + } + + str = get_attr("face"); + if(str) + { + m_style.add_property(_font_family_, str); + } + + str = get_attr("size"); + if(str) + { + int sz = atoi(str); + if(*str == '+' || *str == '-') sz = 3 + sz; // relative size + + if(sz <= 1) + { + m_style.add_property(_font_size_, "x-small"); + } else if(sz >= 6) + { + m_style.add_property(_font_size_, "xx-large"); + } else + { + switch(sz) + { + case 2: + m_style.add_property(_font_size_, "small"); + break; + case 3: + m_style.add_property(_font_size_, "medium"); + break; + case 4: + m_style.add_property(_font_size_, "large"); + break; + case 5: + m_style.add_property(_font_size_, "x-large"); + break; + } + } + } + + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/el_image.cpp b/libs/litehtml/src/el_image.cpp new file mode 100644 index 0000000000..b481734dde --- /dev/null +++ b/libs/litehtml/src/el_image.cpp @@ -0,0 +1,120 @@ +#include "html.h" +#include "el_image.h" +#include "render_image.h" + +litehtml::el_image::el_image(const document::ptr& doc) : html_tag(doc) +{ + m_css.set_display(display_inline_block); +} + +void litehtml::el_image::get_content_size( size& sz, int /*max_width*/ ) +{ + get_document()->container()->get_image_size(m_src.c_str(), nullptr, sz); +} + +bool litehtml::el_image::is_replaced() const +{ + return true; +} + +void litehtml::el_image::parse_attributes() +{ + m_src = get_attr("src", ""); + + const char* attr_height = get_attr("height"); + if(attr_height) + { + m_style.add_property(_height_, attr_height); + } + const char* attr_width = get_attr("width"); + if(attr_width) + { + m_style.add_property(_width_, attr_width); + } +} + +void litehtml::el_image::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) +{ + position pos = ri->pos(); + pos.x += x; + pos.y += y; + + position el_pos = pos; + el_pos += ri->get_paddings(); + el_pos += ri->get_borders(); + + // draw standard background here + if (el_pos.does_intersect(clip)) + { + const background* bg = get_background(); + if (bg) + { + std::vector<background_paint> bg_paint; + init_background_paint(pos, bg_paint, bg, ri); + + get_document()->container()->draw_background(hdc, bg_paint); + } + } + + // draw image as background + if(pos.does_intersect(clip)) + { + if (pos.width > 0 && pos.height > 0) { + background_paint bg; + bg.image = m_src; + bg.clip_box = pos; + bg.origin_box = pos; + bg.border_box = pos; + bg.border_box += ri->get_paddings(); + bg.border_box += ri->get_borders(); + bg.repeat = background_repeat_no_repeat; + bg.image_size.width = pos.width; + bg.image_size.height = pos.height; + bg.border_radius = css().get_borders().radius.calc_percents(bg.border_box.width, bg.border_box.height); + bg.position_x = pos.x; + bg.position_y = pos.y; + get_document()->container()->draw_background(hdc, {bg}); + } + } + + // draw borders + if (el_pos.does_intersect(clip)) + { + position border_box = pos; + border_box += ri->get_paddings(); + border_box += ri->get_borders(); + + borders bdr = css().get_borders(); + bdr.radius = css().get_borders().radius.calc_percents(border_box.width, border_box.height); + + get_document()->container()->draw_borders(hdc, bdr, border_box, is_root()); + } +} + +void litehtml::el_image::compute_styles(bool recursive) +{ + html_tag::compute_styles(recursive); + + if(!m_src.empty()) + { + if(!css().get_height().is_predefined() && !css().get_width().is_predefined()) + { + get_document()->container()->load_image(m_src.c_str(), nullptr, true); + } else + { + get_document()->container()->load_image(m_src.c_str(), nullptr, false); + } + } +} + +litehtml::string litehtml::el_image::dump_get_name() +{ + return "img src=\"" + m_src + "\""; +} + +std::shared_ptr<litehtml::render_item> litehtml::el_image::create_render_item(const std::shared_ptr<render_item>& parent_ri) +{ + auto ret = std::make_shared<render_item_image>(shared_from_this()); + ret->parent(parent_ri); + return ret; +} diff --git a/libs/litehtml/src/el_link.cpp b/libs/litehtml/src/el_link.cpp new file mode 100644 index 0000000000..aa3bc76597 --- /dev/null +++ b/libs/litehtml/src/el_link.cpp @@ -0,0 +1,39 @@ +#include "html.h" +#include "el_link.h" +#include "document.h" + + +litehtml::el_link::el_link(const std::shared_ptr<document>& doc) : litehtml::html_tag(doc) +{ + +} + +void litehtml::el_link::parse_attributes() +{ + bool processed = false; + + document::ptr doc = get_document(); + + const char* rel = get_attr("rel"); + if(rel && !strcmp(rel, "stylesheet")) + { + const char* media = get_attr("media"); + const char* href = get_attr("href"); + if(href && href[0]) + { + string css_text; + string css_baseurl; + doc->container()->import_css(css_text, href, css_baseurl); + if(!css_text.empty()) + { + doc->add_stylesheet(css_text.c_str(), css_baseurl.c_str(), media); + processed = true; + } + } + } + + if(!processed) + { + doc->container()->link(doc, shared_from_this()); + } +} diff --git a/libs/litehtml/src/el_para.cpp b/libs/litehtml/src/el_para.cpp new file mode 100644 index 0000000000..5d79151351 --- /dev/null +++ b/libs/litehtml/src/el_para.cpp @@ -0,0 +1,18 @@ +#include "html.h" +#include "el_para.h" +#include "document.h" + +litehtml::el_para::el_para(const std::shared_ptr<document>& doc) : html_tag(doc) +{ +} + +void litehtml::el_para::parse_attributes() +{ + const char* str = get_attr("align"); + if(str) + { + m_style.add_property(_text_align_, str); + } + + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/el_script.cpp b/libs/litehtml/src/el_script.cpp new file mode 100644 index 0000000000..4b598a137e --- /dev/null +++ b/libs/litehtml/src/el_script.cpp @@ -0,0 +1,30 @@ +#include "html.h" +#include "el_script.h" +#include "document.h" + + +litehtml::el_script::el_script(const std::shared_ptr<document>& doc) : element(doc) +{ + +} + +void litehtml::el_script::parse_attributes() +{ + //TODO: pass script text to document container +} + +bool litehtml::el_script::appendChild(const ptr &el) +{ + el->get_text(m_text); + return true; +} + +litehtml::string_id litehtml::el_script::tag() const +{ + return _script_; +} + +const char* litehtml::el_script::get_tagName() const +{ + return "script"; +} diff --git a/libs/litehtml/src/el_space.cpp b/libs/litehtml/src/el_space.cpp new file mode 100644 index 0000000000..f5e3818ca7 --- /dev/null +++ b/libs/litehtml/src/el_space.cpp @@ -0,0 +1,44 @@ +#include "html.h" +#include "document.h" +#include "el_space.h" + +litehtml::el_space::el_space(const char* text, const std::shared_ptr<document>& doc) : el_text(text, doc) +{ +} + +bool litehtml::el_space::is_white_space() const +{ + white_space ws = css().get_white_space(); + if( ws == white_space_normal || + ws == white_space_nowrap || + ws == white_space_pre_line ) + { + return true; + } + return false; +} + +bool litehtml::el_space::is_break() const +{ + white_space ws = css().get_white_space(); + if( ws == white_space_pre || + ws == white_space_pre_line || + ws == white_space_pre_wrap) + { + if(m_text == "\n") + { + return true; + } + } + return false; +} + +bool litehtml::el_space::is_space() const +{ + return true; +} + +litehtml::string litehtml::el_space::dump_get_name() +{ + return "space: \"" + get_escaped_string(m_text) + "\""; +} diff --git a/libs/litehtml/src/el_style.cpp b/libs/litehtml/src/el_style.cpp new file mode 100644 index 0000000000..cc2f0bab6d --- /dev/null +++ b/libs/litehtml/src/el_style.cpp @@ -0,0 +1,36 @@ +#include "html.h" +#include "el_style.h" +#include "document.h" + + +litehtml::el_style::el_style(const std::shared_ptr<document>& doc) : element(doc) +{ + +} + +void litehtml::el_style::parse_attributes() +{ + string text; + + for(auto& el : m_children) + { + el->get_text(text); + } + get_document()->add_stylesheet( text.c_str(), nullptr, get_attr("media") ); +} + +bool litehtml::el_style::appendChild(const ptr &el) +{ + m_children.push_back(el); + return true; +} + +litehtml::string_id litehtml::el_style::tag() const +{ + return _style_; +} + +const char* litehtml::el_style::get_tagName() const +{ + return "style"; +} diff --git a/libs/litehtml/src/el_table.cpp b/libs/litehtml/src/el_table.cpp new file mode 100644 index 0000000000..0bb8648436 --- /dev/null +++ b/libs/litehtml/src/el_table.cpp @@ -0,0 +1,55 @@ +#include "html.h" +#include "el_table.h" +#include "document.h" +#include "iterators.h" + + +litehtml::el_table::el_table(const std::shared_ptr<document>& doc) : html_tag(doc) +{ +} + + +bool litehtml::el_table::appendChild(const element::ptr& el) +{ + if(!el) return false; + if( el->tag() == _tbody_ || + el->tag() == _thead_ || + el->tag() == _tfoot_ || + el->tag() == _caption_) + { + return html_tag::appendChild(el); + } + return false; +} + +void litehtml::el_table::parse_attributes() +{ + const char* str = get_attr("width"); + if(str) + { + m_style.add_property(_width_, str); + } + + str = get_attr("cellspacing"); + if(str) + { + string val = str; + val += " "; + val += str; + m_style.add_property(_border_spacing_, val); + } + + str = get_attr("border"); + if(str) + { + m_style.add_property(_border_width_, str); + } + + str = get_attr("bgcolor"); + if (str) + { + m_style.add_property(_background_color_, str, "", false, get_document()->container()); + } + + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/el_td.cpp b/libs/litehtml/src/el_td.cpp new file mode 100644 index 0000000000..679d9212ab --- /dev/null +++ b/libs/litehtml/src/el_td.cpp @@ -0,0 +1,43 @@ +#include "html.h" +#include "el_td.h" + + +litehtml::el_td::el_td(const std::shared_ptr<document>& doc) : html_tag(doc) +{ + +} + +void litehtml::el_td::parse_attributes() +{ + const char* str = get_attr("width"); + if(str) + { + m_style.add_property(_width_, str); + } + str = get_attr("background"); + if(str) + { + string url = "url('"; + url += str; + url += "')"; + m_style.add_property(_background_image_, url); + } + str = get_attr("align"); + if(str) + { + m_style.add_property(_text_align_, str); + } + + str = get_attr("bgcolor"); + if (str) + { + m_style.add_property(_background_color_, str, "", false, get_document()->container()); + } + + str = get_attr("valign"); + if(str) + { + m_style.add_property(_vertical_align_, str); + } + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/el_text.cpp b/libs/litehtml/src/el_text.cpp new file mode 100644 index 0000000000..5a1dffb69e --- /dev/null +++ b/libs/litehtml/src/el_text.cpp @@ -0,0 +1,140 @@ +#include "html.h" +#include "el_text.h" +#include "render_item.h" + +litehtml::el_text::el_text(const char* text, const document::ptr& doc) : element(doc) +{ + if(text) + { + m_text = text; + } + m_use_transformed = false; + m_draw_spaces = true; + css_w().set_display(display_inline_text); +} + +void litehtml::el_text::get_content_size( size& sz, int /*max_width*/ ) +{ + sz = m_size; +} + +void litehtml::el_text::get_text( string& text ) +{ + text += m_text; +} + +void litehtml::el_text::compute_styles(bool /*recursive*/) +{ + element::ptr el_parent = parent(); + if (el_parent) + { + css_w().set_line_height(el_parent->css().get_line_height()); + css_w().set_font(el_parent->css().get_font()); + css_w().set_font_metrics(el_parent->css().get_font_metrics()); + css_w().set_white_space(el_parent->css().get_white_space()); + css_w().set_text_transform(el_parent->css().get_text_transform()); + } + css_w().set_display(display_inline_text); + css_w().set_float(float_none); + + if(m_css.get_text_transform() != text_transform_none) + { + m_transformed_text = m_text; + m_use_transformed = true; + get_document()->container()->transform_text(m_transformed_text, m_css.get_text_transform()); + } else + { + m_use_transformed = false; + } + + element::ptr p = parent(); + while(p && p->css().get_display() == display_inline) + { + if(p->css().get_position() == element_position_relative) + { + css_w().set_offsets(p->css().get_offsets()); + css_w().set_position(element_position_relative); + break; + } + p = p->parent(); + } + if(p) + { + css_w().set_position(element_position_static); + } + + if(is_white_space()) + { + m_transformed_text = " "; + m_use_transformed = true; + } else + { + if(m_text == "\t") + { + m_transformed_text = " "; + m_use_transformed = true; + } + if(m_text == "\n" || m_text == "\r") + { + m_transformed_text = ""; + m_use_transformed = true; + } + } + + font_metrics fm; + uint_ptr font = 0; + if (el_parent) + { + font = el_parent->css().get_font(); + fm = el_parent->css().get_font_metrics(); + } + if(is_break() || !font) + { + m_size.height = 0; + m_size.width = 0; + } else + { + m_size.height = fm.height; + m_size.width = get_document()->container()->text_width(m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font); + } + m_draw_spaces = fm.draw_spaces; +} + +void litehtml::el_text::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) +{ + if(is_white_space() && !m_draw_spaces) + { + return; + } + + position pos = ri->pos(); + pos.x += x; + pos.y += y; + + if(pos.does_intersect(clip)) + { + element::ptr el_parent = parent(); + if (el_parent) + { + document::ptr doc = get_document(); + + uint_ptr font = el_parent->css().get_font(); + if(font) + { + web_color color = el_parent->css().get_color(); + doc->container()->draw_text(hdc, m_use_transformed ? m_transformed_text.c_str() : m_text.c_str(), font, + color, pos); + } + } + } +} + +litehtml::string litehtml::el_text::dump_get_name() +{ + return "text: \"" + get_escaped_string(m_text) + "\""; +} + +std::vector<std::tuple<litehtml::string, litehtml::string>> litehtml::el_text::dump_get_attrs() +{ + return std::vector<std::tuple<string, string>>(); +} diff --git a/libs/litehtml/src/el_title.cpp b/libs/litehtml/src/el_title.cpp new file mode 100644 index 0000000000..f0e42311b4 --- /dev/null +++ b/libs/litehtml/src/el_title.cpp @@ -0,0 +1,16 @@ +#include "html.h" +#include "el_title.h" +#include "document.h" + +litehtml::el_title::el_title(const std::shared_ptr<document>& doc) : html_tag(doc) +{ + +} + +void litehtml::el_title::parse_attributes() +{ + string text; + get_text(text); + get_document()->container()->set_caption(text.c_str()); +} + diff --git a/libs/litehtml/src/el_tr.cpp b/libs/litehtml/src/el_tr.cpp new file mode 100644 index 0000000000..f109976542 --- /dev/null +++ b/libs/litehtml/src/el_tr.cpp @@ -0,0 +1,28 @@ +#include "html.h" +#include "el_tr.h" + + +litehtml::el_tr::el_tr(const std::shared_ptr<document>& doc) : html_tag(doc) +{ + +} + +void litehtml::el_tr::parse_attributes() +{ + const char* str = get_attr("align"); + if(str) + { + m_style.add_property(_text_align_, str); + } + str = get_attr("valign"); + if(str) + { + m_style.add_property(_vertical_align_, str); + } + str = get_attr("bgcolor"); + if (str) + { + m_style.add_property(_background_color_, str, "", false, get_document()->container()); + } + html_tag::parse_attributes(); +} diff --git a/libs/litehtml/src/element.cpp b/libs/litehtml/src/element.cpp new file mode 100644 index 0000000000..e2b732ff1b --- /dev/null +++ b/libs/litehtml/src/element.cpp @@ -0,0 +1,478 @@ +#include "html.h" +#include "element.h" +#include "document.h" +#include "render_item.h" +#include "render_flex.h" +#include "render_inline.h" +#include "render_table.h" +#include "el_before_after.h" + +namespace litehtml +{ + +#define LITEHTML_EMPTY_FUNC {} +#define LITEHTML_RETURN_FUNC(ret) {return ret;} + +element::element(const document::ptr& doc) : m_doc(doc) +{ +} + +position element::get_placement() const +{ + position pos; + bool is_first = true; + for(const auto& ri_el : m_renders) + { + auto ri = ri_el.lock(); + if(ri) + { + position ri_pos = ri_el.lock()->get_placement(); + if(is_first) + { + is_first = false; + pos = ri_pos; + } else + { + if(pos.x < ri_pos.x) + { + pos.x = ri_pos.x; + } + if(pos.y < ri_pos.y) + { + pos.y = ri_pos.y; + } + } + } + } + return pos; +} + +bool element::is_inline() const +{ + if( css().get_display() == display_inline || + css().get_display() == display_inline_table || + css().get_display() == display_inline_block || + css().get_display() == display_inline_text || + css().get_display() == display_inline_flex) + { + return true; + } + return false; +} + +bool element::is_inline_box() const +{ + if( css().get_display() == display_inline_table || + css().get_display() == display_inline_block || + css().get_display() == display_inline_flex) + { + return true; + } + return false; +} + +bool element::is_ancestor(const ptr &el) const +{ + element::ptr el_parent = parent(); + while(el_parent && el_parent != el) + { + el_parent = el_parent->parent(); + } + if(el_parent) + { + return true; + } + return false; +} + +bool element::is_table_skip() const +{ + return is_space() || is_comment() || css().get_display() == display_none; +} + +string element::dump_get_name() +{ + return "element"; +} + +std::vector<std::tuple<string, string>> element::dump_get_attrs() +{ + return m_css.dump_get_attrs(); +} + +void element::dump(dumper& cout) +{ + cout.begin_node(dump_get_name()); + + auto attrs = dump_get_attrs(); + if(!attrs.empty()) + { + cout.begin_attrs_group("attributes"); + for (const auto &attr: attrs) + { + cout.add_attr(std::get<0>(attr), std::get<1>(attr)); + } + cout.end_attrs_group(); + } + + if(!m_children.empty()) + { + cout.begin_attrs_group("children"); + for (const auto &el: m_children) + { + el->dump(cout); + } + cout.end_attrs_group(); + } + + cout.end_node(); +} + +std::shared_ptr<render_item> element::create_render_item(const std::shared_ptr<render_item>& parent_ri) +{ + std::shared_ptr<render_item> ret; + + if(css().get_display() == display_table_column || + css().get_display() == display_table_column_group || + css().get_display() == display_table_footer_group || + css().get_display() == display_table_header_group || + css().get_display() == display_table_row_group) + { + ret = std::make_shared<render_item_table_part>(shared_from_this()); + } else if(css().get_display() == display_table_row) + { + ret = std::make_shared<render_item_table_row>(shared_from_this()); + } else if(css().get_display() == display_block || + css().get_display() == display_table_cell || + css().get_display() == display_table_caption || + css().get_display() == display_list_item || + css().get_display() == display_inline_block) + { + ret = std::make_shared<render_item_block>(shared_from_this()); + } else if(css().get_display() == display_table || css().get_display() == display_inline_table) + { + ret = std::make_shared<render_item_table>(shared_from_this()); + } else if(css().get_display() == display_inline || css().get_display() == display_inline_text) + { + ret = std::make_shared<render_item_inline>(shared_from_this()); + } else if(css().get_display() == display_flex || css().get_display() == display_inline_flex) + { + ret = std::make_shared<render_item_flex>(shared_from_this()); + } + if(ret) + { + if (css().get_display() == display_table || + css().get_display() == display_inline_table || + css().get_display() == display_table_caption || + css().get_display() == display_table_cell || + css().get_display() == display_table_column || + css().get_display() == display_table_column_group || + css().get_display() == display_table_footer_group || + css().get_display() == display_table_header_group || + css().get_display() == display_table_row || + css().get_display() == display_table_row_group) + { + get_document()->add_tabular(ret); + } + + ret->parent(parent_ri); + for(const auto& el : m_children) + { + auto ri = el->create_render_item(ret); + if(ri) + { + ret->add_child(ri); + } + } + } + return ret; +} + +bool element::requires_styles_update() +{ + for (const auto& used_style : m_used_styles) + { + if(used_style->m_selector->is_media_valid()) + { + int res = select(*(used_style->m_selector), true); + if( (res == select_no_match && used_style->m_used) || (res == select_match && !used_style->m_used) ) + { + return true; + } + } + } + return false; +} + +void element::add_render(const std::shared_ptr<render_item>& ri) +{ + m_renders.push_back(ri); +} + +bool element::find_styles_changes( position::vector& redraw_boxes) +{ + if(css().get_display() == display_inline_text) + { + return false; + } + + bool ret = false; + + if(requires_styles_update()) + { + auto fetch_boxes = [&](const std::shared_ptr<element>& el) + { + for(const auto& weak_ri : el->m_renders) + { + auto ri = weak_ri.lock(); + if(ri) + { + position::vector boxes; + ri->get_rendering_boxes(boxes); + for (auto &box: boxes) + { + redraw_boxes.push_back(box); + } + } + } + }; + fetch_boxes(shared_from_this()); + for (auto& el : m_children) + { + fetch_boxes(el); + } + + refresh_styles(); + compute_styles(); + ret = true; + } + for (auto& el : m_children) + { + if(el->find_styles_changes(redraw_boxes)) + { + ret = true; + } + } + return ret; +} + +element::ptr element::_add_before_after(int type, const style& /*style*/) +{ + element::ptr el; + if(type == 0) + { + el = std::make_shared<el_before>(get_document()); + m_children.insert(m_children.begin(), el); + } else + { + el = std::make_shared<el_after>(get_document()); + m_children.insert(m_children.end(), el); + } + el->parent(shared_from_this()); + return el; +} + +bool element::is_block_formatting_context() const +{ + if(m_css.get_display() == display_block) + { + auto par = parent(); + if(par && (par->css().get_display() == display_inline_flex || par->css().get_display() == display_flex)) + { + return true; + } + } + if( m_css.get_display() == display_inline_block || + m_css.get_display() == display_table_cell || + m_css.get_display() == display_inline_flex || + m_css.get_display() == display_flex || + m_css.get_display() == display_table_caption || + is_root() || + m_css.get_float() != float_none || + m_css.get_position() == element_position_absolute || + m_css.get_position() == element_position_fixed || + m_css.get_overflow() > overflow_visible) + { + return true; + } + return false; +} + +litehtml::string litehtml::element::get_counter_value(const string& counter_name) +{ + std::map<string_id, int>::iterator i; + if (find_counter(_id(counter_name), i)) + { + return std::to_string(i->second); + } + return "0"; +} + +string litehtml::element::get_counters_value(const string_vector& parameters) +{ + string result; + if (parameters.size() >= 2) { + const string_id counter_name_id = _id(parameters[0]); + string delims = parameters[1]; + litehtml::trim(delims, "\"'"); + + string_vector values; + + element::ptr current = shared_from_this(); + while (current != nullptr) + { + auto map_iterator = current->m_counter_values.find(counter_name_id); + if (map_iterator != current->m_counter_values.end()) { + values.push_back(std::to_string(map_iterator->second)); + } + current = current->parent(); + } + if (values.empty()) { + // if no counter is found, instance one with value '0' + shared_from_this()->m_counter_values[counter_name_id] = 0; + result = "0"; + } + else { + std::reverse(values.begin(), values.end()); + litehtml::join_string(result, values, delims); + } + } + return result; +} + + +bool litehtml::element::find_counter(const string_id& counter_name_id, std::map<string_id, int>::iterator& map_iterator) { + element::ptr current = shared_from_this(); + + while (current != nullptr) + { + map_iterator = current->m_counter_values.find(counter_name_id); + if (map_iterator != current->m_counter_values.end()) { + return true; + } + + // on each level, search previous siblings too + std::vector<element::ptr> siblings = current->get_siblings_before(); + std::reverse(siblings.begin(), siblings.end()); + for (const element::ptr& sibling : siblings) { + map_iterator = sibling->m_counter_values.find(counter_name_id); + if (map_iterator != sibling->m_counter_values.end()) { + return true; + } + } + current = current->parent(); + } + + return false; +} + +std::vector<element::ptr> litehtml::element::get_siblings_before() const +{ + std::vector<element::ptr> siblings; + if (parent() != nullptr) { + for (const element::ptr& sybling : parent()->children()) { + if (sybling == shared_from_this()) { + break; + } + siblings.push_back(sybling); + } + } + return siblings; +} + + +void litehtml::element::parse_counter_tokens(const string_vector& tokens, const int default_value, std::function<void(const string_id&, const int)> handler) const { + int pos = 0; + while (pos < (int) tokens.size()) { + string name = tokens[pos]; + int value = default_value; + if (pos < (int) tokens.size() - 1 && litehtml::is_number(tokens[pos + 1], false)) { + value = atoi(tokens[pos + 1].c_str()); + pos += 2; + } + else { + pos += 1; + } + handler(_id(name), value); + } +} + +void litehtml::element::increment_counter(const string_id& counter_name_id, const int increment) +{ + std::map<string_id, int>::iterator i; + if (find_counter(counter_name_id, i)) { + i->second = i->second + increment; + } + else { + // if counter is not found, initialize one on this element + m_counter_values[counter_name_id] = increment; + } +} + +void litehtml::element::reset_counter(const string_id& counter_name_id, const int value) +{ + m_counter_values[counter_name_id] = value; +} + +const background* element::get_background(bool /*own_only*/) LITEHTML_RETURN_FUNC(nullptr) +void element::add_style( const style& /*style*/) LITEHTML_EMPTY_FUNC +void element::select_all(const css_selector& /*selector*/, elements_list& /*res*/) LITEHTML_EMPTY_FUNC +elements_list element::select_all(const css_selector& /*selector*/) LITEHTML_RETURN_FUNC(elements_list()) +elements_list element::select_all(const string& /*selector*/) LITEHTML_RETURN_FUNC(elements_list()) +element::ptr element::select_one( const css_selector& /*selector*/ ) LITEHTML_RETURN_FUNC(nullptr) +element::ptr element::select_one( const string& /*selector*/ ) LITEHTML_RETURN_FUNC(nullptr) +element::ptr element::find_adjacent_sibling(const element::ptr& /*el*/, const css_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/, bool* /*is_pseudo*/ /*= 0*/) LITEHTML_RETURN_FUNC(nullptr) +element::ptr element::find_sibling(const element::ptr& /*el*/, const css_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/, bool* /*is_pseudo*/ /*= 0*/) LITEHTML_RETURN_FUNC(nullptr) +bool element::is_nth_last_child(const element::ptr& /*el*/, int /*num*/, int /*off*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false) +bool element::is_nth_child(const element::ptr&, int /*num*/, int /*off*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false) +bool element::is_only_child(const element::ptr& /*el*/, bool /*of_type*/) const LITEHTML_RETURN_FUNC(false) +void element::get_content_size( size& /*sz*/, int /*max_width*/ ) LITEHTML_EMPTY_FUNC +bool element::appendChild(const ptr &/*el*/) LITEHTML_RETURN_FUNC(false) +bool element::removeChild(const ptr &/*el*/) LITEHTML_RETURN_FUNC(false) +void element::clearRecursive() LITEHTML_EMPTY_FUNC +string_id element::id() const LITEHTML_RETURN_FUNC(empty_id) +string_id element::tag() const LITEHTML_RETURN_FUNC(empty_id) +const char* element::get_tagName() const LITEHTML_RETURN_FUNC("") +void element::set_tagName( const char* /*tag*/ ) LITEHTML_EMPTY_FUNC +void element::set_data( const char* /*data*/ ) LITEHTML_EMPTY_FUNC +void element::set_attr( const char* /*name*/, const char* /*val*/ ) LITEHTML_EMPTY_FUNC +void element::apply_stylesheet( const litehtml::css& /*stylesheet*/ ) LITEHTML_EMPTY_FUNC +void element::refresh_styles() LITEHTML_EMPTY_FUNC +void element::on_click() LITEHTML_EMPTY_FUNC +void element::compute_styles( bool /*recursive*/ ) LITEHTML_EMPTY_FUNC +const char* element::get_attr( const char* /*name*/, const char* def /*= 0*/ ) const LITEHTML_RETURN_FUNC(def) +bool element::is_white_space() const LITEHTML_RETURN_FUNC(false) +bool element::is_space() const LITEHTML_RETURN_FUNC(false) +bool element::is_comment() const LITEHTML_RETURN_FUNC(false) +bool element::is_body() const LITEHTML_RETURN_FUNC(false) +bool element::is_break() const LITEHTML_RETURN_FUNC(false) +bool element::is_text() const LITEHTML_RETURN_FUNC(false) + +bool element::on_mouse_over() LITEHTML_RETURN_FUNC(false) +bool element::on_mouse_leave() LITEHTML_RETURN_FUNC(false) +bool element::on_lbutton_down() LITEHTML_RETURN_FUNC(false) +bool element::on_lbutton_up() LITEHTML_RETURN_FUNC(false) +bool element::set_pseudo_class( string_id /*cls*/, bool /*add*/ ) LITEHTML_RETURN_FUNC(false) +bool element::set_class( const char* /*pclass*/, bool /*add*/ ) LITEHTML_RETURN_FUNC(false) +bool element::is_replaced() const LITEHTML_RETURN_FUNC(false) +void element::draw(uint_ptr /*hdc*/, int /*x*/, int /*y*/, const position */*clip*/, const std::shared_ptr<render_item> &/*ri*/) LITEHTML_EMPTY_FUNC +void element::draw_background(uint_ptr /*hdc*/, int /*x*/, int /*y*/, const position */*clip*/, const std::shared_ptr<render_item> &/*ri*/) LITEHTML_EMPTY_FUNC +int element::get_enum_property (string_id /*name*/, bool /*inherited*/, int /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0) +int element::get_int_property (string_id /*name*/, bool /*inherited*/, int /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0) +css_length element::get_length_property (string_id /*name*/, bool /*inherited*/, css_length /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0) +web_color element::get_color_property (string_id /*name*/, bool /*inherited*/, web_color /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(web_color()) +string element::get_string_property (string_id /*name*/, bool /*inherited*/, const string& /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC("") +float element::get_number_property (string_id /*name*/, bool /*inherited*/, float /*defval*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC(0) +string_vector element::get_string_vector_property (string_id /*name*/, bool /*inherited*/, const string_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({}) +int_vector element::get_int_vector_property (string_id /*name*/, bool /*inherited*/, const int_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({}) +length_vector element::get_length_vector_property (string_id /*name*/, bool /*inherited*/, const length_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({}) +size_vector element::get_size_vector_property (string_id /*name*/, bool /*inherited*/, const size_vector& /*default_value*/, uint_ptr /*css_properties_member_offset*/) const LITEHTML_RETURN_FUNC({}) +string element::get_custom_property (string_id /*name*/, const string& /*defval*/) const LITEHTML_RETURN_FUNC("") +void element::get_text( string& /*text*/ ) LITEHTML_EMPTY_FUNC +void element::parse_attributes() LITEHTML_EMPTY_FUNC +int element::select(const string& /*selector*/) LITEHTML_RETURN_FUNC(select_no_match) +int element::select(const css_selector& /*selector*/, bool /*apply_pseudo*/) LITEHTML_RETURN_FUNC(select_no_match) +int element::select( const css_element_selector& /*selector*/, bool /*apply_pseudo*/ /*= true*/ ) LITEHTML_RETURN_FUNC(select_no_match) +element::ptr element::find_ancestor(const css_selector& /*selector*/, bool /*apply_pseudo*/, bool* /*is_pseudo*/) LITEHTML_RETURN_FUNC(nullptr) + +} // namespace litehtml
\ No newline at end of file diff --git a/libs/litehtml/src/flex_item.cpp b/libs/litehtml/src/flex_item.cpp new file mode 100644 index 0000000000..8eb66847e5 --- /dev/null +++ b/libs/litehtml/src/flex_item.cpp @@ -0,0 +1,498 @@ +#include "html.h" +#include "flex_item.h" +#include "render_item.h" +#include "flex_line.h" +#include <cmath> + +void litehtml::flex_item::init(const litehtml::containing_block_context &self_size, + litehtml::formatting_context *fmt_ctx, flex_align_items align_items) +{ + grow = (int) std::nearbyint(el->css().get_flex_grow() * 1000.0); + // Negative numbers are invalid. + // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-grow-number + if(grow < 0) grow = 0; + + shrink = (int) std::nearbyint(el->css().get_flex_shrink() * 1000.0); + // Negative numbers are invalid. + // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-shrink-number + if(shrink < 0) shrink = 1000; + + el->calc_outlines(self_size.render_width); + order = el->css().get_order(); + + direction_specific_init(self_size, fmt_ctx); + + if (el->css().get_flex_align_self() == flex_align_items_auto) + { + align = align_items; + } else + { + align = el->css().get_flex_align_self(); + } + main_size = base_size; + scaled_flex_shrink_factor = base_size * shrink; + frozen = false; +} + +void litehtml::flex_item::place(flex_line &ln, int main_pos, + const containing_block_context &self_size, + formatting_context *fmt_ctx) +{ + apply_main_auto_margins(); + set_main_position(main_pos); + if(!apply_cross_auto_margins(ln.cross_size)) + { + switch (align & 0xFF) + { + case flex_align_items_baseline: + align_baseline(ln, self_size, fmt_ctx); + break; + case flex_align_items_flex_end: + if(ln.reverse_cross) + { + /// If cross axis is reversed position item from start + set_cross_position(ln.cross_start); + } else + { + set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size()); + } + break; + case flex_align_items_end: + set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size()); + break; + case flex_align_items_center: + set_cross_position(ln.cross_start + ln.cross_size / 2 - get_el_cross_size() / 2); + break; + case flex_align_items_flex_start: + if(ln.reverse_cross) /// If cross axis is reversed position item from end + { + set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size()); + } else + { + set_cross_position(ln.cross_start); + } + break; + case flex_align_items_start: + set_cross_position(ln.cross_start); + break; + default: + align_stretch(ln, self_size, fmt_ctx); + break; + } + } +} + +int litehtml::flex_item::get_last_baseline(baseline::_baseline_type type) const +{ + if(type == baseline::baseline_type_top) + { + return el->get_last_baseline(); + } else if(type == baseline::baseline_type_bottom) + { + return el->height() - el->get_last_baseline(); + } + return 0; +} + +int litehtml::flex_item::get_first_baseline(litehtml::baseline::_baseline_type type) const +{ + if(type == baseline::baseline_type_top) + { + return el->get_first_baseline(); + } else if(type == baseline::baseline_type_bottom) + { + return el->height() - el->get_first_baseline(); + } + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////////// + +void litehtml::flex_item_row_direction::direction_specific_init(const litehtml::containing_block_context &self_size, + litehtml::formatting_context *fmt_ctx) +{ + if(el->css().get_margins().left.is_predefined()) + { + auto_margin_main_start = 0; + } + if(el->css().get_margins().right.is_predefined()) + { + auto_margin_main_end = 0; + } + if(el->css().get_margins().top.is_predefined()) + { + auto_margin_cross_start = true; + } + if(el->css().get_margins().bottom.is_predefined()) + { + auto_margin_cross_end = true; + } + def_value<int> content_size(0); + if (el->css().get_min_width().is_predefined()) + { + min_size = el->render(0, 0, + self_size.new_width(el->content_offset_width(), + containing_block_context::size_mode_content), fmt_ctx); + content_size = min_size; + } else + { + min_size = el->css().get_min_width().calc_percent(self_size.render_width) + + el->content_offset_width(); + } + if (!el->css().get_max_width().is_predefined()) + { + max_size = el->css().get_max_width().calc_percent(self_size.render_width) + + el->content_offset_width(); + } + bool flex_basis_predefined = el->css().get_flex_basis().is_predefined(); + int predef = flex_basis_auto; + if(flex_basis_predefined) + { + predef = el->css().get_flex_basis().predef(); + } else + { + if(el->css().get_flex_basis().val() < 0) + { + flex_basis_predefined = true; + } + } + + if (flex_basis_predefined) + { + if(predef == flex_basis_auto && el->css().get_width().is_predefined()) + { + // if width is not predefined, use content size as base size + predef = flex_basis_content; + } + + switch (predef) + { + case flex_basis_auto: + base_size = el->css().get_width().calc_percent(self_size.render_width) + + el->content_offset_width(); + break; + case flex_basis_fit_content: + case flex_basis_content: + base_size = el->render(0, 0, self_size.new_width(self_size.render_width + el->content_offset_width(), + containing_block_context::size_mode_content | + containing_block_context::size_mode_exact_width), + fmt_ctx); + break; + case flex_basis_min_content: + if(content_size.is_default()) + { + content_size = el->render(0, 0, + self_size.new_width(el->content_offset_width(), + containing_block_context::size_mode_content), + fmt_ctx); + } + base_size = content_size; + break; + case flex_basis_max_content: + el->render(0, 0, self_size, fmt_ctx); + base_size = el->width(); + break; + default: + base_size = 0; + break; + } + } else + { + base_size = el->css().get_flex_basis().calc_percent(self_size.render_width) + + el->content_offset_width(); + base_size = std::max(base_size, min_size); + } +} + +void litehtml::flex_item_row_direction::apply_main_auto_margins() +{ + // apply auto margins to item + if(!auto_margin_main_start.is_default()) + { + el->get_margins().left = auto_margin_main_start; + el->pos().x += auto_margin_main_start; + } + if(!auto_margin_main_end.is_default()) el->get_margins().right = auto_margin_main_end; +} + +bool litehtml::flex_item_row_direction::apply_cross_auto_margins(int cross_size) +{ + if(auto_margin_cross_end || auto_margin_cross_start) + { + int margins_num = 0; + if(auto_margin_cross_end) + { + margins_num++; + } + if(auto_margin_cross_start) + { + margins_num++; + } + int margin = (cross_size - el->height()) / margins_num; + if(auto_margin_cross_start) + { + el->get_margins().top = margin; + el->pos().y = el->content_offset_top(); + } + if(auto_margin_cross_end) + { + el->get_margins().bottom = margin; + } + return true; + } + return false; +} + +void litehtml::flex_item_row_direction::set_main_position(int pos) +{ + el->pos().x = pos + el->content_offset_left(); +} + +void litehtml::flex_item_row_direction::set_cross_position(int pos) +{ + el->pos().y = pos + el->content_offset_top(); +} + +void litehtml::flex_item_row_direction::align_stretch(flex_line &ln, const containing_block_context &self_size, + formatting_context *fmt_ctx) +{ + set_cross_position(ln.cross_start); + if (el->css().get_height().is_predefined()) + { + el->render(el->left(), el->top(), self_size.new_width_height( + el->pos().width + el->box_sizing_width(), + ln.cross_size - el->content_offset_height() + el->box_sizing_height(), + containing_block_context::size_mode_exact_width | + containing_block_context::size_mode_exact_height + ), fmt_ctx); + apply_main_auto_margins(); + } +} + +void litehtml::flex_item_row_direction::align_baseline(litehtml::flex_line &ln, + const containing_block_context &/*self_size*/, + formatting_context */*fmt_ctx*/) +{ + if (align & flex_align_items_last) + { + set_cross_position(ln.cross_start + ln.last_baseline.get_offset_from_top(ln.cross_size) - el->get_last_baseline()); + } else + { + set_cross_position(ln.cross_start + ln.first_baseline.get_offset_from_top(ln.cross_size) - el->get_first_baseline()); + } +} + +int litehtml::flex_item_row_direction::get_el_main_size() +{ + return el->width(); +} + +int litehtml::flex_item_row_direction::get_el_cross_size() +{ + return el->height(); +} + +//////////////////////////////////////////////////////////////////////////////////// + +void litehtml::flex_item_column_direction::direction_specific_init(const litehtml::containing_block_context &self_size, + litehtml::formatting_context *fmt_ctx) +{ + if(el->css().get_margins().top.is_predefined()) + { + auto_margin_main_start = 0; + } + if(el->css().get_margins().bottom.is_predefined()) + { + auto_margin_main_end = 0; + } + if(el->css().get_margins().left.is_predefined()) + { + auto_margin_cross_start = true; + } + if(el->css().get_margins().right.is_predefined()) + { + auto_margin_cross_end = true; + } + if (el->css().get_min_height().is_predefined()) + { + el->render(0, 0, self_size.new_width(self_size.render_width, containing_block_context::size_mode_content), fmt_ctx); + min_size = el->height(); + } else + { + min_size = el->css().get_min_height().calc_percent(self_size.height) + + el->content_offset_height(); + } + if (!el->css().get_max_height().is_predefined()) + { + max_size = el->css().get_max_height().calc_percent(self_size.height) + + el->content_offset_width(); + } + + bool flex_basis_predefined = el->css().get_flex_basis().is_predefined(); + int predef = flex_basis_auto; + if(flex_basis_predefined) + { + predef = el->css().get_flex_basis().predef(); + } else + { + if(el->css().get_flex_basis().val() < 0) + { + flex_basis_predefined = true; + } + } + + if (flex_basis_predefined) + { + if(predef == flex_basis_auto && el->css().get_height().is_predefined()) + { + predef = flex_basis_fit_content; + } + switch (predef) + { + case flex_basis_auto: + base_size = el->css().get_height().calc_percent(self_size.height) + + el->content_offset_height(); + break; + case flex_basis_max_content: + case flex_basis_fit_content: + el->render(0, 0, self_size, fmt_ctx); + base_size = el->height(); + break; + case flex_basis_min_content: + base_size = min_size; + break; + default: + base_size = 0; + } + } else + { + if(el->css().get_flex_basis().units() == css_units_percentage) + { + if(self_size.height.type == containing_block_context::cbc_value_type_absolute) + { + base_size = el->css().get_flex_basis().calc_percent(self_size.height) + + el->content_offset_height(); + } else + { + base_size = 0; + } + } else + { + base_size = (int) el->css().get_flex_basis().val() + el->content_offset_height(); + } + base_size = std::max(base_size, min_size); + } +} + +void litehtml::flex_item_column_direction::apply_main_auto_margins() +{ + // apply auto margins to item + if(!auto_margin_main_start.is_default()) + { + el->get_margins().top = auto_margin_main_start; + el->pos().y += auto_margin_main_start; + } + if(!auto_margin_main_end.is_default()) el->get_margins().bottom = auto_margin_main_end; +} + +bool litehtml::flex_item_column_direction::apply_cross_auto_margins(int cross_size) +{ + if(auto_margin_cross_end || auto_margin_cross_start) + { + int margins_num = 0; + if(auto_margin_cross_end) + { + margins_num++; + } + if(auto_margin_cross_start) + { + margins_num++; + } + int margin = (cross_size - el->width()) / margins_num; + if(auto_margin_cross_start) + { + el->get_margins().left = margin; + el->pos().x += el->content_offset_left(); + } + if(auto_margin_cross_end) + { + el->get_margins().right = margin; + } + } + return false; +} + +void litehtml::flex_item_column_direction::set_main_position(int pos) +{ + el->pos().y = pos + el->content_offset_top(); +} + +void litehtml::flex_item_column_direction::set_cross_position(int pos) +{ + el->pos().x = pos + el->content_offset_left(); +} + +void litehtml::flex_item_column_direction::align_stretch(flex_line &ln, const containing_block_context &self_size, + formatting_context *fmt_ctx) +{ + /// MAIN: Y + /// CROSS: X + if (!el->css().get_width().is_predefined()) + { + el->render(ln.cross_start, + el->pos().y - el->content_offset_top(), + self_size.new_width_height(ln.cross_size - el->content_offset_width() + el->box_sizing_width(), + main_size - el->content_offset_height() + el->box_sizing_height(), + containing_block_context::size_mode_exact_height), + fmt_ctx, false); + } else + { + el->render(ln.cross_start, + el->pos().y - el->content_offset_top(), + self_size.new_width_height( + ln.cross_size - el->content_offset_width() + el->box_sizing_width(), + main_size - el->content_offset_height() + el->box_sizing_height(), + containing_block_context::size_mode_exact_width | + containing_block_context::size_mode_exact_height), + fmt_ctx, false); + } + /// Apply auto margins after rendering + apply_main_auto_margins(); +} + +void litehtml::flex_item_column_direction::align_baseline(litehtml::flex_line &ln, + const containing_block_context &/*self_size*/, + formatting_context */*fmt_ctx*/) +{ + // The fallback alignment for first baseline is start, the one for last baseline is end. + if(align & flex_align_items_last) + { + if(ln.reverse_cross) + { + set_cross_position(ln.cross_start); + } else + { + set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size()); + } + } else + { + if(!ln.reverse_cross) + { + set_cross_position(ln.cross_start); + } else + { + set_cross_position(ln.cross_start + ln.cross_size - get_el_cross_size()); + } + } +} + +int litehtml::flex_item_column_direction::get_el_main_size() +{ + return el->height(); +} + +int litehtml::flex_item_column_direction::get_el_cross_size() +{ + return el->width(); +} diff --git a/libs/litehtml/src/flex_line.cpp b/libs/litehtml/src/flex_line.cpp new file mode 100644 index 0000000000..5f966b3b15 --- /dev/null +++ b/libs/litehtml/src/flex_line.cpp @@ -0,0 +1,454 @@ +#include "html.h" +#include "flex_line.h" +#include "flex_item.h" +#include "render_item.h" + +void litehtml::flex_line::distribute_free_space(int container_main_size) +{ + // Determine the used flex factor. Sum the outer hypothetical main sizes of all items on the line. + // If the sum is less than the flex container’s inner main size, use the flex grow factor for the + // rest of this algorithm; otherwise, use the flex shrink factor. + int initial_free_space = container_main_size - base_size; + bool grow; + int total_flex_factor; + if(initial_free_space < 0) + { + grow = false; + total_flex_factor = total_shrink; + // Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line + // is less than 1, they will take up less than 100% of the free space. + // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-flex-grow + if(total_flex_factor < 1000) + { + for(auto &item : items) + { + item->main_size += initial_free_space * item->shrink / 1000; + } + return; + } + } else + { + grow = true; + total_flex_factor = total_grow; + // Flex values between 0 and 1 have a somewhat special behavior: when the sum of the flex values on the line + // is less than 1, they will take up less than 100% of the free space. + // https://www.w3.org/TR/css-flexbox-1/#valdef-flex-flex-grow + if(total_flex_factor < 1000) + { + for(auto &item : items) + { + item->main_size += initial_free_space * item->grow / 1000; + } + return; + } + } + + if(total_flex_factor > 0) + { + bool processed = true; + while (processed) + { + int sum_scaled_flex_shrink_factor = 0; + int sum_flex_factors = 0; + int remaining_free_space = container_main_size; + int total_not_frozen = 0; + for (auto &item: items) + { + if (!item->frozen) + { + sum_scaled_flex_shrink_factor += item->scaled_flex_shrink_factor; + if(grow) + { + sum_flex_factors += item->grow; + } else + { + sum_flex_factors += item->shrink; + } + remaining_free_space -= item->base_size; + total_not_frozen++; + } else + { + remaining_free_space -= item->main_size; + } + } + // Check for flexible items. If all the flex items on the line are frozen, free space has + // been distributed; exit this loop. + if (!total_not_frozen) break; + + remaining_free_space = abs(remaining_free_space); + // c. Distribute free space proportional to the flex factors. + // If the remaining free space is zero + // Do nothing. + if (!remaining_free_space) + { + processed = false; + } else + { + int total_clamped = 0; + for (auto &item: items) + { + if (!item->frozen) + { + if(!grow) + { + // If using the flex shrink factor + // For every unfrozen item on the line, multiply its flex shrink factor by its + // inner flex base size, and note this as its scaled flex shrink factor. Find + // the ratio of the item’s scaled flex shrink factor to the sum of the scaled + // flex shrink factors of all unfrozen items on the line. Set the item’s target + // main size to its flex base size minus a fraction of the absolute value of the + // remaining free space proportional to the ratio. + int scaled_flex_shrink_factor = item->base_size * item->shrink; + item->main_size = (int) ((float) item->base_size - (float) remaining_free_space * + (float) scaled_flex_shrink_factor / + (float) sum_scaled_flex_shrink_factor); + + // d. Fix min/max violations. Clamp each non-frozen item’s target main size by its used + // min and max main sizes and floor its content-box size at zero. If the item’s target + // main size was made smaller by this, it’s a max violation. If the item’s target main + // size was made larger by this, it’s a min violation. + if (item->main_size <= item->min_size) + { + total_clamped++; + item->main_size = item->min_size; + item->frozen = true; + } + if(!item->max_size.is_default() && item->main_size >= item->max_size) + { + total_clamped++; + item->main_size = item->max_size; + item->frozen = true; + } + } else + { + // If using the flex grow factor + // Find the ratio of the item’s flex grow factor to the sum of the flex grow + // factors of all unfrozen items on the line. Set the item’s target main size to + // its flex base size plus a fraction of the remaining free space proportional + // to the ratio. + item->main_size = (int) ((float) item->base_size + + (float) remaining_free_space * (float) item->grow / + (float) total_flex_factor); + // d. Fix min/max violations. Clamp each non-frozen item’s target main size by its used + // min and max main sizes and floor its content-box size at zero. If the item’s target + // main size was made smaller by this, it’s a max violation. If the item’s target main + // size was made larger by this, it’s a min violation. + if (item->main_size >= container_main_size) + { + total_clamped++; + item->main_size = container_main_size; + item->frozen = true; + } + if(!item->max_size.is_default() && item->main_size >= item->max_size) + { + total_clamped++; + item->main_size = item->max_size; + item->frozen = true; + } + } + } + } + if (total_clamped == 0) processed = false; + } + } + // Distribute remaining after algorithm space + int sum_main_size = 0; + for(auto &item : items) + { + sum_main_size += item->main_size; + } + int free_space = container_main_size - sum_main_size; + if(free_space > 0) + { + for(auto &item : items) + { + if(free_space == 0) break; + item->main_size++; + free_space--; + } + } + } +} + +bool litehtml::flex_line::distribute_main_auto_margins(int free_main_size) +{ + if(free_main_size > 0 && (num_auto_margin_main_start || num_auto_margin_main_end)) + { + int add = (int) (free_main_size / (items.size() * 2)); + for (auto &item: items) + { + if(!item->auto_margin_main_start.is_default()) + { + item->auto_margin_main_start = add; + item->main_size += add; + main_size += add; + free_main_size -= add; + } + if(!item->auto_margin_main_end.is_default()) + { + item->auto_margin_main_end = add; + item->main_size += add; + main_size += add; + free_main_size -= add; + } + } + while (free_main_size > 0) + { + for (auto &item: items) + { + if(!item->auto_margin_main_start.is_default()) + { + item->auto_margin_main_start = item->auto_margin_main_start + 1; + free_main_size--; + if(!free_main_size) break; + } + if(!item->auto_margin_main_end.is_default()) + { + item->auto_margin_main_end = item->auto_margin_main_end + 1; + free_main_size--; + if(!free_main_size) break; + } + } + } + return true; + } + return false; +} + +void litehtml::flex_line::init(int container_main_size, bool fit_container, bool is_row_direction, + const litehtml::containing_block_context &self_size, + litehtml::formatting_context *fmt_ctx) +{ + cross_size = 0; + main_size = 0; + first_baseline.set(0, baseline::baseline_type_none); + last_baseline.set(0, baseline::baseline_type_none); + + if(!fit_container) + { + distribute_free_space(container_main_size); + } + + if(is_row_direction) + { + def_value<int> first_baseline_top = 0; + def_value<int> first_baseline_bottom = 0; + def_value<int> last_baseline_top = 0; + def_value<int> last_baseline_bottom = 0; + int non_baseline_height = 0; + + // Calculate maximum cross size + def_value<int> max_cross_size(0); + if(self_size.height.type != containing_block_context::cbc_value_type_auto) + { + max_cross_size = self_size.height; + } + if(self_size.max_height.type != containing_block_context::cbc_value_type_none) + { + if(max_cross_size.is_default()) + { + max_cross_size = self_size.max_height; + } else + { + max_cross_size = std::max((int) max_cross_size, (int) self_size.max_height); + } + } + + /// Render items into new size + /// Find line cross_size + /// Find line first/last baseline + for (auto &item: items) + { + item->el->render(0, + 0, + self_size.new_width(item->main_size - item->el->content_offset_width(), containing_block_context::size_mode_exact_width), fmt_ctx, false); + + if((item->align & 0xFF) == flex_align_items_baseline) + { + if(item->align & flex_align_items_last) + { + last_baseline.type(reverse_cross ? baseline::baseline_type_top : baseline::baseline_type_bottom); + + int top = -item->el->get_last_baseline(); + int bottom = top + item->el->height(); + + if(last_baseline_top.is_default()) last_baseline_top = top; + else last_baseline_top = std::min((int) last_baseline_top, top); + + if(last_baseline_bottom.is_default()) last_baseline_bottom = bottom; + else last_baseline_bottom = std::max((int)last_baseline_bottom, bottom); + } else + { + first_baseline.type(reverse_cross ? baseline::baseline_type_bottom : baseline::baseline_type_top); + int top = -item->el->get_first_baseline(); + int bottom = top + item->el->height(); + + if(first_baseline_top.is_default()) first_baseline_top = top; + else first_baseline_top = std::min((int) first_baseline_top, top); + + if(first_baseline_bottom.is_default()) first_baseline_bottom = bottom; + else first_baseline_bottom = std::max((int) first_baseline_bottom, bottom); + } + } else + { + non_baseline_height = std::max(non_baseline_height, item->el->height()); + } + main_size += item->el->width(); + } + + cross_size = std::max(first_baseline_bottom - first_baseline_top,last_baseline_bottom - last_baseline_top); + cross_size = std::max(cross_size, non_baseline_height); + if(!max_cross_size.is_default() && cross_size > max_cross_size) + { + cross_size = max_cross_size; + } + + first_baseline.calc(first_baseline_top, first_baseline_bottom); + last_baseline.calc(last_baseline_top, last_baseline_bottom); + } else + { + // Calculate maximum cross size + def_value<int> max_cross_size(0); + if(self_size.width.type != containing_block_context::cbc_value_type_auto) + { + max_cross_size = self_size.width; + } + if(self_size.max_width.type != containing_block_context::cbc_value_type_none) + { + if(max_cross_size.is_default()) + { + max_cross_size = self_size.max_width; + } else + { + max_cross_size = std::max((int) max_cross_size, (int) self_size.max_width); + } + } + + for (auto &item: items) + { + int el_ret_width = item->el->render(0, + 0, + self_size, fmt_ctx, false); + item->el->render(0, + 0, + self_size.new_width_height(el_ret_width - item->el->content_offset_width(), + item->main_size - item->el->content_offset_height(), + containing_block_context::size_mode_exact_width | + containing_block_context::size_mode_exact_height), + fmt_ctx, false); + main_size += item->el->height(); + cross_size = std::max(cross_size, item->el->width()); + } + if(!max_cross_size.is_default() && cross_size > max_cross_size) + { + cross_size = max_cross_size; + } + } +} + +int litehtml::flex_line::calculate_items_position(int container_main_size, + flex_justify_content justify_content, + bool is_row_direction, + const containing_block_context &self_size, + formatting_context *fmt_ctx) +{ + /// Distribute main axis free space for auto-margins + int free_main_size = container_main_size - main_size; + distribute_main_auto_margins(free_main_size); + free_main_size = container_main_size - main_size; + + /// Fix justify-content property + switch (justify_content) + { + case flex_justify_content_left: + case flex_justify_content_right: + if(!is_row_direction) + { + justify_content = flex_justify_content_start; + } + break; + case flex_justify_content_space_between: + // If the leftover free-space is negative or there is only a single flex item on the line, this + // value is identical to flex-start. + if(items.size() == 1 || free_main_size < 0) justify_content = flex_justify_content_flex_start; + break; + case flex_justify_content_space_around: + case flex_justify_content_space_evenly: + // If the leftover free-space is negative or there is only a single flex item on the line, this + // value is identical to center + if(items.size() == 1 || free_main_size < 0) justify_content = flex_justify_content_center; + break; + default: + break; + } + + /// Distribute free main size using justify-content property + int main_pos = 0; + int add_before_item = 0; + int add_after_item = 0; + int item_remainder = 0; + + /// find initial main position and spaces between items + switch (justify_content) + { + + case flex_justify_content_right: + main_pos = free_main_size; + break; + case flex_justify_content_left: + case flex_justify_content_start: + main_pos = 0; + break; + case flex_justify_content_end: + main_pos = free_main_size; + break; + case flex_justify_content_flex_end: + if(!reverse_main) + { + main_pos = free_main_size; + } + break; + case flex_justify_content_center: + main_pos = free_main_size / 2; + break; + case flex_justify_content_space_between: + add_after_item = free_main_size / ((int) items.size() - 1); + item_remainder = free_main_size - (add_after_item * ((int) items.size() - 1)); + break; + case flex_justify_content_space_around: + add_after_item = add_before_item = free_main_size / ((int) items.size() * 2); + item_remainder = free_main_size - (add_after_item * (int) items.size() * 2); + break; + case flex_justify_content_space_evenly: + add_before_item = free_main_size / ((int) items.size() + 1); + item_remainder = free_main_size - add_before_item * ((int) items.size() + 1); + break; + default: + if(reverse_main) + { + main_pos = free_main_size; + } + break; + } + + /// Place all items in main and cross positions + int height = 0; + for(auto &item : items) + { + main_pos += add_before_item; + if(add_before_item > 0 && item_remainder > 0) + { + main_pos++; + item_remainder--; + } + item->place(*this, main_pos, self_size, fmt_ctx); + main_pos += item->get_el_main_size() + add_after_item; + if(add_after_item > 0 && item_remainder > 0) + { + main_pos++; + item_remainder--; + } + height = std::max(height, item->el->bottom()); + } + return height; +} diff --git a/libs/litehtml/src/formatting_context.cpp b/libs/litehtml/src/formatting_context.cpp new file mode 100644 index 0000000000..e85e990c9c --- /dev/null +++ b/libs/litehtml/src/formatting_context.cpp @@ -0,0 +1,441 @@ +#include "html.h" +#include "render_item.h" +#include "formatting_context.h" + +void litehtml::formatting_context::add_float(const std::shared_ptr<render_item> &el, int min_width, int context) +{ + floated_box fb; + fb.pos.x = el->left() + m_current_left; + fb.pos.y = el->top() + m_current_top; + fb.pos.width = el->width(); + fb.pos.height = el->height(); + fb.float_side = el->src_el()->css().get_float(); + fb.clear_floats = el->src_el()->css().get_clear(); + fb.el = el; + fb.context = context; + fb.min_width = min_width; + + if(fb.float_side == float_left) + { + if(m_floats_left.empty()) + { + m_floats_left.push_back(fb); + } else + { + bool inserted = false; + for(auto i = m_floats_left.begin(); i != m_floats_left.end(); i++) + { + if(fb.pos.right() > i->pos.right()) + { + m_floats_left.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_left.push_back(std::move(fb)); + } + } + m_cache_line_left.invalidate(); + } else if(fb.float_side == float_right) + { + if(m_floats_right.empty()) + { + m_floats_right.push_back(std::move(fb)); + } else + { + bool inserted = false; + for(auto i = m_floats_right.begin(); i != m_floats_right.end(); i++) + { + if(fb.pos.left() < i->pos.left()) + { + m_floats_right.insert(i, std::move(fb)); + inserted = true; + break; + } + } + if(!inserted) + { + m_floats_right.push_back(fb); + } + } + m_cache_line_right.invalidate(); + } +} + +int litehtml::formatting_context::get_floats_height(element_float el_float) const +{ + int h = m_current_top; + + for(const auto& fb : m_floats_left) + { + bool process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + + for(const auto& fb : m_floats_right) + { + int process = false; + switch(el_float) + { + case float_none: + process = true; + break; + case float_left: + if (fb.clear_floats == clear_left || fb.clear_floats == clear_both) + { + process = true; + } + break; + case float_right: + if (fb.clear_floats == clear_right || fb.clear_floats == clear_both) + { + process = true; + } + break; + } + if(process) + { + if(el_float == float_none) + { + h = std::max(h, fb.pos.bottom()); + } else + { + h = std::max(h, fb.pos.top()); + } + } + } + + return h - m_current_top; +} + +int litehtml::formatting_context::get_left_floats_height() const +{ + int h = 0; + if(!m_floats_left.empty()) + { + for (const auto& fb : m_floats_left) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_right_floats_height() const +{ + int h = 0; + if(!m_floats_right.empty()) + { + for(const auto& fb : m_floats_right) + { + h = std::max(h, fb.pos.bottom()); + } + } + return h - m_current_top; +} + +int litehtml::formatting_context::get_line_left(int y ) +{ + y += m_current_top; + + if(m_cache_line_left.is_valid && m_cache_line_left.hash == y) + { + if(m_cache_line_left.val - m_current_left < 0) + { + return 0; + } + return m_cache_line_left.val - m_current_left; + } + + int w = 0; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::max(w, fb.pos.right()); + if (w < fb.pos.right()) + { + break; + } + } + } + m_cache_line_left.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + +int litehtml::formatting_context::get_line_right(int y, int def_right ) +{ + y += m_current_top; + def_right += m_current_left; + if(m_cache_line_right.is_valid && m_cache_line_right.hash == y) + { + if(m_cache_line_right.is_default) + { + return def_right - m_current_left; + } else + { + int w = std::min(m_cache_line_right.val, def_right) - m_current_left; + if(w < 0) return 0; + return w; + } + } + + int w = def_right; + m_cache_line_right.is_default = true; + for(const auto& fb : m_floats_right) + { + if(y >= fb.pos.top() && y < fb.pos.bottom()) + { + w = std::min(w, fb.pos.left()); + m_cache_line_right.is_default = false; + if(w > fb.pos.left()) + { + break; + } + } + } + m_cache_line_right.set_value(y, w); + w -= m_current_left; + if(w < 0) return 0; + return w; +} + + +void litehtml::formatting_context::clear_floats(int context) +{ + auto iter = m_floats_left.begin(); + while(iter != m_floats_left.end()) + { + if(iter->context >= context) + { + iter = m_floats_left.erase(iter); + m_cache_line_left.invalidate(); + } else + { + iter++; + } + } + + iter = m_floats_right.begin(); + while(iter != m_floats_right.end()) + { + if(iter->context >= context) + { + iter = m_floats_right.erase(iter); + m_cache_line_right.invalidate(); + } else + { + iter++; + } + } +} + +int litehtml::formatting_context::get_cleared_top(const std::shared_ptr<render_item> &el, int line_top) const +{ + switch(el->src_el()->css().get_clear()) + { + case clear_left: + { + int fh = get_left_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_right: + { + int fh = get_right_floats_height(); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + case clear_both: + { + int fh = get_floats_height(float_none); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + default: + if(el->src_el()->css().get_float() != float_none) + { + int fh = get_floats_height(el->src_el()->css().get_float()); + if(fh && fh > line_top) + { + line_top = fh; + } + } + break; + } + return line_top; +} + +int litehtml::formatting_context::find_next_line_top(int top, int width, int def_right ) +{ + top += m_current_top; + def_right += m_current_left; + + int new_top = top; + int_vector points; + + for(const auto& fb : m_floats_left) + { + if(fb.pos.top() >= top) + { + if(find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + for (const auto& fb : m_floats_right) + { + if (fb.pos.top() >= top) + { + if (find(points.begin(), points.end(), fb.pos.top()) == points.end()) + { + points.push_back(fb.pos.top()); + } + } + if (fb.pos.bottom() >= top) + { + if (find(points.begin(), points.end(), fb.pos.bottom()) == points.end()) + { + points.push_back(fb.pos.bottom()); + } + } + } + + if(!points.empty()) + { + sort(points.begin(), points.end(), std::less<int>( )); + new_top = points.back(); + + for(auto pt : points) + { + int pos_left = 0; + int pos_right = def_right; + get_line_left_right(pt - m_current_top, def_right - m_current_left, pos_left, pos_right); + + if(pos_right - pos_left >= width) + { + new_top = pt; + break; + } + } + } + return new_top - m_current_top; +} + +void litehtml::formatting_context::update_floats(int dy, const std::shared_ptr<render_item> &parent) +{ + bool reset_cache = false; + for(auto fb = m_floats_left.rbegin(); fb != m_floats_left.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_left.invalidate(); + } + reset_cache = false; + for(auto fb = m_floats_right.rbegin(); fb != m_floats_right.rend(); fb++) + { + if(fb->el->src_el()->is_ancestor(parent->src_el())) + { + reset_cache = true; + fb->pos.y += dy; + } + } + if(reset_cache) + { + m_cache_line_right.invalidate(); + } +} + +void litehtml::formatting_context::apply_relative_shift(const containing_block_context &containing_block_size) +{ + for (const auto& fb : m_floats_left) + { + fb.el->apply_relative_shift(containing_block_size); + } +} + +int litehtml::formatting_context::find_min_left(int y, int context_idx) +{ + y += m_current_top; + int min_left = m_current_left; + for(const auto& fb : m_floats_left) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_left += fb.min_width; + } + } + if(min_left < m_current_left) return 0; + return min_left - m_current_left; +} + +int litehtml::formatting_context::find_min_right(int y, int right, int context_idx) +{ + y += m_current_top; + int min_right = right + m_current_left; + for(const auto& fb : m_floats_right) + { + if (y >= fb.pos.top() && y < fb.pos.bottom() && fb.context == context_idx) + { + min_right -= fb.min_width; + } + } + if(min_right < m_current_left) return 0; + return min_right - m_current_left; +} diff --git a/libs/litehtml/src/gumbo/CMakeLists.txt b/libs/litehtml/src/gumbo/CMakeLists.txt new file mode 100644 index 0000000000..17843c9890 --- /dev/null +++ b/libs/litehtml/src/gumbo/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 3.5) + +project(gumbo C) + +# Soname +# MAJOR is incremented when symbols are removed or changed in an incompatible way +# MINOR is incremented when new symbols are added +set(PROJECT_MAJOR 0) +set(PROJECT_MINOR 0) + +set(SOURCE_GUMBO + attribute.c + char_ref.c + error.c + parser.c + string_buffer.c + string_piece.c + tag.c + tokenizer.c + utf8.c + util.c + vector.c +) + +set(HEADER_GUMBO + include/gumbo/attribute.h + include/gumbo/char_ref.h + include/gumbo/error.h + include/gumbo.h + include/gumbo/insertion_mode.h + include/gumbo/parser.h + include/gumbo/string_buffer.h + include/gumbo/string_piece.h + include/gumbo/tag_enum.h + include/gumbo/tag_gperf.h + include/gumbo/tag_sizes.h + include/gumbo/tag_strings.h + include/gumbo/token_type.h + include/gumbo/tokenizer.h + include/gumbo/tokenizer_states.h + include/gumbo/utf8.h + include/gumbo/util.h + include/gumbo/vector.h +) + +set(PROJECT_LIB_VERSION ${PROJECT_MAJOR}.${PROJECT_MINOR}.0) +set(PROJECT_SO_VERSION ${PROJECT_MAJOR}) + +add_library(${PROJECT_NAME} ${SOURCE_GUMBO}) +set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_LIB_VERSION} SOVERSION ${PROJECT_SO_VERSION}) + +set_target_properties(${PROJECT_NAME} PROPERTIES + C_STANDARD 99 + PUBLIC_HEADER "${HEADER_GUMBO}" +) + +if(MSVC) + target_include_directories(${PROJECT_NAME} PRIVATE visualc/include) +endif() + +# Export gumbo includes. +target_include_directories(${PROJECT_NAME} PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include>) +target_include_directories(${PROJECT_NAME} PRIVATE include/gumbo) + +# install and export +install(TARGETS ${PROJECT_NAME} + EXPORT gumbo + RUNTIME DESTINATION bin COMPONENT libraries + ARCHIVE DESTINATION lib${LIB_SUFFIX} COMPONENT libraries + LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT libraries + PUBLIC_HEADER DESTINATION include/gumbo +) +install(EXPORT gumbo FILE gumboConfig.cmake DESTINATION lib${LIB_SUFFIX}/cmake/gumbo) diff --git a/libs/litehtml/src/gumbo/LICENSE b/libs/litehtml/src/gumbo/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/libs/litehtml/src/gumbo/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/libs/litehtml/src/gumbo/attribute.c b/libs/litehtml/src/gumbo/attribute.c new file mode 100644 index 0000000000..234927a5f8 --- /dev/null +++ b/libs/litehtml/src/gumbo/attribute.c @@ -0,0 +1,44 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "attribute.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "util.h" + +struct GumboInternalParser; + +GumboAttribute* gumbo_get_attribute( + const GumboVector* attributes, const char* name) { + for (unsigned int i = 0; i < attributes->length; ++i) { + GumboAttribute* attr = attributes->data[i]; + if (!strcasecmp(attr->name, name)) { + return attr; + } + } + return NULL; +} + +void gumbo_destroy_attribute( + struct GumboInternalParser* parser, GumboAttribute* attribute) { + gumbo_parser_deallocate(parser, (void*) attribute->name); + gumbo_parser_deallocate(parser, (void*) attribute->value); + gumbo_parser_deallocate(parser, (void*) attribute); +} diff --git a/libs/litehtml/src/gumbo/char_ref.c b/libs/litehtml/src/gumbo/char_ref.c new file mode 100644 index 0000000000..b3c5eccaf3 --- /dev/null +++ b/libs/litehtml/src/gumbo/char_ref.c @@ -0,0 +1,23069 @@ + +#line 1 "char_ref.rl" +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This is a Ragel state machine re-implementation of the original char_ref.c, +// rewritten to improve efficiency. To generate the .c file from it, +// +// $ ragel -F0 char_ref.rl +// +// The generated source is also checked into source control so that most people +// hacking on the parser do not need to install ragel. + +#include "char_ref.h" + +#include <assert.h> +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> // Only for debug assertions at present. + +#include "error.h" +#include "string_piece.h" +#include "utf8.h" +#include "util.h" + +struct GumboInternalParser; + +const int kGumboNoChar = -1; + +// Table of replacement characters. The spec specifies that any occurrence of +// the first character should be replaced by the second character, and a parse +// error recorded. +typedef struct { + int from_char; + int to_char; +} CharReplacement; + +static const CharReplacement kCharReplacements[] = {{0x00, 0xfffd}, + {0x0d, 0x000d}, {0x80, 0x20ac}, {0x81, 0x0081}, {0x82, 0x201A}, + {0x83, 0x0192}, {0x84, 0x201E}, {0x85, 0x2026}, {0x86, 0x2020}, + {0x87, 0x2021}, {0x88, 0x02C6}, {0x89, 0x2030}, {0x8A, 0x0160}, + {0x8B, 0x2039}, {0x8C, 0x0152}, {0x8D, 0x008D}, {0x8E, 0x017D}, + {0x8F, 0x008F}, {0x90, 0x0090}, {0x91, 0x2018}, {0x92, 0x2019}, + {0x93, 0x201C}, {0x94, 0x201D}, {0x95, 0x2022}, {0x96, 0x2013}, + {0x97, 0x2014}, {0x98, 0x02DC}, {0x99, 0x2122}, {0x9A, 0x0161}, + {0x9B, 0x203A}, {0x9C, 0x0153}, {0x9D, 0x009D}, {0x9E, 0x017E}, + {0x9F, 0x0178}, + // Terminator. + {-1, -1}}; + +static int parse_digit(int c, bool allow_hex) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (allow_hex && c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (allow_hex && c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +static void add_no_digit_error( + struct GumboInternalParser* parser, Utf8Iterator* input) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS; +} + +static void add_codepoint_error(struct GumboInternalParser* parser, + Utf8Iterator* input, GumboErrorType type, int codepoint) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = type; + error->v.codepoint = codepoint; +} + +static void add_named_reference_error(struct GumboInternalParser* parser, + Utf8Iterator* input, GumboErrorType type, GumboStringPiece text) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = type; + error->v.text = text; +} + +static int maybe_replace_codepoint(int codepoint) { + for (int i = 0; kCharReplacements[i].from_char != -1; ++i) { + if (kCharReplacements[i].from_char == codepoint) { + return kCharReplacements[i].to_char; + } + } + return -1; +} + +static bool consume_numeric_ref( + struct GumboInternalParser* parser, Utf8Iterator* input, int* output) { + utf8iterator_next(input); + bool is_hex = false; + int c = utf8iterator_current(input); + if (c == 'x' || c == 'X') { + is_hex = true; + utf8iterator_next(input); + c = utf8iterator_current(input); + } + + int digit = parse_digit(c, is_hex); + if (digit == -1) { + // First digit was invalid; add a parse error and return. + add_no_digit_error(parser, input); + utf8iterator_reset(input); + *output = kGumboNoChar; + return false; + } + + int codepoint = 0; + bool status = true; + do { + codepoint = (codepoint * (is_hex ? 16 : 10)) + digit; + utf8iterator_next(input); + digit = parse_digit(utf8iterator_current(input), is_hex); + } while (digit != -1); + + if (utf8iterator_current(input) != ';') { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON, codepoint); + status = false; + } else { + utf8iterator_next(input); + } + + int replacement = maybe_replace_codepoint(codepoint); + if (replacement != -1) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + *output = replacement; + return false; + } + + if ((codepoint >= 0xd800 && codepoint <= 0xdfff) || codepoint > 0x10ffff) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + *output = 0xfffd; + return false; + } + + if (utf8_is_invalid_code_point(codepoint) || codepoint == 0xb) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + status = false; + // But return it anyway, per spec. + } + *output = codepoint; + return status; +} + +static bool maybe_add_invalid_named_reference( + struct GumboInternalParser* parser, Utf8Iterator* input) { + // The iterator will always be reset in this code path, so we don't need to + // worry about consuming characters. + const char* start = utf8iterator_get_char_pointer(input); + int c = utf8iterator_current(input); + while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) { + utf8iterator_next(input); + c = utf8iterator_current(input); + } + if (c == ';') { + GumboStringPiece bad_ref; + bad_ref.data = start; + bad_ref.length = utf8iterator_get_char_pointer(input) - start; + add_named_reference_error( + parser, input, GUMBO_ERR_NAMED_CHAR_REF_INVALID, bad_ref); + return false; + } + return true; +} + +#line 2465 "char_ref.rl" + +// clang-format off + +#line 238 "char_ref.c" +static const short _char_ref_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 1, 5, 1, 6, 1, + 7, 1, 8, 1, 9, 1, 10, 1, + 11, 1, 12, 1, 13, 1, 14, 1, + 15, 1, 16, 1, 17, 1, 18, 1, + 19, 1, 20, 1, 21, 1, 22, 1, + 23, 1, 24, 1, 25, 1, 26, 1, + 27, 1, 28, 1, 29, 1, 30, 1, + 31, 1, 32, 1, 33, 1, 34, 1, + 35, 1, 36, 1, 37, 1, 38, 1, + 39, 1, 40, 1, 41, 1, 42, 1, + 43, 1, 44, 1, 45, 1, 46, 1, + 47, 1, 48, 1, 49, 1, 50, 1, + 51, 1, 52, 1, 53, 1, 54, 1, + 55, 1, 56, 1, 57, 1, 58, 1, + 59, 1, 60, 1, 61, 1, 62, 1, + 63, 1, 64, 1, 65, 1, 66, 1, + 67, 1, 68, 1, 69, 1, 70, 1, + 71, 1, 72, 1, 73, 1, 74, 1, + 75, 1, 76, 1, 77, 1, 78, 1, + 79, 1, 80, 1, 81, 1, 82, 1, + 83, 1, 84, 1, 85, 1, 86, 1, + 87, 1, 88, 1, 89, 1, 90, 1, + 91, 1, 92, 1, 93, 1, 94, 1, + 95, 1, 96, 1, 97, 1, 98, 1, + 99, 1, 100, 1, 101, 1, 102, 1, + 103, 1, 104, 1, 105, 1, 106, 1, + 107, 1, 108, 1, 109, 1, 110, 1, + 111, 1, 112, 1, 113, 1, 114, 1, + 115, 1, 116, 1, 117, 1, 118, 1, + 119, 1, 120, 1, 121, 1, 122, 1, + 123, 1, 124, 1, 125, 1, 126, 1, + 127, 1, 128, 1, 129, 1, 130, 1, + 131, 1, 132, 1, 133, 1, 134, 1, + 135, 1, 136, 1, 137, 1, 138, 1, + 139, 1, 140, 1, 141, 1, 142, 1, + 143, 1, 144, 1, 145, 1, 146, 1, + 147, 1, 148, 1, 149, 1, 150, 1, + 151, 1, 152, 1, 153, 1, 154, 1, + 155, 1, 156, 1, 157, 1, 158, 1, + 159, 1, 160, 1, 161, 1, 162, 1, + 163, 1, 164, 1, 165, 1, 166, 1, + 167, 1, 168, 1, 169, 1, 170, 1, + 171, 1, 172, 1, 173, 1, 174, 1, + 175, 1, 176, 1, 177, 1, 178, 1, + 179, 1, 180, 1, 181, 1, 182, 1, + 183, 1, 184, 1, 185, 1, 186, 1, + 187, 1, 188, 1, 189, 1, 190, 1, + 191, 1, 192, 1, 193, 1, 194, 1, + 195, 1, 196, 1, 197, 1, 198, 1, + 199, 1, 200, 1, 201, 1, 202, 1, + 203, 1, 204, 1, 205, 1, 206, 1, + 207, 1, 208, 1, 209, 1, 210, 1, + 211, 1, 212, 1, 213, 1, 214, 1, + 215, 1, 216, 1, 217, 1, 218, 1, + 219, 1, 220, 1, 221, 1, 222, 1, + 223, 1, 224, 1, 225, 1, 226, 1, + 227, 1, 228, 1, 229, 1, 230, 1, + 231, 1, 232, 1, 233, 1, 234, 1, + 235, 1, 236, 1, 237, 1, 238, 1, + 239, 1, 240, 1, 241, 1, 242, 1, + 243, 1, 244, 1, 245, 1, 246, 1, + 247, 1, 248, 1, 249, 1, 250, 1, + 251, 1, 252, 1, 253, 1, 254, 1, + 255, 1, 256, 1, 257, 1, 258, 1, + 259, 1, 260, 1, 261, 1, 262, 1, + 263, 1, 264, 1, 265, 1, 266, 1, + 267, 1, 268, 1, 269, 1, 270, 1, + 271, 1, 272, 1, 273, 1, 274, 1, + 275, 1, 276, 1, 277, 1, 278, 1, + 279, 1, 280, 1, 281, 1, 282, 1, + 283, 1, 284, 1, 285, 1, 286, 1, + 287, 1, 288, 1, 289, 1, 290, 1, + 291, 1, 292, 1, 293, 1, 294, 1, + 295, 1, 296, 1, 297, 1, 298, 1, + 299, 1, 300, 1, 301, 1, 302, 1, + 303, 1, 304, 1, 305, 1, 306, 1, + 307, 1, 308, 1, 309, 1, 310, 1, + 311, 1, 312, 1, 313, 1, 314, 1, + 315, 1, 316, 1, 317, 1, 318, 1, + 319, 1, 320, 1, 321, 1, 322, 1, + 323, 1, 324, 1, 325, 1, 326, 1, + 327, 1, 328, 1, 329, 1, 330, 1, + 331, 1, 332, 1, 333, 1, 334, 1, + 335, 1, 336, 1, 337, 1, 338, 1, + 339, 1, 340, 1, 341, 1, 342, 1, + 343, 1, 344, 1, 345, 1, 346, 1, + 347, 1, 348, 1, 349, 1, 350, 1, + 351, 1, 352, 1, 353, 1, 354, 1, + 355, 1, 356, 1, 357, 1, 358, 1, + 359, 1, 360, 1, 361, 1, 362, 1, + 363, 1, 364, 1, 365, 1, 366, 1, + 367, 1, 368, 1, 369, 1, 370, 1, + 371, 1, 372, 1, 373, 1, 374, 1, + 375, 1, 376, 1, 377, 1, 378, 1, + 379, 1, 380, 1, 381, 1, 382, 1, + 383, 1, 384, 1, 385, 1, 386, 1, + 387, 1, 388, 1, 389, 1, 390, 1, + 391, 1, 392, 1, 393, 1, 394, 1, + 395, 1, 396, 1, 397, 1, 398, 1, + 399, 1, 400, 1, 401, 1, 402, 1, + 403, 1, 404, 1, 405, 1, 406, 1, + 407, 1, 408, 1, 409, 1, 410, 1, + 411, 1, 412, 1, 413, 1, 414, 1, + 415, 1, 416, 1, 417, 1, 418, 1, + 419, 1, 420, 1, 421, 1, 422, 1, + 423, 1, 424, 1, 425, 1, 426, 1, + 427, 1, 428, 1, 429, 1, 430, 1, + 431, 1, 432, 1, 433, 1, 434, 1, + 435, 1, 436, 1, 437, 1, 438, 1, + 439, 1, 440, 1, 441, 1, 442, 1, + 443, 1, 444, 1, 445, 1, 446, 1, + 447, 1, 448, 1, 449, 1, 450, 1, + 451, 1, 452, 1, 453, 1, 454, 1, + 455, 1, 456, 1, 457, 1, 458, 1, + 459, 1, 460, 1, 461, 1, 462, 1, + 463, 1, 464, 1, 465, 1, 466, 1, + 467, 1, 468, 1, 469, 1, 470, 1, + 471, 1, 472, 1, 473, 1, 474, 1, + 475, 1, 476, 1, 477, 1, 478, 1, + 479, 1, 480, 1, 481, 1, 482, 1, + 483, 1, 484, 1, 485, 1, 486, 1, + 487, 1, 488, 1, 489, 1, 490, 1, + 491, 1, 492, 1, 493, 1, 494, 1, + 495, 1, 496, 1, 497, 1, 498, 1, + 499, 1, 500, 1, 501, 1, 502, 1, + 503, 1, 504, 1, 505, 1, 506, 1, + 507, 1, 508, 1, 509, 1, 510, 1, + 511, 1, 512, 1, 513, 1, 514, 1, + 515, 1, 516, 1, 517, 1, 518, 1, + 519, 1, 520, 1, 521, 1, 522, 1, + 523, 1, 524, 1, 525, 1, 526, 1, + 527, 1, 528, 1, 529, 1, 530, 1, + 531, 1, 532, 1, 533, 1, 534, 1, + 535, 1, 536, 1, 537, 1, 538, 1, + 539, 1, 540, 1, 541, 1, 542, 1, + 543, 1, 544, 1, 545, 1, 546, 1, + 547, 1, 548, 1, 549, 1, 550, 1, + 551, 1, 552, 1, 553, 1, 554, 1, + 555, 1, 556, 1, 557, 1, 558, 1, + 559, 1, 560, 1, 561, 1, 562, 1, + 563, 1, 564, 1, 565, 1, 566, 1, + 567, 1, 568, 1, 569, 1, 570, 1, + 571, 1, 572, 1, 573, 1, 574, 1, + 575, 1, 576, 1, 577, 1, 578, 1, + 579, 1, 580, 1, 581, 1, 582, 1, + 583, 1, 584, 1, 585, 1, 586, 1, + 587, 1, 588, 1, 589, 1, 590, 1, + 591, 1, 592, 1, 593, 1, 594, 1, + 595, 1, 596, 1, 597, 1, 598, 1, + 599, 1, 600, 1, 601, 1, 602, 1, + 603, 1, 604, 1, 605, 1, 606, 1, + 607, 1, 608, 1, 609, 1, 610, 1, + 611, 1, 612, 1, 613, 1, 614, 1, + 615, 1, 616, 1, 617, 1, 618, 1, + 619, 1, 620, 1, 621, 1, 622, 1, + 623, 1, 624, 1, 625, 1, 626, 1, + 627, 1, 628, 1, 629, 1, 630, 1, + 631, 1, 632, 1, 633, 1, 634, 1, + 635, 1, 636, 1, 637, 1, 638, 1, + 639, 1, 640, 1, 641, 1, 642, 1, + 643, 1, 644, 1, 645, 1, 646, 1, + 647, 1, 648, 1, 649, 1, 650, 1, + 651, 1, 652, 1, 653, 1, 654, 1, + 655, 1, 656, 1, 657, 1, 658, 1, + 659, 1, 660, 1, 661, 1, 662, 1, + 663, 1, 664, 1, 665, 1, 666, 1, + 667, 1, 668, 1, 669, 1, 670, 1, + 671, 1, 672, 1, 673, 1, 674, 1, + 675, 1, 676, 1, 677, 1, 678, 1, + 679, 1, 680, 1, 681, 1, 682, 1, + 683, 1, 684, 1, 685, 1, 686, 1, + 687, 1, 688, 1, 689, 1, 690, 1, + 691, 1, 692, 1, 693, 1, 694, 1, + 695, 1, 696, 1, 697, 1, 698, 1, + 699, 1, 700, 1, 701, 1, 702, 1, + 703, 1, 704, 1, 705, 1, 706, 1, + 707, 1, 708, 1, 709, 1, 710, 1, + 711, 1, 712, 1, 713, 1, 714, 1, + 715, 1, 716, 1, 717, 1, 718, 1, + 719, 1, 720, 1, 721, 1, 722, 1, + 723, 1, 724, 1, 725, 1, 726, 1, + 727, 1, 728, 1, 729, 1, 730, 1, + 731, 1, 732, 1, 733, 1, 734, 1, + 735, 1, 736, 1, 737, 1, 738, 1, + 739, 1, 740, 1, 741, 1, 742, 1, + 743, 1, 744, 1, 745, 1, 746, 1, + 747, 1, 748, 1, 749, 1, 750, 1, + 751, 1, 752, 1, 753, 1, 754, 1, + 755, 1, 756, 1, 757, 1, 758, 1, + 759, 1, 760, 1, 761, 1, 762, 1, + 763, 1, 764, 1, 765, 1, 766, 1, + 767, 1, 768, 1, 769, 1, 770, 1, + 771, 1, 772, 1, 773, 1, 774, 1, + 775, 1, 776, 1, 777, 1, 778, 1, + 779, 1, 780, 1, 781, 1, 782, 1, + 783, 1, 784, 1, 785, 1, 786, 1, + 787, 1, 788, 1, 789, 1, 790, 1, + 791, 1, 792, 1, 793, 1, 794, 1, + 795, 1, 796, 1, 797, 1, 798, 1, + 799, 1, 800, 1, 801, 1, 802, 1, + 803, 1, 804, 1, 805, 1, 806, 1, + 807, 1, 808, 1, 809, 1, 810, 1, + 811, 1, 812, 1, 813, 1, 814, 1, + 815, 1, 816, 1, 817, 1, 818, 1, + 819, 1, 820, 1, 821, 1, 822, 1, + 823, 1, 824, 1, 825, 1, 826, 1, + 827, 1, 828, 1, 829, 1, 830, 1, + 831, 1, 832, 1, 833, 1, 834, 1, + 835, 1, 836, 1, 837, 1, 838, 1, + 839, 1, 840, 1, 841, 1, 842, 1, + 843, 1, 844, 1, 845, 1, 846, 1, + 847, 1, 848, 1, 849, 1, 850, 1, + 851, 1, 852, 1, 853, 1, 854, 1, + 855, 1, 856, 1, 857, 1, 858, 1, + 859, 1, 860, 1, 861, 1, 862, 1, + 863, 1, 864, 1, 865, 1, 866, 1, + 867, 1, 868, 1, 869, 1, 870, 1, + 871, 1, 872, 1, 873, 1, 874, 1, + 875, 1, 876, 1, 877, 1, 878, 1, + 879, 1, 880, 1, 881, 1, 882, 1, + 883, 1, 884, 1, 885, 1, 886, 1, + 887, 1, 888, 1, 889, 1, 890, 1, + 891, 1, 892, 1, 893, 1, 894, 1, + 895, 1, 896, 1, 897, 1, 898, 1, + 899, 1, 900, 1, 901, 1, 902, 1, + 903, 1, 904, 1, 905, 1, 906, 1, + 907, 1, 908, 1, 909, 1, 910, 1, + 911, 1, 912, 1, 913, 1, 914, 1, + 915, 1, 916, 1, 917, 1, 918, 1, + 919, 1, 920, 1, 921, 1, 922, 1, + 923, 1, 924, 1, 925, 1, 926, 1, + 927, 1, 928, 1, 929, 1, 930, 1, + 931, 1, 932, 1, 933, 1, 934, 1, + 935, 1, 936, 1, 937, 1, 938, 1, + 939, 1, 940, 1, 941, 1, 942, 1, + 943, 1, 944, 1, 945, 1, 946, 1, + 947, 1, 948, 1, 949, 1, 950, 1, + 951, 1, 952, 1, 953, 1, 954, 1, + 955, 1, 956, 1, 957, 1, 958, 1, + 959, 1, 960, 1, 961, 1, 962, 1, + 963, 1, 964, 1, 965, 1, 966, 1, + 967, 1, 968, 1, 969, 1, 970, 1, + 971, 1, 972, 1, 973, 1, 974, 1, + 975, 1, 976, 1, 977, 1, 978, 1, + 979, 1, 980, 1, 981, 1, 982, 1, + 983, 1, 984, 1, 985, 1, 986, 1, + 987, 1, 988, 1, 989, 1, 990, 1, + 991, 1, 992, 1, 993, 1, 994, 1, + 995, 1, 996, 1, 997, 1, 998, 1, + 999, 1, 1000, 1, 1001, 1, 1002, 1, + 1003, 1, 1004, 1, 1005, 1, 1006, 1, + 1007, 1, 1008, 1, 1009, 1, 1010, 1, + 1011, 1, 1012, 1, 1013, 1, 1014, 1, + 1015, 1, 1016, 1, 1017, 1, 1018, 1, + 1019, 1, 1020, 1, 1021, 1, 1022, 1, + 1023, 1, 1024, 1, 1025, 1, 1026, 1, + 1027, 1, 1028, 1, 1029, 1, 1030, 1, + 1031, 1, 1032, 1, 1033, 1, 1034, 1, + 1035, 1, 1036, 1, 1037, 1, 1038, 1, + 1039, 1, 1040, 1, 1041, 1, 1042, 1, + 1043, 1, 1044, 1, 1045, 1, 1046, 1, + 1047, 1, 1048, 1, 1049, 1, 1050, 1, + 1051, 1, 1052, 1, 1053, 1, 1054, 1, + 1055, 1, 1056, 1, 1057, 1, 1058, 1, + 1059, 1, 1060, 1, 1061, 1, 1062, 1, + 1063, 1, 1064, 1, 1065, 1, 1066, 1, + 1067, 1, 1068, 1, 1069, 1, 1070, 1, + 1071, 1, 1072, 1, 1073, 1, 1074, 1, + 1075, 1, 1076, 1, 1077, 1, 1078, 1, + 1079, 1, 1080, 1, 1081, 1, 1082, 1, + 1083, 1, 1084, 1, 1085, 1, 1086, 1, + 1087, 1, 1088, 1, 1089, 1, 1090, 1, + 1091, 1, 1092, 1, 1093, 1, 1094, 1, + 1095, 1, 1096, 1, 1097, 1, 1098, 1, + 1099, 1, 1100, 1, 1101, 1, 1102, 1, + 1103, 1, 1104, 1, 1105, 1, 1106, 1, + 1107, 1, 1108, 1, 1109, 1, 1110, 1, + 1111, 1, 1112, 1, 1113, 1, 1114, 1, + 1115, 1, 1116, 1, 1117, 1, 1118, 1, + 1119, 1, 1120, 1, 1121, 1, 1122, 1, + 1123, 1, 1124, 1, 1125, 1, 1126, 1, + 1127, 1, 1128, 1, 1129, 1, 1130, 1, + 1131, 1, 1132, 1, 1133, 1, 1134, 1, + 1135, 1, 1136, 1, 1137, 1, 1138, 1, + 1139, 1, 1140, 1, 1141, 1, 1142, 1, + 1143, 1, 1144, 1, 1145, 1, 1146, 1, + 1147, 1, 1148, 1, 1149, 1, 1150, 1, + 1151, 1, 1152, 1, 1153, 1, 1154, 1, + 1155, 1, 1156, 1, 1157, 1, 1158, 1, + 1159, 1, 1160, 1, 1161, 1, 1162, 1, + 1163, 1, 1164, 1, 1165, 1, 1166, 1, + 1167, 1, 1168, 1, 1169, 1, 1170, 1, + 1171, 1, 1172, 1, 1173, 1, 1174, 1, + 1175, 1, 1176, 1, 1177, 1, 1178, 1, + 1179, 1, 1180, 1, 1181, 1, 1182, 1, + 1183, 1, 1184, 1, 1185, 1, 1186, 1, + 1187, 1, 1188, 1, 1189, 1, 1190, 1, + 1191, 1, 1192, 1, 1193, 1, 1194, 1, + 1195, 1, 1196, 1, 1197, 1, 1198, 1, + 1199, 1, 1200, 1, 1201, 1, 1202, 1, + 1203, 1, 1204, 1, 1205, 1, 1206, 1, + 1207, 1, 1208, 1, 1209, 1, 1210, 1, + 1211, 1, 1212, 1, 1213, 1, 1214, 1, + 1215, 1, 1216, 1, 1217, 1, 1218, 1, + 1219, 1, 1220, 1, 1221, 1, 1222, 1, + 1223, 1, 1224, 1, 1225, 1, 1226, 1, + 1227, 1, 1228, 1, 1229, 1, 1230, 1, + 1231, 1, 1232, 1, 1233, 1, 1234, 1, + 1235, 1, 1236, 1, 1237, 1, 1238, 1, + 1239, 1, 1240, 1, 1241, 1, 1242, 1, + 1243, 1, 1244, 1, 1245, 1, 1246, 1, + 1247, 1, 1248, 1, 1249, 1, 1250, 1, + 1251, 1, 1252, 1, 1253, 1, 1254, 1, + 1255, 1, 1256, 1, 1257, 1, 1258, 1, + 1259, 1, 1260, 1, 1261, 1, 1262, 1, + 1263, 1, 1264, 1, 1265, 1, 1266, 1, + 1267, 1, 1268, 1, 1269, 1, 1270, 1, + 1271, 1, 1272, 1, 1273, 1, 1274, 1, + 1275, 1, 1276, 1, 1277, 1, 1278, 1, + 1279, 1, 1280, 1, 1281, 1, 1282, 1, + 1283, 1, 1284, 1, 1285, 1, 1286, 1, + 1287, 1, 1288, 1, 1289, 1, 1290, 1, + 1291, 1, 1292, 1, 1293, 1, 1294, 1, + 1295, 1, 1296, 1, 1297, 1, 1298, 1, + 1299, 1, 1300, 1, 1301, 1, 1302, 1, + 1303, 1, 1304, 1, 1305, 1, 1306, 1, + 1307, 1, 1308, 1, 1309, 1, 1310, 1, + 1311, 1, 1312, 1, 1313, 1, 1314, 1, + 1315, 1, 1316, 1, 1317, 1, 1318, 1, + 1319, 1, 1320, 1, 1321, 1, 1322, 1, + 1323, 1, 1324, 1, 1325, 1, 1326, 1, + 1327, 1, 1328, 1, 1329, 1, 1330, 1, + 1331, 1, 1332, 1, 1333, 1, 1334, 1, + 1335, 1, 1336, 1, 1337, 1, 1338, 1, + 1339, 1, 1340, 1, 1341, 1, 1342, 1, + 1343, 1, 1344, 1, 1345, 1, 1346, 1, + 1347, 1, 1348, 1, 1349, 1, 1350, 1, + 1351, 1, 1352, 1, 1353, 1, 1354, 1, + 1355, 1, 1356, 1, 1357, 1, 1358, 1, + 1359, 1, 1360, 1, 1361, 1, 1362, 1, + 1363, 1, 1364, 1, 1365, 1, 1366, 1, + 1367, 1, 1368, 1, 1369, 1, 1370, 1, + 1371, 1, 1372, 1, 1373, 1, 1374, 1, + 1375, 1, 1376, 1, 1377, 1, 1378, 1, + 1379, 1, 1380, 1, 1381, 1, 1382, 1, + 1383, 1, 1384, 1, 1385, 1, 1386, 1, + 1387, 1, 1388, 1, 1389, 1, 1390, 1, + 1391, 1, 1392, 1, 1393, 1, 1394, 1, + 1395, 1, 1396, 1, 1397, 1, 1398, 1, + 1399, 1, 1400, 1, 1401, 1, 1402, 1, + 1403, 1, 1404, 1, 1405, 1, 1406, 1, + 1407, 1, 1408, 1, 1409, 1, 1410, 1, + 1411, 1, 1412, 1, 1413, 1, 1414, 1, + 1415, 1, 1416, 1, 1417, 1, 1418, 1, + 1419, 1, 1420, 1, 1421, 1, 1422, 1, + 1423, 1, 1424, 1, 1425, 1, 1426, 1, + 1427, 1, 1428, 1, 1429, 1, 1430, 1, + 1431, 1, 1432, 1, 1433, 1, 1434, 1, + 1435, 1, 1436, 1, 1437, 1, 1438, 1, + 1439, 1, 1440, 1, 1441, 1, 1442, 1, + 1443, 1, 1444, 1, 1445, 1, 1446, 1, + 1447, 1, 1448, 1, 1449, 1, 1450, 1, + 1451, 1, 1452, 1, 1453, 1, 1454, 1, + 1455, 1, 1456, 1, 1457, 1, 1458, 1, + 1459, 1, 1460, 1, 1461, 1, 1462, 1, + 1463, 1, 1464, 1, 1465, 1, 1466, 1, + 1467, 1, 1468, 1, 1469, 1, 1470, 1, + 1471, 1, 1472, 1, 1473, 1, 1474, 1, + 1475, 1, 1476, 1, 1477, 1, 1478, 1, + 1479, 1, 1480, 1, 1481, 1, 1482, 1, + 1483, 1, 1484, 1, 1485, 1, 1486, 1, + 1487, 1, 1488, 1, 1489, 1, 1490, 1, + 1491, 1, 1492, 1, 1493, 1, 1494, 1, + 1495, 1, 1496, 1, 1497, 1, 1498, 1, + 1499, 1, 1500, 1, 1501, 1, 1502, 1, + 1503, 1, 1504, 1, 1505, 1, 1506, 1, + 1507, 1, 1508, 1, 1509, 1, 1510, 1, + 1511, 1, 1512, 1, 1513, 1, 1514, 1, + 1515, 1, 1516, 1, 1517, 1, 1518, 1, + 1519, 1, 1520, 1, 1521, 1, 1522, 1, + 1523, 1, 1524, 1, 1525, 1, 1526, 1, + 1527, 1, 1528, 1, 1529, 1, 1530, 1, + 1531, 1, 1532, 1, 1533, 1, 1534, 1, + 1535, 1, 1536, 1, 1537, 1, 1538, 1, + 1539, 1, 1540, 1, 1541, 1, 1542, 1, + 1543, 1, 1544, 1, 1545, 1, 1546, 1, + 1547, 1, 1548, 1, 1549, 1, 1550, 1, + 1551, 1, 1552, 1, 1553, 1, 1554, 1, + 1555, 1, 1556, 1, 1557, 1, 1558, 1, + 1559, 1, 1560, 1, 1561, 1, 1562, 1, + 1563, 1, 1564, 1, 1565, 1, 1566, 1, + 1567, 1, 1568, 1, 1569, 1, 1570, 1, + 1571, 1, 1572, 1, 1573, 1, 1574, 1, + 1575, 1, 1576, 1, 1577, 1, 1578, 1, + 1579, 1, 1580, 1, 1581, 1, 1582, 1, + 1583, 1, 1584, 1, 1585, 1, 1586, 1, + 1587, 1, 1588, 1, 1589, 1, 1590, 1, + 1591, 1, 1592, 1, 1593, 1, 1594, 1, + 1595, 1, 1596, 1, 1597, 1, 1598, 1, + 1599, 1, 1600, 1, 1601, 1, 1602, 1, + 1603, 1, 1604, 1, 1605, 1, 1606, 1, + 1607, 1, 1608, 1, 1609, 1, 1610, 1, + 1611, 1, 1612, 1, 1613, 1, 1614, 1, + 1615, 1, 1616, 1, 1617, 1, 1618, 1, + 1619, 1, 1620, 1, 1621, 1, 1622, 1, + 1623, 1, 1624, 1, 1625, 1, 1626, 1, + 1627, 1, 1628, 1, 1629, 1, 1630, 1, + 1631, 1, 1632, 1, 1633, 1, 1634, 1, + 1635, 1, 1636, 1, 1637, 1, 1638, 1, + 1639, 1, 1640, 1, 1641, 1, 1642, 1, + 1643, 1, 1644, 1, 1645, 1, 1646, 1, + 1647, 1, 1648, 1, 1649, 1, 1650, 1, + 1651, 1, 1652, 1, 1653, 1, 1654, 1, + 1655, 1, 1656, 1, 1657, 1, 1658, 1, + 1659, 1, 1660, 1, 1661, 1, 1662, 1, + 1663, 1, 1664, 1, 1665, 1, 1666, 1, + 1667, 1, 1668, 1, 1669, 1, 1670, 1, + 1671, 1, 1672, 1, 1673, 1, 1674, 1, + 1675, 1, 1676, 1, 1677, 1, 1678, 1, + 1679, 1, 1680, 1, 1681, 1, 1682, 1, + 1683, 1, 1684, 1, 1685, 1, 1686, 1, + 1687, 1, 1688, 1, 1689, 1, 1690, 1, + 1691, 1, 1692, 1, 1693, 1, 1694, 1, + 1695, 1, 1696, 1, 1697, 1, 1698, 1, + 1699, 1, 1700, 1, 1701, 1, 1702, 1, + 1703, 1, 1704, 1, 1705, 1, 1706, 1, + 1707, 1, 1708, 1, 1709, 1, 1710, 1, + 1711, 1, 1712, 1, 1713, 1, 1714, 1, + 1715, 1, 1716, 1, 1717, 1, 1718, 1, + 1719, 1, 1720, 1, 1721, 1, 1722, 1, + 1723, 1, 1724, 1, 1725, 1, 1726, 1, + 1727, 1, 1728, 1, 1729, 1, 1730, 1, + 1731, 1, 1732, 1, 1733, 1, 1734, 1, + 1735, 1, 1736, 1, 1737, 1, 1738, 1, + 1739, 1, 1740, 1, 1741, 1, 1742, 1, + 1743, 1, 1744, 1, 1745, 1, 1746, 1, + 1747, 1, 1748, 1, 1749, 1, 1750, 1, + 1751, 1, 1752, 1, 1753, 1, 1754, 1, + 1755, 1, 1756, 1, 1757, 1, 1758, 1, + 1759, 1, 1760, 1, 1761, 1, 1762, 1, + 1763, 1, 1764, 1, 1765, 1, 1766, 1, + 1767, 1, 1768, 1, 1769, 1, 1770, 1, + 1771, 1, 1772, 1, 1773, 1, 1774, 1, + 1775, 1, 1776, 1, 1777, 1, 1778, 1, + 1779, 1, 1780, 1, 1781, 1, 1782, 1, + 1783, 1, 1784, 1, 1785, 1, 1786, 1, + 1787, 1, 1788, 1, 1789, 1, 1790, 1, + 1791, 1, 1792, 1, 1793, 1, 1794, 1, + 1795, 1, 1796, 1, 1797, 1, 1798, 1, + 1799, 1, 1800, 1, 1801, 1, 1802, 1, + 1803, 1, 1804, 1, 1805, 1, 1806, 1, + 1807, 1, 1808, 1, 1809, 1, 1810, 1, + 1811, 1, 1812, 1, 1813, 1, 1814, 1, + 1815, 1, 1816, 1, 1817, 1, 1818, 1, + 1819, 1, 1820, 1, 1821, 1, 1822, 1, + 1823, 1, 1824, 1, 1825, 1, 1826, 1, + 1827, 1, 1828, 1, 1829, 1, 1830, 1, + 1831, 1, 1832, 1, 1833, 1, 1834, 1, + 1835, 1, 1836, 1, 1837, 1, 1838, 1, + 1839, 1, 1840, 1, 1841, 1, 1842, 1, + 1843, 1, 1844, 1, 1845, 1, 1846, 1, + 1847, 1, 1848, 1, 1849, 1, 1850, 1, + 1851, 1, 1852, 1, 1853, 1, 1854, 1, + 1855, 1, 1856, 1, 1857, 1, 1858, 1, + 1859, 1, 1860, 1, 1861, 1, 1862, 1, + 1863, 1, 1864, 1, 1865, 1, 1866, 1, + 1867, 1, 1868, 1, 1869, 1, 1870, 1, + 1871, 1, 1872, 1, 1873, 1, 1874, 1, + 1875, 1, 1876, 1, 1877, 1, 1878, 1, + 1879, 1, 1880, 1, 1881, 1, 1882, 1, + 1883, 1, 1884, 1, 1885, 1, 1886, 1, + 1887, 1, 1888, 1, 1889, 1, 1890, 1, + 1891, 1, 1892, 1, 1893, 1, 1894, 1, + 1895, 1, 1896, 1, 1897, 1, 1898, 1, + 1899, 1, 1900, 1, 1901, 1, 1902, 1, + 1903, 1, 1904, 1, 1905, 1, 1906, 1, + 1907, 1, 1908, 1, 1909, 1, 1910, 1, + 1911, 1, 1912, 1, 1913, 1, 1914, 1, + 1915, 1, 1916, 1, 1917, 1, 1918, 1, + 1919, 1, 1920, 1, 1921, 1, 1922, 1, + 1923, 1, 1924, 1, 1925, 1, 1926, 1, + 1927, 1, 1928, 1, 1929, 1, 1930, 1, + 1931, 1, 1932, 1, 1933, 1, 1934, 1, + 1935, 1, 1936, 1, 1937, 1, 1938, 1, + 1939, 1, 1940, 1, 1941, 1, 1942, 1, + 1943, 1, 1944, 1, 1945, 1, 1946, 1, + 1947, 1, 1948, 1, 1949, 1, 1950, 1, + 1951, 1, 1952, 1, 1953, 1, 1954, 1, + 1955, 1, 1956, 1, 1957, 1, 1958, 1, + 1959, 1, 1960, 1, 1961, 1, 1962, 1, + 1963, 1, 1964, 1, 1965, 1, 1966, 1, + 1967, 1, 1968, 1, 1969, 1, 1970, 1, + 1971, 1, 1972, 1, 1973, 1, 1974, 1, + 1975, 1, 1976, 1, 1977, 1, 1978, 1, + 1979, 1, 1980, 1, 1981, 1, 1982, 1, + 1983, 1, 1984, 1, 1985, 1, 1986, 1, + 1987, 1, 1988, 1, 1989, 1, 1990, 1, + 1991, 1, 1992, 1, 1993, 1, 1994, 1, + 1995, 1, 1996, 1, 1997, 1, 1998, 1, + 1999, 1, 2000, 1, 2001, 1, 2002, 1, + 2003, 1, 2004, 1, 2005, 1, 2006, 1, + 2007, 1, 2008, 1, 2009, 1, 2010, 1, + 2011, 1, 2012, 1, 2013, 1, 2014, 1, + 2015, 1, 2016, 1, 2017, 1, 2018, 1, + 2019, 1, 2020, 1, 2021, 1, 2022, 1, + 2023, 1, 2024, 1, 2025, 1, 2026, 1, + 2027, 1, 2028, 1, 2029, 1, 2030, 1, + 2031, 1, 2032, 1, 2033, 1, 2034, 1, + 2035, 1, 2036, 1, 2037, 1, 2038, 1, + 2039, 1, 2040, 1, 2041, 1, 2042, 1, + 2043, 1, 2044, 1, 2045, 1, 2046, 1, + 2047, 1, 2048, 1, 2049, 1, 2050, 1, + 2051, 1, 2052, 1, 2053, 1, 2054, 1, + 2055, 1, 2056, 1, 2057, 1, 2058, 1, + 2059, 1, 2060, 1, 2061, 1, 2062, 1, + 2063, 1, 2064, 1, 2065, 1, 2066, 1, + 2067, 1, 2068, 1, 2069, 1, 2070, 1, + 2071, 1, 2072, 1, 2073, 1, 2074, 1, + 2075, 1, 2076, 1, 2077, 1, 2078, 1, + 2079, 1, 2080, 1, 2081, 1, 2082, 1, + 2083, 1, 2084, 1, 2085, 1, 2086, 1, + 2087, 1, 2088, 1, 2089, 1, 2090, 1, + 2091, 1, 2092, 1, 2093, 1, 2094, 1, + 2095, 1, 2096, 1, 2097, 1, 2098, 1, + 2099, 1, 2100, 1, 2101, 1, 2102, 1, + 2103, 1, 2104, 1, 2105, 1, 2106, 1, + 2107, 1, 2108, 1, 2109, 1, 2110, 1, + 2111, 1, 2112, 1, 2113, 1, 2114, 1, + 2115, 1, 2116, 1, 2117, 1, 2118, 1, + 2119, 1, 2120, 1, 2121, 1, 2122, 1, + 2123, 1, 2124, 1, 2125, 1, 2126, 1, + 2127, 1, 2128, 1, 2129, 1, 2130, 1, + 2131, 1, 2132, 1, 2133, 1, 2134, 1, + 2135, 1, 2136, 1, 2137, 1, 2138, 1, + 2139, 1, 2140, 1, 2141, 1, 2142, 1, + 2143, 1, 2144, 1, 2145, 1, 2146, 1, + 2147, 1, 2148, 1, 2149, 1, 2150, 1, + 2151, 1, 2152, 1, 2153, 1, 2154, 1, + 2155, 1, 2156, 1, 2157, 1, 2158, 1, + 2159, 1, 2160, 1, 2161, 1, 2162, 1, + 2163, 1, 2164, 1, 2165, 1, 2166, 1, + 2167, 1, 2168, 1, 2169, 1, 2170, 1, + 2171, 1, 2172, 1, 2173, 1, 2174, 1, + 2175, 1, 2176, 1, 2177, 1, 2178, 1, + 2179, 1, 2180, 1, 2181, 1, 2182, 1, + 2183, 1, 2184, 1, 2185, 1, 2186, 1, + 2187, 1, 2188, 1, 2189, 1, 2190, 1, + 2191, 1, 2192, 1, 2193, 1, 2194, 1, + 2195, 1, 2196, 1, 2197, 1, 2198, 1, + 2199, 1, 2200, 1, 2201, 1, 2202, 1, + 2203, 1, 2204, 1, 2205, 1, 2206, 1, + 2207, 1, 2208, 1, 2209, 1, 2210, 1, + 2211, 1, 2212, 1, 2213, 1, 2214, 1, + 2215, 1, 2216, 1, 2217, 1, 2218, 1, + 2219, 1, 2220, 1, 2221, 1, 2222, 1, + 2223, 1, 2224, 1, 2225, 1, 2226, 1, + 2227, 1, 2228, 1, 2229, 1, 2230, 1, + 2231, 1, 2232, 1, 2233, 1, 2234, 1, + 2235, 1, 2236, 1, 2237, 1, 2238, 1, + 2239, 1, 2240, 1, 2241 +}; + +static const char _char_ref_trans_keys[] = { + 0, 0, 69, 117, 108, 108, 105, 105, 103, 103, 80, 80, 99, 99, 117, 117, + 116, 116, 101, 101, 114, 114, 101, 101, 118, 118, 101, 101, 59, 59, 105, 121, + 114, 114, 99, 99, 59, 59, 114, 114, 59, 59, 114, 114, 97, 97, 118, 118, + 101, 101, 112, 112, 104, 104, 97, 97, 59, 59, 97, 97, 99, 99, 114, 114, + 59, 59, 100, 100, 59, 59, 103, 112, 111, 111, 110, 110, 59, 59, 102, 102, + 59, 59, 112, 112, 108, 108, 121, 121, 70, 70, 117, 117, 110, 110, 99, 99, + 116, 116, 105, 105, 111, 111, 110, 110, 59, 59, 105, 105, 110, 110, 103, 103, + 99, 115, 114, 114, 59, 59, 105, 105, 103, 103, 110, 110, 59, 59, 105, 105, + 108, 108, 100, 100, 101, 101, 109, 109, 108, 108, 97, 117, 99, 114, 107, 107, + 115, 115, 108, 108, 97, 97, 115, 115, 104, 104, 59, 59, 118, 119, 59, 59, + 101, 101, 100, 100, 59, 59, 121, 121, 59, 59, 99, 116, 97, 97, 117, 117, + 115, 115, 101, 101, 59, 59, 110, 110, 111, 111, 117, 117, 108, 108, 108, 108, + 105, 105, 115, 115, 59, 59, 97, 97, 59, 59, 114, 114, 59, 59, 112, 112, + 102, 102, 59, 59, 101, 101, 118, 118, 101, 101, 59, 59, 99, 99, 114, 114, + 59, 59, 109, 109, 112, 112, 101, 101, 113, 113, 59, 59, 72, 117, 99, 99, + 121, 121, 59, 59, 80, 80, 89, 89, 99, 121, 117, 117, 116, 116, 101, 101, + 59, 59, 59, 105, 116, 116, 97, 97, 108, 108, 68, 68, 105, 105, 102, 102, + 102, 102, 101, 101, 114, 114, 101, 101, 110, 110, 116, 116, 105, 105, 97, 97, + 108, 108, 68, 68, 59, 59, 108, 108, 101, 101, 121, 121, 115, 115, 59, 59, + 97, 111, 114, 114, 111, 111, 110, 110, 59, 59, 100, 100, 105, 105, 108, 108, + 114, 114, 99, 99, 59, 59, 110, 110, 105, 105, 110, 110, 116, 116, 59, 59, + 111, 111, 116, 116, 59, 59, 100, 110, 105, 105, 108, 108, 108, 108, 97, 97, + 59, 59, 116, 116, 101, 101, 114, 114, 68, 68, 111, 111, 116, 116, 59, 59, + 114, 114, 59, 59, 105, 105, 59, 59, 114, 114, 99, 99, 108, 108, 101, 101, + 68, 84, 111, 111, 116, 116, 59, 59, 105, 105, 110, 110, 117, 117, 115, 115, + 59, 59, 108, 108, 117, 117, 115, 115, 59, 59, 105, 105, 109, 109, 101, 101, + 115, 115, 59, 59, 111, 111, 99, 115, 107, 107, 119, 119, 105, 105, 115, 115, + 101, 101, 67, 67, 111, 111, 110, 110, 116, 116, 111, 111, 117, 117, 114, 114, + 73, 73, 110, 110, 116, 116, 101, 101, 103, 103, 114, 114, 97, 97, 108, 108, + 59, 59, 101, 101, 67, 67, 117, 117, 114, 114, 108, 108, 121, 121, 68, 81, + 111, 111, 117, 117, 98, 98, 108, 108, 101, 101, 81, 81, 117, 117, 111, 111, + 116, 116, 101, 101, 59, 59, 117, 117, 111, 111, 116, 116, 101, 101, 59, 59, + 108, 117, 111, 111, 110, 110, 59, 101, 59, 59, 103, 116, 114, 114, 117, 117, + 101, 101, 110, 110, 116, 116, 59, 59, 110, 110, 116, 116, 59, 59, 111, 111, + 117, 117, 114, 114, 73, 73, 110, 110, 116, 116, 101, 101, 103, 103, 114, 114, + 97, 97, 108, 108, 59, 59, 102, 114, 59, 59, 111, 111, 100, 100, 117, 117, + 99, 99, 116, 116, 59, 59, 110, 110, 116, 116, 101, 101, 114, 114, 67, 67, + 108, 108, 111, 111, 99, 99, 107, 107, 119, 119, 105, 105, 115, 115, 101, 101, + 67, 67, 111, 111, 110, 110, 116, 116, 111, 111, 117, 117, 114, 114, 73, 73, + 110, 110, 116, 116, 101, 101, 103, 103, 114, 114, 97, 97, 108, 108, 59, 59, + 111, 111, 115, 115, 115, 115, 59, 59, 99, 99, 114, 114, 59, 59, 112, 112, + 59, 67, 97, 97, 112, 112, 59, 59, 68, 115, 59, 111, 116, 116, 114, 114, + 97, 97, 104, 104, 100, 100, 59, 59, 99, 99, 121, 121, 59, 59, 99, 99, + 121, 121, 59, 59, 99, 99, 121, 121, 59, 59, 103, 115, 103, 103, 101, 101, + 114, 114, 59, 59, 114, 114, 59, 59, 104, 104, 118, 118, 59, 59, 97, 121, + 114, 114, 111, 111, 110, 110, 59, 59, 59, 59, 108, 108, 59, 116, 97, 97, + 59, 59, 114, 114, 59, 59, 97, 102, 99, 109, 114, 114, 105, 105, 116, 116, + 105, 105, 99, 99, 97, 97, 108, 108, 65, 84, 99, 99, 117, 117, 116, 116, + 101, 101, 59, 59, 111, 111, 116, 117, 59, 59, 98, 98, 108, 108, 101, 101, + 65, 65, 99, 99, 117, 117, 116, 116, 101, 101, 59, 59, 114, 114, 97, 97, + 118, 118, 101, 101, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, + 111, 111, 110, 110, 100, 100, 59, 59, 102, 102, 101, 101, 114, 114, 101, 101, + 110, 110, 116, 116, 105, 105, 97, 97, 108, 108, 68, 68, 59, 59, 112, 119, + 102, 102, 59, 59, 59, 69, 111, 111, 116, 116, 59, 59, 113, 113, 117, 117, + 97, 97, 108, 108, 59, 59, 98, 98, 108, 108, 101, 101, 67, 86, 111, 111, + 110, 110, 116, 116, 111, 111, 117, 117, 114, 114, 73, 73, 110, 110, 116, 116, + 101, 101, 103, 103, 114, 114, 97, 97, 108, 108, 59, 59, 111, 111, 116, 119, + 59, 59, 110, 110, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 101, 111, 102, 102, 116, 116, 65, 84, 114, 114, 114, 114, 111, 111, 119, 119, + 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 65, 65, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 101, 101, 101, 101, 59, 59, 110, 110, 103, 103, + 76, 82, 101, 101, 102, 102, 116, 116, 65, 82, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 65, 65, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, + 104, 104, 116, 116, 65, 84, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 101, 101, 101, 101, 59, 59, 112, 112, 65, 68, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 111, 111, 119, 119, 110, 110, 65, 65, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 101, 101, 114, 114, 116, 116, 105, 105, 99, 99, + 97, 97, 108, 108, 66, 66, 97, 97, 114, 114, 59, 59, 110, 110, 65, 97, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 85, 97, 97, 114, 114, 59, 59, + 112, 112, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 114, 114, + 101, 101, 118, 118, 101, 101, 59, 59, 101, 101, 102, 102, 116, 116, 82, 86, + 105, 105, 103, 103, 104, 104, 116, 116, 86, 86, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 59, 101, 101, 101, 101, 86, 86, 101, 101, 99, 99, + 116, 116, 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, + 114, 114, 59, 66, 97, 97, 114, 114, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 84, 86, 101, 101, 101, 101, 86, 86, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, 114, 114, + 59, 66, 97, 97, 114, 114, 59, 59, 101, 101, 101, 101, 59, 65, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 114, 114, 114, 114, 111, 111, 119, 119, + 59, 59, 99, 116, 114, 114, 59, 59, 114, 114, 111, 111, 107, 107, 59, 59, + 78, 120, 71, 71, 59, 59, 72, 72, 99, 99, 117, 117, 116, 116, 101, 101, + 97, 121, 114, 114, 111, 111, 110, 110, 59, 59, 114, 114, 99, 99, 59, 59, + 111, 111, 116, 116, 59, 59, 114, 114, 59, 59, 114, 114, 97, 97, 118, 118, + 101, 101, 101, 101, 109, 109, 101, 101, 110, 110, 116, 116, 59, 59, 97, 112, + 99, 99, 114, 114, 59, 59, 116, 116, 121, 121, 83, 86, 109, 109, 97, 97, + 108, 108, 108, 108, 83, 83, 113, 113, 117, 117, 97, 97, 114, 114, 101, 101, + 59, 59, 101, 101, 114, 114, 121, 121, 83, 83, 109, 109, 97, 97, 108, 108, + 108, 108, 83, 83, 113, 113, 117, 117, 97, 97, 114, 114, 101, 101, 59, 59, + 103, 112, 111, 111, 110, 110, 59, 59, 102, 102, 59, 59, 115, 115, 105, 105, + 108, 108, 111, 111, 110, 110, 59, 59, 117, 117, 97, 105, 108, 108, 59, 84, + 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 108, 108, 105, 105, 98, 98, + 114, 114, 105, 105, 117, 117, 109, 109, 59, 59, 99, 105, 114, 114, 59, 59, + 109, 109, 59, 59, 97, 97, 59, 59, 109, 109, 108, 108, 105, 112, 115, 115, + 116, 116, 115, 115, 59, 59, 111, 111, 110, 110, 101, 101, 110, 110, 116, 116, + 105, 105, 97, 97, 108, 108, 69, 69, 59, 59, 99, 115, 121, 121, 59, 59, + 114, 114, 59, 59, 108, 108, 108, 108, 101, 101, 100, 100, 83, 86, 109, 109, + 97, 97, 108, 108, 108, 108, 83, 83, 113, 113, 117, 117, 97, 97, 114, 114, + 101, 101, 59, 59, 101, 101, 114, 114, 121, 121, 83, 83, 109, 109, 97, 97, + 108, 108, 108, 108, 83, 83, 113, 113, 117, 117, 97, 97, 114, 114, 101, 101, + 59, 59, 112, 117, 102, 102, 59, 59, 65, 65, 108, 108, 108, 108, 59, 59, + 114, 114, 105, 105, 101, 101, 114, 114, 116, 116, 114, 114, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 74, 116, 99, 99, 121, 121, 59, 59, 109, 109, + 109, 109, 97, 97, 59, 100, 59, 59, 114, 114, 101, 101, 118, 118, 101, 101, + 59, 59, 101, 121, 100, 100, 105, 105, 108, 108, 59, 59, 114, 114, 99, 99, + 59, 59, 59, 59, 111, 111, 116, 116, 59, 59, 114, 114, 59, 59, 59, 59, + 112, 112, 102, 102, 59, 59, 101, 101, 97, 97, 116, 116, 101, 101, 114, 114, + 69, 84, 113, 113, 117, 117, 97, 97, 108, 108, 59, 76, 101, 101, 115, 115, + 115, 115, 59, 59, 117, 117, 108, 108, 108, 108, 69, 69, 113, 113, 117, 117, + 97, 97, 108, 108, 59, 59, 114, 114, 101, 101, 97, 97, 116, 116, 101, 101, + 114, 114, 59, 59, 101, 101, 115, 115, 115, 115, 59, 59, 108, 108, 97, 97, + 110, 110, 116, 116, 69, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, + 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 99, 99, 114, 114, 59, 59, + 59, 59, 65, 117, 82, 82, 68, 68, 99, 99, 121, 121, 59, 59, 99, 116, + 101, 101, 107, 107, 59, 59, 59, 59, 105, 105, 114, 114, 99, 99, 59, 59, + 114, 114, 59, 59, 108, 108, 98, 98, 101, 101, 114, 114, 116, 116, 83, 83, + 112, 112, 97, 97, 99, 99, 101, 101, 59, 59, 112, 114, 102, 102, 59, 59, + 105, 105, 122, 122, 111, 111, 110, 110, 116, 116, 97, 97, 108, 108, 76, 76, + 105, 105, 110, 110, 101, 101, 59, 59, 99, 116, 114, 114, 59, 59, 114, 114, + 111, 111, 107, 107, 59, 59, 109, 109, 112, 112, 68, 69, 111, 111, 119, 119, + 110, 110, 72, 72, 117, 117, 109, 109, 112, 112, 59, 59, 113, 113, 117, 117, + 97, 97, 108, 108, 59, 59, 69, 117, 99, 99, 121, 121, 59, 59, 108, 108, + 105, 105, 103, 103, 59, 59, 99, 99, 121, 121, 59, 59, 99, 99, 117, 117, + 116, 116, 101, 101, 105, 121, 114, 114, 99, 99, 59, 59, 111, 111, 116, 116, + 59, 59, 114, 114, 59, 59, 114, 114, 97, 97, 118, 118, 101, 101, 59, 112, + 99, 103, 114, 114, 59, 59, 105, 105, 110, 110, 97, 97, 114, 114, 121, 121, + 73, 73, 59, 59, 108, 108, 105, 105, 101, 101, 115, 115, 59, 59, 116, 118, + 59, 101, 103, 114, 114, 114, 97, 97, 108, 108, 59, 59, 115, 115, 101, 101, + 99, 99, 116, 116, 105, 105, 111, 111, 110, 110, 59, 59, 105, 105, 115, 115, + 105, 105, 98, 98, 108, 108, 101, 101, 67, 84, 111, 111, 109, 109, 109, 109, + 97, 97, 59, 59, 105, 105, 109, 109, 101, 101, 115, 115, 59, 59, 103, 116, + 111, 111, 110, 110, 59, 59, 102, 102, 59, 59, 97, 97, 59, 59, 99, 99, + 114, 114, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 107, 109, + 99, 99, 121, 121, 59, 59, 108, 108, 99, 117, 105, 121, 114, 114, 99, 99, + 59, 59, 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, 99, 101, + 114, 114, 59, 59, 114, 114, 99, 99, 121, 121, 59, 59, 107, 107, 99, 99, + 121, 121, 59, 59, 72, 115, 99, 99, 121, 121, 59, 59, 99, 99, 121, 121, + 59, 59, 112, 112, 112, 112, 97, 97, 59, 59, 101, 121, 100, 100, 105, 105, + 108, 108, 59, 59, 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 74, 116, 99, 99, 121, 121, 59, 59, 99, 114, + 117, 117, 116, 116, 101, 101, 59, 59, 98, 98, 100, 100, 97, 97, 59, 59, + 103, 103, 59, 59, 108, 108, 97, 97, 99, 99, 101, 101, 116, 116, 114, 114, + 102, 102, 59, 59, 114, 114, 59, 59, 97, 121, 114, 114, 111, 111, 110, 110, + 59, 59, 100, 100, 105, 105, 108, 108, 59, 59, 59, 59, 102, 115, 116, 116, + 65, 114, 110, 114, 103, 103, 108, 108, 101, 101, 66, 66, 114, 114, 97, 97, + 99, 99, 107, 107, 101, 101, 116, 116, 59, 59, 114, 114, 111, 111, 119, 119, + 59, 82, 97, 97, 114, 114, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 101, 101, 105, 105, + 108, 108, 105, 105, 110, 110, 103, 103, 59, 59, 111, 111, 117, 119, 98, 98, + 108, 108, 101, 101, 66, 66, 114, 114, 97, 97, 99, 99, 107, 107, 101, 101, + 116, 116, 59, 59, 110, 110, 84, 86, 101, 101, 101, 101, 86, 86, 101, 101, + 99, 99, 116, 116, 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 66, 97, 97, 114, 114, 59, 59, 108, 108, 111, 111, + 111, 111, 114, 114, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 65, 86, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 59, 101, 114, 101, 101, 59, 86, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, 114, 114, + 59, 59, 105, 105, 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, 59, 69, + 97, 97, 114, 114, 59, 59, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, + 112, 112, 68, 86, 111, 111, 119, 119, 110, 110, 86, 86, 101, 101, 99, 99, + 116, 116, 111, 111, 114, 114, 59, 59, 101, 101, 101, 101, 86, 86, 101, 101, + 99, 99, 116, 116, 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 66, 97, 97, 114, 114, 59, 59, 101, 101, 99, 99, + 116, 116, 111, 111, 114, 114, 59, 66, 97, 97, 114, 114, 59, 59, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 115, 115, 69, 84, + 113, 113, 117, 117, 97, 97, 108, 108, 71, 71, 114, 114, 101, 101, 97, 97, + 116, 116, 101, 101, 114, 114, 59, 59, 117, 117, 108, 108, 108, 108, 69, 69, + 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 114, 114, 101, 101, 97, 97, + 116, 116, 101, 101, 114, 114, 59, 59, 101, 101, 115, 115, 115, 115, 59, 59, + 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 114, 114, + 59, 59, 59, 101, 102, 102, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 105, 105, 100, 100, 111, 111, 116, 116, 59, 59, 110, 119, + 103, 103, 76, 114, 101, 101, 102, 102, 116, 116, 65, 82, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 65, 65, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 101, 101, + 102, 102, 116, 116, 97, 114, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 105, 105, 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 102, 102, 59, 59, 101, 101, 114, 114, + 76, 82, 101, 101, 102, 102, 116, 116, 65, 65, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 65, 65, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 99, 116, 114, 114, 59, 59, 59, 59, + 114, 114, 111, 111, 107, 107, 59, 59, 59, 59, 97, 117, 112, 112, 59, 59, + 121, 121, 59, 59, 100, 108, 105, 105, 117, 117, 109, 109, 83, 83, 112, 112, + 97, 97, 99, 99, 101, 101, 59, 59, 108, 108, 105, 105, 110, 110, 116, 116, + 114, 114, 102, 102, 59, 59, 114, 114, 59, 59, 110, 110, 117, 117, 115, 115, + 80, 80, 108, 108, 117, 117, 115, 115, 59, 59, 112, 112, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 59, 59, 74, 117, 99, 99, 121, 121, 59, 59, + 99, 99, 117, 117, 116, 116, 101, 101, 59, 59, 97, 121, 114, 114, 111, 111, + 110, 110, 59, 59, 100, 100, 105, 105, 108, 108, 59, 59, 59, 59, 103, 119, + 97, 97, 116, 116, 105, 105, 118, 118, 101, 101, 77, 86, 101, 101, 100, 100, + 105, 105, 117, 117, 109, 109, 83, 83, 112, 112, 97, 97, 99, 99, 101, 101, + 59, 59, 104, 104, 105, 105, 99, 110, 107, 107, 83, 83, 112, 112, 97, 97, + 99, 99, 101, 101, 59, 59, 83, 83, 112, 112, 97, 97, 99, 99, 101, 101, + 59, 59, 101, 101, 114, 114, 121, 121, 84, 84, 104, 104, 105, 105, 110, 110, + 83, 83, 112, 112, 97, 97, 99, 99, 101, 101, 59, 59, 116, 116, 101, 101, + 100, 100, 71, 76, 114, 114, 101, 101, 97, 97, 116, 116, 101, 101, 114, 114, + 71, 71, 114, 114, 101, 101, 97, 97, 116, 116, 101, 101, 114, 114, 59, 59, + 101, 101, 115, 115, 115, 115, 76, 76, 101, 101, 115, 115, 115, 115, 59, 59, + 76, 76, 105, 105, 110, 110, 101, 101, 59, 59, 114, 114, 59, 59, 66, 116, + 114, 114, 101, 101, 97, 97, 107, 107, 59, 59, 66, 66, 114, 114, 101, 101, + 97, 97, 107, 107, 105, 105, 110, 110, 103, 103, 83, 83, 112, 112, 97, 97, + 99, 99, 101, 101, 59, 59, 102, 102, 59, 59, 59, 86, 111, 117, 110, 110, + 103, 103, 114, 114, 117, 117, 101, 101, 110, 110, 116, 116, 59, 59, 112, 112, + 67, 67, 97, 97, 112, 112, 59, 59, 111, 111, 117, 117, 98, 98, 108, 108, + 101, 101, 86, 86, 101, 101, 114, 114, 116, 116, 105, 105, 99, 99, 97, 97, + 108, 108, 66, 66, 97, 97, 114, 114, 59, 59, 108, 120, 101, 101, 109, 109, + 101, 101, 110, 110, 116, 116, 59, 59, 117, 117, 97, 97, 108, 108, 59, 84, + 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 105, 105, 115, 115, 116, 116, + 115, 115, 59, 59, 114, 114, 101, 101, 97, 97, 116, 116, 101, 101, 114, 114, + 59, 84, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 117, 117, 108, 108, + 108, 108, 69, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 114, 114, + 101, 101, 97, 97, 116, 116, 101, 101, 114, 114, 59, 59, 101, 101, 115, 115, + 115, 115, 59, 59, 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, + 117, 117, 97, 97, 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, + 59, 59, 117, 117, 109, 109, 112, 112, 68, 69, 111, 111, 119, 119, 110, 110, + 72, 72, 117, 117, 109, 109, 112, 112, 59, 59, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 101, 101, 102, 115, 116, 116, 84, 84, 114, 114, 105, 105, + 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, 59, 69, 97, 97, 114, 114, + 59, 59, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 115, 115, 59, 84, + 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 114, 114, 101, 101, 97, 97, + 116, 116, 101, 101, 114, 114, 59, 59, 101, 101, 115, 115, 115, 115, 59, 59, + 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 101, 101, + 115, 115, 116, 116, 101, 101, 100, 100, 71, 76, 114, 114, 101, 101, 97, 97, + 116, 116, 101, 101, 114, 114, 71, 71, 114, 114, 101, 101, 97, 97, 116, 116, + 101, 101, 114, 114, 59, 59, 101, 101, 115, 115, 115, 115, 76, 76, 101, 101, + 115, 115, 115, 115, 59, 59, 114, 114, 101, 101, 99, 99, 101, 101, 100, 100, + 101, 101, 115, 115, 59, 83, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, + 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 101, 105, 118, 118, 101, 101, 114, 114, 115, 115, 101, 101, + 69, 69, 108, 108, 101, 101, 109, 109, 101, 101, 110, 110, 116, 116, 59, 59, + 103, 103, 104, 104, 116, 116, 84, 84, 114, 114, 105, 105, 97, 97, 110, 110, + 103, 103, 108, 108, 101, 101, 59, 69, 97, 97, 114, 114, 59, 59, 113, 113, + 117, 117, 97, 97, 108, 108, 59, 59, 113, 117, 117, 117, 97, 97, 114, 114, + 101, 101, 83, 83, 117, 117, 98, 112, 115, 115, 101, 101, 116, 116, 59, 69, + 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 101, 101, 114, 114, 115, 115, + 101, 101, 116, 116, 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, + 98, 112, 115, 115, 101, 101, 116, 116, 59, 69, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 99, 99, 101, 101, 101, 101, 100, 100, 115, 115, 59, 84, + 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 108, 108, 97, 97, 110, 110, + 116, 116, 69, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 105, 105, + 108, 108, 100, 100, 101, 101, 59, 59, 101, 101, 114, 114, 115, 115, 101, 101, + 116, 116, 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 105, 105, + 108, 108, 100, 100, 101, 101, 59, 84, 113, 113, 117, 117, 97, 97, 108, 108, + 59, 59, 117, 117, 108, 108, 108, 108, 69, 69, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, 101, 101, + 114, 114, 116, 116, 105, 105, 99, 99, 97, 97, 108, 108, 66, 66, 97, 97, + 114, 114, 59, 59, 99, 99, 114, 114, 59, 59, 105, 105, 108, 108, 100, 100, + 101, 101, 59, 59, 69, 118, 108, 108, 105, 105, 103, 103, 59, 59, 99, 99, + 117, 117, 116, 116, 101, 101, 105, 121, 114, 114, 99, 99, 59, 59, 98, 98, + 108, 108, 97, 97, 99, 99, 59, 59, 114, 114, 59, 59, 114, 114, 97, 97, + 118, 118, 101, 101, 97, 105, 99, 99, 114, 114, 59, 59, 103, 103, 97, 97, + 59, 59, 99, 99, 114, 114, 111, 111, 110, 110, 59, 59, 112, 112, 102, 102, + 59, 59, 101, 101, 110, 110, 67, 67, 117, 117, 114, 114, 108, 108, 121, 121, + 68, 81, 111, 111, 117, 117, 98, 98, 108, 108, 101, 101, 81, 81, 117, 117, + 111, 111, 116, 116, 101, 101, 59, 59, 117, 117, 111, 111, 116, 116, 101, 101, + 59, 59, 59, 59, 99, 108, 114, 114, 59, 59, 97, 97, 115, 115, 104, 104, + 105, 105, 108, 109, 100, 100, 101, 101, 101, 101, 115, 115, 59, 59, 109, 109, + 108, 108, 101, 101, 114, 114, 66, 80, 97, 114, 114, 114, 59, 59, 97, 97, + 99, 99, 101, 107, 59, 59, 101, 101, 116, 116, 59, 59, 97, 97, 114, 114, + 101, 101, 110, 110, 116, 116, 104, 104, 101, 101, 115, 115, 105, 105, 115, 115, + 59, 59, 97, 115, 114, 114, 116, 116, 105, 105, 97, 97, 108, 108, 68, 68, + 59, 59, 121, 121, 59, 59, 114, 114, 59, 59, 105, 105, 59, 59, 59, 59, + 117, 117, 115, 115, 77, 77, 105, 105, 110, 110, 117, 117, 115, 115, 59, 59, + 105, 112, 110, 110, 99, 99, 97, 97, 114, 114, 101, 101, 112, 112, 108, 108, + 97, 97, 110, 110, 101, 101, 59, 59, 102, 102, 59, 59, 59, 111, 99, 99, + 101, 101, 100, 100, 101, 101, 115, 115, 59, 84, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, + 117, 117, 97, 97, 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, + 59, 59, 109, 109, 101, 101, 59, 59, 100, 112, 117, 117, 99, 99, 116, 116, + 59, 59, 111, 111, 114, 114, 116, 116, 105, 105, 111, 111, 110, 110, 59, 97, + 108, 108, 59, 59, 99, 105, 114, 114, 59, 59, 59, 59, 85, 115, 79, 79, + 84, 84, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, 99, 99, 114, 114, + 59, 59, 66, 117, 97, 97, 114, 114, 114, 114, 59, 59, 71, 71, 99, 114, + 117, 117, 116, 116, 101, 101, 59, 59, 103, 103, 59, 59, 114, 114, 59, 116, + 108, 108, 59, 59, 97, 121, 114, 114, 111, 111, 110, 110, 59, 59, 100, 100, + 105, 105, 108, 108, 59, 59, 59, 59, 59, 118, 101, 101, 114, 114, 115, 115, + 101, 101, 69, 85, 108, 113, 101, 101, 109, 109, 101, 101, 110, 110, 116, 116, + 59, 59, 117, 117, 105, 105, 108, 108, 105, 105, 98, 98, 114, 114, 105, 105, + 117, 117, 109, 109, 59, 59, 112, 112, 69, 69, 113, 113, 117, 117, 105, 105, + 108, 108, 105, 105, 98, 98, 114, 114, 105, 105, 117, 117, 109, 109, 59, 59, + 114, 114, 59, 59, 111, 111, 59, 59, 103, 103, 104, 104, 116, 116, 65, 97, + 110, 114, 103, 103, 108, 108, 101, 101, 66, 66, 114, 114, 97, 97, 99, 99, + 107, 107, 101, 101, 116, 116, 59, 59, 114, 114, 111, 111, 119, 119, 59, 76, + 97, 97, 114, 114, 59, 59, 101, 101, 102, 102, 116, 116, 65, 65, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 101, 101, 105, 105, 108, 108, 105, 105, + 110, 110, 103, 103, 59, 59, 111, 111, 117, 119, 98, 98, 108, 108, 101, 101, + 66, 66, 114, 114, 97, 97, 99, 99, 107, 107, 101, 101, 116, 116, 59, 59, + 110, 110, 84, 86, 101, 101, 101, 101, 86, 86, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, 114, 114, + 59, 66, 97, 97, 114, 114, 59, 59, 108, 108, 111, 111, 111, 111, 114, 114, + 59, 59, 101, 114, 101, 101, 59, 86, 114, 114, 114, 114, 111, 111, 119, 119, + 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, 114, 114, 59, 59, 105, 105, + 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, 59, 69, 97, 97, 114, 114, + 59, 59, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 112, 112, 68, 86, + 111, 111, 119, 119, 110, 110, 86, 86, 101, 101, 99, 99, 116, 116, 111, 111, + 114, 114, 59, 59, 101, 101, 101, 101, 86, 86, 101, 101, 99, 99, 116, 116, + 111, 111, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, 114, 114, + 59, 66, 97, 97, 114, 114, 59, 59, 101, 101, 99, 99, 116, 116, 111, 111, + 114, 114, 59, 66, 97, 97, 114, 114, 59, 59, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 112, 117, 102, 102, 59, 59, 110, 110, 100, 100, 73, 73, + 109, 109, 112, 112, 108, 108, 105, 105, 101, 101, 115, 115, 59, 59, 105, 105, + 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, + 59, 59, 99, 104, 114, 114, 59, 59, 59, 59, 108, 108, 101, 101, 68, 68, + 101, 101, 108, 108, 97, 97, 121, 121, 101, 101, 100, 100, 59, 59, 72, 117, + 67, 99, 72, 72, 99, 99, 121, 121, 59, 59, 121, 121, 59, 59, 70, 70, + 84, 84, 99, 99, 121, 121, 59, 59, 99, 99, 117, 117, 116, 116, 101, 101, + 59, 59, 59, 121, 114, 114, 111, 111, 110, 110, 59, 59, 100, 100, 105, 105, + 108, 108, 59, 59, 114, 114, 99, 99, 59, 59, 59, 59, 114, 114, 59, 59, + 111, 111, 114, 114, 116, 116, 68, 85, 111, 111, 119, 119, 110, 110, 65, 65, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 101, 101, 102, 102, 116, 116, + 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, + 104, 104, 116, 116, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 112, 112, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 103, 103, + 109, 109, 97, 97, 59, 59, 97, 97, 108, 108, 108, 108, 67, 67, 105, 105, + 114, 114, 99, 99, 108, 108, 101, 101, 59, 59, 112, 112, 102, 102, 59, 59, + 114, 117, 116, 116, 59, 59, 97, 97, 114, 114, 101, 101, 59, 85, 110, 110, + 116, 116, 101, 101, 114, 114, 115, 115, 101, 101, 99, 99, 116, 116, 105, 105, + 111, 111, 110, 110, 59, 59, 117, 117, 98, 112, 115, 115, 101, 101, 116, 116, + 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 101, 101, 114, 114, + 115, 115, 101, 101, 116, 116, 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, + 59, 59, 110, 110, 105, 105, 111, 111, 110, 110, 59, 59, 99, 99, 114, 114, + 59, 59, 97, 97, 114, 114, 59, 59, 98, 112, 59, 115, 101, 101, 116, 116, + 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, 59, 59, 99, 104, 101, 101, + 101, 101, 100, 100, 115, 115, 59, 84, 113, 113, 117, 117, 97, 97, 108, 108, + 59, 59, 108, 108, 97, 97, 110, 110, 116, 116, 69, 69, 113, 113, 117, 117, + 97, 97, 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, + 84, 84, 104, 104, 97, 97, 116, 116, 59, 59, 59, 59, 59, 115, 114, 114, + 115, 115, 101, 101, 116, 116, 59, 69, 113, 113, 117, 117, 97, 97, 108, 108, + 59, 59, 101, 101, 116, 116, 59, 59, 72, 115, 79, 79, 82, 82, 78, 78, + 65, 65, 68, 68, 69, 69, 59, 59, 72, 99, 99, 99, 121, 121, 59, 59, + 121, 121, 59, 59, 98, 117, 59, 59, 59, 59, 97, 121, 114, 114, 111, 111, + 110, 110, 59, 59, 100, 100, 105, 105, 108, 108, 59, 59, 59, 59, 114, 114, + 59, 59, 101, 105, 114, 116, 101, 101, 102, 102, 111, 111, 114, 114, 101, 101, + 59, 59, 97, 97, 59, 59, 99, 110, 107, 107, 83, 83, 112, 112, 97, 97, + 99, 99, 101, 101, 59, 59, 83, 83, 112, 112, 97, 97, 99, 99, 101, 101, + 59, 59, 108, 108, 100, 100, 101, 101, 59, 84, 113, 113, 117, 117, 97, 97, + 108, 108, 59, 59, 117, 117, 108, 108, 108, 108, 69, 69, 113, 113, 117, 117, + 97, 97, 108, 108, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, + 112, 112, 102, 102, 59, 59, 105, 105, 112, 112, 108, 108, 101, 101, 68, 68, + 111, 111, 116, 116, 59, 59, 99, 116, 114, 114, 59, 59, 114, 114, 111, 111, + 107, 107, 59, 59, 97, 117, 99, 114, 117, 117, 116, 116, 101, 101, 114, 114, + 59, 111, 99, 99, 105, 105, 114, 114, 59, 59, 114, 114, 99, 101, 121, 121, + 59, 59, 118, 118, 101, 101, 59, 59, 105, 121, 114, 114, 99, 99, 59, 59, + 98, 98, 108, 108, 97, 97, 99, 99, 59, 59, 114, 114, 59, 59, 114, 114, + 97, 97, 118, 118, 101, 101, 97, 97, 99, 99, 114, 114, 59, 59, 100, 105, + 101, 101, 114, 114, 66, 80, 97, 114, 114, 114, 59, 59, 97, 97, 99, 99, + 101, 107, 59, 59, 101, 101, 116, 116, 59, 59, 97, 97, 114, 114, 101, 101, + 110, 110, 116, 116, 104, 104, 101, 101, 115, 115, 105, 105, 115, 115, 59, 59, + 111, 111, 110, 110, 59, 80, 108, 108, 117, 117, 115, 115, 59, 59, 103, 112, + 111, 111, 110, 110, 59, 59, 102, 102, 59, 59, 65, 115, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 68, 97, 97, 114, 114, 59, 59, 111, 111, 119, 119, + 110, 110, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 111, 111, + 119, 119, 110, 110, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 113, 113, 117, 117, 105, 105, 108, 108, 105, 105, 98, 98, 114, 114, 105, 105, + 117, 117, 109, 109, 59, 59, 101, 101, 101, 101, 59, 65, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 111, 111, 119, 119, 110, 110, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, + 59, 59, 101, 101, 114, 114, 76, 82, 101, 101, 102, 102, 116, 116, 65, 65, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 65, 65, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, + 59, 108, 111, 111, 110, 110, 59, 59, 105, 105, 110, 110, 103, 103, 59, 59, + 99, 99, 114, 114, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 59, 59, + 109, 109, 108, 108, 68, 118, 97, 97, 115, 115, 104, 104, 59, 59, 97, 97, + 114, 114, 59, 59, 121, 121, 59, 59, 97, 97, 115, 115, 104, 104, 59, 108, + 59, 59, 101, 114, 59, 59, 98, 121, 97, 97, 114, 114, 59, 59, 59, 105, + 99, 99, 97, 97, 108, 108, 66, 84, 97, 97, 114, 114, 59, 59, 105, 105, + 110, 110, 101, 101, 59, 59, 101, 101, 112, 112, 97, 97, 114, 114, 97, 97, + 116, 116, 111, 111, 114, 114, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, + 59, 59, 84, 84, 104, 104, 105, 105, 110, 110, 83, 83, 112, 112, 97, 97, + 99, 99, 101, 101, 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 100, 100, 97, 97, 115, 115, 104, 104, 59, 59, + 99, 115, 105, 105, 114, 114, 99, 99, 59, 59, 100, 100, 103, 103, 101, 101, + 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, 99, 99, 114, 114, + 59, 59, 102, 115, 114, 114, 59, 59, 59, 59, 112, 112, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 65, 117, 99, 99, 121, 121, 59, 59, 99, 99, + 121, 121, 59, 59, 99, 99, 121, 121, 59, 59, 99, 99, 117, 117, 116, 116, + 101, 101, 105, 121, 114, 114, 99, 99, 59, 59, 59, 59, 114, 114, 59, 59, + 112, 112, 102, 102, 59, 59, 99, 99, 114, 114, 59, 59, 109, 109, 108, 108, + 59, 59, 72, 115, 99, 99, 121, 121, 59, 59, 99, 99, 117, 117, 116, 116, + 101, 101, 59, 59, 97, 121, 114, 114, 111, 111, 110, 110, 59, 59, 59, 59, + 111, 111, 116, 116, 59, 59, 114, 116, 111, 111, 87, 87, 105, 105, 100, 100, + 116, 116, 104, 104, 83, 83, 112, 112, 97, 97, 99, 99, 101, 101, 59, 59, + 97, 97, 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, 99, 99, + 114, 114, 59, 59, 97, 119, 99, 99, 117, 117, 116, 116, 101, 101, 114, 114, + 101, 101, 118, 118, 101, 101, 59, 59, 59, 121, 59, 59, 59, 59, 114, 114, + 99, 99, 116, 116, 101, 101, 59, 59, 108, 108, 105, 105, 103, 103, 59, 114, + 59, 59, 114, 114, 97, 97, 118, 118, 101, 101, 101, 112, 102, 112, 115, 115, + 121, 121, 109, 109, 59, 59, 104, 104, 59, 59, 104, 104, 97, 97, 59, 59, + 97, 112, 99, 108, 114, 114, 59, 59, 103, 103, 59, 59, 100, 103, 59, 118, + 110, 110, 100, 100, 59, 59, 59, 59, 108, 108, 111, 111, 112, 112, 101, 101, + 59, 59, 59, 59, 59, 122, 59, 59, 101, 101, 59, 59, 115, 115, 100, 100, + 59, 97, 97, 104, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 116, 116, 59, 118, 98, 98, 59, 100, 59, 59, 112, 116, + 104, 104, 59, 59, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, 103, 112, + 111, 111, 110, 110, 59, 59, 102, 102, 59, 59, 59, 112, 59, 59, 99, 99, + 105, 105, 114, 114, 59, 59, 59, 59, 100, 100, 59, 59, 115, 115, 59, 59, + 114, 114, 111, 111, 120, 120, 59, 101, 113, 113, 59, 59, 105, 105, 110, 110, + 103, 103, 99, 121, 114, 114, 59, 59, 59, 59, 109, 109, 112, 112, 59, 101, + 113, 113, 59, 59, 105, 105, 108, 108, 100, 100, 101, 101, 109, 109, 108, 108, + 99, 105, 111, 111, 110, 110, 105, 105, 110, 110, 116, 116, 59, 59, 110, 110, + 116, 116, 59, 59, 78, 117, 111, 111, 116, 116, 59, 59, 99, 114, 107, 107, + 99, 115, 111, 111, 110, 110, 103, 103, 59, 59, 112, 112, 115, 115, 105, 105, + 108, 108, 111, 111, 110, 110, 59, 59, 114, 114, 105, 105, 109, 109, 101, 101, + 59, 59, 105, 105, 109, 109, 59, 101, 113, 113, 59, 59, 118, 119, 101, 101, + 101, 101, 59, 59, 101, 101, 100, 100, 59, 103, 101, 101, 59, 59, 114, 114, + 107, 107, 59, 116, 98, 98, 114, 114, 107, 107, 59, 59, 111, 121, 110, 110, + 103, 103, 59, 59, 59, 59, 113, 113, 117, 117, 111, 111, 59, 59, 99, 116, + 97, 97, 117, 117, 115, 115, 59, 101, 59, 59, 112, 112, 116, 116, 121, 121, + 118, 118, 59, 59, 115, 115, 105, 105, 59, 59, 110, 110, 111, 111, 117, 117, + 59, 59, 97, 119, 59, 59, 59, 59, 101, 101, 101, 101, 110, 110, 59, 59, + 114, 114, 59, 59, 103, 103, 99, 119, 97, 117, 112, 112, 59, 59, 114, 114, + 99, 99, 59, 59, 112, 112, 59, 59, 100, 116, 111, 111, 116, 116, 59, 59, + 108, 108, 117, 117, 115, 115, 59, 59, 105, 105, 109, 109, 101, 101, 115, 115, + 59, 59, 113, 116, 99, 99, 117, 117, 112, 112, 59, 59, 97, 97, 114, 114, + 59, 59, 114, 114, 105, 105, 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, + 100, 117, 111, 111, 119, 119, 110, 110, 59, 59, 112, 112, 59, 59, 112, 112, + 108, 108, 117, 117, 115, 115, 59, 59, 101, 101, 101, 101, 59, 59, 101, 101, + 100, 100, 103, 103, 101, 101, 59, 59, 97, 97, 114, 114, 111, 111, 119, 119, + 59, 59, 97, 111, 99, 110, 107, 107, 108, 116, 111, 111, 122, 122, 101, 101, + 110, 110, 103, 103, 101, 101, 59, 59, 113, 113, 117, 117, 97, 97, 114, 114, + 101, 101, 59, 59, 114, 114, 105, 105, 97, 97, 110, 110, 103, 103, 108, 108, + 101, 101, 59, 114, 111, 111, 119, 119, 110, 110, 59, 59, 101, 101, 102, 102, + 116, 116, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 59, 59, 107, 107, + 59, 59, 49, 51, 50, 52, 59, 59, 59, 59, 52, 52, 59, 59, 99, 99, + 107, 107, 59, 59, 101, 111, 59, 113, 117, 117, 105, 105, 118, 118, 59, 59, + 116, 116, 59, 59, 112, 120, 102, 102, 59, 59, 59, 116, 111, 111, 109, 109, + 59, 59, 116, 116, 105, 105, 101, 101, 59, 59, 68, 118, 76, 114, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 117, 59, 59, 59, 59, 59, 59, 59, 59, + 76, 114, 59, 59, 59, 59, 59, 59, 59, 59, 59, 114, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 111, 111, 120, 120, 59, 59, 76, 114, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 117, 59, 59, 59, 59, 59, 59, + 59, 59, 105, 105, 110, 110, 117, 117, 115, 115, 59, 59, 108, 108, 117, 117, + 115, 115, 59, 59, 105, 105, 109, 109, 101, 101, 115, 115, 59, 59, 76, 114, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 114, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 114, 114, 105, 105, 109, 109, 101, 101, 59, 59, + 101, 118, 118, 118, 101, 101, 59, 59, 98, 98, 97, 97, 114, 114, 99, 111, + 114, 114, 59, 59, 109, 109, 105, 105, 59, 59, 109, 109, 59, 101, 59, 59, + 108, 108, 59, 104, 59, 59, 115, 115, 117, 117, 98, 98, 59, 59, 108, 109, + 108, 108, 59, 101, 116, 116, 59, 59, 112, 112, 59, 101, 59, 59, 59, 113, + 59, 59, 97, 121, 99, 114, 117, 117, 116, 116, 101, 101, 59, 59, 59, 115, + 110, 110, 100, 100, 59, 59, 114, 114, 99, 99, 117, 117, 112, 112, 59, 59, + 97, 117, 112, 112, 59, 59, 112, 112, 59, 59, 111, 111, 116, 116, 59, 59, + 59, 59, 101, 111, 116, 116, 59, 59, 110, 110, 59, 59, 97, 117, 112, 114, + 115, 115, 59, 59, 111, 111, 110, 110, 59, 59, 100, 100, 105, 105, 108, 108, + 114, 114, 99, 99, 59, 59, 112, 112, 115, 115, 59, 115, 109, 109, 59, 59, + 111, 111, 116, 116, 59, 59, 100, 110, 105, 105, 108, 108, 112, 112, 116, 116, + 121, 121, 118, 118, 59, 59, 116, 116, 114, 114, 100, 100, 111, 111, 116, 116, + 59, 59, 114, 114, 59, 59, 99, 105, 121, 121, 59, 59, 99, 99, 107, 107, + 59, 109, 97, 97, 114, 114, 107, 107, 59, 59, 59, 59, 114, 114, 59, 115, + 59, 59, 59, 108, 113, 113, 59, 59, 101, 101, 97, 100, 114, 114, 114, 114, + 111, 111, 119, 119, 108, 114, 101, 101, 102, 102, 116, 116, 59, 59, 105, 105, + 103, 103, 104, 104, 116, 116, 59, 59, 82, 100, 59, 59, 59, 59, 115, 115, + 116, 116, 59, 59, 105, 105, 114, 114, 99, 99, 59, 59, 97, 97, 115, 115, + 104, 104, 59, 59, 59, 59, 110, 110, 105, 105, 110, 110, 116, 116, 59, 59, + 105, 105, 100, 100, 59, 59, 99, 99, 105, 105, 114, 114, 59, 59, 117, 117, + 98, 98, 115, 115, 59, 117, 105, 105, 116, 116, 59, 59, 108, 112, 111, 111, + 110, 110, 59, 101, 59, 113, 59, 59, 109, 112, 97, 97, 59, 116, 59, 59, + 59, 108, 110, 110, 59, 59, 101, 101, 109, 120, 101, 101, 110, 110, 116, 116, + 59, 59, 101, 101, 115, 115, 59, 59, 103, 105, 59, 100, 111, 111, 116, 116, + 59, 59, 110, 110, 116, 116, 59, 59, 102, 121, 59, 59, 111, 111, 100, 100, + 59, 59, 114, 114, 59, 59, 97, 111, 114, 114, 114, 114, 59, 59, 115, 115, + 115, 115, 59, 59, 99, 117, 114, 114, 59, 59, 98, 112, 59, 101, 59, 59, + 59, 101, 59, 59, 100, 100, 111, 111, 116, 116, 59, 59, 100, 119, 97, 97, + 114, 114, 114, 114, 108, 114, 59, 59, 59, 59, 112, 115, 114, 114, 59, 59, + 99, 99, 59, 59, 97, 97, 114, 114, 114, 114, 59, 112, 59, 59, 59, 115, + 114, 114, 99, 99, 97, 97, 112, 112, 59, 59, 97, 117, 112, 112, 59, 59, + 112, 112, 59, 59, 111, 111, 116, 116, 59, 59, 114, 114, 59, 59, 59, 59, + 97, 118, 114, 114, 114, 114, 59, 109, 59, 59, 121, 121, 101, 119, 113, 113, + 112, 115, 114, 114, 101, 101, 99, 99, 59, 59, 117, 117, 99, 99, 99, 99, + 59, 59, 101, 101, 101, 101, 59, 59, 101, 101, 100, 100, 103, 103, 101, 101, + 59, 59, 101, 101, 110, 110, 101, 101, 97, 97, 114, 114, 114, 114, 111, 111, + 119, 119, 108, 114, 101, 101, 102, 102, 116, 116, 59, 59, 105, 105, 103, 103, + 104, 104, 116, 116, 59, 59, 101, 101, 101, 101, 59, 59, 101, 101, 100, 100, + 59, 59, 99, 105, 111, 111, 110, 110, 105, 105, 110, 110, 116, 116, 59, 59, + 110, 110, 116, 116, 59, 59, 108, 108, 99, 99, 116, 116, 121, 121, 59, 59, + 65, 122, 114, 114, 114, 114, 59, 59, 97, 97, 114, 114, 59, 59, 103, 115, + 103, 103, 101, 101, 114, 114, 59, 59, 101, 101, 116, 116, 104, 104, 59, 59, + 114, 114, 59, 59, 104, 104, 59, 118, 59, 59, 107, 108, 97, 97, 114, 114, + 111, 111, 119, 119, 59, 59, 97, 97, 99, 99, 59, 59, 97, 121, 114, 114, + 111, 111, 110, 110, 59, 59, 59, 59, 59, 111, 103, 114, 103, 103, 101, 101, + 114, 114, 59, 59, 114, 114, 59, 59, 116, 116, 115, 115, 101, 101, 113, 113, + 59, 59, 103, 109, 116, 116, 97, 97, 59, 59, 112, 112, 116, 116, 121, 121, + 118, 118, 59, 59, 105, 114, 115, 115, 104, 104, 116, 116, 59, 59, 59, 59, + 97, 97, 114, 114, 108, 114, 59, 59, 59, 59, 97, 118, 109, 109, 59, 115, + 110, 110, 100, 100, 59, 115, 117, 117, 105, 105, 116, 116, 59, 59, 59, 59, + 59, 59, 97, 97, 109, 109, 109, 109, 97, 97, 59, 59, 105, 105, 110, 110, + 59, 59, 59, 111, 100, 100, 101, 101, 110, 110, 116, 116, 105, 105, 109, 109, + 101, 101, 115, 115, 59, 59, 110, 110, 120, 120, 59, 59, 99, 99, 121, 121, + 59, 59, 99, 99, 111, 114, 114, 114, 110, 110, 59, 59, 111, 111, 112, 112, + 59, 59, 108, 119, 108, 108, 97, 97, 114, 114, 59, 59, 102, 102, 59, 59, + 59, 115, 113, 113, 59, 100, 111, 111, 116, 116, 59, 59, 105, 105, 110, 110, + 117, 117, 115, 115, 59, 59, 108, 108, 117, 117, 115, 115, 59, 59, 113, 113, + 117, 117, 97, 97, 114, 114, 101, 101, 59, 59, 98, 98, 108, 108, 101, 101, + 98, 98, 97, 97, 114, 114, 119, 119, 101, 101, 100, 100, 103, 103, 101, 101, + 59, 59, 110, 110, 97, 104, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 111, 111, 119, 119, 110, 110, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, + 115, 115, 59, 59, 97, 97, 114, 114, 112, 112, 111, 111, 111, 111, 110, 110, + 108, 114, 101, 101, 102, 102, 116, 116, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 59, 59, 98, 99, 107, 107, 97, 97, 114, 114, 111, 111, 119, 119, + 59, 59, 111, 114, 114, 114, 110, 110, 59, 59, 111, 111, 112, 112, 59, 59, + 99, 116, 114, 121, 59, 59, 59, 59, 108, 108, 59, 59, 114, 114, 111, 111, + 107, 107, 59, 59, 100, 114, 111, 111, 116, 116, 59, 59, 105, 105, 59, 102, + 59, 59, 97, 104, 114, 114, 114, 114, 59, 59, 97, 97, 114, 114, 59, 59, + 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, 59, 59, 99, 105, 121, 121, + 59, 59, 103, 103, 114, 114, 97, 97, 114, 114, 114, 114, 59, 59, 68, 120, + 68, 111, 111, 111, 116, 116, 59, 59, 116, 116, 59, 59, 99, 115, 117, 117, + 116, 116, 101, 101, 116, 116, 101, 101, 114, 114, 59, 59, 97, 121, 114, 114, + 111, 111, 110, 110, 59, 59, 114, 114, 59, 99, 108, 108, 111, 111, 110, 110, + 59, 59, 59, 59, 111, 111, 116, 116, 59, 59, 59, 59, 68, 114, 111, 111, + 116, 116, 59, 59, 59, 59, 59, 115, 97, 97, 118, 118, 101, 101, 59, 100, + 111, 111, 116, 116, 59, 59, 59, 115, 110, 110, 116, 116, 101, 101, 114, 114, + 115, 115, 59, 59, 59, 59, 59, 100, 111, 111, 116, 116, 59, 59, 97, 115, + 99, 99, 114, 114, 59, 59, 116, 116, 121, 121, 59, 118, 101, 101, 116, 116, + 59, 59, 59, 59, 112, 112, 49, 59, 51, 52, 59, 59, 59, 59, 103, 115, + 59, 59, 112, 112, 59, 59, 103, 112, 111, 111, 110, 110, 59, 59, 102, 102, + 59, 59, 97, 115, 114, 114, 59, 115, 108, 108, 59, 59, 117, 117, 115, 115, + 59, 59, 105, 105, 59, 118, 111, 111, 110, 110, 59, 59, 59, 59, 99, 118, + 105, 111, 114, 114, 99, 99, 59, 59, 108, 108, 111, 111, 110, 110, 59, 59, + 105, 108, 109, 109, 59, 59, 97, 97, 110, 110, 116, 116, 103, 108, 116, 116, + 114, 114, 59, 59, 101, 101, 115, 115, 115, 115, 59, 59, 97, 105, 108, 108, + 115, 115, 59, 59, 115, 115, 116, 116, 59, 59, 118, 118, 59, 68, 68, 68, + 59, 59, 112, 112, 97, 97, 114, 114, 115, 115, 108, 108, 59, 59, 68, 97, + 111, 111, 116, 116, 59, 59, 114, 114, 114, 114, 59, 59, 99, 105, 114, 114, + 59, 59, 111, 111, 116, 116, 59, 59, 109, 109, 59, 59, 97, 104, 59, 59, + 109, 114, 108, 108, 111, 111, 59, 59, 99, 112, 108, 108, 59, 59, 115, 115, + 116, 116, 59, 59, 101, 111, 99, 99, 116, 116, 97, 97, 116, 116, 105, 105, + 111, 111, 110, 110, 59, 59, 110, 110, 101, 101, 110, 110, 116, 116, 105, 105, + 97, 97, 108, 108, 101, 101, 59, 59, 97, 115, 108, 108, 108, 108, 105, 105, + 110, 110, 103, 103, 100, 100, 111, 111, 116, 116, 115, 115, 101, 101, 113, 113, + 59, 59, 121, 121, 59, 59, 109, 109, 97, 97, 108, 108, 101, 101, 59, 59, + 105, 114, 108, 108, 105, 105, 103, 103, 59, 59, 105, 108, 103, 103, 59, 59, + 105, 105, 103, 103, 59, 59, 59, 59, 108, 108, 105, 105, 103, 103, 59, 59, + 108, 108, 105, 105, 103, 103, 59, 59, 97, 116, 116, 116, 59, 59, 105, 105, + 103, 103, 59, 59, 110, 110, 115, 115, 59, 59, 111, 111, 102, 102, 59, 59, + 112, 114, 102, 102, 59, 59, 97, 107, 108, 108, 108, 108, 59, 59, 59, 118, + 59, 59, 97, 97, 114, 114, 116, 116, 105, 105, 110, 110, 116, 116, 59, 59, + 97, 111, 99, 115, 49, 55, 50, 56, 59, 59, 59, 59, 59, 59, 59, 59, + 51, 53, 59, 59, 59, 59, 52, 56, 59, 59, 59, 59, 53, 53, 59, 59, + 54, 56, 59, 59, 59, 59, 56, 56, 59, 59, 108, 108, 59, 59, 119, 119, + 110, 110, 59, 59, 99, 99, 114, 114, 59, 59, 69, 118, 59, 108, 59, 59, + 99, 112, 117, 117, 116, 116, 101, 101, 59, 59, 109, 109, 97, 97, 59, 100, + 59, 59, 59, 59, 114, 114, 101, 101, 118, 118, 101, 101, 59, 59, 105, 121, + 114, 114, 99, 99, 59, 59, 59, 59, 111, 111, 116, 116, 59, 59, 59, 115, + 59, 59, 59, 115, 59, 59, 108, 108, 97, 97, 110, 110, 116, 116, 59, 59, + 59, 108, 99, 99, 59, 59, 111, 111, 116, 116, 59, 111, 59, 108, 59, 59, + 59, 101, 115, 115, 59, 59, 114, 114, 59, 59, 59, 103, 59, 59, 109, 109, + 101, 101, 108, 108, 59, 59, 99, 99, 121, 121, 59, 59, 59, 106, 59, 59, + 59, 59, 59, 59, 69, 115, 59, 59, 112, 112, 59, 112, 114, 114, 111, 111, + 120, 120, 59, 59, 59, 113, 59, 113, 59, 59, 105, 105, 109, 109, 59, 59, + 112, 112, 102, 102, 59, 59, 97, 97, 118, 118, 101, 101, 59, 59, 99, 105, + 114, 114, 59, 59, 109, 109, 59, 108, 59, 59, 59, 59, 99, 105, 59, 59, + 114, 114, 59, 59, 111, 111, 116, 116, 59, 59, 80, 80, 97, 97, 114, 114, + 59, 59, 117, 117, 101, 101, 115, 115, 116, 116, 59, 59, 97, 115, 112, 114, + 112, 112, 114, 114, 111, 111, 120, 120, 59, 59, 114, 114, 59, 59, 111, 111, + 116, 116, 59, 59, 113, 113, 108, 113, 101, 101, 115, 115, 115, 115, 59, 59, + 108, 108, 101, 101, 115, 115, 115, 115, 59, 59, 101, 101, 115, 115, 115, 115, + 59, 59, 105, 105, 109, 109, 59, 59, 101, 110, 114, 114, 116, 116, 110, 110, + 101, 101, 113, 113, 113, 113, 59, 59, 69, 69, 59, 59, 65, 121, 114, 114, + 114, 114, 59, 59, 105, 114, 114, 114, 115, 115, 112, 112, 59, 59, 102, 102, + 59, 59, 105, 105, 108, 108, 116, 116, 59, 59, 100, 114, 99, 99, 121, 121, + 59, 59, 59, 119, 105, 105, 114, 114, 59, 59, 59, 59, 97, 97, 114, 114, + 59, 59, 105, 105, 114, 114, 99, 99, 59, 59, 97, 114, 114, 114, 116, 116, + 115, 115, 59, 117, 105, 105, 116, 116, 59, 59, 108, 108, 105, 105, 112, 112, + 59, 59, 99, 99, 111, 111, 110, 110, 59, 59, 114, 114, 59, 59, 115, 115, + 101, 119, 97, 97, 114, 114, 111, 111, 119, 119, 59, 59, 97, 97, 114, 114, + 111, 111, 119, 119, 59, 59, 97, 114, 114, 114, 114, 114, 59, 59, 116, 116, + 104, 104, 116, 116, 59, 59, 107, 107, 108, 114, 101, 101, 102, 102, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, + 104, 104, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, + 102, 102, 59, 59, 98, 98, 97, 97, 114, 114, 59, 59, 99, 116, 114, 114, + 59, 59, 97, 97, 115, 115, 104, 104, 59, 59, 114, 114, 111, 111, 107, 107, + 59, 59, 98, 112, 117, 117, 108, 108, 108, 108, 59, 59, 104, 104, 101, 101, + 110, 110, 59, 59, 97, 117, 99, 99, 117, 117, 116, 116, 101, 101, 59, 121, + 114, 114, 99, 99, 59, 59, 99, 120, 121, 121, 59, 59, 99, 99, 108, 108, + 102, 114, 59, 59, 59, 59, 114, 114, 97, 97, 118, 118, 101, 101, 59, 111, + 105, 110, 110, 110, 116, 116, 59, 59, 116, 116, 59, 59, 102, 102, 105, 105, + 110, 110, 59, 59, 116, 116, 97, 97, 59, 59, 108, 108, 105, 105, 103, 103, + 59, 59, 97, 112, 99, 116, 114, 114, 59, 59, 101, 112, 59, 59, 105, 105, + 110, 110, 101, 101, 59, 59, 97, 97, 114, 114, 116, 116, 59, 59, 104, 104, + 59, 59, 102, 102, 59, 59, 101, 101, 100, 100, 59, 59, 59, 116, 97, 97, + 114, 114, 101, 101, 59, 59, 105, 105, 110, 110, 59, 116, 105, 105, 101, 101, + 59, 59, 100, 100, 111, 111, 116, 116, 59, 59, 59, 112, 97, 97, 108, 108, + 59, 59, 103, 114, 101, 101, 114, 114, 115, 115, 59, 59, 99, 99, 97, 97, + 108, 108, 59, 59, 97, 97, 114, 114, 104, 104, 107, 107, 59, 59, 114, 114, + 111, 111, 100, 100, 59, 59, 99, 116, 121, 121, 59, 59, 111, 111, 110, 110, + 59, 59, 102, 102, 59, 59, 97, 97, 59, 59, 114, 114, 111, 111, 100, 100, + 59, 59, 117, 117, 101, 101, 115, 115, 116, 116, 99, 105, 114, 114, 59, 59, + 110, 110, 59, 118, 59, 59, 111, 111, 116, 116, 59, 59, 59, 118, 59, 59, + 59, 59, 59, 105, 108, 108, 100, 100, 101, 101, 59, 59, 107, 109, 99, 99, + 121, 121, 59, 59, 108, 108, 99, 117, 105, 121, 114, 114, 99, 99, 59, 59, + 59, 59, 114, 114, 59, 59, 97, 97, 116, 116, 104, 104, 59, 59, 112, 112, + 102, 102, 59, 59, 99, 101, 114, 114, 59, 59, 114, 114, 99, 99, 121, 121, + 59, 59, 107, 107, 99, 99, 121, 121, 59, 59, 97, 115, 112, 112, 112, 112, + 97, 97, 59, 118, 59, 59, 101, 121, 100, 100, 105, 105, 108, 108, 59, 59, + 59, 59, 114, 114, 59, 59, 114, 114, 101, 101, 101, 101, 110, 110, 59, 59, + 99, 99, 121, 121, 59, 59, 99, 99, 121, 121, 59, 59, 112, 112, 102, 102, + 59, 59, 99, 99, 114, 114, 59, 59, 65, 118, 97, 116, 114, 114, 114, 114, + 59, 59, 114, 114, 59, 59, 97, 97, 105, 105, 108, 108, 59, 59, 97, 97, + 114, 114, 114, 114, 59, 59, 59, 103, 59, 59, 97, 97, 114, 114, 59, 59, + 99, 116, 117, 117, 116, 116, 101, 101, 59, 59, 109, 109, 112, 112, 116, 116, + 121, 121, 118, 118, 59, 59, 114, 114, 97, 97, 110, 110, 59, 59, 98, 98, + 100, 100, 97, 97, 59, 59, 103, 103, 59, 108, 59, 59, 101, 101, 59, 59, + 59, 59, 117, 117, 111, 111, 114, 114, 59, 116, 59, 102, 115, 115, 59, 59, + 115, 115, 59, 59, 107, 107, 59, 59, 112, 112, 59, 59, 108, 108, 59, 59, + 105, 105, 109, 109, 59, 59, 108, 108, 59, 59, 59, 101, 105, 105, 108, 108, + 59, 59, 59, 115, 59, 59, 97, 114, 114, 114, 114, 114, 59, 59, 114, 114, + 107, 107, 59, 59, 97, 107, 99, 99, 101, 107, 59, 59, 59, 59, 101, 115, + 59, 59, 108, 108, 100, 117, 59, 59, 59, 59, 97, 121, 114, 114, 111, 111, + 110, 110, 59, 59, 100, 105, 105, 105, 108, 108, 59, 59, 108, 108, 59, 59, + 98, 98, 59, 59, 59, 59, 99, 115, 97, 97, 59, 59, 117, 117, 111, 111, + 59, 114, 59, 59, 100, 117, 104, 104, 97, 97, 114, 114, 59, 59, 115, 115, + 104, 104, 97, 97, 114, 114, 59, 59, 104, 104, 59, 59, 59, 115, 116, 116, + 97, 116, 114, 114, 114, 114, 111, 111, 119, 119, 59, 116, 97, 97, 105, 105, + 108, 108, 59, 59, 97, 97, 114, 114, 112, 112, 111, 111, 111, 111, 110, 110, + 100, 117, 111, 111, 119, 119, 110, 110, 59, 59, 112, 112, 59, 59, 101, 101, + 102, 102, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 115, 115, + 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 97, 115, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 115, 59, 59, 97, 97, 114, 114, 112, 112, 111, 111, + 111, 111, 110, 110, 115, 115, 59, 59, 113, 113, 117, 117, 105, 105, 103, 103, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 104, 104, 114, 114, + 101, 101, 101, 101, 116, 116, 105, 105, 109, 109, 101, 101, 115, 115, 59, 59, + 59, 59, 59, 115, 59, 59, 108, 108, 97, 97, 110, 110, 116, 116, 59, 59, + 59, 115, 99, 99, 59, 59, 111, 111, 116, 116, 59, 111, 59, 114, 59, 59, + 59, 101, 115, 115, 59, 59, 97, 115, 112, 112, 112, 112, 114, 114, 111, 111, + 120, 120, 59, 59, 111, 111, 116, 116, 59, 59, 113, 113, 103, 113, 116, 116, + 114, 114, 59, 59, 103, 103, 116, 116, 114, 114, 59, 59, 116, 116, 114, 114, + 59, 59, 105, 105, 109, 109, 59, 59, 105, 114, 115, 115, 104, 104, 116, 116, + 59, 59, 111, 111, 111, 111, 114, 114, 59, 59, 59, 59, 59, 69, 59, 59, + 97, 98, 114, 114, 100, 117, 59, 59, 59, 108, 59, 59, 108, 108, 107, 107, + 59, 59, 99, 99, 121, 121, 59, 59, 59, 116, 114, 114, 114, 114, 59, 59, + 111, 111, 114, 114, 110, 110, 101, 101, 114, 114, 59, 59, 97, 97, 114, 114, + 100, 100, 59, 59, 114, 114, 105, 105, 59, 59, 105, 111, 100, 100, 111, 111, + 116, 116, 59, 59, 117, 117, 115, 115, 116, 116, 59, 97, 99, 99, 104, 104, + 101, 101, 59, 59, 69, 115, 59, 59, 112, 112, 59, 112, 114, 114, 111, 111, + 120, 120, 59, 59, 59, 113, 59, 113, 59, 59, 105, 105, 109, 109, 59, 59, + 97, 122, 110, 114, 103, 103, 59, 59, 114, 114, 59, 59, 114, 114, 107, 107, + 59, 59, 103, 103, 108, 114, 101, 101, 102, 102, 116, 116, 97, 114, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 97, 97, 112, 112, + 115, 115, 116, 116, 111, 111, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 112, 112, 97, 97, + 114, 114, 114, 114, 111, 111, 119, 119, 108, 114, 101, 101, 102, 102, 116, 116, + 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 59, 59, 97, 108, 114, 114, + 59, 59, 59, 59, 117, 117, 115, 115, 59, 59, 105, 105, 109, 109, 101, 101, + 115, 115, 59, 59, 97, 98, 115, 115, 116, 116, 59, 59, 97, 97, 114, 114, + 59, 59, 59, 102, 110, 110, 103, 103, 101, 101, 59, 59, 59, 59, 97, 97, + 114, 114, 59, 108, 116, 116, 59, 59, 97, 116, 114, 114, 114, 114, 59, 59, + 111, 111, 114, 114, 110, 110, 101, 101, 114, 114, 59, 59, 97, 97, 114, 114, + 59, 100, 59, 59, 59, 59, 114, 114, 105, 105, 59, 59, 97, 116, 113, 113, + 117, 117, 111, 111, 59, 59, 114, 114, 59, 59, 59, 59, 109, 109, 59, 103, + 59, 59, 59, 59, 98, 117, 59, 59, 111, 111, 59, 114, 59, 59, 114, 114, + 111, 111, 107, 107, 59, 59, 99, 105, 59, 59, 114, 114, 59, 59, 111, 111, + 116, 116, 59, 59, 114, 114, 101, 101, 101, 101, 59, 59, 109, 109, 101, 101, + 115, 115, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, 117, 117, 101, 101, + 115, 115, 116, 116, 59, 59, 80, 105, 97, 97, 114, 114, 59, 59, 59, 102, + 59, 59, 59, 59, 114, 114, 100, 117, 115, 115, 104, 104, 97, 97, 114, 114, + 59, 59, 104, 104, 97, 97, 114, 114, 59, 59, 101, 110, 114, 114, 116, 116, + 110, 110, 101, 101, 113, 113, 113, 113, 59, 59, 69, 69, 59, 59, 68, 117, + 68, 68, 111, 111, 116, 116, 59, 59, 99, 114, 114, 114, 101, 116, 59, 59, + 59, 101, 115, 115, 101, 101, 59, 59, 59, 115, 116, 116, 111, 111, 59, 117, + 111, 111, 119, 119, 110, 110, 59, 59, 101, 101, 102, 102, 116, 116, 59, 59, + 112, 112, 59, 59, 107, 107, 101, 101, 114, 114, 59, 59, 111, 121, 109, 109, + 109, 109, 97, 97, 59, 59, 59, 59, 97, 97, 115, 115, 104, 104, 59, 59, + 97, 97, 115, 115, 117, 117, 114, 114, 101, 101, 100, 100, 97, 97, 110, 110, + 103, 103, 108, 108, 101, 101, 59, 59, 114, 114, 59, 59, 111, 111, 59, 59, + 99, 110, 114, 114, 111, 111, 59, 100, 115, 115, 116, 116, 59, 59, 105, 105, + 114, 114, 59, 59, 111, 111, 116, 116, 117, 117, 115, 115, 59, 100, 59, 59, + 59, 117, 59, 59, 99, 100, 112, 112, 59, 59, 114, 114, 59, 59, 112, 112, + 108, 108, 117, 117, 115, 115, 59, 59, 100, 112, 101, 101, 108, 108, 115, 115, + 59, 59, 102, 102, 59, 59, 59, 59, 99, 116, 114, 114, 59, 59, 112, 112, + 111, 111, 115, 115, 59, 59, 59, 109, 116, 116, 105, 105, 109, 109, 97, 97, + 112, 112, 59, 59, 97, 97, 112, 112, 59, 59, 71, 119, 103, 116, 59, 59, + 59, 118, 59, 59, 101, 116, 102, 102, 116, 116, 97, 114, 114, 114, 114, 114, + 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 97, 97, + 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 59, 59, 59, 118, 59, 59, + 105, 105, 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 68, 100, 97, 97, 115, 115, 104, 104, 59, 59, 97, 97, + 115, 115, 104, 104, 59, 59, 98, 116, 108, 108, 97, 97, 59, 59, 117, 117, + 116, 116, 101, 101, 59, 59, 103, 103, 59, 59, 59, 112, 59, 59, 100, 100, + 59, 59, 115, 115, 59, 59, 114, 114, 111, 111, 120, 120, 59, 59, 117, 117, + 114, 114, 59, 97, 108, 108, 59, 115, 59, 59, 115, 117, 112, 112, 109, 109, + 112, 112, 59, 101, 59, 59, 97, 121, 112, 114, 59, 59, 111, 111, 110, 110, + 59, 59, 100, 100, 105, 105, 108, 108, 59, 59, 110, 110, 103, 103, 59, 100, + 111, 111, 116, 116, 59, 59, 112, 112, 59, 59, 59, 59, 97, 97, 115, 115, + 104, 104, 59, 59, 59, 120, 114, 114, 114, 114, 59, 59, 114, 114, 104, 114, + 107, 107, 59, 59, 59, 111, 119, 119, 59, 59, 111, 111, 116, 116, 59, 59, + 117, 117, 105, 105, 118, 118, 59, 59, 101, 105, 97, 97, 114, 114, 59, 59, + 109, 109, 59, 59, 105, 105, 115, 115, 116, 116, 59, 115, 59, 59, 114, 114, + 59, 59, 69, 116, 59, 59, 59, 115, 59, 115, 59, 59, 108, 108, 97, 97, + 110, 110, 116, 116, 59, 59, 59, 59, 105, 105, 109, 109, 59, 59, 59, 114, + 59, 59, 65, 112, 114, 114, 114, 114, 59, 59, 114, 114, 114, 114, 59, 59, + 97, 97, 114, 114, 59, 59, 59, 118, 59, 100, 59, 59, 59, 59, 99, 99, + 121, 121, 59, 59, 65, 116, 114, 114, 114, 114, 59, 59, 59, 59, 114, 114, + 114, 114, 59, 59, 114, 114, 59, 59, 59, 115, 116, 116, 97, 114, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 59, 115, 59, 59, + 108, 108, 97, 97, 110, 110, 116, 116, 59, 59, 59, 115, 59, 59, 105, 105, + 109, 109, 59, 59, 59, 114, 105, 105, 59, 101, 59, 59, 105, 105, 100, 100, + 59, 59, 112, 116, 102, 102, 59, 59, 110, 110, 59, 118, 59, 59, 111, 111, + 116, 116, 59, 59, 97, 99, 59, 59, 59, 59, 59, 59, 105, 105, 59, 118, + 97, 99, 59, 59, 59, 59, 59, 59, 97, 114, 114, 114, 59, 116, 108, 108, + 108, 108, 101, 101, 108, 108, 59, 59, 108, 108, 59, 59, 59, 59, 108, 108, + 105, 105, 110, 110, 116, 116, 59, 59, 59, 101, 117, 117, 101, 101, 59, 59, + 59, 99, 59, 101, 113, 113, 59, 59, 65, 116, 114, 114, 114, 114, 59, 59, + 114, 114, 114, 114, 59, 119, 59, 59, 59, 59, 103, 103, 104, 104, 116, 116, + 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 114, 114, 105, 105, + 59, 101, 59, 59, 99, 117, 59, 114, 117, 117, 101, 101, 59, 59, 59, 59, + 59, 59, 111, 111, 114, 114, 116, 116, 109, 112, 105, 105, 100, 100, 59, 59, + 97, 97, 114, 114, 97, 97, 108, 108, 108, 108, 101, 101, 108, 108, 59, 59, + 109, 109, 59, 101, 59, 113, 59, 59, 105, 105, 100, 100, 59, 59, 97, 97, + 114, 114, 59, 59, 115, 115, 117, 117, 98, 112, 101, 101, 59, 59, 101, 101, + 59, 59, 98, 112, 59, 115, 59, 59, 59, 59, 101, 101, 116, 116, 59, 101, + 113, 113, 59, 113, 59, 59, 99, 99, 59, 101, 113, 113, 59, 59, 59, 115, + 59, 59, 59, 59, 101, 101, 116, 116, 59, 101, 113, 113, 59, 113, 59, 59, + 103, 114, 108, 108, 59, 59, 108, 108, 100, 100, 101, 101, 103, 103, 59, 59, + 105, 105, 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, 108, 114, 101, 101, + 102, 102, 116, 116, 59, 101, 113, 113, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 59, 101, 113, 113, 59, 59, 59, 109, 59, 115, 114, 114, 111, 111, + 59, 59, 112, 112, 59, 59, 68, 115, 97, 97, 115, 115, 104, 104, 59, 59, + 97, 97, 114, 114, 114, 114, 59, 59, 112, 112, 59, 59, 97, 97, 115, 115, + 104, 104, 59, 59, 101, 116, 59, 59, 59, 59, 110, 110, 102, 102, 105, 105, + 110, 110, 59, 59, 65, 116, 114, 114, 114, 114, 59, 59, 59, 59, 59, 114, + 105, 105, 101, 101, 59, 59, 65, 116, 114, 114, 114, 114, 59, 59, 114, 114, + 105, 105, 101, 101, 59, 59, 105, 105, 109, 109, 59, 59, 65, 110, 114, 114, + 114, 114, 59, 59, 114, 114, 104, 114, 107, 107, 59, 59, 59, 111, 119, 119, + 59, 59, 101, 101, 97, 97, 114, 114, 59, 59, 83, 118, 59, 59, 99, 115, + 117, 117, 116, 116, 101, 101, 116, 116, 59, 59, 105, 121, 114, 114, 59, 99, + 59, 59, 97, 115, 115, 115, 104, 104, 59, 59, 108, 108, 97, 97, 99, 99, + 59, 59, 118, 118, 59, 59, 116, 116, 59, 59, 111, 111, 108, 108, 100, 100, + 59, 59, 108, 108, 105, 105, 103, 103, 59, 59, 99, 114, 105, 105, 114, 114, + 59, 59, 59, 59, 111, 116, 110, 110, 59, 59, 97, 97, 118, 118, 101, 101, + 59, 59, 98, 109, 97, 97, 114, 114, 59, 59, 59, 59, 110, 110, 116, 116, + 59, 59, 97, 116, 114, 114, 114, 114, 59, 59, 105, 114, 114, 114, 59, 59, + 111, 111, 115, 115, 115, 115, 59, 59, 110, 110, 101, 101, 59, 59, 59, 59, + 97, 105, 99, 99, 114, 114, 59, 59, 103, 103, 97, 97, 59, 59, 99, 110, + 114, 114, 111, 111, 110, 110, 59, 59, 59, 59, 117, 117, 115, 115, 59, 59, + 112, 112, 102, 102, 59, 59, 97, 108, 114, 114, 59, 59, 114, 114, 112, 112, + 59, 59, 117, 117, 115, 115, 59, 59, 59, 118, 114, 114, 114, 114, 59, 59, + 59, 109, 114, 114, 59, 111, 102, 102, 59, 59, 103, 103, 111, 111, 102, 102, + 59, 59, 114, 114, 59, 59, 108, 108, 111, 111, 112, 112, 101, 101, 59, 59, + 59, 59, 99, 111, 114, 114, 59, 59, 97, 97, 115, 115, 104, 104, 108, 108, + 59, 59, 105, 105, 108, 109, 100, 100, 101, 101, 101, 101, 115, 115, 59, 97, + 115, 115, 59, 59, 109, 109, 108, 108, 98, 98, 97, 97, 114, 114, 59, 59, + 97, 117, 114, 114, 59, 116, 108, 108, 101, 101, 108, 108, 59, 59, 105, 108, + 109, 109, 59, 59, 59, 59, 59, 59, 121, 121, 59, 59, 114, 114, 99, 116, + 110, 110, 116, 116, 59, 59, 111, 111, 100, 100, 59, 59, 105, 105, 108, 108, + 59, 59, 59, 59, 101, 101, 110, 110, 107, 107, 59, 59, 114, 114, 59, 59, + 105, 111, 59, 118, 59, 59, 109, 109, 97, 97, 116, 116, 59, 59, 110, 110, + 101, 101, 59, 59, 59, 118, 99, 99, 104, 104, 102, 102, 111, 111, 114, 114, + 107, 107, 59, 59, 59, 59, 97, 117, 110, 110, 99, 107, 107, 107, 59, 104, + 59, 59, 118, 118, 59, 59, 115, 115, 59, 116, 99, 99, 105, 105, 114, 114, + 59, 59, 59, 59, 105, 105, 114, 114, 59, 59, 111, 117, 59, 59, 59, 59, + 59, 59, 110, 110, 105, 105, 109, 109, 59, 59, 119, 119, 111, 111, 59, 59, + 59, 59, 105, 117, 110, 110, 116, 116, 105, 105, 110, 110, 116, 116, 59, 59, + 102, 102, 59, 59, 110, 110, 100, 100, 59, 117, 59, 59, 112, 112, 59, 59, + 117, 117, 101, 101, 59, 59, 59, 99, 59, 115, 112, 112, 112, 112, 114, 114, + 111, 111, 120, 120, 59, 59, 117, 117, 114, 114, 108, 108, 121, 121, 101, 101, + 113, 113, 59, 59, 113, 113, 59, 59, 97, 115, 112, 112, 112, 112, 114, 114, + 111, 111, 120, 120, 59, 59, 113, 113, 113, 113, 59, 59, 105, 105, 109, 109, + 59, 59, 105, 105, 109, 109, 59, 59, 109, 109, 101, 101, 59, 115, 59, 59, + 69, 115, 59, 59, 112, 112, 59, 59, 105, 105, 109, 109, 59, 59, 100, 112, + 59, 59, 97, 115, 108, 108, 97, 97, 114, 114, 59, 59, 105, 105, 110, 110, + 101, 101, 59, 59, 117, 117, 114, 114, 102, 102, 59, 59, 59, 116, 111, 111, + 59, 59, 105, 105, 109, 109, 59, 59, 114, 114, 101, 101, 108, 108, 59, 59, + 99, 105, 114, 114, 59, 59, 59, 59, 110, 110, 99, 99, 115, 115, 112, 112, + 59, 59, 102, 117, 114, 114, 59, 59, 110, 110, 116, 116, 59, 59, 112, 112, + 102, 102, 59, 59, 114, 114, 105, 105, 109, 109, 101, 101, 59, 59, 99, 99, + 114, 114, 59, 59, 97, 111, 116, 116, 101, 105, 114, 114, 110, 110, 105, 105, + 111, 111, 110, 110, 115, 115, 59, 59, 110, 110, 116, 116, 59, 59, 115, 115, + 116, 116, 59, 101, 113, 113, 59, 59, 116, 116, 65, 120, 97, 116, 114, 114, + 114, 114, 59, 59, 114, 114, 59, 59, 97, 97, 105, 105, 108, 108, 59, 59, + 97, 97, 114, 114, 114, 114, 59, 59, 97, 97, 114, 114, 59, 59, 99, 116, + 101, 117, 59, 59, 116, 116, 101, 101, 59, 59, 105, 105, 99, 99, 59, 59, + 109, 109, 112, 112, 116, 116, 121, 121, 118, 118, 59, 59, 103, 103, 59, 108, + 59, 59, 59, 59, 101, 101, 59, 59, 117, 117, 111, 111, 114, 114, 59, 119, + 112, 112, 59, 59, 59, 102, 115, 115, 59, 59, 59, 59, 115, 115, 59, 59, + 107, 107, 59, 59, 112, 112, 59, 59, 108, 108, 59, 59, 105, 105, 109, 109, + 59, 59, 108, 108, 59, 59, 59, 59, 97, 105, 105, 105, 108, 108, 59, 59, + 111, 111, 59, 110, 97, 97, 108, 108, 115, 115, 59, 59, 97, 114, 114, 114, + 114, 114, 59, 59, 114, 114, 107, 107, 59, 59, 97, 107, 99, 99, 101, 107, + 59, 59, 59, 59, 101, 115, 59, 59, 108, 108, 100, 117, 59, 59, 59, 59, + 97, 121, 114, 114, 111, 111, 110, 110, 59, 59, 100, 105, 105, 105, 108, 108, + 59, 59, 108, 108, 59, 59, 98, 98, 59, 59, 59, 59, 99, 115, 97, 97, + 59, 59, 100, 100, 104, 104, 97, 97, 114, 114, 59, 59, 117, 117, 111, 111, + 59, 114, 59, 59, 104, 104, 59, 59, 97, 103, 108, 108, 59, 115, 110, 110, + 101, 101, 59, 59, 97, 97, 114, 114, 116, 116, 59, 59, 59, 59, 116, 116, + 59, 59, 105, 114, 115, 115, 104, 104, 116, 116, 59, 59, 111, 111, 111, 111, + 114, 114, 59, 59, 59, 59, 97, 111, 114, 114, 100, 117, 59, 59, 59, 108, + 59, 59, 59, 118, 59, 59, 103, 115, 104, 104, 116, 116, 97, 116, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 116, 97, 97, 105, 105, 108, 108, 59, 59, + 97, 97, 114, 114, 112, 112, 111, 111, 111, 111, 110, 110, 100, 117, 111, 111, + 119, 119, 110, 110, 59, 59, 112, 112, 59, 59, 101, 101, 102, 102, 116, 116, + 97, 104, 114, 114, 114, 114, 111, 111, 119, 119, 115, 115, 59, 59, 97, 97, + 114, 114, 112, 112, 111, 111, 111, 111, 110, 110, 115, 115, 59, 59, 105, 105, + 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, + 115, 115, 59, 59, 113, 113, 117, 117, 105, 105, 103, 103, 97, 97, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 104, 104, 114, 114, 101, 101, 101, 101, + 116, 116, 105, 105, 109, 109, 101, 101, 115, 115, 59, 59, 103, 103, 59, 59, + 105, 105, 110, 110, 103, 103, 100, 100, 111, 111, 116, 116, 115, 115, 101, 101, + 113, 113, 59, 59, 97, 109, 114, 114, 114, 114, 59, 59, 97, 97, 114, 114, + 59, 59, 59, 59, 111, 111, 117, 117, 115, 115, 116, 116, 59, 97, 99, 99, + 104, 104, 101, 101, 59, 59, 109, 109, 105, 105, 100, 100, 59, 59, 97, 116, + 110, 114, 103, 103, 59, 59, 114, 114, 59, 59, 114, 114, 107, 107, 59, 59, + 97, 108, 114, 114, 59, 59, 59, 59, 117, 117, 115, 115, 59, 59, 105, 105, + 109, 109, 101, 101, 115, 115, 59, 59, 97, 112, 114, 114, 59, 103, 116, 116, + 59, 59, 111, 111, 108, 108, 105, 105, 110, 110, 116, 116, 59, 59, 97, 97, + 114, 114, 114, 114, 59, 59, 97, 113, 113, 113, 117, 117, 111, 111, 59, 59, + 114, 114, 59, 59, 59, 59, 98, 117, 59, 59, 111, 111, 59, 114, 59, 59, + 104, 114, 114, 114, 101, 101, 101, 101, 59, 59, 109, 109, 101, 101, 115, 115, + 59, 59, 105, 105, 59, 108, 59, 59, 59, 59, 116, 116, 114, 114, 105, 105, + 59, 59, 108, 108, 117, 117, 104, 104, 97, 97, 114, 114, 59, 59, 59, 59, + 97, 122, 99, 99, 117, 117, 116, 116, 101, 101, 59, 59, 113, 113, 117, 117, + 111, 111, 59, 59, 59, 121, 59, 59, 112, 114, 59, 59, 111, 111, 110, 110, + 59, 59, 117, 117, 101, 101, 59, 59, 59, 100, 105, 105, 108, 108, 59, 59, + 114, 114, 99, 99, 59, 59, 69, 115, 59, 59, 112, 112, 59, 59, 105, 105, + 109, 109, 59, 59, 111, 111, 108, 108, 105, 105, 110, 110, 116, 116, 59, 59, + 105, 105, 109, 109, 59, 59, 59, 59, 111, 111, 116, 116, 59, 101, 59, 59, + 59, 59, 65, 120, 114, 114, 114, 114, 59, 59, 114, 114, 104, 114, 107, 107, + 59, 59, 59, 111, 119, 119, 59, 59, 116, 116, 105, 105, 59, 59, 119, 119, + 97, 97, 114, 114, 59, 59, 109, 109, 105, 110, 110, 110, 117, 117, 115, 115, + 59, 59, 59, 59, 116, 116, 59, 59, 114, 114, 59, 111, 119, 119, 110, 110, + 59, 59, 97, 121, 114, 114, 112, 112, 59, 59, 104, 121, 99, 99, 121, 121, + 59, 59, 59, 59, 114, 114, 116, 116, 109, 112, 105, 105, 100, 100, 59, 59, + 97, 97, 114, 114, 97, 97, 108, 108, 108, 108, 101, 101, 108, 108, 59, 59, + 103, 109, 109, 109, 97, 97, 59, 118, 59, 59, 59, 59, 59, 114, 111, 111, + 116, 116, 59, 59, 59, 113, 59, 59, 59, 69, 59, 59, 59, 69, 59, 59, + 101, 101, 59, 59, 108, 108, 117, 117, 115, 115, 59, 59, 97, 97, 114, 114, + 114, 114, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, 97, 116, 108, 115, + 108, 108, 115, 115, 101, 101, 116, 116, 109, 109, 105, 105, 110, 110, 117, 117, + 115, 115, 59, 59, 104, 104, 112, 112, 59, 59, 112, 112, 97, 97, 114, 114, + 115, 115, 108, 108, 59, 59, 100, 108, 59, 59, 101, 101, 59, 59, 59, 101, + 59, 115, 59, 59, 102, 112, 116, 116, 99, 99, 121, 121, 59, 59, 59, 98, + 59, 97, 114, 114, 59, 59, 102, 102, 59, 59, 97, 97, 100, 114, 101, 101, + 115, 115, 59, 117, 105, 105, 116, 116, 59, 59, 59, 59, 99, 117, 97, 117, + 112, 112, 59, 115, 59, 59, 112, 112, 59, 115, 59, 59, 117, 117, 98, 112, + 59, 115, 59, 59, 101, 101, 116, 116, 59, 101, 113, 113, 59, 59, 59, 115, + 59, 59, 101, 101, 116, 116, 59, 101, 113, 113, 59, 59, 59, 102, 114, 114, + 101, 102, 59, 59, 59, 59, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, + 99, 116, 114, 114, 59, 59, 116, 116, 109, 109, 110, 110, 59, 59, 105, 105, + 108, 108, 101, 101, 59, 59, 97, 97, 114, 114, 102, 102, 59, 59, 97, 114, + 114, 114, 59, 102, 59, 59, 97, 110, 105, 105, 103, 103, 104, 104, 116, 116, + 101, 112, 112, 112, 115, 115, 105, 105, 108, 108, 111, 111, 110, 110, 59, 59, + 104, 104, 105, 105, 59, 59, 115, 115, 59, 59, 98, 112, 59, 115, 59, 59, + 111, 111, 116, 116, 59, 59, 59, 100, 111, 111, 116, 116, 59, 59, 117, 117, + 108, 108, 116, 116, 59, 59, 69, 101, 59, 59, 59, 59, 108, 108, 117, 117, + 115, 115, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, 101, 117, 116, 116, + 59, 110, 113, 113, 59, 113, 59, 59, 101, 101, 113, 113, 59, 113, 59, 59, + 109, 109, 59, 59, 98, 112, 59, 59, 59, 59, 99, 99, 59, 115, 112, 112, + 112, 112, 114, 114, 111, 111, 120, 120, 59, 59, 117, 117, 114, 114, 108, 108, + 121, 121, 101, 101, 113, 113, 59, 59, 113, 113, 59, 59, 97, 115, 112, 112, + 112, 112, 114, 114, 111, 111, 120, 120, 59, 59, 113, 113, 113, 113, 59, 59, + 105, 105, 109, 109, 59, 59, 105, 105, 109, 109, 59, 59, 59, 59, 103, 103, + 59, 59, 49, 115, 59, 59, 111, 115, 116, 116, 59, 59, 117, 117, 98, 98, + 59, 59, 59, 100, 111, 111, 116, 116, 59, 59, 115, 115, 111, 117, 108, 108, + 59, 59, 98, 98, 59, 59, 97, 97, 114, 114, 114, 114, 59, 59, 117, 117, + 108, 108, 116, 116, 59, 59, 69, 101, 59, 59, 59, 59, 108, 108, 117, 117, + 115, 115, 59, 59, 101, 117, 116, 116, 59, 110, 113, 113, 59, 113, 59, 59, + 101, 101, 113, 113, 59, 113, 59, 59, 109, 109, 59, 59, 98, 112, 59, 59, + 59, 59, 65, 110, 114, 114, 114, 114, 59, 59, 114, 114, 104, 114, 107, 107, + 59, 59, 59, 111, 119, 119, 59, 59, 119, 119, 97, 97, 114, 114, 59, 59, + 108, 108, 105, 105, 103, 103, 97, 119, 114, 117, 103, 103, 101, 101, 116, 116, + 59, 59, 59, 59, 114, 114, 107, 107, 59, 59, 97, 121, 114, 114, 111, 111, + 110, 110, 59, 59, 100, 100, 105, 105, 108, 108, 59, 59, 59, 59, 111, 111, + 116, 116, 59, 59, 108, 108, 114, 114, 101, 101, 99, 99, 59, 59, 114, 114, + 59, 59, 101, 111, 114, 116, 101, 101, 52, 102, 59, 59, 111, 111, 114, 114, + 101, 101, 59, 59, 97, 97, 59, 118, 121, 121, 109, 109, 59, 59, 59, 59, + 99, 110, 107, 107, 97, 115, 112, 112, 112, 112, 114, 114, 111, 111, 120, 120, + 59, 59, 105, 105, 109, 109, 59, 59, 115, 115, 112, 112, 59, 59, 97, 115, + 112, 112, 59, 59, 105, 105, 109, 109, 59, 59, 114, 114, 110, 110, 108, 110, + 100, 100, 101, 101, 59, 59, 101, 101, 115, 115, 59, 97, 114, 114, 59, 59, + 59, 59, 116, 116, 59, 59, 101, 115, 97, 97, 59, 59, 59, 102, 111, 111, + 116, 116, 59, 59, 105, 105, 114, 114, 59, 59, 59, 111, 114, 114, 107, 107, + 59, 59, 97, 97, 59, 59, 114, 114, 105, 105, 109, 109, 101, 101, 59, 59, + 97, 112, 100, 100, 101, 101, 59, 59, 97, 116, 110, 110, 103, 103, 108, 108, + 101, 101, 59, 114, 111, 111, 119, 119, 110, 110, 59, 59, 101, 101, 102, 102, + 116, 116, 59, 101, 113, 113, 59, 59, 59, 59, 105, 105, 103, 103, 104, 104, + 116, 116, 59, 101, 113, 113, 59, 59, 111, 111, 116, 116, 59, 59, 59, 59, + 105, 105, 110, 110, 117, 117, 115, 115, 59, 59, 108, 108, 117, 117, 115, 115, + 59, 59, 98, 98, 59, 59, 105, 105, 109, 109, 101, 101, 59, 59, 101, 101, + 122, 122, 105, 105, 117, 117, 109, 109, 59, 59, 99, 116, 114, 121, 59, 59, + 59, 59, 99, 99, 121, 121, 59, 59, 114, 114, 111, 111, 107, 107, 59, 59, + 105, 111, 120, 120, 116, 116, 59, 59, 104, 104, 101, 101, 97, 97, 100, 100, + 108, 114, 101, 101, 102, 102, 116, 116, 97, 97, 114, 114, 114, 114, 111, 111, + 119, 119, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 97, 97, 114, 114, + 114, 114, 111, 111, 119, 119, 59, 59, 65, 119, 114, 114, 114, 114, 59, 59, + 97, 97, 114, 114, 59, 59, 99, 114, 117, 117, 116, 116, 101, 101, 114, 114, + 59, 59, 114, 114, 99, 101, 121, 121, 59, 59, 118, 118, 101, 101, 59, 59, + 105, 121, 114, 114, 99, 99, 59, 59, 97, 104, 114, 114, 114, 114, 59, 59, + 108, 108, 97, 97, 99, 99, 59, 59, 97, 97, 114, 114, 59, 59, 105, 114, + 115, 115, 104, 104, 116, 116, 59, 59, 59, 59, 114, 114, 97, 97, 118, 118, + 101, 101, 97, 98, 114, 114, 108, 114, 59, 59, 59, 59, 108, 108, 107, 107, + 59, 59, 99, 116, 111, 114, 114, 114, 110, 110, 59, 101, 114, 114, 59, 59, + 111, 111, 112, 112, 59, 59, 114, 114, 105, 105, 59, 59, 97, 108, 99, 99, + 114, 114, 59, 59, 103, 112, 111, 111, 110, 110, 59, 59, 102, 102, 59, 59, + 97, 117, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 111, 111, 119, 119, + 110, 110, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 59, 59, 97, 97, + 114, 114, 112, 112, 111, 111, 111, 111, 110, 110, 108, 114, 101, 101, 102, 102, + 116, 116, 59, 59, 105, 105, 103, 103, 104, 104, 116, 116, 59, 59, 117, 117, + 115, 115, 59, 59, 105, 105, 59, 108, 59, 59, 111, 111, 110, 110, 59, 59, + 112, 112, 97, 97, 114, 114, 114, 114, 111, 111, 119, 119, 115, 115, 59, 59, + 99, 116, 111, 114, 114, 114, 110, 110, 59, 101, 114, 114, 59, 59, 111, 111, + 112, 112, 59, 59, 110, 110, 103, 103, 59, 59, 114, 114, 105, 105, 59, 59, + 99, 99, 114, 114, 59, 59, 100, 114, 111, 111, 116, 116, 59, 59, 108, 108, + 100, 100, 101, 101, 59, 59, 105, 105, 59, 102, 59, 59, 97, 109, 114, 114, + 114, 114, 59, 59, 108, 108, 97, 97, 110, 110, 103, 103, 108, 108, 101, 101, + 59, 59, 65, 122, 114, 114, 114, 114, 59, 59, 97, 97, 114, 114, 59, 118, + 59, 59, 97, 97, 115, 115, 104, 104, 59, 59, 110, 114, 103, 103, 114, 114, + 116, 116, 59, 59, 101, 116, 112, 112, 115, 115, 105, 105, 108, 108, 111, 111, + 110, 110, 59, 59, 97, 97, 112, 112, 112, 112, 97, 97, 59, 59, 111, 111, + 116, 116, 104, 104, 105, 105, 110, 110, 103, 103, 59, 59, 104, 114, 105, 105, + 59, 59, 59, 59, 111, 111, 112, 112, 116, 116, 111, 111, 59, 59, 59, 104, + 111, 111, 59, 59, 105, 117, 103, 103, 109, 109, 97, 97, 59, 59, 98, 112, + 115, 115, 101, 101, 116, 116, 110, 110, 101, 101, 113, 113, 59, 113, 59, 59, + 115, 115, 101, 101, 116, 116, 110, 110, 101, 101, 113, 113, 59, 113, 59, 59, + 104, 114, 101, 101, 116, 116, 97, 97, 59, 59, 105, 105, 97, 97, 110, 110, + 103, 103, 108, 108, 101, 101, 108, 114, 101, 101, 102, 102, 116, 116, 59, 59, + 105, 105, 103, 103, 104, 104, 116, 116, 59, 59, 121, 121, 59, 59, 97, 97, + 115, 115, 104, 104, 59, 59, 101, 114, 59, 101, 97, 97, 114, 114, 59, 59, + 113, 113, 59, 59, 108, 108, 105, 105, 112, 112, 59, 59, 98, 116, 97, 97, + 114, 114, 59, 59, 59, 59, 114, 114, 59, 59, 116, 116, 114, 114, 105, 105, + 59, 59, 115, 115, 117, 117, 98, 112, 59, 59, 59, 59, 112, 112, 102, 102, + 59, 59, 114, 114, 111, 111, 112, 112, 59, 59, 116, 116, 114, 114, 105, 105, + 59, 59, 99, 117, 114, 114, 59, 59, 98, 112, 110, 110, 69, 101, 59, 59, + 59, 59, 110, 110, 69, 101, 59, 59, 59, 59, 105, 105, 103, 103, 122, 122, + 97, 97, 103, 103, 59, 59, 99, 115, 105, 105, 114, 114, 99, 99, 59, 59, + 100, 105, 98, 103, 97, 97, 114, 114, 59, 59, 101, 101, 59, 113, 59, 59, + 101, 101, 114, 114, 112, 112, 59, 59, 114, 114, 59, 59, 112, 112, 102, 102, + 59, 59, 59, 59, 59, 101, 97, 97, 116, 116, 104, 104, 59, 59, 99, 99, + 114, 114, 59, 59, 99, 119, 97, 117, 112, 112, 59, 59, 114, 114, 99, 99, + 59, 59, 112, 112, 59, 59, 116, 116, 114, 114, 105, 105, 59, 59, 114, 114, + 59, 59, 65, 97, 114, 114, 114, 114, 59, 59, 114, 114, 114, 114, 59, 59, + 59, 59, 65, 97, 114, 114, 114, 114, 59, 59, 114, 114, 114, 114, 59, 59, + 97, 97, 112, 112, 59, 59, 105, 105, 115, 115, 59, 59, 100, 116, 111, 111, + 116, 116, 59, 59, 102, 108, 59, 59, 117, 117, 115, 115, 59, 59, 105, 105, + 109, 109, 101, 101, 59, 59, 65, 97, 114, 114, 114, 114, 59, 59, 114, 114, + 114, 114, 59, 59, 99, 113, 114, 114, 59, 59, 99, 99, 117, 117, 112, 112, + 59, 59, 112, 116, 108, 108, 117, 117, 115, 115, 59, 59, 114, 114, 105, 105, + 59, 59, 101, 101, 101, 101, 59, 59, 101, 101, 100, 100, 103, 103, 101, 101, + 59, 59, 97, 117, 99, 99, 117, 121, 116, 116, 101, 101, 59, 59, 105, 121, + 114, 114, 99, 99, 59, 59, 59, 59, 110, 110, 114, 114, 59, 59, 99, 99, + 121, 121, 59, 59, 112, 112, 102, 102, 59, 59, 99, 99, 114, 114, 59, 59, + 99, 109, 121, 121, 59, 59, 108, 108, 97, 119, 99, 99, 117, 117, 116, 116, + 101, 101, 59, 59, 97, 121, 114, 114, 111, 111, 110, 110, 59, 59, 59, 59, + 111, 111, 116, 116, 59, 59, 101, 116, 116, 116, 114, 114, 102, 102, 59, 59, + 97, 97, 59, 59, 114, 114, 59, 59, 99, 99, 121, 121, 59, 59, 103, 103, + 114, 114, 97, 97, 114, 114, 114, 114, 59, 59, 112, 112, 102, 102, 59, 59, + 99, 99, 114, 114, 59, 59, 106, 110, 59, 59, 106, 106, 59, 59, 65, 122, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 101, 59, 115, 59, 59, 59, 59, 59, 111, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 114, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 114, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 110, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 108, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 100, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 0 +}; + +static const char _char_ref_key_spans[] = { + 0, 49, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 10, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 17, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 21, 16, 1, + 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 1, 1, 1, 23, 1, 1, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 15, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 17, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 17, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 10, 1, 1, 43, 1, 14, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 13, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9, 1, 1, 1, 48, 53, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 13, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 25, + 1, 1, 1, 1, 1, 1, 58, 1, + 1, 1, 1, 6, 11, 1, 1, 1, + 1, 1, 1, 1, 20, 1, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8, + 1, 1, 11, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 20, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, + 1, 1, 1, 1, 1, 1, 1, 1, + 11, 1, 1, 20, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 20, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 33, + 1, 1, 1, 1, 27, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 18, 1, 1, 1, 1, 1, 1, + 43, 1, 1, 1, 1, 1, 1, 1, + 25, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 10, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 26, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 1, 1, 1, 1, 1, 8, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 17, 1, 1, + 1, 1, 1, 1, 1, 1, 4, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 43, 1, 1, 1, 1, + 1, 1, 42, 1, 1, 1, 1, 1, + 1, 21, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 16, 1, 1, 1, 1, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 53, 1, 1, 1, 1, 1, 18, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 49, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 17, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 54, + 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, + 43, 12, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 19, 17, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 44, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 21, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 43, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 25, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 14, 1, + 50, 5, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 24, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 22, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 14, 1, 28, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 11, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 19, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8, 1, 1, 1, 1, 1, + 1, 1, 1, 8, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 10, + 1, 39, 1, 1, 1, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 18, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 21, 1, 1, + 1, 1, 9, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 44, 1, 1, 1, + 1, 1, 1, 1, 1, 25, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 1, 1, 10, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 12, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 51, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 28, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 13, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 26, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 26, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 14, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 11, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 26, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 25, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 11, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 11, 1, 1, 1, 1, 1, + 15, 1, 1, 1, 11, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 26, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 11, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 26, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 50, 1, 1, 1, 1, 1, + 1, 1, 1, 17, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 9, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 14, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 18, 1, 1, 1, + 1, 7, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 19, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 53, 1, + 1, 1, 1, 1, 26, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 1, 1, 7, 1, 1, 1, 31, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 52, 1, 1, 1, 1, 1, 16, + 1, 1, 1, 1, 1, 1, 1, 58, + 1, 1, 25, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 60, 1, 1, 1, + 1, 17, 6, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 33, + 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 18, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 1, + 1, 14, 1, 28, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 11, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 19, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 1, + 1, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 6, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 46, + 33, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 63, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 1, 1, 1, 27, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 15, 1, 1, 1, + 11, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 15, 57, 1, 1, + 11, 1, 1, 1, 1, 1, 6, 1, + 1, 1, 1, 26, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 44, 1, 1, 1, + 1, 1, 1, 1, 28, 1, 1, 1, + 1, 1, 20, 1, 1, 25, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 12, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 26, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 18, 1, 1, 1, 1, + 1, 1, 21, 16, 1, 1, 1, 1, + 53, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 17, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6, + 1, 1, 15, 18, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 22, 1, 1, 1, 1, 10, + 1, 1, 1, 1, 1, 51, 1, 1, + 1, 1, 10, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 50, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 50, + 1, 14, 1, 24, 1, 1, 1, 47, + 1, 1, 1, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 17, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 14, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 44, 1, 1, 1, 1, 1, 1, + 1, 1, 25, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 23, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 63, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 56, + 1, 1, 1, 1, 1, 12, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 16, 10, 1, 1, 1, 1, 4, 60, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 64, 1, 1, 1, 1, 1, + 39, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 42, 1, 5, + 1, 1, 1, 1, 1, 1, 1, 10, + 1, 1, 1, 1, 1, 54, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 43, 1, 1, 1, 1, + 1, 23, 1, 1, 1, 1, 1, 43, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 40, 1, 1, 1, 16, 1, + 17, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 43, 1, 1, 2, 1, + 1, 1, 1, 1, 45, 1, 1, 1, + 1, 58, 1, 1, 1, 1, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 18, + 1, 1, 1, 43, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 23, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 21, 21, 1, 1, 1, + 1, 1, 1, 1, 17, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 15, 12, 1, 9, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 56, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 1, 1, 1, 1, 1, + 1, 1, 11, 55, 1, 1, 1, 1, + 1, 1, 9, 1, 1, 58, 1, 1, + 1, 1, 1, 1, 1, 51, 39, 1, + 1, 1, 1, 59, 1, 1, 1, 1, + 39, 1, 1, 1, 1, 56, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 1, 1, 1, 1, 59, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 1, 1, 1, 1, 56, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 13, + 1, 1, 1, 1, 1, 1, 43, 1, + 1, 46, 1, 1, 1, 1, 1, 2, + 1, 43, 1, 1, 1, 43, 1, 55, + 1, 25, 16, 1, 1, 1, 1, 57, + 1, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 1, 1, 1, 1, + 1, 11, 1, 1, 1, 1, 21, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 57, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7, 1, 1, 1, 1, + 51, 1, 1, 1, 1, 1, 1, 57, + 1, 50, 1, 1, 1, 4, 1, 1, + 1, 1, 7, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 19, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 59, 1, 1, 1, 5, 1, + 1, 43, 55, 1, 4, 1, 58, 1, + 50, 1, 1, 1, 12, 1, 1, 1, + 1, 1, 1, 1, 3, 42, 1, 1, + 1, 1, 1, 1, 20, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 1, + 1, 1, 19, 1, 1, 15, 43, 1, + 43, 1, 1, 1, 1, 1, 20, 1, + 1, 1, 7, 1, 1, 4, 1, 1, + 1, 1, 1, 1, 1, 54, 1, 57, + 1, 1, 1, 1, 1, 21, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 22, 1, 1, 51, 1, 1, 19, 1, + 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 58, 1, 1, 1, 1, 1, 1, 13, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 25, 1, + 1, 1, 1, 1, 53, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 1, 1, 1, 1, + 1, 1, 7, 1, 1, 22, 1, 57, + 1, 1, 57, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 53, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 1, 1, 1, 1, 1, + 1, 12, 1, 1, 1, 1, 1, 1, + 57, 1, 42, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 1, 1, 1, + 18, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 1, 1, 1, 1, 44, + 1, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 53, + 44, 1, 1, 1, 1, 1, 17, 1, + 1, 1, 1, 1, 1, 1, 25, 1, + 1, 1, 1, 1, 41, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 47, 1, + 1, 1, 1, 57, 1, 1, 1, 42, + 1, 1, 1, 57, 1, 1, 1, 1, + 1, 1, 1, 42, 1, 1, 1, 19, + 1, 1, 1, 1, 1, 60, 1, 1, + 1, 1, 1, 11, 2, 1, 1, 13, + 1, 1, 1, 10, 1, 1, 1, 1, + 1, 19, 1, 57, 1, 1, 1, 1, + 1, 1, 60, 1, 1, 1, 1, 20, + 7, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 1, 1, 1, 6, 1, + 1, 1, 1, 1, 1, 1, 9, 1, + 1, 1, 1, 1, 1, 1, 10, 1, + 1, 1, 1, 1, 1, 1, 1, 30, + 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 8, 1, + 6, 1, 1, 1, 14, 1, 1, 1, + 1, 1, 11, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 19, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 10, 1, 1, 1, 1, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 20, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3, 1, 1, 11, 1, 1, 1, 60, + 1, 1, 1, 1, 1, 1, 1, 1, + 15, 17, 7, 7, 1, 1, 1, 1, + 3, 1, 1, 5, 1, 1, 1, 1, + 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 50, 50, 1, + 14, 1, 1, 1, 1, 1, 1, 42, + 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 1, 1, 1, 1, 57, + 1, 57, 1, 1, 1, 1, 1, 1, + 50, 1, 1, 1, 1, 53, 50, 1, + 43, 1, 1, 1, 1, 45, 1, 1, + 1, 1, 1, 1, 1, 1, 48, 1, + 1, 1, 47, 1, 1, 54, 1, 1, + 1, 1, 55, 55, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7, + 1, 1, 1, 50, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 19, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 10, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 1, 1, 10, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 15, 1, 1, + 1, 61, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 18, 1, 1, + 1, 59, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 19, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 7, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 15, 1, 1, 1, 1, 1, 1, + 1, 1, 21, 1, 1, 1, 1, 63, + 1, 1, 1, 22, 1, 1, 1, 1, + 13, 1, 1, 1, 1, 1, 1, 53, + 6, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 16, 18, 1, 1, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 58, 1, + 1, 1, 1, 1, 1, 58, 1, 1, + 1, 1, 1, 1, 1, 54, 1, 1, + 1, 12, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 60, 1, 1, 1, 1, 60, 1, + 1, 47, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 19, 17, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 19, 1, 1, + 1, 60, 1, 21, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 54, 20, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 45, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 1, + 1, 1, 1, 1, 58, 44, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 1, 1, + 1, 57, 1, 18, 1, 1, 1, 1, + 1, 1, 11, 1, 7, 1, 1, 15, + 1, 1, 18, 1, 1, 25, 1, 1, + 1, 1, 6, 1, 1, 1, 1, 1, + 1, 1, 1, 17, 1, 1, 1, 1, + 56, 1, 18, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 20, 1, 1, 1, 1, 58, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 19, 1, 1, + 1, 1, 57, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 57, 1, 1, 1, 1, 1, 1, + 57, 1, 1, 1, 1, 53, 56, 1, + 43, 1, 1, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 10, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, + 2, 1, 18, 1, 50, 1, 1, 1, + 1, 1, 1, 1, 58, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 1, 1, 1, 1, 39, 1, 1, + 1, 1, 47, 1, 1, 54, 1, 1, + 1, 1, 55, 55, 1, 1, 1, 1, + 26, 5, 1, 1, 1, 1, 1, 1, + 1, 1, 7, 1, 1, 1, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 12, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 1, + 1, 44, 1, 1, 1, 1, 1, 1, + 1, 50, 1, 1, 20, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 42, 1, 1, 1, 1, 1, 20, 1, + 1, 1, 1, 1, 1, 1, 1, 45, + 1, 1, 20, 1, 1, 56, 1, 1, + 1, 1, 1, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 26, 1, 1, 1, 44, + 1, 1, 1, 18, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 10, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 50, + 1, 1, 1, 1, 16, 1, 16, 1, + 43, 1, 1, 1, 57, 1, 1, 59, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 1, 42, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 42, 1, + 59, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 51, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 49, 14, 1, + 60, 1, 16, 1, 1, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 60, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 33, 1, 1, 1, 1, 1, + 1, 1, 1, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 54, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 39, 1, 57, 1, 3, 1, 1, + 1, 43, 1, 25, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 42, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 62, 1, 1, 1, 1, 11, + 1, 1, 53, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 57, 1, 1, + 1, 48, 1, 57, 57, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 56, + 1, 48, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 42, 1, 1, 1, + 1, 1, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 57, 1, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 1, 1, 1, 1, 1, 57, 1, 1, + 1, 1, 56, 1, 43, 1, 1, 1, + 1, 5, 1, 1, 1, 60, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 60, + 3, 1, 1, 1, 18, 1, 58, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 43, 1, 1, 1, + 41, 43, 1, 1, 52, 1, 1, 1, + 1, 1, 61, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 43, 1, 19, 56, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 55, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 15, 1, 1, 1, + 1, 15, 57, 1, 1, 1, 1, 43, + 1, 55, 1, 1, 43, 1, 1, 57, + 1, 1, 1, 1, 43, 1, 55, 1, + 12, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 43, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 51, 57, 1, 1, + 1, 1, 1, 48, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 16, 1, 1, 1, 1, 1, + 1, 1, 52, 1, 1, 1, 1, 56, + 1, 1, 1, 52, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 1, 1, 11, 1, 1, 53, 1, + 1, 1, 1, 1, 1, 36, 1, 17, + 1, 1, 1, 1, 1, 17, 1, 41, + 1, 19, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 16, 1, 1, + 1, 1, 6, 1, 1, 1, 1, 1, + 1, 12, 1, 1, 1, 1, 1, 1, + 1, 20, 1, 1, 1, 10, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9, 1, 1, 1, 1, 1, 1, 12, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 12, 1, 1, 1, 1, + 1, 1, 1, 1, 60, 1, 1, 1, + 51, 1, 53, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 13, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 39, + 1, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 58, 1, 1, 1, 1, 4, + 1, 1, 1, 1, 1, 1, 1, 18, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 60, 1, 1, 1, 1, 1, 1, + 1, 1, 60, 1, 1, 1, 1, 1, + 1, 1, 1, 21, 1, 9, 1, 46, + 1, 1, 1, 1, 58, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 13, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 59, 1, 1, 1, + 1, 1, 1, 41, 57, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 19, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 47, 1, 1, 1, 1, 1, 1, 13, + 1, 19, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 58, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 16, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 15, 1, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 56, 20, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 18, + 17, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 50, + 1, 1, 1, 1, 1, 1, 1, 61, + 1, 1, 44, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9, 1, 1, 1, + 1, 52, 1, 1, 1, 1, 18, 1, + 1, 1, 1, 1, 1, 11, 1, 7, + 1, 1, 15, 1, 1, 18, 1, 1, + 25, 1, 1, 1, 1, 6, 1, 1, + 1, 1, 1, 1, 1, 1, 17, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 56, 1, 1, 1, 7, 1, 57, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 10, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 1, 18, 1, 50, + 1, 60, 1, 13, 1, 1, 20, 1, + 1, 1, 1, 58, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 13, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 39, 1, + 1, 1, 1, 1, 1, 1, 1, 20, + 5, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 16, 1, 45, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 17, 1, 1, 1, 1, + 1, 1, 1, 20, 1, 1, 56, 1, + 11, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 50, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 26, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 63, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 42, 1, 1, 1, + 1, 1, 1, 47, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 43, 1, + 1, 56, 1, 1, 1, 1, 11, 1, + 1, 53, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6, 1, 1, 1, + 1, 1, 1, 1, 1, 53, 1, 1, + 1, 25, 1, 1, 1, 18, 1, 1, + 1, 1, 1, 1, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 60, 1, 1, 56, 1, + 1, 1, 55, 1, 11, 1, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 20, 8, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9, 1, 1, 1, 43, + 57, 1, 11, 1, 1, 1, 1, 40, + 39, 1, 1, 1, 1, 1, 15, 1, + 1, 59, 1, 1, 1, 1, 19, 21, + 1, 57, 1, 1, 57, 1, 1, 15, + 57, 1, 1, 1, 43, 1, 1, 57, + 1, 1, 1, 43, 1, 1, 44, 1, + 2, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 18, + 1, 44, 1, 14, 1, 1, 1, 1, + 12, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 15, 57, 1, + 1, 1, 1, 42, 1, 1, 1, 1, + 1, 1, 1, 33, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 17, 1, + 52, 1, 55, 1, 1, 1, 55, 1, + 1, 1, 15, 1, 1, 1, 57, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 19, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 67, 1, 5, 1, 1, 1, 1, + 1, 42, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 33, 1, 1, 1, 1, + 1, 1, 17, 1, 52, 1, 55, 1, + 1, 1, 55, 1, 1, 1, 15, 1, + 1, 46, 1, 1, 1, 1, 11, 1, + 1, 53, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 23, 4, 1, 1, 1, + 1, 1, 1, 1, 1, 25, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 11, 3, 1, 51, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, + 12, 1, 19, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 19, + 1, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 39, 1, 1, + 1, 1, 1, 15, 1, 1, 44, 1, + 1, 1, 1, 1, 1, 53, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 16, 1, 1, 1, 20, 1, 1, 1, + 1, 56, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 18, 8, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 55, 1, 1, 1, + 1, 1, 1, 16, 1, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, + 17, 1, 1, 1, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 10, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 7, 1, 1, 1, 1, + 1, 18, 4, 1, 1, 43, 1, 1, + 1, 1, 1, 1, 1, 1, 12, 1, + 1, 1, 10, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 50, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 4, 1, 1, 43, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 1, + 1, 1, 1, 1, 44, 1, 13, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 58, 1, 1, 1, 1, 1, 60, + 1, 1, 1, 1, 1, 5, 1, 1, + 1, 1, 16, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, + 1, 1, 1, 1, 1, 1, 1, 46, + 1, 1, 13, 1, 1, 1, 1, 15, + 1, 1, 1, 1, 1, 1, 55, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 11, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 14, 43, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 19, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 19, 1, 1, 15, 1, 33, 1, + 1, 1, 33, 1, 1, 1, 1, 1, + 1, 1, 1, 17, 1, 1, 1, 1, + 6, 6, 1, 1, 1, 1, 55, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 43, 1, 1, 1, 1, 1, + 1, 1, 21, 21, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 33, 1, 1, 1, 1, 1, 1, + 1, 33, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 17, 1, + 1, 1, 7, 1, 1, 1, 1, 1, + 1, 1, 1, 33, 1, 1, 1, 1, + 1, 1, 15, 1, 1, 1, 1, 1, + 1, 5, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 21, 1, 5, 1, 1, 1, 17, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 11, 1, 1, 1, 23, 1, 1, 1, + 1, 1, 25, 1, 1, 1, 1, 1, + 1, 1, 1, 16, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5, 1, 1, 1, 58, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 43, 57, 1, 1, 53, 1, 1, 1, + 1, 1, 1, 1, 1, 56, 1, 1, + 1, 1, 1, 1, 1, 56, 1, 1, + 1, 1, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 42, 1, 1, 1, 1, 1, 1, + 1, 1 +}; + +static const unsigned short _char_ref_index_offsets[] = { + 0, 0, 50, 52, 54, 56, 58, 60, + 62, 64, 66, 68, 70, 72, 74, 76, + 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 118, 120, 122, 124, + 126, 128, 130, 132, 143, 145, 147, 149, + 151, 153, 155, 157, 159, 161, 163, 165, + 167, 169, 171, 173, 175, 177, 179, 181, + 183, 201, 203, 205, 207, 209, 211, 213, + 215, 217, 219, 221, 223, 225, 247, 264, + 266, 268, 270, 272, 274, 276, 278, 281, + 283, 285, 287, 289, 291, 293, 312, 314, + 316, 318, 320, 322, 324, 326, 328, 330, + 332, 334, 336, 338, 340, 342, 344, 346, + 348, 350, 352, 354, 356, 358, 360, 362, + 364, 366, 368, 370, 372, 374, 376, 423, + 425, 427, 429, 431, 433, 457, 459, 461, + 463, 465, 513, 515, 517, 519, 521, 523, + 525, 527, 529, 531, 533, 535, 537, 539, + 541, 543, 545, 547, 549, 551, 553, 555, + 557, 573, 575, 577, 579, 581, 583, 585, + 587, 589, 591, 593, 595, 597, 599, 601, + 603, 605, 607, 609, 621, 623, 625, 627, + 629, 631, 633, 635, 637, 639, 641, 643, + 645, 647, 649, 651, 653, 655, 657, 659, + 661, 679, 681, 683, 685, 687, 689, 691, + 693, 695, 697, 699, 701, 703, 705, 707, + 709, 711, 713, 715, 733, 735, 737, 739, + 741, 743, 745, 747, 749, 751, 753, 755, + 757, 759, 761, 763, 765, 767, 769, 771, + 773, 775, 777, 779, 781, 783, 785, 787, + 802, 804, 806, 808, 810, 812, 814, 816, + 818, 820, 822, 824, 826, 828, 830, 832, + 834, 845, 847, 849, 893, 895, 910, 912, + 914, 916, 918, 920, 922, 924, 926, 928, + 930, 932, 934, 936, 938, 940, 942, 944, + 946, 948, 950, 952, 966, 968, 970, 972, + 974, 976, 978, 980, 982, 984, 986, 988, + 990, 992, 994, 996, 998, 1000, 1002, 1004, + 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020, + 1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, + 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052, + 1054, 1064, 1066, 1068, 1070, 1119, 1173, 1175, + 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, + 1193, 1195, 1197, 1199, 1201, 1203, 1217, 1219, + 1221, 1223, 1225, 1227, 1229, 1231, 1233, 1235, + 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1332, + 1334, 1336, 1338, 1340, 1347, 1359, 1361, 1363, + 1365, 1367, 1369, 1371, 1373, 1394, 1396, 1398, + 1400, 1402, 1404, 1406, 1409, 1411, 1413, 1415, + 1417, 1419, 1421, 1423, 1425, 1427, 1429, 1431, + 1433, 1435, 1437, 1439, 1441, 1443, 1445, 1447, + 1449, 1451, 1453, 1455, 1457, 1459, 1461, 1463, + 1465, 1467, 1469, 1471, 1473, 1475, 1477, 1479, + 1488, 1490, 1492, 1504, 1506, 1508, 1510, 1512, + 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1547, + 1549, 1551, 1553, 1555, 1557, 1559, 1561, 1563, + 1565, 1567, 1569, 1571, 1573, 1575, 1577, 1579, + 1584, 1586, 1588, 1590, 1592, 1594, 1596, 1598, + 1600, 1612, 1614, 1616, 1637, 1639, 1641, 1643, + 1645, 1647, 1649, 1651, 1653, 1655, 1657, 1659, + 1661, 1663, 1665, 1667, 1669, 1671, 1673, 1675, + 1677, 1685, 1687, 1689, 1691, 1710, 1712, 1714, + 1716, 1718, 1720, 1722, 1724, 1726, 1728, 1730, + 1732, 1734, 1736, 1738, 1740, 1742, 1744, 1746, + 1748, 1750, 1752, 1754, 1756, 1758, 1760, 1762, + 1764, 1766, 1768, 1789, 1791, 1793, 1795, 1797, + 1799, 1801, 1803, 1805, 1807, 1812, 1814, 1816, + 1818, 1820, 1822, 1824, 1826, 1828, 1830, 1832, + 1834, 1836, 1838, 1840, 1842, 1844, 1846, 1848, + 1850, 1852, 1854, 1856, 1858, 1860, 1862, 1864, + 1898, 1900, 1902, 1904, 1906, 1934, 1936, 1938, + 1940, 1942, 1944, 1946, 1948, 1950, 1952, 1954, + 1956, 1958, 1960, 1962, 1964, 1966, 1968, 1970, + 1976, 1978, 1980, 1982, 1984, 1986, 1988, 1990, + 1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, + 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022, + 2024, 2026, 2035, 2037, 2039, 2041, 2043, 2045, + 2047, 2049, 2053, 2055, 2057, 2059, 2061, 2063, + 2065, 2067, 2069, 2071, 2073, 2075, 2077, 2079, + 2081, 2090, 2092, 2094, 2096, 2098, 2100, 2108, + 2110, 2112, 2114, 2116, 2118, 2120, 2122, 2124, + 2126, 2128, 2147, 2149, 2151, 2153, 2155, 2157, + 2159, 2203, 2205, 2207, 2209, 2211, 2213, 2215, + 2217, 2243, 2245, 2247, 2249, 2251, 2253, 2255, + 2257, 2259, 2261, 2263, 2265, 2267, 2269, 2271, + 2273, 2275, 2277, 2279, 2281, 2283, 2285, 2287, + 2304, 2306, 2308, 2310, 2312, 2314, 2319, 2321, + 2323, 2325, 2327, 2329, 2331, 2333, 2335, 2337, + 2339, 2341, 2343, 2345, 2347, 2349, 2351, 2353, + 2355, 2357, 2359, 2361, 2363, 2365, 2367, 2369, + 2371, 2382, 2384, 2386, 2388, 2390, 2392, 2394, + 2396, 2398, 2400, 2402, 2404, 2406, 2416, 2418, + 2445, 2447, 2449, 2451, 2453, 2455, 2457, 2459, + 2461, 2463, 2465, 2467, 2469, 2471, 2479, 2481, + 2483, 2485, 2487, 2489, 2491, 2493, 2495, 2504, + 2506, 2508, 2510, 2512, 2514, 2516, 2518, 2520, + 2522, 2524, 2526, 2528, 2530, 2532, 2550, 2552, + 2554, 2556, 2558, 2560, 2562, 2564, 2566, 2571, + 2573, 2575, 2577, 2579, 2581, 2583, 2585, 2587, + 2589, 2591, 2593, 2595, 2597, 2599, 2601, 2603, + 2605, 2607, 2609, 2611, 2613, 2615, 2617, 2619, + 2621, 2623, 2630, 2632, 2634, 2636, 2638, 2640, + 2642, 2644, 2646, 2648, 2650, 2652, 2654, 2656, + 2658, 2660, 2662, 2664, 2708, 2710, 2712, 2714, + 2716, 2718, 2720, 2763, 2765, 2767, 2769, 2771, + 2773, 2775, 2797, 2799, 2801, 2803, 2805, 2807, + 2809, 2811, 2813, 2815, 2817, 2819, 2821, 2823, + 2825, 2827, 2829, 2831, 2833, 2835, 2837, 2839, + 2841, 2858, 2860, 2862, 2864, 2866, 2885, 2887, + 2889, 2891, 2893, 2895, 2897, 2899, 2901, 2903, + 2905, 2907, 2909, 2911, 2913, 2915, 2917, 2919, + 2921, 2923, 2925, 2927, 2929, 2931, 2933, 2935, + 2937, 2939, 2941, 2943, 2945, 2947, 2949, 2951, + 2953, 2955, 2957, 2959, 2961, 2963, 2965, 2967, + 2969, 2971, 3025, 3027, 3029, 3031, 3033, 3035, + 3054, 3056, 3058, 3060, 3062, 3064, 3066, 3068, + 3070, 3072, 3074, 3076, 3078, 3080, 3082, 3084, + 3086, 3088, 3090, 3092, 3094, 3096, 3100, 3102, + 3104, 3106, 3108, 3110, 3112, 3114, 3116, 3118, + 3120, 3122, 3124, 3126, 3128, 3147, 3149, 3151, + 3153, 3155, 3157, 3159, 3161, 3163, 3166, 3168, + 3170, 3172, 3174, 3176, 3178, 3180, 3182, 3184, + 3186, 3188, 3190, 3192, 3242, 3244, 3246, 3248, + 3250, 3252, 3254, 3256, 3258, 3260, 3262, 3264, + 3266, 3268, 3270, 3288, 3290, 3292, 3294, 3296, + 3298, 3300, 3302, 3304, 3306, 3308, 3310, 3312, + 3367, 3373, 3375, 3377, 3379, 3381, 3383, 3385, + 3387, 3389, 3391, 3393, 3395, 3397, 3399, 3401, + 3405, 3449, 3462, 3464, 3466, 3468, 3470, 3472, + 3474, 3476, 3478, 3480, 3482, 3484, 3486, 3488, + 3490, 3492, 3494, 3496, 3498, 3517, 3519, 3521, + 3523, 3525, 3527, 3529, 3531, 3533, 3535, 3537, + 3552, 3554, 3556, 3558, 3560, 3562, 3564, 3566, + 3568, 3570, 3572, 3574, 3576, 3578, 3580, 3582, + 3586, 3588, 3590, 3592, 3594, 3614, 3632, 3634, + 3636, 3638, 3640, 3642, 3644, 3646, 3648, 3650, + 3654, 3656, 3658, 3660, 3662, 3664, 3666, 3668, + 3670, 3672, 3674, 3719, 3721, 3723, 3725, 3727, + 3729, 3731, 3733, 3735, 3737, 3739, 3761, 3763, + 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, + 3781, 3783, 3785, 3787, 3831, 3833, 3835, 3837, + 3854, 3856, 3858, 3860, 3862, 3864, 3866, 3868, + 3870, 3872, 3874, 3876, 3878, 3880, 3882, 3884, + 3886, 3888, 3890, 3892, 3894, 3920, 3922, 3924, + 3926, 3928, 3930, 3932, 3934, 3936, 3938, 3953, + 3955, 4006, 4012, 4014, 4016, 4018, 4020, 4022, + 4024, 4026, 4028, 4030, 4032, 4034, 4036, 4038, + 4040, 4065, 4067, 4069, 4071, 4073, 4075, 4077, + 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, + 4095, 4097, 4099, 4101, 4103, 4105, 4107, 4111, + 4113, 4115, 4117, 4119, 4121, 4123, 4125, 4127, + 4129, 4131, 4133, 4135, 4139, 4141, 4143, 4145, + 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, + 4163, 4165, 4167, 4176, 4178, 4180, 4182, 4184, + 4186, 4188, 4190, 4192, 4194, 4196, 4198, 4200, + 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, + 4239, 4241, 4243, 4245, 4260, 4262, 4291, 4293, + 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, + 4311, 4313, 4315, 4317, 4319, 4321, 4323, 4325, + 4337, 4339, 4341, 4343, 4345, 4347, 4349, 4351, + 4353, 4355, 4375, 4377, 4379, 4381, 4383, 4385, + 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, + 4403, 4405, 4407, 4409, 4411, 4413, 4415, 4417, + 4419, 4421, 4423, 4432, 4434, 4436, 4438, 4440, + 4442, 4444, 4446, 4448, 4457, 4459, 4461, 4463, + 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, + 4481, 4483, 4485, 4487, 4489, 4491, 4493, 4495, + 4512, 4514, 4516, 4518, 4520, 4522, 4524, 4526, + 4528, 4530, 4532, 4534, 4536, 4538, 4540, 4542, + 4544, 4546, 4548, 4550, 4552, 4554, 4556, 4558, + 4560, 4562, 4564, 4566, 4568, 4570, 4572, 4574, + 4576, 4578, 4580, 4582, 4584, 4586, 4588, 4590, + 4592, 4594, 4596, 4598, 4600, 4602, 4604, 4606, + 4608, 4610, 4654, 4656, 4658, 4660, 4662, 4664, + 4666, 4668, 4670, 4672, 4674, 4676, 4678, 4680, + 4691, 4693, 4733, 4735, 4737, 4739, 4758, 4760, + 4762, 4764, 4766, 4768, 4770, 4772, 4774, 4776, + 4778, 4780, 4782, 4784, 4786, 4788, 4790, 4792, + 4794, 4796, 4798, 4800, 4802, 4804, 4806, 4808, + 4810, 4812, 4814, 4833, 4835, 4837, 4839, 4841, + 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, + 4859, 4861, 4863, 4865, 4867, 4869, 4871, 4873, + 4875, 4877, 4879, 4881, 4883, 4885, 4887, 4889, + 4891, 4899, 4901, 4903, 4905, 4907, 4909, 4911, + 4913, 4915, 4917, 4919, 4921, 4923, 4925, 4927, + 4929, 4931, 4933, 4935, 4937, 4956, 4958, 4960, + 4962, 4964, 4966, 4968, 4970, 4972, 4994, 4996, + 4998, 5000, 5002, 5012, 5014, 5016, 5018, 5020, + 5022, 5024, 5026, 5028, 5030, 5032, 5034, 5036, + 5038, 5040, 5042, 5044, 5046, 5048, 5050, 5052, + 5054, 5056, 5058, 5060, 5062, 5064, 5066, 5068, + 5070, 5072, 5074, 5076, 5078, 5123, 5125, 5127, + 5129, 5131, 5133, 5135, 5137, 5139, 5165, 5167, + 5169, 5171, 5173, 5175, 5177, 5179, 5181, 5183, + 5201, 5203, 5205, 5207, 5209, 5211, 5222, 5224, + 5226, 5228, 5230, 5232, 5234, 5236, 5238, 5240, + 5242, 5244, 5246, 5248, 5261, 5263, 5265, 5267, + 5269, 5271, 5273, 5275, 5277, 5279, 5281, 5283, + 5285, 5287, 5289, 5291, 5293, 5295, 5297, 5299, + 5301, 5303, 5305, 5307, 5309, 5311, 5313, 5315, + 5317, 5319, 5326, 5328, 5330, 5332, 5334, 5336, + 5338, 5340, 5342, 5344, 5346, 5348, 5350, 5352, + 5354, 5356, 5358, 5360, 5362, 5364, 5366, 5368, + 5370, 5372, 5374, 5376, 5378, 5380, 5382, 5384, + 5436, 5438, 5440, 5442, 5444, 5446, 5448, 5450, + 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, + 5468, 5470, 5472, 5474, 5476, 5478, 5507, 5515, + 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, + 5533, 5535, 5537, 5539, 5541, 5543, 5545, 5547, + 5549, 5551, 5553, 5555, 5557, 5559, 5561, 5563, + 5565, 5567, 5569, 5571, 5573, 5575, 5589, 5591, + 5593, 5595, 5597, 5599, 5601, 5603, 5605, 5607, + 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, + 5650, 5652, 5654, 5656, 5658, 5660, 5662, 5664, + 5666, 5693, 5695, 5697, 5699, 5701, 5703, 5705, + 5707, 5709, 5711, 5713, 5715, 5717, 5719, 5721, + 5723, 5725, 5727, 5729, 5731, 5733, 5735, 5737, + 5739, 5741, 5743, 5745, 5747, 5749, 5751, 5753, + 5755, 5757, 5759, 5761, 5763, 5765, 5767, 5769, + 5771, 5773, 5775, 5777, 5779, 5782, 5784, 5786, + 5788, 5790, 5792, 5794, 5796, 5798, 5800, 5802, + 5804, 5806, 5808, 5810, 5825, 5827, 5829, 5831, + 5833, 5835, 5837, 5839, 5841, 5843, 5855, 5857, + 5859, 5861, 5863, 5865, 5867, 5869, 5871, 5873, + 5900, 5902, 5904, 5906, 5908, 5910, 5912, 5914, + 5916, 5918, 5920, 5922, 5924, 5926, 5928, 5930, + 5932, 5934, 5936, 5938, 5940, 5942, 5944, 5946, + 5948, 5950, 5952, 5954, 5956, 5958, 5960, 5962, + 5964, 5966, 5968, 5970, 5972, 5979, 5981, 5983, + 5985, 5987, 5989, 5991, 5993, 5995, 5997, 5999, + 6001, 6003, 6005, 6007, 6009, 6011, 6013, 6015, + 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, + 6033, 6035, 6037, 6063, 6065, 6067, 6069, 6071, + 6073, 6075, 6077, 6079, 6081, 6083, 6085, 6087, + 6089, 6091, 6093, 6099, 6101, 6103, 6105, 6107, + 6109, 6111, 6113, 6115, 6117, 6119, 6121, 6123, + 6125, 6127, 6129, 6131, 6133, 6135, 6137, 6139, + 6141, 6143, 6145, 6147, 6159, 6161, 6163, 6165, + 6167, 6169, 6171, 6173, 6175, 6181, 6183, 6185, + 6187, 6189, 6191, 6193, 6209, 6211, 6213, 6215, + 6227, 6229, 6231, 6233, 6235, 6237, 6239, 6241, + 6243, 6245, 6247, 6259, 6261, 6263, 6265, 6267, + 6269, 6285, 6287, 6289, 6291, 6303, 6305, 6307, + 6309, 6311, 6313, 6315, 6317, 6319, 6321, 6323, + 6350, 6352, 6354, 6356, 6358, 6360, 6362, 6364, + 6366, 6368, 6370, 6372, 6374, 6376, 6378, 6380, + 6382, 6384, 6386, 6388, 6390, 6392, 6394, 6396, + 6398, 6400, 6412, 6414, 6416, 6418, 6420, 6422, + 6424, 6426, 6428, 6430, 6457, 6459, 6461, 6463, + 6465, 6467, 6469, 6471, 6473, 6475, 6477, 6479, + 6481, 6483, 6485, 6487, 6489, 6491, 6493, 6495, + 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, + 6513, 6515, 6517, 6519, 6521, 6523, 6525, 6527, + 6529, 6531, 6533, 6584, 6586, 6588, 6590, 6592, + 6594, 6596, 6598, 6600, 6618, 6620, 6622, 6624, + 6626, 6628, 6630, 6632, 6634, 6636, 6638, 6640, + 6642, 6644, 6646, 6656, 6658, 6660, 6662, 6664, + 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, + 6682, 6684, 6686, 6688, 6690, 6692, 6694, 6696, + 6698, 6713, 6715, 6717, 6719, 6721, 6723, 6725, + 6727, 6729, 6731, 6733, 6735, 6737, 6739, 6741, + 6743, 6745, 6747, 6758, 6760, 6762, 6764, 6766, + 6768, 6770, 6773, 6775, 6777, 6779, 6781, 6783, + 6785, 6787, 6789, 6791, 6807, 6826, 6828, 6830, + 6832, 6834, 6842, 6844, 6846, 6848, 6850, 6852, + 6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, + 6870, 6872, 6892, 6894, 6896, 6898, 6900, 6902, + 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, + 6920, 6922, 6924, 6926, 6928, 6930, 6932, 6934, + 6936, 6945, 6947, 6949, 6951, 6953, 6955, 6957, + 6959, 6961, 6963, 6965, 6967, 6969, 6971, 7025, + 7027, 7029, 7031, 7033, 7035, 7062, 7064, 7066, + 7068, 7070, 7072, 7074, 7076, 7078, 7080, 7082, + 7084, 7086, 7088, 7090, 7092, 7094, 7096, 7098, + 7100, 7102, 7104, 7106, 7108, 7122, 7124, 7126, + 7128, 7130, 7132, 7134, 7136, 7138, 7140, 7142, + 7182, 7184, 7186, 7194, 7196, 7198, 7200, 7232, + 7234, 7236, 7238, 7240, 7242, 7244, 7246, 7248, + 7250, 7252, 7305, 7307, 7309, 7311, 7313, 7315, + 7332, 7334, 7336, 7338, 7340, 7342, 7344, 7346, + 7405, 7407, 7409, 7435, 7437, 7439, 7441, 7443, + 7445, 7447, 7449, 7451, 7453, 7514, 7516, 7518, + 7520, 7522, 7540, 7547, 7549, 7551, 7553, 7555, + 7557, 7559, 7561, 7563, 7565, 7567, 7569, 7571, + 7573, 7575, 7577, 7579, 7581, 7583, 7585, 7587, + 7589, 7591, 7593, 7595, 7597, 7599, 7601, 7603, + 7605, 7607, 7609, 7611, 7613, 7615, 7617, 7619, + 7653, 7659, 7661, 7663, 7665, 7667, 7669, 7671, + 7673, 7675, 7677, 7679, 7681, 7683, 7685, 7687, + 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, + 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, + 7738, 7740, 7742, 7744, 7746, 7750, 7752, 7754, + 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, + 7772, 7774, 7778, 7780, 7782, 7784, 7786, 7788, + 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, + 7806, 7815, 7817, 7819, 7821, 7823, 7825, 7827, + 7829, 7831, 7846, 7848, 7877, 7879, 7881, 7883, + 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, + 7901, 7903, 7905, 7907, 7909, 7911, 7923, 7925, + 7927, 7929, 7931, 7933, 7935, 7937, 7939, 7941, + 7961, 7963, 7965, 7967, 7969, 7971, 7973, 7975, + 7977, 7979, 7981, 7983, 7985, 7987, 7989, 7991, + 7993, 7995, 7997, 7999, 8001, 8003, 8005, 8007, + 8009, 8018, 8020, 8022, 8024, 8026, 8028, 8030, + 8032, 8034, 8043, 8045, 8047, 8049, 8051, 8053, + 8055, 8057, 8059, 8066, 8068, 8070, 8072, 8074, + 8076, 8078, 8080, 8082, 8084, 8086, 8088, 8090, + 8092, 8094, 8096, 8098, 8100, 8102, 8104, 8106, + 8108, 8110, 8117, 8119, 8121, 8123, 8125, 8127, + 8129, 8131, 8133, 8135, 8137, 8139, 8141, 8143, + 8190, 8224, 8226, 8228, 8230, 8232, 8234, 8236, + 8238, 8240, 8242, 8244, 8246, 8248, 8250, 8252, + 8254, 8256, 8320, 8322, 8324, 8326, 8328, 8330, + 8332, 8334, 8336, 8338, 8340, 8342, 8344, 8346, + 8348, 8350, 8352, 8354, 8373, 8375, 8377, 8379, + 8381, 8383, 8385, 8387, 8389, 8391, 8393, 8395, + 8397, 8399, 8401, 8403, 8405, 8407, 8409, 8411, + 8413, 8415, 8417, 8419, 8421, 8423, 8425, 8427, + 8429, 8431, 8433, 8435, 8437, 8439, 8441, 8443, + 8445, 8447, 8449, 8451, 8453, 8455, 8457, 8459, + 8461, 8463, 8465, 8467, 8469, 8471, 8473, 8475, + 8477, 8482, 8484, 8486, 8488, 8490, 8492, 8520, + 8522, 8524, 8526, 8528, 8530, 8532, 8534, 8536, + 8538, 8540, 8542, 8544, 8546, 8562, 8564, 8566, + 8568, 8580, 8582, 8584, 8586, 8588, 8590, 8592, + 8594, 8596, 8598, 8600, 8612, 8614, 8616, 8618, + 8620, 8622, 8624, 8626, 8628, 8630, 8632, 8634, + 8636, 8638, 8640, 8642, 8644, 8660, 8718, 8720, + 8722, 8734, 8736, 8738, 8740, 8742, 8744, 8751, + 8753, 8755, 8757, 8759, 8786, 8788, 8790, 8792, + 8794, 8796, 8798, 8800, 8802, 8804, 8806, 8808, + 8810, 8812, 8814, 8816, 8818, 8820, 8822, 8824, + 8826, 8828, 8830, 8832, 8834, 8836, 8838, 8896, + 8898, 8900, 8902, 8904, 8916, 8918, 8920, 8922, + 8924, 8926, 8928, 8930, 8932, 8977, 8979, 8981, + 8983, 8985, 8987, 8989, 8991, 9020, 9022, 9024, + 9026, 9028, 9030, 9051, 9053, 9055, 9081, 9083, + 9085, 9087, 9089, 9091, 9093, 9095, 9097, 9099, + 9101, 9103, 9109, 9113, 9115, 9117, 9119, 9121, + 9123, 9125, 9127, 9129, 9142, 9144, 9146, 9148, + 9150, 9152, 9154, 9156, 9158, 9160, 9162, 9164, + 9166, 9168, 9170, 9172, 9174, 9201, 9203, 9205, + 9207, 9209, 9211, 9213, 9215, 9217, 9219, 9221, + 9223, 9225, 9227, 9229, 9231, 9233, 9235, 9237, + 9239, 9241, 9243, 9245, 9247, 9249, 9251, 9253, + 9255, 9257, 9259, 9261, 9280, 9282, 9284, 9286, + 9288, 9290, 9292, 9314, 9331, 9333, 9335, 9337, + 9339, 9393, 9395, 9397, 9399, 9401, 9403, 9407, + 9409, 9411, 9413, 9415, 9417, 9435, 9437, 9439, + 9441, 9443, 9445, 9447, 9449, 9451, 9453, 9455, + 9457, 9459, 9461, 9463, 9465, 9467, 9469, 9471, + 9478, 9480, 9482, 9498, 9517, 9519, 9521, 9523, + 9525, 9533, 9535, 9537, 9539, 9541, 9543, 9545, + 9547, 9549, 9551, 9553, 9555, 9557, 9559, 9561, + 9563, 9565, 9567, 9590, 9592, 9594, 9596, 9598, + 9609, 9611, 9613, 9615, 9617, 9619, 9671, 9673, + 9675, 9677, 9679, 9690, 9692, 9694, 9696, 9698, + 9700, 9702, 9704, 9706, 9708, 9710, 9712, 9714, + 9716, 9718, 9720, 9722, 9724, 9726, 9728, 9730, + 9732, 9734, 9736, 9738, 9740, 9742, 9744, 9746, + 9748, 9750, 9752, 9754, 9756, 9758, 9766, 9768, + 9770, 9772, 9774, 9776, 9778, 9780, 9782, 9784, + 9786, 9788, 9790, 9792, 9794, 9796, 9798, 9800, + 9802, 9804, 9806, 9808, 9816, 9818, 9820, 9822, + 9824, 9826, 9828, 9830, 9832, 9834, 9836, 9838, + 9840, 9842, 9844, 9846, 9848, 9850, 9852, 9854, + 9856, 9907, 9909, 9911, 9913, 9915, 9917, 9919, + 9921, 9923, 9925, 9927, 9929, 9931, 9933, 9935, + 9937, 9939, 9941, 9993, 9995, 9997, 9999, 10001, + 10003, 10005, 10007, 10009, 10011, 10013, 10015, 10017, + 10068, 10070, 10085, 10087, 10112, 10114, 10116, 10118, + 10166, 10168, 10170, 10172, 10192, 10194, 10196, 10198, + 10200, 10202, 10204, 10206, 10208, 10210, 10212, 10214, + 10216, 10218, 10220, 10222, 10224, 10226, 10228, 10230, + 10232, 10234, 10236, 10238, 10240, 10242, 10244, 10246, + 10248, 10250, 10252, 10254, 10256, 10258, 10260, 10262, + 10264, 10266, 10268, 10270, 10272, 10274, 10276, 10278, + 10280, 10298, 10300, 10302, 10304, 10306, 10308, 10310, + 10312, 10314, 10316, 10318, 10320, 10322, 10324, 10326, + 10328, 10330, 10345, 10347, 10349, 10351, 10353, 10355, + 10357, 10359, 10361, 10363, 10417, 10419, 10421, 10423, + 10425, 10427, 10429, 10431, 10433, 10435, 10437, 10439, + 10441, 10443, 10461, 10463, 10465, 10467, 10469, 10471, + 10473, 10475, 10477, 10479, 10481, 10483, 10485, 10487, + 10489, 10491, 10536, 10538, 10540, 10542, 10544, 10546, + 10548, 10550, 10552, 10578, 10580, 10582, 10584, 10586, + 10588, 10590, 10592, 10594, 10598, 10600, 10602, 10604, + 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620, + 10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, + 10638, 10640, 10642, 10666, 10668, 10670, 10672, 10674, + 10676, 10678, 10680, 10682, 10684, 10748, 10750, 10752, + 10754, 10756, 10758, 10760, 10762, 10764, 10766, 10768, + 10825, 10827, 10829, 10831, 10833, 10835, 10848, 10860, + 10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, + 10878, 10895, 10906, 10908, 10910, 10912, 10914, 10919, + 10980, 10982, 10984, 10986, 10988, 10990, 10992, 10994, + 10996, 10998, 11000, 11065, 11067, 11069, 11071, 11073, + 11075, 11115, 11124, 11126, 11128, 11130, 11132, 11134, + 11136, 11138, 11140, 11142, 11203, 11205, 11248, 11250, + 11256, 11258, 11260, 11262, 11264, 11266, 11268, 11270, + 11281, 11283, 11285, 11287, 11289, 11291, 11346, 11348, + 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364, + 11366, 11368, 11370, 11372, 11416, 11418, 11420, 11422, + 11424, 11426, 11450, 11452, 11454, 11456, 11458, 11460, + 11504, 11506, 11508, 11510, 11512, 11514, 11516, 11518, + 11520, 11528, 11530, 11532, 11534, 11536, 11538, 11540, + 11542, 11544, 11546, 11587, 11589, 11591, 11593, 11610, + 11612, 11630, 11632, 11634, 11636, 11638, 11640, 11642, + 11644, 11646, 11648, 11650, 11652, 11654, 11656, 11658, + 11660, 11662, 11664, 11666, 11710, 11712, 11714, 11717, + 11719, 11721, 11723, 11725, 11727, 11773, 11775, 11777, + 11779, 11781, 11840, 11842, 11844, 11846, 11848, 11860, + 11862, 11864, 11866, 11868, 11870, 11872, 11874, 11876, + 11895, 11897, 11899, 11901, 11945, 11947, 11949, 11951, + 11953, 11955, 11957, 11959, 11961, 11963, 11965, 11967, + 11969, 11971, 11995, 11997, 11999, 12001, 12003, 12005, + 12007, 12009, 12011, 12013, 12035, 12057, 12059, 12061, + 12063, 12065, 12067, 12069, 12071, 12089, 12091, 12093, + 12095, 12097, 12099, 12101, 12103, 12105, 12107, 12109, + 12111, 12113, 12118, 12120, 12122, 12124, 12126, 12128, + 12130, 12132, 12134, 12136, 12138, 12140, 12142, 12144, + 12146, 12165, 12167, 12169, 12171, 12173, 12175, 12177, + 12179, 12181, 12183, 12185, 12187, 12189, 12191, 12193, + 12195, 12197, 12199, 12201, 12203, 12205, 12207, 12209, + 12211, 12213, 12229, 12242, 12244, 12254, 12256, 12258, + 12260, 12262, 12264, 12266, 12268, 12270, 12272, 12274, + 12276, 12278, 12280, 12282, 12284, 12286, 12288, 12290, + 12292, 12294, 12351, 12353, 12355, 12357, 12359, 12361, + 12363, 12365, 12367, 12369, 12371, 12373, 12375, 12377, + 12379, 12381, 12385, 12389, 12391, 12393, 12395, 12397, + 12399, 12401, 12403, 12415, 12471, 12473, 12475, 12477, + 12479, 12481, 12483, 12493, 12495, 12497, 12556, 12558, + 12560, 12562, 12564, 12566, 12568, 12570, 12622, 12662, + 12664, 12666, 12668, 12670, 12730, 12732, 12734, 12736, + 12738, 12778, 12780, 12782, 12784, 12786, 12843, 12845, + 12847, 12849, 12851, 12853, 12855, 12857, 12859, 12861, + 12901, 12903, 12905, 12907, 12909, 12969, 12971, 12973, + 12975, 12977, 12979, 12981, 12983, 12985, 12987, 12989, + 12991, 12993, 12995, 12997, 12999, 13001, 13003, 13005, + 13045, 13047, 13049, 13051, 13053, 13110, 13112, 13114, + 13116, 13118, 13120, 13122, 13124, 13126, 13128, 13130, + 13132, 13151, 13153, 13155, 13157, 13159, 13161, 13163, + 13177, 13179, 13181, 13183, 13185, 13187, 13189, 13233, + 13235, 13237, 13284, 13286, 13288, 13290, 13292, 13294, + 13297, 13299, 13343, 13345, 13347, 13349, 13393, 13395, + 13451, 13453, 13479, 13496, 13498, 13500, 13502, 13504, + 13562, 13564, 13566, 13568, 13570, 13572, 13574, 13576, + 13578, 13600, 13602, 13604, 13606, 13608, 13610, 13612, + 13614, 13616, 13628, 13630, 13632, 13634, 13636, 13658, + 13662, 13664, 13666, 13668, 13670, 13672, 13674, 13676, + 13678, 13680, 13682, 13684, 13686, 13688, 13746, 13748, + 13750, 13752, 13754, 13756, 13768, 13770, 13772, 13774, + 13776, 13778, 13780, 13782, 13784, 13786, 13788, 13790, + 13792, 13794, 13796, 13798, 13806, 13808, 13810, 13812, + 13814, 13866, 13868, 13870, 13872, 13874, 13876, 13878, + 13936, 13938, 13989, 13991, 13993, 13995, 14000, 14002, + 14004, 14006, 14008, 14016, 14018, 14020, 14022, 14024, + 14026, 14028, 14030, 14032, 14034, 14054, 14056, 14058, + 14060, 14062, 14064, 14066, 14068, 14070, 14072, 14074, + 14076, 14078, 14080, 14082, 14084, 14086, 14088, 14090, + 14092, 14094, 14096, 14098, 14100, 14102, 14104, 14106, + 14108, 14110, 14112, 14172, 14174, 14176, 14178, 14184, + 14186, 14188, 14232, 14288, 14290, 14295, 14297, 14356, + 14358, 14409, 14411, 14413, 14415, 14428, 14430, 14432, + 14434, 14436, 14438, 14440, 14442, 14446, 14489, 14491, + 14493, 14495, 14497, 14499, 14501, 14522, 14524, 14526, + 14528, 14530, 14532, 14534, 14550, 14552, 14554, 14556, + 14558, 14560, 14562, 14582, 14584, 14586, 14602, 14646, + 14648, 14692, 14694, 14696, 14698, 14700, 14702, 14723, + 14725, 14727, 14729, 14737, 14739, 14741, 14746, 14748, + 14750, 14752, 14754, 14756, 14758, 14760, 14815, 14817, + 14875, 14877, 14879, 14881, 14883, 14885, 14907, 14909, + 14911, 14913, 14915, 14917, 14919, 14921, 14923, 14925, + 14927, 14950, 14952, 14954, 15006, 15008, 15010, 15030, + 15032, 15037, 15039, 15041, 15043, 15045, 15047, 15049, + 15051, 15053, 15055, 15057, 15059, 15061, 15063, 15065, + 15067, 15069, 15071, 15073, 15075, 15077, 15079, 15081, + 15083, 15085, 15093, 15095, 15097, 15099, 15101, 15103, + 15105, 15107, 15109, 15111, 15113, 15115, 15117, 15119, + 15121, 15123, 15131, 15133, 15135, 15137, 15139, 15141, + 15143, 15145, 15147, 15149, 15151, 15153, 15155, 15157, + 15159, 15218, 15220, 15222, 15224, 15226, 15228, 15230, + 15244, 15246, 15248, 15250, 15252, 15254, 15256, 15258, + 15260, 15262, 15264, 15266, 15327, 15329, 15332, 15334, + 15336, 15338, 15340, 15342, 15344, 15346, 15348, 15374, + 15376, 15378, 15380, 15382, 15384, 15438, 15451, 15453, + 15455, 15457, 15459, 15461, 15463, 15465, 15467, 15469, + 15471, 15473, 15481, 15483, 15485, 15487, 15489, 15491, + 15493, 15495, 15497, 15508, 15510, 15512, 15514, 15516, + 15518, 15520, 15522, 15530, 15532, 15534, 15557, 15559, + 15617, 15619, 15621, 15679, 15681, 15683, 15685, 15687, + 15689, 15691, 15693, 15695, 15697, 15699, 15701, 15703, + 15705, 15707, 15761, 15763, 15765, 15767, 15769, 15771, + 15773, 15775, 15777, 15779, 15781, 15783, 15785, 15787, + 15789, 15791, 15793, 15798, 15800, 15802, 15804, 15806, + 15808, 15810, 15823, 15825, 15827, 15829, 15831, 15833, + 15835, 15893, 15895, 15938, 15940, 15942, 15944, 15946, + 15948, 15950, 15952, 15954, 15956, 15958, 15960, 15962, + 15964, 15966, 15968, 15970, 15972, 15974, 15976, 15978, + 15980, 15982, 15984, 15986, 15988, 15990, 15992, 15994, + 15996, 15998, 16000, 16009, 16011, 16013, 16015, 16017, + 16019, 16021, 16023, 16025, 16027, 16029, 16031, 16033, + 16035, 16037, 16039, 16041, 16043, 16045, 16047, 16049, + 16051, 16059, 16061, 16063, 16065, 16067, 16069, 16071, + 16073, 16075, 16077, 16080, 16082, 16084, 16086, 16088, + 16090, 16092, 16097, 16099, 16101, 16103, 16105, 16107, + 16109, 16128, 16137, 16139, 16141, 16143, 16145, 16147, + 16149, 16151, 16153, 16169, 16171, 16173, 16175, 16177, + 16222, 16224, 16233, 16235, 16237, 16239, 16241, 16243, + 16245, 16247, 16249, 16251, 16253, 16255, 16257, 16265, + 16267, 16269, 16271, 16273, 16275, 16277, 16279, 16281, + 16335, 16380, 16382, 16384, 16386, 16388, 16390, 16408, + 16410, 16412, 16414, 16416, 16418, 16420, 16422, 16448, + 16450, 16452, 16454, 16456, 16458, 16500, 16502, 16504, + 16506, 16508, 16510, 16512, 16514, 16516, 16518, 16566, + 16568, 16570, 16572, 16574, 16632, 16634, 16636, 16638, + 16681, 16683, 16685, 16687, 16745, 16747, 16749, 16751, + 16753, 16755, 16757, 16759, 16802, 16804, 16806, 16808, + 16828, 16830, 16832, 16834, 16836, 16838, 16899, 16901, + 16903, 16905, 16907, 16909, 16921, 16924, 16926, 16928, + 16942, 16944, 16946, 16948, 16959, 16961, 16963, 16965, + 16967, 16969, 16989, 16991, 17049, 17051, 17053, 17055, + 17057, 17059, 17061, 17122, 17124, 17126, 17128, 17130, + 17151, 17159, 17161, 17163, 17165, 17167, 17169, 17171, + 17173, 17178, 17180, 17182, 17184, 17186, 17188, 17195, + 17197, 17199, 17201, 17203, 17205, 17207, 17209, 17219, + 17221, 17223, 17225, 17227, 17229, 17231, 17233, 17244, + 17246, 17248, 17250, 17252, 17254, 17256, 17258, 17260, + 17291, 17293, 17295, 17297, 17299, 17301, 17303, 17311, + 17313, 17315, 17317, 17319, 17321, 17323, 17325, 17334, + 17336, 17343, 17345, 17347, 17349, 17364, 17366, 17368, + 17370, 17372, 17374, 17386, 17388, 17390, 17392, 17394, + 17396, 17398, 17400, 17402, 17404, 17406, 17408, 17410, + 17412, 17414, 17416, 17418, 17420, 17440, 17442, 17444, + 17446, 17448, 17450, 17452, 17454, 17456, 17458, 17460, + 17462, 17464, 17466, 17468, 17470, 17472, 17474, 17476, + 17478, 17489, 17491, 17493, 17495, 17497, 17502, 17504, + 17506, 17508, 17510, 17512, 17514, 17516, 17518, 17520, + 17522, 17524, 17526, 17528, 17530, 17551, 17553, 17555, + 17557, 17559, 17561, 17563, 17565, 17567, 17569, 17571, + 17573, 17577, 17579, 17581, 17593, 17595, 17597, 17599, + 17660, 17662, 17664, 17666, 17668, 17670, 17672, 17674, + 17676, 17692, 17710, 17718, 17726, 17728, 17730, 17732, + 17734, 17738, 17740, 17742, 17748, 17750, 17752, 17754, + 17756, 17760, 17762, 17764, 17766, 17768, 17770, 17772, + 17774, 17776, 17778, 17780, 17782, 17784, 17835, 17886, + 17888, 17903, 17905, 17907, 17909, 17911, 17913, 17915, + 17958, 17960, 17962, 17964, 17966, 17968, 17970, 17972, + 17990, 17992, 17994, 17996, 17998, 18000, 18002, 18004, + 18062, 18064, 18122, 18124, 18126, 18128, 18130, 18132, + 18134, 18185, 18187, 18189, 18191, 18193, 18247, 18298, + 18300, 18344, 18346, 18348, 18350, 18352, 18398, 18400, + 18402, 18404, 18406, 18408, 18410, 18412, 18414, 18463, + 18465, 18467, 18469, 18517, 18519, 18521, 18576, 18578, + 18580, 18582, 18584, 18640, 18696, 18698, 18700, 18702, + 18704, 18706, 18708, 18710, 18712, 18714, 18716, 18718, + 18726, 18728, 18730, 18732, 18783, 18785, 18787, 18795, + 18797, 18799, 18801, 18803, 18805, 18807, 18809, 18811, + 18813, 18815, 18817, 18819, 18821, 18823, 18825, 18845, + 18849, 18851, 18853, 18855, 18857, 18859, 18861, 18863, + 18865, 18867, 18869, 18871, 18878, 18880, 18882, 18884, + 18886, 18888, 18890, 18892, 18894, 18896, 18898, 18900, + 18902, 18904, 18906, 18908, 18910, 18921, 18923, 18925, + 18927, 18929, 18931, 18933, 18935, 18937, 18939, 18997, + 18999, 19001, 19003, 19014, 19016, 19018, 19020, 19022, + 19024, 19026, 19028, 19030, 19032, 19034, 19050, 19052, + 19054, 19056, 19118, 19120, 19122, 19124, 19126, 19128, + 19130, 19132, 19134, 19136, 19138, 19140, 19159, 19161, + 19163, 19165, 19225, 19227, 19229, 19231, 19233, 19235, + 19237, 19239, 19241, 19243, 19245, 19247, 19249, 19251, + 19253, 19273, 19275, 19277, 19279, 19281, 19283, 19285, + 19287, 19289, 19291, 19293, 19312, 19314, 19316, 19318, + 19320, 19322, 19324, 19326, 19328, 19336, 19338, 19340, + 19342, 19344, 19346, 19348, 19350, 19352, 19354, 19356, + 19358, 19360, 19362, 19364, 19366, 19368, 19370, 19372, + 19374, 19376, 19378, 19380, 19382, 19384, 19386, 19405, + 19407, 19409, 19411, 19413, 19415, 19417, 19419, 19421, + 19423, 19425, 19441, 19443, 19445, 19447, 19449, 19451, + 19453, 19455, 19457, 19479, 19481, 19483, 19485, 19487, + 19551, 19553, 19555, 19557, 19580, 19582, 19584, 19586, + 19588, 19602, 19604, 19606, 19608, 19610, 19612, 19614, + 19668, 19675, 19677, 19679, 19681, 19683, 19685, 19687, + 19689, 19691, 19693, 19695, 19697, 19699, 19701, 19703, + 19705, 19707, 19724, 19743, 19745, 19747, 19760, 19762, + 19764, 19766, 19768, 19770, 19772, 19774, 19776, 19778, + 19780, 19782, 19784, 19786, 19788, 19790, 19792, 19851, + 19853, 19855, 19857, 19859, 19861, 19863, 19922, 19924, + 19926, 19928, 19930, 19932, 19934, 19936, 19991, 19993, + 19995, 19997, 20010, 20012, 20014, 20016, 20018, 20020, + 20022, 20024, 20026, 20028, 20030, 20032, 20034, 20036, + 20038, 20040, 20042, 20044, 20063, 20065, 20067, 20069, + 20071, 20073, 20075, 20077, 20079, 20081, 20083, 20085, + 20087, 20089, 20091, 20093, 20095, 20097, 20105, 20107, + 20109, 20111, 20172, 20174, 20176, 20178, 20180, 20241, + 20243, 20245, 20293, 20295, 20297, 20299, 20301, 20305, + 20307, 20309, 20311, 20313, 20333, 20351, 20353, 20355, + 20357, 20359, 20361, 20363, 20365, 20367, 20369, 20371, + 20373, 20375, 20377, 20381, 20383, 20385, 20387, 20389, + 20391, 20393, 20395, 20397, 20399, 20401, 20421, 20423, + 20425, 20427, 20488, 20490, 20512, 20514, 20516, 20518, + 20520, 20522, 20524, 20526, 20528, 20530, 20532, 20534, + 20536, 20538, 20540, 20542, 20544, 20546, 20548, 20550, + 20552, 20554, 20556, 20558, 20560, 20615, 20636, 20638, + 20640, 20642, 20644, 20646, 20648, 20650, 20652, 20654, + 20656, 20658, 20660, 20662, 20708, 20710, 20712, 20714, + 20716, 20735, 20737, 20739, 20741, 20743, 20745, 20747, + 20749, 20751, 20753, 20755, 20757, 20759, 20761, 20763, + 20765, 20767, 20769, 20771, 20773, 20824, 20826, 20828, + 20830, 20832, 20834, 20836, 20838, 20897, 20942, 20944, + 20946, 20948, 20950, 20952, 20954, 20956, 20958, 20960, + 20962, 20964, 20966, 20968, 20970, 20972, 21016, 21018, + 21020, 21022, 21080, 21082, 21101, 21103, 21105, 21107, + 21109, 21111, 21113, 21125, 21127, 21135, 21137, 21139, + 21155, 21157, 21159, 21178, 21180, 21182, 21208, 21210, + 21212, 21214, 21216, 21223, 21225, 21227, 21229, 21231, + 21233, 21235, 21237, 21239, 21257, 21259, 21261, 21263, + 21265, 21322, 21324, 21343, 21345, 21347, 21349, 21351, + 21353, 21355, 21357, 21359, 21361, 21363, 21365, 21423, + 21425, 21446, 21448, 21450, 21452, 21454, 21513, 21515, + 21517, 21519, 21521, 21523, 21525, 21527, 21529, 21531, + 21533, 21552, 21554, 21556, 21558, 21560, 21562, 21564, + 21566, 21568, 21570, 21572, 21574, 21576, 21578, 21580, + 21582, 21584, 21586, 21588, 21590, 21592, 21612, 21614, + 21616, 21618, 21620, 21678, 21680, 21682, 21684, 21686, + 21688, 21690, 21692, 21694, 21696, 21698, 21700, 21702, + 21704, 21706, 21708, 21710, 21712, 21714, 21716, 21718, + 21720, 21722, 21724, 21726, 21728, 21730, 21732, 21734, + 21736, 21738, 21796, 21798, 21800, 21802, 21804, 21806, + 21808, 21866, 21868, 21870, 21872, 21874, 21928, 21985, + 21987, 22031, 22033, 22035, 22055, 22057, 22059, 22061, + 22063, 22065, 22067, 22069, 22071, 22073, 22075, 22087, + 22089, 22091, 22093, 22095, 22097, 22099, 22101, 22103, + 22105, 22107, 22109, 22111, 22113, 22124, 22126, 22128, + 22130, 22132, 22134, 22136, 22138, 22140, 22142, 22154, + 22156, 22159, 22161, 22180, 22182, 22233, 22235, 22237, + 22239, 22241, 22243, 22245, 22247, 22306, 22308, 22310, + 22312, 22314, 22316, 22318, 22320, 22322, 22324, 22326, + 22328, 22330, 22332, 22334, 22336, 22338, 22346, 22348, + 22350, 22352, 22354, 22356, 22358, 22360, 22400, 22402, + 22404, 22406, 22408, 22456, 22458, 22460, 22515, 22517, + 22519, 22521, 22523, 22579, 22635, 22637, 22639, 22641, + 22643, 22670, 22676, 22678, 22680, 22682, 22684, 22686, + 22688, 22690, 22692, 22700, 22702, 22704, 22706, 22725, + 22727, 22729, 22731, 22733, 22735, 22737, 22739, 22741, + 22743, 22745, 22747, 22749, 22751, 22753, 22755, 22757, + 22759, 22761, 22763, 22765, 22767, 22769, 22771, 22773, + 22775, 22777, 22779, 22781, 22783, 22785, 22787, 22789, + 22791, 22793, 22795, 22797, 22799, 22807, 22809, 22811, + 22813, 22815, 22817, 22819, 22821, 22823, 22825, 22838, + 22840, 22842, 22844, 22846, 22848, 22850, 22852, 22854, + 22856, 22858, 22860, 22863, 22865, 22867, 22869, 22871, + 22873, 22875, 22920, 22922, 22924, 22926, 22928, 22930, + 22932, 22934, 22985, 22987, 22989, 23010, 23012, 23014, + 23016, 23018, 23020, 23022, 23024, 23026, 23028, 23030, + 23032, 23075, 23077, 23079, 23081, 23083, 23085, 23106, + 23108, 23110, 23112, 23114, 23116, 23118, 23120, 23122, + 23168, 23170, 23172, 23193, 23195, 23197, 23254, 23256, + 23258, 23260, 23262, 23264, 23272, 23274, 23276, 23278, + 23280, 23282, 23284, 23286, 23288, 23290, 23292, 23294, + 23296, 23298, 23300, 23302, 23304, 23306, 23308, 23310, + 23312, 23314, 23316, 23318, 23345, 23347, 23349, 23351, + 23396, 23398, 23400, 23402, 23421, 23423, 23425, 23427, + 23429, 23431, 23433, 23435, 23437, 23439, 23450, 23452, + 23454, 23456, 23458, 23460, 23462, 23464, 23466, 23468, + 23519, 23521, 23523, 23525, 23527, 23544, 23546, 23563, + 23565, 23609, 23611, 23613, 23615, 23673, 23675, 23677, + 23737, 23739, 23741, 23743, 23745, 23747, 23749, 23751, + 23753, 23755, 23757, 23759, 23761, 23763, 23765, 23777, + 23779, 23781, 23783, 23785, 23787, 23789, 23791, 23793, + 23795, 23797, 23799, 23801, 23803, 23805, 23807, 23809, + 23811, 23813, 23815, 23817, 23819, 23821, 23823, 23825, + 23827, 23840, 23842, 23844, 23887, 23889, 23891, 23893, + 23895, 23897, 23899, 23901, 23903, 23905, 23907, 23950, + 23952, 24012, 24014, 24017, 24019, 24021, 24023, 24025, + 24027, 24029, 24031, 24033, 24035, 24049, 24051, 24053, + 24055, 24057, 24059, 24061, 24063, 24082, 24084, 24086, + 24088, 24090, 24092, 24094, 24146, 24148, 24150, 24152, + 24154, 24156, 24158, 24160, 24162, 24164, 24214, 24229, + 24231, 24292, 24294, 24311, 24313, 24315, 24334, 24336, + 24338, 24340, 24342, 24344, 24346, 24348, 24350, 24352, + 24354, 24356, 24358, 24360, 24362, 24364, 24366, 24427, + 24429, 24431, 24433, 24435, 24437, 24439, 24441, 24443, + 24445, 24447, 24449, 24483, 24485, 24487, 24489, 24491, + 24493, 24495, 24497, 24499, 24519, 24521, 24523, 24525, + 24527, 24529, 24531, 24533, 24535, 24537, 24592, 24594, + 24596, 24598, 24600, 24602, 24604, 24606, 24608, 24610, + 24612, 24614, 24654, 24656, 24714, 24716, 24720, 24722, + 24724, 24726, 24770, 24772, 24798, 24802, 24804, 24806, + 24808, 24810, 24812, 24814, 24816, 24818, 24820, 24822, + 24865, 24867, 24869, 24871, 24873, 24875, 24877, 24879, + 24881, 24883, 24885, 24948, 24950, 24952, 24954, 24956, + 24968, 24970, 24972, 25026, 25028, 25030, 25032, 25034, + 25036, 25038, 25040, 25042, 25044, 25050, 25052, 25054, + 25056, 25058, 25060, 25062, 25064, 25066, 25124, 25126, + 25128, 25130, 25179, 25181, 25239, 25297, 25299, 25301, + 25303, 25305, 25307, 25309, 25311, 25313, 25315, 25317, + 25374, 25376, 25425, 25427, 25429, 25431, 25433, 25435, + 25437, 25439, 25441, 25443, 25504, 25547, 25549, 25551, + 25553, 25555, 25557, 25610, 25612, 25614, 25616, 25618, + 25620, 25622, 25624, 25626, 25628, 25686, 25688, 25707, + 25709, 25711, 25713, 25715, 25717, 25719, 25721, 25723, + 25725, 25727, 25729, 25731, 25733, 25735, 25737, 25795, + 25797, 25799, 25801, 25803, 25805, 25807, 25865, 25867, + 25869, 25871, 25873, 25930, 25932, 25976, 25978, 25980, + 25982, 25984, 25990, 25992, 25994, 25996, 26057, 26059, + 26061, 26063, 26065, 26069, 26071, 26073, 26075, 26077, + 26138, 26142, 26144, 26146, 26148, 26167, 26169, 26228, + 26230, 26232, 26234, 26236, 26238, 26240, 26242, 26244, + 26246, 26248, 26250, 26252, 26254, 26298, 26300, 26302, + 26304, 26346, 26390, 26392, 26394, 26447, 26449, 26451, + 26453, 26455, 26457, 26519, 26521, 26523, 26525, 26527, + 26529, 26531, 26533, 26535, 26537, 26539, 26541, 26543, + 26545, 26589, 26591, 26611, 26668, 26670, 26672, 26674, + 26676, 26678, 26680, 26682, 26684, 26689, 26691, 26693, + 26695, 26697, 26699, 26701, 26703, 26705, 26707, 26709, + 26711, 26713, 26757, 26813, 26815, 26817, 26819, 26821, + 26823, 26825, 26827, 26829, 26831, 26847, 26849, 26851, + 26853, 26855, 26871, 26929, 26931, 26933, 26935, 26937, + 26981, 26983, 27039, 27041, 27043, 27087, 27089, 27091, + 27149, 27151, 27153, 27155, 27157, 27201, 27203, 27259, + 27261, 27274, 27276, 27278, 27280, 27282, 27284, 27286, + 27288, 27290, 27292, 27294, 27296, 27298, 27300, 27308, + 27310, 27312, 27314, 27358, 27360, 27362, 27364, 27366, + 27368, 27370, 27414, 27416, 27418, 27470, 27528, 27530, + 27532, 27534, 27536, 27538, 27587, 27589, 27591, 27593, + 27595, 27597, 27599, 27601, 27603, 27605, 27607, 27609, + 27611, 27613, 27615, 27632, 27634, 27636, 27638, 27640, + 27642, 27644, 27646, 27699, 27701, 27703, 27705, 27707, + 27764, 27766, 27768, 27770, 27823, 27825, 27827, 27829, + 27831, 27833, 27835, 27837, 27839, 27841, 27843, 27890, + 27892, 27894, 27896, 27898, 27910, 27912, 27914, 27968, + 27970, 27972, 27974, 27976, 27978, 27980, 28017, 28019, + 28037, 28039, 28041, 28043, 28045, 28047, 28065, 28067, + 28109, 28111, 28131, 28133, 28135, 28137, 28139, 28141, + 28143, 28145, 28147, 28149, 28151, 28153, 28155, 28157, + 28159, 28161, 28163, 28165, 28167, 28169, 28186, 28188, + 28190, 28192, 28194, 28201, 28203, 28205, 28207, 28209, + 28211, 28213, 28226, 28228, 28230, 28232, 28234, 28236, + 28238, 28240, 28261, 28263, 28265, 28267, 28278, 28280, + 28282, 28284, 28286, 28288, 28290, 28292, 28294, 28296, + 28298, 28308, 28310, 28312, 28314, 28316, 28318, 28320, + 28333, 28335, 28337, 28339, 28341, 28343, 28345, 28347, + 28349, 28351, 28353, 28355, 28368, 28370, 28372, 28374, + 28376, 28378, 28380, 28382, 28384, 28445, 28447, 28449, + 28451, 28503, 28505, 28559, 28561, 28563, 28565, 28567, + 28569, 28571, 28573, 28575, 28577, 28579, 28581, 28583, + 28585, 28587, 28601, 28603, 28605, 28607, 28609, 28611, + 28613, 28615, 28617, 28620, 28622, 28624, 28626, 28628, + 28668, 28670, 28672, 28674, 28676, 28678, 28680, 28682, + 28684, 28706, 28708, 28767, 28769, 28771, 28773, 28775, + 28780, 28782, 28784, 28786, 28788, 28790, 28792, 28794, + 28813, 28815, 28817, 28819, 28821, 28823, 28825, 28827, + 28829, 28831, 28833, 28835, 28837, 28839, 28841, 28843, + 28845, 28853, 28914, 28916, 28918, 28920, 28922, 28924, + 28926, 28928, 28930, 28991, 28993, 28995, 28997, 28999, + 29001, 29003, 29005, 29007, 29029, 29031, 29041, 29043, + 29090, 29092, 29094, 29096, 29098, 29157, 29159, 29161, + 29163, 29165, 29167, 29169, 29171, 29173, 29181, 29183, + 29185, 29187, 29189, 29191, 29193, 29195, 29197, 29199, + 29201, 29203, 29217, 29219, 29221, 29223, 29225, 29227, + 29229, 29231, 29233, 29235, 29237, 29297, 29299, 29301, + 29303, 29305, 29307, 29309, 29351, 29409, 29411, 29413, + 29415, 29417, 29419, 29421, 29423, 29425, 29427, 29429, + 29431, 29433, 29435, 29437, 29439, 29459, 29461, 29463, + 29465, 29467, 29469, 29471, 29473, 29475, 29477, 29479, + 29481, 29483, 29485, 29487, 29489, 29491, 29493, 29551, + 29553, 29601, 29603, 29605, 29607, 29609, 29611, 29613, + 29627, 29629, 29649, 29651, 29653, 29655, 29657, 29659, + 29661, 29663, 29665, 29667, 29669, 29671, 29673, 29732, + 29734, 29736, 29738, 29740, 29742, 29744, 29746, 29748, + 29750, 29758, 29760, 29762, 29764, 29766, 29768, 29770, + 29772, 29774, 29791, 29793, 29795, 29797, 29799, 29801, + 29803, 29805, 29807, 29809, 29811, 29813, 29815, 29817, + 29819, 29821, 29823, 29839, 29841, 29847, 29849, 29851, + 29853, 29855, 29857, 29859, 29861, 29863, 29865, 29867, + 29869, 29871, 29915, 29917, 29919, 29921, 29978, 29999, + 30001, 30003, 30005, 30007, 30009, 30011, 30013, 30015, + 30017, 30019, 30021, 30023, 30025, 30027, 30029, 30031, + 30050, 30068, 30070, 30072, 30074, 30076, 30078, 30080, + 30082, 30084, 30086, 30088, 30090, 30092, 30094, 30096, + 30147, 30149, 30151, 30153, 30155, 30157, 30159, 30161, + 30223, 30225, 30227, 30272, 30274, 30276, 30278, 30280, + 30282, 30284, 30286, 30288, 30290, 30292, 30294, 30296, + 30298, 30300, 30302, 30304, 30306, 30316, 30318, 30320, + 30322, 30324, 30377, 30379, 30381, 30383, 30385, 30404, + 30406, 30408, 30410, 30412, 30414, 30416, 30428, 30430, + 30438, 30440, 30442, 30458, 30460, 30462, 30481, 30483, + 30485, 30511, 30513, 30515, 30517, 30519, 30526, 30528, + 30530, 30532, 30534, 30536, 30538, 30540, 30542, 30560, + 30562, 30564, 30566, 30568, 30570, 30572, 30574, 30576, + 30578, 30635, 30637, 30639, 30641, 30649, 30651, 30709, + 30711, 30713, 30715, 30717, 30719, 30721, 30723, 30725, + 30727, 30729, 30740, 30742, 30744, 30746, 30748, 30750, + 30752, 30754, 30756, 30758, 30774, 30776, 30795, 30797, + 30848, 30850, 30911, 30913, 30927, 30929, 30931, 30952, + 30954, 30956, 30958, 30960, 31019, 31021, 31023, 31025, + 31027, 31029, 31031, 31033, 31035, 31037, 31039, 31058, + 31060, 31062, 31064, 31066, 31068, 31070, 31072, 31074, + 31076, 31085, 31087, 31089, 31091, 31093, 31095, 31097, + 31099, 31101, 31103, 31105, 31107, 31109, 31111, 31113, + 31115, 31117, 31119, 31121, 31123, 31125, 31127, 31129, + 31131, 31133, 31135, 31137, 31139, 31141, 31143, 31145, + 31147, 31149, 31151, 31153, 31155, 31157, 31159, 31161, + 31163, 31165, 31167, 31169, 31171, 31173, 31175, 31177, + 31179, 31181, 31183, 31185, 31187, 31189, 31191, 31193, + 31195, 31197, 31199, 31213, 31215, 31217, 31219, 31221, + 31223, 31225, 31227, 31229, 31231, 31233, 31235, 31275, + 31277, 31279, 31281, 31283, 31285, 31287, 31289, 31291, + 31312, 31318, 31320, 31322, 31324, 31326, 31328, 31330, + 31332, 31345, 31347, 31349, 31351, 31353, 31355, 31357, + 31359, 31361, 31363, 31365, 31367, 31384, 31386, 31432, + 31434, 31436, 31438, 31440, 31442, 31444, 31446, 31448, + 31450, 31452, 31454, 31456, 31474, 31476, 31478, 31480, + 31482, 31484, 31486, 31488, 31509, 31511, 31513, 31570, + 31572, 31584, 31586, 31588, 31590, 31592, 31594, 31596, + 31598, 31600, 31602, 31653, 31655, 31657, 31659, 31661, + 31663, 31665, 31667, 31669, 31671, 31673, 31675, 31677, + 31679, 31706, 31708, 31710, 31712, 31714, 31716, 31718, + 31720, 31722, 31724, 31788, 31790, 31794, 31796, 31798, + 31800, 31802, 31804, 31806, 31808, 31851, 31853, 31855, + 31857, 31859, 31861, 31863, 31911, 31913, 31915, 31917, + 31919, 31921, 31923, 31925, 31927, 31929, 31931, 31933, + 31935, 31937, 31939, 31941, 31943, 31945, 31947, 31991, + 31993, 31995, 32052, 32054, 32056, 32058, 32060, 32072, + 32074, 32076, 32130, 32132, 32134, 32136, 32138, 32140, + 32142, 32144, 32146, 32148, 32150, 32157, 32159, 32161, + 32163, 32165, 32167, 32169, 32171, 32173, 32227, 32229, + 32231, 32233, 32259, 32261, 32263, 32265, 32284, 32286, + 32288, 32290, 32292, 32294, 32296, 32301, 32303, 32305, + 32307, 32309, 32311, 32313, 32315, 32317, 32319, 32321, + 32323, 32331, 32333, 32335, 32396, 32398, 32400, 32457, + 32459, 32461, 32463, 32519, 32521, 32533, 32535, 32547, + 32549, 32551, 32553, 32555, 32557, 32559, 32561, 32563, + 32565, 32567, 32569, 32571, 32573, 32575, 32577, 32598, + 32607, 32609, 32611, 32613, 32615, 32617, 32619, 32621, + 32623, 32625, 32627, 32629, 32631, 32633, 32635, 32637, + 32639, 32641, 32643, 32645, 32655, 32657, 32659, 32661, + 32705, 32763, 32765, 32777, 32779, 32781, 32783, 32785, + 32826, 32866, 32868, 32870, 32872, 32874, 32876, 32892, + 32894, 32896, 32956, 32958, 32960, 32962, 32964, 32984, + 33006, 33008, 33066, 33068, 33070, 33128, 33130, 33132, + 33148, 33206, 33208, 33210, 33212, 33256, 33258, 33260, + 33318, 33320, 33322, 33324, 33368, 33370, 33372, 33417, + 33419, 33422, 33424, 33426, 33428, 33430, 33432, 33434, + 33436, 33455, 33457, 33459, 33461, 33463, 33465, 33467, + 33469, 33471, 33473, 33475, 33477, 33479, 33481, 33483, + 33502, 33504, 33549, 33551, 33566, 33568, 33570, 33572, + 33574, 33587, 33589, 33591, 33593, 33595, 33597, 33599, + 33601, 33603, 33605, 33607, 33609, 33611, 33627, 33685, + 33687, 33689, 33691, 33693, 33736, 33738, 33740, 33742, + 33744, 33746, 33748, 33750, 33784, 33786, 33788, 33790, + 33792, 33794, 33796, 33798, 33800, 33802, 33804, 33822, + 33824, 33877, 33879, 33935, 33937, 33939, 33941, 33997, + 33999, 34001, 34003, 34019, 34021, 34023, 34025, 34083, + 34085, 34087, 34089, 34091, 34093, 34095, 34097, 34099, + 34101, 34103, 34105, 34107, 34109, 34111, 34113, 34133, + 34135, 34137, 34139, 34141, 34143, 34145, 34147, 34149, + 34151, 34153, 34155, 34157, 34159, 34161, 34163, 34165, + 34167, 34169, 34237, 34239, 34245, 34247, 34249, 34251, + 34253, 34255, 34298, 34300, 34302, 34304, 34306, 34314, + 34316, 34318, 34320, 34322, 34324, 34326, 34328, 34330, + 34332, 34334, 34336, 34338, 34372, 34374, 34376, 34378, + 34380, 34382, 34384, 34402, 34404, 34457, 34459, 34515, + 34517, 34519, 34521, 34577, 34579, 34581, 34583, 34599, + 34601, 34603, 34650, 34652, 34654, 34656, 34658, 34670, + 34672, 34674, 34728, 34730, 34732, 34734, 34736, 34738, + 34740, 34742, 34744, 34746, 34770, 34775, 34777, 34779, + 34781, 34783, 34785, 34787, 34789, 34791, 34817, 34819, + 34821, 34823, 34825, 34827, 34829, 34831, 34833, 34835, + 34837, 34839, 34841, 34843, 34845, 34847, 34849, 34851, + 34853, 34855, 34867, 34871, 34873, 34925, 34927, 34929, + 34931, 34933, 34935, 34937, 34998, 35000, 35002, 35004, + 35006, 35019, 35021, 35041, 35043, 35045, 35047, 35049, + 35051, 35053, 35055, 35057, 35059, 35061, 35063, 35065, + 35085, 35087, 35089, 35091, 35093, 35095, 35097, 35099, + 35103, 35105, 35107, 35109, 35111, 35113, 35153, 35155, + 35157, 35159, 35161, 35163, 35179, 35181, 35183, 35228, + 35230, 35232, 35234, 35236, 35238, 35240, 35294, 35296, + 35298, 35300, 35302, 35304, 35306, 35308, 35310, 35312, + 35314, 35331, 35333, 35335, 35337, 35358, 35360, 35362, + 35364, 35366, 35423, 35425, 35427, 35429, 35431, 35433, + 35435, 35437, 35481, 35483, 35485, 35487, 35489, 35491, + 35493, 35495, 35539, 35541, 35543, 35545, 35547, 35549, + 35551, 35553, 35555, 35557, 35559, 35561, 35563, 35565, + 35567, 35569, 35571, 35573, 35575, 35577, 35579, 35581, + 35583, 35585, 35587, 35589, 35591, 35593, 35612, 35621, + 35623, 35625, 35627, 35629, 35631, 35633, 35635, 35637, + 35639, 35647, 35649, 35651, 35653, 35655, 35657, 35659, + 35661, 35669, 35671, 35673, 35675, 35677, 35679, 35681, + 35683, 35685, 35687, 35689, 35691, 35693, 35695, 35697, + 35699, 35701, 35703, 35705, 35707, 35763, 35765, 35767, + 35769, 35771, 35773, 35775, 35792, 35794, 35796, 35798, + 35800, 35802, 35804, 35808, 35810, 35812, 35814, 35816, + 35818, 35836, 35838, 35840, 35842, 35851, 35853, 35855, + 35857, 35859, 35861, 35863, 35865, 35867, 35869, 35871, + 35882, 35884, 35886, 35888, 35890, 35892, 35894, 35896, + 35898, 35900, 35903, 35905, 35913, 35915, 35917, 35919, + 35921, 35923, 35942, 35947, 35949, 35951, 35995, 35997, + 35999, 36001, 36003, 36005, 36007, 36009, 36011, 36024, + 36026, 36028, 36030, 36041, 36043, 36045, 36047, 36049, + 36051, 36073, 36075, 36077, 36079, 36081, 36083, 36085, + 36087, 36089, 36091, 36093, 36095, 36097, 36099, 36101, + 36103, 36105, 36107, 36109, 36111, 36113, 36121, 36123, + 36125, 36127, 36129, 36131, 36133, 36135, 36137, 36139, + 36141, 36143, 36145, 36147, 36198, 36200, 36202, 36204, + 36206, 36208, 36210, 36212, 36214, 36216, 36218, 36220, + 36222, 36241, 36246, 36248, 36250, 36294, 36296, 36298, + 36300, 36302, 36304, 36306, 36308, 36310, 36312, 36314, + 36316, 36318, 36320, 36322, 36338, 36340, 36342, 36344, + 36346, 36348, 36350, 36352, 36354, 36399, 36401, 36415, + 36417, 36419, 36421, 36423, 36425, 36427, 36429, 36431, + 36433, 36435, 36494, 36496, 36498, 36500, 36502, 36504, + 36565, 36567, 36569, 36571, 36573, 36575, 36581, 36583, + 36585, 36587, 36589, 36606, 36608, 36610, 36612, 36614, + 36616, 36618, 36620, 36622, 36624, 36626, 36628, 36630, + 36632, 36634, 36636, 36638, 36640, 36642, 36644, 36656, + 36658, 36660, 36662, 36664, 36666, 36668, 36670, 36672, + 36719, 36721, 36723, 36737, 36739, 36741, 36743, 36745, + 36761, 36763, 36765, 36767, 36769, 36771, 36773, 36829, + 36831, 36833, 36835, 36837, 36839, 36841, 36843, 36899, + 36901, 36913, 36915, 36917, 36919, 36921, 36923, 36925, + 36927, 36929, 36931, 36933, 36941, 36943, 36945, 36947, + 36949, 36951, 36953, 36955, 36957, 36959, 36961, 36963, + 36965, 36967, 36969, 36971, 36986, 37030, 37032, 37034, + 37036, 37038, 37040, 37042, 37044, 37046, 37048, 37068, + 37070, 37072, 37074, 37076, 37078, 37080, 37082, 37084, + 37086, 37088, 37090, 37092, 37108, 37110, 37112, 37114, + 37116, 37118, 37120, 37122, 37124, 37126, 37128, 37130, + 37132, 37134, 37154, 37156, 37158, 37174, 37176, 37210, + 37212, 37214, 37216, 37250, 37252, 37254, 37256, 37258, + 37260, 37262, 37264, 37266, 37284, 37286, 37288, 37290, + 37292, 37299, 37306, 37308, 37310, 37312, 37314, 37370, + 37372, 37374, 37376, 37378, 37380, 37382, 37384, 37386, + 37388, 37390, 37392, 37436, 37438, 37440, 37442, 37444, + 37446, 37448, 37450, 37472, 37494, 37496, 37498, 37500, + 37502, 37504, 37506, 37508, 37510, 37512, 37514, 37516, + 37518, 37520, 37554, 37556, 37558, 37560, 37562, 37564, + 37566, 37568, 37602, 37604, 37606, 37608, 37610, 37612, + 37614, 37616, 37618, 37620, 37622, 37624, 37626, 37644, + 37646, 37648, 37650, 37658, 37660, 37662, 37664, 37666, + 37668, 37670, 37672, 37674, 37708, 37710, 37712, 37714, + 37716, 37718, 37720, 37736, 37738, 37740, 37742, 37744, + 37746, 37748, 37754, 37756, 37758, 37760, 37762, 37764, + 37766, 37768, 37770, 37772, 37774, 37776, 37778, 37780, + 37782, 37784, 37806, 37808, 37814, 37816, 37818, 37820, + 37838, 37840, 37842, 37844, 37846, 37848, 37850, 37852, + 37854, 37856, 37858, 37860, 37862, 37864, 37866, 37868, + 37870, 37882, 37884, 37886, 37888, 37912, 37914, 37916, + 37918, 37920, 37922, 37948, 37950, 37952, 37954, 37956, + 37958, 37960, 37962, 37964, 37981, 37983, 37985, 37987, + 37989, 37991, 37993, 37995, 37997, 37999, 38001, 38003, + 38005, 38007, 38009, 38011, 38013, 38015, 38017, 38019, + 38021, 38023, 38025, 38027, 38033, 38035, 38037, 38039, + 38098, 38100, 38102, 38104, 38106, 38108, 38110, 38112, + 38114, 38116, 38118, 38120, 38122, 38124, 38126, 38128, + 38130, 38132, 38134, 38136, 38138, 38140, 38142, 38144, + 38146, 38148, 38150, 38152, 38154, 38156, 38158, 38160, + 38162, 38164, 38166, 38168, 38170, 38172, 38174, 38176, + 38178, 38180, 38182, 38184, 38186, 38188, 38190, 38192, + 38194, 38238, 38296, 38298, 38300, 38354, 38356, 38358, + 38360, 38362, 38364, 38366, 38368, 38370, 38427, 38429, + 38431, 38433, 38435, 38437, 38439, 38441, 38498, 38500, + 38502, 38504, 38506, 38559, 38561, 38563, 38565, 38567, + 38569, 38571, 38573, 38575, 38577, 38628, 38630, 38632, + 38634, 38636, 38638, 38640, 38642, 38644, 38646, 38648, + 38650, 38652, 38695, 38697, 38699, 38701, 38703, 38705, + 38707, 38709 +}; + +static const short _char_ref_indicies[] = { + 0, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 4, 5, + 1, 1, 6, 7, 1, 1, 1, 1, + 8, 9, 10, 11, 12, 1, 13, 14, + 15, 16, 1, 17, 1, 18, 1, 19, + 1, 20, 1, 21, 1, 22, 1, 23, + 1, 24, 1, 25, 1, 26, 1, 27, + 1, 28, 1, 29, 1, 30, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 31, 1, 32, + 1, 33, 1, 34, 1, 35, 1, 36, + 1, 37, 1, 38, 1, 39, 1, 40, + 1, 41, 1, 42, 1, 43, 1, 44, + 1, 45, 1, 46, 1, 47, 1, 48, + 1, 49, 1, 50, 1, 51, 1, 1, + 1, 1, 1, 1, 1, 1, 52, 1, + 53, 1, 54, 1, 55, 1, 56, 1, + 57, 1, 58, 1, 59, 1, 60, 1, + 61, 1, 62, 1, 63, 1, 64, 1, + 65, 1, 66, 1, 67, 1, 68, 1, + 69, 1, 70, 1, 71, 1, 72, 1, + 73, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 74, 1, 75, 1, 76, 1, 77, 1, + 78, 1, 79, 1, 80, 1, 81, 1, + 82, 1, 83, 1, 84, 1, 85, 1, + 86, 1, 87, 1, 88, 1, 89, 90, + 1, 1, 1, 1, 1, 1, 1, 1, + 91, 1, 1, 92, 93, 1, 94, 1, + 95, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 96, + 1, 97, 1, 98, 1, 99, 1, 100, + 1, 101, 1, 102, 1, 103, 1, 104, + 105, 1, 106, 1, 107, 1, 108, 1, + 109, 1, 110, 1, 111, 1, 112, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 113, 1, 114, + 1, 115, 1, 116, 1, 117, 1, 118, + 1, 119, 1, 120, 1, 121, 1, 122, + 1, 123, 1, 124, 1, 125, 1, 126, + 1, 127, 1, 128, 1, 129, 1, 130, + 1, 131, 1, 132, 1, 133, 1, 134, + 1, 135, 1, 136, 1, 137, 1, 138, + 1, 139, 1, 140, 1, 141, 1, 142, + 1, 143, 1, 144, 1, 145, 1, 146, + 1, 147, 1, 1, 1, 1, 1, 1, + 148, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 149, 1, 150, 151, 152, 153, + 1, 154, 155, 1, 1, 156, 1, 1, + 157, 1, 1, 158, 159, 1, 160, 1, + 161, 1, 162, 1, 163, 1, 164, 1, + 165, 1, 166, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 167, + 1, 1, 1, 1, 1, 1, 1, 1, + 168, 1, 169, 1, 170, 1, 171, 1, + 172, 1, 173, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 174, 1, 175, 1, 176, 1, 177, 1, + 178, 1, 179, 1, 180, 1, 181, 1, + 182, 1, 183, 1, 184, 1, 185, 1, + 186, 1, 187, 1, 188, 1, 189, 1, + 190, 1, 191, 1, 192, 1, 193, 1, + 194, 1, 195, 1, 196, 1, 197, 1, + 1, 1, 198, 1, 1, 1, 199, 1, + 1, 1, 1, 1, 200, 1, 201, 1, + 202, 1, 203, 1, 204, 1, 205, 1, + 206, 1, 207, 1, 208, 1, 209, 1, + 210, 1, 211, 1, 212, 1, 213, 1, + 214, 1, 215, 1, 216, 1, 217, 1, + 218, 1, 219, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 220, 1, 221, 1, + 222, 1, 223, 1, 224, 1, 225, 1, + 226, 1, 227, 1, 228, 1, 229, 1, + 230, 1, 231, 1, 232, 1, 233, 1, + 234, 1, 235, 1, 236, 1, 237, 1, + 238, 1, 239, 1, 240, 1, 241, 1, + 1, 1, 1, 1, 1, 1, 1, 242, + 1, 1, 243, 1, 1, 1, 244, 1, + 245, 1, 246, 1, 247, 1, 248, 1, + 249, 1, 250, 1, 251, 1, 252, 1, + 253, 1, 254, 1, 255, 1, 256, 1, + 257, 1, 258, 1, 259, 1, 260, 1, + 261, 1, 262, 1, 263, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 264, 1, 265, 1, + 266, 1, 267, 1, 268, 1, 269, 1, + 270, 1, 271, 1, 272, 1, 273, 1, + 274, 1, 275, 1, 276, 1, 277, 1, + 278, 1, 279, 1, 280, 1, 281, 1, + 282, 1, 283, 1, 284, 1, 285, 1, + 286, 1, 287, 1, 288, 1, 289, 1, + 290, 1, 291, 1, 292, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 293, 1, 294, 1, 295, 1, 296, + 1, 297, 1, 298, 1, 299, 1, 300, + 1, 301, 1, 302, 1, 303, 1, 304, + 1, 305, 1, 306, 1, 307, 1, 308, + 1, 309, 1, 310, 1, 311, 1, 312, + 1, 1, 1, 1, 313, 1, 314, 1, + 315, 1, 316, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 317, 1, 318, 1, + 319, 1, 320, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 321, 1, 322, + 1, 323, 1, 324, 1, 325, 1, 326, + 1, 327, 1, 328, 1, 329, 1, 330, + 1, 331, 1, 332, 1, 333, 1, 334, + 1, 335, 1, 336, 1, 337, 1, 338, + 1, 339, 1, 340, 1, 341, 1, 342, + 1, 343, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 344, 1, 345, + 1, 346, 1, 347, 1, 348, 1, 349, + 1, 350, 1, 351, 1, 352, 1, 353, + 1, 354, 1, 355, 1, 356, 1, 357, + 1, 358, 1, 359, 1, 360, 1, 361, + 1, 362, 1, 363, 1, 364, 1, 365, + 1, 366, 1, 367, 1, 368, 1, 369, + 1, 370, 1, 371, 1, 372, 1, 373, + 1, 374, 1, 375, 1, 376, 1, 377, + 1, 378, 1, 379, 1, 380, 1, 381, + 1, 382, 1, 383, 1, 384, 1, 385, + 1, 386, 1, 387, 1, 388, 1, 389, + 1, 1, 1, 1, 1, 1, 1, 390, + 1, 391, 1, 392, 1, 393, 1, 394, + 1, 1, 1, 1, 1, 395, 1, 1, + 1, 1, 1, 1, 1, 1, 396, 1, + 1, 1, 1, 1, 1, 397, 1, 1, + 1, 1, 1, 1, 398, 1, 399, 1, + 400, 401, 1, 1, 402, 1, 1, 1, + 1, 1, 403, 1, 1, 1, 404, 1, + 405, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 406, 1, 407, 1, + 408, 1, 409, 1, 410, 1, 411, 1, + 412, 1, 413, 1, 414, 1, 415, 1, + 416, 1, 417, 1, 418, 1, 419, 1, + 420, 1, 421, 1, 422, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 423, + 424, 1, 425, 1, 426, 1, 427, 1, + 428, 1, 429, 1, 430, 1, 431, 1, + 432, 1, 433, 1, 434, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 435, 1, 436, 1, + 437, 1, 438, 1, 439, 1, 440, 1, + 441, 1, 442, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 443, 1, 444, 1, 445, + 1, 446, 1, 447, 1, 448, 1, 1, + 1, 1, 449, 1, 450, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 451, 1, + 452, 1, 453, 1, 454, 1, 455, 1, + 456, 1, 457, 1, 458, 1, 459, 1, + 1, 460, 1, 1, 461, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 462, 1, 463, 1, 464, 1, 465, + 1, 466, 1, 467, 1, 468, 1, 469, + 470, 1, 471, 1, 472, 1, 473, 1, + 474, 1, 475, 1, 476, 1, 477, 1, + 478, 1, 479, 1, 480, 1, 481, 1, + 482, 1, 483, 1, 484, 1, 485, 1, + 486, 1, 487, 1, 488, 1, 489, 1, + 490, 1, 491, 1, 492, 1, 493, 1, + 494, 1, 495, 1, 496, 1, 497, 1, + 498, 1, 499, 1, 500, 1, 501, 1, + 502, 1, 503, 1, 504, 1, 505, 1, + 506, 1, 1, 1, 507, 508, 1, 509, + 1, 510, 1, 511, 1, 512, 1, 1, + 1, 1, 1, 1, 1, 1, 513, 514, + 1, 515, 1, 516, 1, 517, 1, 518, + 1, 519, 1, 520, 1, 521, 1, 522, + 1, 523, 1, 524, 1, 525, 1, 526, + 527, 1, 1, 1, 1, 1, 1, 1, + 528, 1, 1, 1, 1, 1, 529, 1, + 1, 530, 531, 1, 532, 1, 533, 1, + 534, 1, 535, 1, 536, 1, 537, 1, + 538, 1, 539, 1, 540, 1, 541, 1, + 542, 1, 543, 1, 544, 1, 545, 1, + 546, 1, 547, 1, 548, 1, 1, 549, + 1, 550, 1, 551, 1, 552, 1, 553, + 1, 554, 1, 555, 1, 556, 1, 557, + 1, 558, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 559, 1, 560, 1, 561, + 1, 562, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 563, 1, 564, 1, 565, 1, + 566, 1, 567, 1, 568, 1, 569, 1, + 570, 1, 571, 1, 572, 1, 573, 1, + 574, 1, 575, 1, 576, 1, 577, 1, + 578, 1, 579, 1, 580, 1, 581, 1, + 582, 1, 583, 1, 584, 1, 585, 1, + 1, 1, 1, 1, 586, 1, 587, 1, + 588, 1, 589, 1, 590, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 591, 1, 592, + 1, 593, 1, 594, 1, 595, 1, 596, + 1, 597, 1, 598, 1, 599, 1, 600, + 1, 601, 1, 602, 1, 603, 1, 604, + 1, 605, 1, 606, 1, 607, 1, 608, + 1, 609, 1, 610, 1, 611, 1, 612, + 1, 613, 1, 614, 1, 615, 1, 616, + 1, 617, 1, 618, 1, 619, 1, 620, + 1, 621, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 622, 1, 623, 1, + 624, 1, 625, 1, 626, 1, 627, 1, + 628, 1, 629, 1, 630, 1, 631, 1, + 632, 1, 1, 633, 1, 634, 1, 635, + 1, 636, 1, 637, 1, 638, 1, 639, + 1, 640, 1, 641, 1, 642, 1, 643, + 1, 644, 1, 645, 1, 646, 1, 647, + 1, 648, 1, 649, 1, 650, 1, 651, + 1, 652, 1, 653, 1, 654, 1, 655, + 1, 656, 1, 657, 1, 658, 1, 659, + 1, 660, 661, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 662, 1, 1, 1, + 1, 1, 663, 1, 664, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 665, 1, 666, 1, 667, 1, 668, + 1, 669, 1, 670, 1, 1, 1, 1, + 1, 1, 671, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 672, 1, 673, + 1, 674, 1, 675, 1, 676, 1, 677, + 1, 678, 1, 679, 1, 680, 1, 681, + 1, 682, 1, 683, 1, 684, 1, 685, + 1, 686, 1, 687, 1, 688, 1, 689, + 1, 690, 1, 691, 1, 692, 1, 693, + 1, 694, 1, 695, 1, 696, 1, 697, + 1, 698, 1, 699, 1, 700, 1, 701, + 1, 702, 1, 703, 1, 704, 1, 705, + 1, 706, 1, 707, 1, 708, 1, 709, + 1, 710, 1, 711, 1, 712, 1, 713, + 1, 714, 1, 715, 1, 716, 1, 717, + 1, 718, 1, 719, 1, 1, 1, 1, + 1, 1, 720, 1, 721, 1, 722, 1, + 723, 1, 724, 1, 725, 1, 726, 1, + 727, 1, 728, 1, 729, 1, 730, 1, + 731, 1, 732, 1, 733, 1, 734, 1, + 735, 1, 736, 1, 737, 1, 738, 1, + 739, 1, 740, 1, 741, 1, 742, 1, + 743, 1, 744, 1, 1, 1, 1, 1, + 1, 745, 1, 746, 1, 747, 1, 748, + 1, 749, 1, 750, 1, 751, 1, 1, + 1, 1, 1, 752, 1, 753, 1, 754, + 1, 755, 1, 756, 1, 757, 1, 758, + 1, 759, 1, 760, 1, 761, 1, 762, + 1, 763, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 764, 1, 765, 1, 766, 1, + 767, 1, 768, 1, 769, 1, 770, 1, + 771, 1, 1, 1, 1, 1, 772, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 773, 1, 774, 775, 1, + 776, 777, 1, 1, 1, 1, 778, 779, + 1, 780, 781, 782, 1, 783, 784, 785, + 1, 1, 786, 1, 787, 1, 788, 1, + 789, 1, 790, 1, 791, 1, 792, 1, + 793, 1, 794, 1, 1, 1, 1, 1, + 1, 1, 795, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 796, 1, 797, 1, 798, 1, + 799, 1, 800, 1, 801, 1, 802, 1, + 803, 1, 804, 1, 805, 1, 806, 1, + 807, 1, 808, 1, 809, 1, 810, 1, + 811, 1, 812, 1, 813, 1, 814, 1, + 815, 1, 816, 1, 817, 1, 818, 1, + 819, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 820, + 1, 821, 1, 822, 1, 823, 1, 824, + 1, 825, 1, 826, 1, 1, 827, 1, + 828, 1, 829, 1, 830, 1, 831, 1, + 832, 1, 833, 1, 834, 1, 835, 1, + 836, 1, 837, 1, 838, 1, 839, 1, + 840, 1, 841, 1, 842, 1, 843, 1, + 844, 1, 845, 1, 846, 1, 847, 1, + 848, 1, 849, 1, 850, 1, 851, 1, + 852, 1, 853, 1, 854, 1, 1, 1, + 1, 1, 1, 1, 1, 855, 1, 856, + 1, 857, 1, 858, 1, 859, 1, 860, + 1, 861, 1, 862, 1, 863, 1, 864, + 1, 865, 1, 866, 1, 867, 1, 868, + 1, 1, 1, 1, 1, 1, 1, 869, + 1, 870, 1, 871, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 872, 1, 873, 1, + 874, 1, 875, 1, 876, 1, 877, 1, + 878, 1, 879, 1, 880, 1, 881, 1, + 882, 1, 883, 1, 884, 1, 885, 1, + 886, 1, 1, 1, 1, 1, 887, 1, + 888, 1, 889, 1, 890, 1, 891, 1, + 892, 1, 893, 1, 894, 1, 895, 1, + 896, 1, 1, 1, 1, 1, 1, 897, + 1, 898, 1, 899, 1, 900, 1, 901, + 1, 902, 1, 903, 1, 904, 1, 905, + 1, 906, 1, 907, 1, 908, 1, 909, + 1, 910, 1, 911, 1, 912, 1, 1, + 913, 1, 1, 914, 1, 1, 1, 1, + 1, 915, 1, 1, 1, 916, 1, 917, + 1, 918, 1, 919, 1, 920, 1, 921, + 1, 922, 1, 923, 1, 924, 1, 925, + 1, 1, 926, 1, 927, 1, 928, 1, + 929, 1, 930, 1, 931, 1, 932, 1, + 933, 1, 934, 1, 935, 1, 936, 1, + 937, 1, 938, 1, 939, 1, 940, 1, + 941, 1, 942, 1, 943, 1, 944, 1, + 945, 1, 946, 1, 947, 1, 948, 1, + 949, 1, 950, 1, 951, 1, 952, 1, + 953, 1, 954, 1, 1, 955, 1, 956, + 1, 957, 1, 958, 1, 959, 1, 960, + 1, 961, 1, 962, 1, 963, 1, 964, + 1, 965, 1, 966, 1, 967, 1, 968, + 1, 969, 1, 970, 1, 971, 1, 972, + 1, 973, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 974, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 975, 976, 977, 978, 1, 979, 980, 1, + 1, 1, 1, 1, 1, 1, 981, 1, + 1, 982, 983, 984, 1, 985, 1, 986, + 1, 987, 1, 988, 1, 989, 1, 990, + 1, 991, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 992, 1, 993, 1, 994, 1, + 995, 1, 996, 1, 997, 1, 998, 1, + 999, 1, 1, 1, 1000, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1001, 1, 1002, 1, + 1003, 1, 1004, 1, 1005, 1, 1006, 1, + 1007, 1, 1008, 1, 1009, 1, 1010, 1, + 1011, 1, 1012, 1, 1013, 1, 1014, 1, + 1015, 1, 1016, 1, 1017, 1, 1018, 1, + 1019, 1, 1020, 1, 1021, 1, 1022, 1, + 1023, 1, 1024, 1025, 1026, 1, 1, 1, + 1, 1027, 1, 1, 1, 1, 1, 1, + 1028, 1029, 1, 1030, 1, 1031, 1, 1032, + 1, 1033, 1, 1034, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1035, 1, 1036, 1, + 1037, 1, 1038, 1, 1039, 1, 1040, 1, + 1041, 1, 1042, 1, 1043, 1, 1044, 1, + 1045, 1, 1046, 1, 1047, 1, 1048, 1, + 1049, 1, 1050, 1, 1051, 1, 1052, 1, + 1053, 1, 1054, 1, 1055, 1, 1056, 1, + 1057, 1, 1058, 1, 1059, 1, 1060, 1, + 1061, 1, 1062, 1, 1063, 1, 1064, 1, + 1065, 1, 1066, 1, 1067, 1, 1068, 1, + 1069, 1, 1070, 1, 1071, 1, 1072, 1, + 1073, 1, 1074, 1, 1075, 1, 1076, 1, + 1077, 1, 1078, 1, 1079, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1080, 1, 1081, 1, + 1, 1082, 1, 1, 1083, 1, 1, 1, + 1, 1, 1084, 1, 1, 1, 1085, 1, + 1086, 1, 1087, 1, 1088, 1, 1089, 1, + 1090, 1, 1091, 1, 1092, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1093, 1, 1094, + 1, 1095, 1, 1096, 1, 1097, 1, 1098, + 1, 1099, 1, 1100, 1, 1101, 1, 1102, + 1, 1103, 1, 1104, 1, 1105, 1, 1106, + 1, 1107, 1, 1108, 1, 1109, 1, 1110, + 1, 1111, 1, 1112, 1, 1113, 1, 1114, + 1, 1115, 1, 1116, 1, 1117, 1, 1118, + 1, 1119, 1, 1120, 1, 1121, 1, 1122, + 1, 1123, 1, 1124, 1, 1125, 1, 1126, + 1, 1127, 1, 1128, 1, 1129, 1, 1130, + 1, 1131, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1132, 1, 1133, 1, 1134, 1, + 1135, 1, 1136, 1, 1137, 1, 1138, 1, + 1139, 1, 1140, 1, 1141, 1142, 1, 1143, + 1, 1144, 1, 1145, 1, 1146, 1, 1147, + 1, 1148, 1, 1149, 1, 1150, 1, 1151, + 1, 1152, 1, 1153, 1, 1154, 1, 1155, + 1, 1156, 1, 1, 1, 1, 1157, 1, + 1, 1, 1, 1158, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1159, 1, 1160, + 1161, 1, 1162, 1163, 1, 1, 1, 1, + 1, 1164, 1165, 1166, 1, 1, 1, 1167, + 1168, 1169, 1, 1170, 1, 1171, 1, 1172, + 1, 1173, 1, 1174, 1, 1175, 1, 1176, + 1, 1177, 1, 1178, 1, 1179, 1, 1180, + 1, 1181, 1, 1182, 1, 1183, 1, 1184, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1185, + 1, 1186, 1, 1187, 1, 1188, 1, 1189, + 1, 1190, 1, 1191, 1, 1192, 1, 1193, + 1, 1194, 1, 1195, 1, 1196, 1, 1197, + 1, 1198, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1199, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1200, 1, + 1201, 1, 1, 1, 1202, 1, 1203, 1, + 1204, 1, 1205, 1, 1206, 1, 1207, 1, + 1208, 1, 1209, 1, 1210, 1, 1211, 1, + 1212, 1, 1213, 1, 1214, 1, 1215, 1, + 1216, 1, 1217, 1, 1218, 1, 1219, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1220, 1, 1221, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1222, 1, 1223, + 1, 1224, 1, 1225, 1, 1226, 1, 1227, + 1, 1228, 1, 1229, 1, 1230, 1, 1231, + 1, 1232, 1, 1233, 1, 1234, 1, 1235, + 1, 1236, 1, 1237, 1, 1238, 1, 1239, + 1, 1240, 1, 1241, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1242, 1, 1243, 1, + 1244, 1, 1245, 1, 1246, 1, 1247, 1, + 1248, 1, 1249, 1, 1250, 1, 1251, 1, + 1252, 1, 1253, 1, 1, 1, 1, 1, + 1, 1, 1, 1254, 1, 1, 1, 1255, + 1, 1256, 1, 1257, 1, 1258, 1, 1259, + 1, 1260, 1, 1261, 1, 1262, 1, 1263, + 1, 1264, 1, 1265, 1, 1266, 1, 1267, + 1, 1268, 1, 1269, 1, 1270, 1, 1271, + 1, 1272, 1, 1273, 1, 1274, 1, 1275, + 1, 1276, 1, 1277, 1, 1, 1278, 1, + 1, 1, 1, 1, 1, 1, 1, 1279, + 1, 1, 1, 1280, 1, 1281, 1, 1282, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1283, + 1, 1284, 1, 1285, 1, 1286, 1, 1287, + 1, 1288, 1, 1289, 1, 1290, 1, 1291, + 1, 1292, 1, 1293, 1, 1294, 1, 1295, + 1, 1296, 1, 1297, 1, 1298, 1, 1299, + 1, 1300, 1, 1301, 1, 1302, 1, 1303, + 1, 1304, 1, 1305, 1, 1306, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1307, 1, 1308, 1, + 1, 1309, 1, 1, 1, 1, 1, 1, + 1, 1, 1310, 1, 1, 1, 1311, 1, + 1312, 1, 1313, 1, 1314, 1, 1315, 1, + 1316, 1, 1317, 1, 1318, 1, 1319, 1, + 1320, 1, 1321, 1, 1322, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1323, 1, 1324, 1, 1325, 1, 1326, 1, + 1327, 1, 1328, 1, 1329, 1, 1330, 1, + 1331, 1, 1332, 1, 1333, 1, 1334, 1, + 1335, 1, 1336, 1, 1337, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1338, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1339, 1, 1340, 1, 1341, + 1342, 1, 1, 1, 1, 1, 1343, 1344, + 1, 1345, 1, 1, 1, 1346, 1347, 1, + 1348, 1, 1349, 1, 1350, 1, 1351, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1352, 1353, 1, 1354, 1, 1355, 1, 1356, + 1, 1357, 1, 1358, 1, 1359, 1, 1360, + 1, 1361, 1, 1362, 1, 1363, 1, 1364, + 1, 1365, 1, 1366, 1, 1367, 1, 1368, + 1, 1369, 1, 1370, 1, 1371, 1, 1372, + 1, 1373, 1, 1374, 1, 1375, 1, 1376, + 1, 1, 1, 1377, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1378, + 1, 1379, 1, 1380, 1, 1381, 1, 1382, + 1, 1383, 1, 1384, 1, 1385, 1, 1386, + 1, 1387, 1, 1388, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1389, 1, 1390, 1, 1391, 1, 1392, 1393, + 1, 1394, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1395, 1, 1396, + 1397, 1398, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1399, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1400, 1, 1401, + 1, 1, 1, 1402, 1, 1403, 1, 1404, + 1, 1405, 1, 1406, 1, 1407, 1, 1408, + 1, 1409, 1, 1410, 1, 1411, 1, 1412, + 1, 1413, 1, 1414, 1, 1415, 1, 1416, + 1, 1417, 1, 1, 1, 1, 1, 1, + 1418, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1419, 1, 1420, 1, 1421, 1, 1422, 1, + 1423, 1, 1424, 1, 1425, 1, 1426, 1, + 1427, 1, 1428, 1, 1429, 1, 1430, 1, + 1431, 1, 1432, 1, 1433, 1, 1434, 1, + 1435, 1, 1436, 1, 1437, 1, 1438, 1, + 1439, 1, 1440, 1, 1441, 1, 1442, 1, + 1443, 1, 1444, 1, 1445, 1, 1446, 1, + 1447, 1, 1448, 1, 1449, 1, 1450, 1, + 1451, 1, 1452, 1, 1453, 1, 1454, 1, + 1455, 1, 1456, 1, 1457, 1, 1458, 1, + 1459, 1, 1460, 1, 1461, 1, 1462, 1, + 1463, 1, 1464, 1, 1465, 1, 1466, 1, + 1467, 1, 1468, 1, 1469, 1, 1470, 1, + 1471, 1, 1, 1, 1, 1, 1, 1472, + 1, 1473, 1, 1474, 1, 1475, 1, 1476, + 1, 1477, 1, 1478, 1, 1479, 1, 1480, + 1, 1481, 1, 1482, 1, 1483, 1, 1484, + 1, 1485, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1486, 1, + 1487, 1, 1488, 1, 1489, 1, 1490, 1, + 1491, 1, 1492, 1, 1493, 1, 1494, 1, + 1495, 1, 1496, 1, 1497, 1, 1498, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1499, 1, 1500, 1, 1501, + 1, 1, 1, 1, 1, 1502, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1503, 1, 1504, 1, 1505, 1, + 1506, 1, 1507, 1, 1508, 1, 1509, 1, + 1510, 1, 1511, 1, 1512, 1, 1513, 1, + 1514, 1, 1515, 1, 1516, 1, 1517, 1, + 1518, 1, 1519, 1, 1520, 1, 1521, 1, + 1, 1, 1, 1, 1, 1522, 1, 1, + 1523, 1, 1524, 1, 1525, 1, 1526, 1, + 1527, 1, 1528, 1, 1529, 1, 1530, 1, + 1531, 1, 1532, 1, 1533, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1534, 1, 1535, 1, + 1536, 1, 1537, 1, 1538, 1, 1539, 1, + 1540, 1, 1541, 1, 1542, 1, 1543, 1, + 1544, 1, 1545, 1, 1546, 1, 1547, 1, + 1548, 1, 1549, 1, 1550, 1, 1551, 1, + 1552, 1, 1553, 1, 1554, 1, 1555, 1, + 1556, 1, 1557, 1, 1558, 1, 1559, 1, + 1560, 1, 1, 1, 1, 1, 1, 1561, + 1, 1562, 1, 1563, 1, 1564, 1, 1565, + 1, 1566, 1, 1567, 1, 1568, 1, 1569, + 1, 1570, 1, 1, 1, 1, 1, 1, + 1571, 1, 1572, 1, 1573, 1, 1574, 1, + 1575, 1, 1576, 1, 1577, 1, 1578, 1, + 1579, 1, 1580, 1, 1581, 1, 1582, 1, + 1583, 1, 1584, 1, 1585, 1, 1586, 1, + 1587, 1, 1588, 1, 1589, 1, 1590, 1, + 1591, 1592, 1593, 1, 1, 1, 1, 1594, + 1, 1, 1, 1, 1, 1, 1595, 1596, + 1, 1597, 1, 1598, 1, 1599, 1, 1600, + 1, 1601, 1, 1602, 1, 1603, 1, 1604, + 1, 1605, 1, 1606, 1, 1607, 1, 1608, + 1, 1609, 1, 1610, 1, 1611, 1, 1612, + 1, 1613, 1, 1614, 1, 1615, 1, 1616, + 1, 1617, 1, 1618, 1, 1619, 1, 1620, + 1, 1621, 1, 1622, 1, 1623, 1, 1624, + 1, 1625, 1, 1626, 1, 1627, 1, 1628, + 1, 1629, 1, 1630, 1, 1631, 1, 1632, + 1, 1633, 1, 1634, 1, 1635, 1, 1636, + 1, 1637, 1, 1638, 1, 1639, 1, 1640, + 1, 1641, 1, 1642, 1, 1643, 1, 1644, + 1, 1645, 1, 1646, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1647, 1, 1648, + 1, 1649, 1, 1650, 1, 1651, 1, 1652, + 1, 1653, 1, 1654, 1, 1655, 1, 1656, + 1, 1657, 1, 1658, 1, 1659, 1, 1660, + 1, 1661, 1, 1662, 1, 1, 1, 1, + 1, 1, 1663, 1, 1664, 1, 1665, 1, + 1, 1, 1, 1, 1666, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1667, 1, + 1, 1, 1, 1, 1668, 1, 1669, 1, + 1670, 1, 1671, 1, 1672, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1673, 1, 1674, + 1, 1675, 1, 1676, 1, 1677, 1, 1678, + 1, 1679, 1, 1680, 1, 1681, 1, 1682, + 1, 1683, 1, 1684, 1, 1685, 1, 1686, + 1, 1687, 1, 1688, 1, 1689, 1, 1690, + 1, 1691, 1, 1692, 1, 1693, 1, 1694, + 1, 1695, 1, 1696, 1, 1697, 1, 1698, + 1, 1699, 1, 1700, 1, 1701, 1, 1702, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1703, 1, 1704, 1, 1705, 1, 1706, 1, + 1707, 1, 1708, 1, 1709, 1, 1710, 1, + 1711, 1, 1712, 1, 1713, 1, 1714, 1, + 1715, 1, 1716, 1, 1717, 1, 1718, 1, + 1719, 1, 1720, 1, 1721, 1, 1722, 1, + 1723, 1, 1724, 1, 1725, 1, 1726, 1, + 1727, 1, 1728, 1, 1729, 1, 1730, 1, + 1731, 1, 1732, 1, 1733, 1, 1, 1, + 1, 1, 1734, 1, 1735, 1, 1736, 1, + 1737, 1, 1738, 1, 1739, 1, 1740, 1, + 1741, 1, 1742, 1, 1743, 1, 1744, 1, + 1745, 1, 1746, 1, 1747, 1, 1748, 1, + 1749, 1, 1750, 1, 1751, 1, 1752, 1, + 1753, 1, 1754, 1, 1, 1, 1, 1755, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1756, 1, 1757, 1, 1758, + 1, 1759, 1, 1760, 1, 1761, 1, 1762, + 1, 1763, 1, 1764, 1, 1765, 1, 1766, + 1, 1767, 1768, 1, 1, 1769, 1, 1, + 1, 1, 1, 1770, 1, 1, 1, 1771, + 1, 1772, 1, 1773, 1, 1774, 1, 1775, + 1, 1776, 1, 1777, 1, 1, 1, 1, + 1, 1, 1, 1778, 1, 1779, 1, 1780, + 1, 1781, 1, 1782, 1, 1783, 1, 1784, + 1, 1785, 1, 1786, 1, 1787, 1, 1788, + 1, 1789, 1, 1790, 1, 1791, 1, 1792, + 1, 1793, 1, 1794, 1, 1795, 1, 1796, + 1, 1797, 1, 1798, 1, 1799, 1, 1800, + 1, 1801, 1, 1802, 1, 1803, 1, 1804, + 1, 1805, 1, 1806, 1, 1807, 1, 1808, + 1, 1809, 1, 1810, 1, 1811, 1, 1812, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1813, 1, + 1814, 1, 1815, 1816, 1, 1, 1, 1, + 1, 1, 1, 1, 1817, 1, 1, 1, + 1818, 1819, 1820, 1, 1821, 1, 1822, 1, + 1823, 1, 1824, 1, 1825, 1, 1826, 1, + 1827, 1, 1828, 1, 1829, 1, 1, 1, + 1830, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1831, 1, 1832, 1, + 1833, 1, 1834, 1, 1835, 1, 1836, 1, + 1837, 1, 1838, 1, 1839, 1, 1840, 1, + 1841, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1842, 1, 1, 1, + 1843, 1, 1844, 1, 1845, 1, 1846, 1, + 1847, 1, 1848, 1, 1849, 1, 1, 1, + 1, 1, 1, 1850, 1, 1851, 1, 1852, + 1, 1853, 1, 1854, 1, 1855, 1, 1856, + 1, 1857, 1, 1858, 1, 1859, 1, 1860, + 1, 1861, 1, 1862, 1, 1863, 1, 1864, + 1, 1865, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1866, 1, 1867, 1, + 1868, 1, 1869, 1, 1870, 1, 1871, 1, + 1872, 1, 1873, 1, 1874, 1, 1875, 1, + 1876, 1, 1877, 1, 1878, 1, 1879, 1, + 1880, 1, 1881, 1, 1882, 1, 1883, 1, + 1884, 1, 1885, 1, 1886, 1, 1887, 1, + 1888, 1, 1889, 1, 1890, 1, 1891, 1, + 1892, 1, 1893, 1, 1894, 1, 1895, 1, + 1896, 1, 1, 1, 1, 1897, 1, 1898, + 1, 1899, 1, 1900, 1, 1901, 1, 1902, + 1, 1903, 1, 1904, 1, 1905, 1, 1906, + 1, 1907, 1, 1908, 1, 1909, 1, 1910, + 1, 1911, 1, 1912, 1, 1913, 1, 1914, + 1, 1915, 1, 1916, 1, 1917, 1, 1918, + 1, 1919, 1, 1920, 1, 1921, 1, 1922, + 1, 1923, 1, 1924, 1, 1925, 1, 1926, + 1, 1927, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1928, 1, 1929, + 1, 1, 1, 1930, 1, 1931, 1, 1932, + 1, 1933, 1, 1934, 1, 1935, 1, 1936, + 1, 1937, 1, 1938, 1, 1939, 1, 1940, + 1, 1941, 1, 1942, 1, 1943, 1, 1944, + 1, 1945, 1, 1946, 1, 1947, 1, 1948, + 1, 1949, 1, 1950, 1, 1951, 1, 1952, + 1, 1, 1, 1, 1, 1, 1, 1953, + 1954, 1955, 1, 1956, 1957, 1, 1, 1, + 1958, 1, 1959, 1, 1960, 1, 1961, 1962, + 1963, 1, 1964, 1, 1965, 1, 1, 1, + 1, 1, 1966, 1, 1967, 1, 1968, 1, + 1969, 1, 1970, 1, 1971, 1, 1972, 1, + 1973, 1, 1974, 1, 1975, 1, 1976, 1, + 1977, 1, 1978, 1, 1979, 1, 1980, 1, + 1981, 1, 1982, 1, 1983, 1, 1984, 1, + 1985, 1, 1986, 1, 1987, 1, 1988, 1, + 1989, 1, 1990, 1, 1991, 1, 1992, 1, + 1993, 1, 1994, 1, 1995, 1, 1996, 1, + 1997, 1, 1, 1, 1, 1998, 1, 1, + 1, 1, 1, 1, 1999, 1, 2000, 1, + 2001, 1, 2002, 1, 2003, 1, 2004, 1, + 2005, 1, 2006, 1, 2007, 1, 2008, 1, + 2009, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2010, 1, 2011, 1, 2012, 1, 2013, + 1, 2014, 1, 2015, 1, 2016, 1, 2017, + 1, 2018, 1, 2019, 1, 2020, 1, 2021, + 1, 2022, 1, 2023, 1, 2024, 1, 2025, + 1, 2026, 1, 2027, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2028, 2029, 2030, + 1, 1, 1, 1, 2031, 1, 1, 1, + 1, 1, 1, 2032, 2033, 1, 2034, 1, + 2035, 1, 2036, 1, 2037, 1, 2038, 1, + 2039, 1, 2040, 1, 2041, 1, 2042, 1, + 2043, 1, 2044, 1, 2045, 1, 2046, 1, + 2047, 1, 2048, 1, 2049, 1, 2050, 1, + 2051, 1, 2052, 1, 2053, 1, 2054, 1, + 2055, 1, 2056, 1, 2057, 1, 2058, 1, + 2059, 1, 2060, 1, 2061, 1, 2062, 1, + 2063, 1, 2064, 1, 2065, 1, 2066, 1, + 2067, 1, 2068, 1, 2069, 1, 2070, 1, + 2071, 1, 2072, 1, 2073, 1, 2074, 1, + 2075, 1, 2076, 1, 2077, 2078, 1, 2079, + 1, 2080, 1, 2081, 1, 2082, 1, 2083, + 1, 2084, 1, 2085, 1, 2086, 1, 2087, + 1, 2088, 1, 2089, 1, 2090, 1, 2091, + 1, 2092, 1, 2093, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2094, 1, 2095, 1, 2096, 1, 2097, 1, + 2098, 1, 2099, 1, 2100, 1, 2101, 1, + 2102, 1, 2103, 1, 2104, 1, 1, 1, + 1, 1, 1, 2105, 1, 1, 2106, 1, + 2107, 1, 2108, 1, 2109, 1, 2110, 1, + 2111, 1, 2112, 1, 2113, 1, 2114, 1, + 2115, 1, 2116, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2117, 1, 2118, 1, + 1, 1, 1, 2119, 1, 1, 1, 1, + 1, 1, 2120, 2121, 1, 2122, 1, 2123, + 1, 2124, 1, 2125, 1, 2126, 1, 2127, + 1, 2128, 1, 2129, 1, 2130, 1, 2131, + 1, 2132, 1, 2133, 1, 2134, 1, 2135, + 1, 2136, 1, 2137, 1, 2138, 1, 2139, + 1, 2140, 1, 2141, 1, 2142, 1, 2143, + 1, 2144, 1, 2145, 1, 2146, 1, 2147, + 1, 2148, 1, 2149, 1, 2150, 1, 2151, + 1, 2152, 1, 2153, 1, 2154, 1, 2155, + 1, 2156, 1, 2157, 1, 2158, 1, 1, + 1, 1, 2159, 1, 2160, 1, 2161, 1, + 2162, 1, 2163, 1, 2164, 1, 2165, 1, + 2166, 1, 2167, 1, 2168, 1, 2169, 1, + 2170, 1, 2171, 1, 2172, 1, 2173, 1, + 2174, 1, 2175, 1, 2176, 1, 2177, 1, + 2178, 1, 2179, 1, 2180, 1, 2181, 1, + 2182, 1, 2183, 1, 2184, 1, 2185, 1, + 2186, 1, 2187, 1, 2188, 1, 2189, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2190, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2191, 1, + 2192, 1, 2193, 1, 2194, 1, 2195, 1, + 2196, 1, 2197, 1, 2198, 1, 2199, 1, + 2200, 1, 2201, 1, 2202, 1, 2203, 1, + 2204, 1, 2205, 1, 2206, 1, 2207, 1, + 1, 1, 2208, 1, 2209, 1, 2210, 1, + 2211, 1, 2212, 1, 2213, 1, 2214, 1, + 2215, 1, 2216, 1, 2217, 1, 2218, 1, + 2219, 1, 2220, 1, 2221, 1, 2222, 1, + 2223, 1, 2224, 1, 2225, 1, 2226, 1, + 2227, 1, 2228, 1, 2229, 1, 2230, 1, + 2231, 1, 2232, 1, 2233, 1, 1, 1, + 1, 1, 1, 2234, 1, 1, 2235, 1, + 2236, 1, 2237, 1, 2238, 1, 2239, 1, + 2240, 1, 2241, 1, 2242, 1, 2243, 1, + 2244, 1, 1, 1, 2245, 1, 2246, 1, + 2247, 1, 2248, 1, 2249, 1, 2250, 1, + 2251, 1, 2252, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2253, 1, 2254, 1, 2255, 1, 2256, 1, + 2257, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2258, 1, 2259, 1, 2260, 1, + 2261, 1, 2262, 1, 2263, 1, 2264, 1, + 2265, 1, 2266, 1, 2267, 1, 2268, 1, + 2269, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2270, 1, 2271, 1, 2272, 1, + 2273, 1, 2274, 1, 2275, 1, 2276, 2277, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2278, 1, 2279, 1, + 2280, 1, 2281, 1, 2282, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2283, 1, + 2284, 1, 2285, 1, 2286, 1, 2287, 1, + 2288, 1, 2289, 1, 2290, 1, 2291, 1, + 2292, 1, 2293, 1, 2294, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2295, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2296, 2297, 1, 2298, + 1, 2299, 1, 2300, 1, 2301, 1, 2302, + 1, 2303, 1, 2304, 1, 2305, 1, 2306, + 1, 2307, 1, 2308, 1, 2309, 1, 2310, + 1, 2311, 1, 2312, 1, 2313, 1, 2314, + 1, 2315, 1, 2316, 1, 2317, 1, 2318, + 1, 2319, 1, 2320, 1, 2321, 1, 2322, + 1, 2323, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2324, 1, 2325, 1, 2326, + 1, 2327, 1, 2328, 1, 2329, 1, 2330, + 1, 2331, 1, 2332, 1, 2333, 1, 2334, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2335, 2336, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2337, 1, 2338, 1, 2339, 1, 2340, 1, + 2341, 1, 2342, 1, 2343, 1, 2344, 1, + 2345, 1, 2346, 1, 2347, 1, 2348, 1, + 2349, 1, 2350, 1, 2351, 1, 2352, 1, + 2353, 1, 2354, 1, 2355, 1, 2356, 1, + 2357, 1, 2358, 1, 2359, 1, 2360, 1, + 2361, 1, 2362, 1, 2363, 1, 2364, 1, + 2365, 1, 2366, 1, 2367, 1, 2368, 1, + 2369, 1, 2370, 1, 2371, 1, 2372, 1, + 2373, 1, 2374, 1, 2375, 1, 2376, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2377, 1, 2378, 2379, 1, 2380, + 2381, 1, 1, 1, 1, 1, 2382, 1, + 2383, 2384, 1, 2385, 2386, 2387, 2388, 2389, + 1, 2390, 1, 2391, 1, 2392, 1, 2393, + 1, 2394, 1, 2395, 1, 2396, 1, 2397, + 1, 2398, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2399, 1, 2400, 1, 2401, 1, 2402, + 1, 2403, 1, 2404, 1, 2405, 1, 2406, + 1, 2407, 1, 2408, 1, 2409, 1, 2410, + 1, 2411, 1, 2412, 1, 2413, 1, 2414, + 1, 1, 1, 2415, 1, 1, 1, 2416, + 1, 2417, 1, 2418, 1, 2419, 1, 2420, + 1, 2421, 1, 2422, 1, 2423, 1, 2424, + 1, 2425, 1, 2426, 1, 2427, 1, 2428, + 1, 2429, 1, 2430, 1, 2431, 1, 2432, + 1, 2433, 1, 2434, 1, 2435, 1, 2436, + 1, 2437, 1, 2438, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2439, 1, 2440, 1, 2441, 1, 2442, 1, + 2443, 1, 2444, 1, 2445, 1, 2446, 1, + 2447, 1, 2448, 1, 2449, 1, 2450, 1, + 2451, 1, 2452, 1, 2453, 1, 2454, 1, + 2455, 1, 2456, 1, 2457, 1, 1, 1, + 1, 1, 1, 1, 1, 2458, 1, 2459, + 1, 2460, 1, 2461, 1, 2462, 1, 2463, + 1, 2464, 1, 2465, 2466, 1, 2467, 1, + 2468, 1, 2469, 1, 2470, 1, 2471, 1, + 2472, 1, 2473, 1, 2474, 1, 2475, 1, + 2476, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2477, 1, + 2478, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2479, 1, 2480, 1, 2481, 1, 2482, + 1, 2483, 1, 2484, 1, 1, 1, 1, + 1, 2485, 1, 2486, 1, 2487, 1, 2488, + 1, 2489, 1, 2490, 1, 2491, 1, 2492, + 1, 2493, 1, 2494, 1, 2495, 1, 2496, + 1, 2497, 1, 2498, 1, 2499, 1, 2500, + 1, 2501, 1, 2502, 1, 1, 2503, 1, + 2504, 2505, 1, 1, 2506, 1, 1, 2507, + 1, 1, 2508, 2509, 1, 2510, 1, 2511, + 1, 2512, 1, 2513, 1, 2514, 1, 2515, + 1, 2516, 1, 2517, 1, 2518, 1, 2519, + 1, 2520, 1, 2521, 1, 2522, 1, 2523, + 1, 2524, 1, 2525, 1, 2526, 1, 2527, + 1, 2528, 1, 2529, 1, 2530, 1, 2531, + 1, 2532, 1, 1, 1, 1, 1, 1, + 2533, 1, 2534, 1, 2535, 1, 2536, 1, + 2537, 1, 2538, 1, 2539, 1, 2540, 1, + 2541, 1, 2542, 1, 2543, 1, 2544, 1, + 2545, 1, 2546, 1, 2547, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2548, 1, + 1, 1, 2549, 1, 1, 1, 1, 1, + 2550, 1, 2551, 1, 2552, 1, 2553, 1, + 2554, 1, 2555, 1, 2556, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2557, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2558, 2559, 1, 2560, + 1, 2561, 1, 2562, 1, 2563, 1, 2564, + 1, 2565, 1, 2566, 1, 2567, 1, 2568, + 1, 2569, 1, 2570, 1, 2571, 1, 2572, + 1, 2573, 1, 2574, 1, 2575, 1, 2576, + 1, 2577, 1, 2578, 1, 2579, 1, 2580, + 1, 2581, 1, 2582, 1, 2583, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2584, 1, 2585, 1, 2586, 1, 2587, + 1, 2588, 1, 2589, 1, 2590, 1, 2591, + 1, 2592, 1, 2593, 1, 2594, 1, 2595, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2596, 1, 2597, + 1, 2598, 1, 2599, 1, 1, 1, 1, + 1, 2600, 1, 2601, 1, 2602, 1, 2603, + 1, 2604, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2605, 1, 1, 1, 1, 1, + 1, 1, 1, 2606, 1, 1, 1, 2607, + 1, 2608, 1, 2609, 1, 2610, 1, 2611, + 1, 2612, 1, 2613, 1, 2614, 1, 2615, + 1, 2616, 1, 2617, 1, 2618, 1, 1, + 2619, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2620, 1, 2621, 1, + 2622, 2623, 1, 2624, 2625, 1, 1, 1, + 1, 1, 2626, 1, 1, 2627, 2628, 1, + 2629, 1, 2630, 1, 2631, 1, 2632, 1, + 2633, 1, 2634, 1, 2635, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2636, + 1, 1, 1, 2637, 1, 2638, 1, 2639, + 1, 2640, 1, 2641, 1, 2642, 1, 2643, + 1, 2644, 1, 2645, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2646, 1, 2647, 1, + 2648, 1, 2649, 1, 1, 1, 2650, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2651, 1, 2652, 1, 2653, 1, + 2654, 1, 2655, 1, 2656, 1, 2657, 1, + 2658, 1, 2659, 1, 2660, 1, 2661, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2662, 1, 2663, 1, 2664, 1, 2665, + 1, 2666, 1, 2667, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2668, 1, 2669, 1, 1, + 1, 1, 2670, 1, 2671, 1, 2672, 1, + 2673, 1, 2674, 1, 2675, 1, 2676, 1, + 2677, 1, 2678, 1, 2679, 1, 2680, 1, + 2681, 1, 2682, 1, 2683, 1, 2684, 1, + 2685, 1, 2686, 1, 2687, 1, 2688, 1, + 2689, 1, 2690, 1, 2691, 1, 2692, 1, + 2693, 1, 2694, 1, 2695, 1, 2696, 1, + 2697, 1, 2698, 1, 2699, 1, 2700, 1, + 2701, 1, 2702, 1, 2703, 1, 2704, 1, + 2705, 1, 2706, 1, 2707, 1, 2708, 2709, + 1, 2710, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2711, + 2712, 2713, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2714, 1, 2715, 1, + 1, 1, 2716, 1, 2717, 1, 2718, 1, + 2719, 1, 2720, 1, 2721, 1, 2722, 1, + 2723, 1, 2724, 1, 2725, 1, 2726, 1, + 2727, 1, 2728, 1, 2729, 1, 2730, 1, + 2731, 1, 1, 1, 1, 1, 1, 2732, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2733, 1, 2734, 1, 2735, 1, 2736, + 1, 2737, 1, 2738, 1, 2739, 1, 2740, + 1, 2741, 1, 2742, 1, 2743, 1, 2744, + 1, 2745, 1, 2746, 1, 2747, 1, 2748, + 1, 2749, 1, 2750, 1, 2751, 1, 2752, + 1, 2753, 1, 2754, 1, 2755, 1, 2756, + 1, 2757, 1, 2758, 1, 2759, 1, 2760, + 1, 2761, 1, 2762, 1, 2763, 1, 2764, + 1, 2765, 1, 2766, 1, 2767, 1, 2768, + 1, 2769, 1, 2770, 1, 2771, 1, 2772, + 1, 2773, 1, 2774, 1, 2775, 1, 2776, + 1, 2777, 1, 2778, 1, 2779, 1, 2780, + 1, 2781, 1, 2782, 1, 2783, 1, 2784, + 1, 1, 1, 1, 1, 1, 2785, 1, + 2786, 1, 2787, 1, 2788, 1, 2789, 1, + 2790, 1, 2791, 1, 2792, 1, 2793, 1, + 2794, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2795, 1, 2796, + 1, 2797, 1, 1, 1, 1, 1, 2798, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2799, 1, 2800, 1, + 2801, 1, 2802, 1, 2803, 1, 2804, 1, + 2805, 1, 2806, 1, 2807, 1, 2808, 1, + 2809, 1, 2810, 1, 2811, 1, 2812, 1, + 2813, 1, 2814, 1, 2815, 1, 2816, 1, + 2817, 1, 1, 1, 1, 1, 1, 2818, + 1, 1, 2819, 1, 2820, 1, 2821, 1, + 2822, 1, 2823, 1, 2824, 1, 2825, 1, + 2826, 1, 2827, 1, 2828, 1, 2829, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2830, 1, + 2831, 1, 2832, 1, 2833, 1, 2834, 1, + 2835, 1, 2836, 1, 2837, 1, 2838, 1, + 2839, 1, 2840, 1, 2841, 1, 2842, 1, + 2843, 1, 2844, 1, 2845, 1, 2846, 1, + 2847, 1, 2848, 1, 2849, 1, 2850, 1, + 2851, 1, 2852, 1, 2853, 1, 2854, 1, + 2855, 1, 2856, 1, 1, 1, 1, 1, + 1, 2857, 1, 2858, 1, 2859, 1, 2860, + 1, 2861, 1, 2862, 1, 2863, 1, 2864, + 1, 2865, 1, 2866, 1, 1, 1, 1, + 1, 1, 2867, 1, 2868, 1, 2869, 1, + 2870, 1, 2871, 1, 2872, 1, 2873, 1, + 2874, 1, 2875, 1, 2876, 1, 1, 1, + 1, 2877, 1, 2878, 1, 2879, 1, 2880, + 1, 2881, 1, 2882, 1, 2883, 1, 2884, + 1, 2885, 1, 2886, 1, 2887, 1, 2888, + 1, 2889, 1, 2890, 1, 2891, 1, 2892, + 1, 2893, 1, 2894, 1, 2895, 1, 2896, + 1, 2897, 1, 2898, 1, 2899, 1, 2900, + 1, 1, 1, 1, 2901, 1, 2902, 1, + 2903, 1, 2904, 1, 2905, 1, 2906, 1, + 2907, 1, 2908, 1, 2909, 1, 2910, 1, + 2911, 1, 2912, 1, 2913, 1, 2914, 1, + 2915, 1, 1, 1, 1, 1, 1, 2916, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2917, 1, 2918, 1, 1, 2919, 1, + 2920, 2921, 1, 1, 1, 2922, 1, 2923, + 1, 2924, 1, 2925, 2926, 2927, 1, 2928, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2929, + 1, 2930, 1, 2931, 1, 2932, 1, 2933, + 1, 2934, 1, 2935, 1, 2936, 1, 2937, + 1, 2938, 1, 2939, 1, 2940, 1, 2941, + 1, 2942, 1, 2943, 1, 2944, 1, 2945, + 1, 2946, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2947, + 1, 1, 1, 2948, 1, 1, 1, 2949, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2950, + 1, 2951, 1, 2952, 1, 2953, 1, 2954, + 1, 2955, 1, 2956, 1, 2957, 1, 2958, + 1, 2959, 1, 2960, 1, 2961, 1, 2962, + 1, 2963, 1, 2964, 1, 2965, 1, 2966, + 1, 2967, 1, 2968, 1, 1, 1, 1, + 1, 1, 1, 2969, 1, 1, 1, 1, + 1, 2970, 1, 1, 2971, 1, 2972, 1, + 2973, 1, 2974, 1, 2975, 1, 2976, 1, + 2977, 1, 2978, 1, 2979, 1, 2980, 1, + 2981, 1, 2982, 1, 2983, 1, 2984, 1, + 2985, 1, 2986, 1, 2987, 1, 2988, 1, + 2989, 1, 2990, 1, 2991, 1, 2992, 1, + 2993, 1, 2994, 1, 2995, 1, 2996, 1, + 2997, 1, 2998, 1, 2999, 1, 3000, 1, + 3001, 1, 3002, 1, 3003, 1, 3004, 1, + 3005, 1, 3006, 1, 3007, 1, 3008, 1, + 3009, 1, 3010, 1, 3011, 1, 3012, 1, + 3013, 1, 3014, 1, 3015, 1, 3016, 1, + 3017, 1, 3018, 1, 3019, 1, 3020, 1, + 3021, 1, 3022, 1, 3023, 1, 3024, 1, + 1, 3025, 1, 3026, 1, 3027, 1, 3028, + 1, 3029, 1, 3030, 1, 3031, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3032, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3033, 1, 3034, + 1, 3035, 1, 3036, 1, 3037, 1, 3038, + 1, 3039, 1, 3040, 1, 3041, 1, 3042, + 1, 3043, 1, 3044, 1, 3045, 1, 3046, + 1, 3047, 1, 3048, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3049, 1, 3050, 1, 3051, 1, 3052, + 1, 3053, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3054, 1, 3055, 1, 3056, + 1, 3057, 1, 3058, 1, 3059, 1, 3060, + 1, 3061, 1, 3062, 1, 3063, 1, 3064, + 1, 3065, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3066, 1, 3067, 1, 3068, + 1, 3069, 1, 3070, 1, 3071, 1, 3072, + 1, 3073, 1, 3074, 1, 3075, 1, 3076, + 1, 3077, 1, 3078, 1, 3079, 1, 3080, + 1, 3081, 1, 3082, 1, 3083, 3084, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3085, 1, 1, 3086, 1, 3087, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3088, 1, 3089, + 1, 3090, 1, 3091, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3092, 1, 3093, + 1, 3094, 1, 3095, 1, 3096, 1, 3097, + 1, 3098, 1, 1, 1, 1, 3099, 1, + 3100, 1, 3101, 1, 3102, 1, 3103, 1, + 3104, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3105, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3106, 3107, 1, 3108, 1, 3109, 1, 3110, + 1, 3111, 1, 3112, 1, 3113, 1, 3114, + 1, 3115, 1, 3116, 1, 3117, 1, 3118, + 1, 3119, 1, 3120, 1, 3121, 1, 3122, + 1, 3123, 1, 3124, 1, 3125, 1, 3126, + 1, 3127, 1, 3128, 1, 3129, 1, 3130, + 1, 3131, 1, 3132, 1, 3133, 1, 3134, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3135, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3136, + 1, 3137, 1, 3138, 1, 3139, 1, 3140, + 1, 3141, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3142, 1, 3143, 1, 3144, + 1, 3145, 1, 3146, 1, 3147, 1, 3148, + 1, 3149, 1, 3150, 1, 3151, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3152, + 3153, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3154, 1, + 3155, 1, 1, 3156, 1, 3157, 3158, 1, + 1, 1, 1, 1, 3159, 1, 1, 3160, + 3161, 1, 3162, 1, 3163, 1, 3164, 1, + 3165, 1, 3166, 1, 3167, 1, 3168, 1, + 3169, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3170, 1, 3171, 1, 3172, + 1, 3173, 1, 3174, 1, 3175, 1, 3176, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3177, 1, 3178, 1, 3179, 1, + 3180, 1, 1, 1, 3181, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3182, 1, 3183, 1, 3184, 1, 3185, 1, + 3186, 1, 3187, 1, 3188, 1, 3189, 1, + 3190, 1, 3191, 1, 3192, 1, 3193, 1, + 3194, 1, 1, 1, 3195, 1, 3196, 1, + 3197, 1, 3198, 1, 3199, 1, 3200, 1, + 3201, 1, 3202, 1, 3203, 1, 3204, 1, + 3205, 1, 3206, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3207, 1, 3208, + 1, 3209, 1, 3210, 1, 3211, 1, 3212, + 1, 3213, 1, 3214, 1, 3215, 1, 3216, + 1, 3217, 1, 3218, 1, 3219, 1, 3220, + 1, 3221, 1, 3222, 1, 3223, 1, 3224, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3225, 3226, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3227, 1, 3228, 1, 3229, 1, 3230, 1, + 3231, 1, 3232, 1, 3233, 1, 3234, 1, + 3235, 1, 3236, 1, 3237, 1, 3238, 1, + 3239, 1, 3240, 1, 3241, 1, 3242, 1, + 3243, 1, 3244, 1, 3245, 1, 3246, 1, + 3247, 1, 3248, 1, 3249, 1, 3250, 1, + 3251, 1, 3252, 1, 3253, 1, 3254, 1, + 3255, 1, 3256, 1, 3257, 1, 3258, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3259, + 1, 3260, 1, 3261, 1, 3262, 1, 3263, + 1, 3264, 1, 3265, 1, 3266, 3267, 3268, + 3269, 1, 3270, 3271, 1, 1, 1, 1, + 1, 3272, 3273, 3274, 3275, 1, 3276, 3277, + 3278, 3279, 1, 3280, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3281, 1, 3282, 1, 3283, 1, + 3284, 1, 3285, 1, 3286, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3287, 1, 3288, 1, 3289, 1, 3290, 1, + 3291, 1, 3292, 1, 3293, 1, 3294, 1, + 3295, 1, 3296, 1, 3297, 1, 3298, 1, + 3299, 1, 3300, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3301, 1, 3302, 1, 3303, 1, + 3304, 1, 3305, 1, 3306, 1, 3307, 1, + 3308, 1, 3309, 1, 3310, 1, 3311, 1, + 3312, 1, 3313, 1, 3314, 1, 3315, 1, + 3316, 1, 3317, 1, 3318, 1, 3319, 1, + 3320, 1, 1, 1, 1, 3321, 1, 3322, + 1, 3323, 1, 3324, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3325, 1, 3326, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3327, 1, 3328, 1, + 3329, 1, 3330, 1, 3331, 1, 3332, 1, + 1, 1, 1, 1, 3333, 1, 3334, 1, + 3335, 1, 3336, 1, 3337, 1, 3338, 1, + 3339, 1, 3340, 1, 3341, 1, 3342, 1, + 3343, 1, 3344, 1, 3345, 1, 3346, 1, + 3347, 1, 3348, 1, 3349, 1, 3350, 1, + 3351, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3352, 1, 3353, + 1, 3354, 1, 3355, 1, 3356, 1, 3357, + 1, 1, 1, 1, 1, 1, 1, 1, + 3358, 1, 3359, 1, 3360, 1, 3361, 1, + 3362, 1, 3363, 1, 3364, 1, 1, 3365, + 3366, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3367, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3368, 1, 1, 3369, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3370, 1, 1, 3371, 1, + 3372, 1, 3373, 1, 3374, 1, 3375, 1, + 3376, 1, 1, 1, 1, 1, 1, 3377, + 1, 3378, 1, 3379, 1, 3380, 1, 3381, + 1, 3382, 1, 3383, 1, 3384, 1, 3385, + 1, 3386, 1, 3387, 1, 3388, 1, 3389, + 1, 3390, 1, 3391, 1, 3392, 1, 3393, + 1, 3394, 1, 3395, 1, 3396, 1, 3397, + 1, 3398, 1, 3399, 1, 3400, 1, 3401, + 1, 3402, 1, 3403, 1, 3404, 1, 3405, + 1, 3406, 1, 3407, 1, 3408, 1, 3409, + 1, 3410, 1, 3411, 1, 3412, 1, 3413, + 1, 1, 1, 1, 1, 3414, 1, 3415, + 1, 3416, 1, 3417, 1, 3418, 1, 3419, + 1, 3420, 1, 3421, 1, 3422, 1, 3423, + 1, 3424, 1, 3425, 1, 3426, 1, 3427, + 1, 3428, 1, 3429, 1, 3430, 1, 3431, + 1, 3432, 1, 3433, 1, 3434, 1, 3435, + 1, 3436, 1, 1, 1, 1, 1, 3437, + 1, 3438, 1, 3439, 1, 3440, 1, 3441, + 1, 3442, 1, 3443, 1, 3444, 1, 3445, + 1, 3446, 1, 3447, 1, 3448, 1, 3449, + 1, 3450, 1, 3451, 1, 3452, 1, 3453, + 1, 3454, 1, 3455, 1, 3456, 1, 3457, + 1, 3458, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3459, 1, 3460, 1, 3461, 1, + 3462, 1, 3463, 1, 3464, 1, 3465, 1, + 3466, 1, 3467, 1, 3468, 1, 3469, 1, + 3470, 1, 3471, 1, 3472, 1, 3473, 1, + 3474, 1, 3475, 1, 3476, 1, 3477, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3478, 3479, 3480, 3481, + 3482, 1, 1, 1, 1, 1, 1, 1, + 1, 3483, 1, 1, 1, 3484, 1, 1, + 3485, 1, 3486, 1, 3487, 1, 3488, 1, + 3489, 1, 3490, 1, 3491, 1, 3492, 1, + 3493, 1, 3494, 1, 3495, 1, 3496, 1, + 3497, 1, 3498, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3499, 1, 3500, 1, 3501, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3502, 1, 3503, 1, + 3504, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3505, 1, 1, 1, 1, 3506, + 1, 3507, 1, 3508, 1, 3509, 1, 3510, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3511, 1, 3512, + 1, 3513, 1, 3514, 1, 3515, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3516, + 1, 1, 1, 1, 1, 1, 3517, 3518, + 1, 3519, 1, 3520, 1, 3521, 1, 3522, + 1, 3523, 1, 3524, 1, 3525, 1, 3526, + 1, 3527, 1, 3528, 1, 3529, 1, 3530, + 1, 3531, 1, 3532, 1, 3533, 1, 3534, + 1, 3535, 1, 3536, 1, 3537, 1, 3538, + 1, 3539, 1, 3540, 1, 3541, 1, 3542, + 1, 3543, 1, 3544, 1, 3545, 1, 3546, + 1, 3547, 1, 3548, 1, 3549, 1, 3550, + 1, 3551, 1, 3552, 1, 3553, 1, 3554, + 1, 3555, 1, 3556, 1, 3557, 1, 3558, + 1, 3559, 1, 3560, 1, 3561, 1, 3562, + 1, 3563, 1, 3564, 3565, 1, 1, 1, + 1, 1, 1, 1, 1, 3566, 1, 1, + 1, 3567, 1, 3568, 1, 3569, 1, 3570, + 1, 3571, 1, 3572, 1, 3573, 1, 3574, + 1, 3575, 1, 3576, 1, 3577, 1, 3578, + 1, 3579, 1, 3580, 1, 3581, 1, 3582, + 1, 3583, 1, 3584, 1, 1, 3585, 1, + 1, 1, 1, 1, 3586, 1, 1, 1, + 3587, 1, 3588, 1, 3589, 1, 3590, 1, + 3591, 1, 3592, 1, 3593, 1, 3594, 1, + 3595, 1, 3596, 1, 3597, 1, 1, 1, + 1, 1, 1, 1, 3598, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3599, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3600, 1, 3601, 1, + 1, 3602, 1, 1, 1, 1, 1, 1, + 1, 1, 3603, 1, 1, 1, 3604, 1, + 3605, 1, 3606, 1, 3607, 1, 3608, 1, + 3609, 1, 3610, 1, 3611, 1, 3612, 1, + 3613, 1, 3614, 1, 3615, 1, 3616, 1, + 3617, 1, 3618, 1, 3619, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3620, 1, 3621, 1, + 3622, 1, 3623, 1, 3624, 1, 3625, 1, + 3626, 1, 3627, 1, 3628, 1, 3629, 1, + 3630, 1, 3631, 1, 3632, 1, 3633, 1, + 3634, 1, 3635, 1, 3636, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3637, 1, 3638, + 3639, 3640, 3641, 1, 1, 1, 1, 1, + 1, 1, 1, 3642, 1, 1, 1, 3643, + 1, 3644, 1, 3645, 1, 3646, 1, 3647, + 1, 3648, 1, 3649, 1, 3650, 1, 3651, + 1, 3652, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3653, 1, 3654, 1, 3655, 1, 3656, + 1, 3657, 1, 3658, 1, 3659, 1, 3660, + 1, 3661, 1, 3662, 1, 3663, 1, 3664, + 1, 3665, 1, 3666, 1, 3667, 1, 3668, + 1, 3669, 1, 3670, 1, 3671, 1, 3672, + 1, 3673, 1, 3674, 1, 3675, 1, 3676, + 1, 3677, 1, 3678, 1, 3679, 1, 3680, + 1, 3681, 1, 3682, 1, 3683, 1, 3684, + 1, 3685, 1, 3686, 3687, 3688, 1, 3689, + 3690, 3691, 1, 1, 1, 1, 3692, 3693, + 3694, 3695, 3696, 1, 3697, 3698, 3699, 3700, + 1, 3701, 1, 3702, 1, 3703, 1, 3704, + 1, 3705, 1, 3706, 1, 3707, 1, 3708, + 1, 3709, 1, 3710, 1, 3711, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3712, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3713, 1, + 1, 1, 1, 3714, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3715, + 1, 1, 1, 3716, 1, 3717, 1, 3718, + 1, 3719, 1, 3720, 1, 3721, 1, 3722, + 1, 3723, 1, 3724, 1, 3725, 1, 3726, + 1, 3727, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3728, 1, 3729, 1, 3730, 1, 3731, 1, + 3732, 1, 3733, 1, 3734, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3735, + 1, 3736, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3737, 1, 3738, 1, 3739, + 1, 3740, 1, 3741, 1, 3742, 1, 3743, + 1, 3744, 1, 3745, 1, 3746, 1, 3747, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3748, 1, + 3749, 1, 1, 1, 1, 1, 1, 1, + 1, 3750, 1, 3751, 1, 3752, 1, 3753, + 1, 3754, 1, 3755, 1, 1, 3756, 1, + 3757, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3758, 1, + 1, 3759, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3760, 1, 1, 3761, 1, 3762, 1, 3763, + 1, 3764, 1, 3765, 1, 3766, 1, 3767, + 1, 3768, 1, 3769, 1, 3770, 1, 3771, + 1, 3772, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3773, 1, 1, 1, 1, + 1, 1, 3774, 3775, 1, 1, 1, 1, + 3776, 3777, 1, 1, 1, 1, 1, 1, + 3778, 1, 3779, 1, 3780, 1, 3781, 1, + 3782, 1, 3783, 1, 3784, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3785, 1, 3786, 3787, 3788, 3789, + 3790, 3791, 3792, 3793, 1, 3794, 1, 3795, + 1, 3796, 1, 3797, 1, 3798, 1, 3799, + 1, 3800, 1, 3801, 1, 3802, 1, 3803, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3804, 1, 3805, 1, 3806, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3807, + 1, 3808, 1, 3809, 1, 1, 1, 3810, + 1, 3811, 1, 3812, 1, 3813, 1, 3814, + 1, 3815, 1, 3816, 1, 3817, 1, 3818, + 1, 1, 1, 1, 1, 1, 1, 1, + 3819, 1, 3820, 1, 3821, 1, 3822, 1, + 3823, 1, 3824, 1, 3825, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3826, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3827, 1, 1, 1, 3828, 1, + 1, 1, 3829, 1, 1, 1, 1, 1, + 3830, 3831, 1, 3832, 1, 3833, 1, 3834, + 1, 3835, 1, 3836, 1, 3837, 1, 3838, + 1, 3839, 1, 3840, 1, 3841, 1, 3842, + 1, 3843, 1, 3844, 1, 3845, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3846, + 1, 3847, 1, 3848, 1, 3849, 1, 3850, + 1, 3851, 1, 3852, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3853, 1, 1, 1, + 1, 3854, 1, 3855, 1, 3856, 1, 3857, + 1, 3858, 1, 3859, 1, 3860, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3861, + 1, 3862, 1, 3863, 1, 3864, 1, 3865, + 1, 3866, 1, 3867, 1, 3868, 1, 3869, + 1, 3870, 1, 1, 1, 1, 1, 3871, + 1, 3872, 1, 3873, 1, 3874, 1, 3875, + 1, 3876, 1, 3877, 1, 3878, 1, 3879, + 1, 3880, 1, 3881, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3882, 3883, + 3884, 3885, 3886, 3887, 1, 1, 3888, 1, + 3889, 3890, 1, 3891, 3892, 3893, 1, 3894, + 3895, 1, 3896, 1, 3897, 1, 3898, 1, + 3899, 1, 3900, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3901, 1, 3902, 1, 3903, 1, 3904, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3905, 1, 1, 3906, 1, 3907, + 1, 3908, 1, 3909, 1, 3910, 1, 3911, + 1, 3912, 1, 3913, 1, 3914, 1, 3915, + 1, 3916, 1, 3917, 1, 3918, 1, 3919, + 1, 3920, 1, 3921, 1, 3922, 1, 3923, + 1, 3924, 1, 3925, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3926, 1, 3927, + 1, 3928, 1, 3929, 3930, 1, 3931, 1, + 3932, 1, 3933, 1, 3934, 1, 3935, 1, + 3936, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3937, 1, 3938, 1, + 3939, 1, 3940, 1, 3941, 1, 3942, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3943, + 1, 3944, 1, 3945, 1, 3946, 1, 3947, + 1, 3948, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3949, 1, 3950, 1, 3951, + 1, 3952, 1, 3953, 1, 3954, 1, 3955, + 1, 3956, 1, 3957, 1, 3958, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3959, + 1, 1, 3960, 1, 3961, 1, 3962, 1, + 3963, 1, 3964, 1, 3965, 1, 3966, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 3967, 1, 3968, 1, 3969, 1, 3970, 1, + 3971, 1, 3972, 1, 3973, 1, 3974, 1, + 3975, 1, 3976, 1, 3977, 1, 3978, 1, + 3979, 1, 3980, 1, 3981, 1, 1, 1, + 1, 1, 1, 3982, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3983, 1, 3984, 1, 3985, 1, + 3986, 1, 3987, 1, 3988, 1, 3989, 1, + 3990, 1, 3991, 1, 3992, 1, 3993, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3994, 1, 1, 1, 3995, 3996, + 3997, 3998, 3999, 1, 4000, 1, 1, 1, + 1, 1, 1, 1, 4001, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4002, 1, 4003, 1, 4004, 1, 4005, 1, + 4006, 1, 4007, 1, 4008, 1, 4009, 1, + 4010, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4011, 1, 1, 1, + 4012, 1, 4013, 1, 4014, 1, 4015, 1, + 4016, 1, 4017, 1, 4018, 1, 4019, 1, + 4020, 1, 4021, 1, 4022, 1, 4023, 1, + 4024, 1, 4025, 1, 1, 4026, 1, 4027, + 1, 4028, 1, 4029, 1, 4030, 1, 4031, + 1, 4032, 1, 4033, 1, 4034, 1, 4035, + 1, 4036, 1, 4037, 1, 4038, 1, 4039, + 1, 4040, 1, 4041, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4042, 1, 4043, 1, + 4044, 1, 4045, 1, 4046, 1, 4047, 1, + 4048, 1, 4049, 1, 4050, 1, 4051, 1, + 4052, 1, 4053, 1, 4054, 1, 4055, 1, + 4056, 1, 4057, 1, 4058, 1, 4059, 1, + 4060, 1, 4061, 1, 4062, 1, 4063, 1, + 4064, 1, 4065, 1, 4066, 1, 4067, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4068, 1, 1, 1, 4069, 1, 4070, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4071, 1, 4072, 1, 4073, 1, 1, + 1, 1, 1, 1, 4074, 4075, 1, 4076, + 1, 4077, 1, 4078, 1, 4079, 1, 4080, + 1, 4081, 1, 4082, 1, 4083, 1, 4084, + 1, 4085, 1, 4086, 1, 4087, 1, 4088, + 1, 4089, 1, 4090, 1, 4091, 1, 4092, + 1, 4093, 1, 4094, 1, 4095, 1, 4096, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4097, 1, 1, 1, 1, 1, 1, 1, + 4098, 1, 1, 1, 1, 1, 4099, 1, + 4100, 1, 4101, 1, 4102, 1, 4103, 1, + 4104, 1, 4105, 1, 4106, 1, 4107, 1, + 4108, 1, 4109, 1, 4110, 1, 4111, 1, + 4112, 1, 4113, 1, 4114, 1, 4115, 1, + 4116, 1, 4117, 1, 4118, 1, 4119, 1, + 4120, 1, 4121, 1, 4122, 1, 4123, 1, + 4124, 1, 4125, 1, 4126, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4127, 1, + 4128, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4129, 1, + 4130, 1, 4131, 1, 4132, 1, 4133, 1, + 4134, 1, 4135, 1, 4136, 1, 1, 1, + 4137, 1, 1, 4138, 4139, 1, 4140, 1, + 4141, 1, 4142, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4143, 1, 4144, 1, 4145, + 1, 4146, 1, 4147, 1, 4148, 1, 4149, + 1, 4150, 1, 4151, 1, 1, 1, 4152, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4153, 4154, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4155, 1, 4156, 1, 1, 1, 4157, + 1, 1, 1, 1, 4158, 1, 1, 4159, + 1, 1, 1, 4160, 4161, 4162, 1, 4163, + 1, 1, 1, 1, 1, 4164, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4165, + 1, 1, 1, 1, 1, 4166, 1, 4167, + 1, 4168, 1, 4169, 1, 4170, 1, 4171, + 1, 1, 1, 1, 1, 1, 1, 1, + 4172, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4173, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4174, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4175, 1, 4176, 1, 4177, 1, 4178, + 1, 4179, 1, 4180, 1, 1, 1, 1, + 1, 4181, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4182, 1, 1, 1, 1, + 1, 4183, 1, 4184, 1, 4185, 1, 4186, + 1, 4187, 1, 4188, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4189, 1, 1, 1, 4190, 1, 1, 1, + 1, 1, 4191, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4192, 1, 1, 1, 4193, 1, 1, 1, + 1, 1, 4194, 1, 4195, 1, 4196, 1, + 4197, 1, 4198, 1, 4199, 1, 4200, 1, + 4201, 1, 4202, 1, 4203, 1, 4204, 1, + 1, 1, 1, 1, 4205, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4206, 1, + 1, 1, 1, 1, 4207, 1, 4208, 1, + 4209, 1, 4210, 1, 4211, 1, 4212, 1, + 1, 1, 1, 1, 1, 1, 1, 4213, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4214, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4215, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4216, 1, 4217, 1, 4218, 1, 4219, 1, + 4220, 1, 4221, 1, 4222, 1, 4223, 1, + 4224, 1, 4225, 1, 4226, 1, 4227, 1, + 4228, 1, 4229, 1, 4230, 1, 4231, 1, + 4232, 1, 4233, 1, 4234, 1, 4235, 1, + 1, 1, 1, 1, 4236, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4237, 1, + 1, 1, 1, 1, 4238, 1, 4239, 1, + 4240, 1, 4241, 1, 4242, 1, 4243, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4244, 1, 1, 1, 4245, + 1, 1, 1, 1, 1, 4246, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4247, 1, 1, 1, 4248, + 1, 1, 1, 1, 1, 4249, 1, 4250, + 1, 4251, 1, 4252, 1, 4253, 1, 4254, + 1, 4255, 1, 4256, 1, 4257, 1, 4258, + 1, 4259, 1, 4260, 1, 4261, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4262, 1, + 4263, 1, 4264, 1, 4265, 1, 4266, 1, + 4267, 1, 4268, 1, 4269, 1, 4270, 1, + 1, 1, 4271, 1, 1, 1, 1, 1, + 4272, 1, 4273, 1, 4274, 1, 4275, 1, + 4276, 1, 4277, 1, 4278, 1, 4279, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4280, 1, 4281, 1, 4282, 1, 4283, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4284, 1, 1, + 1, 1, 1, 4285, 1, 4286, 1, 4287, + 1, 4288, 1, 4289, 1, 4290, 1, 4291, + 4292, 1, 4293, 1, 4294, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4295, 1, + 4296, 1, 4297, 1, 4298, 1, 4299, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4300, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4301, 1, 4302, 1, 4303, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4304, 1, 4305, 1, 4306, 1, + 4307, 4308, 4309, 4310, 1, 4311, 4312, 1, + 1, 4313, 1, 1, 4314, 1, 1, 4315, + 4316, 4317, 4318, 1, 4319, 1, 4320, 1, + 4321, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4322, 1, 4323, + 1, 4324, 1, 4325, 1, 4326, 1, 4327, + 1, 4328, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4329, + 4330, 4331, 4332, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4333, 1, 4334, 1, 4335, 1, 4336, + 1, 4337, 1, 4338, 1, 4339, 1, 4340, + 1, 4341, 1, 4342, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4343, + 1, 4344, 1, 4345, 1, 4346, 1, 4347, + 1, 4348, 1, 4349, 1, 4350, 1, 4351, + 1, 4352, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4353, 1, 4354, 1, 4355, + 1, 4356, 1, 4357, 1, 4358, 1, 1, + 1, 4359, 1, 1, 1, 4360, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4361, 1, 4362, 1, 4363, 1, 4364, + 1, 4365, 1, 4366, 1, 4367, 1, 4368, + 1, 4369, 1, 4370, 1, 4371, 1, 4372, + 1, 4373, 1, 4374, 1, 4375, 1, 4376, + 1, 4377, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4378, 1, 4379, 1, 4380, 1, 4381, + 1, 4382, 1, 4383, 1, 4384, 1, 1, + 1, 1, 1, 1, 1, 1, 4385, 4386, + 1, 4387, 1, 4388, 1, 4389, 1, 4390, + 1, 4391, 1, 4392, 1, 4393, 1, 4394, + 1, 4396, 4395, 4397, 4395, 4398, 4395, 4399, + 4395, 4400, 4395, 4401, 1, 4402, 1, 4403, + 1, 4404, 1, 1, 1, 4405, 1, 4406, + 1, 4407, 1, 4408, 1, 4409, 1, 4410, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4411, 1, 4412, 1, 4413, 1, 4414, + 1, 4415, 1, 4416, 1, 4417, 1, 4418, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4419, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4420, + 1, 4421, 4422, 1, 1, 1, 1, 1, + 1, 4423, 1, 1, 1, 1, 1, 4424, + 1, 4425, 1, 4426, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4427, 1, 1, + 1, 1, 1, 1, 4428, 1, 4429, 1, + 4430, 1, 4431, 1, 4432, 1, 1, 4433, + 1, 4434, 1, 4435, 1, 4436, 1, 4437, + 1, 4438, 1, 1, 1, 1, 1, 4439, + 1, 4440, 1, 4441, 1, 4442, 1, 4443, + 1, 4444, 1, 4445, 1, 4446, 1, 4447, + 1, 4448, 1, 4449, 4450, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4451, 1, 4452, 4453, 1, 4454, + 1, 4455, 1, 4456, 1, 4457, 1, 4458, + 1, 4459, 1, 4460, 1, 4461, 1, 4462, + 1, 4463, 1, 4464, 1, 4465, 1, 4466, + 1, 4467, 1, 4468, 1, 4469, 1, 4470, + 1, 4471, 1, 4472, 1, 4473, 1, 4474, + 1, 4475, 1, 4476, 1, 4477, 1, 4478, + 1, 4479, 1, 4480, 1, 4481, 1, 4482, + 1, 4483, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4484, 1, 4485, 1, 4486, + 1, 4487, 1, 4488, 4489, 4490, 1, 4491, + 1, 4492, 1, 4493, 1, 4494, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4495, + 1, 4496, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4497, + 1, 4498, 1, 4499, 1, 1, 4500, 1, + 4501, 1, 4502, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4503, 1, 4504, 1, 4505, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4506, 1, 1, 1, 1, 1, + 4507, 1, 4508, 1, 4509, 1, 4510, 1, + 4511, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4512, 1, 4513, 1, 4514, + 1, 4515, 1, 4516, 1, 4517, 1, 4518, + 1, 4519, 1, 4520, 1, 4521, 1, 4522, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4523, 1, 4524, 1, 4525, 1, 4526, 1, + 4527, 1, 4528, 1, 4529, 1, 4530, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4531, 1, 1, 1, 1, 1, + 1, 4532, 1, 4533, 1, 4534, 1, 4535, + 1, 4536, 1, 4538, 4537, 4539, 4537, 4540, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4541, 1, 4542, + 1, 4543, 1, 4544, 1, 4545, 1, 4546, + 1, 4547, 1, 4548, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4549, 1, 4550, + 1, 4551, 1, 4552, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4553, 1, 4554, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4555, 1, 4556, + 1, 4557, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4558, 1, 4559, 1, 4560, + 1, 4561, 1, 4562, 1, 4563, 1, 4564, + 4565, 1, 1, 1, 1, 1, 1, 4566, + 1, 1, 1, 4567, 1, 4568, 1, 1, + 1, 4569, 4570, 1, 4571, 1, 4572, 1, + 4573, 1, 4574, 1, 1, 1, 1, 1, + 4575, 1, 4576, 1, 4577, 1, 4578, 1, + 1, 4579, 1, 4580, 1, 4581, 1, 4582, + 1, 4583, 1, 4584, 1, 4585, 1, 4586, + 1, 4587, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4588, 1, + 4589, 1, 4590, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4591, 4592, 4593, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4594, 1, + 1, 1, 4595, 1, 4596, 1, 4597, 1, + 4598, 1, 4599, 1, 4600, 1, 4601, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4602, 1, 4603, 1, 4604, 1, + 4605, 1, 4606, 1, 4607, 1, 4608, 1, + 4609, 1, 4610, 1, 4611, 1, 4612, 1, + 4613, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4614, 1, 1, 1, 1, + 1, 4615, 1, 1, 1, 4616, 1, 4617, + 1, 4618, 1, 4619, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4620, 1, 4621, + 1, 4622, 1, 4623, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4624, 4625, 1, 4626, + 1, 4627, 1, 1, 4628, 1, 4629, 1, + 4630, 1, 4631, 1, 4632, 1, 4633, 1, + 4634, 1, 4635, 1, 4636, 1, 4637, 1, + 4638, 1, 4639, 1, 4640, 1, 4641, 1, + 4642, 1, 4643, 1, 4644, 1, 4645, 1, + 4646, 1, 4647, 1, 4648, 1, 4649, 1, + 4650, 1, 4651, 1, 4652, 1, 4653, 1, + 1, 1, 1, 1, 4654, 1, 4655, 1, + 4656, 1, 4657, 1, 4658, 1, 4659, 1, + 4660, 1, 4661, 1, 4662, 1, 4663, 1, + 4664, 1, 4665, 1, 4666, 1, 4667, 1, + 4668, 1, 4669, 1, 4670, 1, 1, 1, + 1, 1, 4671, 1, 4672, 1, 4673, 1, + 4674, 1, 4675, 1, 4676, 1, 4677, 1, + 4678, 1, 4679, 1, 4680, 1, 4681, 1, + 4682, 1, 4683, 1, 4684, 1, 4685, 1, + 4686, 1, 1, 1, 1, 1, 1, 4687, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4688, 4689, 4690, 4691, 4692, 4693, 1, 4694, + 4695, 4696, 1, 4697, 1, 1, 4698, 1, + 1, 4699, 4700, 4701, 4702, 1, 4703, 1, + 1, 4704, 1, 4705, 1, 4706, 1, 4707, + 1, 4708, 1, 4709, 1, 4710, 1, 4711, + 1, 1, 1, 1, 4712, 1, 1, 1, + 1, 1, 4713, 4714, 1, 4715, 1, 4716, + 1, 4717, 1, 4718, 1, 4719, 1, 4720, + 1, 4721, 1, 4722, 1, 4723, 1, 4724, + 1, 4725, 1, 4726, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4727, 1, + 4728, 1, 4729, 4730, 1, 4731, 1, 4732, + 1, 4733, 1, 4734, 1, 4735, 1, 4736, + 1, 4737, 1, 4738, 1, 4739, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4740, 1, 4741, + 1, 4742, 1, 4743, 1, 4744, 1, 4745, + 1, 4746, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4747, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4748, 1, 4749, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4750, 1, 4751, 1, 4752, 1, + 4753, 1, 4754, 1, 4755, 1, 4756, 1, + 4757, 1, 4758, 1, 4759, 1, 4760, 1, + 4761, 1, 4762, 1, 1, 1, 1, 4763, + 4764, 1, 4765, 1, 4766, 1, 4767, 1, + 4768, 1, 4769, 1, 4770, 1, 4771, 1, + 4772, 1, 4773, 1, 1, 1, 1, 1, + 1, 1, 1, 4774, 1, 4775, 1, 4776, + 1, 4777, 1, 4778, 1, 4779, 1, 4780, + 1, 4781, 1, 4782, 1, 1, 1, 1, + 1, 4783, 1, 4784, 1, 4785, 1, 4786, + 1, 1, 1, 4787, 1, 4788, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4789, 1, 1, 4790, 1, 4791, 1, + 4792, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4793, 1, 1, 1, + 4794, 1, 4795, 1, 4796, 1, 4797, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4798, 1, + 4799, 1, 4800, 1, 4801, 1, 4802, 1, + 4803, 1, 4804, 1, 4805, 1, 4806, 1, + 4807, 1, 4808, 1, 4809, 1, 4810, 1, + 4811, 1, 4812, 1, 4813, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4814, 1, 1, 1, 1, 1, + 4815, 1, 4816, 1, 4817, 1, 4819, 4818, + 4820, 4818, 4821, 4818, 4822, 4818, 4823, 4818, + 4824, 4818, 4825, 4818, 4826, 1, 4827, 1, + 4828, 1, 4829, 1, 4830, 1, 4831, 1, + 4832, 1, 4833, 1, 1, 4834, 1, 4835, + 1, 4836, 1, 4837, 1, 4838, 1, 4839, + 1, 4840, 1, 4841, 1, 1, 1, 4842, + 1, 1, 1, 4843, 4844, 1, 4845, 1, + 4846, 1, 4847, 1, 4848, 1, 4849, 1, + 4850, 1, 4851, 1, 4852, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 4853, 1, + 1, 1, 1, 1, 1, 1, 4854, 1, + 1, 4855, 1, 1, 4856, 1, 4857, 1, + 4858, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4859, 1, 4860, 1, 4861, 1, 4862, + 1, 4863, 1, 4864, 1, 4865, 1, 4866, + 1, 4867, 1, 4868, 1, 4869, 1, 4870, + 1, 4871, 1, 4872, 1, 4873, 1, 4874, + 1, 4875, 1, 4876, 1, 4877, 1, 4878, + 1, 4879, 1, 4880, 1, 4881, 1, 4882, + 1, 4883, 1, 4884, 1, 4885, 1, 4886, + 1, 4887, 1, 4888, 1, 4889, 1, 4890, + 1, 4891, 1, 1, 4892, 1, 1, 1, + 4893, 1, 4894, 1, 4895, 1, 4896, 1, + 4897, 1, 4898, 1, 4899, 1, 4900, 1, + 4901, 1, 4902, 1, 4903, 1, 4904, 1, + 4905, 1, 4906, 1, 4907, 1, 4908, 1, + 4909, 1, 4910, 1, 4911, 1, 4912, 1, + 4913, 1, 4914, 1, 4915, 1, 1, 1, + 1, 1, 4916, 1, 4917, 1, 4918, 1, + 4919, 1, 4920, 1, 4921, 1, 4922, 1, + 4923, 1, 4924, 1, 4925, 1, 4926, 4927, + 1, 4928, 1, 4929, 1, 4930, 1, 4931, + 1, 4932, 1, 4933, 1, 4934, 1, 1, + 4935, 1, 4936, 1, 4937, 1, 4938, 1, + 4939, 1, 4940, 1, 4941, 1, 4942, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4943, 1, 1, 1, 1, 4944, + 1, 4945, 1, 1, 1, 1, 1, 1, + 4946, 1, 4947, 1, 4948, 1, 4949, 1, + 4950, 1, 4951, 1, 4952, 1, 4953, 1, + 4954, 1, 4955, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4956, 1, 4957, 1, 4958, 1, 4959, 1, + 4960, 1, 4961, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4962, 1, 4963, + 1, 4964, 1, 1, 1, 1, 1, 1, + 4965, 1, 4966, 1, 4967, 1, 4968, 1, + 4969, 1, 4970, 1, 4971, 1, 4972, 1, + 4973, 1, 4974, 1, 4975, 1, 4976, 1, + 4977, 1, 4978, 1, 1, 1, 1, 1, + 4979, 1, 4980, 1, 4981, 1, 4982, 1, + 4983, 1, 4984, 1, 4985, 1, 4986, 1, + 4987, 1, 4988, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4989, + 1, 4990, 4991, 4992, 4993, 4994, 1, 1, + 1, 1, 4995, 4996, 4997, 4998, 4999, 5000, + 5001, 5002, 5003, 5004, 1, 1, 5005, 1, + 5006, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5007, 1, 5008, 1, 5009, + 1, 5010, 1, 5011, 1, 5012, 1, 5013, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5014, + 1, 5015, 1, 5016, 1, 5017, 1, 5018, + 1, 5019, 1, 5020, 1, 5021, 1, 5022, + 1, 1, 1, 1, 1, 1, 1, 5023, + 1, 1, 1, 1, 1, 5024, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5025, + 1, 5026, 1, 5027, 1, 5028, 1, 5029, + 1, 5030, 1, 5031, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5032, 1, 5033, 1, 5034, + 1, 5035, 1, 5036, 1, 5037, 1, 5038, + 1, 5039, 1, 5040, 1, 5041, 1, 5042, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5043, 1, 5044, + 1, 5045, 1, 5046, 1, 5047, 1, 5048, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5049, 5050, + 1, 5051, 1, 5052, 1, 5053, 1, 5054, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5055, 1, 5056, 1, 5057, 1, 5058, 1, + 5059, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5060, 1, + 1, 5061, 1, 1, 1, 1, 1, 1, + 5062, 1, 5063, 1, 5064, 1, 5065, 1, + 5066, 1, 5067, 1, 5068, 1, 5069, 1, + 5070, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5071, 1, 5072, 1, 5073, 1, 5074, + 1, 5075, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5076, 1, 1, 5077, 1, 5078, 1, 5079, + 1, 5080, 1, 5081, 1, 5082, 1, 5083, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5084, + 1, 1, 5085, 1, 5086, 1, 5087, 1, + 5088, 1, 5089, 1, 5090, 1, 5091, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5092, 1, 5093, 5094, 1, 5095, 1, 5096, + 1, 5097, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5098, 1, 5099, + 1, 5100, 1, 5101, 1, 5102, 1, 1, + 1, 1, 1, 1, 1, 1, 5103, 1, + 5104, 1, 5105, 1, 5106, 1, 5107, 1, + 5108, 1, 5109, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5110, 1, 1, + 1, 1, 1, 1, 5111, 1, 5112, 1, + 5113, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5114, 1, 5115, 1, 5116, 1, 5117, 1, + 5118, 1, 5119, 1, 5120, 1, 5121, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5122, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5123, 1, 5124, 1, 5125, 1, 5126, + 1, 5127, 1, 5128, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5129, 1, 5130, 5131, 1, + 5132, 1, 1, 1, 1, 1, 5133, 1, + 5134, 1, 5135, 1, 5136, 1, 5137, 1, + 5138, 1, 5139, 1, 5140, 1, 5141, 1, + 1, 5142, 1, 5143, 1, 5144, 1, 5145, + 1, 5146, 1, 5147, 1, 5148, 1, 1, + 1, 1, 5149, 1, 5150, 1, 5151, 1, + 5152, 1, 5153, 1, 5154, 1, 5155, 1, + 5156, 1, 5157, 1, 1, 1, 5158, 1, + 1, 1, 5159, 1, 5160, 1, 5161, 1, + 5162, 1, 5163, 1, 5164, 1, 5165, 1, + 5166, 1, 5167, 1, 1, 1, 1, 1, + 1, 1, 1, 5168, 1, 5169, 1, 5170, + 1, 5171, 1, 5172, 1, 5173, 1, 5174, + 1, 5175, 1, 5176, 1, 5177, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5178, 1, 5179, 1, 5180, 1, + 5181, 1, 5182, 1, 5183, 1, 5184, 1, + 5185, 5186, 1, 1, 1, 1, 5187, 1, + 5188, 1, 5189, 1, 5190, 1, 5191, 1, + 5192, 1, 5193, 1, 5194, 1, 5195, 1, + 1, 1, 1, 1, 1, 5196, 1, 5197, + 1, 5198, 1, 1, 1, 1, 5199, 1, + 5200, 1, 5201, 1, 5202, 1, 5203, 1, + 1, 1, 1, 1, 5204, 1, 1, 1, + 1, 1, 1, 5205, 1, 5206, 1, 5207, + 1, 5208, 1, 5209, 1, 5210, 1, 5211, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5212, 1, 5213, 1, 5214, 1, 5215, + 1, 5216, 1, 5217, 1, 5218, 1, 5219, + 1, 5220, 1, 5221, 1, 5222, 1, 5223, + 1, 5224, 1, 5225, 1, 5226, 1, 5227, + 1, 5228, 1, 5229, 1, 5230, 1, 5231, + 1, 5232, 5233, 1, 1, 5234, 5235, 1, + 5236, 1, 5237, 5238, 5239, 1, 5240, 5241, + 1, 5242, 1, 5243, 1, 5244, 1, 5245, + 1, 5246, 1, 5247, 1, 5248, 1, 5249, + 1, 5250, 1, 5251, 1, 5252, 1, 5253, + 1, 5254, 1, 5255, 1, 5256, 1, 5257, + 1, 5258, 1, 5259, 1, 5260, 1, 5261, + 1, 1, 5262, 1, 1, 1, 1, 1, + 5263, 1, 5264, 1, 5265, 1, 5266, 1, + 5267, 1, 5268, 1, 1, 5269, 1, 5270, + 1, 5271, 1, 5272, 1, 5273, 1, 5274, + 1, 5275, 1, 5276, 1, 5277, 1, 5278, + 1, 5279, 1, 5280, 1, 5281, 1, 5282, + 1, 5283, 1, 5284, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5285, 1, + 1, 1, 1, 1, 1, 1, 5286, 1, + 5287, 1, 5288, 1, 5289, 1, 5290, 1, + 5291, 1, 5292, 1, 5293, 1, 5294, 1, + 5295, 1, 5296, 1, 5297, 1, 5298, 1, + 5299, 1, 5300, 1, 5301, 1, 5302, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5303, 1, 5304, 1, 5305, 1, 5306, 1, + 5307, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5308, 1, 5309, 1, 5310, + 1, 5311, 1, 5312, 1, 5313, 1, 5314, + 1, 5315, 1, 5316, 1, 5317, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5318, 1, 5319, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5320, 1, 5321, + 5322, 5323, 5324, 5325, 1, 5326, 1, 5327, + 5328, 5329, 5330, 5331, 1, 5332, 1, 5333, + 1, 5334, 1, 5335, 1, 5336, 1, 5337, + 1, 5338, 1, 5339, 1, 5340, 1, 5341, + 5342, 1, 1, 5343, 1, 5344, 1, 5345, + 1, 5346, 1, 5347, 1, 5348, 1, 5349, + 1, 5350, 1, 5351, 1, 5352, 1, 5353, + 1, 5354, 1, 5355, 1, 5356, 1, 5357, + 1, 5358, 1, 5359, 1, 5360, 1, 5361, + 1, 5362, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5363, 5364, 5365, + 5366, 5367, 5368, 5369, 1, 5370, 5371, 1, + 5372, 1, 5373, 5374, 1, 1, 5375, 5376, + 5377, 1, 5378, 1, 5379, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5380, 1, 5381, + 1, 5382, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5383, 1, 1, 5384, 1, + 5385, 1, 5386, 1, 5387, 1, 5388, 1, + 5389, 1, 5390, 1, 5391, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5392, 1, 5393, + 1, 5394, 1, 5395, 1, 5396, 1, 5397, + 1, 5398, 1, 5399, 1, 5400, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5401, 1, 5402, + 1, 5403, 1, 5404, 1, 5405, 1, 5406, + 1, 5407, 1, 5408, 1, 5409, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5410, 1, + 1, 1, 1, 5411, 1, 5412, 1, 5413, + 1, 5414, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5415, + 1, 5416, 1, 5417, 1, 5418, 1, 5419, + 1, 5420, 1, 5421, 1, 5422, 1, 5423, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5424, + 5425, 1, 1, 1, 1, 1, 1, 1, + 5426, 1, 5427, 1, 5428, 1, 5429, 1, + 5430, 1, 5431, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5432, 1, + 5433, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5434, 1, 5435, 1, 5436, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5437, + 1, 5438, 1, 5439, 1, 5440, 1, 5441, + 1, 5442, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5443, 1, 5444, + 1, 5445, 1, 5446, 1, 5447, 1, 5448, + 1, 5449, 1, 5450, 1, 5451, 1, 5452, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5453, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5454, 1, 1, + 1, 1, 1, 1, 1, 1, 5455, 1, + 5456, 1, 5457, 1, 5458, 1, 5459, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5460, 1, 1, 1, 5461, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5462, 1, 5463, 1, + 5464, 1, 5465, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5466, + 1, 5467, 1, 5468, 1, 5469, 1, 5470, + 1, 5471, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5472, + 1, 5473, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5474, + 1, 5475, 1, 5476, 1, 5477, 1, 5478, + 1, 5479, 1, 5480, 1, 5481, 1, 5482, + 1, 5483, 1, 5484, 1, 5485, 1, 5486, + 1, 1, 1, 1, 1, 5487, 1, 5488, + 1, 5489, 1, 5490, 1, 5491, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5492, + 1, 1, 1, 1, 1, 1, 5493, 1, + 5494, 1, 5495, 1, 5497, 5496, 5496, 5496, + 5496, 5496, 5498, 5496, 5499, 5496, 5500, 5496, + 5501, 5496, 5502, 5496, 5503, 5496, 5504, 5496, + 5505, 5496, 5506, 5496, 5507, 5496, 5508, 5496, + 5509, 5496, 5510, 5496, 5511, 5496, 5512, 5496, + 5513, 5496, 5514, 5496, 5496, 5515, 5516, 5496, + 5496, 5496, 5496, 5496, 5496, 5517, 5496, 5496, + 5496, 5496, 5496, 5496, 5518, 5496, 5519, 5496, + 5520, 5496, 5521, 5496, 5522, 5496, 5523, 5496, + 5524, 5496, 5525, 5496, 5526, 5496, 5527, 5496, + 5528, 5496, 5529, 5496, 5530, 5496, 5531, 5496, + 5532, 5496, 5496, 5496, 5496, 5533, 5496, 5534, + 5496, 5535, 5496, 5536, 5496, 5537, 5496, 5538, + 5496, 5539, 5496, 5540, 5496, 5541, 5496, 5542, + 5496, 5543, 5496, 5544, 5496, 5545, 5496, 5546, + 5496, 5547, 5496, 5548, 5496, 5549, 5496, 5550, + 1, 1, 1, 1, 1, 1, 1, 1, + 5551, 1, 5552, 1, 5553, 1, 5554, 1, + 5555, 1, 5556, 1, 5557, 1, 5558, 1, + 5559, 1, 5560, 1, 5561, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5562, 5563, 5564, 1, + 5565, 5566, 1, 1, 1, 1, 5567, 1, + 1, 1, 5568, 1, 1, 1, 5569, 1, + 1, 1, 1, 1, 5570, 1, 5571, 1, + 5572, 1, 5573, 1, 5574, 1, 1, 5575, + 5576, 1, 1, 1, 1, 5577, 1, 5578, + 1, 5579, 1, 5580, 1, 5581, 1, 5582, + 1, 5583, 1, 5584, 1, 5585, 1, 5586, + 1, 5587, 1, 5588, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5589, 1, 5590, 1, 5591, 1, 5592, + 1, 5593, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5594, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5595, 1, 5596, + 1, 5597, 1, 5598, 1, 5599, 1, 5600, + 1, 5601, 1, 5602, 1, 5603, 1, 5604, + 1, 5605, 1, 5606, 1, 5607, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5608, 1, 1, 1, 1, 1, 5609, 1, + 5610, 1, 5611, 1, 5612, 1, 5613, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5614, 1, 5615, 1, 5616, 1, 5617, 1, + 5618, 1, 5619, 1, 5620, 1, 5621, 1, + 5622, 1, 5623, 1, 5624, 1, 5625, 1, + 5626, 1, 5627, 1, 5628, 1, 5629, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5630, 1, 5631, 1, 5632, 1, 5633, 1, + 5634, 1, 5635, 1, 5636, 1, 5637, 1, + 5638, 1, 5639, 1, 5640, 1, 5641, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5642, 1, 5643, 5644, 1, 5645, + 1, 5646, 1, 5647, 1, 5648, 1, 5649, + 1, 5650, 1, 5651, 1, 5652, 1, 5653, + 1, 5654, 1, 1, 1, 1, 1, 5655, + 1, 5656, 1, 5657, 1, 5658, 1, 5659, + 1, 5660, 1, 5661, 1, 5662, 1, 5663, + 1, 5664, 1, 5665, 1, 5666, 1, 5667, + 1, 5668, 1, 5669, 1, 5670, 1, 5671, + 1, 5672, 1, 5673, 1, 5674, 1, 5675, + 1, 5676, 1, 5677, 1, 5678, 1, 5679, + 1, 5680, 1, 5681, 1, 1, 1, 1, + 1, 1, 1, 1, 5682, 1, 1, 1, + 1, 1, 1, 1, 5683, 1, 5684, 1, + 5685, 1, 5686, 1, 5687, 1, 5688, 1, + 5689, 1, 5690, 1, 5691, 1, 5692, 1, + 5693, 1, 5694, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5695, 1, 5696, 1, 5697, 1, 5698, 1, + 5699, 1, 5700, 1, 5701, 1, 5702, 1, + 5703, 1, 5704, 1, 5705, 1, 5706, 5707, + 5708, 1, 5709, 5710, 1, 1, 5711, 5712, + 5713, 5714, 5715, 1, 5716, 5717, 5718, 1, + 5719, 1, 5720, 1, 5721, 1, 5722, 1, + 5723, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5724, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5725, 1, + 5726, 1, 5727, 1, 5728, 1, 5729, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 5730, 1, 5731, 1, 5732, + 1, 5733, 1, 5734, 1, 5735, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5736, 1, 5737, 1, 5738, 1, 5739, + 1, 5740, 1, 5741, 1, 5742, 1, 5743, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5744, 1, 1, + 1, 1, 5745, 5746, 1, 5747, 1, 1, + 1, 1, 5748, 1, 5749, 1, 5750, 1, + 5751, 1, 5752, 1, 5753, 1, 5754, 1, + 5755, 1, 5756, 1, 5757, 1, 5758, 1, + 5759, 1, 5760, 1, 5761, 1, 5762, 1, + 5763, 1, 5764, 1, 5765, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5766, 5767, 1, 5768, 1, 1, + 1, 5769, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5770, 1, + 5771, 1, 5772, 1, 5773, 1, 1, 1, + 1, 1, 1, 5774, 1, 1, 1, 5775, + 1, 5776, 1, 5777, 1, 5778, 1, 5779, + 1, 5780, 1, 5781, 1, 5782, 1, 5783, + 1, 5784, 1, 5785, 1, 5786, 1, 5787, + 1, 5788, 1, 5789, 1, 5790, 1, 5791, + 1, 5792, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5793, 1, 1, 5794, 1, 1, 1, + 1, 1, 1, 1, 1, 5795, 1, 1, + 1, 1, 5796, 1, 5797, 1, 5798, 1, + 5799, 1, 5800, 1, 5801, 1, 5802, 1, + 5803, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5804, 1, 5805, 1, 5806, 1, 5807, + 1, 5808, 1, 5809, 1, 5810, 1, 5811, + 1, 5812, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5813, 1, 5814, 1, 1, 1, 1, + 1, 1, 5815, 1, 1, 1, 5816, 1, + 5817, 1, 5818, 1, 5819, 1, 5820, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5821, 1, 5822, 1, 5823, 1, 5824, + 1, 5825, 1, 5826, 1, 5827, 1, 5828, + 1, 5829, 1, 5830, 1, 5831, 1, 5832, + 1, 5833, 1, 5834, 1, 5835, 1, 5836, + 1, 5837, 1, 5838, 1, 5839, 1, 1, + 1, 5840, 1, 1, 1, 1, 1, 1, + 1, 1, 5841, 1, 1, 1, 5842, 1, + 5843, 1, 5844, 1, 5845, 1, 5846, 1, + 5847, 1, 5848, 1, 5849, 1, 5850, 1, + 5851, 1, 5852, 1, 5853, 1, 5854, 1, + 5855, 1, 5856, 1, 5857, 1, 5858, 1, + 5859, 1, 5860, 1, 1, 1, 1, 1, + 5861, 1, 5862, 1, 5863, 1, 5864, 1, + 5865, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5866, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5867, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5868, 1, 1, 5869, 1, 5870, 1, 5871, + 1, 5872, 1, 5873, 1, 5874, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 5875, 1, 5876, 1, 5877, 1, 5878, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5879, 1, 5880, 1, + 5881, 1, 5882, 1, 5883, 1, 5884, 1, + 5885, 1, 5886, 1, 5887, 1, 5888, 1, + 5889, 1, 5890, 1, 1, 5891, 1, 1, + 1, 1, 1, 1, 5892, 1, 5893, 1, + 1, 1, 5894, 1, 5895, 1, 5896, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 5897, 1, + 5898, 1, 5899, 1, 5900, 1, 5901, 1, + 5902, 1, 5903, 1, 5904, 1, 5905, 1, + 5906, 1, 5907, 1, 5908, 1, 5909, 1, + 5910, 1, 5911, 1, 5912, 1, 5913, 1, + 5914, 1, 5915, 1, 5916, 1, 5917, 1, + 5918, 1, 5919, 1, 5920, 1, 5921, 1, + 5922, 1, 5923, 1, 5924, 1, 1, 5925, + 5926, 5927, 1, 5928, 1, 1, 1, 1, + 5929, 1, 1, 1, 5930, 1, 5931, 1, + 5932, 1, 5933, 1, 5934, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5935, + 1, 5936, 1, 5937, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5938, + 1, 5939, 1, 5940, 1, 5941, 1, 5942, + 1, 5943, 1, 5944, 1, 5945, 1, 5946, + 1, 5947, 1, 5948, 1, 5949, 1, 5950, + 1, 5951, 1, 5952, 1, 5953, 1, 5954, + 1, 5955, 1, 5956, 1, 5957, 1, 5958, + 1, 5959, 1, 5960, 1, 5961, 1, 5962, + 1, 5963, 5964, 1, 1, 5965, 1, 1, + 5966, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5967, 5968, 5969, 5970, 5971, 5972, 5973, + 5974, 1, 5975, 1, 5976, 5977, 5978, 5979, + 5980, 1, 5981, 5982, 5983, 5984, 5985, 1, + 5986, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5987, 1, 5988, 1, 5989, 1, 5990, + 1, 5991, 1, 5992, 1, 5993, 1, 5994, + 1, 5995, 1, 5996, 1, 5997, 1, 5998, + 1, 5999, 1, 6000, 1, 6001, 1, 6002, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6003, 1, 6004, 1, 6005, + 1, 6006, 1, 6007, 1, 6008, 1, 6009, + 1, 6010, 1, 1, 1, 1, 1, 6011, + 6012, 1, 6013, 6014, 6015, 1, 6016, 1, + 6017, 1, 6018, 1, 6019, 1, 6020, 1, + 6021, 1, 6022, 1, 6023, 1, 6024, 1, + 6025, 1, 6026, 1, 6027, 1, 6028, 1, + 6029, 1, 6030, 1, 6031, 1, 6032, 1, + 6033, 1, 6034, 1, 6035, 1, 6036, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6037, + 1, 1, 1, 1, 1, 1, 1, 6038, + 1, 6039, 1, 6040, 1, 6041, 1, 6042, + 1, 6043, 1, 6044, 1, 6045, 1, 6046, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6047, 1, + 1, 1, 6048, 1, 6049, 1, 1, 1, + 6050, 1, 1, 1, 6051, 1, 1, 6052, + 6053, 1, 6054, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6055, 1, 6056, + 1, 6057, 1, 6058, 1, 6059, 1, 6060, + 1, 6061, 1, 6062, 1, 6063, 1, 6064, + 1, 6065, 1, 6066, 1, 6067, 1, 6068, + 1, 6069, 1, 6070, 1, 6071, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6072, 1, 1, 1, 6073, + 1, 6074, 1, 6075, 1, 6076, 1, 6077, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6078, + 1, 6079, 1, 6080, 6081, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6082, 1, 6083, 1, + 6084, 1, 6085, 1, 6086, 1, 6087, 1, + 6088, 1, 6089, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6090, 1, 6091, 1, + 6092, 1, 1, 1, 1, 1, 6093, 1, + 6094, 1, 6095, 1, 6096, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6097, 1, 6098, 1, 6099, 1, + 6100, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6101, 1, 6102, 1, 6103, 1, 6104, + 1, 1, 1, 6105, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6106, 1, 1, 1, 6107, + 1, 6108, 1, 6109, 1, 6110, 1, 6111, + 1, 6112, 1, 1, 1, 1, 6113, 1, + 6114, 1, 6115, 1, 6116, 1, 6117, 1, + 6118, 1, 6119, 1, 6120, 1, 6121, 1, + 6122, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6123, 6124, + 6125, 1, 6126, 1, 6127, 1, 6128, 1, + 6129, 1, 6130, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6131, 1, 6132, 1, 6133, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6134, 1, + 6135, 1, 6136, 1, 6137, 1, 6138, 1, + 6139, 1, 6140, 1, 6141, 1, 6142, 1, + 6143, 1, 6144, 1, 6145, 1, 6146, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6147, 6148, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6149, 1, 6150, 1, + 6151, 1, 6152, 1, 1, 1, 1, 1, + 1, 6153, 1, 1, 1, 6154, 1, 1, + 1, 1, 1, 6155, 1, 6156, 1, 6157, + 1, 6158, 1, 6159, 1, 6160, 1, 6161, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6162, 1, 6163, 1, 6164, 1, 6165, 1, + 6166, 1, 6167, 1, 6168, 1, 6169, 1, + 6170, 1, 6171, 1, 6172, 1, 6173, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6174, + 1, 6175, 1, 6176, 1, 6177, 1, 6178, + 1, 6179, 1, 6180, 1, 6181, 1, 6182, + 1, 6183, 1, 6184, 1, 6185, 1, 6186, + 1, 6187, 1, 6188, 1, 6189, 1, 6190, + 1, 6191, 1, 6192, 1, 6193, 1, 6194, + 1, 6195, 1, 1, 1, 1, 1, 1, + 6196, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6197, 1, 6198, 1, 6199, + 1, 6200, 1, 6201, 1, 6202, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6203, 1, 6204, + 1, 6205, 1, 6206, 1, 6207, 1, 6208, + 1, 6209, 1, 6210, 1, 6211, 1, 6212, + 1, 6213, 1, 6214, 1, 6215, 1, 6216, + 1, 6217, 1, 6218, 1, 6219, 1, 6220, + 1, 6221, 1, 6222, 1, 6223, 1, 6224, + 1, 6225, 1, 6226, 1, 6227, 1, 6228, + 1, 6229, 1, 6230, 1, 6231, 1, 6232, + 1, 6233, 1, 6234, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6235, 1, 6236, 1, 6237, 1, 6238, + 1, 6239, 1, 6240, 1, 6241, 1, 6242, + 1, 6243, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6244, 6245, 1, 1, 6246, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6247, 1, 6248, 1, 6249, 1, 6250, + 1, 6251, 1, 6252, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6253, + 1, 6254, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6255, 1, 6256, 1, 6257, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6258, 1, + 6259, 1, 6260, 1, 6261, 1, 1, 6262, + 6263, 1, 6264, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6265, 1, + 6266, 1, 6267, 1, 6268, 1, 6269, 1, + 6270, 1, 6271, 1, 6272, 1, 6273, 1, + 6274, 1, 6275, 1, 6276, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6277, 1, + 6278, 1, 6279, 1, 6280, 1, 6281, 1, + 6282, 1, 6283, 1, 6284, 1, 6285, 1, + 6286, 1, 6287, 1, 6288, 1, 6289, 1, + 6290, 1, 6291, 1, 1, 6292, 1, 1, + 1, 1, 1, 6293, 1, 6294, 1, 6295, + 1, 6296, 1, 6297, 1, 6298, 1, 6299, + 1, 6300, 1, 6301, 1, 6302, 1, 6303, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6304, 1, 6305, 1, 6306, 6307, 1, + 6308, 1, 6309, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6310, 1, 6311, 1, 6312, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6313, 1, 6314, 1, 6315, 1, 6316, 1, + 6317, 1, 6318, 1, 6319, 1, 6320, 1, + 6321, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6322, 1, + 6323, 1, 1, 1, 1, 6324, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6325, 1, 6326, 1, 6327, 1, 6328, + 1, 6329, 1, 6330, 1, 6331, 1, 6332, + 1, 6333, 1, 6334, 1, 6335, 1, 6336, + 1, 6337, 1, 6338, 1, 6339, 1, 6340, + 1, 6341, 1, 6342, 1, 1, 1, 1, + 1, 6343, 1, 6344, 1, 6345, 1, 6346, + 1, 6347, 1, 6348, 1, 6349, 1, 6350, + 1, 6351, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6352, + 1, 6353, 1, 6354, 1, 6355, 1, 6356, + 1, 6357, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6358, 1, 1, + 1, 6359, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6360, + 1, 6361, 1, 6362, 1, 6363, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6364, 1, 6365, 1, 6366, 1, + 6367, 1, 6368, 1, 6369, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6370, 1, 6371, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6372, 1, 6373, 1, 6374, 1, + 6375, 1, 6376, 1, 6377, 6378, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6379, 6380, 6381, 1, 1, 1, 6382, + 1, 1, 6383, 1, 1, 6384, 1, 6385, + 1, 1, 1, 6386, 1, 6387, 1, 6388, + 1, 6389, 1, 6390, 1, 6391, 1, 6392, + 1, 6393, 1, 6394, 1, 6395, 6396, 1, + 1, 1, 1, 6397, 1, 6398, 1, 6399, + 1, 6400, 1, 6401, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6402, 1, 6403, 1, + 6404, 1, 6405, 1, 6406, 1, 6407, 1, + 6408, 1, 6409, 1, 6410, 1, 6411, 1, + 6412, 1, 6413, 1, 6414, 1, 6415, 1, + 6416, 1, 6417, 1, 6418, 1, 6419, 1, + 6420, 1, 6421, 1, 6422, 1, 6423, 1, + 6424, 1, 6425, 1, 6426, 1, 6427, 1, + 6428, 1, 6429, 1, 6430, 1, 6431, 1, + 6432, 1, 6433, 1, 6434, 1, 6435, 1, + 6436, 1, 6437, 1, 6438, 1, 6439, 1, + 6440, 1, 1, 1, 1, 1, 6441, 1, + 6442, 1, 6443, 1, 6444, 1, 6445, 1, + 6446, 1, 6447, 1, 6448, 1, 6449, 1, + 6450, 1, 6451, 1, 1, 1, 1, 6452, + 1, 1, 1, 1, 1, 6453, 1, 6454, + 1, 6455, 1, 6456, 1, 6457, 1, 6458, + 1, 6459, 1, 6460, 1, 6461, 1, 6462, + 1, 6463, 1, 6464, 1, 6465, 6466, 1, + 6467, 1, 6468, 1, 6469, 1, 6470, 1, + 6471, 1, 6472, 1, 6473, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6474, 6475, + 1, 6476, 1, 6477, 1, 6478, 1, 6479, + 1, 6480, 1, 6481, 1, 6482, 1, 6483, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6484, 1, 6485, 1, 6486, 1, 6487, 1, + 6488, 1, 1, 1, 1, 6489, 1, 1, + 1, 1, 6490, 1, 1, 1, 1, 1, + 1, 6491, 1, 6492, 1, 6493, 1, 6494, + 1, 6495, 1, 6496, 1, 6497, 1, 6498, + 1, 6499, 1, 6500, 1, 6501, 1, 6502, + 1, 6503, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6504, 1, 6505, 1, 6506, 1, + 6507, 1, 6508, 1, 6509, 1, 6510, 1, + 6511, 1, 1, 1, 1, 6512, 6513, 1, + 1, 1, 1, 1, 1, 1, 6514, 1, + 1, 6515, 1, 6516, 1, 6517, 1, 6518, + 1, 6519, 1, 6520, 1, 6521, 1, 6522, + 1, 6523, 1, 6524, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6525, 1, 6526, + 1, 6527, 1, 6528, 1, 6529, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6530, 1, 6531, 1, 6532, 1, 6533, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6534, 1, 6535, + 1, 6536, 1, 6537, 1, 6538, 1, 6539, + 1, 6541, 6540, 6540, 6540, 6540, 6540, 6542, + 6540, 6543, 6540, 6544, 6540, 6545, 6540, 6546, + 6540, 6547, 6540, 6548, 6540, 6549, 6540, 6550, + 6540, 6551, 6540, 6552, 6540, 6553, 6540, 6554, + 6540, 6555, 6540, 6556, 6540, 6557, 6540, 6558, + 6540, 6559, 6540, 6560, 6540, 6561, 6540, 6562, + 6540, 6563, 6540, 6564, 6540, 6565, 6540, 6566, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6567, 6540, 6568, 6540, 6569, 6540, 6570, 6540, + 6571, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6540, 6540, 6540, 6540, 6540, 6540, + 6540, 6540, 6572, 6573, 6540, 6574, 6540, 6575, + 6540, 6576, 1, 6577, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6578, 1, 6579, 1, + 6580, 1, 6581, 1, 6582, 1, 6583, 1, + 6584, 1, 6585, 1, 6586, 1, 6587, 1, + 6588, 1, 1, 1, 1, 1, 1, 1, + 1, 6589, 1, 6590, 1, 6591, 1, 6592, + 1, 6593, 1, 6594, 1, 6595, 1, 6596, + 1, 6597, 1, 6598, 1, 6599, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6600, 1, 6601, 6602, 6603, 6604, + 1, 6605, 6606, 1, 1, 6607, 1, 6608, + 6609, 6610, 1, 1, 6611, 1, 6612, 1, + 6613, 1, 6614, 1, 6615, 1, 6616, 1, + 6617, 1, 1, 1, 1, 1, 1, 1, + 1, 6618, 1, 1, 1, 6619, 1, 6620, + 1, 6621, 1, 6622, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6623, 1, 6624, 1, 6625, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6626, 1, 6627, 1, 6628, 1, 6629, 1, + 6630, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6631, 1, 6632, 1, 6633, 1, 6634, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6635, + 1, 1, 1, 1, 1, 1, 1, 6636, + 1, 1, 1, 1, 1, 1, 1, 1, + 6637, 1, 6638, 1, 6639, 1, 6640, 1, + 6641, 1, 6642, 1, 6643, 1, 6644, 1, + 6645, 1, 6646, 1, 6647, 1, 6648, 1, + 6649, 1, 6650, 1, 6651, 1, 6652, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6653, 1, 6654, 1, 6655, 1, 6656, 1, + 6657, 1, 6658, 1, 6659, 1, 6660, 1, + 6661, 1, 6662, 1, 6663, 1, 6664, 1, + 6665, 1, 6666, 1, 6667, 1, 6668, 1, + 6669, 1, 6670, 1, 6671, 1, 6672, 1, + 6673, 1, 6674, 1, 6675, 1, 6676, 1, + 6677, 1, 6678, 1, 6679, 6680, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6681, + 1, 6682, 1, 6683, 1, 6684, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6685, 1, 6686, 6687, 1, + 6688, 1, 6689, 1, 6690, 1, 6691, 1, + 6692, 1, 6693, 1, 6694, 1, 6695, 1, + 6696, 1, 6697, 1, 6698, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6699, 1, 6700, 1, 6701, + 1, 6702, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6703, 1, 6704, 1, 6705, + 6706, 1, 6707, 1, 6708, 1, 6709, 1, + 6710, 1, 6711, 1, 6712, 1, 6713, 1, + 6714, 1, 6715, 1, 6716, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6717, 1, 6718, 1, 6719, 1, 6720, 1, + 6721, 1, 6722, 1, 6723, 1, 6724, 1, + 6725, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6726, 1, 6727, 1, 6728, 1, 6729, + 1, 6730, 1, 6731, 1, 6732, 1, 6733, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6734, 6735, 1, 6736, 1, 6737, 1, 6738, + 1, 6739, 1, 6740, 1, 6741, 1, 6742, + 1, 6743, 1, 6744, 1, 6745, 1, 1, + 1, 1, 6746, 1, 1, 1, 1, 1, + 6747, 1, 1, 1, 6748, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6749, + 6750, 6751, 6752, 6753, 6754, 6755, 6756, 6757, + 6758, 1, 6759, 6760, 1, 6761, 6762, 1, + 6763, 6764, 6765, 6766, 6767, 6768, 1, 6769, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6770, 1, 6771, 1, + 6772, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6773, 1, 6774, 1, 6775, + 1, 1, 1, 1, 1, 1, 6776, 1, + 1, 1, 1, 1, 1, 1, 6777, 1, + 6778, 1, 6779, 1, 6780, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6781, 1, 6782, + 1, 6783, 1, 6784, 1, 6785, 1, 6786, + 1, 6787, 1, 6788, 1, 6789, 1, 6790, + 1, 6791, 1, 6792, 1, 6793, 1, 6794, + 1, 6795, 1, 6796, 1, 6797, 1, 6798, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6799, 1, 6800, 1, 6801, 1, + 6802, 1, 6803, 1, 6804, 1, 6805, 1, + 6806, 1, 6807, 1, 6808, 1, 6809, 1, + 6810, 1, 6811, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6812, 1, 6813, 1, 6814, 1, + 6815, 1, 6816, 1, 6817, 1, 6818, 1, + 6819, 1, 6820, 1, 6821, 6822, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6823, 1, 6824, 1, 1, 1, 6825, 1, + 6826, 1, 6827, 1, 6828, 1, 6829, 1, + 6830, 1, 6831, 1, 6832, 1, 6833, 1, + 6834, 1, 6835, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6836, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6837, 1, 1, 1, 1, 1, 6838, 6839, + 1, 6840, 1, 6841, 1, 6842, 1, 6843, + 1, 6844, 1, 6845, 1, 6846, 1, 6847, + 1, 6848, 1, 6849, 1, 6850, 1, 6851, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6852, 1, 6853, + 1, 6854, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6855, 1, 6856, 1, 6857, 1, 6858, + 1, 6859, 1, 6860, 1, 6861, 1, 6862, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6863, 1, 6864, 1, 6865, 1, 1, + 1, 6866, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6867, 1, 1, 1, 1, + 1, 6868, 1, 1, 1, 6869, 1, 6870, + 1, 6871, 1, 6872, 1, 6873, 1, 6874, + 1, 6875, 1, 6876, 1, 6877, 1, 6878, + 1, 6879, 1, 6880, 1, 6881, 1, 6882, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6883, 1, 6884, 1, 6885, 1, 6886, 1, + 6887, 1, 6888, 1, 6889, 1, 6890, 1, + 6891, 1, 6892, 1, 6893, 1, 6894, 1, + 1, 1, 1, 1, 6895, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6896, 1, 1, 6897, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6898, 1, 6899, 1, + 1, 1, 1, 6900, 1, 6901, 1, 6902, + 1, 6903, 1, 6904, 1, 6905, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6906, + 1, 6907, 1, 6908, 1, 6909, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6910, 1, 6911, 1, 6912, 1, 6913, + 1, 6914, 1, 6915, 1, 6916, 1, 6917, + 1, 6918, 1, 6919, 1, 6920, 1, 1, + 1, 6921, 1, 6922, 1, 6923, 1, 6924, + 1, 6925, 1, 6926, 1, 6927, 1, 6928, + 1, 6929, 1, 6930, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6931, 1, 6932, 1, 6933, + 1, 6934, 1, 6935, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6936, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6937, 6938, 1, 6939, 1, 6940, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6941, 1, 6942, 1, + 6943, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6944, 1, + 6945, 1, 6946, 1, 6947, 1, 6948, 1, + 6949, 1, 6950, 1, 6951, 1, 6952, 1, + 6953, 1, 6954, 1, 6955, 1, 6956, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 6957, 1, 6958, + 1, 6959, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6960, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6961, 1, 6962, 1, 6963, 1, 6964, 1, + 6965, 1, 6966, 1, 6967, 1, 6968, 1, + 6969, 1, 6970, 1, 6971, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6972, 1, 1, 6973, + 1, 6974, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6975, 1, 6976, 1, 6977, 1, + 6978, 1, 6979, 1, 6980, 1, 6981, 1, + 1, 1, 6982, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6983, 1, + 1, 6984, 6985, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6986, 6987, 1, 6988, 1, 6989, 1, 6990, + 1, 6991, 1, 6992, 1, 6993, 1, 6994, + 1, 6995, 1, 6996, 1, 6997, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 6998, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6999, 1, 7000, 1, 7001, + 1, 7002, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7003, 1, 7004, 1, 7005, 1, + 7006, 1, 7007, 1, 7008, 1, 7009, 1, + 7010, 1, 7011, 1, 7012, 1, 7013, 1, + 7014, 1, 7015, 1, 7016, 1, 7017, 1, + 7018, 1, 7019, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7020, 1, 7021, 1, 7022, 1, 7023, 1, + 7024, 1, 7025, 1, 7026, 1, 7027, 1, + 7028, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7029, 1, 7030, 1, 7031, 1, 7032, 1, + 7033, 1, 7034, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7035, 1, 7036, 1, 7037, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7038, + 1, 7039, 1, 7040, 1, 7041, 1, 7042, + 1, 7043, 1, 1, 1, 7044, 1, 7045, + 1, 7046, 1, 7048, 7047, 7049, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7050, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7051, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7052, 7047, 7053, 7047, 7054, 7047, 7055, 7047, + 7056, 7047, 7057, 7058, 7059, 7047, 7060, 7047, + 7061, 7047, 7062, 7047, 7063, 7047, 7064, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7047, 7047, 7047, 7047, 7047, 7047, 7047, + 7047, 7065, 7047, 7066, 7067, 7068, 7047, 7069, + 7047, 7070, 7047, 7071, 7047, 7072, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7073, 1, 1, 7074, 1, + 7075, 1, 7076, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7077, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7078, 7079, 1, 7080, 1, 7081, + 1, 7082, 1, 7083, 1, 7084, 1, 7085, + 1, 7086, 1, 7087, 1, 7088, 1, 7089, + 1, 7090, 1, 7091, 1, 7092, 1, 7093, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7094, + 1, 7095, 1, 7096, 1, 7097, 1, 7098, + 1, 7099, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7100, 1, 7101, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7102, 1, 7103, + 1, 7104, 1, 7105, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7106, 1, 1, 1, 1, + 1, 1, 1, 7107, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7108, 1, + 7109, 1, 7110, 1, 7111, 1, 7112, 1, + 7113, 1, 7114, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7115, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7116, 1, + 7117, 1, 7118, 1, 7119, 1, 7120, 1, + 7121, 1, 7122, 1, 7123, 1, 7124, 1, + 7125, 1, 7126, 1, 7127, 1, 7128, 1, + 7129, 1, 7130, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7131, 1, 7132, 1, + 7133, 1, 1, 1, 1, 7134, 7135, 1, + 1, 1, 7136, 1, 1, 7137, 7138, 1, + 1, 1, 7139, 1, 7140, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7141, 1, 7142, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7143, 1, 7144, 1, 7145, + 1, 7146, 1, 7147, 1, 7148, 1, 7149, + 1, 7150, 1, 7151, 1, 7152, 1, 1, + 7153, 1, 7154, 1, 7155, 1, 7156, 1, + 7157, 1, 7158, 1, 7159, 1, 7160, 1, + 7161, 1, 7162, 1, 7163, 1, 7164, 1, + 7165, 1, 7166, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7167, 1, 7168, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7169, 1, 7170, 1, + 7171, 1, 7172, 1, 7173, 1, 7174, 1, + 7175, 1, 7176, 1, 7177, 1, 7178, 1, + 7179, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7180, 1, + 7181, 1, 7182, 1, 7183, 1, 7184, 1, + 7185, 7186, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7187, 1, + 7188, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7189, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7190, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7191, 1, 7192, 1, 7193, 1, 7194, 1, + 7195, 1, 7196, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7197, 1, 7198, 1, + 7199, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7200, 1, + 7201, 1, 7202, 1, 7203, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7204, 1, + 7205, 1, 7206, 1, 7207, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7208, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7209, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7210, 1, 7211, 1, + 7212, 1, 7213, 1, 7214, 1, 7215, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7216, 1, 7217, 1, 7218, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7219, 1, 7220, 1, 7221, 1, + 7222, 1, 1, 7223, 1, 1, 1, 1, + 1, 7224, 1, 7225, 1, 7226, 1, 7227, + 1, 7228, 1, 7229, 1, 7230, 1, 7231, + 1, 7232, 1, 7233, 1, 7234, 1, 7235, + 1, 7236, 1, 7237, 1, 7238, 1, 1, + 1, 1, 1, 7239, 1, 7240, 1, 7241, + 1, 7242, 1, 7243, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7244, 1, 7245, + 1, 7246, 1, 7247, 1, 7248, 1, 7249, + 1, 7250, 1, 7251, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7252, 1, 7253, + 1, 7254, 1, 7255, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7256, 1, 7257, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7258, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7259, + 1, 7260, 1, 7261, 1, 7262, 1, 7263, + 1, 7264, 1, 7265, 1, 1, 1, 7266, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7267, 1, 1, 7268, 1, 1, 7269, 1, + 7270, 1, 1, 7271, 1, 1, 1, 1, + 1, 7272, 7273, 1, 7274, 1, 7275, 1, + 7276, 1, 7277, 1, 7278, 1, 7279, 1, + 7280, 1, 7281, 1, 7282, 1, 7283, 1, + 7284, 1, 7285, 1, 7286, 1, 7287, 1, + 7288, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7289, + 1, 7290, 1, 7291, 1, 7292, 1, 7293, + 1, 7294, 1, 7295, 1, 7296, 1, 7297, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7298, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7299, 1, 7300, 1, 7301, 1, + 7302, 1, 7303, 1, 7304, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7305, 1, 7306, 1, 7307, + 1, 7308, 1, 7309, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7310, 1, + 7311, 1, 7312, 1, 7313, 1, 7314, 1, + 7315, 1, 7316, 1, 7317, 1, 7318, 1, + 7319, 1, 7320, 1, 7321, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7322, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7323, 1, 7324, 1, 7325, 1, 7326, + 1, 7327, 1, 7328, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7329, 1, 7330, + 1, 7331, 1, 7332, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7333, + 1, 7334, 1, 7335, 1, 7336, 1, 7337, + 1, 7338, 1, 7339, 1, 7340, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7341, 1, 7342, 7343, 7344, + 7345, 7346, 7347, 7348, 1, 1, 7349, 7350, + 1, 7351, 7352, 1, 7353, 7354, 7355, 7356, + 7357, 1, 7358, 1, 7359, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7360, 1, 7361, 1, + 7362, 1, 7363, 1, 7364, 1, 7365, 1, + 7366, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7367, 1, 7368, 1, 7369, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7370, 1, 7371, 1, + 7372, 7373, 1, 1, 1, 1, 1, 1, + 7374, 1, 1, 1, 1, 1, 7375, 1, + 1, 1, 7376, 1, 7377, 1, 7378, 1, + 7379, 1, 7380, 1, 7381, 1, 7382, 1, + 7383, 1, 7384, 1, 7385, 1, 7386, 1, + 7387, 1, 7388, 1, 7389, 1, 7390, 1, + 7391, 1, 7392, 1, 7393, 1, 7394, 1, + 7395, 1, 7396, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7397, 1, 7398, 1, 7399, 1, 7400, + 1, 7401, 1, 7402, 1, 1, 7403, 1, + 7404, 1, 7405, 1, 7406, 1, 7407, 1, + 7408, 1, 7409, 1, 7410, 1, 7411, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7412, 1, 7413, 1, 7414, 1, 7415, + 1, 7416, 1, 7417, 1, 7418, 1, 7419, + 1, 7420, 1, 7421, 1, 1, 1, 1, + 1, 7422, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7423, 1, 7424, 1, + 7425, 1, 7426, 1, 7427, 1, 1, 1, + 1, 1, 1, 1, 1, 7428, 1, 7429, + 1, 7430, 1, 7431, 1, 7432, 1, 7433, + 1, 7434, 1, 7435, 1, 7436, 1, 7437, + 1, 7438, 1, 7439, 1, 1, 1, 7440, + 1, 1, 1, 7441, 1, 7442, 1, 7443, + 1, 7444, 1, 7445, 1, 7446, 1, 7447, + 1, 7448, 7449, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7450, 1, 7451, 1, + 7452, 1, 7453, 1, 7454, 1, 7455, 1, + 7456, 1, 7457, 1, 7458, 1, 7459, 1, + 7460, 1, 7461, 1, 7462, 1, 1, 1, + 7463, 1, 1, 1, 1, 1, 1, 7464, + 1, 7465, 1, 7466, 1, 7467, 1, 7468, + 1, 7469, 1, 7470, 1, 7471, 1, 7472, + 1, 7473, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7474, + 1, 1, 7475, 1, 1, 1, 1, 7476, + 1, 1, 1, 1, 1, 7477, 1, 1, + 1, 7478, 1, 1, 7479, 1, 7480, 1, + 7481, 1, 7482, 1, 7483, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7484, 7485, + 1, 1, 1, 1, 1, 1, 7486, 1, + 7487, 1, 7488, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7489, 1, + 7490, 1, 7491, 1, 7492, 1, 7493, 1, + 7494, 1, 7495, 1, 7496, 1, 7497, 1, + 7498, 1, 7499, 1, 7500, 1, 7501, 1, + 7502, 1, 7503, 1, 7504, 1, 1, 1, + 1, 1, 1, 1, 1, 7505, 1, 1, + 7506, 1, 7507, 1, 7508, 1, 7509, 1, + 7510, 1, 7511, 1, 7512, 1, 7513, 1, + 7514, 1, 7515, 7516, 1, 7517, 1, 7518, + 1, 7519, 1, 7520, 1, 7521, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7522, 1, 7523, 1, 7524, + 1, 7525, 1, 7526, 1, 7527, 1, 7528, + 1, 7529, 1, 7530, 1, 7531, 1, 7532, + 1, 7533, 7534, 1, 7535, 7536, 1, 1, + 7537, 7538, 1, 7539, 1, 1, 7540, 7541, + 1, 7542, 1, 7543, 1, 7544, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7545, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7546, 7547, 1, + 7549, 7548, 7550, 7548, 7551, 7548, 7552, 7548, + 7553, 1, 1, 7554, 1, 7555, 1, 7556, + 1, 7557, 1, 7558, 1, 7559, 1, 7560, + 1, 7561, 1, 7562, 1, 1, 1, 1, + 1, 7563, 1, 1, 1, 7564, 1, 1, + 7565, 1, 1, 1, 7566, 1, 7567, 1, + 7568, 1, 7569, 1, 7570, 1, 7571, 1, + 7572, 1, 7573, 1, 7574, 1, 7575, 1, + 7576, 1, 7577, 1, 7578, 1, 7579, 1, + 7580, 1, 7581, 1, 7582, 1, 7583, 1, + 1, 1, 7584, 1, 7585, 1, 7586, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7587, 1, 7588, 1, 7589, 1, 7590, + 1, 7591, 1, 7592, 1, 7593, 1, 7594, + 1, 7595, 1, 7596, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7597, 1, 7598, 1, + 7599, 1, 7600, 1, 7601, 1, 7602, 1, + 7603, 1, 7604, 1, 7605, 1, 7606, 1, + 7607, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7608, 1, 7609, 1, + 7610, 1, 1, 1, 1, 1, 1, 1, + 7611, 1, 7612, 1, 7613, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7614, 1, 7615, 1, 7616, 1, 7617, + 1, 7618, 1, 7619, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7620, 7621, 7622, 7623, 7624, 1, 1, + 1, 1, 1, 1, 1, 7625, 1, 1, + 1, 1, 1, 7626, 7627, 1, 7628, 1, + 7629, 1, 7630, 1, 7631, 1, 7632, 1, + 7633, 1, 7634, 1, 7635, 1, 7636, 1, + 1, 1, 1, 1, 7637, 1, 7638, 1, + 7639, 1, 7640, 1, 7641, 1, 7642, 1, + 7643, 1, 7644, 1, 7645, 1, 7646, 1, + 7647, 1, 7648, 1, 7649, 1, 1, 1, + 1, 1, 1, 7650, 1, 1, 1, 1, + 7651, 1, 7652, 1, 7653, 1, 7654, 1, + 7655, 1, 7656, 1, 7657, 1, 7658, 1, + 7659, 1, 7660, 1, 7661, 1, 7662, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7663, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7664, 1, 7665, 1, + 7666, 1, 1, 1, 7667, 1, 1, 1, + 1, 7668, 7669, 1, 1, 1, 7670, 1, + 7671, 1, 7672, 1, 7673, 1, 7674, 1, + 7675, 1, 7676, 1, 7677, 1, 7678, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7679, 1, + 7680, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7681, 1, + 7682, 1, 7683, 1, 1, 1, 1, 1, + 1, 1, 1, 7684, 1, 1, 1, 1, + 7685, 1, 7686, 1, 7687, 1, 7688, 1, + 7689, 1, 7690, 1, 7691, 1, 7692, 1, + 7693, 1, 7694, 1, 7695, 1, 7696, 1, + 7697, 1, 7698, 1, 7699, 1, 7700, 1, + 7701, 1, 1, 1, 7702, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7703, 1, 7704, 1, 7705, 1, + 7706, 1, 7707, 1, 7708, 1, 7709, 1, + 7710, 1, 7711, 1, 7712, 1, 7713, 1, + 7714, 1, 7715, 1, 7716, 1, 7717, 1, + 7718, 1, 7719, 1, 7720, 1, 7721, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7722, 1, + 7723, 1, 7724, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7725, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7726, 1, 7727, 1, 7728, 1, 7729, 1, + 7730, 1, 7731, 1, 7732, 1, 7733, 1, + 7734, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7735, 1, 7736, 1, 7737, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7738, 1, 1, 1, 1, 1, 1, + 7739, 1, 7740, 1, 7741, 1, 7742, 1, + 7743, 1, 7744, 1, 7745, 1, 7746, 1, + 7747, 1, 7748, 1, 7749, 1, 7750, 1, + 7751, 1, 7752, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7753, 1, 7754, 1, 7755, + 1, 7756, 1, 7757, 1, 7758, 1, 7759, + 1, 7760, 1, 7761, 1, 7762, 1, 7763, + 1, 1, 1, 1, 1, 7764, 1, 7765, + 1, 7766, 1, 7767, 1, 7768, 1, 7769, + 1, 7770, 1, 7771, 1, 7772, 1, 7773, + 1, 1, 7774, 1, 1, 1, 1, 1, + 7775, 7776, 1, 1, 7777, 1, 7778, 1, + 7779, 1, 7780, 1, 7781, 1, 7782, 1, + 7783, 1, 7784, 1, 7785, 1, 7786, 1, + 7787, 1, 7788, 1, 7789, 1, 7790, 1, + 7791, 1, 7792, 1, 7793, 1, 7794, 1, + 7795, 1, 1, 1, 7796, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7797, 1, + 7798, 1, 7799, 1, 1, 1, 7800, 1, + 7801, 1, 7802, 1, 7803, 1, 7804, 1, + 7805, 1, 7806, 1, 7807, 1, 7808, 1, + 7809, 1, 7810, 1, 7811, 1, 7812, 1, + 7813, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7814, 1, 7815, 1, 7816, 1, + 7817, 1, 7818, 7819, 1, 1, 1, 1, + 1, 7820, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7821, 7822, 7823, 7824, 7825, 7826, + 1, 7827, 7828, 1, 1, 7829, 7830, 7831, + 7832, 7833, 1, 7834, 7835, 7836, 7837, 1, + 1, 7838, 1, 7839, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7840, 1, 7841, 1, + 7842, 1, 7843, 1, 7844, 1, 7845, 1, + 7846, 1, 7847, 1, 7848, 1, 7849, 1, + 7850, 1, 7851, 1, 7852, 1, 7853, 1, + 7854, 1, 7855, 1, 7856, 1, 7857, 1, + 7858, 7859, 7860, 1, 1, 1, 1, 1, + 1, 1, 1, 7861, 1, 1, 7862, 7863, + 1, 7864, 1, 7865, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7866, 1, 7867, 1, 7868, + 1, 7869, 1, 7870, 1, 7871, 1, 7872, + 1, 7873, 1, 7874, 1, 7875, 1, 7876, + 1, 7877, 1, 7878, 1, 7879, 1, 7880, + 1, 7881, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7882, 7883, 1, 1, 1, 1, + 1, 1, 7884, 1, 7885, 1, 7886, 1, + 7887, 1, 7888, 1, 7889, 1, 7890, 1, + 7891, 1, 7892, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7893, 7894, 7895, 1, 1, 7896, 1, 7897, + 1, 1, 1, 7898, 1, 1, 1, 7899, + 1, 1, 7900, 7901, 1, 1, 7902, 1, + 7903, 1, 7904, 1, 7905, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7906, + 1, 7907, 1, 7908, 1, 7909, 1, 7910, + 1, 7911, 1, 7912, 1, 7913, 1, 7914, + 1, 7915, 1, 7916, 1, 7917, 1, 7918, + 1, 7919, 1, 7920, 1, 7921, 1, 7922, + 1, 7923, 1, 7924, 1, 1, 1, 1, + 1, 1, 1, 7925, 1, 7926, 1, 7927, + 1, 7928, 1, 7929, 1, 7930, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7931, 1, 7932, 1, 7933, 1, 7934, 1, + 7935, 1, 7936, 7937, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7938, 1, 7939, 1, 7940, + 1, 7941, 1, 7942, 1, 7943, 1, 7944, + 1, 7945, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 7946, 1, 7947, 1, 7948, + 1, 1, 1, 1, 1, 7949, 1, 7950, + 1, 7951, 1, 7952, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 7953, 1, 7954, 1, 7955, 1, 7956, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 7957, 1, 7958, 1, 7959, 1, 7960, 1, + 1, 1, 7961, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7962, 1, 1, 1, 7963, 1, + 7964, 1, 7965, 1, 7966, 1, 7967, 1, + 7968, 1, 1, 1, 1, 7969, 1, 7970, + 1, 7971, 1, 7972, 1, 7973, 1, 7974, + 1, 7975, 1, 7976, 1, 7977, 1, 7978, + 1, 1, 1, 1, 1, 1, 1, 1, + 7979, 1, 1, 1, 1, 7980, 1, 7981, + 1, 7982, 1, 7983, 1, 7984, 1, 7985, + 1, 7986, 1, 7987, 1, 7988, 1, 7989, + 1, 7990, 1, 7991, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7992, 1, 7993, 1, 7994, 1, + 7995, 1, 7996, 1, 7997, 1, 1, 1, + 7998, 1, 7999, 1, 8000, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8001, 1, 1, 1, 1, 1, + 1, 8002, 1, 1, 8003, 1, 8004, 1, + 8005, 1, 8006, 1, 8007, 1, 8008, 1, + 8009, 1, 8010, 1, 8011, 1, 8012, 1, + 8013, 1, 8014, 1, 1, 8015, 1, 1, + 1, 1, 1, 8016, 1, 8017, 1, 8018, + 1, 8019, 1, 8020, 1, 8021, 1, 8022, + 1, 8023, 1, 8024, 1, 8025, 1, 8026, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8027, 1, 8028, + 1, 8029, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8030, 1, 8031, 1, 8032, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8033, + 1, 8034, 1, 8035, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8036, 1, + 8037, 1, 8038, 1, 1, 1, 1, 1, + 1, 8039, 1, 1, 1, 1, 8040, 1, + 8041, 1, 8042, 1, 8043, 1, 1, 1, + 1, 1, 1, 8044, 1, 1, 1, 8045, + 1, 1, 1, 1, 1, 8046, 8047, 8048, + 1, 8049, 1, 8050, 1, 8051, 1, 8052, + 1, 8053, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8054, 1, 8055, 1, 8056, 1, + 8057, 1, 8058, 1, 8059, 1, 8060, 1, + 8061, 1, 8062, 1, 8063, 1, 8064, 1, + 8065, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8066, 1, 8067, 1, 8068, 1, 8069, + 1, 8070, 1, 8071, 1, 8072, 1, 8073, + 1, 8074, 1, 8075, 1, 8076, 1, 1, + 1, 1, 1, 1, 8077, 1, 8078, 1, + 8079, 1, 8080, 1, 8081, 1, 8082, 1, + 8083, 1, 8084, 1, 8085, 1, 8086, 1, + 8087, 1, 8088, 1, 8089, 1, 8090, 1, + 8091, 1, 8092, 1, 8093, 1, 8094, 1, + 8095, 1, 8096, 1, 8097, 1, 8098, 1, + 8099, 1, 8100, 1, 8101, 1, 8102, 1, + 8103, 1, 8104, 1, 8105, 1, 8106, 1, + 8107, 1, 8108, 1, 8109, 1, 8110, 1, + 8111, 1, 8112, 1, 8113, 1, 8114, 1, + 8115, 1, 8116, 1, 8117, 1, 8118, 1, + 8119, 1, 8120, 1, 8121, 1, 8122, 1, + 8123, 1, 8124, 1, 8125, 1, 8126, 1, + 8127, 1, 8128, 1, 8129, 1, 8130, 1, + 8131, 1, 8132, 1, 8133, 1, 8134, 1, + 8135, 1, 1, 1, 1, 1, 1, 8136, + 1, 1, 1, 1, 8137, 1, 8138, 1, + 8139, 1, 8140, 1, 8141, 1, 8142, 1, + 8143, 1, 8144, 1, 8145, 1, 8146, 1, + 8147, 1, 8148, 1, 8149, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8150, 1, 8151, 1, 8152, 1, + 8153, 1, 8154, 1, 8155, 1, 8156, 1, + 8157, 1, 8158, 1, 8159, 8160, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8161, 1, 1, 1, 8162, + 1, 8163, 1, 1, 1, 8164, 1, 8165, + 1, 8166, 1, 8167, 1, 8168, 1, 8169, + 1, 8170, 1, 8171, 1, 8172, 1, 1, + 1, 1, 8173, 1, 1, 1, 1, 1, + 8174, 1, 8175, 1, 8176, 1, 8177, 1, + 8178, 1, 8179, 1, 8180, 1, 8181, 1, + 8182, 1, 8183, 1, 8184, 1, 8185, 1, + 8186, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8187, + 1, 8188, 1, 8189, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8190, + 1, 8191, 1, 8192, 1, 8193, 1, 8194, + 1, 8195, 1, 8196, 1, 8197, 1, 8198, + 1, 8199, 1, 8200, 1, 8201, 1, 8202, + 1, 8203, 1, 8204, 1, 1, 1, 1, + 8205, 1, 1, 1, 1, 1, 1, 1, + 1, 8206, 1, 8207, 1, 8208, 1, 8209, + 1, 8210, 1, 8211, 1, 8212, 1, 8213, + 1, 8214, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8215, 1, 8216, 1, + 8217, 1, 8218, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8219, 1, 8220, 1, 8221, 8222, 1, + 1, 1, 1, 1, 1, 1, 1, 8223, + 1, 8224, 1, 8225, 1, 8226, 1, 8227, + 1, 8228, 1, 8229, 1, 8230, 1, 8231, + 1, 8232, 1, 8233, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8234, 8235, 1, + 1, 1, 1, 1, 8236, 1, 8237, 1, + 8238, 1, 8239, 1, 8240, 1, 8241, 1, + 8242, 1, 8243, 1, 8244, 1, 8245, 1, + 8246, 1, 8247, 1, 8248, 1, 8249, 1, + 8250, 8251, 8252, 8253, 8254, 8255, 1, 8256, + 8257, 1, 1, 8258, 8259, 1, 8260, 8261, + 8262, 8263, 8264, 8265, 8266, 1, 8267, 1, + 1, 8268, 1, 8269, 1, 8270, 1, 8271, + 1, 8272, 1, 8273, 1, 8274, 1, 8275, + 1, 8276, 1, 8277, 1, 8278, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8279, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8280, 1, 8281, 1, 8282, + 1, 1, 1, 8283, 1, 1, 1, 1, + 8284, 1, 8285, 1, 1, 8286, 1, 1, + 1, 1, 1, 8287, 1, 8288, 1, 8289, + 1, 8290, 1, 8291, 1, 8292, 1, 8293, + 1, 8294, 1, 8295, 1, 8296, 1, 8297, + 1, 8298, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8299, 1, 8300, 1, 8301, 1, + 8302, 1, 8303, 1, 8304, 1, 8305, 1, + 8306, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8307, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8308, 1, + 8309, 1, 8310, 1, 8311, 1, 8312, 1, + 8313, 1, 8314, 1, 8315, 1, 8316, 1, + 8317, 1, 8318, 1, 8319, 1, 8320, 1, + 8321, 1, 8322, 1, 8323, 1, 8324, 1, + 8325, 1, 8326, 1, 8327, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8328, 1, 1, 8329, 1, + 8330, 1, 8331, 1, 8332, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8333, 1, 8334, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8335, 1, 1, 1, 1, 1, 8336, 8337, + 1, 1, 1, 8338, 1, 8339, 1, 8340, + 1, 8341, 1, 8342, 1, 8343, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8344, + 1, 8345, 1, 8346, 1, 8347, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8348, 1, 8349, 1, 8350, 1, 8351, + 1, 8352, 1, 8353, 1, 8354, 1, 8355, + 1, 8356, 1, 8357, 1, 8358, 1, 8359, + 1, 1, 1, 1, 8360, 1, 8361, 1, + 8362, 1, 8363, 1, 8364, 1, 8365, 1, + 8366, 1, 8367, 1, 8368, 1, 8369, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8370, 1, 8371, 1, 8372, 1, + 8373, 1, 8374, 1, 8375, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8376, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8377, 1, 8378, 1, 8379, 1, + 8380, 1, 8381, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8382, 1, 8383, 1, 8384, + 1, 8385, 1, 8386, 1, 8387, 1, 8388, + 1, 8389, 1, 1, 8390, 1, 8391, 1, + 8392, 1, 8393, 1, 8394, 1, 8395, 1, + 8396, 1, 8397, 1, 8398, 1, 8399, 1, + 8400, 1, 8401, 1, 8402, 1, 1, 1, + 1, 1, 8403, 1, 8404, 1, 8405, 1, + 8406, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8407, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8408, 1, 8409, 1, 8410, + 1, 8411, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8412, 8413, 1, 8414, 1, 1, + 1, 1, 8415, 1, 8416, 1, 8417, 1, + 8418, 1, 8419, 1, 8420, 1, 8421, 1, + 8422, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8423, 1, + 8424, 1, 8425, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8426, 1, 8427, 1, + 8428, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8429, 1, 8430, 1, 8431, 1, + 8432, 1, 8433, 1, 8434, 1, 8435, 1, + 8436, 1, 8437, 1, 8438, 1, 8439, 1, + 8440, 1, 8441, 1, 8442, 1, 8443, 1, + 8444, 1, 8445, 1, 1, 1, 8446, 1, + 1, 1, 8447, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8448, 1, 8449, + 1, 1, 1, 1, 1, 1, 8450, 1, + 8451, 1, 8452, 1, 8453, 1, 8454, 1, + 8455, 1, 8456, 1, 8457, 1, 8458, 1, + 8459, 1, 8460, 1, 8461, 1, 8462, 1, + 8463, 1, 8464, 1, 8465, 1, 8466, 1, + 8467, 1, 8468, 1, 8469, 1, 8470, 1, + 1, 1, 1, 1, 1, 1, 8471, 1, + 8472, 1, 8473, 1, 8474, 1, 8475, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8476, 1, 8477, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8478, 1, 8479, 1, 8480, 1, + 1, 1, 1, 1, 8481, 1, 1, 1, + 8482, 1, 8483, 1, 8484, 1, 8485, 1, + 8486, 1, 8487, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8488, 1, 8489, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8490, 1, 8491, 1, 8492, 1, 8493, + 1, 8494, 1, 8495, 1, 8496, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8497, 1, 8498, 1, 8499, + 1, 8500, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8501, 1, 8502, 1, 8503, + 1, 8504, 1, 8505, 1, 8506, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8507, 1, 8508, + 1, 8509, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8510, 1, 8511, + 1, 8512, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8513, 1, 8514, 1, 8515, 1, 8516, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8517, + 1, 8518, 1, 8519, 1, 8520, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8521, 1, 8522, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8523, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8524, 1, 8525, + 1, 8526, 1, 8527, 1, 8528, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8529, + 1, 8530, 1, 8531, 1, 8532, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8533, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8534, 1, 8535, + 1, 8536, 1, 8537, 1, 8538, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8539, + 1, 8540, 1, 8541, 1, 8542, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8543, 1, 1, 1, 1, + 8544, 1, 8545, 1, 8546, 8547, 1, 8548, + 1, 8549, 1, 8550, 1, 8551, 1, 8552, + 1, 8553, 1, 8554, 1, 8555, 1, 8556, + 1, 1, 1, 1, 1, 1, 1, 8557, + 1, 1, 1, 1, 1, 1, 8558, 1, + 8559, 1, 8560, 1, 8561, 1, 8562, 1, + 8563, 1, 8564, 1, 8565, 1, 8566, 1, + 8567, 1, 8568, 1, 8569, 1, 8570, 1, + 8571, 1, 8572, 1, 8573, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8574, 1, 8575, + 1, 8576, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8577, 1, 8578, 1, + 8579, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8580, 1, 8581, + 1, 8582, 1, 8583, 1, 8584, 1, 8585, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8586, 1, 8587, 1, 8588, 1, + 8589, 1, 8590, 1, 8591, 1, 8592, 1, + 8593, 1, 8594, 1, 8595, 1, 8596, 1, + 8597, 1, 8598, 1, 8599, 8600, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8601, + 8602, 1, 8603, 1, 8604, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8605, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8606, 8607, 1, + 1, 1, 1, 1, 1, 1, 8608, 8609, + 1, 8610, 1, 8611, 8612, 1, 8613, 1, + 8614, 1, 8615, 1, 8616, 1, 8617, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8618, + 1, 8619, 1, 8620, 1, 8621, 1, 8622, + 1, 8623, 1, 8624, 1, 8625, 1, 8626, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8627, + 1, 8628, 1, 8629, 1, 8630, 1, 8631, + 1, 8632, 1, 8633, 1, 8634, 1, 8635, + 1, 8636, 1, 8637, 1, 8638, 1, 1, + 1, 8639, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8640, 1, 8641, + 1, 8642, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8643, 1, 1, 1, 1, + 1, 1, 1, 1, 8644, 1, 8645, 1, + 8646, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8647, 1, + 8648, 1, 8649, 1, 8650, 1, 8651, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8652, 1, 8653, 1, + 8654, 1, 8655, 1, 8656, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8657, 1, 8658, 1, 8659, 1, + 8660, 1, 8661, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8662, 1, 8663, 1, 8664, 1, 1, 1, + 1, 1, 1, 1, 1, 8665, 1, 1, + 1, 1, 8666, 1, 8667, 1, 8668, 1, + 8669, 1, 8670, 1, 8671, 1, 8672, 1, + 8673, 1, 8674, 1, 8675, 1, 8676, 1, + 8677, 1, 8678, 1, 8679, 1, 8680, 1, + 8681, 1, 8682, 1, 1, 1, 8683, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8684, 1, 8685, 1, + 8686, 1, 8687, 1, 8688, 1, 8689, 1, + 8690, 1, 8691, 1, 8692, 1, 8693, 1, + 8694, 1, 8695, 1, 8696, 1, 8697, 1, + 8698, 1, 8699, 1, 8700, 1, 8701, 1, + 8702, 1, 8703, 8704, 8705, 1, 1, 1, + 1, 1, 1, 1, 8706, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8707, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8708, 8709, 1, + 1, 8710, 1, 1, 1, 8711, 8712, 8713, + 1, 8714, 1, 1, 8715, 1, 8716, 1, + 8717, 1, 1, 1, 8718, 1, 8719, 1, + 8720, 1, 8721, 1, 8722, 1, 8723, 1, + 8724, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8725, 1, 8726, 1, 8727, 1, 8728, + 1, 8729, 1, 8730, 1, 1, 1, 1, + 1, 8731, 1, 8732, 1, 8733, 1, 8734, + 1, 8735, 1, 8736, 1, 8737, 1, 8738, + 1, 8739, 1, 8740, 1, 8741, 1, 8742, + 1, 8743, 1, 8744, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8745, 1, 8746, 1, 8747, + 1, 8748, 1, 8749, 1, 8750, 1, 8751, + 1, 8752, 1, 1, 1, 8753, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8754, 1, 8755, 1, 8756, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8757, + 1, 1, 1, 1, 1, 1, 1, 1, + 8758, 1, 8759, 1, 8760, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8761, 1, 8762, 1, 8763, 1, + 8764, 1, 8765, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8766, 1, 8767, 1, 8768, 1, 8769, 1, + 8770, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8771, 1, + 8772, 1, 8773, 1, 8774, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8775, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 8776, 1, 8777, 1, 8778, 1, 8779, + 1, 8780, 1, 8781, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8782, 1, 8783, + 1, 8784, 1, 8785, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8786, + 1, 8787, 1, 8788, 1, 8789, 1, 8790, + 1, 8791, 1, 8792, 1, 8793, 1, 8794, + 1, 8795, 1, 8796, 8797, 8798, 8799, 8800, + 8801, 1, 8802, 8803, 1, 1, 1, 1, + 1, 8804, 8805, 1, 8806, 8807, 1, 1, + 1, 8808, 1, 8809, 1, 1, 8810, 1, + 8811, 1, 8812, 1, 8813, 1, 8814, 1, + 8815, 1, 8816, 1, 8817, 1, 8818, 1, + 8819, 1, 1, 1, 8820, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8821, 1, 8822, 1, 8823, 1, 8824, 1, + 8825, 1, 8826, 1, 8827, 1, 8828, 1, + 8829, 1, 8830, 1, 8831, 1, 8832, 1, + 8833, 1, 8834, 1, 8835, 1, 8836, 1, + 8837, 1, 8838, 1, 8839, 1, 8840, 1, + 8841, 1, 1, 1, 8842, 1, 8843, 1, + 1, 1, 8844, 1, 8845, 1, 8846, 1, + 8847, 1, 8848, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8849, 1, 8850, 1, + 8851, 1, 8852, 1, 8853, 1, 8854, 1, + 8855, 1, 8856, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8857, 1, 1, 8858, 1, 8859, + 1, 8860, 1, 8861, 1, 8862, 1, 8863, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8864, 1, 8865, 1, 8866, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8867, 1, 8868, 1, 8869, 1, 8870, 1, + 8871, 1, 8872, 1, 8873, 1, 8874, 1, + 8875, 1, 8876, 1, 8877, 1, 8878, 1, + 8879, 1, 8880, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 8881, 1, 8882, 1, + 8883, 1, 8884, 1, 8885, 1, 8886, 1, + 8887, 1, 8888, 1, 8889, 8890, 8891, 1, + 8892, 1, 8893, 1, 8894, 1, 8895, 1, + 8896, 1, 8898, 8897, 8897, 8897, 8897, 8897, + 8897, 8897, 8897, 8897, 8897, 8897, 8897, 8897, + 8897, 8897, 8897, 8897, 8897, 8897, 8897, 8897, + 8897, 8897, 8897, 8897, 8897, 8897, 8897, 8897, + 8897, 8897, 8897, 8897, 8897, 8897, 8897, 8897, + 8899, 8897, 8900, 8897, 8901, 8897, 8902, 8897, + 8903, 1, 8904, 1, 8905, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8906, + 1, 1, 8907, 1, 8908, 1, 8909, 1, + 8910, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8911, + 8912, 1, 1, 8913, 1, 8914, 1, 8915, + 1, 8916, 1, 8917, 1, 8918, 1, 8919, + 1, 8920, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 8921, 1, 8922, + 1, 8923, 1, 8924, 1, 8925, 1, 8926, + 1, 8927, 1, 8928, 1, 8929, 1, 8930, + 1, 8931, 1, 8932, 1, 1, 1, 1, + 1, 1, 1, 8933, 1, 1, 1, 1, + 1, 1, 8934, 1, 8935, 1, 8936, 1, + 8937, 1, 8938, 1, 1, 8939, 8940, 1, + 1, 1, 1, 1, 1, 1, 8941, 1, + 1, 8942, 1, 1, 8943, 8944, 1, 8945, + 1, 8946, 1, 8947, 1, 8948, 1, 8949, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8950, 1, 1, 1, 1, 1, 1, 1, + 8951, 1, 1, 1, 1, 8952, 8953, 1, + 8954, 1, 8955, 1, 8956, 1, 8957, 1, + 8958, 1, 8959, 1, 8960, 1, 8961, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 8962, 1, 8963, 1, 8964, 1, 8965, 1, + 8966, 1, 8967, 1, 8968, 1, 8969, 1, + 8970, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8971, 1, 8972, 1, 8973, 1, + 8974, 1, 8975, 1, 8976, 1, 8977, 1, + 8978, 1, 8979, 1, 8980, 1, 8981, 1, + 8982, 1, 8983, 1, 8984, 1, 8985, 1, + 8986, 1, 8987, 1, 8988, 1, 8989, 1, + 8990, 1, 8991, 1, 8992, 1, 8993, 1, + 8994, 1, 8995, 1, 8996, 1, 8997, 1, + 8998, 1, 8999, 1, 1, 1, 1, 9000, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9001, 1, 9002, 1, 1, + 1, 1, 1, 1, 9003, 1, 9004, 1, + 9005, 1, 9006, 1, 9007, 1, 9008, 1, + 9009, 1, 9010, 1, 9011, 1, 9012, 1, + 9013, 1, 1, 1, 1, 1, 9014, 1, + 9015, 1, 9016, 1, 9017, 1, 9018, 1, + 9019, 1, 9020, 1, 9021, 1, 9022, 1, + 1, 1, 1, 1, 9023, 1, 9024, 1, + 9025, 1, 9026, 1, 9027, 1, 9028, 1, + 9029, 1, 9030, 1, 9031, 1, 9032, 1, + 9033, 1, 9034, 1, 9035, 1, 9036, 1, + 9037, 1, 9038, 1, 9039, 1, 9040, 1, + 9041, 1, 9042, 1, 9043, 1, 1, 1, + 1, 1, 1, 9044, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9045, 9046, 9047, 9048, + 1, 9049, 9050, 9051, 1, 1, 1, 9052, + 9053, 1, 9054, 9055, 1, 9056, 9057, 9058, + 9059, 1, 9060, 1, 9061, 1, 9062, 1, + 9063, 1, 9064, 1, 9065, 1, 9066, 1, + 9067, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 9068, + 1, 9069, 1, 9070, 1, 9071, 1, 9072, + 1, 9073, 1, 9074, 1, 9075, 1, 9076, + 1, 9077, 1, 9078, 1, 9079, 1, 9080, + 1, 9081, 1, 9082, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9083, 1, 9084, 1, 9085, + 1, 9086, 1, 9087, 9088, 1, 1, 1, + 1, 1, 9089, 1, 9090, 1, 9091, 1, + 9092, 1, 9093, 1, 9094, 1, 9095, 1, + 9096, 1, 9097, 1, 9098, 1, 9099, 1, + 9100, 1, 1, 1, 1, 1, 1, 1, + 1, 9101, 1, 9102, 1, 9103, 1, 9104, + 1, 9105, 1, 9106, 1, 9107, 1, 9108, + 1, 9109, 1, 9110, 1, 9111, 9112, 1, + 9113, 1, 9114, 1, 1, 1, 1, 1, + 9115, 1, 9116, 1, 9117, 1, 9118, 1, + 9119, 1, 9120, 1, 9121, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9122, 1, 9123, + 1, 1, 9124, 1, 9125, 1, 9126, 1, + 9127, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 9128, 1, 9129, 1, 9130, 1, + 9131, 1, 9132, 1, 9133, 1, 9134, 1, + 9135, 1, 9136, 1, 9137, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 9138, + 1, 9139, 1, 9140, 1, 9141, 1, 9142, + 1, 1, 1, 1, 1, 1, 1, 1, + 9143, 1, 9144, 1, 9145, 1, 9146, 1, + 9147, 1, 9148, 1, 9149, 1, 1, 9150, + 1, 1, 1, 9151, 1, 1, 1, 9152, + 1, 1, 1, 1, 1, 1, 9153, 1, + 9154, 1, 9155, 1, 9156, 1, 9157, 1, + 9158, 1, 9159, 1, 9160, 1, 9161, 1, + 9162, 1, 9163, 1, 9164, 1, 9165, 1, + 9166, 1, 9167, 1, 9168, 1, 9169, 1, + 9170, 1, 9171, 1, 9172, 1, 9173, 1, + 9174, 1, 9175, 1, 1, 1, 1, 1, + 9176, 1, 9177, 1, 9178, 1, 9179, 1, + 9180, 1, 9181, 1, 9182, 1, 9183, 1, + 9184, 1, 9185, 1, 9186, 1, 9187, 1, + 9188, 1, 9189, 1, 9190, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9191, 1, 1, 1, 9192, 1, 9193, + 1, 9194, 1, 9195, 1, 9196, 1, 9197, + 1, 9198, 1, 9199, 1, 9200, 1, 9201, + 1, 9202, 1, 9203, 1, 9204, 1, 9205, + 1, 1, 1, 1, 1, 9206, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9207, 1, 9208, 1, 1, 9209, 1, 9210, + 1, 9211, 1, 9212, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9213, 1, 9214, + 1, 9215, 1, 9216, 1, 9217, 1, 9218, + 1, 9219, 1, 9220, 1, 9221, 1, 9222, + 1, 9223, 1, 9224, 1, 9225, 1, 9226, + 1, 9227, 1, 9228, 1, 1, 1, 1, + 9229, 1, 1, 1, 1, 1, 1, 1, + 1, 9230, 1, 9231, 1, 9232, 1, 9233, + 1, 9234, 1, 9235, 1, 9236, 1, 9237, + 1, 9238, 1, 9239, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 9240, 1, + 9241, 1, 9242, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 9243, 1, + 9244, 1, 9245, 1, 9246, 1, 9247, 1, + 9248, 1, 9249, 1, 9250, 1, 9251, 1, + 9252, 1, 9253, 1, 9254, 9255, 1, 9256, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9257, 1, 9258, 9259, + 9260, 9261, 1, 1, 1, 1, 1, 9262, + 1, 9263, 9264, 9265, 1, 9266, 9267, 1, + 1, 1, 1, 1, 1, 9268, 1, 9269, + 1, 9270, 1, 9271, 1, 9272, 1, 9273, + 1, 9274, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9275, 1, 9276, 1, + 9277, 1, 9278, 1, 9279, 1, 9280, 1, + 9281, 1, 1, 1, 9282, 1, 9283, 1, + 9284, 1, 9285, 1, 9286, 1, 9287, 1, + 1, 1, 1, 1, 9288, 1, 1, 9289, + 1, 9290, 1, 9291, 9292, 9293, 1, 9294, + 1, 9295, 1, 9296, 1, 9297, 1, 9298, + 1, 9299, 1, 9300, 1, 9301, 1, 9302, + 1, 9303, 1, 9304, 1, 9305, 1, 9306, + 1, 9307, 1, 9308, 1, 9309, 1, 9310, + 1, 9311, 1, 9312, 1, 9313, 9314, 1, + 1, 1, 1, 1, 1, 1, 1, 9315, + 1, 9316, 1, 9317, 1, 9318, 1, 9319, + 1, 9320, 1, 9321, 1, 9322, 1, 9323, + 1, 9324, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 9325, 1, + 9326, 1, 9327, 1, 9328, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9329, 1, 9330, 1, 9331, 1, 9332, 1, + 9333, 1, 9334, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9335, 1, 9336, 1, 9337, 1, 9338, 1, + 9339, 1, 9340, 1, 9341, 1, 9342, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9343, 1, 9344, 1, + 9345, 1, 9346, 1, 9347, 1, 9348, 1, + 9349, 1, 9350, 1, 9351, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 9352, 1, 9353, 1, 9354, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 9355, 1, 9356, 1, 9357, 1, 9358, 1, + 9359, 1, 9360, 1, 9361, 1, 9362, 1, + 9363, 1, 9364, 1, 9365, 1, 9366, 1, + 1, 1, 1, 1, 9367, 1, 9368, 1, + 9369, 1, 9370, 1, 9371, 1, 9372, 1, + 9373, 1, 9374, 1, 9375, 1, 9376, 1, + 9377, 1, 9378, 1, 9379, 1, 9380, 1, + 9381, 1, 9382, 1, 9383, 1, 1, 1, + 1, 1, 1, 9384, 1, 1, 1, 1, + 1, 9385, 1, 9386, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 9387, 1, 1, 9388, 1, 9389, + 1, 9390, 1, 9391, 1, 9392, 1, 9393, + 1, 9394, 1, 9395, 1, 9396, 1, 9397, + 1, 9398, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9399, 1, 9400, 1, 9401, + 1, 9402, 1, 9403, 1, 9404, 1, 9405, + 1, 9406, 1, 9407, 1, 9408, 1, 9409, + 1, 9410, 1, 9411, 1, 9412, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9413, 1, 9414, 1, 9415, + 1, 9416, 1, 9417, 1, 9418, 1, 9419, + 1, 9420, 1, 9421, 1, 9422, 1, 9423, + 1, 9424, 1, 9425, 1, 9426, 1, 9427, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9428, 1, 9429, 1, 9430, 1, 9431, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9432, 1, 9433, + 1, 9434, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9435, 1, 9436, 1, 9437, 1, 9438, + 1, 9439, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9440, 1, 9441, 1, 9442, 1, 9443, + 1, 9444, 1, 9445, 1, 9446, 1, 9447, + 1, 9448, 1, 9449, 1, 9450, 9451, 1, + 1, 1, 1, 1, 1, 1, 1, 9452, + 9453, 1, 9454, 9455, 1, 9456, 1, 9457, + 1, 9458, 1, 9459, 1, 9460, 1, 1, + 1, 1, 9461, 1, 9462, 1, 1, 1, + 1, 9463, 1, 9464, 1, 9465, 1, 9466, + 1, 9467, 1, 9468, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9469, 1, 9470, 1, 9471, 1, 9472, + 1, 9473, 1, 9474, 1, 9475, 1, 9476, + 1, 9477, 1, 9478, 1, 9479, 1, 9480, + 1, 9481, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9482, 1, 9483, 1, 9484, + 1, 9485, 1, 9486, 1, 9487, 1, 9488, + 1, 9489, 1, 9490, 9491, 1, 9492, 1, + 9493, 9494, 1, 1, 9495, 9496, 9497, 9498, + 1, 1, 9499, 9500, 1, 9501, 9502, 9503, + 1, 9504, 1, 1, 1, 1, 1, 1, + 1, 9505, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9506, 1, 9507, + 1, 9508, 1, 9509, 1, 9510, 1, 9511, + 1, 9512, 1, 9513, 1, 9514, 1, 9515, + 1, 9516, 1, 9517, 1, 9518, 1, 9519, + 1, 9520, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9521, 1, 9522, 1, 9523, 1, 9524, + 1, 9525, 1, 9526, 1, 9527, 1, 9528, + 1, 9529, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9530, 1, 9531, 1, 9532, 1, 9533, + 1, 9534, 1, 9535, 1, 9536, 1, 9537, + 1, 9538, 1, 9539, 1, 9540, 1, 9541, + 1, 9542, 1, 9543, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 9544, + 1, 1, 1, 9545, 1, 9546, 1, 9547, + 1, 9548, 1, 9549, 1, 1, 1, 1, + 1, 9550, 1, 9551, 1, 9552, 1, 9553, + 1, 9554, 1, 9555, 1, 9556, 1, 9557, + 1, 9558, 1, 9559, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9560, 1, 9561, 1, 9562, + 1, 9563, 1, 9564, 1, 9565, 1, 9566, + 1, 9567, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 9568, + 1, 9569, 1, 9570, 1, 9571, 1, 9572, + 1, 9573, 1, 9574, 1, 9575, 1, 1, + 1, 9576, 1, 9577, 1, 9578, 1, 9579, + 1, 9580, 1, 9581, 1, 9582, 1, 9583, + 1, 9584, 1, 9585, 1, 9586, 1, 9587, + 1, 9588, 1, 9589, 1, 9590, 1, 9591, + 1, 9592, 1, 9593, 1, 9594, 9595, 1, + 1, 9596, 1, 1, 1, 1, 1, 9597, + 1, 1, 1, 9598, 1, 9599, 1, 9600, + 1, 9601, 1, 1, 1, 9602, 1, 9603, + 1, 9604, 1, 9605, 1, 9606, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9607, 1, 9608, + 1, 9609, 1, 9610, 1, 9611, 1, 9612, + 1, 9613, 1, 9614, 1, 9615, 1, 9616, + 1, 9617, 1, 9618, 1, 9619, 1, 9620, + 1, 9621, 1, 9622, 1, 9623, 1, 9624, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9625, 1, 9626, 1, 9627, 1, 9628, + 1, 9629, 1, 9630, 9631, 9632, 9633, 1, + 9634, 9635, 1, 1, 1, 1, 1, 9636, + 1, 1, 1, 9637, 1, 1, 1, 9638, + 1, 9639, 1, 9640, 1, 9641, 1, 9642, + 1, 9643, 1, 9644, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 9645, 1, 9646, 1, 9647, + 1, 9648, 1, 9649, 1, 9650, 1, 9651, + 1, 9652, 1, 9653, 1, 9654, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 9655, 1, 9656, 1, + 9657, 1, 9658, 1, 9659, 1, 9660, 1, + 9661, 1, 9662, 1, 9663, 1, 9664, 1, + 9665, 1, 9666, 1, 9667, 1, 9668, 1, + 9669, 1, 9670, 1, 9671, 1, 9672, 1, + 9673, 1, 9674, 1, 9675, 1, 9676, 1, + 9677, 1, 9678, 1, 9679, 1, 1, 1, + 9680, 1, 9681, 1, 9682, 1, 9683, 1, + 9684, 9685, 9686, 9687, 9688, 9689, 9690, 9691, + 9692, 9693, 9694, 9695, 9696, 9697, 9698, 9699, + 9700, 9701, 9702, 9703, 9704, 9705, 9706, 9707, + 9708, 9709, 1, 1, 1, 1, 1, 1, + 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, + 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, + 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, + 9734, 9735, 1, 9737, 9736, 9739, 9738, 9741, + 9740, 9743, 9742, 9745, 9744, 9747, 9746, 9749, + 9748, 9751, 9750, 9753, 9752, 9755, 9754, 9757, + 9756, 9759, 9758, 9761, 9760, 9763, 9762, 9765, + 9764, 9767, 9766, 9769, 9768, 9771, 9770, 9773, + 9772, 9775, 9774, 9777, 9776, 9779, 9778, 9781, + 9780, 9783, 9782, 9785, 9784, 9787, 9786, 9789, + 9788, 9791, 9790, 9793, 9792, 9795, 9794, 9797, + 9796, 9799, 9798, 9801, 9800, 9803, 9802, 9805, + 9804, 9807, 9806, 9809, 9808, 9811, 9810, 9813, + 9812, 9815, 9814, 9817, 9816, 9819, 9818, 9821, + 9820, 9823, 9822, 9825, 9824, 9827, 9826, 9829, + 9828, 9831, 9830, 9833, 9832, 9832, 9832, 9832, + 9832, 9832, 9832, 9832, 9832, 9832, 9832, 9832, + 9832, 9832, 9832, 9832, 9832, 9832, 9832, 9832, + 9832, 9832, 9832, 9832, 9832, 9832, 9832, 9832, + 9832, 9832, 9832, 9832, 9832, 9832, 9832, 9832, + 9832, 9832, 9832, 9832, 9832, 9834, 9832, 9836, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9835, + 9835, 9835, 9835, 9835, 9835, 9835, 9835, 9837, + 9835, 9839, 9838, 9841, 9840, 9843, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9842, 9842, 9842, 9842, 9842, 9842, 9842, + 9842, 9844, 9842, 9846, 9845, 9848, 9847, 9850, + 9849, 9852, 9851, 9854, 9853, 9856, 9855, 9858, + 9857, 9860, 9859, 9862, 9861, 9861, 9861, 9861, + 9861, 9861, 9861, 9861, 9861, 9861, 9861, 9861, + 9861, 9861, 9861, 9861, 9861, 9861, 9861, 9861, + 9861, 9861, 9861, 9861, 9861, 9861, 9861, 9861, + 9861, 9861, 9861, 9861, 9861, 9861, 9861, 9861, + 9861, 9861, 9861, 9863, 9864, 9861, 9861, 9861, + 9861, 9861, 9861, 9861, 9865, 9861, 9861, 9861, + 9861, 9866, 9867, 9861, 9869, 9868, 9871, 9870, + 9873, 9872, 9875, 9874, 9877, 9876, 9879, 9878, + 9881, 9880, 9883, 9882, 9882, 9882, 9882, 9882, + 9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882, + 9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882, + 9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882, + 9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882, + 9882, 9882, 9884, 9885, 9882, 9882, 9882, 9886, + 9887, 9882, 9882, 9888, 9882, 9882, 9882, 9882, + 9889, 9890, 9882, 9892, 9891, 9894, 9893, 9896, + 9895, 9898, 9897, 9900, 9899, 9899, 9899, 9899, + 9899, 9899, 9899, 9899, 9899, 9899, 9899, 9899, + 9899, 9899, 9899, 9899, 9899, 9899, 9899, 9899, + 9899, 9899, 9899, 9899, 9899, 9899, 9899, 9899, + 9899, 9899, 9899, 9899, 9899, 9899, 9899, 9899, + 9899, 9899, 9899, 9899, 9899, 9899, 9899, 9899, + 9899, 9901, 9899, 9899, 9899, 9899, 9902, 9899, + 9904, 9903, 9906, 9905, 9908, 9907, 9910, 9909, + 9912, 9911, 9914, 9913, 9916, 9915, 9918, 9917, + 9920, 9919, 9922, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9921, 9921, 9921, 9921, 9921, + 9921, 9921, 9921, 9923, 9921, 9925, 9924, 9927, + 9926, 9929, 9928, 9931, 9930, 9933, 9932, 9935, + 9934, 9937, 9936, 9939, 9938, 9941, 9940, 9943, + 9942, 9945, 9944, 9947, 9946, 9949, 9948, 9948, + 9948, 9948, 9948, 9948, 9948, 9948, 9948, 9948, + 9948, 9948, 9948, 9948, 9948, 9948, 9948, 9948, + 9948, 9948, 9948, 9948, 9948, 9948, 9948, 9948, + 9948, 9948, 9948, 9948, 9948, 9948, 9948, 9948, + 9948, 9948, 9948, 9948, 9950, 9948, 9951, 9948, + 9953, 9952, 9955, 9954, 9957, 9956, 9959, 9958, + 9961, 9960, 9963, 9962, 9965, 9964, 9967, 9966, + 0 +}; + +static const short _char_ref_trans_targs[] = { + 2, 0, 5, 6, 10, 15, 19, 21, + 25, 29, 33, 35, 41, 53, 56, 63, + 67, 3, 4, 7624, 7625, 7, 8, 9, + 7626, 11, 12, 13, 14, 7623, 16, 18, + 17, 7627, 7623, 20, 7623, 22, 23, 24, + 7628, 26, 27, 28, 7623, 30, 31, 32, + 7623, 34, 7623, 36, 39, 37, 38, 7623, + 40, 7623, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 7623, 54, 55, + 7629, 57, 59, 58, 7623, 60, 61, 62, + 7623, 64, 65, 66, 7630, 68, 7631, 70, + 83, 85, 101, 103, 106, 110, 113, 71, + 78, 72, 73, 74, 75, 76, 77, 7623, + 79, 80, 7623, 81, 82, 7623, 84, 7623, + 86, 91, 99, 87, 88, 89, 90, 7623, + 92, 93, 94, 95, 96, 97, 98, 7623, + 100, 7623, 102, 7623, 104, 105, 7623, 107, + 108, 109, 7623, 111, 112, 7623, 114, 115, + 116, 117, 7623, 119, 122, 124, 152, 168, + 171, 184, 186, 188, 210, 256, 320, 324, + 327, 120, 121, 7623, 123, 7632, 125, 129, + 147, 126, 127, 128, 7623, 7623, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 7623, + 148, 149, 150, 151, 7623, 153, 157, 160, + 163, 154, 155, 156, 7623, 158, 159, 7633, + 161, 162, 7623, 164, 165, 166, 167, 7623, + 169, 170, 7623, 172, 177, 173, 174, 175, + 176, 7623, 178, 179, 180, 181, 182, 183, + 7623, 185, 7623, 187, 7623, 189, 190, 191, + 192, 193, 196, 201, 205, 194, 195, 7623, + 197, 198, 199, 200, 7623, 202, 203, 204, + 7623, 206, 207, 208, 209, 7623, 211, 212, + 233, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 7623, 234, 235, + 236, 237, 238, 239, 240, 251, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, + 7623, 252, 253, 254, 255, 7623, 257, 261, + 283, 291, 258, 259, 7623, 260, 7623, 262, + 268, 271, 263, 264, 265, 266, 267, 7623, + 269, 270, 7623, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 7623, 284, + 285, 7623, 286, 287, 288, 289, 290, 7623, + 292, 293, 294, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 7623, 321, 322, 323, + 7623, 325, 326, 7623, 328, 7623, 329, 330, + 331, 7623, 333, 340, 343, 346, 349, 359, + 365, 369, 371, 423, 649, 7623, 334, 335, + 336, 337, 338, 339, 7623, 341, 342, 7623, + 344, 345, 7623, 347, 348, 7623, 350, 354, + 356, 351, 352, 353, 7623, 355, 7623, 357, + 358, 7623, 360, 364, 361, 362, 363, 7623, + 7623, 366, 7623, 367, 368, 7623, 370, 7623, + 372, 412, 373, 408, 374, 375, 376, 377, + 378, 379, 380, 381, 386, 398, 403, 382, + 383, 384, 385, 7623, 387, 388, 389, 7623, + 390, 391, 392, 393, 394, 395, 396, 397, + 7623, 399, 400, 401, 402, 7623, 404, 405, + 406, 407, 7623, 409, 410, 411, 7623, 413, + 414, 415, 416, 417, 418, 419, 420, 421, + 422, 7623, 424, 426, 435, 558, 425, 7623, + 7623, 427, 430, 428, 429, 7623, 431, 432, + 433, 434, 7623, 436, 437, 438, 439, 454, + 464, 518, 531, 547, 440, 441, 442, 443, + 444, 445, 446, 447, 448, 449, 450, 451, + 452, 453, 7623, 455, 456, 457, 7623, 458, + 459, 460, 461, 462, 463, 7623, 465, 486, + 466, 467, 468, 473, 483, 469, 470, 471, + 472, 7623, 474, 475, 476, 477, 478, 479, + 480, 481, 482, 7623, 484, 485, 7623, 487, + 488, 489, 508, 490, 491, 492, 493, 498, + 494, 495, 496, 497, 7623, 499, 500, 501, + 502, 503, 504, 505, 506, 507, 7623, 509, + 510, 511, 512, 513, 514, 515, 516, 517, + 7623, 519, 520, 521, 522, 523, 528, 524, + 525, 526, 527, 7623, 529, 530, 7623, 532, + 533, 538, 534, 535, 536, 537, 7623, 539, + 540, 541, 542, 543, 544, 545, 546, 7623, + 548, 549, 550, 551, 552, 553, 554, 555, + 556, 557, 7623, 559, 560, 575, 580, 613, + 636, 644, 561, 562, 563, 564, 7623, 565, + 568, 566, 567, 7623, 569, 570, 571, 572, + 573, 574, 7623, 576, 577, 578, 579, 7623, + 581, 582, 583, 584, 595, 604, 585, 586, + 587, 588, 589, 590, 591, 592, 593, 594, + 7623, 596, 597, 598, 599, 600, 601, 602, + 603, 7623, 605, 606, 607, 608, 609, 7623, + 610, 611, 612, 7623, 614, 615, 616, 617, + 618, 627, 619, 620, 621, 622, 623, 624, + 625, 626, 7623, 628, 629, 630, 631, 632, + 7623, 633, 634, 635, 7623, 637, 638, 7623, + 639, 640, 641, 642, 643, 7623, 645, 646, + 647, 648, 7623, 650, 652, 651, 7623, 653, + 654, 655, 7623, 657, 659, 660, 664, 672, + 675, 677, 681, 687, 720, 726, 732, 749, + 754, 756, 758, 658, 7623, 7634, 661, 662, + 663, 7635, 665, 669, 671, 666, 667, 668, + 7623, 670, 7636, 7623, 673, 674, 7623, 676, + 7623, 678, 679, 680, 7637, 682, 683, 684, + 685, 686, 7623, 688, 691, 689, 690, 7623, + 692, 693, 694, 705, 695, 696, 697, 698, + 699, 700, 701, 702, 703, 704, 7623, 706, + 707, 708, 709, 710, 711, 712, 713, 714, + 715, 716, 717, 718, 719, 7623, 721, 724, + 722, 723, 7623, 725, 7623, 727, 728, 729, + 730, 731, 7623, 733, 734, 741, 735, 7623, + 736, 737, 738, 739, 740, 7623, 742, 743, + 744, 745, 746, 747, 748, 7623, 750, 752, + 751, 7623, 753, 7623, 755, 7623, 757, 7638, + 759, 763, 760, 761, 762, 7623, 764, 765, + 766, 767, 768, 769, 770, 771, 772, 7623, + 774, 776, 778, 809, 824, 775, 7623, 777, + 7623, 779, 780, 781, 782, 783, 794, 784, + 785, 786, 787, 788, 789, 790, 791, 792, + 793, 7623, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, + 7623, 810, 812, 816, 811, 7623, 813, 814, + 815, 7623, 817, 818, 819, 820, 821, 822, + 823, 7623, 825, 826, 7623, 828, 7639, 831, + 836, 841, 850, 853, 855, 856, 859, 909, + 912, 829, 830, 7623, 832, 833, 834, 7623, + 835, 7623, 837, 838, 839, 840, 7623, 842, + 846, 849, 843, 844, 845, 7623, 847, 848, + 7623, 7623, 851, 852, 7623, 854, 7623, 7623, + 857, 858, 7623, 860, 861, 862, 863, 864, + 865, 874, 883, 890, 894, 904, 866, 867, + 868, 869, 7623, 870, 871, 872, 873, 7623, + 875, 876, 877, 878, 879, 880, 881, 882, + 7623, 884, 885, 886, 887, 888, 889, 7623, + 891, 892, 893, 7623, 895, 896, 897, 898, + 899, 900, 901, 902, 903, 7623, 905, 906, + 907, 908, 7623, 910, 911, 7623, 7623, 914, + 919, 924, 928, 930, 941, 956, 963, 915, + 916, 917, 918, 7623, 920, 923, 921, 922, + 7623, 7623, 925, 926, 927, 7623, 929, 7623, + 931, 932, 933, 934, 935, 936, 937, 938, + 939, 940, 7623, 942, 944, 943, 7623, 945, + 946, 947, 948, 949, 950, 951, 952, 953, + 954, 955, 7623, 957, 959, 958, 7623, 960, + 961, 962, 7623, 964, 965, 966, 974, 967, + 968, 969, 970, 971, 972, 973, 7623, 975, + 976, 977, 978, 7623, 980, 983, 987, 990, + 994, 998, 1001, 1003, 1007, 1023, 1055, 1063, + 1066, 1071, 981, 982, 7623, 984, 985, 986, + 7623, 988, 989, 7623, 991, 992, 993, 7640, + 995, 997, 996, 7641, 7623, 999, 1000, 7623, + 1002, 7623, 1004, 1005, 1006, 7642, 7623, 1008, + 1018, 1009, 1011, 1010, 7623, 1012, 1013, 1014, + 1015, 1016, 1017, 7623, 1019, 1020, 1021, 1022, + 7623, 1024, 1038, 7623, 1025, 1026, 1030, 1027, + 1028, 1029, 7623, 1031, 1032, 1033, 1034, 1035, + 1036, 1037, 7623, 1039, 1040, 1041, 1042, 1043, + 1044, 1045, 1050, 1046, 1047, 1048, 1049, 7623, + 1051, 1052, 1053, 1054, 7623, 1056, 1059, 1061, + 1057, 1058, 7623, 1060, 7623, 1062, 7623, 1064, + 1065, 7623, 1067, 1068, 1069, 1070, 7623, 1072, + 1075, 1073, 1074, 7623, 7643, 1077, 1082, 1084, + 1087, 1094, 1078, 1081, 1079, 1080, 7623, 7623, + 1083, 7623, 1085, 1086, 7623, 1088, 1090, 1089, + 7623, 1091, 1092, 1093, 7623, 1095, 1096, 1097, + 7623, 1099, 1102, 1105, 1109, 1115, 1117, 1120, + 1100, 1101, 7623, 1103, 1104, 7623, 1106, 1107, + 1108, 7623, 1110, 1114, 1111, 1112, 1113, 7623, + 7623, 1116, 7623, 1118, 1119, 7623, 1121, 1122, + 7623, 1124, 7644, 1127, 1148, 1158, 1383, 1385, + 1394, 1399, 1484, 1492, 1125, 1126, 7623, 1128, + 1132, 1136, 1138, 1146, 1129, 1130, 1131, 7623, + 1133, 1134, 1135, 7623, 1137, 7623, 1139, 1140, + 1141, 1142, 1143, 1144, 1145, 7623, 1147, 7623, + 1149, 1153, 1157, 1150, 1151, 1152, 7623, 1154, + 1155, 1156, 7623, 7623, 1159, 1334, 1160, 1161, + 1190, 1197, 1230, 1235, 1251, 1280, 1310, 1319, + 1324, 1162, 1173, 1163, 1164, 1165, 1166, 1167, + 1168, 1169, 1170, 1171, 1172, 7623, 1174, 1175, + 1176, 7623, 1177, 1180, 1178, 1179, 7623, 1181, + 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, + 7623, 1191, 1192, 1193, 1194, 1195, 1196, 7623, + 1198, 1199, 1210, 1200, 1201, 1202, 1203, 1204, + 1205, 1206, 1207, 1208, 1209, 7623, 1211, 1212, + 1221, 1213, 1214, 1215, 1216, 1217, 1218, 1219, + 1220, 7623, 1222, 1223, 1224, 1225, 1226, 7623, + 1227, 1228, 1229, 7623, 1231, 1232, 1233, 1234, + 7623, 1236, 1237, 1238, 1239, 1240, 1245, 1241, + 1242, 1243, 1244, 7623, 1246, 1247, 1248, 1249, + 1250, 7623, 1252, 1265, 1253, 7623, 1254, 1259, + 1255, 1256, 1257, 1258, 7623, 1260, 1261, 1262, + 1263, 1264, 7623, 1266, 1267, 1268, 1269, 1270, + 1271, 7623, 1272, 1275, 1273, 1274, 7623, 1276, + 1277, 1278, 1279, 7623, 1281, 1282, 1292, 1301, + 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, + 1291, 7623, 1293, 1294, 1295, 1296, 1297, 1298, + 1299, 1300, 7623, 1302, 1303, 1304, 1305, 1306, + 7623, 1307, 1308, 1309, 7623, 1311, 1312, 1313, + 1314, 1315, 7623, 1316, 1317, 1318, 7623, 1320, + 1321, 1322, 1323, 7623, 1325, 1326, 1327, 1328, + 1329, 1330, 1331, 1332, 1333, 7623, 1335, 1336, + 1348, 1357, 1364, 1368, 1378, 1337, 1338, 1339, + 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, + 7623, 1349, 1350, 1351, 1352, 1353, 1354, 1355, + 1356, 7623, 1358, 1359, 1360, 1361, 1362, 1363, + 7623, 1365, 1366, 1367, 7623, 1369, 1370, 1371, + 1372, 1373, 1374, 1375, 1376, 1377, 7623, 1379, + 1380, 1381, 1382, 7623, 1384, 7623, 7623, 1386, + 1387, 1388, 1389, 1390, 1391, 1392, 1393, 7623, + 1395, 1396, 1397, 1398, 7623, 1400, 1460, 1462, + 1401, 1402, 1421, 1431, 1450, 1403, 1404, 1405, + 1406, 1411, 1407, 1408, 1409, 1410, 7623, 1412, + 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, + 7623, 1422, 1423, 1424, 1425, 1426, 1427, 1428, + 1429, 1430, 7623, 1432, 1433, 1434, 1435, 1440, + 1436, 1437, 1438, 1439, 7623, 1441, 1442, 1443, + 1444, 1445, 1446, 1447, 1448, 1449, 7623, 1451, + 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, + 7623, 1461, 7623, 1463, 1464, 1465, 1474, 1466, + 1467, 1468, 1469, 1470, 1471, 1472, 1473, 7623, + 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, + 1483, 7623, 1485, 1487, 1488, 1486, 7623, 7623, + 1489, 1490, 1491, 7623, 7623, 1494, 1496, 1498, + 1515, 1517, 1525, 1528, 1531, 1495, 7623, 1497, + 7623, 1499, 1508, 1500, 1501, 1502, 1503, 1504, + 1505, 1506, 1507, 7623, 1509, 1510, 1511, 1512, + 1513, 1514, 7623, 1516, 7623, 1518, 1519, 1520, + 1521, 1522, 1523, 1524, 7623, 1526, 1527, 7623, + 1529, 1530, 7623, 7623, 1533, 1536, 1541, 1551, + 1629, 1631, 2018, 2021, 2025, 1534, 1535, 7623, + 1537, 1538, 1539, 1540, 7623, 1542, 1546, 1550, + 1543, 1544, 1545, 7623, 1547, 1548, 1549, 7623, + 7623, 1552, 1598, 1624, 1553, 1554, 1555, 1556, + 1557, 1558, 1569, 1585, 1559, 1560, 1561, 1562, + 1563, 1564, 1565, 1566, 1567, 1568, 7623, 1570, + 1571, 1572, 1579, 1573, 1574, 1575, 1576, 1577, + 1578, 7623, 1580, 1581, 1582, 1583, 1584, 7623, + 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 7623, 1599, 1600, 1601, + 1602, 1616, 1603, 1604, 1605, 1606, 1607, 1608, + 1609, 1610, 1611, 1612, 1613, 1614, 1615, 7623, + 1617, 1618, 1619, 1620, 1621, 1622, 1623, 7623, + 1625, 1626, 1627, 1628, 7623, 1630, 7623, 1632, + 1637, 1651, 1653, 1633, 1634, 1635, 1636, 7623, + 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, + 1646, 1647, 1648, 1649, 1650, 7623, 1652, 7623, + 7623, 1654, 1668, 1685, 1706, 1753, 1770, 1823, + 1851, 1874, 1908, 1983, 2007, 1655, 1663, 1656, + 1657, 1658, 1659, 1660, 1661, 1662, 7623, 1664, + 1665, 1666, 1667, 7623, 1669, 1670, 1671, 1672, + 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, + 1681, 1682, 1683, 1684, 7623, 1686, 1692, 1701, + 1687, 1688, 1689, 1690, 1691, 7623, 1693, 1694, + 1695, 7623, 1696, 1697, 1698, 1699, 1700, 7623, + 1702, 1703, 1704, 1705, 7623, 1707, 1708, 1709, + 1710, 1711, 1712, 7623, 1713, 1718, 1727, 1734, + 1738, 1748, 1714, 1715, 1716, 1717, 7623, 1719, + 1720, 1721, 1722, 1723, 1724, 1725, 1726, 7623, + 1728, 1729, 1730, 1731, 1732, 1733, 7623, 1735, + 1736, 1737, 7623, 1739, 1740, 1741, 1742, 1743, + 1744, 1745, 1746, 1747, 7623, 1749, 1750, 1751, + 1752, 7623, 1754, 1755, 1756, 1757, 1765, 1758, + 1759, 1760, 1761, 1762, 1763, 1764, 7623, 1766, + 1767, 1768, 1769, 7623, 1771, 1772, 1790, 1773, + 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, + 7623, 1782, 1785, 1783, 1784, 7623, 1786, 1787, + 1788, 1789, 7623, 1791, 7623, 1792, 1797, 1804, + 1808, 1818, 1793, 1794, 1795, 1796, 7623, 1798, + 1799, 1800, 1801, 1802, 1803, 7623, 1805, 1806, + 1807, 7623, 1809, 1810, 1811, 1812, 1813, 1814, + 1815, 1816, 1817, 7623, 1819, 1820, 1821, 1822, + 7623, 1824, 1825, 1826, 1827, 1828, 1829, 1843, + 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, + 1838, 1839, 1840, 1841, 1842, 7623, 1844, 1845, + 1846, 1847, 1848, 1849, 1850, 7623, 1852, 1853, + 1854, 1855, 1856, 1857, 1858, 7623, 1859, 1864, + 1860, 1861, 1862, 1863, 7623, 1865, 1866, 1867, + 1868, 1869, 1870, 1871, 1872, 1873, 7623, 1875, + 1888, 1876, 1877, 1878, 1879, 1880, 1881, 1882, + 1883, 1884, 1885, 1886, 1887, 7623, 1889, 1890, + 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, + 1899, 7623, 1900, 1903, 1901, 1902, 7623, 1904, + 1905, 1906, 1907, 7623, 1909, 1936, 1910, 1911, + 1912, 1913, 1914, 1915, 1916, 1925, 1917, 1918, + 1919, 7623, 1920, 1921, 1922, 1923, 1924, 7623, + 1926, 1927, 1928, 1929, 1930, 7623, 1931, 1932, + 1933, 1934, 1935, 7623, 1937, 1946, 1972, 1938, + 1939, 1940, 7623, 1941, 1942, 1943, 1944, 1945, + 7623, 1947, 1948, 1949, 1950, 1951, 7623, 1952, + 1957, 1967, 1953, 1954, 1955, 1956, 7623, 1958, + 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, + 7623, 1968, 1969, 1970, 1971, 7623, 1973, 1974, + 1975, 1976, 1977, 7623, 1978, 1979, 1980, 1981, + 1982, 7623, 1984, 1985, 1986, 1987, 7623, 1988, + 1993, 2002, 1989, 1990, 1991, 1992, 7623, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 7623, + 2003, 2004, 2005, 2006, 7623, 2008, 2009, 2010, + 2011, 2012, 2013, 2014, 2015, 2016, 2017, 7623, + 2019, 2020, 7623, 2022, 2023, 2024, 7645, 7623, + 2027, 2031, 2035, 2039, 2044, 2046, 2050, 2062, + 2065, 2089, 2090, 2096, 2103, 2105, 2028, 2029, + 2030, 7623, 2032, 2033, 2034, 7646, 2036, 2038, + 2037, 7647, 7623, 2040, 2041, 2042, 2043, 7623, + 2045, 7623, 2047, 2048, 2049, 7648, 2051, 2054, + 2057, 2052, 2053, 7623, 2055, 2056, 7623, 2058, + 2059, 2060, 2061, 7623, 2063, 2064, 7623, 2066, + 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2084, + 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, + 2082, 2083, 7623, 2085, 2086, 2087, 2088, 7623, + 7623, 2091, 2093, 2092, 7623, 2094, 2095, 7649, + 2097, 2098, 2100, 2099, 7650, 2101, 2102, 7623, + 2104, 7651, 2106, 2107, 2108, 2118, 2109, 2111, + 2110, 7623, 2112, 2113, 2114, 2115, 7623, 2116, + 2117, 7623, 2119, 2120, 2121, 2122, 2123, 2124, + 2125, 2126, 2127, 2128, 7623, 2130, 2137, 2139, + 2141, 2143, 2144, 2152, 2166, 2210, 2131, 2132, + 2133, 2134, 2135, 2136, 7623, 2138, 7623, 2140, + 7623, 2142, 7623, 7623, 2145, 2146, 2147, 2148, + 2149, 2150, 2151, 7623, 2153, 2164, 2154, 2155, + 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, + 7623, 2165, 7623, 7623, 2167, 2193, 2196, 2168, + 2169, 2170, 2171, 2172, 7623, 2173, 2178, 2188, + 2174, 2175, 2176, 2177, 7623, 2179, 2180, 2181, + 2182, 2183, 2184, 2185, 2186, 2187, 7623, 2189, + 2190, 2191, 2192, 7623, 2194, 2195, 7623, 2197, + 2201, 2198, 2199, 2200, 7623, 2202, 2203, 2204, + 2205, 2206, 2207, 7623, 2208, 2209, 7623, 2211, + 2213, 2212, 7623, 7623, 2215, 2217, 2219, 2222, + 2216, 7652, 2218, 7623, 2220, 2221, 7623, 2223, + 2224, 7623, 2226, 2230, 2231, 2242, 2252, 2288, + 2290, 2292, 2442, 2455, 2465, 2469, 2227, 2228, + 2229, 7623, 7653, 2232, 2236, 2238, 2233, 2234, + 2235, 7623, 2237, 7623, 2239, 7623, 2240, 2241, + 7623, 2243, 2247, 2251, 2244, 2245, 2246, 7623, + 2248, 2249, 2250, 7623, 7623, 7623, 2253, 2254, + 2255, 2256, 2257, 2258, 2275, 2259, 2265, 2260, + 2261, 2262, 2263, 2264, 7623, 2266, 2267, 2268, + 2269, 2270, 2271, 2272, 2273, 2274, 7623, 2276, + 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, + 2285, 2286, 2287, 7623, 2289, 7623, 2291, 7623, + 2293, 2294, 2295, 2296, 2324, 2331, 2364, 2369, + 2398, 2428, 2437, 2297, 2308, 2298, 2299, 2300, + 2301, 2302, 2303, 2304, 2305, 2306, 2307, 7623, + 2309, 2310, 2311, 7623, 2312, 2315, 2313, 2314, + 7623, 2316, 2317, 2318, 2319, 2320, 2321, 2322, + 2323, 7623, 2325, 2326, 2327, 2328, 2329, 2330, + 7623, 2332, 2333, 2344, 2334, 2335, 2336, 2337, + 2338, 2339, 2340, 2341, 2342, 2343, 7623, 2345, + 2346, 2355, 2347, 2348, 2349, 2350, 2351, 2352, + 2353, 2354, 7623, 2356, 2357, 2358, 2359, 2360, + 7623, 2361, 2362, 2363, 7623, 2365, 2366, 2367, + 2368, 7623, 2370, 2383, 2371, 7623, 2372, 2377, + 2373, 2374, 2375, 2376, 7623, 2378, 2379, 2380, + 2381, 2382, 7623, 2384, 2385, 2386, 2387, 2388, + 2389, 7623, 2390, 2393, 2391, 2392, 7623, 2394, + 2395, 2396, 2397, 7623, 2399, 2400, 2410, 2419, + 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, + 2409, 7623, 2411, 2412, 2413, 2414, 2415, 2416, + 2417, 2418, 7623, 2420, 2421, 2422, 2423, 2424, + 7623, 2425, 2426, 2427, 7623, 2429, 2430, 2431, + 2432, 2433, 7623, 2434, 2435, 2436, 7623, 2438, + 2439, 2440, 2441, 7623, 2443, 2445, 2444, 7623, + 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, + 2454, 7623, 2456, 2457, 2458, 2459, 2460, 2461, + 2462, 2463, 2464, 7623, 2466, 2468, 2467, 7623, + 7623, 2470, 2471, 2472, 2473, 2474, 2475, 2476, + 2477, 2478, 7623, 2480, 2487, 2492, 2497, 2510, + 2512, 2551, 2555, 2565, 2568, 2614, 2617, 2620, + 2481, 2485, 2482, 2483, 2484, 7623, 2486, 7623, + 2488, 2489, 2490, 2491, 7623, 2493, 2494, 2495, + 2496, 7623, 7623, 2498, 2502, 2506, 2509, 2499, + 2500, 2501, 7623, 2503, 2504, 2505, 7623, 2507, + 2508, 7623, 7623, 2511, 7623, 2513, 2514, 2515, + 2516, 2525, 2534, 2544, 2517, 2518, 2519, 2520, + 2521, 2522, 2523, 2524, 7623, 2526, 2527, 2528, + 2529, 2530, 2531, 2532, 2533, 7623, 2535, 2536, + 2537, 2538, 2539, 2540, 2541, 2542, 2543, 7623, + 2545, 2546, 2547, 2548, 2549, 2550, 7623, 2552, + 2553, 2554, 7623, 2556, 2557, 2558, 2559, 2560, + 2561, 2562, 2563, 2564, 7623, 2566, 2567, 7623, + 2569, 2571, 2570, 7623, 2572, 2573, 2574, 7623, + 2575, 2587, 2609, 2576, 2577, 2578, 2579, 2580, + 2581, 2582, 2583, 2584, 2585, 2586, 7623, 2588, + 2589, 2598, 2590, 2591, 2592, 7623, 2593, 2594, + 2595, 2596, 2597, 7623, 2599, 2600, 2601, 2602, + 2603, 7623, 2604, 2605, 2606, 2607, 2608, 7623, + 2610, 2611, 2612, 2613, 7623, 2615, 2616, 7623, + 2618, 2619, 7623, 2621, 2630, 2661, 2662, 7623, + 2622, 2623, 2624, 7623, 2625, 2626, 2627, 2628, + 2629, 7623, 2631, 2656, 2632, 2633, 2634, 2635, + 7623, 2636, 2641, 2651, 2637, 2638, 2639, 2640, + 7623, 2642, 2643, 2644, 2645, 2646, 2647, 2648, + 2649, 2650, 7623, 2652, 2653, 2654, 2655, 7623, + 2657, 2658, 2659, 2660, 7623, 7623, 7623, 2663, + 2673, 2664, 2665, 2666, 2667, 7623, 2668, 2669, + 2670, 2671, 2672, 7623, 2674, 2675, 7623, 2677, + 2680, 2684, 2690, 2693, 2703, 2705, 2729, 2752, + 2755, 2763, 2678, 2679, 7654, 2681, 2682, 2683, + 7623, 2685, 2688, 2686, 2687, 7623, 2689, 7623, + 2691, 2692, 7623, 7623, 2694, 2698, 2702, 2695, + 2696, 2697, 7623, 2699, 2700, 2701, 7623, 7623, + 2704, 7623, 2706, 2715, 2707, 2713, 2708, 2709, + 2710, 2711, 2712, 7623, 2714, 7623, 2716, 2723, + 2717, 2718, 2719, 2720, 2721, 2722, 7623, 2724, + 2725, 2726, 2727, 2728, 7623, 2730, 2731, 2732, + 7623, 2733, 2738, 2747, 2734, 2735, 2736, 2737, + 7623, 2739, 2740, 2741, 2742, 2743, 2744, 2745, + 2746, 7623, 2748, 2749, 2750, 2751, 7623, 2753, + 2754, 7623, 2756, 2757, 2758, 2759, 2760, 2761, + 2762, 7623, 2764, 2766, 2765, 7623, 2767, 2768, + 2769, 7623, 2771, 2781, 2788, 2792, 2797, 2799, + 2803, 2807, 2839, 2845, 2932, 2936, 2939, 2944, + 2772, 2775, 2773, 2774, 7655, 2776, 7623, 2777, + 2778, 2779, 2780, 7623, 2782, 2783, 2785, 2784, + 7623, 2786, 2787, 7623, 2789, 2791, 2790, 7656, + 7623, 2793, 2794, 2795, 2796, 7623, 2798, 7623, + 2800, 2801, 2802, 7657, 2804, 2805, 2806, 7623, + 2808, 2832, 2809, 2810, 2811, 2821, 2812, 2814, + 2813, 7623, 2815, 2816, 2817, 2818, 7623, 2819, + 2820, 7623, 2822, 2823, 2824, 2825, 2826, 2827, + 2828, 2829, 2830, 2831, 7623, 2833, 2834, 7623, + 2835, 2836, 2837, 2838, 7623, 2840, 2843, 2841, + 2842, 7623, 2844, 7623, 2846, 2863, 2872, 2883, + 2891, 2896, 2905, 2927, 2847, 2848, 2849, 2850, + 7623, 2851, 2854, 2852, 2853, 7623, 2855, 2856, + 2857, 2858, 2859, 2860, 2861, 2862, 7623, 2864, + 2865, 2866, 2867, 2868, 2869, 2870, 2871, 7623, + 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, + 2881, 2882, 7623, 2884, 2885, 7623, 2886, 2887, + 2888, 2889, 2890, 7623, 2892, 2893, 2894, 2895, + 7623, 2897, 2898, 2899, 2900, 2901, 2902, 2903, + 2904, 7623, 2906, 2907, 2908, 2917, 2909, 2910, + 2911, 2912, 2913, 2914, 2915, 2916, 7623, 2918, + 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, + 7623, 2928, 7623, 2929, 2930, 2931, 7623, 2933, + 2934, 2935, 7623, 2937, 2938, 7623, 2940, 2941, + 2942, 2943, 7623, 2945, 7658, 2947, 2951, 2954, + 2956, 2961, 3003, 3005, 3008, 3011, 2948, 2949, + 2950, 7623, 2952, 2953, 7623, 2955, 7623, 2957, + 2958, 2959, 7623, 2960, 7623, 2962, 2963, 7623, + 2964, 2967, 2993, 2965, 2966, 7623, 7623, 2968, + 2969, 2970, 2971, 2972, 2975, 2979, 2988, 2973, + 2974, 7623, 2976, 2977, 2978, 7623, 2980, 2981, + 2982, 2983, 2984, 2985, 2986, 2987, 7623, 2989, + 2990, 2991, 2992, 7623, 2994, 2995, 2996, 2997, + 2998, 2999, 3000, 3001, 3002, 7623, 3004, 7623, + 3006, 3007, 7623, 3009, 3010, 7623, 3012, 3013, + 3014, 3015, 7623, 3017, 3021, 3025, 3027, 3030, + 3018, 3019, 3020, 7623, 3022, 3023, 3024, 7623, + 3026, 7623, 3028, 3029, 7623, 3031, 3032, 7623, + 3034, 3036, 3037, 3040, 3035, 7623, 7623, 3038, + 3039, 7623, 3041, 3042, 7623, 3044, 3047, 3050, + 3053, 3057, 3062, 3064, 3067, 3070, 3045, 3046, + 7623, 3048, 3049, 7623, 3051, 3052, 7623, 3054, + 3055, 3056, 7659, 3058, 3061, 3059, 3060, 7623, + 7623, 3063, 7623, 3065, 3066, 7623, 3068, 3069, + 7623, 3071, 3072, 7623, 3074, 3077, 3082, 3088, + 3091, 3106, 3108, 3111, 3075, 3076, 7623, 3078, + 3079, 3080, 3081, 7623, 3083, 3087, 3084, 3085, + 3086, 7623, 7623, 3089, 3090, 7623, 3092, 3104, + 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, + 3101, 3102, 3103, 7623, 3105, 7623, 3107, 7623, + 3109, 3110, 7623, 3112, 3113, 7623, 3115, 3119, + 3124, 3132, 3135, 3137, 3141, 3152, 3158, 3199, + 3205, 3222, 3225, 3234, 3238, 3240, 3116, 3117, + 3118, 7660, 3120, 3121, 3122, 3123, 7623, 7623, + 3125, 3126, 3127, 3129, 3131, 7623, 7623, 3128, + 7661, 3130, 7662, 7623, 3133, 3134, 7663, 7623, + 3136, 7623, 3138, 3139, 3140, 7664, 3142, 3149, + 3143, 3147, 3144, 3145, 3146, 7623, 3148, 7623, + 3150, 3151, 7623, 3153, 7665, 3154, 3156, 3155, + 7623, 3157, 7623, 3159, 3170, 7623, 3160, 3163, + 3164, 3169, 3161, 3162, 7623, 7623, 3165, 3166, + 3167, 3168, 7623, 7623, 7623, 3171, 3172, 3174, + 3186, 3191, 3195, 7623, 3173, 7623, 3175, 3176, + 7623, 3177, 3178, 3179, 3180, 3181, 3182, 3183, + 3184, 3185, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 3187, 7623, 3188, 3189, 7623, 3190, + 7623, 3192, 3194, 3193, 7623, 7623, 3196, 3197, + 3198, 7623, 3200, 3203, 3201, 3202, 7623, 3204, + 7623, 7623, 3206, 3207, 3211, 3212, 3214, 3216, + 7623, 3208, 3209, 3210, 7623, 7623, 3213, 7623, + 3215, 7623, 3217, 3218, 3219, 7623, 3220, 3221, + 7623, 3223, 3224, 7666, 3226, 3228, 3229, 3227, + 7623, 7623, 3230, 3231, 7623, 3232, 3233, 7623, + 3235, 3236, 3237, 7667, 3239, 7668, 3241, 3247, + 3242, 3243, 3244, 3245, 3246, 7623, 3248, 3249, + 7623, 3251, 3254, 3287, 3294, 3299, 3303, 3328, + 3330, 3388, 3393, 3442, 3450, 3523, 3528, 3535, + 3551, 3252, 3253, 7623, 3255, 3278, 3256, 3257, + 3261, 3268, 3273, 3258, 3259, 3260, 7623, 3262, + 3263, 3264, 3265, 3266, 3267, 7623, 3269, 3270, + 3271, 3272, 7623, 3274, 3275, 7623, 3276, 3277, + 7623, 3279, 3282, 3280, 3281, 7623, 3283, 3284, + 7623, 3285, 3286, 7623, 3288, 3289, 7623, 3290, + 3291, 3292, 3293, 7623, 3295, 3298, 3296, 3297, + 7623, 7623, 3300, 3301, 3302, 7623, 3304, 3309, + 3314, 3317, 3321, 3305, 3306, 3307, 7623, 3308, + 7623, 3310, 3311, 3312, 3313, 7623, 3315, 3316, + 7623, 3318, 3319, 3320, 7623, 3322, 3323, 3324, + 7623, 7623, 3325, 3326, 3327, 7623, 3329, 7623, + 3331, 3332, 3340, 3353, 3361, 3375, 3380, 3383, + 3333, 3335, 3338, 3334, 7623, 3336, 3337, 7623, + 3339, 7623, 3341, 3344, 3348, 3342, 3343, 7623, + 3345, 3346, 3347, 7623, 3349, 3350, 3351, 3352, + 7623, 3354, 3358, 3355, 3356, 3357, 7623, 3359, + 3360, 7623, 3362, 3363, 3364, 3365, 3366, 3367, + 3368, 3369, 3373, 3370, 3371, 3372, 7623, 3374, + 7623, 3376, 3377, 3378, 3379, 7623, 3381, 3382, + 7623, 3384, 3385, 3386, 3387, 7623, 3389, 3390, + 3391, 3392, 7623, 3394, 3433, 3439, 3395, 3431, + 3396, 3397, 3404, 3410, 3398, 3399, 3400, 3401, + 3402, 3403, 7623, 3405, 3406, 3407, 3408, 3409, + 7623, 3411, 3412, 3413, 3414, 3415, 3416, 3417, + 7623, 3418, 3422, 3426, 3419, 3420, 3421, 7623, + 3423, 3424, 3425, 7623, 3427, 3428, 3429, 3430, + 7623, 3432, 7623, 3434, 3437, 3435, 3436, 7623, + 7623, 3438, 7623, 3440, 3441, 7623, 3443, 3448, + 7623, 3444, 3445, 3446, 3447, 7623, 3449, 7623, + 3451, 3453, 3457, 3461, 3452, 7623, 7623, 3454, + 3455, 3456, 7623, 3458, 3459, 3460, 7623, 3462, + 3467, 3472, 3477, 3484, 3487, 3492, 3497, 3502, + 3506, 3511, 3516, 3463, 3464, 3465, 3466, 7623, + 7623, 7623, 7623, 7623, 3468, 3469, 3470, 3471, + 7623, 7623, 7623, 7623, 3473, 3474, 3475, 3476, + 7623, 7623, 7623, 7623, 7623, 3478, 3479, 3480, + 3481, 3482, 3483, 7623, 7623, 7623, 7623, 7623, + 7623, 3485, 3486, 7623, 3488, 3489, 3490, 3491, + 7623, 7623, 7623, 7623, 7623, 3493, 3494, 3495, + 3496, 7623, 7623, 7623, 7623, 3498, 3499, 3500, + 3501, 7623, 3503, 3504, 3505, 7623, 3507, 3508, + 3509, 3510, 7623, 3512, 3513, 3514, 3515, 7623, + 7623, 7623, 7623, 7623, 3517, 3518, 3519, 3520, + 3521, 3522, 7623, 7623, 7623, 7623, 7623, 7623, + 3524, 3525, 3526, 3527, 7623, 3529, 3532, 3530, + 3531, 7623, 3533, 3534, 7669, 3536, 3538, 3541, + 3544, 3537, 7623, 3539, 3540, 7623, 3542, 7623, + 3543, 7623, 3545, 7623, 3546, 3547, 7623, 3548, + 3549, 3550, 7623, 3552, 3556, 3553, 7623, 3554, + 3555, 7623, 3557, 7623, 3558, 3559, 7623, 7623, + 3560, 7623, 3562, 3590, 3608, 3611, 3625, 3627, + 3638, 3687, 3694, 3731, 3738, 3746, 3750, 3833, + 3843, 3563, 3567, 3585, 3564, 3565, 3566, 7623, + 7623, 3568, 3571, 3576, 3581, 3584, 3569, 3570, + 7623, 3572, 3573, 3574, 3575, 7623, 3577, 3579, + 3578, 7623, 3580, 7623, 3582, 3583, 7623, 7623, + 3586, 3588, 3587, 7623, 3589, 7623, 3591, 3597, + 3600, 3603, 3592, 3594, 3593, 7623, 3595, 3596, + 7623, 3598, 3599, 7670, 3601, 3602, 7623, 3604, + 3605, 7623, 3606, 3607, 7623, 3609, 3610, 7623, + 3612, 3614, 3619, 3613, 7671, 3615, 3616, 3617, + 3618, 7623, 7672, 7623, 3621, 3622, 3623, 3624, + 7623, 3626, 7623, 3628, 3630, 3637, 3629, 7623, + 3631, 3632, 7623, 3633, 3634, 3635, 3636, 7623, + 7623, 3639, 7623, 3640, 3641, 3674, 3675, 3680, + 3683, 7623, 7623, 3642, 3644, 3643, 7623, 3645, + 3646, 3660, 3647, 3648, 3649, 3650, 3651, 3655, + 3652, 3653, 3654, 7623, 3656, 3657, 3658, 3659, + 7623, 3661, 3662, 3663, 3666, 3670, 7623, 7623, + 3664, 3665, 7623, 3667, 3668, 3669, 7623, 3671, + 3672, 3673, 7623, 7623, 3676, 3677, 3678, 3679, + 7623, 3681, 3682, 7623, 3684, 3685, 3686, 7623, + 3688, 3689, 3690, 7623, 3691, 3692, 3693, 7623, + 3695, 3700, 3716, 3724, 3696, 3697, 7623, 3698, + 7623, 3699, 7623, 3701, 3704, 3702, 7623, 3703, + 7623, 7623, 3705, 3707, 3706, 7623, 3708, 3709, + 3713, 3710, 3711, 3712, 7623, 3714, 3715, 7623, + 3717, 3721, 7623, 3718, 3719, 3720, 7623, 3722, + 3723, 7623, 3725, 3726, 7673, 7623, 3727, 3728, + 7623, 7623, 3730, 7623, 3732, 3735, 3733, 3734, + 7623, 3736, 3737, 7623, 3739, 3741, 3740, 7623, + 3742, 3744, 7623, 3743, 7623, 7623, 3745, 7623, + 3747, 3748, 3749, 7623, 3751, 3757, 3762, 3767, + 3784, 3827, 3830, 3752, 3753, 3754, 3755, 3756, + 7623, 7623, 3758, 3760, 3759, 7623, 3761, 7623, + 3763, 3764, 3765, 7623, 3766, 7623, 7623, 3768, + 3773, 3778, 3781, 3783, 3769, 3770, 3771, 3772, + 7623, 3774, 3776, 3775, 7623, 3777, 7623, 3779, + 3780, 7623, 3782, 7623, 7623, 3785, 3789, 3809, + 3811, 3786, 3787, 7623, 3788, 7623, 3790, 3791, + 3801, 3804, 3792, 3793, 3797, 3794, 3795, 3796, + 7623, 3798, 3799, 3800, 7623, 3802, 3803, 7623, + 3805, 3806, 3807, 3808, 7623, 3810, 7674, 3812, + 3813, 3814, 3815, 3816, 3817, 3818, 3822, 3819, + 3820, 3821, 7623, 3823, 3824, 3825, 3826, 7623, + 3828, 3829, 7623, 3831, 3832, 7623, 3834, 3840, + 3835, 3836, 3837, 3838, 3839, 7623, 3841, 3842, + 7623, 3844, 3845, 3846, 3847, 7623, 3849, 3852, + 3855, 3869, 3878, 3884, 3897, 3906, 3912, 3917, + 3950, 3953, 3961, 4034, 4048, 4058, 4065, 4072, + 4078, 3850, 3851, 7623, 3853, 3854, 7623, 3856, + 3860, 3864, 3866, 3857, 3858, 3859, 7623, 3861, + 3862, 3863, 7623, 3865, 7623, 3867, 7623, 3868, + 7623, 3870, 3875, 3871, 3872, 3873, 3874, 7623, + 3876, 3877, 7623, 3879, 3883, 3880, 3881, 3882, + 7623, 7623, 7623, 3885, 3892, 3886, 3890, 3887, + 3888, 3889, 7623, 3891, 7623, 3893, 3894, 3895, + 3896, 7623, 7675, 3898, 3901, 3899, 3900, 7623, + 3902, 3903, 3904, 3905, 7623, 3907, 3911, 3908, + 3909, 3910, 7623, 7623, 3913, 3914, 3915, 3916, + 7623, 7623, 3918, 3928, 3929, 3934, 3937, 3919, + 7623, 3920, 3927, 3921, 3922, 7623, 3923, 3924, + 3925, 3926, 7623, 7623, 7623, 3930, 3931, 3932, + 3933, 7623, 3935, 3936, 7623, 7623, 3938, 3947, + 3939, 7676, 7623, 3941, 3942, 3943, 3944, 3945, + 3946, 7623, 3948, 3949, 7623, 3951, 3952, 7623, + 3954, 3955, 3958, 3956, 3957, 7623, 3959, 3960, + 7623, 3962, 3966, 3968, 3989, 4001, 3963, 3964, + 3965, 7623, 3967, 7623, 7623, 3969, 3974, 3979, + 3983, 3970, 7623, 3971, 3972, 3973, 7623, 3975, + 3976, 3977, 3978, 7623, 3980, 3981, 3982, 7623, + 3984, 3985, 3986, 3987, 3988, 7623, 3990, 3991, + 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, + 4000, 7623, 4002, 4003, 4008, 4018, 4004, 4005, + 4006, 4007, 7623, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 7623, 4019, 4020, 4021, + 4022, 4023, 4024, 4025, 4029, 4026, 4027, 4028, + 7623, 4030, 4031, 4032, 4033, 7623, 4035, 4041, + 4036, 4037, 4038, 4039, 4040, 7623, 4042, 4045, + 4043, 4044, 7623, 4046, 4047, 7623, 4049, 4052, + 4054, 4050, 4051, 7623, 7623, 4053, 7623, 4055, + 4056, 4057, 7623, 4059, 4062, 4060, 4061, 7623, + 4063, 7623, 4064, 7623, 4066, 4069, 4067, 4068, + 7623, 4070, 4071, 7623, 4073, 4074, 4075, 4076, + 4077, 7623, 4079, 4081, 4080, 7623, 4082, 4083, + 4084, 4085, 4086, 7623, 4088, 4094, 4102, 4114, + 4117, 4118, 4123, 4131, 4143, 4159, 4163, 4169, + 4183, 4223, 4230, 4238, 4240, 4244, 4089, 4092, + 4090, 4091, 7623, 4093, 7623, 4095, 4098, 4096, + 4097, 7677, 4099, 4100, 4101, 7623, 4103, 4107, + 4109, 4113, 4104, 4105, 4106, 7623, 4108, 7623, + 7678, 4110, 4111, 4112, 7623, 7623, 4115, 4116, + 7623, 7623, 4119, 4122, 4120, 4121, 7623, 7623, + 7623, 4124, 4127, 4125, 4126, 7679, 7623, 4128, + 4129, 4130, 7623, 7623, 4132, 4138, 4139, 4133, + 4134, 4135, 4136, 4137, 7623, 7623, 7623, 4140, + 4141, 4142, 7623, 4144, 4147, 4154, 4145, 4146, + 7623, 4148, 4149, 7623, 4150, 4153, 4151, 4152, + 7623, 7623, 4155, 4156, 7623, 4157, 4158, 7623, + 7623, 4160, 4161, 7623, 4162, 7623, 4164, 4167, + 4165, 4166, 7623, 4168, 7623, 4170, 4174, 4177, + 4171, 7623, 4172, 4173, 7623, 4175, 4176, 7623, + 4178, 7623, 4179, 4182, 4180, 4181, 7623, 7623, + 4184, 4192, 4206, 4217, 4185, 4188, 4186, 4187, + 7623, 4189, 4190, 4191, 7623, 4193, 4195, 4194, + 7623, 4196, 4197, 4198, 4199, 4202, 4200, 4201, + 7623, 4203, 4204, 4205, 7623, 4207, 4210, 4213, + 4208, 4209, 7623, 4211, 4212, 7623, 4214, 7623, + 4215, 4216, 7623, 4218, 4219, 4220, 4221, 4222, + 7623, 4224, 4227, 4225, 4226, 7623, 4228, 4229, + 7623, 4231, 4233, 4236, 4232, 7623, 4234, 4235, + 7623, 4237, 7623, 4239, 7680, 7623, 4241, 4242, + 7681, 4243, 7623, 4245, 4247, 4250, 4246, 7623, + 4248, 4249, 7623, 4251, 4259, 4252, 4253, 4254, + 4255, 4256, 4257, 4258, 7623, 4260, 4261, 4262, + 4263, 4264, 4265, 4266, 4267, 7623, 4269, 4281, + 4283, 4288, 4300, 4304, 4308, 4317, 4320, 4329, + 4336, 4362, 4270, 4271, 4272, 4273, 4274, 4275, + 4276, 4277, 4278, 4279, 4280, 7623, 4282, 7623, + 4284, 4285, 4286, 4287, 7623, 4289, 4293, 4299, + 4290, 4291, 4292, 7623, 4294, 4296, 4295, 7623, + 4297, 4298, 7623, 7623, 4301, 4302, 4303, 7623, + 4305, 4306, 4307, 7623, 4309, 4311, 4314, 4310, + 7623, 4312, 4313, 7623, 4315, 4316, 7623, 4318, + 4319, 7623, 4321, 4323, 4322, 7623, 4324, 4327, + 4325, 4326, 7623, 7623, 4328, 7623, 4330, 4331, + 4332, 4333, 4334, 4335, 7623, 4337, 4359, 4338, + 4357, 4339, 4344, 4347, 4350, 4352, 4355, 7682, + 4340, 7683, 4341, 4342, 4343, 7623, 7623, 7623, + 7623, 4345, 4346, 7623, 7623, 7684, 4348, 4349, + 7623, 7623, 4351, 7623, 4353, 4354, 7623, 7623, + 4356, 7623, 4358, 7623, 4360, 4361, 7623, 4363, + 4364, 7623, 4366, 4368, 4378, 4383, 4388, 4391, + 4411, 4413, 4415, 4419, 4422, 4426, 4440, 4443, + 4447, 7685, 4500, 7623, 4367, 7623, 4369, 4373, + 4377, 4370, 4371, 4372, 7623, 4374, 4375, 7623, + 4376, 7623, 7623, 4379, 4380, 4381, 4382, 7623, + 4384, 4387, 4385, 4386, 7623, 7623, 4389, 4390, + 7623, 7623, 4392, 4393, 4400, 7623, 7623, 4394, + 4395, 7623, 4396, 4397, 4398, 4399, 7623, 7623, + 4401, 4403, 4408, 4402, 7623, 4404, 4405, 7623, + 4406, 7623, 4407, 7623, 7623, 4409, 4410, 7623, + 4412, 7623, 7623, 4414, 7623, 4416, 4417, 4418, + 7623, 4420, 4421, 7623, 7623, 4423, 4424, 4425, + 7623, 7623, 7623, 4427, 4428, 4434, 4437, 7623, + 4429, 7623, 4430, 4431, 4432, 4433, 7623, 7623, + 4435, 7623, 4436, 7623, 4438, 4439, 7623, 4441, + 4442, 7623, 4444, 4445, 4446, 7623, 4448, 4450, + 4449, 7623, 4451, 7623, 4452, 4453, 7623, 7623, + 7623, 4455, 4456, 7623, 4457, 7623, 4459, 4460, + 7623, 4462, 4463, 4464, 7623, 4466, 4467, 4468, + 4469, 7623, 4471, 4479, 4482, 4493, 4497, 4472, + 4477, 4473, 4474, 4475, 4476, 7623, 4478, 7623, + 4480, 4481, 7623, 4483, 4484, 4488, 4485, 4486, + 4487, 7623, 4489, 4490, 4491, 4492, 7623, 4494, + 4495, 4496, 7623, 4498, 4499, 7623, 4501, 4508, + 4502, 4503, 4504, 4505, 4506, 4507, 7623, 4509, + 7623, 4511, 4514, 4534, 4537, 4541, 4557, 4559, + 4571, 4606, 4617, 4512, 4513, 7623, 4515, 4519, + 4521, 4525, 4516, 4517, 4518, 7623, 4520, 7623, + 4522, 4523, 4524, 7623, 4526, 4529, 4527, 4528, + 7623, 7623, 4530, 4533, 4531, 4532, 7623, 7623, + 4535, 4536, 7623, 4538, 4539, 4540, 7623, 4542, + 4549, 4553, 4543, 4544, 4545, 7623, 4546, 4547, + 4548, 7623, 4550, 4551, 4552, 7623, 4554, 4555, + 4556, 7623, 4558, 7623, 4560, 4561, 4566, 4562, + 4563, 4564, 4565, 7623, 4567, 4568, 4569, 4570, + 7623, 4572, 4575, 4579, 4600, 4602, 4573, 4574, + 7623, 4576, 4577, 4578, 7623, 4580, 4581, 4590, + 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, + 7623, 4591, 4592, 4593, 4594, 4595, 4596, 4597, + 4598, 4599, 7623, 4601, 7623, 4603, 4604, 4605, + 7623, 4607, 4609, 4613, 4608, 7623, 4610, 4611, + 4612, 7623, 4614, 4615, 4616, 7623, 4618, 4622, + 4619, 4620, 4621, 7623, 4623, 4624, 4625, 7623, + 4627, 4631, 4635, 4640, 4643, 4647, 4661, 4665, + 4686, 4723, 4733, 4737, 4741, 4753, 4758, 4628, + 4629, 4630, 7686, 7623, 4632, 4634, 4633, 7687, + 7623, 4636, 4638, 4637, 7623, 4639, 7688, 4641, + 4642, 7623, 7623, 4644, 4645, 4646, 7689, 7623, + 4648, 4654, 4658, 4649, 4652, 4650, 4651, 7623, + 4653, 7623, 4655, 4656, 4657, 7623, 4659, 4660, + 7623, 4662, 4663, 4664, 7623, 4666, 4681, 4683, + 4667, 4669, 4679, 4668, 7623, 4670, 4671, 4675, + 7623, 4672, 4673, 4674, 7623, 4676, 4677, 4678, + 7623, 4680, 7623, 4682, 7623, 4684, 4685, 7623, + 7623, 4687, 4691, 4697, 4701, 4688, 4689, 4690, + 7623, 4692, 4693, 7623, 4694, 4695, 4696, 7623, + 4698, 4699, 4700, 7623, 7623, 4702, 4705, 4714, + 4719, 4703, 4704, 7623, 4706, 4710, 4707, 4708, + 4709, 7623, 4711, 4712, 4713, 7623, 4715, 4716, + 4717, 4718, 7623, 4720, 4721, 4722, 7623, 4724, + 4726, 4729, 4731, 4725, 7623, 4727, 4728, 7623, + 4730, 7623, 4732, 7623, 4734, 4735, 4736, 7623, + 4738, 4739, 4740, 7690, 4742, 4744, 4743, 7623, + 4745, 7623, 4746, 4747, 4750, 4752, 7623, 4748, + 4749, 7623, 7623, 4751, 7623, 7623, 7623, 4754, + 4755, 4756, 4757, 7623, 4759, 4762, 4760, 4761, + 7623, 7691, 4764, 4769, 4771, 4775, 4778, 4785, + 4765, 4768, 4766, 4767, 7623, 7623, 4770, 7623, + 4772, 4773, 4774, 7623, 4776, 4777, 7623, 4779, + 4781, 4780, 7623, 4782, 4783, 4784, 7623, 4786, + 4787, 4788, 7623, 4790, 4795, 4801, 4803, 4808, + 4811, 4814, 4817, 4791, 4792, 4793, 7623, 4794, + 7623, 4796, 4800, 4797, 4798, 4799, 7623, 7623, + 4802, 7623, 4804, 4805, 4806, 4807, 7623, 4809, + 4810, 7623, 4812, 4813, 7623, 4815, 4816, 7623, + 4818, 4819, 7623, 4821, 4831, 4835, 4837, 4840, + 4891, 4909, 4923, 4942, 5060, 5070, 5072, 5081, + 5084, 5101, 5114, 5128, 5215, 5220, 5238, 7693, + 5290, 5301, 4822, 4825, 4827, 4823, 4824, 7623, + 4826, 7623, 4828, 4829, 4830, 7623, 4832, 4833, + 4834, 7623, 7623, 4836, 7623, 4838, 4839, 7623, + 4841, 4845, 4851, 4855, 4859, 4864, 4865, 4867, + 4885, 4842, 4843, 4844, 7623, 4846, 4847, 4848, + 4849, 4850, 7623, 4852, 4853, 4854, 7623, 4856, + 4857, 4858, 7623, 4860, 7623, 4861, 4862, 7623, + 4863, 7623, 7623, 4866, 7692, 4868, 7623, 4869, + 4872, 4874, 4876, 4878, 4880, 4883, 7623, 4870, + 4871, 7623, 4873, 7623, 4875, 7623, 4877, 7623, + 4879, 7623, 4881, 4882, 7623, 4884, 7623, 7623, + 4886, 4889, 4887, 4888, 7623, 7623, 4890, 7623, + 4892, 4895, 4898, 4893, 4894, 7623, 4896, 4897, + 7623, 4899, 4903, 4900, 4901, 4902, 7623, 7623, + 4904, 4905, 7623, 4906, 4907, 4908, 7623, 7623, + 4910, 4914, 4920, 4922, 4911, 4912, 4913, 7623, + 4915, 4918, 4916, 4917, 7623, 4919, 7623, 4921, + 7623, 7623, 4924, 4926, 4930, 4940, 4925, 7623, + 4927, 4928, 7623, 4929, 7623, 4931, 4935, 4932, + 4933, 4934, 7623, 4936, 4937, 4938, 4939, 7623, + 4941, 7623, 7623, 4943, 5016, 5017, 5024, 4944, + 4945, 4954, 4967, 4977, 5006, 4946, 4947, 4948, + 4949, 7623, 4950, 4951, 4952, 4953, 7623, 4955, + 4956, 4957, 4958, 4959, 4960, 4961, 4965, 4962, + 4963, 4964, 7623, 4966, 7623, 4968, 4969, 4970, + 4971, 4972, 4973, 4974, 4975, 4976, 7623, 4978, + 4979, 4980, 4981, 4982, 4988, 4996, 4983, 4984, + 4985, 4986, 7623, 4987, 7623, 4989, 4990, 4991, + 4992, 4993, 4994, 4995, 7623, 4997, 4998, 4999, + 5000, 5001, 5002, 5003, 5004, 5005, 7623, 5007, + 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, + 7623, 7623, 7623, 5018, 5019, 7623, 5020, 5021, + 5022, 5023, 7623, 7623, 5025, 5027, 5032, 5035, + 5026, 7623, 5028, 5029, 7623, 5030, 7623, 5031, + 7623, 7623, 5033, 5034, 7623, 5036, 5042, 5045, + 5054, 5057, 5037, 5038, 5039, 5040, 5041, 7623, + 5043, 5044, 7623, 5046, 5047, 5050, 5048, 5049, + 7623, 5051, 5052, 5053, 7623, 5055, 5056, 7623, + 5058, 5059, 7623, 5061, 5065, 5069, 5062, 5063, + 5064, 7623, 5066, 5067, 5068, 7623, 7623, 7623, + 5071, 7623, 5073, 5078, 5074, 5075, 5076, 7623, + 7623, 5077, 7623, 5079, 5080, 7623, 5082, 5083, + 7623, 7623, 5085, 5088, 5094, 5098, 5086, 5087, + 7623, 5089, 5090, 5091, 5092, 5093, 7623, 5095, + 5096, 5097, 7623, 5099, 5100, 7623, 5102, 5106, + 5103, 5104, 5105, 7623, 5107, 5108, 5109, 7623, + 5110, 5111, 5112, 5113, 7623, 5115, 5116, 5122, + 5125, 7623, 5117, 7623, 5118, 5119, 5120, 5121, + 7623, 7623, 5123, 7623, 5124, 7623, 5126, 5127, + 7623, 5129, 5134, 5137, 5174, 5190, 5197, 5202, + 5209, 5130, 5132, 5131, 7623, 5133, 7623, 5135, + 5136, 7623, 5138, 5139, 5158, 5164, 5140, 5141, + 5142, 5143, 5148, 5144, 5145, 5146, 5147, 7623, + 5149, 5150, 5151, 5152, 5153, 5154, 5155, 5156, + 5157, 7623, 5159, 5160, 5161, 5162, 5163, 7623, + 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, + 5173, 7623, 5175, 5176, 5177, 5178, 5179, 5180, + 5181, 5185, 5182, 5183, 5184, 7623, 5186, 5187, + 5188, 5189, 7623, 5191, 5193, 5194, 5192, 7623, + 7623, 5195, 5196, 7623, 5198, 5199, 5200, 5201, + 7623, 5203, 5206, 5204, 5205, 7623, 5207, 5208, + 7623, 7623, 5210, 5214, 5211, 5212, 5213, 7623, + 7623, 5216, 5217, 7623, 5218, 5219, 7623, 5221, + 5224, 5230, 5234, 5235, 5222, 5223, 7623, 5225, + 5226, 5227, 5228, 5229, 7623, 5231, 5232, 7623, + 5233, 7623, 7623, 5236, 5237, 7623, 5239, 5243, + 5245, 5246, 5250, 5255, 5240, 5241, 5242, 7623, + 5244, 7623, 7623, 5247, 7623, 5248, 5249, 7623, + 7623, 5251, 5252, 7623, 5253, 7623, 5254, 7623, + 5256, 5257, 5258, 7623, 7623, 5260, 5261, 7623, + 5262, 7623, 5264, 5265, 7623, 5267, 5268, 5269, + 7623, 5271, 5272, 5273, 7623, 5275, 5276, 5277, + 7623, 5279, 5280, 5281, 5282, 7623, 5284, 5287, + 5285, 5286, 7623, 7623, 5288, 5289, 7623, 7623, + 5291, 5292, 5297, 5293, 5294, 5295, 5296, 7623, + 5298, 5299, 5300, 7623, 5302, 5309, 5303, 5304, + 5305, 5306, 5307, 5308, 7623, 5310, 7623, 5312, + 5316, 5342, 5348, 5352, 5364, 5366, 5368, 5386, + 5391, 5396, 5403, 5404, 5411, 5313, 5314, 5315, + 7623, 5317, 5318, 5324, 5338, 7694, 5319, 5320, + 7623, 7623, 5321, 5322, 5323, 7623, 7623, 5325, + 5326, 5327, 7623, 5328, 5332, 5336, 5329, 5330, + 5331, 7623, 5333, 5334, 5335, 7623, 5337, 7623, + 5339, 5340, 5341, 7623, 5343, 5347, 5344, 5345, + 5346, 7623, 7623, 5349, 5350, 5351, 7623, 5353, + 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, + 5362, 5363, 7623, 5365, 7623, 5367, 7623, 5369, + 5371, 5380, 5370, 7695, 7623, 5372, 5375, 5378, + 5373, 5374, 7623, 5376, 5377, 7623, 5379, 7696, + 5381, 5382, 7623, 5383, 5384, 7623, 7623, 5385, + 7623, 5387, 5389, 5388, 7623, 5390, 7623, 5392, + 5393, 5394, 5395, 7623, 5397, 5401, 5398, 5399, + 5400, 7623, 5402, 7623, 7623, 5405, 5407, 5406, + 7623, 5408, 5409, 5410, 7623, 7623, 5412, 5418, + 5413, 5414, 5415, 5416, 5417, 7623, 5419, 5420, + 7623, 5422, 5426, 5448, 5458, 5467, 5493, 5499, + 5518, 5522, 5551, 5553, 5569, 5579, 5583, 5586, + 5630, 5633, 5652, 5676, 5698, 5760, 5788, 5795, + 5838, 5423, 5424, 7623, 7623, 5425, 7623, 5427, + 5445, 5446, 5428, 5429, 5430, 5435, 5431, 5432, + 5433, 5434, 7623, 5436, 5437, 5438, 5439, 5440, + 5441, 5442, 5443, 5444, 7623, 7623, 7623, 5447, + 7623, 5449, 5450, 5451, 5452, 5453, 5454, 5455, + 5456, 5457, 7623, 5459, 5463, 5460, 5461, 5462, + 7623, 5464, 5465, 5466, 7623, 5468, 5471, 5475, + 5477, 5487, 5469, 5470, 7623, 5472, 5473, 5474, + 7623, 5476, 7623, 7623, 5478, 5479, 5481, 5483, + 7623, 5480, 7623, 5482, 7623, 5484, 5485, 5486, + 7623, 5488, 5489, 7623, 5490, 5491, 7623, 5492, + 7623, 5494, 5495, 7697, 5496, 5497, 7623, 5498, + 7623, 5500, 5505, 5509, 5515, 5517, 5501, 5502, + 7623, 5503, 5504, 7623, 5506, 5507, 5508, 7623, + 5510, 5511, 7623, 5512, 5513, 5514, 7623, 5516, + 7623, 7623, 5519, 5520, 5521, 7623, 7623, 5523, + 5526, 5533, 5536, 5540, 5546, 5524, 5525, 7623, + 5527, 5528, 5530, 5529, 7623, 7623, 5531, 5532, + 7623, 5534, 5535, 7623, 5537, 5538, 5539, 7623, + 5541, 5544, 5542, 5543, 7623, 5545, 7623, 5547, + 5548, 5549, 7623, 5550, 7623, 5552, 7623, 5554, + 5555, 5564, 5567, 7623, 7623, 5556, 5563, 7623, + 5557, 5558, 7623, 5559, 5560, 5561, 5562, 7623, + 7623, 5565, 5566, 7623, 7623, 5568, 7623, 5570, + 5573, 5576, 5571, 5572, 7623, 5574, 5575, 7623, + 5577, 5578, 7623, 7623, 5580, 5582, 7623, 5581, + 7623, 7623, 5584, 5585, 7623, 5587, 5590, 5591, + 5594, 5596, 5623, 5626, 5588, 5589, 7623, 7623, + 5592, 5593, 7623, 5595, 7623, 7623, 5597, 5614, + 5621, 5598, 5599, 5604, 5600, 5601, 5602, 5603, + 7623, 5605, 5606, 5607, 5608, 5609, 5610, 5611, + 5612, 5613, 7623, 7623, 5615, 5616, 7623, 5617, + 5618, 5619, 5620, 7623, 7623, 5622, 7623, 5624, + 5625, 7623, 7623, 5627, 5628, 7623, 5629, 7623, + 5631, 5632, 7623, 5634, 7698, 5635, 7623, 7623, + 5637, 7623, 5638, 5639, 5642, 7623, 5640, 5641, + 7623, 5643, 5644, 5645, 7623, 7623, 7623, 5647, + 7623, 5648, 5649, 5650, 5651, 7623, 7623, 7623, + 5653, 5663, 5668, 5654, 7623, 5655, 5660, 5662, + 5656, 5657, 5658, 5659, 7623, 5661, 7623, 7623, + 5664, 5665, 5666, 5667, 7623, 7623, 5669, 5672, + 5670, 5671, 7623, 7623, 5673, 7623, 5674, 5675, + 7623, 5677, 5680, 5685, 5694, 5678, 5679, 7623, + 5681, 5682, 7623, 5683, 5684, 7623, 7623, 5686, + 5687, 5688, 5689, 5690, 5691, 5692, 5693, 7623, + 5695, 5696, 7623, 5697, 7623, 5699, 5705, 5720, + 5724, 5727, 5730, 5737, 7623, 5700, 5703, 5704, + 5701, 5702, 7623, 7623, 7623, 5706, 5707, 5708, + 5709, 5712, 5710, 5711, 7623, 5713, 5714, 5715, + 5716, 5717, 5718, 5719, 7623, 5721, 7623, 5722, + 7623, 5723, 7623, 5725, 5726, 7623, 5728, 5729, + 7623, 5731, 5732, 5733, 5735, 5734, 7623, 5736, + 7623, 5738, 5747, 5751, 7623, 5739, 5740, 5741, + 7623, 7623, 5742, 5743, 7623, 5744, 5745, 7623, + 5746, 7623, 5748, 7623, 5749, 5750, 7623, 7623, + 5752, 5753, 5754, 7623, 7623, 5755, 5756, 7623, + 5757, 5758, 7623, 5759, 7623, 5761, 5763, 5766, + 5768, 5762, 7623, 5764, 5765, 7699, 5767, 7623, + 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5781, + 5776, 5777, 5778, 7623, 5779, 5780, 7623, 5782, + 5783, 5784, 5785, 7623, 5786, 5787, 7623, 7623, + 5789, 7623, 5790, 5793, 5791, 5792, 7623, 5794, + 7623, 5796, 5800, 5804, 5806, 5810, 5813, 5818, + 5827, 5835, 5797, 5798, 5799, 7623, 5801, 5802, + 5803, 7623, 5805, 7623, 5807, 5808, 5809, 7623, + 5811, 5812, 7623, 7623, 5814, 5815, 5816, 5817, + 7623, 5819, 5822, 5823, 5820, 5821, 7623, 7623, + 7623, 5824, 5825, 5826, 7623, 5828, 5831, 5829, + 5830, 7623, 5832, 5833, 5834, 7623, 5836, 5837, + 7623, 5839, 5842, 5849, 5840, 5841, 7623, 5843, + 5844, 5846, 5845, 7623, 7623, 5847, 5848, 7623, + 5850, 5851, 5852, 7623, 5854, 5855, 5861, 5865, + 5881, 5885, 5890, 5897, 5902, 5905, 5920, 5936, + 5939, 5948, 5969, 5977, 5986, 5988, 7623, 5856, + 5859, 5857, 5858, 7700, 5860, 7623, 5862, 5864, + 5863, 7623, 7701, 7623, 5866, 5869, 5873, 5875, + 5877, 5867, 5868, 7623, 5870, 5871, 5872, 7623, + 5874, 7623, 5876, 7623, 5878, 5879, 5880, 7623, + 5882, 5883, 5884, 7623, 5886, 5889, 5887, 5888, + 7623, 7623, 5891, 5893, 5896, 5892, 7623, 5894, + 5895, 7702, 7623, 5898, 5901, 5899, 5900, 7623, + 7623, 5903, 5904, 7623, 5906, 5909, 5916, 5919, + 5907, 5908, 7623, 5910, 5912, 5911, 7623, 5913, + 5914, 5915, 7623, 5917, 5918, 7623, 7623, 5921, + 5924, 5927, 5922, 5923, 7623, 5925, 5926, 7623, + 5928, 5932, 5933, 5929, 5930, 5931, 7623, 7623, + 5934, 5935, 7623, 5937, 5938, 7623, 5940, 5942, + 5945, 5941, 7623, 5943, 5944, 7623, 5946, 5947, + 7623, 7623, 5949, 5952, 5957, 5961, 5963, 5968, + 5950, 5951, 7623, 7623, 5953, 7703, 7704, 5954, + 7623, 5955, 5956, 7623, 5958, 5959, 5960, 7623, + 5962, 7623, 5964, 5965, 5966, 5967, 7623, 7623, + 5970, 5972, 5975, 5971, 7623, 5973, 5974, 7705, + 5976, 7623, 5978, 5979, 5981, 5980, 7706, 5982, + 5983, 7623, 5984, 5985, 7623, 5987, 7707, 5989, + 5990, 5991, 7623, 5993, 6004, 6006, 6022, 6024, + 6034, 6043, 6072, 6073, 6084, 6160, 6164, 5994, + 7623, 7708, 5999, 6003, 7623, 5996, 5997, 5998, + 7623, 6000, 6002, 6001, 7623, 7623, 7623, 6005, + 7623, 6007, 6008, 6011, 6014, 6017, 6018, 6009, + 6010, 7623, 6012, 6013, 7623, 6015, 6016, 7623, + 7623, 6019, 6020, 6021, 7623, 6023, 7623, 6025, + 6027, 6031, 7623, 6026, 7623, 6028, 6029, 6030, + 7623, 6032, 6033, 7623, 7623, 6035, 6042, 6036, + 6037, 6038, 6039, 6040, 6041, 7623, 7623, 6044, + 6051, 6045, 6046, 6049, 6047, 7623, 6048, 7623, + 6050, 7623, 6052, 7623, 6053, 6057, 6058, 6061, + 6064, 6065, 6066, 6069, 6054, 6055, 6056, 7623, + 7623, 6059, 6060, 7623, 6062, 6063, 7623, 7623, + 7623, 7709, 6067, 6068, 7623, 6070, 6071, 7623, + 7623, 6074, 6080, 6082, 6075, 6076, 6077, 6078, + 6079, 7623, 6081, 7623, 6083, 7710, 7623, 6085, + 6086, 6088, 6091, 6124, 6128, 6135, 6153, 6156, + 7623, 6087, 7623, 6089, 6090, 7623, 7623, 6092, + 7623, 6093, 6099, 6106, 6108, 6121, 6094, 6095, + 6096, 6097, 6098, 7623, 6100, 6101, 6102, 6103, + 6104, 6105, 7623, 6107, 7623, 6109, 6115, 6118, + 6110, 6111, 6112, 6113, 6114, 7623, 6116, 6117, + 7623, 6119, 6120, 7623, 6122, 6123, 7623, 6125, + 6126, 7623, 6127, 7623, 6129, 6130, 6132, 7623, + 6131, 7623, 6133, 6134, 7623, 6136, 6137, 6150, + 7623, 6138, 6142, 6146, 6139, 6140, 6141, 7623, + 6143, 6144, 6145, 7623, 6147, 6148, 6149, 7623, + 7623, 6151, 6152, 7623, 6154, 6155, 7623, 6157, + 6158, 6159, 7623, 6161, 6163, 6162, 7623, 7623, + 6165, 6166, 6167, 6168, 7623, 6170, 6172, 6175, + 6178, 6183, 6186, 6171, 7623, 6173, 6174, 7623, + 6176, 6177, 7623, 6179, 6180, 6181, 6182, 7623, + 6184, 6185, 7623, 6187, 6199, 6204, 6188, 6189, + 6196, 6190, 6191, 6192, 6193, 6194, 6195, 7623, + 6197, 6198, 7623, 6200, 6201, 7623, 6202, 6203, + 7623, 7711, 6206, 6216, 6220, 6223, 6278, 6296, + 6310, 6324, 6337, 6347, 6355, 6442, 6450, 6459, + 6463, 6484, 6495, 6499, 6512, 6529, 6535, 6207, + 6210, 6212, 6208, 6209, 7623, 6211, 7623, 6213, + 6214, 6215, 7623, 6217, 6218, 6219, 7623, 6221, + 6222, 7623, 6224, 6229, 6232, 6238, 6244, 6246, + 6268, 6225, 6226, 7623, 6227, 6228, 7623, 6230, + 6231, 7623, 6233, 6234, 6235, 6236, 6237, 7623, + 6239, 7623, 6240, 6241, 6242, 7623, 7623, 6243, + 7623, 6245, 7712, 6247, 7623, 6248, 6250, 6253, + 6254, 6256, 6258, 6260, 6262, 6265, 6267, 6249, + 7623, 7623, 6251, 6252, 7623, 7623, 6255, 7623, + 6257, 7623, 6259, 7623, 6261, 7623, 6263, 6264, + 7623, 6266, 7623, 7623, 6269, 6272, 6270, 6271, + 7623, 6273, 7623, 6274, 6275, 6276, 6277, 7623, + 6279, 6282, 6285, 6280, 6281, 7623, 6283, 6284, + 7623, 6286, 6290, 6287, 6288, 6289, 7623, 7623, + 6291, 6292, 7623, 6293, 6294, 6295, 7623, 7623, + 6297, 6301, 6307, 6309, 6298, 6299, 6300, 7623, + 6302, 6305, 6303, 6304, 7623, 6306, 7623, 6308, + 7623, 7623, 6311, 6313, 6318, 6322, 6312, 7623, + 6314, 6315, 6316, 6317, 7623, 6319, 6320, 7623, + 6321, 7623, 6323, 7623, 6325, 6335, 7713, 6326, + 7623, 6327, 6330, 6334, 6328, 6329, 7623, 6331, + 6332, 6333, 7623, 7623, 6336, 7623, 6338, 6342, + 6346, 6339, 6340, 6341, 7623, 6343, 6344, 6345, + 7623, 7623, 6348, 6353, 6349, 6350, 6351, 7623, + 7623, 6352, 7623, 7623, 6354, 7623, 6356, 6430, + 6432, 6357, 6358, 6359, 6368, 6381, 6399, 6410, + 6420, 6360, 6361, 6362, 6363, 7623, 6364, 6365, + 6366, 6367, 7623, 6369, 6370, 6371, 6372, 6373, + 6374, 6375, 6379, 6376, 6377, 6378, 7623, 6380, + 7623, 6382, 6383, 6384, 6385, 6391, 6386, 6387, + 6388, 6389, 6390, 7623, 6392, 6393, 6394, 6395, + 6396, 6397, 6398, 7623, 6400, 6401, 6402, 6403, + 6404, 6405, 6406, 6407, 6408, 6409, 7623, 6411, + 6412, 6413, 6414, 6415, 6416, 6417, 6418, 6419, + 7623, 6421, 6422, 6423, 6424, 6425, 6426, 6427, + 6428, 6429, 7623, 6431, 7623, 6433, 6434, 6435, + 6436, 6437, 6438, 6439, 6440, 6441, 7623, 6443, + 6446, 6449, 6444, 6445, 7623, 6447, 6448, 7623, + 7623, 6451, 6452, 6453, 6454, 7623, 6455, 6456, + 6457, 6458, 7623, 6460, 6461, 6462, 7623, 6464, + 6469, 6472, 6479, 6465, 6467, 6466, 7623, 6468, + 7623, 6470, 6471, 7623, 6473, 6475, 6476, 6474, + 7623, 7623, 6477, 6478, 7623, 6480, 6481, 6482, + 6483, 7623, 6485, 6489, 6486, 7623, 6487, 6488, + 7623, 6490, 6491, 6492, 6493, 6494, 7623, 6496, + 6497, 6498, 7623, 6500, 6504, 6506, 6507, 6501, + 6502, 6503, 7623, 6505, 7623, 7623, 6508, 6509, + 7623, 6510, 7623, 6511, 7623, 6513, 6517, 6521, + 6514, 6515, 6516, 7623, 6518, 6519, 6520, 7623, + 6522, 7623, 6523, 6524, 6525, 7623, 7623, 6526, + 6527, 6528, 7623, 6530, 6531, 6532, 6533, 6534, + 7623, 7623, 6537, 6542, 6546, 6580, 6585, 6612, + 6617, 6640, 6666, 6670, 6698, 6709, 6718, 6748, + 6752, 6767, 6789, 6913, 6928, 6538, 6539, 6540, + 6541, 7623, 6543, 6544, 6545, 7623, 7623, 6547, + 6548, 6553, 6556, 6560, 6563, 6570, 6576, 6579, + 7623, 6549, 6550, 7623, 6551, 6552, 7623, 6554, + 6555, 7623, 7623, 6557, 6558, 6559, 7623, 6561, + 6562, 7623, 6564, 6565, 6567, 7623, 6566, 7623, + 6568, 6569, 7623, 6571, 6572, 6573, 6574, 6575, + 7623, 6577, 6578, 7623, 7623, 6581, 6582, 7623, + 6583, 6584, 7623, 7623, 6586, 6589, 6596, 6597, + 6599, 6603, 6610, 6587, 6588, 7623, 6590, 6591, + 6593, 6592, 7623, 7623, 6594, 6595, 7623, 7714, + 6598, 7623, 6600, 6601, 6602, 7623, 6604, 6605, + 6609, 6606, 6607, 6608, 7623, 7623, 6611, 7623, + 6613, 7623, 6614, 6615, 6616, 7623, 6618, 6621, + 6626, 7715, 6619, 6620, 7623, 6622, 6625, 6623, + 6624, 7623, 7623, 6627, 6628, 6629, 6632, 6630, + 6631, 7623, 6633, 6634, 6635, 6636, 6637, 6638, + 6639, 7623, 6641, 6646, 6642, 6643, 7623, 6644, + 6645, 7623, 7623, 7623, 6647, 6650, 6652, 6654, + 6656, 6658, 6662, 6648, 6649, 7623, 7623, 6651, + 7623, 7623, 6653, 7623, 7623, 6655, 7623, 6657, + 7623, 6659, 6660, 6661, 7623, 6663, 6664, 6665, + 7623, 6667, 6668, 6669, 7623, 6671, 6685, 6691, + 6695, 6672, 6682, 6673, 6674, 6675, 6676, 6677, + 6678, 6679, 6680, 6681, 7623, 6683, 6684, 7623, + 6686, 6687, 6688, 6689, 6690, 7623, 6692, 6693, + 7623, 6694, 7623, 7623, 6696, 7623, 6697, 7623, + 6699, 6703, 6707, 6700, 6701, 6702, 7623, 7623, + 6704, 7623, 6705, 6706, 7623, 6708, 7623, 6710, + 6711, 6717, 6712, 6713, 7623, 6714, 6715, 6716, + 7623, 7623, 6719, 6726, 6742, 6720, 6723, 6721, + 7623, 6722, 7623, 6724, 7623, 6725, 7623, 6727, + 6728, 6735, 7623, 6729, 6730, 7623, 6731, 6732, + 7623, 6733, 6734, 7623, 7623, 6736, 6737, 7623, + 6738, 6739, 7623, 6740, 6741, 7623, 7623, 6743, + 6747, 6744, 6745, 6746, 7623, 7623, 7623, 6749, + 6750, 6751, 7623, 6753, 6755, 6759, 6763, 6754, + 7623, 6756, 6757, 6758, 7623, 6760, 6761, 6762, + 7623, 6764, 6765, 6766, 7623, 6768, 6771, 6769, + 7623, 6770, 7623, 6772, 6787, 6773, 6774, 6775, + 6776, 6777, 6784, 6778, 6779, 6780, 6781, 6782, + 6783, 7623, 6785, 6786, 7623, 6788, 7623, 6790, + 6829, 6862, 6863, 6865, 7623, 6791, 6792, 6795, + 6799, 6803, 6806, 6810, 6814, 7623, 6793, 6794, + 7623, 7623, 6796, 6797, 6798, 7623, 6800, 6801, + 6802, 7623, 6804, 6805, 7623, 7623, 6807, 6808, + 6809, 7623, 6811, 6812, 6813, 7623, 6815, 6824, + 6826, 6816, 7623, 6817, 6820, 6818, 7623, 6819, + 7623, 6821, 6822, 7623, 6823, 7623, 6825, 7623, + 6827, 6828, 7623, 7623, 6830, 7623, 6831, 6837, + 6844, 6846, 6859, 6832, 6833, 6834, 6835, 6836, + 7623, 6838, 6839, 6840, 6841, 6842, 6843, 7623, + 6845, 7623, 6847, 6853, 6856, 6848, 6849, 6850, + 6851, 6852, 7623, 6854, 6855, 7623, 6857, 6858, + 7623, 6860, 6861, 7623, 7623, 6864, 7623, 7716, + 7717, 7718, 7623, 6866, 6867, 6873, 6877, 6883, + 6887, 6891, 6894, 6898, 7623, 6868, 6870, 6869, + 7623, 6871, 6872, 7623, 7623, 6874, 6875, 6876, + 7623, 6878, 6879, 6881, 6880, 7623, 6882, 7623, + 6884, 6885, 6886, 7623, 6888, 6889, 6890, 7623, + 6892, 6893, 7623, 7623, 6895, 6896, 6897, 7623, + 6899, 6908, 6910, 6900, 7623, 6901, 6904, 6902, + 7623, 6903, 7623, 6905, 6906, 7623, 6907, 7623, + 6909, 7623, 6911, 6912, 7623, 7623, 6914, 6917, + 6924, 6915, 6916, 7623, 6918, 6919, 6921, 6920, + 7623, 7623, 6922, 6923, 7623, 6925, 6926, 6927, + 7623, 6929, 6930, 7719, 6932, 6938, 6941, 6951, + 6954, 6959, 6961, 6999, 7011, 7027, 7032, 7085, + 7096, 6933, 6937, 6934, 6935, 6936, 7623, 7623, + 6939, 6940, 7623, 6942, 6946, 6950, 6943, 6944, + 6945, 7623, 6947, 6948, 6949, 7623, 7623, 6952, + 6953, 7623, 6955, 6956, 6957, 6958, 7623, 6960, + 7623, 6962, 6976, 6991, 6997, 6963, 6970, 6964, + 6965, 6966, 7623, 6967, 6968, 6969, 7623, 6971, + 7623, 6972, 6975, 6973, 6974, 7623, 7623, 6977, + 6988, 6978, 6979, 6985, 6980, 6981, 6982, 6983, + 6984, 7623, 6986, 6987, 7623, 6989, 6990, 7623, + 6992, 6994, 6993, 7623, 6995, 6996, 7623, 6998, + 7720, 7000, 7003, 7009, 7001, 7002, 7623, 7004, + 7721, 7623, 7623, 7006, 7007, 7623, 7623, 7010, + 7623, 7012, 7014, 7025, 7013, 7623, 7623, 7015, + 7018, 7021, 7016, 7017, 7623, 7019, 7020, 7623, + 7623, 7022, 7023, 7024, 7623, 7026, 7623, 7028, + 7029, 7030, 7031, 7623, 7033, 7036, 7079, 7034, + 7035, 7623, 7037, 7060, 7063, 7064, 7069, 7073, + 7075, 7038, 7039, 7040, 7041, 7623, 7042, 7046, + 7052, 7053, 7043, 7044, 7045, 7623, 7047, 7048, + 7049, 7623, 7050, 7051, 7623, 7623, 7054, 7055, + 7056, 7057, 7623, 7058, 7059, 7623, 7061, 7062, + 7623, 7623, 7065, 7066, 7067, 7068, 7623, 7070, + 7071, 7072, 7623, 7074, 7623, 7076, 7077, 7078, + 7623, 7080, 7081, 7082, 7083, 7084, 7623, 7086, + 7089, 7092, 7087, 7088, 7623, 7623, 7090, 7091, + 7623, 7093, 7094, 7095, 7623, 7097, 7100, 7098, + 7099, 7623, 7101, 7102, 7103, 7104, 7105, 7114, + 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, + 7623, 7115, 7116, 7117, 7118, 7119, 7120, 7121, + 7122, 7123, 7623, 7125, 7128, 7131, 7137, 7144, + 7148, 7159, 7165, 7169, 7177, 7190, 7194, 7200, + 7248, 7264, 7267, 7278, 7283, 7126, 7127, 7623, + 7129, 7130, 7623, 7132, 7135, 7133, 7134, 7722, + 7136, 7623, 7138, 7139, 7141, 7140, 7623, 7142, + 7143, 7623, 7145, 7147, 7146, 7723, 7623, 7149, + 7152, 7156, 7150, 7151, 7623, 7153, 7154, 7155, + 7623, 7157, 7158, 7623, 7160, 7164, 7161, 7162, + 7163, 7623, 7623, 7166, 7167, 7168, 7724, 7170, + 7174, 7171, 7172, 7173, 7623, 7623, 7175, 7176, + 7623, 7178, 7187, 7179, 7184, 7180, 7181, 7623, + 7182, 7183, 7623, 7185, 7186, 7623, 7188, 7189, + 7623, 7191, 7725, 7192, 7193, 7623, 7195, 7198, + 7196, 7197, 7623, 7199, 7623, 7201, 7206, 7215, + 7231, 7234, 7240, 7202, 7203, 7204, 7205, 7623, + 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, + 7623, 7216, 7217, 7218, 7219, 7220, 7221, 7222, + 7226, 7223, 7224, 7225, 7623, 7227, 7228, 7229, + 7230, 7623, 7232, 7233, 7623, 7235, 7623, 7236, + 7237, 7623, 7238, 7239, 7623, 7241, 7242, 7243, + 7244, 7245, 7246, 7247, 7623, 7249, 7258, 7261, + 7250, 7255, 7251, 7252, 7623, 7253, 7254, 7623, + 7256, 7257, 7623, 7259, 7260, 7623, 7262, 7263, + 7623, 7265, 7266, 7623, 7268, 7271, 7275, 7269, + 7270, 7623, 7272, 7273, 7274, 7623, 7276, 7623, + 7277, 7623, 7279, 7282, 7280, 7281, 7623, 7726, + 7284, 7285, 7286, 7287, 7288, 7623, 7290, 7293, + 7297, 7301, 7381, 7383, 7387, 7403, 7405, 7409, + 7414, 7417, 7421, 7425, 7437, 7291, 7292, 7623, + 7294, 7295, 7623, 7296, 7623, 7298, 7299, 7300, + 7623, 7302, 7306, 7303, 7304, 7305, 7623, 7307, + 7314, 7319, 7326, 7335, 7338, 7360, 7308, 7309, + 7310, 7311, 7312, 7313, 7623, 7315, 7316, 7317, + 7318, 7623, 7320, 7321, 7322, 7323, 7324, 7325, + 7623, 7327, 7329, 7330, 7328, 7623, 7623, 7331, + 7332, 7333, 7334, 7623, 7623, 7336, 7337, 7623, + 7339, 7343, 7340, 7341, 7342, 7623, 7344, 7352, + 7345, 7346, 7347, 7348, 7349, 7350, 7623, 7351, + 7623, 7353, 7354, 7355, 7356, 7357, 7358, 7623, + 7359, 7623, 7361, 7365, 7362, 7363, 7364, 7623, + 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7376, + 7373, 7374, 7375, 7623, 7377, 7378, 7379, 7380, + 7623, 7382, 7623, 7384, 7385, 7386, 7623, 7388, + 7394, 7398, 7623, 7389, 7392, 7390, 7391, 7623, + 7393, 7623, 7395, 7396, 7397, 7623, 7399, 7402, + 7400, 7401, 7623, 7623, 7404, 7623, 7406, 7407, + 7408, 7623, 7410, 7411, 7412, 7413, 7623, 7623, + 7415, 7416, 7623, 7418, 7419, 7420, 7623, 7422, + 7423, 7424, 7623, 7426, 7428, 7427, 7623, 7429, + 7433, 7430, 7431, 7432, 7623, 7623, 7434, 7435, + 7436, 7623, 7623, 7438, 7439, 7440, 7441, 7442, + 7623, 7444, 7448, 7460, 7462, 7465, 7466, 7471, + 7445, 7446, 7447, 7623, 7449, 7456, 7450, 7453, + 7451, 7452, 7623, 7454, 7623, 7455, 7623, 7457, + 7458, 7459, 7623, 7461, 7623, 7463, 7464, 7623, + 7623, 7623, 7467, 7468, 7469, 7470, 7623, 7472, + 7473, 7623, 7475, 7483, 7487, 7489, 7496, 7497, + 7504, 7507, 7510, 7523, 7530, 7537, 7545, 7548, + 7476, 7478, 7481, 7477, 7623, 7479, 7480, 7623, + 7482, 7623, 7484, 7485, 7486, 7623, 7488, 7623, + 7490, 7493, 7491, 7492, 7623, 7494, 7495, 7623, + 7623, 7498, 7501, 7499, 7500, 7623, 7502, 7503, + 7623, 7505, 7506, 7623, 7508, 7509, 7623, 7511, + 7514, 7519, 7512, 7513, 7623, 7515, 7516, 7623, + 7517, 7518, 7623, 7520, 7521, 7522, 7623, 7524, + 7527, 7525, 7526, 7623, 7528, 7529, 7623, 7531, + 7533, 7532, 7623, 7534, 7535, 7536, 7623, 7538, + 7542, 7539, 7540, 7541, 7623, 7543, 7544, 7623, + 7546, 7547, 7623, 7549, 7550, 7551, 7552, 7623, + 7554, 7559, 7564, 7565, 7567, 7570, 7573, 7576, + 7555, 7556, 7558, 7557, 7727, 7623, 7560, 7563, + 7561, 7562, 7623, 7623, 7728, 7566, 7623, 7568, + 7569, 7623, 7571, 7572, 7623, 7574, 7575, 7623, + 7577, 7579, 7578, 7623, 7729, 7581, 7586, 7592, + 7595, 7602, 7604, 7607, 7613, 7616, 7619, 7582, + 7583, 7584, 7585, 7623, 7587, 7591, 7588, 7589, + 7590, 7623, 7623, 7593, 7594, 7623, 7596, 7600, + 7597, 7598, 7599, 7623, 7601, 7623, 7603, 7623, + 7605, 7606, 7623, 7608, 7609, 7610, 7611, 7612, + 7623, 7614, 7615, 7623, 7617, 7618, 7623, 7620, + 7621, 7623, 7622, 7623, 1, 69, 118, 332, + 656, 773, 827, 913, 979, 1076, 1098, 1123, + 1493, 1532, 2026, 2129, 2214, 2225, 2479, 2676, + 2770, 2946, 3016, 3033, 3043, 3073, 3114, 3250, + 3561, 3848, 4087, 4268, 4365, 4510, 4626, 4763, + 4789, 4820, 5311, 5421, 5853, 5992, 6169, 6205, + 6536, 6931, 7124, 7289, 7443, 7474, 7553, 7580, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 3620, 7623, 7623, 3729, 7623, 7623, + 7623, 7623, 7623, 7623, 3940, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 4454, + 4458, 4461, 4465, 4470, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 5259, 5263, 5266, 5270, + 5274, 5278, 5283, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 5636, 5646, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 5995, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7005, 7008, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623, + 7623, 7623, 7623, 7623, 7623, 7623, 7623, 7623 +}; + +static const short _char_ref_trans_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 0, 0, + 0, 0, 17, 0, 19, 0, 0, 0, + 0, 0, 0, 0, 23, 0, 0, 0, + 25, 0, 27, 0, 0, 0, 0, 29, + 0, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 37, 0, 0, 0, + 39, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 45, + 0, 0, 47, 0, 0, 49, 0, 51, + 0, 0, 0, 0, 0, 0, 0, 53, + 0, 0, 0, 0, 0, 0, 0, 55, + 0, 57, 0, 59, 0, 0, 61, 0, + 0, 0, 63, 0, 0, 65, 0, 0, + 0, 0, 67, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 73, 75, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 77, + 0, 0, 0, 0, 79, 0, 0, 0, + 0, 0, 0, 0, 81, 0, 0, 0, + 0, 0, 85, 0, 0, 0, 0, 87, + 0, 0, 89, 0, 0, 0, 0, 0, + 0, 91, 0, 0, 0, 0, 0, 0, + 93, 0, 95, 0, 97, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 99, + 0, 0, 0, 0, 101, 0, 0, 0, + 103, 0, 0, 0, 0, 105, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 107, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 109, 0, 0, 0, 0, 111, 0, 0, + 0, 0, 0, 0, 113, 0, 115, 0, + 0, 0, 0, 0, 0, 0, 0, 117, + 0, 0, 119, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 121, 0, + 0, 123, 0, 0, 0, 0, 0, 125, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 127, 0, 0, 0, + 129, 0, 0, 131, 0, 133, 0, 0, + 0, 135, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 137, 0, 0, + 0, 0, 0, 0, 139, 0, 0, 141, + 0, 0, 143, 0, 0, 145, 0, 0, + 0, 0, 0, 0, 147, 0, 149, 0, + 0, 151, 0, 0, 0, 0, 0, 153, + 155, 0, 157, 0, 0, 159, 0, 161, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 163, 0, 0, 0, 165, + 0, 0, 0, 0, 0, 0, 0, 0, + 167, 0, 0, 0, 0, 169, 0, 0, + 0, 0, 171, 0, 0, 0, 173, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 175, 0, 0, 0, 0, 0, 177, + 179, 0, 0, 0, 0, 181, 0, 0, + 0, 0, 183, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 185, 0, 0, 0, 187, 0, + 0, 0, 0, 0, 0, 189, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 193, 0, 0, 195, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 199, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 201, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 203, 0, 0, 205, 0, + 0, 0, 0, 0, 0, 0, 207, 0, + 0, 0, 0, 0, 0, 0, 0, 209, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 211, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 213, 0, + 0, 0, 0, 215, 0, 0, 0, 0, + 0, 0, 217, 0, 0, 0, 0, 219, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 221, 0, 0, 0, 0, 0, 0, 0, + 0, 223, 0, 0, 0, 0, 0, 225, + 0, 0, 0, 227, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, + 231, 0, 0, 0, 233, 0, 0, 235, + 0, 0, 0, 0, 0, 237, 0, 0, + 0, 0, 239, 0, 0, 0, 241, 0, + 0, 0, 243, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 245, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 251, 0, 0, 255, 0, 0, 257, 0, + 259, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 263, 0, 0, 0, 0, 265, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 267, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 271, 0, 273, 0, 0, 0, + 0, 0, 275, 0, 0, 0, 0, 277, + 0, 0, 0, 0, 0, 279, 0, 0, + 0, 0, 0, 0, 0, 281, 0, 0, + 0, 283, 0, 285, 0, 287, 0, 0, + 0, 0, 0, 0, 0, 291, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 293, + 0, 0, 0, 0, 0, 0, 295, 0, + 297, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 299, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 301, 0, 0, 0, 0, 303, 0, 0, + 0, 305, 0, 0, 0, 0, 0, 0, + 0, 307, 0, 0, 309, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 311, 0, 0, 0, 315, + 0, 317, 0, 0, 0, 0, 319, 0, + 0, 0, 0, 0, 0, 321, 0, 0, + 323, 325, 0, 0, 327, 0, 329, 331, + 0, 0, 333, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 335, 0, 0, 0, 0, 337, + 0, 0, 0, 0, 0, 0, 0, 0, + 339, 0, 0, 0, 0, 0, 0, 341, + 0, 0, 0, 343, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 345, 0, 0, + 0, 0, 347, 0, 0, 349, 351, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 353, 0, 0, 0, 0, + 355, 357, 0, 0, 0, 359, 0, 361, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 363, 0, 0, 0, 365, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 367, 0, 0, 0, 369, 0, + 0, 0, 371, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 373, 0, + 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 377, 0, 0, 0, + 379, 0, 0, 381, 0, 0, 0, 0, + 0, 0, 0, 0, 387, 0, 0, 389, + 0, 391, 0, 0, 0, 0, 395, 0, + 0, 0, 0, 0, 397, 0, 0, 0, + 0, 0, 0, 399, 0, 0, 0, 0, + 401, 0, 0, 403, 0, 0, 0, 0, + 0, 0, 405, 0, 0, 0, 0, 0, + 0, 0, 407, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 409, + 0, 0, 0, 0, 411, 0, 0, 0, + 0, 0, 413, 0, 415, 0, 417, 0, + 0, 419, 0, 0, 0, 0, 421, 0, + 0, 0, 0, 423, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 427, 429, + 0, 431, 0, 0, 433, 0, 0, 0, + 435, 0, 0, 0, 437, 0, 0, 0, + 439, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 441, 0, 0, 443, 0, 0, + 0, 445, 0, 0, 0, 0, 0, 447, + 449, 0, 451, 0, 0, 453, 0, 0, + 455, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 457, 0, + 0, 0, 0, 0, 0, 0, 0, 461, + 0, 0, 0, 463, 0, 465, 0, 0, + 0, 0, 0, 0, 0, 467, 0, 469, + 0, 0, 0, 0, 0, 0, 471, 0, + 0, 0, 473, 475, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 477, 0, 0, + 0, 479, 0, 0, 0, 0, 481, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 483, 0, 0, 0, 0, 0, 0, 485, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 487, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 489, 0, 0, 0, 0, 0, 491, + 0, 0, 0, 493, 0, 0, 0, 0, + 495, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 497, 0, 0, 0, 0, + 0, 499, 0, 0, 0, 501, 0, 0, + 0, 0, 0, 0, 503, 0, 0, 0, + 0, 0, 505, 0, 0, 0, 0, 0, + 0, 507, 0, 0, 0, 0, 509, 0, + 0, 0, 0, 511, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 513, 0, 0, 0, 0, 0, 0, + 0, 0, 515, 0, 0, 0, 0, 0, + 517, 0, 0, 0, 519, 0, 0, 0, + 0, 0, 521, 0, 0, 0, 523, 0, + 0, 0, 0, 525, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 527, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 529, 0, 0, 0, 0, 0, 0, 0, + 0, 531, 0, 0, 0, 0, 0, 0, + 533, 0, 0, 0, 535, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 537, 0, + 0, 0, 0, 539, 0, 541, 543, 0, + 0, 0, 0, 0, 0, 0, 0, 545, + 0, 0, 0, 0, 547, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 549, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 551, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 553, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 555, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 557, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 559, 0, 561, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 563, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 565, 0, 0, 0, 0, 567, 569, + 0, 0, 0, 571, 573, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 575, 0, + 577, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 579, 0, 0, 0, 0, + 0, 0, 581, 0, 583, 0, 0, 0, + 0, 0, 0, 0, 585, 0, 0, 587, + 0, 0, 589, 591, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 593, + 0, 0, 0, 0, 595, 0, 0, 0, + 0, 0, 0, 597, 0, 0, 0, 599, + 601, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 603, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 605, 0, 0, 0, 0, 0, 607, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 609, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 611, + 0, 0, 0, 0, 0, 0, 0, 613, + 0, 0, 0, 0, 615, 0, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 619, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 621, 0, 623, + 625, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 627, 0, + 0, 0, 0, 629, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 631, 0, 0, 0, + 0, 0, 0, 0, 0, 633, 0, 0, + 0, 635, 0, 0, 0, 0, 0, 637, + 0, 0, 0, 0, 639, 0, 0, 0, + 0, 0, 0, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 643, 0, + 0, 0, 0, 0, 0, 0, 0, 645, + 0, 0, 0, 0, 0, 0, 647, 0, + 0, 0, 649, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 651, 0, 0, 0, + 0, 653, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 655, 0, + 0, 0, 0, 657, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 659, 0, 0, 0, 0, 661, 0, 0, + 0, 0, 663, 0, 665, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 667, 0, + 0, 0, 0, 0, 0, 669, 0, 0, + 0, 671, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 673, 0, 0, 0, 0, + 675, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 677, 0, 0, + 0, 0, 0, 0, 0, 679, 0, 0, + 0, 0, 0, 0, 0, 681, 0, 0, + 0, 0, 0, 0, 683, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 687, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 689, 0, 0, 0, 0, 691, 0, + 0, 0, 0, 693, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 695, 0, 0, 0, 0, 0, 697, + 0, 0, 0, 0, 0, 699, 0, 0, + 0, 0, 0, 701, 0, 0, 0, 0, + 0, 0, 703, 0, 0, 0, 0, 0, + 705, 0, 0, 0, 0, 0, 707, 0, + 0, 0, 0, 0, 0, 0, 709, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 711, 0, 0, 0, 0, 713, 0, 0, + 0, 0, 0, 715, 0, 0, 0, 0, + 0, 717, 0, 0, 0, 0, 719, 0, + 0, 0, 0, 0, 0, 0, 721, 0, + 0, 0, 0, 0, 0, 0, 0, 723, + 0, 0, 0, 0, 725, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 727, + 0, 0, 729, 0, 0, 0, 0, 733, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 735, 0, 0, 0, 0, 0, 0, + 0, 0, 741, 0, 0, 0, 0, 743, + 0, 745, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 749, 0, 0, 751, 0, + 0, 0, 0, 753, 0, 0, 755, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 757, 0, 0, 0, 0, 759, + 761, 0, 0, 0, 763, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 769, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 773, 0, 0, 0, 0, 775, 0, + 0, 777, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 779, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 781, 0, 783, 0, + 785, 0, 787, 789, 0, 0, 0, 0, + 0, 0, 0, 791, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 793, 0, 795, 797, 0, 0, 0, 0, + 0, 0, 0, 0, 799, 0, 0, 0, + 0, 0, 0, 0, 801, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 803, 0, + 0, 0, 0, 805, 0, 0, 807, 0, + 0, 0, 0, 0, 809, 0, 0, 0, + 0, 0, 0, 811, 0, 0, 813, 0, + 0, 0, 815, 817, 0, 0, 0, 0, + 0, 0, 0, 821, 0, 0, 823, 0, + 0, 825, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 827, 0, 0, 0, 0, 0, 0, + 0, 831, 0, 833, 0, 835, 0, 0, + 837, 0, 0, 0, 0, 0, 0, 839, + 0, 0, 0, 841, 843, 845, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 847, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 849, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 851, 0, 853, 0, 855, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 857, + 0, 0, 0, 859, 0, 0, 0, 0, + 861, 0, 0, 0, 0, 0, 0, 0, + 0, 863, 0, 0, 0, 0, 0, 0, + 865, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 867, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 869, 0, 0, 0, 0, 0, + 871, 0, 0, 0, 873, 0, 0, 0, + 0, 875, 0, 0, 0, 877, 0, 0, + 0, 0, 0, 0, 879, 0, 0, 0, + 0, 0, 881, 0, 0, 0, 0, 0, + 0, 883, 0, 0, 0, 0, 885, 0, + 0, 0, 0, 887, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 889, 0, 0, 0, 0, 0, 0, + 0, 0, 891, 0, 0, 0, 0, 0, + 893, 0, 0, 0, 895, 0, 0, 0, + 0, 0, 897, 0, 0, 0, 899, 0, + 0, 0, 0, 901, 0, 0, 0, 903, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 905, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 907, 0, 0, 0, 909, + 911, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 913, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 915, 0, 917, + 0, 0, 0, 0, 919, 0, 0, 0, + 0, 921, 923, 0, 0, 0, 0, 0, + 0, 0, 925, 0, 0, 0, 927, 0, + 0, 929, 931, 0, 933, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 935, 0, 0, 0, + 0, 0, 0, 0, 0, 937, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 939, + 0, 0, 0, 0, 0, 0, 941, 0, + 0, 0, 943, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 945, 0, 0, 947, + 0, 0, 0, 949, 0, 0, 0, 951, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 953, 0, + 0, 0, 0, 0, 0, 955, 0, 0, + 0, 0, 0, 957, 0, 0, 0, 0, + 0, 959, 0, 0, 0, 0, 0, 961, + 0, 0, 0, 0, 963, 0, 0, 965, + 0, 0, 967, 0, 0, 0, 0, 969, + 0, 0, 0, 971, 0, 0, 0, 0, + 0, 973, 0, 0, 0, 0, 0, 0, + 975, 0, 0, 0, 0, 0, 0, 0, + 977, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 979, 0, 0, 0, 0, 981, + 0, 0, 0, 0, 983, 985, 987, 0, + 0, 0, 0, 0, 0, 989, 0, 0, + 0, 0, 0, 991, 0, 0, 993, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 997, 0, 0, 0, 0, 999, 0, 1001, + 0, 0, 1003, 1005, 0, 0, 0, 0, + 0, 0, 1007, 0, 0, 0, 1009, 1011, + 0, 1013, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1015, 0, 1017, 0, 0, + 0, 0, 0, 0, 0, 0, 1019, 0, + 0, 0, 0, 0, 1021, 0, 0, 0, + 1023, 0, 0, 0, 0, 0, 0, 0, + 1025, 0, 0, 0, 0, 0, 0, 0, + 0, 1027, 0, 0, 0, 0, 1029, 0, + 0, 1031, 0, 0, 0, 0, 0, 0, + 0, 1033, 0, 0, 0, 1035, 0, 0, + 0, 1037, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1041, 0, + 0, 0, 0, 1043, 0, 0, 0, 0, + 1045, 0, 0, 1047, 0, 0, 0, 0, + 1051, 0, 0, 0, 0, 1053, 0, 1055, + 0, 0, 0, 0, 0, 0, 0, 1059, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1061, 0, 0, 0, 0, 1063, 0, + 0, 1065, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1067, 0, 0, 1069, + 0, 0, 0, 0, 1071, 0, 0, 0, + 0, 1073, 0, 1075, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1077, 0, 0, 0, 0, 1079, 0, 0, + 0, 0, 0, 0, 0, 0, 1081, 0, + 0, 0, 0, 0, 0, 0, 0, 1083, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1085, 0, 0, 1087, 0, 0, + 0, 0, 0, 1089, 0, 0, 0, 0, + 1091, 0, 0, 0, 0, 0, 0, 0, + 0, 1093, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1095, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1097, 0, 1099, 0, 0, 0, 1101, 0, + 0, 0, 1103, 0, 0, 1105, 0, 0, + 0, 0, 1107, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1111, 0, 0, 1113, 0, 1115, 0, + 0, 0, 1117, 0, 1119, 0, 0, 1121, + 0, 0, 0, 0, 0, 1123, 1125, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1127, 0, 0, 0, 1129, 0, 0, + 0, 0, 0, 0, 0, 0, 1131, 0, + 0, 0, 0, 1133, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1135, 0, 1137, + 0, 0, 1139, 0, 0, 1141, 0, 0, + 0, 0, 1143, 0, 0, 0, 0, 0, + 0, 0, 0, 1145, 0, 0, 0, 1147, + 0, 1149, 0, 0, 1151, 0, 0, 1153, + 0, 0, 0, 0, 0, 1155, 1157, 0, + 0, 1159, 0, 0, 1161, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1163, 0, 0, 1165, 0, 0, 1167, 0, + 0, 0, 0, 0, 0, 0, 0, 1171, + 1173, 0, 1175, 0, 0, 1177, 0, 0, + 1179, 0, 0, 1181, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1183, 0, + 0, 0, 0, 1185, 0, 0, 0, 0, + 0, 1187, 1189, 0, 0, 1191, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1193, 0, 1195, 0, 1197, + 0, 0, 1199, 0, 0, 1201, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1205, 1207, + 0, 0, 0, 0, 0, 1209, 1211, 0, + 0, 0, 0, 1217, 0, 0, 0, 1221, + 0, 1223, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1227, 0, 1229, + 0, 0, 1231, 0, 0, 0, 0, 0, + 1233, 0, 1235, 0, 0, 1239, 0, 0, + 0, 0, 0, 0, 1241, 1243, 0, 0, + 0, 0, 1245, 1247, 1249, 0, 0, 0, + 0, 0, 0, 1251, 0, 1253, 0, 0, + 1255, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1257, 1259, 1261, 1263, 1265, 1267, + 1269, 1271, 0, 1273, 0, 0, 1275, 0, + 1277, 0, 0, 0, 1279, 1281, 0, 0, + 0, 1283, 0, 0, 0, 0, 1285, 0, + 1287, 1289, 0, 0, 0, 0, 0, 0, + 1291, 0, 0, 0, 1293, 1295, 0, 1297, + 0, 1299, 0, 0, 0, 1301, 0, 0, + 1303, 0, 0, 0, 0, 0, 0, 0, + 1307, 1309, 0, 0, 1311, 0, 0, 1313, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1319, 0, 0, + 1321, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1323, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1325, 0, + 0, 0, 0, 0, 0, 1327, 0, 0, + 0, 0, 1329, 0, 0, 1331, 0, 0, + 1333, 0, 0, 0, 0, 1335, 0, 0, + 1337, 0, 0, 1339, 0, 0, 1341, 0, + 0, 0, 0, 1343, 0, 0, 0, 0, + 1345, 1347, 0, 0, 0, 1349, 0, 0, + 0, 0, 0, 0, 0, 0, 1351, 0, + 1353, 0, 0, 0, 0, 1355, 0, 0, + 1357, 0, 0, 0, 1359, 0, 0, 0, + 1361, 1363, 0, 0, 0, 1365, 0, 1367, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1369, 0, 0, 1371, + 0, 1373, 0, 0, 0, 0, 0, 1375, + 0, 0, 0, 1377, 0, 0, 0, 0, + 1379, 0, 0, 0, 0, 0, 1381, 0, + 0, 1383, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1385, 0, + 1387, 0, 0, 0, 0, 1389, 0, 0, + 1391, 0, 0, 0, 0, 1393, 0, 0, + 0, 0, 1395, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1397, 0, 0, 0, 0, 0, + 1399, 0, 0, 0, 0, 0, 0, 0, + 1401, 0, 0, 0, 0, 0, 0, 1403, + 0, 0, 0, 1405, 0, 0, 0, 0, + 1407, 0, 1409, 0, 0, 0, 0, 1411, + 1413, 0, 1415, 0, 0, 1417, 0, 0, + 1419, 0, 0, 0, 0, 1421, 0, 1423, + 0, 0, 0, 0, 0, 1425, 1427, 0, + 0, 0, 1429, 0, 0, 0, 1431, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1433, + 1435, 1437, 1439, 1441, 0, 0, 0, 0, + 1443, 1445, 1447, 1449, 0, 0, 0, 0, + 1451, 1453, 1455, 1457, 1459, 0, 0, 0, + 0, 0, 0, 1461, 1463, 1465, 1467, 1469, + 1471, 0, 0, 1473, 0, 0, 0, 0, + 1475, 1477, 1479, 1481, 1483, 0, 0, 0, + 0, 1485, 1487, 1489, 1491, 0, 0, 0, + 0, 1493, 0, 0, 0, 1495, 0, 0, + 0, 0, 1497, 0, 0, 0, 0, 1499, + 1501, 1503, 1505, 1507, 0, 0, 0, 0, + 0, 0, 1509, 1511, 1513, 1515, 1517, 1519, + 0, 0, 0, 0, 1521, 0, 0, 0, + 0, 1523, 0, 0, 0, 0, 0, 0, + 0, 0, 1527, 0, 0, 1529, 0, 1531, + 0, 1533, 0, 1535, 0, 0, 1537, 0, + 0, 0, 1539, 0, 0, 0, 1541, 0, + 0, 1543, 0, 1545, 0, 0, 1547, 1549, + 0, 1551, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1553, + 1555, 0, 0, 0, 0, 0, 0, 0, + 1557, 0, 0, 0, 0, 1559, 0, 0, + 0, 1561, 0, 1563, 0, 0, 1565, 1567, + 0, 0, 0, 1569, 0, 1571, 0, 0, + 0, 0, 0, 0, 0, 1573, 0, 0, + 1575, 0, 0, 0, 0, 0, 1579, 0, + 0, 1581, 0, 0, 1583, 0, 0, 1585, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1589, 5, 4469, 0, 0, 0, 0, + 1593, 0, 1595, 0, 0, 0, 0, 1597, + 0, 0, 1599, 0, 0, 0, 0, 1601, + 1603, 0, 1605, 0, 0, 0, 0, 0, + 0, 1607, 1609, 0, 0, 0, 1611, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1613, 0, 0, 0, 0, + 1615, 0, 0, 0, 0, 0, 1617, 1619, + 0, 0, 1621, 0, 0, 0, 1623, 0, + 0, 0, 1625, 1627, 0, 0, 0, 0, + 1629, 0, 0, 1631, 0, 0, 0, 1633, + 0, 0, 0, 1635, 0, 0, 0, 1637, + 0, 0, 0, 0, 0, 0, 1639, 0, + 1641, 0, 1643, 0, 0, 0, 1645, 0, + 1647, 1649, 0, 0, 0, 1651, 0, 0, + 0, 0, 0, 0, 1653, 0, 0, 1655, + 0, 0, 1657, 0, 0, 0, 1659, 0, + 0, 1661, 0, 0, 5, 1663, 0, 0, + 1665, 4471, 0, 1669, 0, 0, 0, 0, + 1671, 0, 0, 1673, 0, 0, 0, 1675, + 0, 0, 1677, 0, 1679, 1681, 0, 1683, + 0, 0, 0, 1685, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1687, 1689, 0, 0, 0, 1691, 0, 1693, + 0, 0, 0, 1695, 0, 1697, 1699, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1701, 0, 0, 0, 1703, 0, 1705, 0, + 0, 1707, 0, 1709, 1711, 0, 0, 0, + 0, 0, 0, 1713, 0, 1715, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1717, 0, 0, 0, 1719, 0, 0, 1721, + 0, 0, 0, 0, 1723, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1727, 0, 0, 0, 0, 1729, + 0, 0, 1731, 0, 0, 1733, 0, 0, + 0, 0, 0, 0, 0, 1735, 0, 0, + 1737, 0, 0, 0, 0, 1739, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1741, 0, 0, 1743, 0, + 0, 0, 0, 0, 0, 0, 1745, 0, + 0, 0, 1747, 0, 1749, 0, 1751, 0, + 1753, 0, 0, 0, 0, 0, 0, 1755, + 0, 0, 1757, 0, 0, 0, 0, 0, + 1759, 1761, 1763, 0, 0, 0, 0, 0, + 0, 0, 1765, 0, 1767, 0, 0, 0, + 0, 1769, 0, 0, 0, 0, 0, 1773, + 0, 0, 0, 0, 1775, 0, 0, 0, + 0, 0, 1777, 1779, 0, 0, 0, 0, + 1781, 1783, 0, 0, 0, 0, 0, 0, + 1785, 0, 0, 0, 0, 1787, 0, 0, + 0, 0, 1789, 1791, 1793, 0, 0, 0, + 0, 1795, 0, 0, 1797, 1799, 0, 0, + 0, 5, 4473, 0, 0, 0, 0, 0, + 0, 1803, 0, 0, 1805, 0, 0, 1807, + 0, 0, 0, 0, 0, 1809, 0, 0, + 1811, 0, 0, 0, 0, 0, 0, 0, + 0, 1813, 0, 1815, 1817, 0, 0, 0, + 0, 0, 1819, 0, 0, 0, 1821, 0, + 0, 0, 0, 1823, 0, 0, 0, 1825, + 0, 0, 0, 0, 0, 1827, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1829, 0, 0, 0, 0, 0, 0, + 0, 0, 1831, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1833, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1835, 0, 0, 0, 0, 1837, 0, 0, + 0, 0, 0, 0, 0, 1839, 0, 0, + 0, 0, 1841, 0, 0, 1843, 0, 0, + 0, 0, 0, 1845, 1847, 0, 1849, 0, + 0, 0, 1851, 0, 0, 0, 0, 1853, + 0, 1855, 0, 1857, 0, 0, 0, 0, + 1859, 0, 0, 1861, 0, 0, 0, 0, + 0, 1863, 0, 0, 0, 1865, 0, 0, + 0, 0, 0, 1867, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1869, 0, 1871, 0, 0, 0, + 0, 0, 0, 0, 0, 1875, 0, 0, + 0, 0, 0, 0, 0, 1877, 0, 1879, + 0, 0, 0, 0, 1883, 1885, 0, 0, + 1887, 1889, 0, 0, 0, 0, 1891, 1893, + 1895, 0, 0, 0, 0, 0, 1899, 0, + 0, 0, 1901, 1903, 0, 0, 0, 0, + 0, 0, 0, 0, 1905, 1907, 1909, 0, + 0, 0, 1911, 0, 0, 0, 0, 0, + 1913, 0, 0, 1915, 0, 0, 0, 0, + 1917, 1919, 0, 0, 1925, 0, 0, 1921, + 1923, 0, 0, 1927, 0, 1929, 0, 0, + 0, 0, 1931, 0, 1933, 0, 0, 0, + 0, 1935, 0, 0, 1937, 0, 0, 1939, + 0, 1941, 0, 0, 0, 0, 1943, 1945, + 0, 0, 0, 0, 0, 0, 0, 0, + 1947, 0, 0, 0, 1949, 0, 0, 0, + 1951, 0, 0, 0, 0, 0, 0, 0, + 1953, 0, 0, 0, 1955, 0, 0, 0, + 0, 0, 1957, 0, 0, 1959, 0, 1961, + 0, 0, 1963, 0, 0, 0, 0, 0, + 1965, 0, 0, 0, 0, 1967, 0, 0, + 1969, 0, 0, 0, 0, 1971, 0, 0, + 1973, 0, 1975, 0, 0, 1977, 0, 0, + 0, 0, 1983, 0, 0, 0, 0, 1985, + 0, 0, 1987, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1989, 0, 0, 0, + 0, 0, 0, 0, 0, 1991, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1993, 0, 1995, + 0, 0, 0, 0, 1997, 0, 0, 0, + 0, 0, 0, 1999, 0, 0, 0, 2001, + 0, 0, 2003, 2005, 0, 0, 0, 2007, + 0, 0, 0, 2009, 0, 0, 0, 0, + 2011, 0, 0, 2013, 0, 0, 2015, 0, + 0, 2017, 0, 0, 0, 2019, 0, 0, + 0, 0, 2021, 2023, 0, 2025, 0, 0, + 0, 0, 0, 0, 2027, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2031, 2035, 2037, + 2039, 0, 0, 2041, 2043, 0, 0, 0, + 2047, 2049, 0, 2051, 0, 0, 2053, 2055, + 0, 2057, 0, 2059, 0, 0, 2061, 0, + 0, 2063, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 0, 2065, 0, 2067, 0, 0, + 0, 0, 0, 0, 2069, 0, 0, 2071, + 0, 2073, 2075, 0, 0, 0, 0, 2077, + 0, 0, 0, 0, 2079, 2081, 0, 0, + 2083, 2085, 0, 0, 0, 2087, 2089, 0, + 0, 2091, 0, 0, 0, 0, 2093, 2095, + 0, 0, 0, 0, 2097, 0, 0, 2099, + 0, 2101, 0, 2103, 2105, 0, 0, 2107, + 0, 2109, 2111, 0, 2113, 0, 0, 0, + 2115, 0, 0, 2117, 2119, 0, 0, 0, + 2121, 2123, 2125, 0, 0, 0, 0, 2127, + 0, 2129, 0, 0, 0, 0, 2131, 2133, + 0, 2135, 0, 2137, 0, 0, 2139, 0, + 0, 2141, 0, 0, 0, 2143, 0, 0, + 0, 2145, 0, 2147, 0, 0, 2149, 2151, + 4475, 0, 0, 2155, 0, 2157, 0, 0, + 2159, 0, 0, 0, 2161, 0, 0, 0, + 0, 2163, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2165, 0, 2167, + 0, 0, 2169, 0, 0, 0, 0, 0, + 0, 2171, 0, 0, 0, 0, 2173, 0, + 0, 0, 2175, 0, 0, 2177, 0, 0, + 0, 0, 0, 0, 0, 0, 2179, 0, + 2181, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2183, 0, 0, + 0, 0, 0, 0, 0, 2185, 0, 2187, + 0, 0, 0, 2189, 0, 0, 0, 0, + 2191, 2193, 0, 0, 0, 0, 2195, 2197, + 0, 0, 2199, 0, 0, 0, 2201, 0, + 0, 0, 0, 0, 0, 2203, 0, 0, + 0, 2205, 0, 0, 0, 2207, 0, 0, + 0, 2209, 0, 2211, 0, 0, 0, 0, + 0, 0, 0, 2213, 0, 0, 0, 0, + 2215, 0, 0, 0, 0, 0, 0, 0, + 2217, 0, 0, 0, 2219, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2221, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2223, 0, 2225, 0, 0, 0, + 2227, 0, 0, 0, 0, 2229, 0, 0, + 0, 2231, 0, 0, 0, 2233, 0, 0, + 0, 0, 0, 2235, 0, 0, 0, 2237, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2241, 0, 0, 0, 0, + 2245, 0, 0, 0, 2247, 0, 0, 0, + 0, 2251, 2253, 0, 0, 0, 0, 2257, + 0, 0, 0, 0, 0, 0, 0, 2259, + 0, 2261, 0, 0, 0, 2263, 0, 0, + 2265, 0, 0, 0, 2267, 0, 0, 0, + 0, 0, 0, 0, 2269, 0, 0, 0, + 2271, 0, 0, 0, 2273, 0, 0, 0, + 2275, 0, 2277, 0, 2279, 0, 0, 2281, + 2283, 0, 0, 0, 0, 0, 0, 0, + 2285, 0, 0, 2287, 0, 0, 0, 2289, + 0, 0, 0, 2291, 2293, 0, 0, 0, + 0, 0, 0, 2295, 0, 0, 0, 0, + 0, 2297, 0, 0, 0, 2299, 0, 0, + 0, 0, 2301, 0, 0, 0, 2303, 0, + 0, 0, 0, 0, 2305, 0, 0, 2307, + 0, 2309, 0, 2311, 0, 0, 0, 2313, + 0, 0, 0, 0, 0, 0, 0, 2317, + 0, 2319, 0, 0, 0, 0, 2321, 0, + 0, 2323, 2325, 0, 2327, 2329, 2331, 0, + 0, 0, 0, 2333, 0, 0, 0, 0, + 2335, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2339, 2341, 0, 2343, + 0, 0, 0, 2345, 0, 0, 2347, 0, + 0, 0, 2349, 0, 0, 0, 2351, 0, + 0, 0, 2353, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2355, 0, + 2357, 0, 0, 0, 0, 0, 2359, 2361, + 0, 2363, 0, 0, 0, 0, 2365, 0, + 0, 2367, 0, 0, 2369, 0, 0, 2371, + 0, 0, 2373, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 2375, + 0, 2377, 0, 0, 0, 2379, 0, 0, + 0, 2381, 2383, 0, 2385, 0, 0, 2387, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2389, 0, 0, 0, + 0, 0, 2391, 0, 0, 0, 2393, 0, + 0, 0, 2395, 0, 2397, 0, 0, 2399, + 0, 2401, 2403, 0, 0, 0, 2407, 0, + 0, 0, 0, 0, 0, 0, 2409, 0, + 0, 2411, 0, 2413, 0, 2415, 0, 2417, + 0, 2419, 0, 0, 2421, 0, 2423, 2425, + 0, 0, 0, 0, 2427, 2429, 0, 2431, + 0, 0, 0, 0, 0, 2433, 0, 0, + 2435, 0, 0, 0, 0, 0, 2437, 2439, + 0, 0, 2441, 0, 0, 0, 2443, 2445, + 0, 0, 0, 0, 0, 0, 0, 2447, + 0, 0, 0, 0, 2449, 0, 2451, 0, + 2453, 2455, 0, 0, 0, 0, 0, 2457, + 0, 0, 2459, 0, 2461, 0, 0, 0, + 0, 0, 2463, 0, 0, 0, 0, 2465, + 0, 2467, 2469, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2471, 0, 0, 0, 0, 2473, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2475, 0, 2477, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2479, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2481, 0, 2483, 0, 0, 0, + 0, 0, 0, 0, 2485, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2487, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2489, 2491, 2493, 0, 0, 2495, 0, 0, + 0, 0, 2497, 2499, 0, 0, 0, 0, + 0, 2501, 0, 0, 2503, 0, 2505, 0, + 2507, 2509, 0, 0, 2511, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2513, + 0, 0, 2515, 0, 0, 0, 0, 0, + 2517, 0, 0, 0, 2519, 0, 0, 2521, + 0, 0, 2523, 0, 0, 0, 0, 0, + 0, 2525, 0, 0, 0, 2527, 2529, 2531, + 0, 2533, 0, 0, 0, 0, 0, 2535, + 2537, 0, 2539, 0, 0, 2541, 0, 0, + 2543, 2545, 0, 0, 0, 0, 0, 0, + 2547, 0, 0, 0, 0, 0, 2549, 0, + 0, 0, 2551, 0, 0, 2553, 0, 0, + 0, 0, 0, 2555, 0, 0, 0, 2557, + 0, 0, 0, 0, 2559, 0, 0, 0, + 0, 2561, 0, 2563, 0, 0, 0, 0, + 2565, 2567, 0, 2569, 0, 2571, 0, 0, + 2573, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2575, 0, 2577, 0, + 0, 2579, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2581, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2583, 0, 0, 0, 0, 0, 2585, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2587, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2589, 0, 0, + 0, 0, 2591, 0, 0, 0, 0, 2593, + 2595, 0, 0, 2597, 0, 0, 0, 0, + 2599, 0, 0, 0, 0, 2601, 0, 0, + 2603, 2605, 0, 0, 0, 0, 0, 2607, + 2609, 0, 0, 2611, 0, 0, 2613, 0, + 0, 0, 0, 0, 0, 0, 2615, 0, + 0, 0, 0, 0, 2617, 0, 0, 2619, + 0, 2621, 2623, 0, 0, 2625, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2627, + 0, 2629, 2631, 0, 2633, 0, 0, 2635, + 2637, 0, 0, 2639, 0, 2641, 0, 2643, + 0, 0, 0, 2645, 4477, 0, 0, 2649, + 0, 2651, 0, 0, 2653, 0, 0, 0, + 2655, 0, 0, 0, 2657, 0, 0, 0, + 2659, 0, 0, 0, 0, 2661, 0, 0, + 0, 0, 2663, 2665, 0, 0, 2667, 2669, + 0, 0, 0, 0, 0, 0, 0, 2671, + 0, 0, 0, 2673, 0, 0, 0, 0, + 0, 0, 0, 0, 2675, 0, 2677, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2679, 0, 0, 0, 0, 0, 0, 0, + 2683, 2685, 0, 0, 0, 2687, 2689, 0, + 0, 0, 2691, 0, 0, 0, 0, 0, + 0, 2693, 0, 0, 0, 2695, 0, 2697, + 0, 0, 0, 2699, 0, 0, 0, 0, + 0, 2701, 2703, 0, 0, 0, 2705, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2707, 0, 2709, 0, 2711, 0, + 0, 0, 0, 0, 2715, 0, 0, 0, + 0, 0, 2717, 0, 0, 2719, 0, 0, + 0, 0, 2723, 0, 0, 2725, 2727, 0, + 2729, 0, 0, 0, 2731, 0, 2733, 0, + 0, 0, 0, 2735, 0, 0, 0, 0, + 0, 2737, 0, 2739, 2741, 0, 0, 0, + 2743, 0, 0, 0, 2745, 2747, 0, 0, + 0, 0, 0, 0, 0, 2749, 0, 0, + 2751, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2753, 2755, 0, 2757, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2759, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2761, 2763, 2765, 0, + 2767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2769, 0, 0, 0, 0, 0, + 2771, 0, 0, 0, 2773, 0, 0, 0, + 0, 0, 0, 0, 2775, 0, 0, 0, + 2777, 0, 2779, 2781, 0, 0, 0, 0, + 2783, 0, 2785, 0, 2787, 0, 0, 0, + 2789, 0, 0, 2791, 0, 0, 2793, 0, + 2795, 0, 0, 0, 0, 0, 2799, 0, + 2801, 0, 0, 0, 0, 0, 0, 0, + 2803, 0, 0, 2805, 0, 0, 0, 2807, + 0, 0, 2809, 0, 0, 0, 2811, 0, + 2813, 2815, 0, 0, 0, 2817, 2819, 0, + 0, 0, 0, 0, 0, 0, 0, 2821, + 0, 0, 0, 0, 2823, 2825, 0, 0, + 2827, 0, 0, 2829, 0, 0, 0, 2831, + 0, 0, 0, 0, 2833, 0, 2835, 0, + 0, 0, 2837, 0, 2839, 0, 2841, 0, + 0, 0, 0, 2843, 2845, 0, 0, 2847, + 0, 0, 2849, 0, 0, 0, 0, 2851, + 2853, 0, 0, 2855, 2857, 0, 2859, 0, + 0, 0, 0, 0, 2861, 0, 0, 2863, + 0, 0, 2865, 2867, 0, 0, 2869, 0, + 2871, 2873, 0, 0, 2875, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2877, 2879, + 0, 0, 2881, 0, 2883, 2885, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2887, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2889, 2891, 0, 0, 2893, 0, + 0, 0, 0, 2895, 2897, 0, 2899, 0, + 0, 2901, 2903, 0, 0, 2905, 0, 2907, + 0, 0, 2909, 0, 5, 0, 2911, 4479, + 0, 2915, 0, 0, 0, 2917, 0, 0, + 2919, 0, 0, 0, 2921, 2923, 2925, 0, + 2927, 0, 0, 0, 0, 2929, 2931, 2933, + 0, 0, 0, 0, 2935, 0, 0, 0, + 0, 0, 0, 0, 2937, 0, 2939, 2941, + 0, 0, 0, 0, 2943, 2945, 0, 0, + 0, 0, 2947, 2949, 0, 2951, 0, 0, + 2953, 0, 0, 0, 0, 0, 0, 2955, + 0, 0, 2957, 0, 0, 2959, 2961, 0, + 0, 0, 0, 0, 0, 0, 0, 2963, + 0, 0, 2965, 0, 2967, 0, 0, 0, + 0, 0, 0, 0, 2969, 0, 0, 0, + 0, 0, 2971, 2973, 2975, 0, 0, 0, + 0, 0, 0, 0, 2977, 0, 0, 0, + 0, 0, 0, 0, 2979, 0, 2981, 0, + 2983, 0, 2985, 0, 0, 2987, 0, 0, + 2989, 0, 0, 0, 0, 0, 2991, 0, + 2993, 0, 0, 0, 2995, 0, 0, 0, + 2997, 2999, 0, 0, 3001, 0, 0, 3003, + 0, 3005, 0, 3007, 0, 0, 3009, 3011, + 0, 0, 0, 3013, 3015, 0, 0, 3017, + 0, 0, 3019, 0, 3021, 0, 0, 0, + 0, 0, 3023, 0, 0, 0, 0, 3027, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3029, 0, 0, 3031, 0, + 0, 0, 0, 3033, 0, 0, 3035, 3037, + 0, 3039, 0, 0, 0, 0, 3041, 0, + 3043, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3045, 0, 0, + 0, 3047, 0, 3049, 0, 0, 0, 3051, + 0, 0, 3053, 3055, 0, 0, 0, 0, + 3057, 0, 0, 0, 0, 0, 3059, 3061, + 3063, 0, 0, 0, 3065, 0, 0, 0, + 0, 3067, 0, 0, 0, 3069, 0, 0, + 3071, 0, 0, 0, 0, 0, 3073, 0, + 0, 0, 0, 3075, 3077, 0, 0, 3079, + 0, 0, 0, 3081, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3083, 0, + 0, 0, 0, 0, 0, 3087, 0, 0, + 0, 3089, 0, 3093, 0, 0, 0, 0, + 0, 0, 0, 3095, 0, 0, 0, 3097, + 0, 3099, 0, 3101, 0, 0, 0, 3103, + 0, 0, 0, 3105, 0, 0, 0, 0, + 3107, 3109, 0, 0, 0, 0, 3111, 0, + 0, 0, 3115, 0, 0, 0, 0, 3117, + 3119, 0, 0, 3121, 0, 0, 0, 0, + 0, 0, 3123, 0, 0, 0, 3125, 0, + 0, 0, 3127, 0, 0, 3129, 3131, 0, + 0, 0, 0, 0, 3133, 0, 0, 3135, + 0, 0, 0, 0, 0, 0, 3137, 3139, + 0, 0, 3141, 0, 0, 3143, 0, 0, + 0, 0, 3145, 0, 0, 3147, 0, 0, + 3149, 3151, 0, 0, 0, 0, 0, 0, + 0, 0, 3153, 3155, 0, 0, 0, 0, + 3157, 0, 0, 3159, 0, 0, 0, 3165, + 0, 3167, 0, 0, 0, 0, 3169, 3171, + 0, 0, 0, 0, 3173, 0, 0, 0, + 0, 3177, 0, 0, 0, 0, 0, 0, + 0, 3181, 0, 0, 3183, 0, 0, 0, + 0, 0, 3187, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3189, 5, 0, 0, 4481, 0, 0, 0, + 3193, 0, 0, 0, 3195, 3197, 3199, 0, + 3201, 0, 0, 0, 0, 0, 0, 0, + 0, 3203, 0, 0, 3205, 0, 0, 3207, + 3209, 0, 0, 0, 3211, 0, 3213, 0, + 0, 0, 3215, 0, 3217, 0, 0, 0, + 3219, 0, 0, 3221, 3223, 0, 0, 0, + 0, 0, 0, 0, 0, 3225, 3227, 0, + 0, 0, 0, 0, 0, 3229, 0, 3231, + 0, 3233, 0, 3235, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3237, + 3239, 0, 0, 3241, 0, 0, 3243, 3245, + 3247, 0, 0, 0, 3251, 0, 0, 3253, + 3255, 0, 0, 0, 0, 0, 0, 0, + 0, 3257, 0, 3259, 0, 0, 3263, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3265, 0, 3267, 0, 0, 3269, 3271, 0, + 3273, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3275, 0, 0, 0, 0, + 0, 0, 3277, 0, 3279, 0, 0, 0, + 0, 0, 0, 0, 0, 3281, 0, 0, + 3283, 0, 0, 3285, 0, 0, 3287, 0, + 0, 3289, 0, 3291, 0, 0, 0, 3293, + 0, 3295, 0, 0, 3297, 0, 0, 0, + 3299, 0, 0, 0, 0, 0, 0, 3301, + 0, 0, 0, 3303, 0, 0, 0, 3305, + 3307, 0, 0, 3309, 0, 0, 3311, 0, + 0, 0, 3313, 0, 0, 0, 3315, 3317, + 0, 0, 0, 0, 3319, 0, 0, 0, + 0, 0, 0, 0, 3321, 0, 0, 3323, + 0, 0, 3325, 0, 0, 0, 0, 3327, + 0, 0, 3329, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3331, + 0, 0, 3333, 0, 0, 3335, 0, 0, + 3337, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3341, 0, 3343, 0, + 0, 0, 3345, 0, 0, 0, 3347, 0, + 0, 3349, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3351, 0, 0, 3353, 0, + 0, 3355, 0, 0, 0, 0, 0, 3357, + 0, 3359, 0, 0, 0, 3361, 3363, 0, + 3365, 0, 0, 0, 3369, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3371, 3373, 0, 0, 3375, 3377, 0, 3379, + 0, 3381, 0, 3383, 0, 3385, 0, 0, + 3387, 0, 3389, 3391, 0, 0, 0, 0, + 3393, 0, 3395, 0, 0, 0, 0, 3397, + 0, 0, 0, 0, 0, 3399, 0, 0, + 3401, 0, 0, 0, 0, 0, 3403, 3405, + 0, 0, 3407, 0, 0, 0, 3409, 3411, + 0, 0, 0, 0, 0, 0, 0, 3413, + 0, 0, 0, 0, 3415, 0, 3417, 0, + 3419, 3421, 0, 0, 0, 0, 0, 3423, + 0, 0, 0, 0, 3425, 0, 0, 3427, + 0, 3429, 0, 3431, 0, 0, 0, 0, + 3433, 0, 0, 0, 0, 0, 3435, 0, + 0, 0, 3437, 3439, 0, 3441, 0, 0, + 0, 0, 0, 0, 3445, 0, 0, 0, + 3447, 3449, 0, 0, 0, 0, 0, 3451, + 3453, 0, 3455, 3457, 0, 3459, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3461, 0, 0, + 0, 0, 3463, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3465, 0, + 3467, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3469, 0, 0, 0, 0, + 0, 0, 0, 3471, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3473, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3475, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3477, 0, 3479, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3481, 0, + 0, 0, 0, 0, 3483, 0, 0, 3485, + 3487, 0, 0, 0, 0, 3489, 0, 0, + 0, 0, 3491, 0, 0, 0, 3493, 0, + 0, 0, 0, 0, 0, 0, 3495, 0, + 3497, 0, 0, 3499, 0, 0, 0, 0, + 3501, 3503, 0, 0, 3505, 0, 0, 0, + 0, 3507, 0, 0, 0, 3509, 0, 0, + 3511, 0, 0, 0, 0, 0, 3513, 0, + 0, 0, 3515, 0, 0, 0, 0, 0, + 0, 0, 3517, 0, 3519, 3521, 0, 0, + 3523, 0, 3525, 0, 3527, 0, 0, 0, + 0, 0, 0, 3529, 0, 0, 0, 3531, + 0, 3533, 0, 0, 0, 3535, 3537, 0, + 0, 0, 3539, 0, 0, 0, 0, 0, + 3541, 3543, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3545, 0, 0, 0, 3547, 3549, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3551, 0, 0, 3553, 0, 0, 3555, 0, + 0, 3557, 3559, 0, 0, 0, 3561, 0, + 0, 3563, 0, 0, 0, 3565, 0, 3567, + 0, 0, 3569, 0, 0, 0, 0, 0, + 3571, 0, 0, 3573, 3575, 0, 0, 3577, + 0, 0, 3579, 3581, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3583, 0, 0, + 0, 0, 3585, 3587, 0, 0, 3589, 0, + 0, 3593, 0, 0, 0, 3595, 0, 0, + 0, 0, 0, 0, 3597, 3599, 0, 3601, + 0, 3603, 0, 0, 0, 3605, 0, 0, + 0, 0, 0, 0, 3607, 0, 0, 0, + 0, 3609, 3611, 0, 0, 0, 0, 0, + 0, 3613, 0, 0, 0, 0, 0, 0, + 0, 3615, 0, 0, 0, 0, 3619, 0, + 0, 3621, 3623, 3625, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3627, 3629, 0, + 3631, 3633, 0, 3635, 3637, 0, 3639, 0, + 3641, 0, 0, 0, 3643, 0, 0, 0, + 3645, 0, 0, 0, 3647, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3649, 0, 0, 3651, + 0, 0, 0, 0, 0, 3653, 0, 0, + 3655, 0, 3657, 3659, 0, 3661, 0, 3663, + 0, 0, 0, 0, 0, 0, 3665, 3667, + 0, 3669, 0, 0, 3671, 0, 3673, 0, + 0, 0, 0, 0, 3675, 0, 0, 0, + 3677, 3679, 0, 0, 0, 0, 0, 0, + 3681, 0, 3683, 0, 3685, 0, 3687, 0, + 0, 0, 3689, 0, 0, 3691, 0, 0, + 3693, 0, 0, 3695, 3697, 0, 0, 3699, + 0, 0, 3701, 0, 0, 3703, 3705, 0, + 0, 0, 0, 0, 3707, 3709, 3711, 0, + 0, 0, 3713, 0, 0, 0, 0, 0, + 3715, 0, 0, 0, 3717, 0, 0, 0, + 3719, 0, 0, 0, 3721, 0, 0, 0, + 3723, 0, 3725, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3727, 0, 0, 3729, 0, 3731, 0, + 0, 0, 0, 0, 3733, 0, 0, 0, + 0, 0, 0, 0, 0, 3735, 0, 0, + 3737, 3739, 0, 0, 0, 3741, 0, 0, + 0, 3743, 0, 0, 3745, 3747, 0, 0, + 0, 3749, 0, 0, 0, 3751, 0, 0, + 0, 0, 3753, 0, 0, 0, 3755, 0, + 3757, 0, 0, 3759, 0, 3761, 0, 3763, + 0, 0, 3765, 3767, 0, 3769, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3771, 0, 0, 0, 0, 0, 0, 3773, + 0, 3775, 0, 0, 0, 0, 0, 0, + 0, 0, 3777, 0, 0, 3779, 0, 0, + 3781, 0, 0, 3783, 3785, 0, 3787, 0, + 0, 0, 3795, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3797, 0, 0, 0, + 3799, 0, 0, 3801, 3803, 0, 0, 0, + 3805, 0, 0, 0, 0, 3807, 0, 3809, + 0, 0, 0, 3811, 0, 0, 0, 3813, + 0, 0, 3815, 3817, 0, 0, 0, 3819, + 0, 0, 0, 0, 3821, 0, 0, 0, + 3823, 0, 3825, 0, 0, 3827, 0, 3829, + 0, 3831, 0, 0, 3833, 3835, 0, 0, + 0, 0, 0, 3837, 0, 0, 0, 0, + 3839, 3841, 0, 0, 3843, 0, 0, 0, + 3845, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3849, 3851, + 0, 0, 3853, 0, 0, 0, 0, 0, + 0, 3855, 0, 0, 0, 3857, 3859, 0, + 0, 3861, 0, 0, 0, 0, 3863, 0, + 3865, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3867, 0, 0, 0, 3869, 0, + 3871, 0, 0, 0, 0, 3873, 3875, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3877, 0, 0, 3879, 0, 0, 3881, + 0, 0, 0, 3883, 0, 0, 3885, 0, + 0, 0, 0, 0, 0, 0, 3889, 0, + 5, 4483, 3893, 0, 0, 3895, 3897, 0, + 3899, 0, 0, 0, 0, 3901, 3903, 0, + 0, 0, 0, 0, 3905, 0, 0, 3907, + 3909, 0, 0, 0, 3911, 0, 3913, 0, + 0, 0, 0, 3915, 0, 0, 0, 0, + 0, 3917, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3919, 0, 0, + 0, 0, 0, 0, 0, 3921, 0, 0, + 0, 3923, 0, 0, 3925, 3927, 0, 0, + 0, 0, 3929, 0, 0, 3931, 0, 0, + 3933, 3935, 0, 0, 0, 0, 3937, 0, + 0, 0, 3939, 0, 3941, 0, 0, 0, + 3943, 0, 0, 0, 0, 0, 3945, 0, + 0, 0, 0, 0, 3947, 3949, 0, 0, + 3951, 0, 0, 0, 3953, 0, 0, 0, + 0, 3955, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3957, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3959, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3961, + 0, 0, 3963, 0, 0, 0, 0, 0, + 0, 3967, 0, 0, 0, 0, 3969, 0, + 0, 3971, 0, 0, 0, 0, 3975, 0, + 0, 0, 0, 0, 3977, 0, 0, 0, + 3979, 0, 0, 3981, 0, 0, 0, 0, + 0, 3983, 3985, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3989, 3991, 0, 0, + 3993, 0, 0, 0, 0, 0, 0, 3995, + 0, 0, 3997, 0, 0, 3999, 0, 0, + 4001, 0, 0, 0, 0, 4003, 0, 0, + 0, 0, 4007, 0, 4009, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4011, + 0, 0, 0, 0, 0, 0, 0, 0, + 4013, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4015, 0, 0, 0, + 0, 4017, 0, 0, 4019, 0, 4021, 0, + 0, 4023, 0, 0, 4025, 0, 0, 0, + 0, 0, 0, 0, 4027, 0, 0, 0, + 0, 0, 0, 0, 4029, 0, 0, 4031, + 0, 0, 4033, 0, 0, 4035, 0, 0, + 4037, 0, 0, 4039, 0, 0, 0, 0, + 0, 4041, 0, 0, 0, 4043, 0, 4045, + 0, 4047, 0, 0, 0, 0, 4049, 0, + 0, 0, 0, 0, 0, 4053, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4055, + 0, 0, 4057, 0, 4059, 0, 0, 0, + 4061, 0, 0, 0, 0, 0, 4063, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4065, 0, 0, 0, + 0, 4067, 0, 0, 0, 0, 0, 0, + 4069, 0, 0, 0, 0, 4071, 4073, 0, + 0, 0, 0, 4075, 4077, 0, 0, 4079, + 0, 0, 0, 0, 0, 4081, 0, 0, + 0, 0, 0, 0, 0, 0, 4083, 0, + 4085, 0, 0, 0, 0, 0, 0, 4087, + 0, 4089, 0, 0, 0, 0, 0, 4091, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4093, 0, 0, 0, 0, + 4095, 0, 4097, 0, 0, 0, 4099, 0, + 0, 0, 4101, 0, 0, 0, 0, 4103, + 0, 4105, 0, 0, 0, 4107, 0, 0, + 0, 0, 4109, 4111, 0, 4113, 0, 0, + 0, 4115, 0, 0, 0, 0, 4117, 4119, + 0, 0, 4121, 0, 0, 0, 4123, 0, + 0, 0, 4125, 0, 0, 0, 4127, 0, + 0, 0, 0, 0, 4129, 4131, 0, 0, + 0, 4133, 4135, 0, 0, 0, 0, 0, + 4137, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4139, 0, 0, 0, 0, + 0, 0, 4141, 0, 4143, 0, 4145, 0, + 0, 0, 4147, 0, 4149, 0, 0, 4151, + 4153, 4155, 0, 0, 0, 0, 4157, 0, + 0, 4159, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4161, 0, 0, 4163, + 0, 4165, 0, 0, 0, 4167, 0, 4169, + 0, 0, 0, 0, 4171, 0, 0, 4173, + 4175, 0, 0, 0, 0, 4177, 0, 0, + 4179, 0, 0, 4181, 0, 0, 4183, 0, + 0, 0, 0, 0, 4185, 0, 0, 4187, + 0, 0, 4189, 0, 0, 0, 4191, 0, + 0, 0, 0, 4193, 0, 0, 4195, 0, + 0, 0, 4197, 0, 0, 0, 4199, 0, + 0, 0, 0, 0, 4201, 0, 0, 4203, + 0, 0, 4205, 0, 0, 0, 0, 4207, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4211, 0, 0, + 0, 0, 4213, 4215, 0, 0, 4219, 0, + 0, 4221, 0, 0, 4223, 0, 0, 4225, + 0, 0, 0, 4227, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4231, 0, 0, 0, 0, + 0, 4233, 4235, 0, 0, 4237, 0, 0, + 0, 0, 0, 4239, 0, 4241, 0, 4243, + 0, 0, 4245, 0, 0, 0, 0, 0, + 4247, 0, 0, 4249, 0, 0, 4251, 0, + 0, 4253, 0, 4255, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4257, 7, 4259, 9, 4261, 11, 4263, 15, + 4265, 21, 4267, 35, 4269, 41, 4271, 43, + 4273, 71, 4275, 83, 4277, 247, 4279, 249, + 4281, 253, 4283, 261, 4285, 289, 4287, 313, + 4289, 383, 4291, 385, 4293, 393, 4295, 425, + 4297, 459, 4299, 731, 4301, 737, 4303, 739, + 4305, 747, 4307, 765, 4309, 767, 4311, 771, + 4313, 819, 4315, 829, 4317, 995, 4319, 1039, + 4321, 1049, 4323, 1057, 4325, 1109, 4327, 1169, + 4329, 1203, 4331, 1213, 4333, 1215, 4335, 1219, + 4337, 1225, 4339, 1237, 4341, 1305, 4343, 1315, + 4345, 1317, 4347, 1525, 4349, 1577, 4351, 1587, + 4353, 1591, 0, 4355, 1667, 0, 4357, 1725, + 4359, 1771, 4361, 1801, 0, 4363, 1873, 4365, + 1881, 4367, 1897, 4369, 1979, 4371, 1981, 4373, + 2029, 4375, 2033, 4377, 2045, 4379, 2153, 0, + 0, 0, 0, 0, 4381, 2239, 4383, 2243, + 4385, 2249, 4387, 2255, 4389, 2315, 4391, 2337, + 4393, 2405, 4395, 2647, 0, 0, 0, 0, + 0, 0, 0, 4397, 2681, 4399, 2713, 4401, + 2721, 4403, 2797, 4405, 2913, 0, 0, 4407, + 3025, 4409, 3085, 4411, 3091, 4413, 3113, 4415, + 3161, 4417, 3163, 4419, 3175, 4421, 3179, 4423, + 3185, 4425, 3191, 0, 4427, 3249, 4429, 3261, + 4431, 3339, 4433, 3367, 4435, 3443, 4437, 3591, + 4439, 3617, 4441, 3789, 4443, 3791, 4445, 3793, + 4447, 3847, 4449, 3887, 4451, 3891, 0, 0, + 4453, 3965, 4455, 3973, 4457, 3987, 4459, 4005, + 4461, 4051, 4463, 4209, 4465, 4217, 4467, 4229 +}; + +static const short _char_ref_to_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 +}; + +static const short _char_ref_from_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 +}; + +static const short _char_ref_eof_trans[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4396, 4396, 4396, 4396, + 4396, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4538, 4538, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4819, 4819, 4819, 4819, + 4819, 4819, 4819, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5497, 5497, + 5497, 5497, 5497, 5497, 5497, 5497, 5497, 5497, + 5497, 5497, 5497, 5497, 5497, 5497, 5497, 5497, + 5497, 5497, 5497, 5497, 5497, 5497, 5497, 5497, + 5497, 5497, 5497, 5497, 5497, 5497, 5497, 5497, + 5497, 5497, 5497, 5497, 5497, 5497, 5497, 5497, + 5497, 5497, 5497, 5497, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6541, 6541, 6541, 6541, 6541, + 6541, 6541, 6541, 6541, 6541, 6541, 6541, 6541, + 6541, 6541, 6541, 6541, 6541, 6541, 6541, 6541, + 6541, 6541, 6541, 6541, 6541, 6541, 6541, 6541, + 6541, 6541, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7048, 7048, 7048, 7048, + 7048, 7048, 7048, 7048, 7048, 7048, 7048, 7048, + 7048, 7048, 7048, 7048, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7549, 7549, 7549, 7549, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8898, 8898, 8898, + 8898, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9737, 9739, 9741, 9743, 9745, 9747, 9749, 9751, + 9753, 9755, 9757, 9759, 9761, 9763, 9765, 9767, + 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, + 9785, 9787, 9789, 9791, 9793, 9795, 9797, 9799, + 9801, 9803, 9805, 9807, 9809, 9811, 9813, 9815, + 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, + 9833, 9836, 9839, 9841, 9843, 9846, 9848, 9850, + 9852, 9854, 9856, 9858, 9860, 9862, 9869, 9871, + 9873, 9875, 9877, 9879, 9881, 9883, 9892, 9894, + 9896, 9898, 9900, 9904, 9906, 9908, 9910, 9912, + 9914, 9916, 9918, 9920, 9922, 9925, 9927, 9929, + 9931, 9933, 9935, 9937, 9939, 9941, 9943, 9945, + 9947, 9949, 9953, 9955, 9957, 9959, 9961, 9963, + 9965, 9967 +}; + +static const int char_ref_start = 7623; + +static const int char_ref_en_valid_named_ref = 7623; + + +#line 2469 "char_ref.rl" +// clang-format on + +static bool consume_named_ref(struct GumboInternalParser* parser, + Utf8Iterator* input, bool is_in_attribute, OneOrTwoCodepoints* output) { + assert(output->first == kGumboNoChar); + const char* p = utf8iterator_get_char_pointer(input); + const char* pe = utf8iterator_get_end_pointer(input); + const char* eof = pe; + const char* te = 0; + const char *ts, *start; + int cs, act; + +// clang-format off + +#line 13985 "char_ref.c" + { + cs = char_ref_start; + ts = 0; + te = 0; + act = 0; + } + +#line 2484 "char_ref.rl" + // Avoid unused variable warnings. + (void) act; + (void) ts; + (void) char_ref_en_valid_named_ref; + + start = p; + +#line 14001 "char_ref.c" + { + int _slen; + int _trans; + const short *_acts; + unsigned int _nacts; + const char *_keys; + const short *_inds; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _acts = _char_ref_actions + _char_ref_from_state_actions[cs]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) { + switch ( *_acts++ ) { + case 1: +#line 1 "NONE" + {ts = p;} + break; +#line 14023 "char_ref.c" + } + } + + _keys = _char_ref_trans_keys + (cs<<1); + _inds = _char_ref_indicies + _char_ref_index_offsets[cs]; + + _slen = _char_ref_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + +_eof_trans: + cs = _char_ref_trans_targs[_trans]; + + if ( _char_ref_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _char_ref_actions + _char_ref_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) { + switch ( *(_acts++) ) + { + case 2: +#line 1 "NONE" + {te = p+1;} + break; + case 3: +#line 233 "char_ref.rl" + {te = p+1;{ output->first = 0xc6; {p++; goto _out; } }} + break; + case 4: +#line 235 "char_ref.rl" + {te = p+1;{ output->first = 0x26; {p++; goto _out; } }} + break; + case 5: +#line 237 "char_ref.rl" + {te = p+1;{ output->first = 0xc1; {p++; goto _out; } }} + break; + case 6: +#line 239 "char_ref.rl" + {te = p+1;{ output->first = 0x0102; {p++; goto _out; } }} + break; + case 7: +#line 240 "char_ref.rl" + {te = p+1;{ output->first = 0xc2; {p++; goto _out; } }} + break; + case 8: +#line 242 "char_ref.rl" + {te = p+1;{ output->first = 0x0410; {p++; goto _out; } }} + break; + case 9: +#line 243 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d504; {p++; goto _out; } }} + break; + case 10: +#line 244 "char_ref.rl" + {te = p+1;{ output->first = 0xc0; {p++; goto _out; } }} + break; + case 11: +#line 246 "char_ref.rl" + {te = p+1;{ output->first = 0x0391; {p++; goto _out; } }} + break; + case 12: +#line 247 "char_ref.rl" + {te = p+1;{ output->first = 0x0100; {p++; goto _out; } }} + break; + case 13: +#line 248 "char_ref.rl" + {te = p+1;{ output->first = 0x2a53; {p++; goto _out; } }} + break; + case 14: +#line 249 "char_ref.rl" + {te = p+1;{ output->first = 0x0104; {p++; goto _out; } }} + break; + case 15: +#line 250 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d538; {p++; goto _out; } }} + break; + case 16: +#line 251 "char_ref.rl" + {te = p+1;{ output->first = 0x2061; {p++; goto _out; } }} + break; + case 17: +#line 252 "char_ref.rl" + {te = p+1;{ output->first = 0xc5; {p++; goto _out; } }} + break; + case 18: +#line 254 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d49c; {p++; goto _out; } }} + break; + case 19: +#line 255 "char_ref.rl" + {te = p+1;{ output->first = 0x2254; {p++; goto _out; } }} + break; + case 20: +#line 256 "char_ref.rl" + {te = p+1;{ output->first = 0xc3; {p++; goto _out; } }} + break; + case 21: +#line 258 "char_ref.rl" + {te = p+1;{ output->first = 0xc4; {p++; goto _out; } }} + break; + case 22: +#line 260 "char_ref.rl" + {te = p+1;{ output->first = 0x2216; {p++; goto _out; } }} + break; + case 23: +#line 261 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae7; {p++; goto _out; } }} + break; + case 24: +#line 262 "char_ref.rl" + {te = p+1;{ output->first = 0x2306; {p++; goto _out; } }} + break; + case 25: +#line 263 "char_ref.rl" + {te = p+1;{ output->first = 0x0411; {p++; goto _out; } }} + break; + case 26: +#line 264 "char_ref.rl" + {te = p+1;{ output->first = 0x2235; {p++; goto _out; } }} + break; + case 27: +#line 265 "char_ref.rl" + {te = p+1;{ output->first = 0x212c; {p++; goto _out; } }} + break; + case 28: +#line 266 "char_ref.rl" + {te = p+1;{ output->first = 0x0392; {p++; goto _out; } }} + break; + case 29: +#line 267 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d505; {p++; goto _out; } }} + break; + case 30: +#line 268 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d539; {p++; goto _out; } }} + break; + case 31: +#line 269 "char_ref.rl" + {te = p+1;{ output->first = 0x02d8; {p++; goto _out; } }} + break; + case 32: +#line 270 "char_ref.rl" + {te = p+1;{ output->first = 0x212c; {p++; goto _out; } }} + break; + case 33: +#line 271 "char_ref.rl" + {te = p+1;{ output->first = 0x224e; {p++; goto _out; } }} + break; + case 34: +#line 272 "char_ref.rl" + {te = p+1;{ output->first = 0x0427; {p++; goto _out; } }} + break; + case 35: +#line 273 "char_ref.rl" + {te = p+1;{ output->first = 0xa9; {p++; goto _out; } }} + break; + case 36: +#line 275 "char_ref.rl" + {te = p+1;{ output->first = 0x0106; {p++; goto _out; } }} + break; + case 37: +#line 276 "char_ref.rl" + {te = p+1;{ output->first = 0x22d2; {p++; goto _out; } }} + break; + case 38: +#line 277 "char_ref.rl" + {te = p+1;{ output->first = 0x2145; {p++; goto _out; } }} + break; + case 39: +#line 278 "char_ref.rl" + {te = p+1;{ output->first = 0x212d; {p++; goto _out; } }} + break; + case 40: +#line 279 "char_ref.rl" + {te = p+1;{ output->first = 0x010c; {p++; goto _out; } }} + break; + case 41: +#line 280 "char_ref.rl" + {te = p+1;{ output->first = 0xc7; {p++; goto _out; } }} + break; + case 42: +#line 282 "char_ref.rl" + {te = p+1;{ output->first = 0x0108; {p++; goto _out; } }} + break; + case 43: +#line 283 "char_ref.rl" + {te = p+1;{ output->first = 0x2230; {p++; goto _out; } }} + break; + case 44: +#line 284 "char_ref.rl" + {te = p+1;{ output->first = 0x010a; {p++; goto _out; } }} + break; + case 45: +#line 285 "char_ref.rl" + {te = p+1;{ output->first = 0xb8; {p++; goto _out; } }} + break; + case 46: +#line 286 "char_ref.rl" + {te = p+1;{ output->first = 0xb7; {p++; goto _out; } }} + break; + case 47: +#line 287 "char_ref.rl" + {te = p+1;{ output->first = 0x212d; {p++; goto _out; } }} + break; + case 48: +#line 288 "char_ref.rl" + {te = p+1;{ output->first = 0x03a7; {p++; goto _out; } }} + break; + case 49: +#line 289 "char_ref.rl" + {te = p+1;{ output->first = 0x2299; {p++; goto _out; } }} + break; + case 50: +#line 290 "char_ref.rl" + {te = p+1;{ output->first = 0x2296; {p++; goto _out; } }} + break; + case 51: +#line 291 "char_ref.rl" + {te = p+1;{ output->first = 0x2295; {p++; goto _out; } }} + break; + case 52: +#line 292 "char_ref.rl" + {te = p+1;{ output->first = 0x2297; {p++; goto _out; } }} + break; + case 53: +#line 293 "char_ref.rl" + {te = p+1;{ output->first = 0x2232; {p++; goto _out; } }} + break; + case 54: +#line 294 "char_ref.rl" + {te = p+1;{ output->first = 0x201d; {p++; goto _out; } }} + break; + case 55: +#line 295 "char_ref.rl" + {te = p+1;{ output->first = 0x2019; {p++; goto _out; } }} + break; + case 56: +#line 296 "char_ref.rl" + {te = p+1;{ output->first = 0x2237; {p++; goto _out; } }} + break; + case 57: +#line 297 "char_ref.rl" + {te = p+1;{ output->first = 0x2a74; {p++; goto _out; } }} + break; + case 58: +#line 298 "char_ref.rl" + {te = p+1;{ output->first = 0x2261; {p++; goto _out; } }} + break; + case 59: +#line 299 "char_ref.rl" + {te = p+1;{ output->first = 0x222f; {p++; goto _out; } }} + break; + case 60: +#line 300 "char_ref.rl" + {te = p+1;{ output->first = 0x222e; {p++; goto _out; } }} + break; + case 61: +#line 301 "char_ref.rl" + {te = p+1;{ output->first = 0x2102; {p++; goto _out; } }} + break; + case 62: +#line 302 "char_ref.rl" + {te = p+1;{ output->first = 0x2210; {p++; goto _out; } }} + break; + case 63: +#line 303 "char_ref.rl" + {te = p+1;{ output->first = 0x2233; {p++; goto _out; } }} + break; + case 64: +#line 304 "char_ref.rl" + {te = p+1;{ output->first = 0x2a2f; {p++; goto _out; } }} + break; + case 65: +#line 305 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d49e; {p++; goto _out; } }} + break; + case 66: +#line 306 "char_ref.rl" + {te = p+1;{ output->first = 0x22d3; {p++; goto _out; } }} + break; + case 67: +#line 307 "char_ref.rl" + {te = p+1;{ output->first = 0x224d; {p++; goto _out; } }} + break; + case 68: +#line 308 "char_ref.rl" + {te = p+1;{ output->first = 0x2145; {p++; goto _out; } }} + break; + case 69: +#line 309 "char_ref.rl" + {te = p+1;{ output->first = 0x2911; {p++; goto _out; } }} + break; + case 70: +#line 310 "char_ref.rl" + {te = p+1;{ output->first = 0x0402; {p++; goto _out; } }} + break; + case 71: +#line 311 "char_ref.rl" + {te = p+1;{ output->first = 0x0405; {p++; goto _out; } }} + break; + case 72: +#line 312 "char_ref.rl" + {te = p+1;{ output->first = 0x040f; {p++; goto _out; } }} + break; + case 73: +#line 313 "char_ref.rl" + {te = p+1;{ output->first = 0x2021; {p++; goto _out; } }} + break; + case 74: +#line 314 "char_ref.rl" + {te = p+1;{ output->first = 0x21a1; {p++; goto _out; } }} + break; + case 75: +#line 315 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae4; {p++; goto _out; } }} + break; + case 76: +#line 316 "char_ref.rl" + {te = p+1;{ output->first = 0x010e; {p++; goto _out; } }} + break; + case 77: +#line 317 "char_ref.rl" + {te = p+1;{ output->first = 0x0414; {p++; goto _out; } }} + break; + case 78: +#line 318 "char_ref.rl" + {te = p+1;{ output->first = 0x2207; {p++; goto _out; } }} + break; + case 79: +#line 319 "char_ref.rl" + {te = p+1;{ output->first = 0x0394; {p++; goto _out; } }} + break; + case 80: +#line 320 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d507; {p++; goto _out; } }} + break; + case 81: +#line 321 "char_ref.rl" + {te = p+1;{ output->first = 0xb4; {p++; goto _out; } }} + break; + case 82: +#line 322 "char_ref.rl" + {te = p+1;{ output->first = 0x02d9; {p++; goto _out; } }} + break; + case 83: +#line 323 "char_ref.rl" + {te = p+1;{ output->first = 0x02dd; {p++; goto _out; } }} + break; + case 84: +#line 324 "char_ref.rl" + {te = p+1;{ output->first = 0x60; {p++; goto _out; } }} + break; + case 85: +#line 325 "char_ref.rl" + {te = p+1;{ output->first = 0x02dc; {p++; goto _out; } }} + break; + case 86: +#line 326 "char_ref.rl" + {te = p+1;{ output->first = 0x22c4; {p++; goto _out; } }} + break; + case 87: +#line 327 "char_ref.rl" + {te = p+1;{ output->first = 0x2146; {p++; goto _out; } }} + break; + case 88: +#line 328 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d53b; {p++; goto _out; } }} + break; + case 89: +#line 329 "char_ref.rl" + {te = p+1;{ output->first = 0xa8; {p++; goto _out; } }} + break; + case 90: +#line 330 "char_ref.rl" + {te = p+1;{ output->first = 0x20dc; {p++; goto _out; } }} + break; + case 91: +#line 331 "char_ref.rl" + {te = p+1;{ output->first = 0x2250; {p++; goto _out; } }} + break; + case 92: +#line 332 "char_ref.rl" + {te = p+1;{ output->first = 0x222f; {p++; goto _out; } }} + break; + case 93: +#line 333 "char_ref.rl" + {te = p+1;{ output->first = 0xa8; {p++; goto _out; } }} + break; + case 94: +#line 334 "char_ref.rl" + {te = p+1;{ output->first = 0x21d3; {p++; goto _out; } }} + break; + case 95: +#line 335 "char_ref.rl" + {te = p+1;{ output->first = 0x21d0; {p++; goto _out; } }} + break; + case 96: +#line 336 "char_ref.rl" + {te = p+1;{ output->first = 0x21d4; {p++; goto _out; } }} + break; + case 97: +#line 337 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae4; {p++; goto _out; } }} + break; + case 98: +#line 338 "char_ref.rl" + {te = p+1;{ output->first = 0x27f8; {p++; goto _out; } }} + break; + case 99: +#line 339 "char_ref.rl" + {te = p+1;{ output->first = 0x27fa; {p++; goto _out; } }} + break; + case 100: +#line 340 "char_ref.rl" + {te = p+1;{ output->first = 0x27f9; {p++; goto _out; } }} + break; + case 101: +#line 341 "char_ref.rl" + {te = p+1;{ output->first = 0x21d2; {p++; goto _out; } }} + break; + case 102: +#line 342 "char_ref.rl" + {te = p+1;{ output->first = 0x22a8; {p++; goto _out; } }} + break; + case 103: +#line 343 "char_ref.rl" + {te = p+1;{ output->first = 0x21d1; {p++; goto _out; } }} + break; + case 104: +#line 344 "char_ref.rl" + {te = p+1;{ output->first = 0x21d5; {p++; goto _out; } }} + break; + case 105: +#line 345 "char_ref.rl" + {te = p+1;{ output->first = 0x2225; {p++; goto _out; } }} + break; + case 106: +#line 346 "char_ref.rl" + {te = p+1;{ output->first = 0x2193; {p++; goto _out; } }} + break; + case 107: +#line 347 "char_ref.rl" + {te = p+1;{ output->first = 0x2913; {p++; goto _out; } }} + break; + case 108: +#line 348 "char_ref.rl" + {te = p+1;{ output->first = 0x21f5; {p++; goto _out; } }} + break; + case 109: +#line 349 "char_ref.rl" + {te = p+1;{ output->first = 0x0311; {p++; goto _out; } }} + break; + case 110: +#line 350 "char_ref.rl" + {te = p+1;{ output->first = 0x2950; {p++; goto _out; } }} + break; + case 111: +#line 351 "char_ref.rl" + {te = p+1;{ output->first = 0x295e; {p++; goto _out; } }} + break; + case 112: +#line 352 "char_ref.rl" + {te = p+1;{ output->first = 0x21bd; {p++; goto _out; } }} + break; + case 113: +#line 353 "char_ref.rl" + {te = p+1;{ output->first = 0x2956; {p++; goto _out; } }} + break; + case 114: +#line 354 "char_ref.rl" + {te = p+1;{ output->first = 0x295f; {p++; goto _out; } }} + break; + case 115: +#line 355 "char_ref.rl" + {te = p+1;{ output->first = 0x21c1; {p++; goto _out; } }} + break; + case 116: +#line 356 "char_ref.rl" + {te = p+1;{ output->first = 0x2957; {p++; goto _out; } }} + break; + case 117: +#line 357 "char_ref.rl" + {te = p+1;{ output->first = 0x22a4; {p++; goto _out; } }} + break; + case 118: +#line 358 "char_ref.rl" + {te = p+1;{ output->first = 0x21a7; {p++; goto _out; } }} + break; + case 119: +#line 359 "char_ref.rl" + {te = p+1;{ output->first = 0x21d3; {p++; goto _out; } }} + break; + case 120: +#line 360 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d49f; {p++; goto _out; } }} + break; + case 121: +#line 361 "char_ref.rl" + {te = p+1;{ output->first = 0x0110; {p++; goto _out; } }} + break; + case 122: +#line 362 "char_ref.rl" + {te = p+1;{ output->first = 0x014a; {p++; goto _out; } }} + break; + case 123: +#line 363 "char_ref.rl" + {te = p+1;{ output->first = 0xd0; {p++; goto _out; } }} + break; + case 124: +#line 365 "char_ref.rl" + {te = p+1;{ output->first = 0xc9; {p++; goto _out; } }} + break; + case 125: +#line 367 "char_ref.rl" + {te = p+1;{ output->first = 0x011a; {p++; goto _out; } }} + break; + case 126: +#line 368 "char_ref.rl" + {te = p+1;{ output->first = 0xca; {p++; goto _out; } }} + break; + case 127: +#line 370 "char_ref.rl" + {te = p+1;{ output->first = 0x042d; {p++; goto _out; } }} + break; + case 128: +#line 371 "char_ref.rl" + {te = p+1;{ output->first = 0x0116; {p++; goto _out; } }} + break; + case 129: +#line 372 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d508; {p++; goto _out; } }} + break; + case 130: +#line 373 "char_ref.rl" + {te = p+1;{ output->first = 0xc8; {p++; goto _out; } }} + break; + case 131: +#line 375 "char_ref.rl" + {te = p+1;{ output->first = 0x2208; {p++; goto _out; } }} + break; + case 132: +#line 376 "char_ref.rl" + {te = p+1;{ output->first = 0x0112; {p++; goto _out; } }} + break; + case 133: +#line 377 "char_ref.rl" + {te = p+1;{ output->first = 0x25fb; {p++; goto _out; } }} + break; + case 134: +#line 378 "char_ref.rl" + {te = p+1;{ output->first = 0x25ab; {p++; goto _out; } }} + break; + case 135: +#line 379 "char_ref.rl" + {te = p+1;{ output->first = 0x0118; {p++; goto _out; } }} + break; + case 136: +#line 380 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d53c; {p++; goto _out; } }} + break; + case 137: +#line 381 "char_ref.rl" + {te = p+1;{ output->first = 0x0395; {p++; goto _out; } }} + break; + case 138: +#line 382 "char_ref.rl" + {te = p+1;{ output->first = 0x2a75; {p++; goto _out; } }} + break; + case 139: +#line 383 "char_ref.rl" + {te = p+1;{ output->first = 0x2242; {p++; goto _out; } }} + break; + case 140: +#line 384 "char_ref.rl" + {te = p+1;{ output->first = 0x21cc; {p++; goto _out; } }} + break; + case 141: +#line 385 "char_ref.rl" + {te = p+1;{ output->first = 0x2130; {p++; goto _out; } }} + break; + case 142: +#line 386 "char_ref.rl" + {te = p+1;{ output->first = 0x2a73; {p++; goto _out; } }} + break; + case 143: +#line 387 "char_ref.rl" + {te = p+1;{ output->first = 0x0397; {p++; goto _out; } }} + break; + case 144: +#line 388 "char_ref.rl" + {te = p+1;{ output->first = 0xcb; {p++; goto _out; } }} + break; + case 145: +#line 390 "char_ref.rl" + {te = p+1;{ output->first = 0x2203; {p++; goto _out; } }} + break; + case 146: +#line 391 "char_ref.rl" + {te = p+1;{ output->first = 0x2147; {p++; goto _out; } }} + break; + case 147: +#line 392 "char_ref.rl" + {te = p+1;{ output->first = 0x0424; {p++; goto _out; } }} + break; + case 148: +#line 393 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d509; {p++; goto _out; } }} + break; + case 149: +#line 394 "char_ref.rl" + {te = p+1;{ output->first = 0x25fc; {p++; goto _out; } }} + break; + case 150: +#line 395 "char_ref.rl" + {te = p+1;{ output->first = 0x25aa; {p++; goto _out; } }} + break; + case 151: +#line 396 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d53d; {p++; goto _out; } }} + break; + case 152: +#line 397 "char_ref.rl" + {te = p+1;{ output->first = 0x2200; {p++; goto _out; } }} + break; + case 153: +#line 398 "char_ref.rl" + {te = p+1;{ output->first = 0x2131; {p++; goto _out; } }} + break; + case 154: +#line 399 "char_ref.rl" + {te = p+1;{ output->first = 0x2131; {p++; goto _out; } }} + break; + case 155: +#line 400 "char_ref.rl" + {te = p+1;{ output->first = 0x0403; {p++; goto _out; } }} + break; + case 156: +#line 401 "char_ref.rl" + {te = p+1;{ output->first = 0x3e; {p++; goto _out; } }} + break; + case 157: +#line 403 "char_ref.rl" + {te = p+1;{ output->first = 0x0393; {p++; goto _out; } }} + break; + case 158: +#line 404 "char_ref.rl" + {te = p+1;{ output->first = 0x03dc; {p++; goto _out; } }} + break; + case 159: +#line 405 "char_ref.rl" + {te = p+1;{ output->first = 0x011e; {p++; goto _out; } }} + break; + case 160: +#line 406 "char_ref.rl" + {te = p+1;{ output->first = 0x0122; {p++; goto _out; } }} + break; + case 161: +#line 407 "char_ref.rl" + {te = p+1;{ output->first = 0x011c; {p++; goto _out; } }} + break; + case 162: +#line 408 "char_ref.rl" + {te = p+1;{ output->first = 0x0413; {p++; goto _out; } }} + break; + case 163: +#line 409 "char_ref.rl" + {te = p+1;{ output->first = 0x0120; {p++; goto _out; } }} + break; + case 164: +#line 410 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d50a; {p++; goto _out; } }} + break; + case 165: +#line 411 "char_ref.rl" + {te = p+1;{ output->first = 0x22d9; {p++; goto _out; } }} + break; + case 166: +#line 412 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d53e; {p++; goto _out; } }} + break; + case 167: +#line 413 "char_ref.rl" + {te = p+1;{ output->first = 0x2265; {p++; goto _out; } }} + break; + case 168: +#line 414 "char_ref.rl" + {te = p+1;{ output->first = 0x22db; {p++; goto _out; } }} + break; + case 169: +#line 415 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; {p++; goto _out; } }} + break; + case 170: +#line 416 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa2; {p++; goto _out; } }} + break; + case 171: +#line 417 "char_ref.rl" + {te = p+1;{ output->first = 0x2277; {p++; goto _out; } }} + break; + case 172: +#line 418 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; {p++; goto _out; } }} + break; + case 173: +#line 419 "char_ref.rl" + {te = p+1;{ output->first = 0x2273; {p++; goto _out; } }} + break; + case 174: +#line 420 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4a2; {p++; goto _out; } }} + break; + case 175: +#line 421 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; {p++; goto _out; } }} + break; + case 176: +#line 422 "char_ref.rl" + {te = p+1;{ output->first = 0x042a; {p++; goto _out; } }} + break; + case 177: +#line 423 "char_ref.rl" + {te = p+1;{ output->first = 0x02c7; {p++; goto _out; } }} + break; + case 178: +#line 424 "char_ref.rl" + {te = p+1;{ output->first = 0x5e; {p++; goto _out; } }} + break; + case 179: +#line 425 "char_ref.rl" + {te = p+1;{ output->first = 0x0124; {p++; goto _out; } }} + break; + case 180: +#line 426 "char_ref.rl" + {te = p+1;{ output->first = 0x210c; {p++; goto _out; } }} + break; + case 181: +#line 427 "char_ref.rl" + {te = p+1;{ output->first = 0x210b; {p++; goto _out; } }} + break; + case 182: +#line 428 "char_ref.rl" + {te = p+1;{ output->first = 0x210d; {p++; goto _out; } }} + break; + case 183: +#line 429 "char_ref.rl" + {te = p+1;{ output->first = 0x2500; {p++; goto _out; } }} + break; + case 184: +#line 430 "char_ref.rl" + {te = p+1;{ output->first = 0x210b; {p++; goto _out; } }} + break; + case 185: +#line 431 "char_ref.rl" + {te = p+1;{ output->first = 0x0126; {p++; goto _out; } }} + break; + case 186: +#line 432 "char_ref.rl" + {te = p+1;{ output->first = 0x224e; {p++; goto _out; } }} + break; + case 187: +#line 433 "char_ref.rl" + {te = p+1;{ output->first = 0x224f; {p++; goto _out; } }} + break; + case 188: +#line 434 "char_ref.rl" + {te = p+1;{ output->first = 0x0415; {p++; goto _out; } }} + break; + case 189: +#line 435 "char_ref.rl" + {te = p+1;{ output->first = 0x0132; {p++; goto _out; } }} + break; + case 190: +#line 436 "char_ref.rl" + {te = p+1;{ output->first = 0x0401; {p++; goto _out; } }} + break; + case 191: +#line 437 "char_ref.rl" + {te = p+1;{ output->first = 0xcd; {p++; goto _out; } }} + break; + case 192: +#line 439 "char_ref.rl" + {te = p+1;{ output->first = 0xce; {p++; goto _out; } }} + break; + case 193: +#line 441 "char_ref.rl" + {te = p+1;{ output->first = 0x0418; {p++; goto _out; } }} + break; + case 194: +#line 442 "char_ref.rl" + {te = p+1;{ output->first = 0x0130; {p++; goto _out; } }} + break; + case 195: +#line 443 "char_ref.rl" + {te = p+1;{ output->first = 0x2111; {p++; goto _out; } }} + break; + case 196: +#line 444 "char_ref.rl" + {te = p+1;{ output->first = 0xcc; {p++; goto _out; } }} + break; + case 197: +#line 446 "char_ref.rl" + {te = p+1;{ output->first = 0x2111; {p++; goto _out; } }} + break; + case 198: +#line 447 "char_ref.rl" + {te = p+1;{ output->first = 0x012a; {p++; goto _out; } }} + break; + case 199: +#line 448 "char_ref.rl" + {te = p+1;{ output->first = 0x2148; {p++; goto _out; } }} + break; + case 200: +#line 449 "char_ref.rl" + {te = p+1;{ output->first = 0x21d2; {p++; goto _out; } }} + break; + case 201: +#line 450 "char_ref.rl" + {te = p+1;{ output->first = 0x222c; {p++; goto _out; } }} + break; + case 202: +#line 451 "char_ref.rl" + {te = p+1;{ output->first = 0x222b; {p++; goto _out; } }} + break; + case 203: +#line 452 "char_ref.rl" + {te = p+1;{ output->first = 0x22c2; {p++; goto _out; } }} + break; + case 204: +#line 453 "char_ref.rl" + {te = p+1;{ output->first = 0x2063; {p++; goto _out; } }} + break; + case 205: +#line 454 "char_ref.rl" + {te = p+1;{ output->first = 0x2062; {p++; goto _out; } }} + break; + case 206: +#line 455 "char_ref.rl" + {te = p+1;{ output->first = 0x012e; {p++; goto _out; } }} + break; + case 207: +#line 456 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d540; {p++; goto _out; } }} + break; + case 208: +#line 457 "char_ref.rl" + {te = p+1;{ output->first = 0x0399; {p++; goto _out; } }} + break; + case 209: +#line 458 "char_ref.rl" + {te = p+1;{ output->first = 0x2110; {p++; goto _out; } }} + break; + case 210: +#line 459 "char_ref.rl" + {te = p+1;{ output->first = 0x0128; {p++; goto _out; } }} + break; + case 211: +#line 460 "char_ref.rl" + {te = p+1;{ output->first = 0x0406; {p++; goto _out; } }} + break; + case 212: +#line 461 "char_ref.rl" + {te = p+1;{ output->first = 0xcf; {p++; goto _out; } }} + break; + case 213: +#line 463 "char_ref.rl" + {te = p+1;{ output->first = 0x0134; {p++; goto _out; } }} + break; + case 214: +#line 464 "char_ref.rl" + {te = p+1;{ output->first = 0x0419; {p++; goto _out; } }} + break; + case 215: +#line 465 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d50d; {p++; goto _out; } }} + break; + case 216: +#line 466 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d541; {p++; goto _out; } }} + break; + case 217: +#line 467 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4a5; {p++; goto _out; } }} + break; + case 218: +#line 468 "char_ref.rl" + {te = p+1;{ output->first = 0x0408; {p++; goto _out; } }} + break; + case 219: +#line 469 "char_ref.rl" + {te = p+1;{ output->first = 0x0404; {p++; goto _out; } }} + break; + case 220: +#line 470 "char_ref.rl" + {te = p+1;{ output->first = 0x0425; {p++; goto _out; } }} + break; + case 221: +#line 471 "char_ref.rl" + {te = p+1;{ output->first = 0x040c; {p++; goto _out; } }} + break; + case 222: +#line 472 "char_ref.rl" + {te = p+1;{ output->first = 0x039a; {p++; goto _out; } }} + break; + case 223: +#line 473 "char_ref.rl" + {te = p+1;{ output->first = 0x0136; {p++; goto _out; } }} + break; + case 224: +#line 474 "char_ref.rl" + {te = p+1;{ output->first = 0x041a; {p++; goto _out; } }} + break; + case 225: +#line 475 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d50e; {p++; goto _out; } }} + break; + case 226: +#line 476 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d542; {p++; goto _out; } }} + break; + case 227: +#line 477 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4a6; {p++; goto _out; } }} + break; + case 228: +#line 478 "char_ref.rl" + {te = p+1;{ output->first = 0x0409; {p++; goto _out; } }} + break; + case 229: +#line 479 "char_ref.rl" + {te = p+1;{ output->first = 0x3c; {p++; goto _out; } }} + break; + case 230: +#line 481 "char_ref.rl" + {te = p+1;{ output->first = 0x0139; {p++; goto _out; } }} + break; + case 231: +#line 482 "char_ref.rl" + {te = p+1;{ output->first = 0x039b; {p++; goto _out; } }} + break; + case 232: +#line 483 "char_ref.rl" + {te = p+1;{ output->first = 0x27ea; {p++; goto _out; } }} + break; + case 233: +#line 484 "char_ref.rl" + {te = p+1;{ output->first = 0x2112; {p++; goto _out; } }} + break; + case 234: +#line 485 "char_ref.rl" + {te = p+1;{ output->first = 0x219e; {p++; goto _out; } }} + break; + case 235: +#line 486 "char_ref.rl" + {te = p+1;{ output->first = 0x013d; {p++; goto _out; } }} + break; + case 236: +#line 487 "char_ref.rl" + {te = p+1;{ output->first = 0x013b; {p++; goto _out; } }} + break; + case 237: +#line 488 "char_ref.rl" + {te = p+1;{ output->first = 0x041b; {p++; goto _out; } }} + break; + case 238: +#line 489 "char_ref.rl" + {te = p+1;{ output->first = 0x27e8; {p++; goto _out; } }} + break; + case 239: +#line 490 "char_ref.rl" + {te = p+1;{ output->first = 0x2190; {p++; goto _out; } }} + break; + case 240: +#line 491 "char_ref.rl" + {te = p+1;{ output->first = 0x21e4; {p++; goto _out; } }} + break; + case 241: +#line 492 "char_ref.rl" + {te = p+1;{ output->first = 0x21c6; {p++; goto _out; } }} + break; + case 242: +#line 493 "char_ref.rl" + {te = p+1;{ output->first = 0x2308; {p++; goto _out; } }} + break; + case 243: +#line 494 "char_ref.rl" + {te = p+1;{ output->first = 0x27e6; {p++; goto _out; } }} + break; + case 244: +#line 495 "char_ref.rl" + {te = p+1;{ output->first = 0x2961; {p++; goto _out; } }} + break; + case 245: +#line 496 "char_ref.rl" + {te = p+1;{ output->first = 0x21c3; {p++; goto _out; } }} + break; + case 246: +#line 497 "char_ref.rl" + {te = p+1;{ output->first = 0x2959; {p++; goto _out; } }} + break; + case 247: +#line 498 "char_ref.rl" + {te = p+1;{ output->first = 0x230a; {p++; goto _out; } }} + break; + case 248: +#line 499 "char_ref.rl" + {te = p+1;{ output->first = 0x2194; {p++; goto _out; } }} + break; + case 249: +#line 500 "char_ref.rl" + {te = p+1;{ output->first = 0x294e; {p++; goto _out; } }} + break; + case 250: +#line 501 "char_ref.rl" + {te = p+1;{ output->first = 0x22a3; {p++; goto _out; } }} + break; + case 251: +#line 502 "char_ref.rl" + {te = p+1;{ output->first = 0x21a4; {p++; goto _out; } }} + break; + case 252: +#line 503 "char_ref.rl" + {te = p+1;{ output->first = 0x295a; {p++; goto _out; } }} + break; + case 253: +#line 504 "char_ref.rl" + {te = p+1;{ output->first = 0x22b2; {p++; goto _out; } }} + break; + case 254: +#line 505 "char_ref.rl" + {te = p+1;{ output->first = 0x29cf; {p++; goto _out; } }} + break; + case 255: +#line 506 "char_ref.rl" + {te = p+1;{ output->first = 0x22b4; {p++; goto _out; } }} + break; + case 256: +#line 507 "char_ref.rl" + {te = p+1;{ output->first = 0x2951; {p++; goto _out; } }} + break; + case 257: +#line 508 "char_ref.rl" + {te = p+1;{ output->first = 0x2960; {p++; goto _out; } }} + break; + case 258: +#line 509 "char_ref.rl" + {te = p+1;{ output->first = 0x21bf; {p++; goto _out; } }} + break; + case 259: +#line 510 "char_ref.rl" + {te = p+1;{ output->first = 0x2958; {p++; goto _out; } }} + break; + case 260: +#line 511 "char_ref.rl" + {te = p+1;{ output->first = 0x21bc; {p++; goto _out; } }} + break; + case 261: +#line 512 "char_ref.rl" + {te = p+1;{ output->first = 0x2952; {p++; goto _out; } }} + break; + case 262: +#line 513 "char_ref.rl" + {te = p+1;{ output->first = 0x21d0; {p++; goto _out; } }} + break; + case 263: +#line 514 "char_ref.rl" + {te = p+1;{ output->first = 0x21d4; {p++; goto _out; } }} + break; + case 264: +#line 515 "char_ref.rl" + {te = p+1;{ output->first = 0x22da; {p++; goto _out; } }} + break; + case 265: +#line 516 "char_ref.rl" + {te = p+1;{ output->first = 0x2266; {p++; goto _out; } }} + break; + case 266: +#line 517 "char_ref.rl" + {te = p+1;{ output->first = 0x2276; {p++; goto _out; } }} + break; + case 267: +#line 518 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa1; {p++; goto _out; } }} + break; + case 268: +#line 519 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; {p++; goto _out; } }} + break; + case 269: +#line 520 "char_ref.rl" + {te = p+1;{ output->first = 0x2272; {p++; goto _out; } }} + break; + case 270: +#line 521 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d50f; {p++; goto _out; } }} + break; + case 271: +#line 522 "char_ref.rl" + {te = p+1;{ output->first = 0x22d8; {p++; goto _out; } }} + break; + case 272: +#line 523 "char_ref.rl" + {te = p+1;{ output->first = 0x21da; {p++; goto _out; } }} + break; + case 273: +#line 524 "char_ref.rl" + {te = p+1;{ output->first = 0x013f; {p++; goto _out; } }} + break; + case 274: +#line 525 "char_ref.rl" + {te = p+1;{ output->first = 0x27f5; {p++; goto _out; } }} + break; + case 275: +#line 526 "char_ref.rl" + {te = p+1;{ output->first = 0x27f7; {p++; goto _out; } }} + break; + case 276: +#line 527 "char_ref.rl" + {te = p+1;{ output->first = 0x27f6; {p++; goto _out; } }} + break; + case 277: +#line 528 "char_ref.rl" + {te = p+1;{ output->first = 0x27f8; {p++; goto _out; } }} + break; + case 278: +#line 529 "char_ref.rl" + {te = p+1;{ output->first = 0x27fa; {p++; goto _out; } }} + break; + case 279: +#line 530 "char_ref.rl" + {te = p+1;{ output->first = 0x27f9; {p++; goto _out; } }} + break; + case 280: +#line 531 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d543; {p++; goto _out; } }} + break; + case 281: +#line 532 "char_ref.rl" + {te = p+1;{ output->first = 0x2199; {p++; goto _out; } }} + break; + case 282: +#line 533 "char_ref.rl" + {te = p+1;{ output->first = 0x2198; {p++; goto _out; } }} + break; + case 283: +#line 534 "char_ref.rl" + {te = p+1;{ output->first = 0x2112; {p++; goto _out; } }} + break; + case 284: +#line 535 "char_ref.rl" + {te = p+1;{ output->first = 0x21b0; {p++; goto _out; } }} + break; + case 285: +#line 536 "char_ref.rl" + {te = p+1;{ output->first = 0x0141; {p++; goto _out; } }} + break; + case 286: +#line 537 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; {p++; goto _out; } }} + break; + case 287: +#line 538 "char_ref.rl" + {te = p+1;{ output->first = 0x2905; {p++; goto _out; } }} + break; + case 288: +#line 539 "char_ref.rl" + {te = p+1;{ output->first = 0x041c; {p++; goto _out; } }} + break; + case 289: +#line 540 "char_ref.rl" + {te = p+1;{ output->first = 0x205f; {p++; goto _out; } }} + break; + case 290: +#line 541 "char_ref.rl" + {te = p+1;{ output->first = 0x2133; {p++; goto _out; } }} + break; + case 291: +#line 542 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d510; {p++; goto _out; } }} + break; + case 292: +#line 543 "char_ref.rl" + {te = p+1;{ output->first = 0x2213; {p++; goto _out; } }} + break; + case 293: +#line 544 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d544; {p++; goto _out; } }} + break; + case 294: +#line 545 "char_ref.rl" + {te = p+1;{ output->first = 0x2133; {p++; goto _out; } }} + break; + case 295: +#line 546 "char_ref.rl" + {te = p+1;{ output->first = 0x039c; {p++; goto _out; } }} + break; + case 296: +#line 547 "char_ref.rl" + {te = p+1;{ output->first = 0x040a; {p++; goto _out; } }} + break; + case 297: +#line 548 "char_ref.rl" + {te = p+1;{ output->first = 0x0143; {p++; goto _out; } }} + break; + case 298: +#line 549 "char_ref.rl" + {te = p+1;{ output->first = 0x0147; {p++; goto _out; } }} + break; + case 299: +#line 550 "char_ref.rl" + {te = p+1;{ output->first = 0x0145; {p++; goto _out; } }} + break; + case 300: +#line 551 "char_ref.rl" + {te = p+1;{ output->first = 0x041d; {p++; goto _out; } }} + break; + case 301: +#line 552 "char_ref.rl" + {te = p+1;{ output->first = 0x200b; {p++; goto _out; } }} + break; + case 302: +#line 553 "char_ref.rl" + {te = p+1;{ output->first = 0x200b; {p++; goto _out; } }} + break; + case 303: +#line 554 "char_ref.rl" + {te = p+1;{ output->first = 0x200b; {p++; goto _out; } }} + break; + case 304: +#line 555 "char_ref.rl" + {te = p+1;{ output->first = 0x200b; {p++; goto _out; } }} + break; + case 305: +#line 556 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; {p++; goto _out; } }} + break; + case 306: +#line 557 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; {p++; goto _out; } }} + break; + case 307: +#line 558 "char_ref.rl" + {te = p+1;{ output->first = 0x0a; {p++; goto _out; } }} + break; + case 308: +#line 559 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d511; {p++; goto _out; } }} + break; + case 309: +#line 560 "char_ref.rl" + {te = p+1;{ output->first = 0x2060; {p++; goto _out; } }} + break; + case 310: +#line 561 "char_ref.rl" + {te = p+1;{ output->first = 0xa0; {p++; goto _out; } }} + break; + case 311: +#line 562 "char_ref.rl" + {te = p+1;{ output->first = 0x2115; {p++; goto _out; } }} + break; + case 312: +#line 563 "char_ref.rl" + {te = p+1;{ output->first = 0x2aec; {p++; goto _out; } }} + break; + case 313: +#line 564 "char_ref.rl" + {te = p+1;{ output->first = 0x2262; {p++; goto _out; } }} + break; + case 314: +#line 565 "char_ref.rl" + {te = p+1;{ output->first = 0x226d; {p++; goto _out; } }} + break; + case 315: +#line 566 "char_ref.rl" + {te = p+1;{ output->first = 0x2226; {p++; goto _out; } }} + break; + case 316: +#line 567 "char_ref.rl" + {te = p+1;{ output->first = 0x2209; {p++; goto _out; } }} + break; + case 317: +#line 568 "char_ref.rl" + {te = p+1;{ output->first = 0x2260; {p++; goto _out; } }} + break; + case 318: +#line 569 "char_ref.rl" + {te = p+1;{ output->first = 0x2242; output->second = 0x0338; {p++; goto _out; } }} + break; + case 319: +#line 570 "char_ref.rl" + {te = p+1;{ output->first = 0x2204; {p++; goto _out; } }} + break; + case 320: +#line 571 "char_ref.rl" + {te = p+1;{ output->first = 0x226f; {p++; goto _out; } }} + break; + case 321: +#line 572 "char_ref.rl" + {te = p+1;{ output->first = 0x2271; {p++; goto _out; } }} + break; + case 322: +#line 573 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; output->second = 0x0338; {p++; goto _out; } }} + break; + case 323: +#line 574 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; output->second = 0x0338; {p++; goto _out; } }} + break; + case 324: +#line 575 "char_ref.rl" + {te = p+1;{ output->first = 0x2279; {p++; goto _out; } }} + break; + case 325: +#line 576 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; output->second = 0x0338; {p++; goto _out; } }} + break; + case 326: +#line 577 "char_ref.rl" + {te = p+1;{ output->first = 0x2275; {p++; goto _out; } }} + break; + case 327: +#line 578 "char_ref.rl" + {te = p+1;{ output->first = 0x224e; output->second = 0x0338; {p++; goto _out; } }} + break; + case 328: +#line 579 "char_ref.rl" + {te = p+1;{ output->first = 0x224f; output->second = 0x0338; {p++; goto _out; } }} + break; + case 329: +#line 580 "char_ref.rl" + {te = p+1;{ output->first = 0x22ea; {p++; goto _out; } }} + break; + case 330: +#line 581 "char_ref.rl" + {te = p+1;{ output->first = 0x29cf; output->second = 0x0338; {p++; goto _out; } }} + break; + case 331: +#line 582 "char_ref.rl" + {te = p+1;{ output->first = 0x22ec; {p++; goto _out; } }} + break; + case 332: +#line 583 "char_ref.rl" + {te = p+1;{ output->first = 0x226e; {p++; goto _out; } }} + break; + case 333: +#line 584 "char_ref.rl" + {te = p+1;{ output->first = 0x2270; {p++; goto _out; } }} + break; + case 334: +#line 585 "char_ref.rl" + {te = p+1;{ output->first = 0x2278; {p++; goto _out; } }} + break; + case 335: +#line 586 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; output->second = 0x0338; {p++; goto _out; } }} + break; + case 336: +#line 587 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; output->second = 0x0338; {p++; goto _out; } }} + break; + case 337: +#line 588 "char_ref.rl" + {te = p+1;{ output->first = 0x2274; {p++; goto _out; } }} + break; + case 338: +#line 589 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa2; output->second = 0x0338; {p++; goto _out; } }} + break; + case 339: +#line 590 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa1; output->second = 0x0338; {p++; goto _out; } }} + break; + case 340: +#line 591 "char_ref.rl" + {te = p+1;{ output->first = 0x2280; {p++; goto _out; } }} + break; + case 341: +#line 592 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; output->second = 0x0338; {p++; goto _out; } }} + break; + case 342: +#line 593 "char_ref.rl" + {te = p+1;{ output->first = 0x22e0; {p++; goto _out; } }} + break; + case 343: +#line 594 "char_ref.rl" + {te = p+1;{ output->first = 0x220c; {p++; goto _out; } }} + break; + case 344: +#line 595 "char_ref.rl" + {te = p+1;{ output->first = 0x22eb; {p++; goto _out; } }} + break; + case 345: +#line 596 "char_ref.rl" + {te = p+1;{ output->first = 0x29d0; output->second = 0x0338; {p++; goto _out; } }} + break; + case 346: +#line 597 "char_ref.rl" + {te = p+1;{ output->first = 0x22ed; {p++; goto _out; } }} + break; + case 347: +#line 598 "char_ref.rl" + {te = p+1;{ output->first = 0x228f; output->second = 0x0338; {p++; goto _out; } }} + break; + case 348: +#line 599 "char_ref.rl" + {te = p+1;{ output->first = 0x22e2; {p++; goto _out; } }} + break; + case 349: +#line 600 "char_ref.rl" + {te = p+1;{ output->first = 0x2290; output->second = 0x0338; {p++; goto _out; } }} + break; + case 350: +#line 601 "char_ref.rl" + {te = p+1;{ output->first = 0x22e3; {p++; goto _out; } }} + break; + case 351: +#line 602 "char_ref.rl" + {te = p+1;{ output->first = 0x2282; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 352: +#line 603 "char_ref.rl" + {te = p+1;{ output->first = 0x2288; {p++; goto _out; } }} + break; + case 353: +#line 604 "char_ref.rl" + {te = p+1;{ output->first = 0x2281; {p++; goto _out; } }} + break; + case 354: +#line 605 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; output->second = 0x0338; {p++; goto _out; } }} + break; + case 355: +#line 606 "char_ref.rl" + {te = p+1;{ output->first = 0x22e1; {p++; goto _out; } }} + break; + case 356: +#line 607 "char_ref.rl" + {te = p+1;{ output->first = 0x227f; output->second = 0x0338; {p++; goto _out; } }} + break; + case 357: +#line 608 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 358: +#line 609 "char_ref.rl" + {te = p+1;{ output->first = 0x2289; {p++; goto _out; } }} + break; + case 359: +#line 610 "char_ref.rl" + {te = p+1;{ output->first = 0x2241; {p++; goto _out; } }} + break; + case 360: +#line 611 "char_ref.rl" + {te = p+1;{ output->first = 0x2244; {p++; goto _out; } }} + break; + case 361: +#line 612 "char_ref.rl" + {te = p+1;{ output->first = 0x2247; {p++; goto _out; } }} + break; + case 362: +#line 613 "char_ref.rl" + {te = p+1;{ output->first = 0x2249; {p++; goto _out; } }} + break; + case 363: +#line 614 "char_ref.rl" + {te = p+1;{ output->first = 0x2224; {p++; goto _out; } }} + break; + case 364: +#line 615 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4a9; {p++; goto _out; } }} + break; + case 365: +#line 616 "char_ref.rl" + {te = p+1;{ output->first = 0xd1; {p++; goto _out; } }} + break; + case 366: +#line 618 "char_ref.rl" + {te = p+1;{ output->first = 0x039d; {p++; goto _out; } }} + break; + case 367: +#line 619 "char_ref.rl" + {te = p+1;{ output->first = 0x0152; {p++; goto _out; } }} + break; + case 368: +#line 620 "char_ref.rl" + {te = p+1;{ output->first = 0xd3; {p++; goto _out; } }} + break; + case 369: +#line 622 "char_ref.rl" + {te = p+1;{ output->first = 0xd4; {p++; goto _out; } }} + break; + case 370: +#line 624 "char_ref.rl" + {te = p+1;{ output->first = 0x041e; {p++; goto _out; } }} + break; + case 371: +#line 625 "char_ref.rl" + {te = p+1;{ output->first = 0x0150; {p++; goto _out; } }} + break; + case 372: +#line 626 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d512; {p++; goto _out; } }} + break; + case 373: +#line 627 "char_ref.rl" + {te = p+1;{ output->first = 0xd2; {p++; goto _out; } }} + break; + case 374: +#line 629 "char_ref.rl" + {te = p+1;{ output->first = 0x014c; {p++; goto _out; } }} + break; + case 375: +#line 630 "char_ref.rl" + {te = p+1;{ output->first = 0x03a9; {p++; goto _out; } }} + break; + case 376: +#line 631 "char_ref.rl" + {te = p+1;{ output->first = 0x039f; {p++; goto _out; } }} + break; + case 377: +#line 632 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d546; {p++; goto _out; } }} + break; + case 378: +#line 633 "char_ref.rl" + {te = p+1;{ output->first = 0x201c; {p++; goto _out; } }} + break; + case 379: +#line 634 "char_ref.rl" + {te = p+1;{ output->first = 0x2018; {p++; goto _out; } }} + break; + case 380: +#line 635 "char_ref.rl" + {te = p+1;{ output->first = 0x2a54; {p++; goto _out; } }} + break; + case 381: +#line 636 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4aa; {p++; goto _out; } }} + break; + case 382: +#line 637 "char_ref.rl" + {te = p+1;{ output->first = 0xd8; {p++; goto _out; } }} + break; + case 383: +#line 639 "char_ref.rl" + {te = p+1;{ output->first = 0xd5; {p++; goto _out; } }} + break; + case 384: +#line 641 "char_ref.rl" + {te = p+1;{ output->first = 0x2a37; {p++; goto _out; } }} + break; + case 385: +#line 642 "char_ref.rl" + {te = p+1;{ output->first = 0xd6; {p++; goto _out; } }} + break; + case 386: +#line 644 "char_ref.rl" + {te = p+1;{ output->first = 0x203e; {p++; goto _out; } }} + break; + case 387: +#line 645 "char_ref.rl" + {te = p+1;{ output->first = 0x23de; {p++; goto _out; } }} + break; + case 388: +#line 646 "char_ref.rl" + {te = p+1;{ output->first = 0x23b4; {p++; goto _out; } }} + break; + case 389: +#line 647 "char_ref.rl" + {te = p+1;{ output->first = 0x23dc; {p++; goto _out; } }} + break; + case 390: +#line 648 "char_ref.rl" + {te = p+1;{ output->first = 0x2202; {p++; goto _out; } }} + break; + case 391: +#line 649 "char_ref.rl" + {te = p+1;{ output->first = 0x041f; {p++; goto _out; } }} + break; + case 392: +#line 650 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d513; {p++; goto _out; } }} + break; + case 393: +#line 651 "char_ref.rl" + {te = p+1;{ output->first = 0x03a6; {p++; goto _out; } }} + break; + case 394: +#line 652 "char_ref.rl" + {te = p+1;{ output->first = 0x03a0; {p++; goto _out; } }} + break; + case 395: +#line 653 "char_ref.rl" + {te = p+1;{ output->first = 0xb1; {p++; goto _out; } }} + break; + case 396: +#line 654 "char_ref.rl" + {te = p+1;{ output->first = 0x210c; {p++; goto _out; } }} + break; + case 397: +#line 655 "char_ref.rl" + {te = p+1;{ output->first = 0x2119; {p++; goto _out; } }} + break; + case 398: +#line 656 "char_ref.rl" + {te = p+1;{ output->first = 0x2abb; {p++; goto _out; } }} + break; + case 399: +#line 657 "char_ref.rl" + {te = p+1;{ output->first = 0x227a; {p++; goto _out; } }} + break; + case 400: +#line 658 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; {p++; goto _out; } }} + break; + case 401: +#line 659 "char_ref.rl" + {te = p+1;{ output->first = 0x227c; {p++; goto _out; } }} + break; + case 402: +#line 660 "char_ref.rl" + {te = p+1;{ output->first = 0x227e; {p++; goto _out; } }} + break; + case 403: +#line 661 "char_ref.rl" + {te = p+1;{ output->first = 0x2033; {p++; goto _out; } }} + break; + case 404: +#line 662 "char_ref.rl" + {te = p+1;{ output->first = 0x220f; {p++; goto _out; } }} + break; + case 405: +#line 663 "char_ref.rl" + {te = p+1;{ output->first = 0x2237; {p++; goto _out; } }} + break; + case 406: +#line 664 "char_ref.rl" + {te = p+1;{ output->first = 0x221d; {p++; goto _out; } }} + break; + case 407: +#line 665 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4ab; {p++; goto _out; } }} + break; + case 408: +#line 666 "char_ref.rl" + {te = p+1;{ output->first = 0x03a8; {p++; goto _out; } }} + break; + case 409: +#line 667 "char_ref.rl" + {te = p+1;{ output->first = 0x22; {p++; goto _out; } }} + break; + case 410: +#line 669 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d514; {p++; goto _out; } }} + break; + case 411: +#line 670 "char_ref.rl" + {te = p+1;{ output->first = 0x211a; {p++; goto _out; } }} + break; + case 412: +#line 671 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4ac; {p++; goto _out; } }} + break; + case 413: +#line 672 "char_ref.rl" + {te = p+1;{ output->first = 0x2910; {p++; goto _out; } }} + break; + case 414: +#line 673 "char_ref.rl" + {te = p+1;{ output->first = 0xae; {p++; goto _out; } }} + break; + case 415: +#line 675 "char_ref.rl" + {te = p+1;{ output->first = 0x0154; {p++; goto _out; } }} + break; + case 416: +#line 676 "char_ref.rl" + {te = p+1;{ output->first = 0x27eb; {p++; goto _out; } }} + break; + case 417: +#line 677 "char_ref.rl" + {te = p+1;{ output->first = 0x21a0; {p++; goto _out; } }} + break; + case 418: +#line 678 "char_ref.rl" + {te = p+1;{ output->first = 0x2916; {p++; goto _out; } }} + break; + case 419: +#line 679 "char_ref.rl" + {te = p+1;{ output->first = 0x0158; {p++; goto _out; } }} + break; + case 420: +#line 680 "char_ref.rl" + {te = p+1;{ output->first = 0x0156; {p++; goto _out; } }} + break; + case 421: +#line 681 "char_ref.rl" + {te = p+1;{ output->first = 0x0420; {p++; goto _out; } }} + break; + case 422: +#line 682 "char_ref.rl" + {te = p+1;{ output->first = 0x211c; {p++; goto _out; } }} + break; + case 423: +#line 683 "char_ref.rl" + {te = p+1;{ output->first = 0x220b; {p++; goto _out; } }} + break; + case 424: +#line 684 "char_ref.rl" + {te = p+1;{ output->first = 0x21cb; {p++; goto _out; } }} + break; + case 425: +#line 685 "char_ref.rl" + {te = p+1;{ output->first = 0x296f; {p++; goto _out; } }} + break; + case 426: +#line 686 "char_ref.rl" + {te = p+1;{ output->first = 0x211c; {p++; goto _out; } }} + break; + case 427: +#line 687 "char_ref.rl" + {te = p+1;{ output->first = 0x03a1; {p++; goto _out; } }} + break; + case 428: +#line 688 "char_ref.rl" + {te = p+1;{ output->first = 0x27e9; {p++; goto _out; } }} + break; + case 429: +#line 689 "char_ref.rl" + {te = p+1;{ output->first = 0x2192; {p++; goto _out; } }} + break; + case 430: +#line 690 "char_ref.rl" + {te = p+1;{ output->first = 0x21e5; {p++; goto _out; } }} + break; + case 431: +#line 691 "char_ref.rl" + {te = p+1;{ output->first = 0x21c4; {p++; goto _out; } }} + break; + case 432: +#line 692 "char_ref.rl" + {te = p+1;{ output->first = 0x2309; {p++; goto _out; } }} + break; + case 433: +#line 693 "char_ref.rl" + {te = p+1;{ output->first = 0x27e7; {p++; goto _out; } }} + break; + case 434: +#line 694 "char_ref.rl" + {te = p+1;{ output->first = 0x295d; {p++; goto _out; } }} + break; + case 435: +#line 695 "char_ref.rl" + {te = p+1;{ output->first = 0x21c2; {p++; goto _out; } }} + break; + case 436: +#line 696 "char_ref.rl" + {te = p+1;{ output->first = 0x2955; {p++; goto _out; } }} + break; + case 437: +#line 697 "char_ref.rl" + {te = p+1;{ output->first = 0x230b; {p++; goto _out; } }} + break; + case 438: +#line 698 "char_ref.rl" + {te = p+1;{ output->first = 0x22a2; {p++; goto _out; } }} + break; + case 439: +#line 699 "char_ref.rl" + {te = p+1;{ output->first = 0x21a6; {p++; goto _out; } }} + break; + case 440: +#line 700 "char_ref.rl" + {te = p+1;{ output->first = 0x295b; {p++; goto _out; } }} + break; + case 441: +#line 701 "char_ref.rl" + {te = p+1;{ output->first = 0x22b3; {p++; goto _out; } }} + break; + case 442: +#line 702 "char_ref.rl" + {te = p+1;{ output->first = 0x29d0; {p++; goto _out; } }} + break; + case 443: +#line 703 "char_ref.rl" + {te = p+1;{ output->first = 0x22b5; {p++; goto _out; } }} + break; + case 444: +#line 704 "char_ref.rl" + {te = p+1;{ output->first = 0x294f; {p++; goto _out; } }} + break; + case 445: +#line 705 "char_ref.rl" + {te = p+1;{ output->first = 0x295c; {p++; goto _out; } }} + break; + case 446: +#line 706 "char_ref.rl" + {te = p+1;{ output->first = 0x21be; {p++; goto _out; } }} + break; + case 447: +#line 707 "char_ref.rl" + {te = p+1;{ output->first = 0x2954; {p++; goto _out; } }} + break; + case 448: +#line 708 "char_ref.rl" + {te = p+1;{ output->first = 0x21c0; {p++; goto _out; } }} + break; + case 449: +#line 709 "char_ref.rl" + {te = p+1;{ output->first = 0x2953; {p++; goto _out; } }} + break; + case 450: +#line 710 "char_ref.rl" + {te = p+1;{ output->first = 0x21d2; {p++; goto _out; } }} + break; + case 451: +#line 711 "char_ref.rl" + {te = p+1;{ output->first = 0x211d; {p++; goto _out; } }} + break; + case 452: +#line 712 "char_ref.rl" + {te = p+1;{ output->first = 0x2970; {p++; goto _out; } }} + break; + case 453: +#line 713 "char_ref.rl" + {te = p+1;{ output->first = 0x21db; {p++; goto _out; } }} + break; + case 454: +#line 714 "char_ref.rl" + {te = p+1;{ output->first = 0x211b; {p++; goto _out; } }} + break; + case 455: +#line 715 "char_ref.rl" + {te = p+1;{ output->first = 0x21b1; {p++; goto _out; } }} + break; + case 456: +#line 716 "char_ref.rl" + {te = p+1;{ output->first = 0x29f4; {p++; goto _out; } }} + break; + case 457: +#line 717 "char_ref.rl" + {te = p+1;{ output->first = 0x0429; {p++; goto _out; } }} + break; + case 458: +#line 718 "char_ref.rl" + {te = p+1;{ output->first = 0x0428; {p++; goto _out; } }} + break; + case 459: +#line 719 "char_ref.rl" + {te = p+1;{ output->first = 0x042c; {p++; goto _out; } }} + break; + case 460: +#line 720 "char_ref.rl" + {te = p+1;{ output->first = 0x015a; {p++; goto _out; } }} + break; + case 461: +#line 721 "char_ref.rl" + {te = p+1;{ output->first = 0x2abc; {p++; goto _out; } }} + break; + case 462: +#line 722 "char_ref.rl" + {te = p+1;{ output->first = 0x0160; {p++; goto _out; } }} + break; + case 463: +#line 723 "char_ref.rl" + {te = p+1;{ output->first = 0x015e; {p++; goto _out; } }} + break; + case 464: +#line 724 "char_ref.rl" + {te = p+1;{ output->first = 0x015c; {p++; goto _out; } }} + break; + case 465: +#line 725 "char_ref.rl" + {te = p+1;{ output->first = 0x0421; {p++; goto _out; } }} + break; + case 466: +#line 726 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d516; {p++; goto _out; } }} + break; + case 467: +#line 727 "char_ref.rl" + {te = p+1;{ output->first = 0x2193; {p++; goto _out; } }} + break; + case 468: +#line 728 "char_ref.rl" + {te = p+1;{ output->first = 0x2190; {p++; goto _out; } }} + break; + case 469: +#line 729 "char_ref.rl" + {te = p+1;{ output->first = 0x2192; {p++; goto _out; } }} + break; + case 470: +#line 730 "char_ref.rl" + {te = p+1;{ output->first = 0x2191; {p++; goto _out; } }} + break; + case 471: +#line 731 "char_ref.rl" + {te = p+1;{ output->first = 0x03a3; {p++; goto _out; } }} + break; + case 472: +#line 732 "char_ref.rl" + {te = p+1;{ output->first = 0x2218; {p++; goto _out; } }} + break; + case 473: +#line 733 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54a; {p++; goto _out; } }} + break; + case 474: +#line 734 "char_ref.rl" + {te = p+1;{ output->first = 0x221a; {p++; goto _out; } }} + break; + case 475: +#line 735 "char_ref.rl" + {te = p+1;{ output->first = 0x25a1; {p++; goto _out; } }} + break; + case 476: +#line 736 "char_ref.rl" + {te = p+1;{ output->first = 0x2293; {p++; goto _out; } }} + break; + case 477: +#line 737 "char_ref.rl" + {te = p+1;{ output->first = 0x228f; {p++; goto _out; } }} + break; + case 478: +#line 738 "char_ref.rl" + {te = p+1;{ output->first = 0x2291; {p++; goto _out; } }} + break; + case 479: +#line 739 "char_ref.rl" + {te = p+1;{ output->first = 0x2290; {p++; goto _out; } }} + break; + case 480: +#line 740 "char_ref.rl" + {te = p+1;{ output->first = 0x2292; {p++; goto _out; } }} + break; + case 481: +#line 741 "char_ref.rl" + {te = p+1;{ output->first = 0x2294; {p++; goto _out; } }} + break; + case 482: +#line 742 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4ae; {p++; goto _out; } }} + break; + case 483: +#line 743 "char_ref.rl" + {te = p+1;{ output->first = 0x22c6; {p++; goto _out; } }} + break; + case 484: +#line 744 "char_ref.rl" + {te = p+1;{ output->first = 0x22d0; {p++; goto _out; } }} + break; + case 485: +#line 745 "char_ref.rl" + {te = p+1;{ output->first = 0x22d0; {p++; goto _out; } }} + break; + case 486: +#line 746 "char_ref.rl" + {te = p+1;{ output->first = 0x2286; {p++; goto _out; } }} + break; + case 487: +#line 747 "char_ref.rl" + {te = p+1;{ output->first = 0x227b; {p++; goto _out; } }} + break; + case 488: +#line 748 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; {p++; goto _out; } }} + break; + case 489: +#line 749 "char_ref.rl" + {te = p+1;{ output->first = 0x227d; {p++; goto _out; } }} + break; + case 490: +#line 750 "char_ref.rl" + {te = p+1;{ output->first = 0x227f; {p++; goto _out; } }} + break; + case 491: +#line 751 "char_ref.rl" + {te = p+1;{ output->first = 0x220b; {p++; goto _out; } }} + break; + case 492: +#line 752 "char_ref.rl" + {te = p+1;{ output->first = 0x2211; {p++; goto _out; } }} + break; + case 493: +#line 753 "char_ref.rl" + {te = p+1;{ output->first = 0x22d1; {p++; goto _out; } }} + break; + case 494: +#line 754 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; {p++; goto _out; } }} + break; + case 495: +#line 755 "char_ref.rl" + {te = p+1;{ output->first = 0x2287; {p++; goto _out; } }} + break; + case 496: +#line 756 "char_ref.rl" + {te = p+1;{ output->first = 0x22d1; {p++; goto _out; } }} + break; + case 497: +#line 757 "char_ref.rl" + {te = p+1;{ output->first = 0xde; {p++; goto _out; } }} + break; + case 498: +#line 759 "char_ref.rl" + {te = p+1;{ output->first = 0x2122; {p++; goto _out; } }} + break; + case 499: +#line 760 "char_ref.rl" + {te = p+1;{ output->first = 0x040b; {p++; goto _out; } }} + break; + case 500: +#line 761 "char_ref.rl" + {te = p+1;{ output->first = 0x0426; {p++; goto _out; } }} + break; + case 501: +#line 762 "char_ref.rl" + {te = p+1;{ output->first = 0x09; {p++; goto _out; } }} + break; + case 502: +#line 763 "char_ref.rl" + {te = p+1;{ output->first = 0x03a4; {p++; goto _out; } }} + break; + case 503: +#line 764 "char_ref.rl" + {te = p+1;{ output->first = 0x0164; {p++; goto _out; } }} + break; + case 504: +#line 765 "char_ref.rl" + {te = p+1;{ output->first = 0x0162; {p++; goto _out; } }} + break; + case 505: +#line 766 "char_ref.rl" + {te = p+1;{ output->first = 0x0422; {p++; goto _out; } }} + break; + case 506: +#line 767 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d517; {p++; goto _out; } }} + break; + case 507: +#line 768 "char_ref.rl" + {te = p+1;{ output->first = 0x2234; {p++; goto _out; } }} + break; + case 508: +#line 769 "char_ref.rl" + {te = p+1;{ output->first = 0x0398; {p++; goto _out; } }} + break; + case 509: +#line 770 "char_ref.rl" + {te = p+1;{ output->first = 0x205f; output->second = 0x200a; {p++; goto _out; } }} + break; + case 510: +#line 771 "char_ref.rl" + {te = p+1;{ output->first = 0x2009; {p++; goto _out; } }} + break; + case 511: +#line 772 "char_ref.rl" + {te = p+1;{ output->first = 0x223c; {p++; goto _out; } }} + break; + case 512: +#line 773 "char_ref.rl" + {te = p+1;{ output->first = 0x2243; {p++; goto _out; } }} + break; + case 513: +#line 774 "char_ref.rl" + {te = p+1;{ output->first = 0x2245; {p++; goto _out; } }} + break; + case 514: +#line 775 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 515: +#line 776 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54b; {p++; goto _out; } }} + break; + case 516: +#line 777 "char_ref.rl" + {te = p+1;{ output->first = 0x20db; {p++; goto _out; } }} + break; + case 517: +#line 778 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4af; {p++; goto _out; } }} + break; + case 518: +#line 779 "char_ref.rl" + {te = p+1;{ output->first = 0x0166; {p++; goto _out; } }} + break; + case 519: +#line 780 "char_ref.rl" + {te = p+1;{ output->first = 0xda; {p++; goto _out; } }} + break; + case 520: +#line 782 "char_ref.rl" + {te = p+1;{ output->first = 0x219f; {p++; goto _out; } }} + break; + case 521: +#line 783 "char_ref.rl" + {te = p+1;{ output->first = 0x2949; {p++; goto _out; } }} + break; + case 522: +#line 784 "char_ref.rl" + {te = p+1;{ output->first = 0x040e; {p++; goto _out; } }} + break; + case 523: +#line 785 "char_ref.rl" + {te = p+1;{ output->first = 0x016c; {p++; goto _out; } }} + break; + case 524: +#line 786 "char_ref.rl" + {te = p+1;{ output->first = 0xdb; {p++; goto _out; } }} + break; + case 525: +#line 788 "char_ref.rl" + {te = p+1;{ output->first = 0x0423; {p++; goto _out; } }} + break; + case 526: +#line 789 "char_ref.rl" + {te = p+1;{ output->first = 0x0170; {p++; goto _out; } }} + break; + case 527: +#line 790 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d518; {p++; goto _out; } }} + break; + case 528: +#line 791 "char_ref.rl" + {te = p+1;{ output->first = 0xd9; {p++; goto _out; } }} + break; + case 529: +#line 793 "char_ref.rl" + {te = p+1;{ output->first = 0x016a; {p++; goto _out; } }} + break; + case 530: +#line 794 "char_ref.rl" + {te = p+1;{ output->first = 0x5f; {p++; goto _out; } }} + break; + case 531: +#line 795 "char_ref.rl" + {te = p+1;{ output->first = 0x23df; {p++; goto _out; } }} + break; + case 532: +#line 796 "char_ref.rl" + {te = p+1;{ output->first = 0x23b5; {p++; goto _out; } }} + break; + case 533: +#line 797 "char_ref.rl" + {te = p+1;{ output->first = 0x23dd; {p++; goto _out; } }} + break; + case 534: +#line 798 "char_ref.rl" + {te = p+1;{ output->first = 0x22c3; {p++; goto _out; } }} + break; + case 535: +#line 799 "char_ref.rl" + {te = p+1;{ output->first = 0x228e; {p++; goto _out; } }} + break; + case 536: +#line 800 "char_ref.rl" + {te = p+1;{ output->first = 0x0172; {p++; goto _out; } }} + break; + case 537: +#line 801 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54c; {p++; goto _out; } }} + break; + case 538: +#line 802 "char_ref.rl" + {te = p+1;{ output->first = 0x2191; {p++; goto _out; } }} + break; + case 539: +#line 803 "char_ref.rl" + {te = p+1;{ output->first = 0x2912; {p++; goto _out; } }} + break; + case 540: +#line 804 "char_ref.rl" + {te = p+1;{ output->first = 0x21c5; {p++; goto _out; } }} + break; + case 541: +#line 805 "char_ref.rl" + {te = p+1;{ output->first = 0x2195; {p++; goto _out; } }} + break; + case 542: +#line 806 "char_ref.rl" + {te = p+1;{ output->first = 0x296e; {p++; goto _out; } }} + break; + case 543: +#line 807 "char_ref.rl" + {te = p+1;{ output->first = 0x22a5; {p++; goto _out; } }} + break; + case 544: +#line 808 "char_ref.rl" + {te = p+1;{ output->first = 0x21a5; {p++; goto _out; } }} + break; + case 545: +#line 809 "char_ref.rl" + {te = p+1;{ output->first = 0x21d1; {p++; goto _out; } }} + break; + case 546: +#line 810 "char_ref.rl" + {te = p+1;{ output->first = 0x21d5; {p++; goto _out; } }} + break; + case 547: +#line 811 "char_ref.rl" + {te = p+1;{ output->first = 0x2196; {p++; goto _out; } }} + break; + case 548: +#line 812 "char_ref.rl" + {te = p+1;{ output->first = 0x2197; {p++; goto _out; } }} + break; + case 549: +#line 813 "char_ref.rl" + {te = p+1;{ output->first = 0x03d2; {p++; goto _out; } }} + break; + case 550: +#line 814 "char_ref.rl" + {te = p+1;{ output->first = 0x03a5; {p++; goto _out; } }} + break; + case 551: +#line 815 "char_ref.rl" + {te = p+1;{ output->first = 0x016e; {p++; goto _out; } }} + break; + case 552: +#line 816 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b0; {p++; goto _out; } }} + break; + case 553: +#line 817 "char_ref.rl" + {te = p+1;{ output->first = 0x0168; {p++; goto _out; } }} + break; + case 554: +#line 818 "char_ref.rl" + {te = p+1;{ output->first = 0xdc; {p++; goto _out; } }} + break; + case 555: +#line 820 "char_ref.rl" + {te = p+1;{ output->first = 0x22ab; {p++; goto _out; } }} + break; + case 556: +#line 821 "char_ref.rl" + {te = p+1;{ output->first = 0x2aeb; {p++; goto _out; } }} + break; + case 557: +#line 822 "char_ref.rl" + {te = p+1;{ output->first = 0x0412; {p++; goto _out; } }} + break; + case 558: +#line 823 "char_ref.rl" + {te = p+1;{ output->first = 0x22a9; {p++; goto _out; } }} + break; + case 559: +#line 824 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae6; {p++; goto _out; } }} + break; + case 560: +#line 825 "char_ref.rl" + {te = p+1;{ output->first = 0x22c1; {p++; goto _out; } }} + break; + case 561: +#line 826 "char_ref.rl" + {te = p+1;{ output->first = 0x2016; {p++; goto _out; } }} + break; + case 562: +#line 827 "char_ref.rl" + {te = p+1;{ output->first = 0x2016; {p++; goto _out; } }} + break; + case 563: +#line 828 "char_ref.rl" + {te = p+1;{ output->first = 0x2223; {p++; goto _out; } }} + break; + case 564: +#line 829 "char_ref.rl" + {te = p+1;{ output->first = 0x7c; {p++; goto _out; } }} + break; + case 565: +#line 830 "char_ref.rl" + {te = p+1;{ output->first = 0x2758; {p++; goto _out; } }} + break; + case 566: +#line 831 "char_ref.rl" + {te = p+1;{ output->first = 0x2240; {p++; goto _out; } }} + break; + case 567: +#line 832 "char_ref.rl" + {te = p+1;{ output->first = 0x200a; {p++; goto _out; } }} + break; + case 568: +#line 833 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d519; {p++; goto _out; } }} + break; + case 569: +#line 834 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54d; {p++; goto _out; } }} + break; + case 570: +#line 835 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b1; {p++; goto _out; } }} + break; + case 571: +#line 836 "char_ref.rl" + {te = p+1;{ output->first = 0x22aa; {p++; goto _out; } }} + break; + case 572: +#line 837 "char_ref.rl" + {te = p+1;{ output->first = 0x0174; {p++; goto _out; } }} + break; + case 573: +#line 838 "char_ref.rl" + {te = p+1;{ output->first = 0x22c0; {p++; goto _out; } }} + break; + case 574: +#line 839 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d51a; {p++; goto _out; } }} + break; + case 575: +#line 840 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54e; {p++; goto _out; } }} + break; + case 576: +#line 841 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b2; {p++; goto _out; } }} + break; + case 577: +#line 842 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d51b; {p++; goto _out; } }} + break; + case 578: +#line 843 "char_ref.rl" + {te = p+1;{ output->first = 0x039e; {p++; goto _out; } }} + break; + case 579: +#line 844 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d54f; {p++; goto _out; } }} + break; + case 580: +#line 845 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b3; {p++; goto _out; } }} + break; + case 581: +#line 846 "char_ref.rl" + {te = p+1;{ output->first = 0x042f; {p++; goto _out; } }} + break; + case 582: +#line 847 "char_ref.rl" + {te = p+1;{ output->first = 0x0407; {p++; goto _out; } }} + break; + case 583: +#line 848 "char_ref.rl" + {te = p+1;{ output->first = 0x042e; {p++; goto _out; } }} + break; + case 584: +#line 849 "char_ref.rl" + {te = p+1;{ output->first = 0xdd; {p++; goto _out; } }} + break; + case 585: +#line 851 "char_ref.rl" + {te = p+1;{ output->first = 0x0176; {p++; goto _out; } }} + break; + case 586: +#line 852 "char_ref.rl" + {te = p+1;{ output->first = 0x042b; {p++; goto _out; } }} + break; + case 587: +#line 853 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d51c; {p++; goto _out; } }} + break; + case 588: +#line 854 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d550; {p++; goto _out; } }} + break; + case 589: +#line 855 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b4; {p++; goto _out; } }} + break; + case 590: +#line 856 "char_ref.rl" + {te = p+1;{ output->first = 0x0178; {p++; goto _out; } }} + break; + case 591: +#line 857 "char_ref.rl" + {te = p+1;{ output->first = 0x0416; {p++; goto _out; } }} + break; + case 592: +#line 858 "char_ref.rl" + {te = p+1;{ output->first = 0x0179; {p++; goto _out; } }} + break; + case 593: +#line 859 "char_ref.rl" + {te = p+1;{ output->first = 0x017d; {p++; goto _out; } }} + break; + case 594: +#line 860 "char_ref.rl" + {te = p+1;{ output->first = 0x0417; {p++; goto _out; } }} + break; + case 595: +#line 861 "char_ref.rl" + {te = p+1;{ output->first = 0x017b; {p++; goto _out; } }} + break; + case 596: +#line 862 "char_ref.rl" + {te = p+1;{ output->first = 0x200b; {p++; goto _out; } }} + break; + case 597: +#line 863 "char_ref.rl" + {te = p+1;{ output->first = 0x0396; {p++; goto _out; } }} + break; + case 598: +#line 864 "char_ref.rl" + {te = p+1;{ output->first = 0x2128; {p++; goto _out; } }} + break; + case 599: +#line 865 "char_ref.rl" + {te = p+1;{ output->first = 0x2124; {p++; goto _out; } }} + break; + case 600: +#line 866 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b5; {p++; goto _out; } }} + break; + case 601: +#line 867 "char_ref.rl" + {te = p+1;{ output->first = 0xe1; {p++; goto _out; } }} + break; + case 602: +#line 869 "char_ref.rl" + {te = p+1;{ output->first = 0x0103; {p++; goto _out; } }} + break; + case 603: +#line 870 "char_ref.rl" + {te = p+1;{ output->first = 0x223e; {p++; goto _out; } }} + break; + case 604: +#line 871 "char_ref.rl" + {te = p+1;{ output->first = 0x223e; output->second = 0x0333; {p++; goto _out; } }} + break; + case 605: +#line 872 "char_ref.rl" + {te = p+1;{ output->first = 0x223f; {p++; goto _out; } }} + break; + case 606: +#line 873 "char_ref.rl" + {te = p+1;{ output->first = 0xe2; {p++; goto _out; } }} + break; + case 607: +#line 875 "char_ref.rl" + {te = p+1;{ output->first = 0xb4; {p++; goto _out; } }} + break; + case 608: +#line 877 "char_ref.rl" + {te = p+1;{ output->first = 0x0430; {p++; goto _out; } }} + break; + case 609: +#line 878 "char_ref.rl" + {te = p+1;{ output->first = 0xe6; {p++; goto _out; } }} + break; + case 610: +#line 880 "char_ref.rl" + {te = p+1;{ output->first = 0x2061; {p++; goto _out; } }} + break; + case 611: +#line 881 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d51e; {p++; goto _out; } }} + break; + case 612: +#line 882 "char_ref.rl" + {te = p+1;{ output->first = 0xe0; {p++; goto _out; } }} + break; + case 613: +#line 884 "char_ref.rl" + {te = p+1;{ output->first = 0x2135; {p++; goto _out; } }} + break; + case 614: +#line 885 "char_ref.rl" + {te = p+1;{ output->first = 0x2135; {p++; goto _out; } }} + break; + case 615: +#line 886 "char_ref.rl" + {te = p+1;{ output->first = 0x03b1; {p++; goto _out; } }} + break; + case 616: +#line 887 "char_ref.rl" + {te = p+1;{ output->first = 0x0101; {p++; goto _out; } }} + break; + case 617: +#line 888 "char_ref.rl" + {te = p+1;{ output->first = 0x2a3f; {p++; goto _out; } }} + break; + case 618: +#line 889 "char_ref.rl" + {te = p+1;{ output->first = 0x26; {p++; goto _out; } }} + break; + case 619: +#line 891 "char_ref.rl" + {te = p+1;{ output->first = 0x2227; {p++; goto _out; } }} + break; + case 620: +#line 892 "char_ref.rl" + {te = p+1;{ output->first = 0x2a55; {p++; goto _out; } }} + break; + case 621: +#line 893 "char_ref.rl" + {te = p+1;{ output->first = 0x2a5c; {p++; goto _out; } }} + break; + case 622: +#line 894 "char_ref.rl" + {te = p+1;{ output->first = 0x2a58; {p++; goto _out; } }} + break; + case 623: +#line 895 "char_ref.rl" + {te = p+1;{ output->first = 0x2a5a; {p++; goto _out; } }} + break; + case 624: +#line 896 "char_ref.rl" + {te = p+1;{ output->first = 0x2220; {p++; goto _out; } }} + break; + case 625: +#line 897 "char_ref.rl" + {te = p+1;{ output->first = 0x29a4; {p++; goto _out; } }} + break; + case 626: +#line 898 "char_ref.rl" + {te = p+1;{ output->first = 0x2220; {p++; goto _out; } }} + break; + case 627: +#line 899 "char_ref.rl" + {te = p+1;{ output->first = 0x2221; {p++; goto _out; } }} + break; + case 628: +#line 900 "char_ref.rl" + {te = p+1;{ output->first = 0x29a8; {p++; goto _out; } }} + break; + case 629: +#line 901 "char_ref.rl" + {te = p+1;{ output->first = 0x29a9; {p++; goto _out; } }} + break; + case 630: +#line 902 "char_ref.rl" + {te = p+1;{ output->first = 0x29aa; {p++; goto _out; } }} + break; + case 631: +#line 903 "char_ref.rl" + {te = p+1;{ output->first = 0x29ab; {p++; goto _out; } }} + break; + case 632: +#line 904 "char_ref.rl" + {te = p+1;{ output->first = 0x29ac; {p++; goto _out; } }} + break; + case 633: +#line 905 "char_ref.rl" + {te = p+1;{ output->first = 0x29ad; {p++; goto _out; } }} + break; + case 634: +#line 906 "char_ref.rl" + {te = p+1;{ output->first = 0x29ae; {p++; goto _out; } }} + break; + case 635: +#line 907 "char_ref.rl" + {te = p+1;{ output->first = 0x29af; {p++; goto _out; } }} + break; + case 636: +#line 908 "char_ref.rl" + {te = p+1;{ output->first = 0x221f; {p++; goto _out; } }} + break; + case 637: +#line 909 "char_ref.rl" + {te = p+1;{ output->first = 0x22be; {p++; goto _out; } }} + break; + case 638: +#line 910 "char_ref.rl" + {te = p+1;{ output->first = 0x299d; {p++; goto _out; } }} + break; + case 639: +#line 911 "char_ref.rl" + {te = p+1;{ output->first = 0x2222; {p++; goto _out; } }} + break; + case 640: +#line 912 "char_ref.rl" + {te = p+1;{ output->first = 0xc5; {p++; goto _out; } }} + break; + case 641: +#line 913 "char_ref.rl" + {te = p+1;{ output->first = 0x237c; {p++; goto _out; } }} + break; + case 642: +#line 914 "char_ref.rl" + {te = p+1;{ output->first = 0x0105; {p++; goto _out; } }} + break; + case 643: +#line 915 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d552; {p++; goto _out; } }} + break; + case 644: +#line 916 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 645: +#line 917 "char_ref.rl" + {te = p+1;{ output->first = 0x2a70; {p++; goto _out; } }} + break; + case 646: +#line 918 "char_ref.rl" + {te = p+1;{ output->first = 0x2a6f; {p++; goto _out; } }} + break; + case 647: +#line 919 "char_ref.rl" + {te = p+1;{ output->first = 0x224a; {p++; goto _out; } }} + break; + case 648: +#line 920 "char_ref.rl" + {te = p+1;{ output->first = 0x224b; {p++; goto _out; } }} + break; + case 649: +#line 921 "char_ref.rl" + {te = p+1;{ output->first = 0x27; {p++; goto _out; } }} + break; + case 650: +#line 922 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 651: +#line 923 "char_ref.rl" + {te = p+1;{ output->first = 0x224a; {p++; goto _out; } }} + break; + case 652: +#line 924 "char_ref.rl" + {te = p+1;{ output->first = 0xe5; {p++; goto _out; } }} + break; + case 653: +#line 926 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b6; {p++; goto _out; } }} + break; + case 654: +#line 927 "char_ref.rl" + {te = p+1;{ output->first = 0x2a; {p++; goto _out; } }} + break; + case 655: +#line 928 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 656: +#line 929 "char_ref.rl" + {te = p+1;{ output->first = 0x224d; {p++; goto _out; } }} + break; + case 657: +#line 930 "char_ref.rl" + {te = p+1;{ output->first = 0xe3; {p++; goto _out; } }} + break; + case 658: +#line 932 "char_ref.rl" + {te = p+1;{ output->first = 0xe4; {p++; goto _out; } }} + break; + case 659: +#line 934 "char_ref.rl" + {te = p+1;{ output->first = 0x2233; {p++; goto _out; } }} + break; + case 660: +#line 935 "char_ref.rl" + {te = p+1;{ output->first = 0x2a11; {p++; goto _out; } }} + break; + case 661: +#line 936 "char_ref.rl" + {te = p+1;{ output->first = 0x2aed; {p++; goto _out; } }} + break; + case 662: +#line 937 "char_ref.rl" + {te = p+1;{ output->first = 0x224c; {p++; goto _out; } }} + break; + case 663: +#line 938 "char_ref.rl" + {te = p+1;{ output->first = 0x03f6; {p++; goto _out; } }} + break; + case 664: +#line 939 "char_ref.rl" + {te = p+1;{ output->first = 0x2035; {p++; goto _out; } }} + break; + case 665: +#line 940 "char_ref.rl" + {te = p+1;{ output->first = 0x223d; {p++; goto _out; } }} + break; + case 666: +#line 941 "char_ref.rl" + {te = p+1;{ output->first = 0x22cd; {p++; goto _out; } }} + break; + case 667: +#line 942 "char_ref.rl" + {te = p+1;{ output->first = 0x22bd; {p++; goto _out; } }} + break; + case 668: +#line 943 "char_ref.rl" + {te = p+1;{ output->first = 0x2305; {p++; goto _out; } }} + break; + case 669: +#line 944 "char_ref.rl" + {te = p+1;{ output->first = 0x2305; {p++; goto _out; } }} + break; + case 670: +#line 945 "char_ref.rl" + {te = p+1;{ output->first = 0x23b5; {p++; goto _out; } }} + break; + case 671: +#line 946 "char_ref.rl" + {te = p+1;{ output->first = 0x23b6; {p++; goto _out; } }} + break; + case 672: +#line 947 "char_ref.rl" + {te = p+1;{ output->first = 0x224c; {p++; goto _out; } }} + break; + case 673: +#line 948 "char_ref.rl" + {te = p+1;{ output->first = 0x0431; {p++; goto _out; } }} + break; + case 674: +#line 949 "char_ref.rl" + {te = p+1;{ output->first = 0x201e; {p++; goto _out; } }} + break; + case 675: +#line 950 "char_ref.rl" + {te = p+1;{ output->first = 0x2235; {p++; goto _out; } }} + break; + case 676: +#line 951 "char_ref.rl" + {te = p+1;{ output->first = 0x2235; {p++; goto _out; } }} + break; + case 677: +#line 952 "char_ref.rl" + {te = p+1;{ output->first = 0x29b0; {p++; goto _out; } }} + break; + case 678: +#line 953 "char_ref.rl" + {te = p+1;{ output->first = 0x03f6; {p++; goto _out; } }} + break; + case 679: +#line 954 "char_ref.rl" + {te = p+1;{ output->first = 0x212c; {p++; goto _out; } }} + break; + case 680: +#line 955 "char_ref.rl" + {te = p+1;{ output->first = 0x03b2; {p++; goto _out; } }} + break; + case 681: +#line 956 "char_ref.rl" + {te = p+1;{ output->first = 0x2136; {p++; goto _out; } }} + break; + case 682: +#line 957 "char_ref.rl" + {te = p+1;{ output->first = 0x226c; {p++; goto _out; } }} + break; + case 683: +#line 958 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d51f; {p++; goto _out; } }} + break; + case 684: +#line 959 "char_ref.rl" + {te = p+1;{ output->first = 0x22c2; {p++; goto _out; } }} + break; + case 685: +#line 960 "char_ref.rl" + {te = p+1;{ output->first = 0x25ef; {p++; goto _out; } }} + break; + case 686: +#line 961 "char_ref.rl" + {te = p+1;{ output->first = 0x22c3; {p++; goto _out; } }} + break; + case 687: +#line 962 "char_ref.rl" + {te = p+1;{ output->first = 0x2a00; {p++; goto _out; } }} + break; + case 688: +#line 963 "char_ref.rl" + {te = p+1;{ output->first = 0x2a01; {p++; goto _out; } }} + break; + case 689: +#line 964 "char_ref.rl" + {te = p+1;{ output->first = 0x2a02; {p++; goto _out; } }} + break; + case 690: +#line 965 "char_ref.rl" + {te = p+1;{ output->first = 0x2a06; {p++; goto _out; } }} + break; + case 691: +#line 966 "char_ref.rl" + {te = p+1;{ output->first = 0x2605; {p++; goto _out; } }} + break; + case 692: +#line 967 "char_ref.rl" + {te = p+1;{ output->first = 0x25bd; {p++; goto _out; } }} + break; + case 693: +#line 968 "char_ref.rl" + {te = p+1;{ output->first = 0x25b3; {p++; goto _out; } }} + break; + case 694: +#line 969 "char_ref.rl" + {te = p+1;{ output->first = 0x2a04; {p++; goto _out; } }} + break; + case 695: +#line 970 "char_ref.rl" + {te = p+1;{ output->first = 0x22c1; {p++; goto _out; } }} + break; + case 696: +#line 971 "char_ref.rl" + {te = p+1;{ output->first = 0x22c0; {p++; goto _out; } }} + break; + case 697: +#line 972 "char_ref.rl" + {te = p+1;{ output->first = 0x290d; {p++; goto _out; } }} + break; + case 698: +#line 973 "char_ref.rl" + {te = p+1;{ output->first = 0x29eb; {p++; goto _out; } }} + break; + case 699: +#line 974 "char_ref.rl" + {te = p+1;{ output->first = 0x25aa; {p++; goto _out; } }} + break; + case 700: +#line 975 "char_ref.rl" + {te = p+1;{ output->first = 0x25b4; {p++; goto _out; } }} + break; + case 701: +#line 976 "char_ref.rl" + {te = p+1;{ output->first = 0x25be; {p++; goto _out; } }} + break; + case 702: +#line 977 "char_ref.rl" + {te = p+1;{ output->first = 0x25c2; {p++; goto _out; } }} + break; + case 703: +#line 978 "char_ref.rl" + {te = p+1;{ output->first = 0x25b8; {p++; goto _out; } }} + break; + case 704: +#line 979 "char_ref.rl" + {te = p+1;{ output->first = 0x2423; {p++; goto _out; } }} + break; + case 705: +#line 980 "char_ref.rl" + {te = p+1;{ output->first = 0x2592; {p++; goto _out; } }} + break; + case 706: +#line 981 "char_ref.rl" + {te = p+1;{ output->first = 0x2591; {p++; goto _out; } }} + break; + case 707: +#line 982 "char_ref.rl" + {te = p+1;{ output->first = 0x2593; {p++; goto _out; } }} + break; + case 708: +#line 983 "char_ref.rl" + {te = p+1;{ output->first = 0x2588; {p++; goto _out; } }} + break; + case 709: +#line 984 "char_ref.rl" + {te = p+1;{ output->first = 0x3d; output->second = 0x20e5; {p++; goto _out; } }} + break; + case 710: +#line 985 "char_ref.rl" + {te = p+1;{ output->first = 0x2261; output->second = 0x20e5; {p++; goto _out; } }} + break; + case 711: +#line 986 "char_ref.rl" + {te = p+1;{ output->first = 0x2310; {p++; goto _out; } }} + break; + case 712: +#line 987 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d553; {p++; goto _out; } }} + break; + case 713: +#line 988 "char_ref.rl" + {te = p+1;{ output->first = 0x22a5; {p++; goto _out; } }} + break; + case 714: +#line 989 "char_ref.rl" + {te = p+1;{ output->first = 0x22a5; {p++; goto _out; } }} + break; + case 715: +#line 990 "char_ref.rl" + {te = p+1;{ output->first = 0x22c8; {p++; goto _out; } }} + break; + case 716: +#line 991 "char_ref.rl" + {te = p+1;{ output->first = 0x2557; {p++; goto _out; } }} + break; + case 717: +#line 992 "char_ref.rl" + {te = p+1;{ output->first = 0x2554; {p++; goto _out; } }} + break; + case 718: +#line 993 "char_ref.rl" + {te = p+1;{ output->first = 0x2556; {p++; goto _out; } }} + break; + case 719: +#line 994 "char_ref.rl" + {te = p+1;{ output->first = 0x2553; {p++; goto _out; } }} + break; + case 720: +#line 995 "char_ref.rl" + {te = p+1;{ output->first = 0x2550; {p++; goto _out; } }} + break; + case 721: +#line 996 "char_ref.rl" + {te = p+1;{ output->first = 0x2566; {p++; goto _out; } }} + break; + case 722: +#line 997 "char_ref.rl" + {te = p+1;{ output->first = 0x2569; {p++; goto _out; } }} + break; + case 723: +#line 998 "char_ref.rl" + {te = p+1;{ output->first = 0x2564; {p++; goto _out; } }} + break; + case 724: +#line 999 "char_ref.rl" + {te = p+1;{ output->first = 0x2567; {p++; goto _out; } }} + break; + case 725: +#line 1000 "char_ref.rl" + {te = p+1;{ output->first = 0x255d; {p++; goto _out; } }} + break; + case 726: +#line 1001 "char_ref.rl" + {te = p+1;{ output->first = 0x255a; {p++; goto _out; } }} + break; + case 727: +#line 1002 "char_ref.rl" + {te = p+1;{ output->first = 0x255c; {p++; goto _out; } }} + break; + case 728: +#line 1003 "char_ref.rl" + {te = p+1;{ output->first = 0x2559; {p++; goto _out; } }} + break; + case 729: +#line 1004 "char_ref.rl" + {te = p+1;{ output->first = 0x2551; {p++; goto _out; } }} + break; + case 730: +#line 1005 "char_ref.rl" + {te = p+1;{ output->first = 0x256c; {p++; goto _out; } }} + break; + case 731: +#line 1006 "char_ref.rl" + {te = p+1;{ output->first = 0x2563; {p++; goto _out; } }} + break; + case 732: +#line 1007 "char_ref.rl" + {te = p+1;{ output->first = 0x2560; {p++; goto _out; } }} + break; + case 733: +#line 1008 "char_ref.rl" + {te = p+1;{ output->first = 0x256b; {p++; goto _out; } }} + break; + case 734: +#line 1009 "char_ref.rl" + {te = p+1;{ output->first = 0x2562; {p++; goto _out; } }} + break; + case 735: +#line 1010 "char_ref.rl" + {te = p+1;{ output->first = 0x255f; {p++; goto _out; } }} + break; + case 736: +#line 1011 "char_ref.rl" + {te = p+1;{ output->first = 0x29c9; {p++; goto _out; } }} + break; + case 737: +#line 1012 "char_ref.rl" + {te = p+1;{ output->first = 0x2555; {p++; goto _out; } }} + break; + case 738: +#line 1013 "char_ref.rl" + {te = p+1;{ output->first = 0x2552; {p++; goto _out; } }} + break; + case 739: +#line 1014 "char_ref.rl" + {te = p+1;{ output->first = 0x2510; {p++; goto _out; } }} + break; + case 740: +#line 1015 "char_ref.rl" + {te = p+1;{ output->first = 0x250c; {p++; goto _out; } }} + break; + case 741: +#line 1016 "char_ref.rl" + {te = p+1;{ output->first = 0x2500; {p++; goto _out; } }} + break; + case 742: +#line 1017 "char_ref.rl" + {te = p+1;{ output->first = 0x2565; {p++; goto _out; } }} + break; + case 743: +#line 1018 "char_ref.rl" + {te = p+1;{ output->first = 0x2568; {p++; goto _out; } }} + break; + case 744: +#line 1019 "char_ref.rl" + {te = p+1;{ output->first = 0x252c; {p++; goto _out; } }} + break; + case 745: +#line 1020 "char_ref.rl" + {te = p+1;{ output->first = 0x2534; {p++; goto _out; } }} + break; + case 746: +#line 1021 "char_ref.rl" + {te = p+1;{ output->first = 0x229f; {p++; goto _out; } }} + break; + case 747: +#line 1022 "char_ref.rl" + {te = p+1;{ output->first = 0x229e; {p++; goto _out; } }} + break; + case 748: +#line 1023 "char_ref.rl" + {te = p+1;{ output->first = 0x22a0; {p++; goto _out; } }} + break; + case 749: +#line 1024 "char_ref.rl" + {te = p+1;{ output->first = 0x255b; {p++; goto _out; } }} + break; + case 750: +#line 1025 "char_ref.rl" + {te = p+1;{ output->first = 0x2558; {p++; goto _out; } }} + break; + case 751: +#line 1026 "char_ref.rl" + {te = p+1;{ output->first = 0x2518; {p++; goto _out; } }} + break; + case 752: +#line 1027 "char_ref.rl" + {te = p+1;{ output->first = 0x2514; {p++; goto _out; } }} + break; + case 753: +#line 1028 "char_ref.rl" + {te = p+1;{ output->first = 0x2502; {p++; goto _out; } }} + break; + case 754: +#line 1029 "char_ref.rl" + {te = p+1;{ output->first = 0x256a; {p++; goto _out; } }} + break; + case 755: +#line 1030 "char_ref.rl" + {te = p+1;{ output->first = 0x2561; {p++; goto _out; } }} + break; + case 756: +#line 1031 "char_ref.rl" + {te = p+1;{ output->first = 0x255e; {p++; goto _out; } }} + break; + case 757: +#line 1032 "char_ref.rl" + {te = p+1;{ output->first = 0x253c; {p++; goto _out; } }} + break; + case 758: +#line 1033 "char_ref.rl" + {te = p+1;{ output->first = 0x2524; {p++; goto _out; } }} + break; + case 759: +#line 1034 "char_ref.rl" + {te = p+1;{ output->first = 0x251c; {p++; goto _out; } }} + break; + case 760: +#line 1035 "char_ref.rl" + {te = p+1;{ output->first = 0x2035; {p++; goto _out; } }} + break; + case 761: +#line 1036 "char_ref.rl" + {te = p+1;{ output->first = 0x02d8; {p++; goto _out; } }} + break; + case 762: +#line 1037 "char_ref.rl" + {te = p+1;{ output->first = 0xa6; {p++; goto _out; } }} + break; + case 763: +#line 1039 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b7; {p++; goto _out; } }} + break; + case 764: +#line 1040 "char_ref.rl" + {te = p+1;{ output->first = 0x204f; {p++; goto _out; } }} + break; + case 765: +#line 1041 "char_ref.rl" + {te = p+1;{ output->first = 0x223d; {p++; goto _out; } }} + break; + case 766: +#line 1042 "char_ref.rl" + {te = p+1;{ output->first = 0x22cd; {p++; goto _out; } }} + break; + case 767: +#line 1043 "char_ref.rl" + {te = p+1;{ output->first = 0x5c; {p++; goto _out; } }} + break; + case 768: +#line 1044 "char_ref.rl" + {te = p+1;{ output->first = 0x29c5; {p++; goto _out; } }} + break; + case 769: +#line 1045 "char_ref.rl" + {te = p+1;{ output->first = 0x27c8; {p++; goto _out; } }} + break; + case 770: +#line 1046 "char_ref.rl" + {te = p+1;{ output->first = 0x2022; {p++; goto _out; } }} + break; + case 771: +#line 1047 "char_ref.rl" + {te = p+1;{ output->first = 0x2022; {p++; goto _out; } }} + break; + case 772: +#line 1048 "char_ref.rl" + {te = p+1;{ output->first = 0x224e; {p++; goto _out; } }} + break; + case 773: +#line 1049 "char_ref.rl" + {te = p+1;{ output->first = 0x2aae; {p++; goto _out; } }} + break; + case 774: +#line 1050 "char_ref.rl" + {te = p+1;{ output->first = 0x224f; {p++; goto _out; } }} + break; + case 775: +#line 1051 "char_ref.rl" + {te = p+1;{ output->first = 0x224f; {p++; goto _out; } }} + break; + case 776: +#line 1052 "char_ref.rl" + {te = p+1;{ output->first = 0x0107; {p++; goto _out; } }} + break; + case 777: +#line 1053 "char_ref.rl" + {te = p+1;{ output->first = 0x2229; {p++; goto _out; } }} + break; + case 778: +#line 1054 "char_ref.rl" + {te = p+1;{ output->first = 0x2a44; {p++; goto _out; } }} + break; + case 779: +#line 1055 "char_ref.rl" + {te = p+1;{ output->first = 0x2a49; {p++; goto _out; } }} + break; + case 780: +#line 1056 "char_ref.rl" + {te = p+1;{ output->first = 0x2a4b; {p++; goto _out; } }} + break; + case 781: +#line 1057 "char_ref.rl" + {te = p+1;{ output->first = 0x2a47; {p++; goto _out; } }} + break; + case 782: +#line 1058 "char_ref.rl" + {te = p+1;{ output->first = 0x2a40; {p++; goto _out; } }} + break; + case 783: +#line 1059 "char_ref.rl" + {te = p+1;{ output->first = 0x2229; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 784: +#line 1060 "char_ref.rl" + {te = p+1;{ output->first = 0x2041; {p++; goto _out; } }} + break; + case 785: +#line 1061 "char_ref.rl" + {te = p+1;{ output->first = 0x02c7; {p++; goto _out; } }} + break; + case 786: +#line 1062 "char_ref.rl" + {te = p+1;{ output->first = 0x2a4d; {p++; goto _out; } }} + break; + case 787: +#line 1063 "char_ref.rl" + {te = p+1;{ output->first = 0x010d; {p++; goto _out; } }} + break; + case 788: +#line 1064 "char_ref.rl" + {te = p+1;{ output->first = 0xe7; {p++; goto _out; } }} + break; + case 789: +#line 1066 "char_ref.rl" + {te = p+1;{ output->first = 0x0109; {p++; goto _out; } }} + break; + case 790: +#line 1067 "char_ref.rl" + {te = p+1;{ output->first = 0x2a4c; {p++; goto _out; } }} + break; + case 791: +#line 1068 "char_ref.rl" + {te = p+1;{ output->first = 0x2a50; {p++; goto _out; } }} + break; + case 792: +#line 1069 "char_ref.rl" + {te = p+1;{ output->first = 0x010b; {p++; goto _out; } }} + break; + case 793: +#line 1070 "char_ref.rl" + {te = p+1;{ output->first = 0xb8; {p++; goto _out; } }} + break; + case 794: +#line 1072 "char_ref.rl" + {te = p+1;{ output->first = 0x29b2; {p++; goto _out; } }} + break; + case 795: +#line 1073 "char_ref.rl" + {te = p+1;{ output->first = 0xa2; {p++; goto _out; } }} + break; + case 796: +#line 1075 "char_ref.rl" + {te = p+1;{ output->first = 0xb7; {p++; goto _out; } }} + break; + case 797: +#line 1076 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d520; {p++; goto _out; } }} + break; + case 798: +#line 1077 "char_ref.rl" + {te = p+1;{ output->first = 0x0447; {p++; goto _out; } }} + break; + case 799: +#line 1078 "char_ref.rl" + {te = p+1;{ output->first = 0x2713; {p++; goto _out; } }} + break; + case 800: +#line 1079 "char_ref.rl" + {te = p+1;{ output->first = 0x2713; {p++; goto _out; } }} + break; + case 801: +#line 1080 "char_ref.rl" + {te = p+1;{ output->first = 0x03c7; {p++; goto _out; } }} + break; + case 802: +#line 1081 "char_ref.rl" + {te = p+1;{ output->first = 0x25cb; {p++; goto _out; } }} + break; + case 803: +#line 1082 "char_ref.rl" + {te = p+1;{ output->first = 0x29c3; {p++; goto _out; } }} + break; + case 804: +#line 1083 "char_ref.rl" + {te = p+1;{ output->first = 0x02c6; {p++; goto _out; } }} + break; + case 805: +#line 1084 "char_ref.rl" + {te = p+1;{ output->first = 0x2257; {p++; goto _out; } }} + break; + case 806: +#line 1085 "char_ref.rl" + {te = p+1;{ output->first = 0x21ba; {p++; goto _out; } }} + break; + case 807: +#line 1086 "char_ref.rl" + {te = p+1;{ output->first = 0x21bb; {p++; goto _out; } }} + break; + case 808: +#line 1087 "char_ref.rl" + {te = p+1;{ output->first = 0xae; {p++; goto _out; } }} + break; + case 809: +#line 1088 "char_ref.rl" + {te = p+1;{ output->first = 0x24c8; {p++; goto _out; } }} + break; + case 810: +#line 1089 "char_ref.rl" + {te = p+1;{ output->first = 0x229b; {p++; goto _out; } }} + break; + case 811: +#line 1090 "char_ref.rl" + {te = p+1;{ output->first = 0x229a; {p++; goto _out; } }} + break; + case 812: +#line 1091 "char_ref.rl" + {te = p+1;{ output->first = 0x229d; {p++; goto _out; } }} + break; + case 813: +#line 1092 "char_ref.rl" + {te = p+1;{ output->first = 0x2257; {p++; goto _out; } }} + break; + case 814: +#line 1093 "char_ref.rl" + {te = p+1;{ output->first = 0x2a10; {p++; goto _out; } }} + break; + case 815: +#line 1094 "char_ref.rl" + {te = p+1;{ output->first = 0x2aef; {p++; goto _out; } }} + break; + case 816: +#line 1095 "char_ref.rl" + {te = p+1;{ output->first = 0x29c2; {p++; goto _out; } }} + break; + case 817: +#line 1096 "char_ref.rl" + {te = p+1;{ output->first = 0x2663; {p++; goto _out; } }} + break; + case 818: +#line 1097 "char_ref.rl" + {te = p+1;{ output->first = 0x2663; {p++; goto _out; } }} + break; + case 819: +#line 1098 "char_ref.rl" + {te = p+1;{ output->first = 0x3a; {p++; goto _out; } }} + break; + case 820: +#line 1099 "char_ref.rl" + {te = p+1;{ output->first = 0x2254; {p++; goto _out; } }} + break; + case 821: +#line 1100 "char_ref.rl" + {te = p+1;{ output->first = 0x2254; {p++; goto _out; } }} + break; + case 822: +#line 1101 "char_ref.rl" + {te = p+1;{ output->first = 0x2c; {p++; goto _out; } }} + break; + case 823: +#line 1102 "char_ref.rl" + {te = p+1;{ output->first = 0x40; {p++; goto _out; } }} + break; + case 824: +#line 1103 "char_ref.rl" + {te = p+1;{ output->first = 0x2201; {p++; goto _out; } }} + break; + case 825: +#line 1104 "char_ref.rl" + {te = p+1;{ output->first = 0x2218; {p++; goto _out; } }} + break; + case 826: +#line 1105 "char_ref.rl" + {te = p+1;{ output->first = 0x2201; {p++; goto _out; } }} + break; + case 827: +#line 1106 "char_ref.rl" + {te = p+1;{ output->first = 0x2102; {p++; goto _out; } }} + break; + case 828: +#line 1107 "char_ref.rl" + {te = p+1;{ output->first = 0x2245; {p++; goto _out; } }} + break; + case 829: +#line 1108 "char_ref.rl" + {te = p+1;{ output->first = 0x2a6d; {p++; goto _out; } }} + break; + case 830: +#line 1109 "char_ref.rl" + {te = p+1;{ output->first = 0x222e; {p++; goto _out; } }} + break; + case 831: +#line 1110 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d554; {p++; goto _out; } }} + break; + case 832: +#line 1111 "char_ref.rl" + {te = p+1;{ output->first = 0x2210; {p++; goto _out; } }} + break; + case 833: +#line 1112 "char_ref.rl" + {te = p+1;{ output->first = 0xa9; {p++; goto _out; } }} + break; + case 834: +#line 1114 "char_ref.rl" + {te = p+1;{ output->first = 0x2117; {p++; goto _out; } }} + break; + case 835: +#line 1115 "char_ref.rl" + {te = p+1;{ output->first = 0x21b5; {p++; goto _out; } }} + break; + case 836: +#line 1116 "char_ref.rl" + {te = p+1;{ output->first = 0x2717; {p++; goto _out; } }} + break; + case 837: +#line 1117 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b8; {p++; goto _out; } }} + break; + case 838: +#line 1118 "char_ref.rl" + {te = p+1;{ output->first = 0x2acf; {p++; goto _out; } }} + break; + case 839: +#line 1119 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad1; {p++; goto _out; } }} + break; + case 840: +#line 1120 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad0; {p++; goto _out; } }} + break; + case 841: +#line 1121 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad2; {p++; goto _out; } }} + break; + case 842: +#line 1122 "char_ref.rl" + {te = p+1;{ output->first = 0x22ef; {p++; goto _out; } }} + break; + case 843: +#line 1123 "char_ref.rl" + {te = p+1;{ output->first = 0x2938; {p++; goto _out; } }} + break; + case 844: +#line 1124 "char_ref.rl" + {te = p+1;{ output->first = 0x2935; {p++; goto _out; } }} + break; + case 845: +#line 1125 "char_ref.rl" + {te = p+1;{ output->first = 0x22de; {p++; goto _out; } }} + break; + case 846: +#line 1126 "char_ref.rl" + {te = p+1;{ output->first = 0x22df; {p++; goto _out; } }} + break; + case 847: +#line 1127 "char_ref.rl" + {te = p+1;{ output->first = 0x21b6; {p++; goto _out; } }} + break; + case 848: +#line 1128 "char_ref.rl" + {te = p+1;{ output->first = 0x293d; {p++; goto _out; } }} + break; + case 849: +#line 1129 "char_ref.rl" + {te = p+1;{ output->first = 0x222a; {p++; goto _out; } }} + break; + case 850: +#line 1130 "char_ref.rl" + {te = p+1;{ output->first = 0x2a48; {p++; goto _out; } }} + break; + case 851: +#line 1131 "char_ref.rl" + {te = p+1;{ output->first = 0x2a46; {p++; goto _out; } }} + break; + case 852: +#line 1132 "char_ref.rl" + {te = p+1;{ output->first = 0x2a4a; {p++; goto _out; } }} + break; + case 853: +#line 1133 "char_ref.rl" + {te = p+1;{ output->first = 0x228d; {p++; goto _out; } }} + break; + case 854: +#line 1134 "char_ref.rl" + {te = p+1;{ output->first = 0x2a45; {p++; goto _out; } }} + break; + case 855: +#line 1135 "char_ref.rl" + {te = p+1;{ output->first = 0x222a; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 856: +#line 1136 "char_ref.rl" + {te = p+1;{ output->first = 0x21b7; {p++; goto _out; } }} + break; + case 857: +#line 1137 "char_ref.rl" + {te = p+1;{ output->first = 0x293c; {p++; goto _out; } }} + break; + case 858: +#line 1138 "char_ref.rl" + {te = p+1;{ output->first = 0x22de; {p++; goto _out; } }} + break; + case 859: +#line 1139 "char_ref.rl" + {te = p+1;{ output->first = 0x22df; {p++; goto _out; } }} + break; + case 860: +#line 1140 "char_ref.rl" + {te = p+1;{ output->first = 0x22ce; {p++; goto _out; } }} + break; + case 861: +#line 1141 "char_ref.rl" + {te = p+1;{ output->first = 0x22cf; {p++; goto _out; } }} + break; + case 862: +#line 1142 "char_ref.rl" + {te = p+1;{ output->first = 0xa4; {p++; goto _out; } }} + break; + case 863: +#line 1144 "char_ref.rl" + {te = p+1;{ output->first = 0x21b6; {p++; goto _out; } }} + break; + case 864: +#line 1145 "char_ref.rl" + {te = p+1;{ output->first = 0x21b7; {p++; goto _out; } }} + break; + case 865: +#line 1146 "char_ref.rl" + {te = p+1;{ output->first = 0x22ce; {p++; goto _out; } }} + break; + case 866: +#line 1147 "char_ref.rl" + {te = p+1;{ output->first = 0x22cf; {p++; goto _out; } }} + break; + case 867: +#line 1148 "char_ref.rl" + {te = p+1;{ output->first = 0x2232; {p++; goto _out; } }} + break; + case 868: +#line 1149 "char_ref.rl" + {te = p+1;{ output->first = 0x2231; {p++; goto _out; } }} + break; + case 869: +#line 1150 "char_ref.rl" + {te = p+1;{ output->first = 0x232d; {p++; goto _out; } }} + break; + case 870: +#line 1151 "char_ref.rl" + {te = p+1;{ output->first = 0x21d3; {p++; goto _out; } }} + break; + case 871: +#line 1152 "char_ref.rl" + {te = p+1;{ output->first = 0x2965; {p++; goto _out; } }} + break; + case 872: +#line 1153 "char_ref.rl" + {te = p+1;{ output->first = 0x2020; {p++; goto _out; } }} + break; + case 873: +#line 1154 "char_ref.rl" + {te = p+1;{ output->first = 0x2138; {p++; goto _out; } }} + break; + case 874: +#line 1155 "char_ref.rl" + {te = p+1;{ output->first = 0x2193; {p++; goto _out; } }} + break; + case 875: +#line 1156 "char_ref.rl" + {te = p+1;{ output->first = 0x2010; {p++; goto _out; } }} + break; + case 876: +#line 1157 "char_ref.rl" + {te = p+1;{ output->first = 0x22a3; {p++; goto _out; } }} + break; + case 877: +#line 1158 "char_ref.rl" + {te = p+1;{ output->first = 0x290f; {p++; goto _out; } }} + break; + case 878: +#line 1159 "char_ref.rl" + {te = p+1;{ output->first = 0x02dd; {p++; goto _out; } }} + break; + case 879: +#line 1160 "char_ref.rl" + {te = p+1;{ output->first = 0x010f; {p++; goto _out; } }} + break; + case 880: +#line 1161 "char_ref.rl" + {te = p+1;{ output->first = 0x0434; {p++; goto _out; } }} + break; + case 881: +#line 1162 "char_ref.rl" + {te = p+1;{ output->first = 0x2146; {p++; goto _out; } }} + break; + case 882: +#line 1163 "char_ref.rl" + {te = p+1;{ output->first = 0x2021; {p++; goto _out; } }} + break; + case 883: +#line 1164 "char_ref.rl" + {te = p+1;{ output->first = 0x21ca; {p++; goto _out; } }} + break; + case 884: +#line 1165 "char_ref.rl" + {te = p+1;{ output->first = 0x2a77; {p++; goto _out; } }} + break; + case 885: +#line 1166 "char_ref.rl" + {te = p+1;{ output->first = 0xb0; {p++; goto _out; } }} + break; + case 886: +#line 1168 "char_ref.rl" + {te = p+1;{ output->first = 0x03b4; {p++; goto _out; } }} + break; + case 887: +#line 1169 "char_ref.rl" + {te = p+1;{ output->first = 0x29b1; {p++; goto _out; } }} + break; + case 888: +#line 1170 "char_ref.rl" + {te = p+1;{ output->first = 0x297f; {p++; goto _out; } }} + break; + case 889: +#line 1171 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d521; {p++; goto _out; } }} + break; + case 890: +#line 1172 "char_ref.rl" + {te = p+1;{ output->first = 0x21c3; {p++; goto _out; } }} + break; + case 891: +#line 1173 "char_ref.rl" + {te = p+1;{ output->first = 0x21c2; {p++; goto _out; } }} + break; + case 892: +#line 1174 "char_ref.rl" + {te = p+1;{ output->first = 0x22c4; {p++; goto _out; } }} + break; + case 893: +#line 1175 "char_ref.rl" + {te = p+1;{ output->first = 0x22c4; {p++; goto _out; } }} + break; + case 894: +#line 1176 "char_ref.rl" + {te = p+1;{ output->first = 0x2666; {p++; goto _out; } }} + break; + case 895: +#line 1177 "char_ref.rl" + {te = p+1;{ output->first = 0x2666; {p++; goto _out; } }} + break; + case 896: +#line 1178 "char_ref.rl" + {te = p+1;{ output->first = 0xa8; {p++; goto _out; } }} + break; + case 897: +#line 1179 "char_ref.rl" + {te = p+1;{ output->first = 0x03dd; {p++; goto _out; } }} + break; + case 898: +#line 1180 "char_ref.rl" + {te = p+1;{ output->first = 0x22f2; {p++; goto _out; } }} + break; + case 899: +#line 1181 "char_ref.rl" + {te = p+1;{ output->first = 0xf7; {p++; goto _out; } }} + break; + case 900: +#line 1182 "char_ref.rl" + {te = p+1;{ output->first = 0xf7; {p++; goto _out; } }} + break; + case 901: +#line 1184 "char_ref.rl" + {te = p+1;{ output->first = 0x22c7; {p++; goto _out; } }} + break; + case 902: +#line 1185 "char_ref.rl" + {te = p+1;{ output->first = 0x22c7; {p++; goto _out; } }} + break; + case 903: +#line 1186 "char_ref.rl" + {te = p+1;{ output->first = 0x0452; {p++; goto _out; } }} + break; + case 904: +#line 1187 "char_ref.rl" + {te = p+1;{ output->first = 0x231e; {p++; goto _out; } }} + break; + case 905: +#line 1188 "char_ref.rl" + {te = p+1;{ output->first = 0x230d; {p++; goto _out; } }} + break; + case 906: +#line 1189 "char_ref.rl" + {te = p+1;{ output->first = 0x24; {p++; goto _out; } }} + break; + case 907: +#line 1190 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d555; {p++; goto _out; } }} + break; + case 908: +#line 1191 "char_ref.rl" + {te = p+1;{ output->first = 0x02d9; {p++; goto _out; } }} + break; + case 909: +#line 1192 "char_ref.rl" + {te = p+1;{ output->first = 0x2250; {p++; goto _out; } }} + break; + case 910: +#line 1193 "char_ref.rl" + {te = p+1;{ output->first = 0x2251; {p++; goto _out; } }} + break; + case 911: +#line 1194 "char_ref.rl" + {te = p+1;{ output->first = 0x2238; {p++; goto _out; } }} + break; + case 912: +#line 1195 "char_ref.rl" + {te = p+1;{ output->first = 0x2214; {p++; goto _out; } }} + break; + case 913: +#line 1196 "char_ref.rl" + {te = p+1;{ output->first = 0x22a1; {p++; goto _out; } }} + break; + case 914: +#line 1197 "char_ref.rl" + {te = p+1;{ output->first = 0x2306; {p++; goto _out; } }} + break; + case 915: +#line 1198 "char_ref.rl" + {te = p+1;{ output->first = 0x2193; {p++; goto _out; } }} + break; + case 916: +#line 1199 "char_ref.rl" + {te = p+1;{ output->first = 0x21ca; {p++; goto _out; } }} + break; + case 917: +#line 1200 "char_ref.rl" + {te = p+1;{ output->first = 0x21c3; {p++; goto _out; } }} + break; + case 918: +#line 1201 "char_ref.rl" + {te = p+1;{ output->first = 0x21c2; {p++; goto _out; } }} + break; + case 919: +#line 1202 "char_ref.rl" + {te = p+1;{ output->first = 0x2910; {p++; goto _out; } }} + break; + case 920: +#line 1203 "char_ref.rl" + {te = p+1;{ output->first = 0x231f; {p++; goto _out; } }} + break; + case 921: +#line 1204 "char_ref.rl" + {te = p+1;{ output->first = 0x230c; {p++; goto _out; } }} + break; + case 922: +#line 1205 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4b9; {p++; goto _out; } }} + break; + case 923: +#line 1206 "char_ref.rl" + {te = p+1;{ output->first = 0x0455; {p++; goto _out; } }} + break; + case 924: +#line 1207 "char_ref.rl" + {te = p+1;{ output->first = 0x29f6; {p++; goto _out; } }} + break; + case 925: +#line 1208 "char_ref.rl" + {te = p+1;{ output->first = 0x0111; {p++; goto _out; } }} + break; + case 926: +#line 1209 "char_ref.rl" + {te = p+1;{ output->first = 0x22f1; {p++; goto _out; } }} + break; + case 927: +#line 1210 "char_ref.rl" + {te = p+1;{ output->first = 0x25bf; {p++; goto _out; } }} + break; + case 928: +#line 1211 "char_ref.rl" + {te = p+1;{ output->first = 0x25be; {p++; goto _out; } }} + break; + case 929: +#line 1212 "char_ref.rl" + {te = p+1;{ output->first = 0x21f5; {p++; goto _out; } }} + break; + case 930: +#line 1213 "char_ref.rl" + {te = p+1;{ output->first = 0x296f; {p++; goto _out; } }} + break; + case 931: +#line 1214 "char_ref.rl" + {te = p+1;{ output->first = 0x29a6; {p++; goto _out; } }} + break; + case 932: +#line 1215 "char_ref.rl" + {te = p+1;{ output->first = 0x045f; {p++; goto _out; } }} + break; + case 933: +#line 1216 "char_ref.rl" + {te = p+1;{ output->first = 0x27ff; {p++; goto _out; } }} + break; + case 934: +#line 1217 "char_ref.rl" + {te = p+1;{ output->first = 0x2a77; {p++; goto _out; } }} + break; + case 935: +#line 1218 "char_ref.rl" + {te = p+1;{ output->first = 0x2251; {p++; goto _out; } }} + break; + case 936: +#line 1219 "char_ref.rl" + {te = p+1;{ output->first = 0xe9; {p++; goto _out; } }} + break; + case 937: +#line 1221 "char_ref.rl" + {te = p+1;{ output->first = 0x2a6e; {p++; goto _out; } }} + break; + case 938: +#line 1222 "char_ref.rl" + {te = p+1;{ output->first = 0x011b; {p++; goto _out; } }} + break; + case 939: +#line 1223 "char_ref.rl" + {te = p+1;{ output->first = 0x2256; {p++; goto _out; } }} + break; + case 940: +#line 1224 "char_ref.rl" + {te = p+1;{ output->first = 0xea; {p++; goto _out; } }} + break; + case 941: +#line 1226 "char_ref.rl" + {te = p+1;{ output->first = 0x2255; {p++; goto _out; } }} + break; + case 942: +#line 1227 "char_ref.rl" + {te = p+1;{ output->first = 0x044d; {p++; goto _out; } }} + break; + case 943: +#line 1228 "char_ref.rl" + {te = p+1;{ output->first = 0x0117; {p++; goto _out; } }} + break; + case 944: +#line 1229 "char_ref.rl" + {te = p+1;{ output->first = 0x2147; {p++; goto _out; } }} + break; + case 945: +#line 1230 "char_ref.rl" + {te = p+1;{ output->first = 0x2252; {p++; goto _out; } }} + break; + case 946: +#line 1231 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d522; {p++; goto _out; } }} + break; + case 947: +#line 1232 "char_ref.rl" + {te = p+1;{ output->first = 0x2a9a; {p++; goto _out; } }} + break; + case 948: +#line 1233 "char_ref.rl" + {te = p+1;{ output->first = 0xe8; {p++; goto _out; } }} + break; + case 949: +#line 1235 "char_ref.rl" + {te = p+1;{ output->first = 0x2a96; {p++; goto _out; } }} + break; + case 950: +#line 1236 "char_ref.rl" + {te = p+1;{ output->first = 0x2a98; {p++; goto _out; } }} + break; + case 951: +#line 1237 "char_ref.rl" + {te = p+1;{ output->first = 0x2a99; {p++; goto _out; } }} + break; + case 952: +#line 1238 "char_ref.rl" + {te = p+1;{ output->first = 0x23e7; {p++; goto _out; } }} + break; + case 953: +#line 1239 "char_ref.rl" + {te = p+1;{ output->first = 0x2113; {p++; goto _out; } }} + break; + case 954: +#line 1240 "char_ref.rl" + {te = p+1;{ output->first = 0x2a95; {p++; goto _out; } }} + break; + case 955: +#line 1241 "char_ref.rl" + {te = p+1;{ output->first = 0x2a97; {p++; goto _out; } }} + break; + case 956: +#line 1242 "char_ref.rl" + {te = p+1;{ output->first = 0x0113; {p++; goto _out; } }} + break; + case 957: +#line 1243 "char_ref.rl" + {te = p+1;{ output->first = 0x2205; {p++; goto _out; } }} + break; + case 958: +#line 1244 "char_ref.rl" + {te = p+1;{ output->first = 0x2205; {p++; goto _out; } }} + break; + case 959: +#line 1245 "char_ref.rl" + {te = p+1;{ output->first = 0x2205; {p++; goto _out; } }} + break; + case 960: +#line 1246 "char_ref.rl" + {te = p+1;{ output->first = 0x2004; {p++; goto _out; } }} + break; + case 961: +#line 1247 "char_ref.rl" + {te = p+1;{ output->first = 0x2005; {p++; goto _out; } }} + break; + case 962: +#line 1248 "char_ref.rl" + {te = p+1;{ output->first = 0x2003; {p++; goto _out; } }} + break; + case 963: +#line 1249 "char_ref.rl" + {te = p+1;{ output->first = 0x014b; {p++; goto _out; } }} + break; + case 964: +#line 1250 "char_ref.rl" + {te = p+1;{ output->first = 0x2002; {p++; goto _out; } }} + break; + case 965: +#line 1251 "char_ref.rl" + {te = p+1;{ output->first = 0x0119; {p++; goto _out; } }} + break; + case 966: +#line 1252 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d556; {p++; goto _out; } }} + break; + case 967: +#line 1253 "char_ref.rl" + {te = p+1;{ output->first = 0x22d5; {p++; goto _out; } }} + break; + case 968: +#line 1254 "char_ref.rl" + {te = p+1;{ output->first = 0x29e3; {p++; goto _out; } }} + break; + case 969: +#line 1255 "char_ref.rl" + {te = p+1;{ output->first = 0x2a71; {p++; goto _out; } }} + break; + case 970: +#line 1256 "char_ref.rl" + {te = p+1;{ output->first = 0x03b5; {p++; goto _out; } }} + break; + case 971: +#line 1257 "char_ref.rl" + {te = p+1;{ output->first = 0x03b5; {p++; goto _out; } }} + break; + case 972: +#line 1258 "char_ref.rl" + {te = p+1;{ output->first = 0x03f5; {p++; goto _out; } }} + break; + case 973: +#line 1259 "char_ref.rl" + {te = p+1;{ output->first = 0x2256; {p++; goto _out; } }} + break; + case 974: +#line 1260 "char_ref.rl" + {te = p+1;{ output->first = 0x2255; {p++; goto _out; } }} + break; + case 975: +#line 1261 "char_ref.rl" + {te = p+1;{ output->first = 0x2242; {p++; goto _out; } }} + break; + case 976: +#line 1262 "char_ref.rl" + {te = p+1;{ output->first = 0x2a96; {p++; goto _out; } }} + break; + case 977: +#line 1263 "char_ref.rl" + {te = p+1;{ output->first = 0x2a95; {p++; goto _out; } }} + break; + case 978: +#line 1264 "char_ref.rl" + {te = p+1;{ output->first = 0x3d; {p++; goto _out; } }} + break; + case 979: +#line 1265 "char_ref.rl" + {te = p+1;{ output->first = 0x225f; {p++; goto _out; } }} + break; + case 980: +#line 1266 "char_ref.rl" + {te = p+1;{ output->first = 0x2261; {p++; goto _out; } }} + break; + case 981: +#line 1267 "char_ref.rl" + {te = p+1;{ output->first = 0x2a78; {p++; goto _out; } }} + break; + case 982: +#line 1268 "char_ref.rl" + {te = p+1;{ output->first = 0x29e5; {p++; goto _out; } }} + break; + case 983: +#line 1269 "char_ref.rl" + {te = p+1;{ output->first = 0x2253; {p++; goto _out; } }} + break; + case 984: +#line 1270 "char_ref.rl" + {te = p+1;{ output->first = 0x2971; {p++; goto _out; } }} + break; + case 985: +#line 1271 "char_ref.rl" + {te = p+1;{ output->first = 0x212f; {p++; goto _out; } }} + break; + case 986: +#line 1272 "char_ref.rl" + {te = p+1;{ output->first = 0x2250; {p++; goto _out; } }} + break; + case 987: +#line 1273 "char_ref.rl" + {te = p+1;{ output->first = 0x2242; {p++; goto _out; } }} + break; + case 988: +#line 1274 "char_ref.rl" + {te = p+1;{ output->first = 0x03b7; {p++; goto _out; } }} + break; + case 989: +#line 1275 "char_ref.rl" + {te = p+1;{ output->first = 0xf0; {p++; goto _out; } }} + break; + case 990: +#line 1277 "char_ref.rl" + {te = p+1;{ output->first = 0xeb; {p++; goto _out; } }} + break; + case 991: +#line 1279 "char_ref.rl" + {te = p+1;{ output->first = 0x20ac; {p++; goto _out; } }} + break; + case 992: +#line 1280 "char_ref.rl" + {te = p+1;{ output->first = 0x21; {p++; goto _out; } }} + break; + case 993: +#line 1281 "char_ref.rl" + {te = p+1;{ output->first = 0x2203; {p++; goto _out; } }} + break; + case 994: +#line 1282 "char_ref.rl" + {te = p+1;{ output->first = 0x2130; {p++; goto _out; } }} + break; + case 995: +#line 1283 "char_ref.rl" + {te = p+1;{ output->first = 0x2147; {p++; goto _out; } }} + break; + case 996: +#line 1284 "char_ref.rl" + {te = p+1;{ output->first = 0x2252; {p++; goto _out; } }} + break; + case 997: +#line 1285 "char_ref.rl" + {te = p+1;{ output->first = 0x0444; {p++; goto _out; } }} + break; + case 998: +#line 1286 "char_ref.rl" + {te = p+1;{ output->first = 0x2640; {p++; goto _out; } }} + break; + case 999: +#line 1287 "char_ref.rl" + {te = p+1;{ output->first = 0xfb03; {p++; goto _out; } }} + break; + case 1000: +#line 1288 "char_ref.rl" + {te = p+1;{ output->first = 0xfb00; {p++; goto _out; } }} + break; + case 1001: +#line 1289 "char_ref.rl" + {te = p+1;{ output->first = 0xfb04; {p++; goto _out; } }} + break; + case 1002: +#line 1290 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d523; {p++; goto _out; } }} + break; + case 1003: +#line 1291 "char_ref.rl" + {te = p+1;{ output->first = 0xfb01; {p++; goto _out; } }} + break; + case 1004: +#line 1292 "char_ref.rl" + {te = p+1;{ output->first = 0x66; output->second = 0x6a; {p++; goto _out; } }} + break; + case 1005: +#line 1293 "char_ref.rl" + {te = p+1;{ output->first = 0x266d; {p++; goto _out; } }} + break; + case 1006: +#line 1294 "char_ref.rl" + {te = p+1;{ output->first = 0xfb02; {p++; goto _out; } }} + break; + case 1007: +#line 1295 "char_ref.rl" + {te = p+1;{ output->first = 0x25b1; {p++; goto _out; } }} + break; + case 1008: +#line 1296 "char_ref.rl" + {te = p+1;{ output->first = 0x0192; {p++; goto _out; } }} + break; + case 1009: +#line 1297 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d557; {p++; goto _out; } }} + break; + case 1010: +#line 1298 "char_ref.rl" + {te = p+1;{ output->first = 0x2200; {p++; goto _out; } }} + break; + case 1011: +#line 1299 "char_ref.rl" + {te = p+1;{ output->first = 0x22d4; {p++; goto _out; } }} + break; + case 1012: +#line 1300 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad9; {p++; goto _out; } }} + break; + case 1013: +#line 1301 "char_ref.rl" + {te = p+1;{ output->first = 0x2a0d; {p++; goto _out; } }} + break; + case 1014: +#line 1302 "char_ref.rl" + {te = p+1;{ output->first = 0xbd; {p++; goto _out; } }} + break; + case 1015: +#line 1304 "char_ref.rl" + {te = p+1;{ output->first = 0x2153; {p++; goto _out; } }} + break; + case 1016: +#line 1305 "char_ref.rl" + {te = p+1;{ output->first = 0xbc; {p++; goto _out; } }} + break; + case 1017: +#line 1307 "char_ref.rl" + {te = p+1;{ output->first = 0x2155; {p++; goto _out; } }} + break; + case 1018: +#line 1308 "char_ref.rl" + {te = p+1;{ output->first = 0x2159; {p++; goto _out; } }} + break; + case 1019: +#line 1309 "char_ref.rl" + {te = p+1;{ output->first = 0x215b; {p++; goto _out; } }} + break; + case 1020: +#line 1310 "char_ref.rl" + {te = p+1;{ output->first = 0x2154; {p++; goto _out; } }} + break; + case 1021: +#line 1311 "char_ref.rl" + {te = p+1;{ output->first = 0x2156; {p++; goto _out; } }} + break; + case 1022: +#line 1312 "char_ref.rl" + {te = p+1;{ output->first = 0xbe; {p++; goto _out; } }} + break; + case 1023: +#line 1314 "char_ref.rl" + {te = p+1;{ output->first = 0x2157; {p++; goto _out; } }} + break; + case 1024: +#line 1315 "char_ref.rl" + {te = p+1;{ output->first = 0x215c; {p++; goto _out; } }} + break; + case 1025: +#line 1316 "char_ref.rl" + {te = p+1;{ output->first = 0x2158; {p++; goto _out; } }} + break; + case 1026: +#line 1317 "char_ref.rl" + {te = p+1;{ output->first = 0x215a; {p++; goto _out; } }} + break; + case 1027: +#line 1318 "char_ref.rl" + {te = p+1;{ output->first = 0x215d; {p++; goto _out; } }} + break; + case 1028: +#line 1319 "char_ref.rl" + {te = p+1;{ output->first = 0x215e; {p++; goto _out; } }} + break; + case 1029: +#line 1320 "char_ref.rl" + {te = p+1;{ output->first = 0x2044; {p++; goto _out; } }} + break; + case 1030: +#line 1321 "char_ref.rl" + {te = p+1;{ output->first = 0x2322; {p++; goto _out; } }} + break; + case 1031: +#line 1322 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4bb; {p++; goto _out; } }} + break; + case 1032: +#line 1323 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; {p++; goto _out; } }} + break; + case 1033: +#line 1324 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8c; {p++; goto _out; } }} + break; + case 1034: +#line 1325 "char_ref.rl" + {te = p+1;{ output->first = 0x01f5; {p++; goto _out; } }} + break; + case 1035: +#line 1326 "char_ref.rl" + {te = p+1;{ output->first = 0x03b3; {p++; goto _out; } }} + break; + case 1036: +#line 1327 "char_ref.rl" + {te = p+1;{ output->first = 0x03dd; {p++; goto _out; } }} + break; + case 1037: +#line 1328 "char_ref.rl" + {te = p+1;{ output->first = 0x2a86; {p++; goto _out; } }} + break; + case 1038: +#line 1329 "char_ref.rl" + {te = p+1;{ output->first = 0x011f; {p++; goto _out; } }} + break; + case 1039: +#line 1330 "char_ref.rl" + {te = p+1;{ output->first = 0x011d; {p++; goto _out; } }} + break; + case 1040: +#line 1331 "char_ref.rl" + {te = p+1;{ output->first = 0x0433; {p++; goto _out; } }} + break; + case 1041: +#line 1332 "char_ref.rl" + {te = p+1;{ output->first = 0x0121; {p++; goto _out; } }} + break; + case 1042: +#line 1333 "char_ref.rl" + {te = p+1;{ output->first = 0x2265; {p++; goto _out; } }} + break; + case 1043: +#line 1334 "char_ref.rl" + {te = p+1;{ output->first = 0x22db; {p++; goto _out; } }} + break; + case 1044: +#line 1335 "char_ref.rl" + {te = p+1;{ output->first = 0x2265; {p++; goto _out; } }} + break; + case 1045: +#line 1336 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; {p++; goto _out; } }} + break; + case 1046: +#line 1337 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; {p++; goto _out; } }} + break; + case 1047: +#line 1338 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; {p++; goto _out; } }} + break; + case 1048: +#line 1339 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa9; {p++; goto _out; } }} + break; + case 1049: +#line 1340 "char_ref.rl" + {te = p+1;{ output->first = 0x2a80; {p++; goto _out; } }} + break; + case 1050: +#line 1341 "char_ref.rl" + {te = p+1;{ output->first = 0x2a82; {p++; goto _out; } }} + break; + case 1051: +#line 1342 "char_ref.rl" + {te = p+1;{ output->first = 0x2a84; {p++; goto _out; } }} + break; + case 1052: +#line 1343 "char_ref.rl" + {te = p+1;{ output->first = 0x22db; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1053: +#line 1344 "char_ref.rl" + {te = p+1;{ output->first = 0x2a94; {p++; goto _out; } }} + break; + case 1054: +#line 1345 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d524; {p++; goto _out; } }} + break; + case 1055: +#line 1346 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; {p++; goto _out; } }} + break; + case 1056: +#line 1347 "char_ref.rl" + {te = p+1;{ output->first = 0x22d9; {p++; goto _out; } }} + break; + case 1057: +#line 1348 "char_ref.rl" + {te = p+1;{ output->first = 0x2137; {p++; goto _out; } }} + break; + case 1058: +#line 1349 "char_ref.rl" + {te = p+1;{ output->first = 0x0453; {p++; goto _out; } }} + break; + case 1059: +#line 1350 "char_ref.rl" + {te = p+1;{ output->first = 0x2277; {p++; goto _out; } }} + break; + case 1060: +#line 1351 "char_ref.rl" + {te = p+1;{ output->first = 0x2a92; {p++; goto _out; } }} + break; + case 1061: +#line 1352 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa5; {p++; goto _out; } }} + break; + case 1062: +#line 1353 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa4; {p++; goto _out; } }} + break; + case 1063: +#line 1354 "char_ref.rl" + {te = p+1;{ output->first = 0x2269; {p++; goto _out; } }} + break; + case 1064: +#line 1355 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8a; {p++; goto _out; } }} + break; + case 1065: +#line 1356 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8a; {p++; goto _out; } }} + break; + case 1066: +#line 1357 "char_ref.rl" + {te = p+1;{ output->first = 0x2a88; {p++; goto _out; } }} + break; + case 1067: +#line 1358 "char_ref.rl" + {te = p+1;{ output->first = 0x2a88; {p++; goto _out; } }} + break; + case 1068: +#line 1359 "char_ref.rl" + {te = p+1;{ output->first = 0x2269; {p++; goto _out; } }} + break; + case 1069: +#line 1360 "char_ref.rl" + {te = p+1;{ output->first = 0x22e7; {p++; goto _out; } }} + break; + case 1070: +#line 1361 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d558; {p++; goto _out; } }} + break; + case 1071: +#line 1362 "char_ref.rl" + {te = p+1;{ output->first = 0x60; {p++; goto _out; } }} + break; + case 1072: +#line 1363 "char_ref.rl" + {te = p+1;{ output->first = 0x210a; {p++; goto _out; } }} + break; + case 1073: +#line 1364 "char_ref.rl" + {te = p+1;{ output->first = 0x2273; {p++; goto _out; } }} + break; + case 1074: +#line 1365 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8e; {p++; goto _out; } }} + break; + case 1075: +#line 1366 "char_ref.rl" + {te = p+1;{ output->first = 0x2a90; {p++; goto _out; } }} + break; + case 1076: +#line 1367 "char_ref.rl" + {te = p+1;{ output->first = 0x3e; {p++; goto _out; } }} + break; + case 1077: +#line 1369 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa7; {p++; goto _out; } }} + break; + case 1078: +#line 1370 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7a; {p++; goto _out; } }} + break; + case 1079: +#line 1371 "char_ref.rl" + {te = p+1;{ output->first = 0x22d7; {p++; goto _out; } }} + break; + case 1080: +#line 1372 "char_ref.rl" + {te = p+1;{ output->first = 0x2995; {p++; goto _out; } }} + break; + case 1081: +#line 1373 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7c; {p++; goto _out; } }} + break; + case 1082: +#line 1374 "char_ref.rl" + {te = p+1;{ output->first = 0x2a86; {p++; goto _out; } }} + break; + case 1083: +#line 1375 "char_ref.rl" + {te = p+1;{ output->first = 0x2978; {p++; goto _out; } }} + break; + case 1084: +#line 1376 "char_ref.rl" + {te = p+1;{ output->first = 0x22d7; {p++; goto _out; } }} + break; + case 1085: +#line 1377 "char_ref.rl" + {te = p+1;{ output->first = 0x22db; {p++; goto _out; } }} + break; + case 1086: +#line 1378 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8c; {p++; goto _out; } }} + break; + case 1087: +#line 1379 "char_ref.rl" + {te = p+1;{ output->first = 0x2277; {p++; goto _out; } }} + break; + case 1088: +#line 1380 "char_ref.rl" + {te = p+1;{ output->first = 0x2273; {p++; goto _out; } }} + break; + case 1089: +#line 1381 "char_ref.rl" + {te = p+1;{ output->first = 0x2269; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1090: +#line 1382 "char_ref.rl" + {te = p+1;{ output->first = 0x2269; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1091: +#line 1383 "char_ref.rl" + {te = p+1;{ output->first = 0x21d4; {p++; goto _out; } }} + break; + case 1092: +#line 1384 "char_ref.rl" + {te = p+1;{ output->first = 0x200a; {p++; goto _out; } }} + break; + case 1093: +#line 1385 "char_ref.rl" + {te = p+1;{ output->first = 0xbd; {p++; goto _out; } }} + break; + case 1094: +#line 1386 "char_ref.rl" + {te = p+1;{ output->first = 0x210b; {p++; goto _out; } }} + break; + case 1095: +#line 1387 "char_ref.rl" + {te = p+1;{ output->first = 0x044a; {p++; goto _out; } }} + break; + case 1096: +#line 1388 "char_ref.rl" + {te = p+1;{ output->first = 0x2194; {p++; goto _out; } }} + break; + case 1097: +#line 1389 "char_ref.rl" + {te = p+1;{ output->first = 0x2948; {p++; goto _out; } }} + break; + case 1098: +#line 1390 "char_ref.rl" + {te = p+1;{ output->first = 0x21ad; {p++; goto _out; } }} + break; + case 1099: +#line 1391 "char_ref.rl" + {te = p+1;{ output->first = 0x210f; {p++; goto _out; } }} + break; + case 1100: +#line 1392 "char_ref.rl" + {te = p+1;{ output->first = 0x0125; {p++; goto _out; } }} + break; + case 1101: +#line 1393 "char_ref.rl" + {te = p+1;{ output->first = 0x2665; {p++; goto _out; } }} + break; + case 1102: +#line 1394 "char_ref.rl" + {te = p+1;{ output->first = 0x2665; {p++; goto _out; } }} + break; + case 1103: +#line 1395 "char_ref.rl" + {te = p+1;{ output->first = 0x2026; {p++; goto _out; } }} + break; + case 1104: +#line 1396 "char_ref.rl" + {te = p+1;{ output->first = 0x22b9; {p++; goto _out; } }} + break; + case 1105: +#line 1397 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d525; {p++; goto _out; } }} + break; + case 1106: +#line 1398 "char_ref.rl" + {te = p+1;{ output->first = 0x2925; {p++; goto _out; } }} + break; + case 1107: +#line 1399 "char_ref.rl" + {te = p+1;{ output->first = 0x2926; {p++; goto _out; } }} + break; + case 1108: +#line 1400 "char_ref.rl" + {te = p+1;{ output->first = 0x21ff; {p++; goto _out; } }} + break; + case 1109: +#line 1401 "char_ref.rl" + {te = p+1;{ output->first = 0x223b; {p++; goto _out; } }} + break; + case 1110: +#line 1402 "char_ref.rl" + {te = p+1;{ output->first = 0x21a9; {p++; goto _out; } }} + break; + case 1111: +#line 1403 "char_ref.rl" + {te = p+1;{ output->first = 0x21aa; {p++; goto _out; } }} + break; + case 1112: +#line 1404 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d559; {p++; goto _out; } }} + break; + case 1113: +#line 1405 "char_ref.rl" + {te = p+1;{ output->first = 0x2015; {p++; goto _out; } }} + break; + case 1114: +#line 1406 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4bd; {p++; goto _out; } }} + break; + case 1115: +#line 1407 "char_ref.rl" + {te = p+1;{ output->first = 0x210f; {p++; goto _out; } }} + break; + case 1116: +#line 1408 "char_ref.rl" + {te = p+1;{ output->first = 0x0127; {p++; goto _out; } }} + break; + case 1117: +#line 1409 "char_ref.rl" + {te = p+1;{ output->first = 0x2043; {p++; goto _out; } }} + break; + case 1118: +#line 1410 "char_ref.rl" + {te = p+1;{ output->first = 0x2010; {p++; goto _out; } }} + break; + case 1119: +#line 1411 "char_ref.rl" + {te = p+1;{ output->first = 0xed; {p++; goto _out; } }} + break; + case 1120: +#line 1413 "char_ref.rl" + {te = p+1;{ output->first = 0x2063; {p++; goto _out; } }} + break; + case 1121: +#line 1414 "char_ref.rl" + {te = p+1;{ output->first = 0xee; {p++; goto _out; } }} + break; + case 1122: +#line 1416 "char_ref.rl" + {te = p+1;{ output->first = 0x0438; {p++; goto _out; } }} + break; + case 1123: +#line 1417 "char_ref.rl" + {te = p+1;{ output->first = 0x0435; {p++; goto _out; } }} + break; + case 1124: +#line 1418 "char_ref.rl" + {te = p+1;{ output->first = 0xa1; {p++; goto _out; } }} + break; + case 1125: +#line 1420 "char_ref.rl" + {te = p+1;{ output->first = 0x21d4; {p++; goto _out; } }} + break; + case 1126: +#line 1421 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d526; {p++; goto _out; } }} + break; + case 1127: +#line 1422 "char_ref.rl" + {te = p+1;{ output->first = 0xec; {p++; goto _out; } }} + break; + case 1128: +#line 1424 "char_ref.rl" + {te = p+1;{ output->first = 0x2148; {p++; goto _out; } }} + break; + case 1129: +#line 1425 "char_ref.rl" + {te = p+1;{ output->first = 0x2a0c; {p++; goto _out; } }} + break; + case 1130: +#line 1426 "char_ref.rl" + {te = p+1;{ output->first = 0x222d; {p++; goto _out; } }} + break; + case 1131: +#line 1427 "char_ref.rl" + {te = p+1;{ output->first = 0x29dc; {p++; goto _out; } }} + break; + case 1132: +#line 1428 "char_ref.rl" + {te = p+1;{ output->first = 0x2129; {p++; goto _out; } }} + break; + case 1133: +#line 1429 "char_ref.rl" + {te = p+1;{ output->first = 0x0133; {p++; goto _out; } }} + break; + case 1134: +#line 1430 "char_ref.rl" + {te = p+1;{ output->first = 0x012b; {p++; goto _out; } }} + break; + case 1135: +#line 1431 "char_ref.rl" + {te = p+1;{ output->first = 0x2111; {p++; goto _out; } }} + break; + case 1136: +#line 1432 "char_ref.rl" + {te = p+1;{ output->first = 0x2110; {p++; goto _out; } }} + break; + case 1137: +#line 1433 "char_ref.rl" + {te = p+1;{ output->first = 0x2111; {p++; goto _out; } }} + break; + case 1138: +#line 1434 "char_ref.rl" + {te = p+1;{ output->first = 0x0131; {p++; goto _out; } }} + break; + case 1139: +#line 1435 "char_ref.rl" + {te = p+1;{ output->first = 0x22b7; {p++; goto _out; } }} + break; + case 1140: +#line 1436 "char_ref.rl" + {te = p+1;{ output->first = 0x01b5; {p++; goto _out; } }} + break; + case 1141: +#line 1437 "char_ref.rl" + {te = p+1;{ output->first = 0x2208; {p++; goto _out; } }} + break; + case 1142: +#line 1438 "char_ref.rl" + {te = p+1;{ output->first = 0x2105; {p++; goto _out; } }} + break; + case 1143: +#line 1439 "char_ref.rl" + {te = p+1;{ output->first = 0x221e; {p++; goto _out; } }} + break; + case 1144: +#line 1440 "char_ref.rl" + {te = p+1;{ output->first = 0x29dd; {p++; goto _out; } }} + break; + case 1145: +#line 1441 "char_ref.rl" + {te = p+1;{ output->first = 0x0131; {p++; goto _out; } }} + break; + case 1146: +#line 1442 "char_ref.rl" + {te = p+1;{ output->first = 0x222b; {p++; goto _out; } }} + break; + case 1147: +#line 1443 "char_ref.rl" + {te = p+1;{ output->first = 0x22ba; {p++; goto _out; } }} + break; + case 1148: +#line 1444 "char_ref.rl" + {te = p+1;{ output->first = 0x2124; {p++; goto _out; } }} + break; + case 1149: +#line 1445 "char_ref.rl" + {te = p+1;{ output->first = 0x22ba; {p++; goto _out; } }} + break; + case 1150: +#line 1446 "char_ref.rl" + {te = p+1;{ output->first = 0x2a17; {p++; goto _out; } }} + break; + case 1151: +#line 1447 "char_ref.rl" + {te = p+1;{ output->first = 0x2a3c; {p++; goto _out; } }} + break; + case 1152: +#line 1448 "char_ref.rl" + {te = p+1;{ output->first = 0x0451; {p++; goto _out; } }} + break; + case 1153: +#line 1449 "char_ref.rl" + {te = p+1;{ output->first = 0x012f; {p++; goto _out; } }} + break; + case 1154: +#line 1450 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55a; {p++; goto _out; } }} + break; + case 1155: +#line 1451 "char_ref.rl" + {te = p+1;{ output->first = 0x03b9; {p++; goto _out; } }} + break; + case 1156: +#line 1452 "char_ref.rl" + {te = p+1;{ output->first = 0x2a3c; {p++; goto _out; } }} + break; + case 1157: +#line 1453 "char_ref.rl" + {te = p+1;{ output->first = 0xbf; {p++; goto _out; } }} + break; + case 1158: +#line 1455 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4be; {p++; goto _out; } }} + break; + case 1159: +#line 1456 "char_ref.rl" + {te = p+1;{ output->first = 0x2208; {p++; goto _out; } }} + break; + case 1160: +#line 1457 "char_ref.rl" + {te = p+1;{ output->first = 0x22f9; {p++; goto _out; } }} + break; + case 1161: +#line 1458 "char_ref.rl" + {te = p+1;{ output->first = 0x22f5; {p++; goto _out; } }} + break; + case 1162: +#line 1459 "char_ref.rl" + {te = p+1;{ output->first = 0x22f4; {p++; goto _out; } }} + break; + case 1163: +#line 1460 "char_ref.rl" + {te = p+1;{ output->first = 0x22f3; {p++; goto _out; } }} + break; + case 1164: +#line 1461 "char_ref.rl" + {te = p+1;{ output->first = 0x2208; {p++; goto _out; } }} + break; + case 1165: +#line 1462 "char_ref.rl" + {te = p+1;{ output->first = 0x2062; {p++; goto _out; } }} + break; + case 1166: +#line 1463 "char_ref.rl" + {te = p+1;{ output->first = 0x0129; {p++; goto _out; } }} + break; + case 1167: +#line 1464 "char_ref.rl" + {te = p+1;{ output->first = 0x0456; {p++; goto _out; } }} + break; + case 1168: +#line 1465 "char_ref.rl" + {te = p+1;{ output->first = 0xef; {p++; goto _out; } }} + break; + case 1169: +#line 1467 "char_ref.rl" + {te = p+1;{ output->first = 0x0135; {p++; goto _out; } }} + break; + case 1170: +#line 1468 "char_ref.rl" + {te = p+1;{ output->first = 0x0439; {p++; goto _out; } }} + break; + case 1171: +#line 1469 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d527; {p++; goto _out; } }} + break; + case 1172: +#line 1470 "char_ref.rl" + {te = p+1;{ output->first = 0x0237; {p++; goto _out; } }} + break; + case 1173: +#line 1471 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55b; {p++; goto _out; } }} + break; + case 1174: +#line 1472 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4bf; {p++; goto _out; } }} + break; + case 1175: +#line 1473 "char_ref.rl" + {te = p+1;{ output->first = 0x0458; {p++; goto _out; } }} + break; + case 1176: +#line 1474 "char_ref.rl" + {te = p+1;{ output->first = 0x0454; {p++; goto _out; } }} + break; + case 1177: +#line 1475 "char_ref.rl" + {te = p+1;{ output->first = 0x03ba; {p++; goto _out; } }} + break; + case 1178: +#line 1476 "char_ref.rl" + {te = p+1;{ output->first = 0x03f0; {p++; goto _out; } }} + break; + case 1179: +#line 1477 "char_ref.rl" + {te = p+1;{ output->first = 0x0137; {p++; goto _out; } }} + break; + case 1180: +#line 1478 "char_ref.rl" + {te = p+1;{ output->first = 0x043a; {p++; goto _out; } }} + break; + case 1181: +#line 1479 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d528; {p++; goto _out; } }} + break; + case 1182: +#line 1480 "char_ref.rl" + {te = p+1;{ output->first = 0x0138; {p++; goto _out; } }} + break; + case 1183: +#line 1481 "char_ref.rl" + {te = p+1;{ output->first = 0x0445; {p++; goto _out; } }} + break; + case 1184: +#line 1482 "char_ref.rl" + {te = p+1;{ output->first = 0x045c; {p++; goto _out; } }} + break; + case 1185: +#line 1483 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55c; {p++; goto _out; } }} + break; + case 1186: +#line 1484 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c0; {p++; goto _out; } }} + break; + case 1187: +#line 1485 "char_ref.rl" + {te = p+1;{ output->first = 0x21da; {p++; goto _out; } }} + break; + case 1188: +#line 1486 "char_ref.rl" + {te = p+1;{ output->first = 0x21d0; {p++; goto _out; } }} + break; + case 1189: +#line 1487 "char_ref.rl" + {te = p+1;{ output->first = 0x291b; {p++; goto _out; } }} + break; + case 1190: +#line 1488 "char_ref.rl" + {te = p+1;{ output->first = 0x290e; {p++; goto _out; } }} + break; + case 1191: +#line 1489 "char_ref.rl" + {te = p+1;{ output->first = 0x2266; {p++; goto _out; } }} + break; + case 1192: +#line 1490 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8b; {p++; goto _out; } }} + break; + case 1193: +#line 1491 "char_ref.rl" + {te = p+1;{ output->first = 0x2962; {p++; goto _out; } }} + break; + case 1194: +#line 1492 "char_ref.rl" + {te = p+1;{ output->first = 0x013a; {p++; goto _out; } }} + break; + case 1195: +#line 1493 "char_ref.rl" + {te = p+1;{ output->first = 0x29b4; {p++; goto _out; } }} + break; + case 1196: +#line 1494 "char_ref.rl" + {te = p+1;{ output->first = 0x2112; {p++; goto _out; } }} + break; + case 1197: +#line 1495 "char_ref.rl" + {te = p+1;{ output->first = 0x03bb; {p++; goto _out; } }} + break; + case 1198: +#line 1496 "char_ref.rl" + {te = p+1;{ output->first = 0x27e8; {p++; goto _out; } }} + break; + case 1199: +#line 1497 "char_ref.rl" + {te = p+1;{ output->first = 0x2991; {p++; goto _out; } }} + break; + case 1200: +#line 1498 "char_ref.rl" + {te = p+1;{ output->first = 0x27e8; {p++; goto _out; } }} + break; + case 1201: +#line 1499 "char_ref.rl" + {te = p+1;{ output->first = 0x2a85; {p++; goto _out; } }} + break; + case 1202: +#line 1500 "char_ref.rl" + {te = p+1;{ output->first = 0xab; {p++; goto _out; } }} + break; + case 1203: +#line 1502 "char_ref.rl" + {te = p+1;{ output->first = 0x2190; {p++; goto _out; } }} + break; + case 1204: +#line 1503 "char_ref.rl" + {te = p+1;{ output->first = 0x21e4; {p++; goto _out; } }} + break; + case 1205: +#line 1504 "char_ref.rl" + {te = p+1;{ output->first = 0x291f; {p++; goto _out; } }} + break; + case 1206: +#line 1505 "char_ref.rl" + {te = p+1;{ output->first = 0x291d; {p++; goto _out; } }} + break; + case 1207: +#line 1506 "char_ref.rl" + {te = p+1;{ output->first = 0x21a9; {p++; goto _out; } }} + break; + case 1208: +#line 1507 "char_ref.rl" + {te = p+1;{ output->first = 0x21ab; {p++; goto _out; } }} + break; + case 1209: +#line 1508 "char_ref.rl" + {te = p+1;{ output->first = 0x2939; {p++; goto _out; } }} + break; + case 1210: +#line 1509 "char_ref.rl" + {te = p+1;{ output->first = 0x2973; {p++; goto _out; } }} + break; + case 1211: +#line 1510 "char_ref.rl" + {te = p+1;{ output->first = 0x21a2; {p++; goto _out; } }} + break; + case 1212: +#line 1511 "char_ref.rl" + {te = p+1;{ output->first = 0x2aab; {p++; goto _out; } }} + break; + case 1213: +#line 1512 "char_ref.rl" + {te = p+1;{ output->first = 0x2919; {p++; goto _out; } }} + break; + case 1214: +#line 1513 "char_ref.rl" + {te = p+1;{ output->first = 0x2aad; {p++; goto _out; } }} + break; + case 1215: +#line 1514 "char_ref.rl" + {te = p+1;{ output->first = 0x2aad; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1216: +#line 1515 "char_ref.rl" + {te = p+1;{ output->first = 0x290c; {p++; goto _out; } }} + break; + case 1217: +#line 1516 "char_ref.rl" + {te = p+1;{ output->first = 0x2772; {p++; goto _out; } }} + break; + case 1218: +#line 1517 "char_ref.rl" + {te = p+1;{ output->first = 0x7b; {p++; goto _out; } }} + break; + case 1219: +#line 1518 "char_ref.rl" + {te = p+1;{ output->first = 0x5b; {p++; goto _out; } }} + break; + case 1220: +#line 1519 "char_ref.rl" + {te = p+1;{ output->first = 0x298b; {p++; goto _out; } }} + break; + case 1221: +#line 1520 "char_ref.rl" + {te = p+1;{ output->first = 0x298f; {p++; goto _out; } }} + break; + case 1222: +#line 1521 "char_ref.rl" + {te = p+1;{ output->first = 0x298d; {p++; goto _out; } }} + break; + case 1223: +#line 1522 "char_ref.rl" + {te = p+1;{ output->first = 0x013e; {p++; goto _out; } }} + break; + case 1224: +#line 1523 "char_ref.rl" + {te = p+1;{ output->first = 0x013c; {p++; goto _out; } }} + break; + case 1225: +#line 1524 "char_ref.rl" + {te = p+1;{ output->first = 0x2308; {p++; goto _out; } }} + break; + case 1226: +#line 1525 "char_ref.rl" + {te = p+1;{ output->first = 0x7b; {p++; goto _out; } }} + break; + case 1227: +#line 1526 "char_ref.rl" + {te = p+1;{ output->first = 0x043b; {p++; goto _out; } }} + break; + case 1228: +#line 1527 "char_ref.rl" + {te = p+1;{ output->first = 0x2936; {p++; goto _out; } }} + break; + case 1229: +#line 1528 "char_ref.rl" + {te = p+1;{ output->first = 0x201c; {p++; goto _out; } }} + break; + case 1230: +#line 1529 "char_ref.rl" + {te = p+1;{ output->first = 0x201e; {p++; goto _out; } }} + break; + case 1231: +#line 1530 "char_ref.rl" + {te = p+1;{ output->first = 0x2967; {p++; goto _out; } }} + break; + case 1232: +#line 1531 "char_ref.rl" + {te = p+1;{ output->first = 0x294b; {p++; goto _out; } }} + break; + case 1233: +#line 1532 "char_ref.rl" + {te = p+1;{ output->first = 0x21b2; {p++; goto _out; } }} + break; + case 1234: +#line 1533 "char_ref.rl" + {te = p+1;{ output->first = 0x2264; {p++; goto _out; } }} + break; + case 1235: +#line 1534 "char_ref.rl" + {te = p+1;{ output->first = 0x2190; {p++; goto _out; } }} + break; + case 1236: +#line 1535 "char_ref.rl" + {te = p+1;{ output->first = 0x21a2; {p++; goto _out; } }} + break; + case 1237: +#line 1536 "char_ref.rl" + {te = p+1;{ output->first = 0x21bd; {p++; goto _out; } }} + break; + case 1238: +#line 1537 "char_ref.rl" + {te = p+1;{ output->first = 0x21bc; {p++; goto _out; } }} + break; + case 1239: +#line 1538 "char_ref.rl" + {te = p+1;{ output->first = 0x21c7; {p++; goto _out; } }} + break; + case 1240: +#line 1539 "char_ref.rl" + {te = p+1;{ output->first = 0x2194; {p++; goto _out; } }} + break; + case 1241: +#line 1540 "char_ref.rl" + {te = p+1;{ output->first = 0x21c6; {p++; goto _out; } }} + break; + case 1242: +#line 1541 "char_ref.rl" + {te = p+1;{ output->first = 0x21cb; {p++; goto _out; } }} + break; + case 1243: +#line 1542 "char_ref.rl" + {te = p+1;{ output->first = 0x21ad; {p++; goto _out; } }} + break; + case 1244: +#line 1543 "char_ref.rl" + {te = p+1;{ output->first = 0x22cb; {p++; goto _out; } }} + break; + case 1245: +#line 1544 "char_ref.rl" + {te = p+1;{ output->first = 0x22da; {p++; goto _out; } }} + break; + case 1246: +#line 1545 "char_ref.rl" + {te = p+1;{ output->first = 0x2264; {p++; goto _out; } }} + break; + case 1247: +#line 1546 "char_ref.rl" + {te = p+1;{ output->first = 0x2266; {p++; goto _out; } }} + break; + case 1248: +#line 1547 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; {p++; goto _out; } }} + break; + case 1249: +#line 1548 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; {p++; goto _out; } }} + break; + case 1250: +#line 1549 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa8; {p++; goto _out; } }} + break; + case 1251: +#line 1550 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7f; {p++; goto _out; } }} + break; + case 1252: +#line 1551 "char_ref.rl" + {te = p+1;{ output->first = 0x2a81; {p++; goto _out; } }} + break; + case 1253: +#line 1552 "char_ref.rl" + {te = p+1;{ output->first = 0x2a83; {p++; goto _out; } }} + break; + case 1254: +#line 1553 "char_ref.rl" + {te = p+1;{ output->first = 0x22da; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1255: +#line 1554 "char_ref.rl" + {te = p+1;{ output->first = 0x2a93; {p++; goto _out; } }} + break; + case 1256: +#line 1555 "char_ref.rl" + {te = p+1;{ output->first = 0x2a85; {p++; goto _out; } }} + break; + case 1257: +#line 1556 "char_ref.rl" + {te = p+1;{ output->first = 0x22d6; {p++; goto _out; } }} + break; + case 1258: +#line 1557 "char_ref.rl" + {te = p+1;{ output->first = 0x22da; {p++; goto _out; } }} + break; + case 1259: +#line 1558 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8b; {p++; goto _out; } }} + break; + case 1260: +#line 1559 "char_ref.rl" + {te = p+1;{ output->first = 0x2276; {p++; goto _out; } }} + break; + case 1261: +#line 1560 "char_ref.rl" + {te = p+1;{ output->first = 0x2272; {p++; goto _out; } }} + break; + case 1262: +#line 1561 "char_ref.rl" + {te = p+1;{ output->first = 0x297c; {p++; goto _out; } }} + break; + case 1263: +#line 1562 "char_ref.rl" + {te = p+1;{ output->first = 0x230a; {p++; goto _out; } }} + break; + case 1264: +#line 1563 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d529; {p++; goto _out; } }} + break; + case 1265: +#line 1564 "char_ref.rl" + {te = p+1;{ output->first = 0x2276; {p++; goto _out; } }} + break; + case 1266: +#line 1565 "char_ref.rl" + {te = p+1;{ output->first = 0x2a91; {p++; goto _out; } }} + break; + case 1267: +#line 1566 "char_ref.rl" + {te = p+1;{ output->first = 0x21bd; {p++; goto _out; } }} + break; + case 1268: +#line 1567 "char_ref.rl" + {te = p+1;{ output->first = 0x21bc; {p++; goto _out; } }} + break; + case 1269: +#line 1568 "char_ref.rl" + {te = p+1;{ output->first = 0x296a; {p++; goto _out; } }} + break; + case 1270: +#line 1569 "char_ref.rl" + {te = p+1;{ output->first = 0x2584; {p++; goto _out; } }} + break; + case 1271: +#line 1570 "char_ref.rl" + {te = p+1;{ output->first = 0x0459; {p++; goto _out; } }} + break; + case 1272: +#line 1571 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; {p++; goto _out; } }} + break; + case 1273: +#line 1572 "char_ref.rl" + {te = p+1;{ output->first = 0x21c7; {p++; goto _out; } }} + break; + case 1274: +#line 1573 "char_ref.rl" + {te = p+1;{ output->first = 0x231e; {p++; goto _out; } }} + break; + case 1275: +#line 1574 "char_ref.rl" + {te = p+1;{ output->first = 0x296b; {p++; goto _out; } }} + break; + case 1276: +#line 1575 "char_ref.rl" + {te = p+1;{ output->first = 0x25fa; {p++; goto _out; } }} + break; + case 1277: +#line 1576 "char_ref.rl" + {te = p+1;{ output->first = 0x0140; {p++; goto _out; } }} + break; + case 1278: +#line 1577 "char_ref.rl" + {te = p+1;{ output->first = 0x23b0; {p++; goto _out; } }} + break; + case 1279: +#line 1578 "char_ref.rl" + {te = p+1;{ output->first = 0x23b0; {p++; goto _out; } }} + break; + case 1280: +#line 1579 "char_ref.rl" + {te = p+1;{ output->first = 0x2268; {p++; goto _out; } }} + break; + case 1281: +#line 1580 "char_ref.rl" + {te = p+1;{ output->first = 0x2a89; {p++; goto _out; } }} + break; + case 1282: +#line 1581 "char_ref.rl" + {te = p+1;{ output->first = 0x2a89; {p++; goto _out; } }} + break; + case 1283: +#line 1582 "char_ref.rl" + {te = p+1;{ output->first = 0x2a87; {p++; goto _out; } }} + break; + case 1284: +#line 1583 "char_ref.rl" + {te = p+1;{ output->first = 0x2a87; {p++; goto _out; } }} + break; + case 1285: +#line 1584 "char_ref.rl" + {te = p+1;{ output->first = 0x2268; {p++; goto _out; } }} + break; + case 1286: +#line 1585 "char_ref.rl" + {te = p+1;{ output->first = 0x22e6; {p++; goto _out; } }} + break; + case 1287: +#line 1586 "char_ref.rl" + {te = p+1;{ output->first = 0x27ec; {p++; goto _out; } }} + break; + case 1288: +#line 1587 "char_ref.rl" + {te = p+1;{ output->first = 0x21fd; {p++; goto _out; } }} + break; + case 1289: +#line 1588 "char_ref.rl" + {te = p+1;{ output->first = 0x27e6; {p++; goto _out; } }} + break; + case 1290: +#line 1589 "char_ref.rl" + {te = p+1;{ output->first = 0x27f5; {p++; goto _out; } }} + break; + case 1291: +#line 1590 "char_ref.rl" + {te = p+1;{ output->first = 0x27f7; {p++; goto _out; } }} + break; + case 1292: +#line 1591 "char_ref.rl" + {te = p+1;{ output->first = 0x27fc; {p++; goto _out; } }} + break; + case 1293: +#line 1592 "char_ref.rl" + {te = p+1;{ output->first = 0x27f6; {p++; goto _out; } }} + break; + case 1294: +#line 1593 "char_ref.rl" + {te = p+1;{ output->first = 0x21ab; {p++; goto _out; } }} + break; + case 1295: +#line 1594 "char_ref.rl" + {te = p+1;{ output->first = 0x21ac; {p++; goto _out; } }} + break; + case 1296: +#line 1595 "char_ref.rl" + {te = p+1;{ output->first = 0x2985; {p++; goto _out; } }} + break; + case 1297: +#line 1596 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55d; {p++; goto _out; } }} + break; + case 1298: +#line 1597 "char_ref.rl" + {te = p+1;{ output->first = 0x2a2d; {p++; goto _out; } }} + break; + case 1299: +#line 1598 "char_ref.rl" + {te = p+1;{ output->first = 0x2a34; {p++; goto _out; } }} + break; + case 1300: +#line 1599 "char_ref.rl" + {te = p+1;{ output->first = 0x2217; {p++; goto _out; } }} + break; + case 1301: +#line 1600 "char_ref.rl" + {te = p+1;{ output->first = 0x5f; {p++; goto _out; } }} + break; + case 1302: +#line 1601 "char_ref.rl" + {te = p+1;{ output->first = 0x25ca; {p++; goto _out; } }} + break; + case 1303: +#line 1602 "char_ref.rl" + {te = p+1;{ output->first = 0x25ca; {p++; goto _out; } }} + break; + case 1304: +#line 1603 "char_ref.rl" + {te = p+1;{ output->first = 0x29eb; {p++; goto _out; } }} + break; + case 1305: +#line 1604 "char_ref.rl" + {te = p+1;{ output->first = 0x28; {p++; goto _out; } }} + break; + case 1306: +#line 1605 "char_ref.rl" + {te = p+1;{ output->first = 0x2993; {p++; goto _out; } }} + break; + case 1307: +#line 1606 "char_ref.rl" + {te = p+1;{ output->first = 0x21c6; {p++; goto _out; } }} + break; + case 1308: +#line 1607 "char_ref.rl" + {te = p+1;{ output->first = 0x231f; {p++; goto _out; } }} + break; + case 1309: +#line 1608 "char_ref.rl" + {te = p+1;{ output->first = 0x21cb; {p++; goto _out; } }} + break; + case 1310: +#line 1609 "char_ref.rl" + {te = p+1;{ output->first = 0x296d; {p++; goto _out; } }} + break; + case 1311: +#line 1610 "char_ref.rl" + {te = p+1;{ output->first = 0x200e; {p++; goto _out; } }} + break; + case 1312: +#line 1611 "char_ref.rl" + {te = p+1;{ output->first = 0x22bf; {p++; goto _out; } }} + break; + case 1313: +#line 1612 "char_ref.rl" + {te = p+1;{ output->first = 0x2039; {p++; goto _out; } }} + break; + case 1314: +#line 1613 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c1; {p++; goto _out; } }} + break; + case 1315: +#line 1614 "char_ref.rl" + {te = p+1;{ output->first = 0x21b0; {p++; goto _out; } }} + break; + case 1316: +#line 1615 "char_ref.rl" + {te = p+1;{ output->first = 0x2272; {p++; goto _out; } }} + break; + case 1317: +#line 1616 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8d; {p++; goto _out; } }} + break; + case 1318: +#line 1617 "char_ref.rl" + {te = p+1;{ output->first = 0x2a8f; {p++; goto _out; } }} + break; + case 1319: +#line 1618 "char_ref.rl" + {te = p+1;{ output->first = 0x5b; {p++; goto _out; } }} + break; + case 1320: +#line 1619 "char_ref.rl" + {te = p+1;{ output->first = 0x2018; {p++; goto _out; } }} + break; + case 1321: +#line 1620 "char_ref.rl" + {te = p+1;{ output->first = 0x201a; {p++; goto _out; } }} + break; + case 1322: +#line 1621 "char_ref.rl" + {te = p+1;{ output->first = 0x0142; {p++; goto _out; } }} + break; + case 1323: +#line 1622 "char_ref.rl" + {te = p+1;{ output->first = 0x3c; {p++; goto _out; } }} + break; + case 1324: +#line 1624 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa6; {p++; goto _out; } }} + break; + case 1325: +#line 1625 "char_ref.rl" + {te = p+1;{ output->first = 0x2a79; {p++; goto _out; } }} + break; + case 1326: +#line 1626 "char_ref.rl" + {te = p+1;{ output->first = 0x22d6; {p++; goto _out; } }} + break; + case 1327: +#line 1627 "char_ref.rl" + {te = p+1;{ output->first = 0x22cb; {p++; goto _out; } }} + break; + case 1328: +#line 1628 "char_ref.rl" + {te = p+1;{ output->first = 0x22c9; {p++; goto _out; } }} + break; + case 1329: +#line 1629 "char_ref.rl" + {te = p+1;{ output->first = 0x2976; {p++; goto _out; } }} + break; + case 1330: +#line 1630 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7b; {p++; goto _out; } }} + break; + case 1331: +#line 1631 "char_ref.rl" + {te = p+1;{ output->first = 0x2996; {p++; goto _out; } }} + break; + case 1332: +#line 1632 "char_ref.rl" + {te = p+1;{ output->first = 0x25c3; {p++; goto _out; } }} + break; + case 1333: +#line 1633 "char_ref.rl" + {te = p+1;{ output->first = 0x22b4; {p++; goto _out; } }} + break; + case 1334: +#line 1634 "char_ref.rl" + {te = p+1;{ output->first = 0x25c2; {p++; goto _out; } }} + break; + case 1335: +#line 1635 "char_ref.rl" + {te = p+1;{ output->first = 0x294a; {p++; goto _out; } }} + break; + case 1336: +#line 1636 "char_ref.rl" + {te = p+1;{ output->first = 0x2966; {p++; goto _out; } }} + break; + case 1337: +#line 1637 "char_ref.rl" + {te = p+1;{ output->first = 0x2268; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1338: +#line 1638 "char_ref.rl" + {te = p+1;{ output->first = 0x2268; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1339: +#line 1639 "char_ref.rl" + {te = p+1;{ output->first = 0x223a; {p++; goto _out; } }} + break; + case 1340: +#line 1640 "char_ref.rl" + {te = p+1;{ output->first = 0xaf; {p++; goto _out; } }} + break; + case 1341: +#line 1642 "char_ref.rl" + {te = p+1;{ output->first = 0x2642; {p++; goto _out; } }} + break; + case 1342: +#line 1643 "char_ref.rl" + {te = p+1;{ output->first = 0x2720; {p++; goto _out; } }} + break; + case 1343: +#line 1644 "char_ref.rl" + {te = p+1;{ output->first = 0x2720; {p++; goto _out; } }} + break; + case 1344: +#line 1645 "char_ref.rl" + {te = p+1;{ output->first = 0x21a6; {p++; goto _out; } }} + break; + case 1345: +#line 1646 "char_ref.rl" + {te = p+1;{ output->first = 0x21a6; {p++; goto _out; } }} + break; + case 1346: +#line 1647 "char_ref.rl" + {te = p+1;{ output->first = 0x21a7; {p++; goto _out; } }} + break; + case 1347: +#line 1648 "char_ref.rl" + {te = p+1;{ output->first = 0x21a4; {p++; goto _out; } }} + break; + case 1348: +#line 1649 "char_ref.rl" + {te = p+1;{ output->first = 0x21a5; {p++; goto _out; } }} + break; + case 1349: +#line 1650 "char_ref.rl" + {te = p+1;{ output->first = 0x25ae; {p++; goto _out; } }} + break; + case 1350: +#line 1651 "char_ref.rl" + {te = p+1;{ output->first = 0x2a29; {p++; goto _out; } }} + break; + case 1351: +#line 1652 "char_ref.rl" + {te = p+1;{ output->first = 0x043c; {p++; goto _out; } }} + break; + case 1352: +#line 1653 "char_ref.rl" + {te = p+1;{ output->first = 0x2014; {p++; goto _out; } }} + break; + case 1353: +#line 1654 "char_ref.rl" + {te = p+1;{ output->first = 0x2221; {p++; goto _out; } }} + break; + case 1354: +#line 1655 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52a; {p++; goto _out; } }} + break; + case 1355: +#line 1656 "char_ref.rl" + {te = p+1;{ output->first = 0x2127; {p++; goto _out; } }} + break; + case 1356: +#line 1657 "char_ref.rl" + {te = p+1;{ output->first = 0xb5; {p++; goto _out; } }} + break; + case 1357: +#line 1659 "char_ref.rl" + {te = p+1;{ output->first = 0x2223; {p++; goto _out; } }} + break; + case 1358: +#line 1660 "char_ref.rl" + {te = p+1;{ output->first = 0x2a; {p++; goto _out; } }} + break; + case 1359: +#line 1661 "char_ref.rl" + {te = p+1;{ output->first = 0x2af0; {p++; goto _out; } }} + break; + case 1360: +#line 1662 "char_ref.rl" + {te = p+1;{ output->first = 0xb7; {p++; goto _out; } }} + break; + case 1361: +#line 1664 "char_ref.rl" + {te = p+1;{ output->first = 0x2212; {p++; goto _out; } }} + break; + case 1362: +#line 1665 "char_ref.rl" + {te = p+1;{ output->first = 0x229f; {p++; goto _out; } }} + break; + case 1363: +#line 1666 "char_ref.rl" + {te = p+1;{ output->first = 0x2238; {p++; goto _out; } }} + break; + case 1364: +#line 1667 "char_ref.rl" + {te = p+1;{ output->first = 0x2a2a; {p++; goto _out; } }} + break; + case 1365: +#line 1668 "char_ref.rl" + {te = p+1;{ output->first = 0x2adb; {p++; goto _out; } }} + break; + case 1366: +#line 1669 "char_ref.rl" + {te = p+1;{ output->first = 0x2026; {p++; goto _out; } }} + break; + case 1367: +#line 1670 "char_ref.rl" + {te = p+1;{ output->first = 0x2213; {p++; goto _out; } }} + break; + case 1368: +#line 1671 "char_ref.rl" + {te = p+1;{ output->first = 0x22a7; {p++; goto _out; } }} + break; + case 1369: +#line 1672 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55e; {p++; goto _out; } }} + break; + case 1370: +#line 1673 "char_ref.rl" + {te = p+1;{ output->first = 0x2213; {p++; goto _out; } }} + break; + case 1371: +#line 1674 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c2; {p++; goto _out; } }} + break; + case 1372: +#line 1675 "char_ref.rl" + {te = p+1;{ output->first = 0x223e; {p++; goto _out; } }} + break; + case 1373: +#line 1676 "char_ref.rl" + {te = p+1;{ output->first = 0x03bc; {p++; goto _out; } }} + break; + case 1374: +#line 1677 "char_ref.rl" + {te = p+1;{ output->first = 0x22b8; {p++; goto _out; } }} + break; + case 1375: +#line 1678 "char_ref.rl" + {te = p+1;{ output->first = 0x22b8; {p++; goto _out; } }} + break; + case 1376: +#line 1679 "char_ref.rl" + {te = p+1;{ output->first = 0x22d9; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1377: +#line 1680 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1378: +#line 1681 "char_ref.rl" + {te = p+1;{ output->first = 0x226b; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1379: +#line 1682 "char_ref.rl" + {te = p+1;{ output->first = 0x21cd; {p++; goto _out; } }} + break; + case 1380: +#line 1683 "char_ref.rl" + {te = p+1;{ output->first = 0x21ce; {p++; goto _out; } }} + break; + case 1381: +#line 1684 "char_ref.rl" + {te = p+1;{ output->first = 0x22d8; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1382: +#line 1685 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1383: +#line 1686 "char_ref.rl" + {te = p+1;{ output->first = 0x226a; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1384: +#line 1687 "char_ref.rl" + {te = p+1;{ output->first = 0x21cf; {p++; goto _out; } }} + break; + case 1385: +#line 1688 "char_ref.rl" + {te = p+1;{ output->first = 0x22af; {p++; goto _out; } }} + break; + case 1386: +#line 1689 "char_ref.rl" + {te = p+1;{ output->first = 0x22ae; {p++; goto _out; } }} + break; + case 1387: +#line 1690 "char_ref.rl" + {te = p+1;{ output->first = 0x2207; {p++; goto _out; } }} + break; + case 1388: +#line 1691 "char_ref.rl" + {te = p+1;{ output->first = 0x0144; {p++; goto _out; } }} + break; + case 1389: +#line 1692 "char_ref.rl" + {te = p+1;{ output->first = 0x2220; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1390: +#line 1693 "char_ref.rl" + {te = p+1;{ output->first = 0x2249; {p++; goto _out; } }} + break; + case 1391: +#line 1694 "char_ref.rl" + {te = p+1;{ output->first = 0x2a70; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1392: +#line 1695 "char_ref.rl" + {te = p+1;{ output->first = 0x224b; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1393: +#line 1696 "char_ref.rl" + {te = p+1;{ output->first = 0x0149; {p++; goto _out; } }} + break; + case 1394: +#line 1697 "char_ref.rl" + {te = p+1;{ output->first = 0x2249; {p++; goto _out; } }} + break; + case 1395: +#line 1698 "char_ref.rl" + {te = p+1;{ output->first = 0x266e; {p++; goto _out; } }} + break; + case 1396: +#line 1699 "char_ref.rl" + {te = p+1;{ output->first = 0x266e; {p++; goto _out; } }} + break; + case 1397: +#line 1700 "char_ref.rl" + {te = p+1;{ output->first = 0x2115; {p++; goto _out; } }} + break; + case 1398: +#line 1701 "char_ref.rl" + {te = p+1;{ output->first = 0xa0; {p++; goto _out; } }} + break; + case 1399: +#line 1703 "char_ref.rl" + {te = p+1;{ output->first = 0x224e; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1400: +#line 1704 "char_ref.rl" + {te = p+1;{ output->first = 0x224f; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1401: +#line 1705 "char_ref.rl" + {te = p+1;{ output->first = 0x2a43; {p++; goto _out; } }} + break; + case 1402: +#line 1706 "char_ref.rl" + {te = p+1;{ output->first = 0x0148; {p++; goto _out; } }} + break; + case 1403: +#line 1707 "char_ref.rl" + {te = p+1;{ output->first = 0x0146; {p++; goto _out; } }} + break; + case 1404: +#line 1708 "char_ref.rl" + {te = p+1;{ output->first = 0x2247; {p++; goto _out; } }} + break; + case 1405: +#line 1709 "char_ref.rl" + {te = p+1;{ output->first = 0x2a6d; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1406: +#line 1710 "char_ref.rl" + {te = p+1;{ output->first = 0x2a42; {p++; goto _out; } }} + break; + case 1407: +#line 1711 "char_ref.rl" + {te = p+1;{ output->first = 0x043d; {p++; goto _out; } }} + break; + case 1408: +#line 1712 "char_ref.rl" + {te = p+1;{ output->first = 0x2013; {p++; goto _out; } }} + break; + case 1409: +#line 1713 "char_ref.rl" + {te = p+1;{ output->first = 0x2260; {p++; goto _out; } }} + break; + case 1410: +#line 1714 "char_ref.rl" + {te = p+1;{ output->first = 0x21d7; {p++; goto _out; } }} + break; + case 1411: +#line 1715 "char_ref.rl" + {te = p+1;{ output->first = 0x2924; {p++; goto _out; } }} + break; + case 1412: +#line 1716 "char_ref.rl" + {te = p+1;{ output->first = 0x2197; {p++; goto _out; } }} + break; + case 1413: +#line 1717 "char_ref.rl" + {te = p+1;{ output->first = 0x2197; {p++; goto _out; } }} + break; + case 1414: +#line 1718 "char_ref.rl" + {te = p+1;{ output->first = 0x2250; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1415: +#line 1719 "char_ref.rl" + {te = p+1;{ output->first = 0x2262; {p++; goto _out; } }} + break; + case 1416: +#line 1720 "char_ref.rl" + {te = p+1;{ output->first = 0x2928; {p++; goto _out; } }} + break; + case 1417: +#line 1721 "char_ref.rl" + {te = p+1;{ output->first = 0x2242; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1418: +#line 1722 "char_ref.rl" + {te = p+1;{ output->first = 0x2204; {p++; goto _out; } }} + break; + case 1419: +#line 1723 "char_ref.rl" + {te = p+1;{ output->first = 0x2204; {p++; goto _out; } }} + break; + case 1420: +#line 1724 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52b; {p++; goto _out; } }} + break; + case 1421: +#line 1725 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1422: +#line 1726 "char_ref.rl" + {te = p+1;{ output->first = 0x2271; {p++; goto _out; } }} + break; + case 1423: +#line 1727 "char_ref.rl" + {te = p+1;{ output->first = 0x2271; {p++; goto _out; } }} + break; + case 1424: +#line 1728 "char_ref.rl" + {te = p+1;{ output->first = 0x2267; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1425: +#line 1729 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1426: +#line 1730 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7e; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1427: +#line 1731 "char_ref.rl" + {te = p+1;{ output->first = 0x2275; {p++; goto _out; } }} + break; + case 1428: +#line 1732 "char_ref.rl" + {te = p+1;{ output->first = 0x226f; {p++; goto _out; } }} + break; + case 1429: +#line 1733 "char_ref.rl" + {te = p+1;{ output->first = 0x226f; {p++; goto _out; } }} + break; + case 1430: +#line 1734 "char_ref.rl" + {te = p+1;{ output->first = 0x21ce; {p++; goto _out; } }} + break; + case 1431: +#line 1735 "char_ref.rl" + {te = p+1;{ output->first = 0x21ae; {p++; goto _out; } }} + break; + case 1432: +#line 1736 "char_ref.rl" + {te = p+1;{ output->first = 0x2af2; {p++; goto _out; } }} + break; + case 1433: +#line 1737 "char_ref.rl" + {te = p+1;{ output->first = 0x220b; {p++; goto _out; } }} + break; + case 1434: +#line 1738 "char_ref.rl" + {te = p+1;{ output->first = 0x22fc; {p++; goto _out; } }} + break; + case 1435: +#line 1739 "char_ref.rl" + {te = p+1;{ output->first = 0x22fa; {p++; goto _out; } }} + break; + case 1436: +#line 1740 "char_ref.rl" + {te = p+1;{ output->first = 0x220b; {p++; goto _out; } }} + break; + case 1437: +#line 1741 "char_ref.rl" + {te = p+1;{ output->first = 0x045a; {p++; goto _out; } }} + break; + case 1438: +#line 1742 "char_ref.rl" + {te = p+1;{ output->first = 0x21cd; {p++; goto _out; } }} + break; + case 1439: +#line 1743 "char_ref.rl" + {te = p+1;{ output->first = 0x2266; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1440: +#line 1744 "char_ref.rl" + {te = p+1;{ output->first = 0x219a; {p++; goto _out; } }} + break; + case 1441: +#line 1745 "char_ref.rl" + {te = p+1;{ output->first = 0x2025; {p++; goto _out; } }} + break; + case 1442: +#line 1746 "char_ref.rl" + {te = p+1;{ output->first = 0x2270; {p++; goto _out; } }} + break; + case 1443: +#line 1747 "char_ref.rl" + {te = p+1;{ output->first = 0x219a; {p++; goto _out; } }} + break; + case 1444: +#line 1748 "char_ref.rl" + {te = p+1;{ output->first = 0x21ae; {p++; goto _out; } }} + break; + case 1445: +#line 1749 "char_ref.rl" + {te = p+1;{ output->first = 0x2270; {p++; goto _out; } }} + break; + case 1446: +#line 1750 "char_ref.rl" + {te = p+1;{ output->first = 0x2266; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1447: +#line 1751 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1448: +#line 1752 "char_ref.rl" + {te = p+1;{ output->first = 0x2a7d; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1449: +#line 1753 "char_ref.rl" + {te = p+1;{ output->first = 0x226e; {p++; goto _out; } }} + break; + case 1450: +#line 1754 "char_ref.rl" + {te = p+1;{ output->first = 0x2274; {p++; goto _out; } }} + break; + case 1451: +#line 1755 "char_ref.rl" + {te = p+1;{ output->first = 0x226e; {p++; goto _out; } }} + break; + case 1452: +#line 1756 "char_ref.rl" + {te = p+1;{ output->first = 0x22ea; {p++; goto _out; } }} + break; + case 1453: +#line 1757 "char_ref.rl" + {te = p+1;{ output->first = 0x22ec; {p++; goto _out; } }} + break; + case 1454: +#line 1758 "char_ref.rl" + {te = p+1;{ output->first = 0x2224; {p++; goto _out; } }} + break; + case 1455: +#line 1759 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d55f; {p++; goto _out; } }} + break; + case 1456: +#line 1760 "char_ref.rl" + {te = p+1;{ output->first = 0xac; {p++; goto _out; } }} + break; + case 1457: +#line 1761 "char_ref.rl" + {te = p+1;{ output->first = 0x2209; {p++; goto _out; } }} + break; + case 1458: +#line 1762 "char_ref.rl" + {te = p+1;{ output->first = 0x22f9; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1459: +#line 1763 "char_ref.rl" + {te = p+1;{ output->first = 0x22f5; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1460: +#line 1764 "char_ref.rl" + {te = p+1;{ output->first = 0x2209; {p++; goto _out; } }} + break; + case 1461: +#line 1765 "char_ref.rl" + {te = p+1;{ output->first = 0x22f7; {p++; goto _out; } }} + break; + case 1462: +#line 1766 "char_ref.rl" + {te = p+1;{ output->first = 0x22f6; {p++; goto _out; } }} + break; + case 1463: +#line 1767 "char_ref.rl" + {te = p+1;{ output->first = 0x220c; {p++; goto _out; } }} + break; + case 1464: +#line 1768 "char_ref.rl" + {te = p+1;{ output->first = 0x220c; {p++; goto _out; } }} + break; + case 1465: +#line 1769 "char_ref.rl" + {te = p+1;{ output->first = 0x22fe; {p++; goto _out; } }} + break; + case 1466: +#line 1770 "char_ref.rl" + {te = p+1;{ output->first = 0x22fd; {p++; goto _out; } }} + break; + case 1467: +#line 1772 "char_ref.rl" + {te = p+1;{ output->first = 0x2226; {p++; goto _out; } }} + break; + case 1468: +#line 1773 "char_ref.rl" + {te = p+1;{ output->first = 0x2226; {p++; goto _out; } }} + break; + case 1469: +#line 1774 "char_ref.rl" + {te = p+1;{ output->first = 0x2afd; output->second = 0x20e5; {p++; goto _out; } }} + break; + case 1470: +#line 1775 "char_ref.rl" + {te = p+1;{ output->first = 0x2202; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1471: +#line 1776 "char_ref.rl" + {te = p+1;{ output->first = 0x2a14; {p++; goto _out; } }} + break; + case 1472: +#line 1777 "char_ref.rl" + {te = p+1;{ output->first = 0x2280; {p++; goto _out; } }} + break; + case 1473: +#line 1778 "char_ref.rl" + {te = p+1;{ output->first = 0x22e0; {p++; goto _out; } }} + break; + case 1474: +#line 1779 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1475: +#line 1780 "char_ref.rl" + {te = p+1;{ output->first = 0x2280; {p++; goto _out; } }} + break; + case 1476: +#line 1781 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1477: +#line 1782 "char_ref.rl" + {te = p+1;{ output->first = 0x21cf; {p++; goto _out; } }} + break; + case 1478: +#line 1783 "char_ref.rl" + {te = p+1;{ output->first = 0x219b; {p++; goto _out; } }} + break; + case 1479: +#line 1784 "char_ref.rl" + {te = p+1;{ output->first = 0x2933; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1480: +#line 1785 "char_ref.rl" + {te = p+1;{ output->first = 0x219d; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1481: +#line 1786 "char_ref.rl" + {te = p+1;{ output->first = 0x219b; {p++; goto _out; } }} + break; + case 1482: +#line 1787 "char_ref.rl" + {te = p+1;{ output->first = 0x22eb; {p++; goto _out; } }} + break; + case 1483: +#line 1788 "char_ref.rl" + {te = p+1;{ output->first = 0x22ed; {p++; goto _out; } }} + break; + case 1484: +#line 1789 "char_ref.rl" + {te = p+1;{ output->first = 0x2281; {p++; goto _out; } }} + break; + case 1485: +#line 1790 "char_ref.rl" + {te = p+1;{ output->first = 0x22e1; {p++; goto _out; } }} + break; + case 1486: +#line 1791 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1487: +#line 1792 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c3; {p++; goto _out; } }} + break; + case 1488: +#line 1793 "char_ref.rl" + {te = p+1;{ output->first = 0x2224; {p++; goto _out; } }} + break; + case 1489: +#line 1794 "char_ref.rl" + {te = p+1;{ output->first = 0x2226; {p++; goto _out; } }} + break; + case 1490: +#line 1795 "char_ref.rl" + {te = p+1;{ output->first = 0x2241; {p++; goto _out; } }} + break; + case 1491: +#line 1796 "char_ref.rl" + {te = p+1;{ output->first = 0x2244; {p++; goto _out; } }} + break; + case 1492: +#line 1797 "char_ref.rl" + {te = p+1;{ output->first = 0x2244; {p++; goto _out; } }} + break; + case 1493: +#line 1798 "char_ref.rl" + {te = p+1;{ output->first = 0x2224; {p++; goto _out; } }} + break; + case 1494: +#line 1799 "char_ref.rl" + {te = p+1;{ output->first = 0x2226; {p++; goto _out; } }} + break; + case 1495: +#line 1800 "char_ref.rl" + {te = p+1;{ output->first = 0x22e2; {p++; goto _out; } }} + break; + case 1496: +#line 1801 "char_ref.rl" + {te = p+1;{ output->first = 0x22e3; {p++; goto _out; } }} + break; + case 1497: +#line 1802 "char_ref.rl" + {te = p+1;{ output->first = 0x2284; {p++; goto _out; } }} + break; + case 1498: +#line 1803 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac5; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1499: +#line 1804 "char_ref.rl" + {te = p+1;{ output->first = 0x2288; {p++; goto _out; } }} + break; + case 1500: +#line 1805 "char_ref.rl" + {te = p+1;{ output->first = 0x2282; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1501: +#line 1806 "char_ref.rl" + {te = p+1;{ output->first = 0x2288; {p++; goto _out; } }} + break; + case 1502: +#line 1807 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac5; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1503: +#line 1808 "char_ref.rl" + {te = p+1;{ output->first = 0x2281; {p++; goto _out; } }} + break; + case 1504: +#line 1809 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1505: +#line 1810 "char_ref.rl" + {te = p+1;{ output->first = 0x2285; {p++; goto _out; } }} + break; + case 1506: +#line 1811 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac6; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1507: +#line 1812 "char_ref.rl" + {te = p+1;{ output->first = 0x2289; {p++; goto _out; } }} + break; + case 1508: +#line 1813 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1509: +#line 1814 "char_ref.rl" + {te = p+1;{ output->first = 0x2289; {p++; goto _out; } }} + break; + case 1510: +#line 1815 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac6; output->second = 0x0338; {p++; goto _out; } }} + break; + case 1511: +#line 1816 "char_ref.rl" + {te = p+1;{ output->first = 0x2279; {p++; goto _out; } }} + break; + case 1512: +#line 1817 "char_ref.rl" + {te = p+1;{ output->first = 0xf1; {p++; goto _out; } }} + break; + case 1513: +#line 1819 "char_ref.rl" + {te = p+1;{ output->first = 0x2278; {p++; goto _out; } }} + break; + case 1514: +#line 1820 "char_ref.rl" + {te = p+1;{ output->first = 0x22ea; {p++; goto _out; } }} + break; + case 1515: +#line 1821 "char_ref.rl" + {te = p+1;{ output->first = 0x22ec; {p++; goto _out; } }} + break; + case 1516: +#line 1822 "char_ref.rl" + {te = p+1;{ output->first = 0x22eb; {p++; goto _out; } }} + break; + case 1517: +#line 1823 "char_ref.rl" + {te = p+1;{ output->first = 0x22ed; {p++; goto _out; } }} + break; + case 1518: +#line 1824 "char_ref.rl" + {te = p+1;{ output->first = 0x03bd; {p++; goto _out; } }} + break; + case 1519: +#line 1825 "char_ref.rl" + {te = p+1;{ output->first = 0x23; {p++; goto _out; } }} + break; + case 1520: +#line 1826 "char_ref.rl" + {te = p+1;{ output->first = 0x2116; {p++; goto _out; } }} + break; + case 1521: +#line 1827 "char_ref.rl" + {te = p+1;{ output->first = 0x2007; {p++; goto _out; } }} + break; + case 1522: +#line 1828 "char_ref.rl" + {te = p+1;{ output->first = 0x22ad; {p++; goto _out; } }} + break; + case 1523: +#line 1829 "char_ref.rl" + {te = p+1;{ output->first = 0x2904; {p++; goto _out; } }} + break; + case 1524: +#line 1830 "char_ref.rl" + {te = p+1;{ output->first = 0x224d; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1525: +#line 1831 "char_ref.rl" + {te = p+1;{ output->first = 0x22ac; {p++; goto _out; } }} + break; + case 1526: +#line 1832 "char_ref.rl" + {te = p+1;{ output->first = 0x2265; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1527: +#line 1833 "char_ref.rl" + {te = p+1;{ output->first = 0x3e; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1528: +#line 1834 "char_ref.rl" + {te = p+1;{ output->first = 0x29de; {p++; goto _out; } }} + break; + case 1529: +#line 1835 "char_ref.rl" + {te = p+1;{ output->first = 0x2902; {p++; goto _out; } }} + break; + case 1530: +#line 1836 "char_ref.rl" + {te = p+1;{ output->first = 0x2264; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1531: +#line 1837 "char_ref.rl" + {te = p+1;{ output->first = 0x3c; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1532: +#line 1838 "char_ref.rl" + {te = p+1;{ output->first = 0x22b4; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1533: +#line 1839 "char_ref.rl" + {te = p+1;{ output->first = 0x2903; {p++; goto _out; } }} + break; + case 1534: +#line 1840 "char_ref.rl" + {te = p+1;{ output->first = 0x22b5; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1535: +#line 1841 "char_ref.rl" + {te = p+1;{ output->first = 0x223c; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 1536: +#line 1842 "char_ref.rl" + {te = p+1;{ output->first = 0x21d6; {p++; goto _out; } }} + break; + case 1537: +#line 1843 "char_ref.rl" + {te = p+1;{ output->first = 0x2923; {p++; goto _out; } }} + break; + case 1538: +#line 1844 "char_ref.rl" + {te = p+1;{ output->first = 0x2196; {p++; goto _out; } }} + break; + case 1539: +#line 1845 "char_ref.rl" + {te = p+1;{ output->first = 0x2196; {p++; goto _out; } }} + break; + case 1540: +#line 1846 "char_ref.rl" + {te = p+1;{ output->first = 0x2927; {p++; goto _out; } }} + break; + case 1541: +#line 1847 "char_ref.rl" + {te = p+1;{ output->first = 0x24c8; {p++; goto _out; } }} + break; + case 1542: +#line 1848 "char_ref.rl" + {te = p+1;{ output->first = 0xf3; {p++; goto _out; } }} + break; + case 1543: +#line 1850 "char_ref.rl" + {te = p+1;{ output->first = 0x229b; {p++; goto _out; } }} + break; + case 1544: +#line 1851 "char_ref.rl" + {te = p+1;{ output->first = 0x229a; {p++; goto _out; } }} + break; + case 1545: +#line 1852 "char_ref.rl" + {te = p+1;{ output->first = 0xf4; {p++; goto _out; } }} + break; + case 1546: +#line 1854 "char_ref.rl" + {te = p+1;{ output->first = 0x043e; {p++; goto _out; } }} + break; + case 1547: +#line 1855 "char_ref.rl" + {te = p+1;{ output->first = 0x229d; {p++; goto _out; } }} + break; + case 1548: +#line 1856 "char_ref.rl" + {te = p+1;{ output->first = 0x0151; {p++; goto _out; } }} + break; + case 1549: +#line 1857 "char_ref.rl" + {te = p+1;{ output->first = 0x2a38; {p++; goto _out; } }} + break; + case 1550: +#line 1858 "char_ref.rl" + {te = p+1;{ output->first = 0x2299; {p++; goto _out; } }} + break; + case 1551: +#line 1859 "char_ref.rl" + {te = p+1;{ output->first = 0x29bc; {p++; goto _out; } }} + break; + case 1552: +#line 1860 "char_ref.rl" + {te = p+1;{ output->first = 0x0153; {p++; goto _out; } }} + break; + case 1553: +#line 1861 "char_ref.rl" + {te = p+1;{ output->first = 0x29bf; {p++; goto _out; } }} + break; + case 1554: +#line 1862 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52c; {p++; goto _out; } }} + break; + case 1555: +#line 1863 "char_ref.rl" + {te = p+1;{ output->first = 0x02db; {p++; goto _out; } }} + break; + case 1556: +#line 1864 "char_ref.rl" + {te = p+1;{ output->first = 0xf2; {p++; goto _out; } }} + break; + case 1557: +#line 1866 "char_ref.rl" + {te = p+1;{ output->first = 0x29c1; {p++; goto _out; } }} + break; + case 1558: +#line 1867 "char_ref.rl" + {te = p+1;{ output->first = 0x29b5; {p++; goto _out; } }} + break; + case 1559: +#line 1868 "char_ref.rl" + {te = p+1;{ output->first = 0x03a9; {p++; goto _out; } }} + break; + case 1560: +#line 1869 "char_ref.rl" + {te = p+1;{ output->first = 0x222e; {p++; goto _out; } }} + break; + case 1561: +#line 1870 "char_ref.rl" + {te = p+1;{ output->first = 0x21ba; {p++; goto _out; } }} + break; + case 1562: +#line 1871 "char_ref.rl" + {te = p+1;{ output->first = 0x29be; {p++; goto _out; } }} + break; + case 1563: +#line 1872 "char_ref.rl" + {te = p+1;{ output->first = 0x29bb; {p++; goto _out; } }} + break; + case 1564: +#line 1873 "char_ref.rl" + {te = p+1;{ output->first = 0x203e; {p++; goto _out; } }} + break; + case 1565: +#line 1874 "char_ref.rl" + {te = p+1;{ output->first = 0x29c0; {p++; goto _out; } }} + break; + case 1566: +#line 1875 "char_ref.rl" + {te = p+1;{ output->first = 0x014d; {p++; goto _out; } }} + break; + case 1567: +#line 1876 "char_ref.rl" + {te = p+1;{ output->first = 0x03c9; {p++; goto _out; } }} + break; + case 1568: +#line 1877 "char_ref.rl" + {te = p+1;{ output->first = 0x03bf; {p++; goto _out; } }} + break; + case 1569: +#line 1878 "char_ref.rl" + {te = p+1;{ output->first = 0x29b6; {p++; goto _out; } }} + break; + case 1570: +#line 1879 "char_ref.rl" + {te = p+1;{ output->first = 0x2296; {p++; goto _out; } }} + break; + case 1571: +#line 1880 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d560; {p++; goto _out; } }} + break; + case 1572: +#line 1881 "char_ref.rl" + {te = p+1;{ output->first = 0x29b7; {p++; goto _out; } }} + break; + case 1573: +#line 1882 "char_ref.rl" + {te = p+1;{ output->first = 0x29b9; {p++; goto _out; } }} + break; + case 1574: +#line 1883 "char_ref.rl" + {te = p+1;{ output->first = 0x2295; {p++; goto _out; } }} + break; + case 1575: +#line 1884 "char_ref.rl" + {te = p+1;{ output->first = 0x2228; {p++; goto _out; } }} + break; + case 1576: +#line 1885 "char_ref.rl" + {te = p+1;{ output->first = 0x21bb; {p++; goto _out; } }} + break; + case 1577: +#line 1886 "char_ref.rl" + {te = p+1;{ output->first = 0x2a5d; {p++; goto _out; } }} + break; + case 1578: +#line 1887 "char_ref.rl" + {te = p+1;{ output->first = 0x2134; {p++; goto _out; } }} + break; + case 1579: +#line 1888 "char_ref.rl" + {te = p+1;{ output->first = 0x2134; {p++; goto _out; } }} + break; + case 1580: +#line 1889 "char_ref.rl" + {te = p+1;{ output->first = 0xaa; {p++; goto _out; } }} + break; + case 1581: +#line 1891 "char_ref.rl" + {te = p+1;{ output->first = 0xba; {p++; goto _out; } }} + break; + case 1582: +#line 1893 "char_ref.rl" + {te = p+1;{ output->first = 0x22b6; {p++; goto _out; } }} + break; + case 1583: +#line 1894 "char_ref.rl" + {te = p+1;{ output->first = 0x2a56; {p++; goto _out; } }} + break; + case 1584: +#line 1895 "char_ref.rl" + {te = p+1;{ output->first = 0x2a57; {p++; goto _out; } }} + break; + case 1585: +#line 1896 "char_ref.rl" + {te = p+1;{ output->first = 0x2a5b; {p++; goto _out; } }} + break; + case 1586: +#line 1897 "char_ref.rl" + {te = p+1;{ output->first = 0x2134; {p++; goto _out; } }} + break; + case 1587: +#line 1898 "char_ref.rl" + {te = p+1;{ output->first = 0xf8; {p++; goto _out; } }} + break; + case 1588: +#line 1900 "char_ref.rl" + {te = p+1;{ output->first = 0x2298; {p++; goto _out; } }} + break; + case 1589: +#line 1901 "char_ref.rl" + {te = p+1;{ output->first = 0xf5; {p++; goto _out; } }} + break; + case 1590: +#line 1903 "char_ref.rl" + {te = p+1;{ output->first = 0x2297; {p++; goto _out; } }} + break; + case 1591: +#line 1904 "char_ref.rl" + {te = p+1;{ output->first = 0x2a36; {p++; goto _out; } }} + break; + case 1592: +#line 1905 "char_ref.rl" + {te = p+1;{ output->first = 0xf6; {p++; goto _out; } }} + break; + case 1593: +#line 1907 "char_ref.rl" + {te = p+1;{ output->first = 0x233d; {p++; goto _out; } }} + break; + case 1594: +#line 1908 "char_ref.rl" + {te = p+1;{ output->first = 0x2225; {p++; goto _out; } }} + break; + case 1595: +#line 1909 "char_ref.rl" + {te = p+1;{ output->first = 0xb6; {p++; goto _out; } }} + break; + case 1596: +#line 1911 "char_ref.rl" + {te = p+1;{ output->first = 0x2225; {p++; goto _out; } }} + break; + case 1597: +#line 1912 "char_ref.rl" + {te = p+1;{ output->first = 0x2af3; {p++; goto _out; } }} + break; + case 1598: +#line 1913 "char_ref.rl" + {te = p+1;{ output->first = 0x2afd; {p++; goto _out; } }} + break; + case 1599: +#line 1914 "char_ref.rl" + {te = p+1;{ output->first = 0x2202; {p++; goto _out; } }} + break; + case 1600: +#line 1915 "char_ref.rl" + {te = p+1;{ output->first = 0x043f; {p++; goto _out; } }} + break; + case 1601: +#line 1916 "char_ref.rl" + {te = p+1;{ output->first = 0x25; {p++; goto _out; } }} + break; + case 1602: +#line 1917 "char_ref.rl" + {te = p+1;{ output->first = 0x2e; {p++; goto _out; } }} + break; + case 1603: +#line 1918 "char_ref.rl" + {te = p+1;{ output->first = 0x2030; {p++; goto _out; } }} + break; + case 1604: +#line 1919 "char_ref.rl" + {te = p+1;{ output->first = 0x22a5; {p++; goto _out; } }} + break; + case 1605: +#line 1920 "char_ref.rl" + {te = p+1;{ output->first = 0x2031; {p++; goto _out; } }} + break; + case 1606: +#line 1921 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52d; {p++; goto _out; } }} + break; + case 1607: +#line 1922 "char_ref.rl" + {te = p+1;{ output->first = 0x03c6; {p++; goto _out; } }} + break; + case 1608: +#line 1923 "char_ref.rl" + {te = p+1;{ output->first = 0x03d5; {p++; goto _out; } }} + break; + case 1609: +#line 1924 "char_ref.rl" + {te = p+1;{ output->first = 0x2133; {p++; goto _out; } }} + break; + case 1610: +#line 1925 "char_ref.rl" + {te = p+1;{ output->first = 0x260e; {p++; goto _out; } }} + break; + case 1611: +#line 1926 "char_ref.rl" + {te = p+1;{ output->first = 0x03c0; {p++; goto _out; } }} + break; + case 1612: +#line 1927 "char_ref.rl" + {te = p+1;{ output->first = 0x22d4; {p++; goto _out; } }} + break; + case 1613: +#line 1928 "char_ref.rl" + {te = p+1;{ output->first = 0x03d6; {p++; goto _out; } }} + break; + case 1614: +#line 1929 "char_ref.rl" + {te = p+1;{ output->first = 0x210f; {p++; goto _out; } }} + break; + case 1615: +#line 1930 "char_ref.rl" + {te = p+1;{ output->first = 0x210e; {p++; goto _out; } }} + break; + case 1616: +#line 1931 "char_ref.rl" + {te = p+1;{ output->first = 0x210f; {p++; goto _out; } }} + break; + case 1617: +#line 1932 "char_ref.rl" + {te = p+1;{ output->first = 0x2b; {p++; goto _out; } }} + break; + case 1618: +#line 1933 "char_ref.rl" + {te = p+1;{ output->first = 0x2a23; {p++; goto _out; } }} + break; + case 1619: +#line 1934 "char_ref.rl" + {te = p+1;{ output->first = 0x229e; {p++; goto _out; } }} + break; + case 1620: +#line 1935 "char_ref.rl" + {te = p+1;{ output->first = 0x2a22; {p++; goto _out; } }} + break; + case 1621: +#line 1936 "char_ref.rl" + {te = p+1;{ output->first = 0x2214; {p++; goto _out; } }} + break; + case 1622: +#line 1937 "char_ref.rl" + {te = p+1;{ output->first = 0x2a25; {p++; goto _out; } }} + break; + case 1623: +#line 1938 "char_ref.rl" + {te = p+1;{ output->first = 0x2a72; {p++; goto _out; } }} + break; + case 1624: +#line 1939 "char_ref.rl" + {te = p+1;{ output->first = 0xb1; {p++; goto _out; } }} + break; + case 1625: +#line 1941 "char_ref.rl" + {te = p+1;{ output->first = 0x2a26; {p++; goto _out; } }} + break; + case 1626: +#line 1942 "char_ref.rl" + {te = p+1;{ output->first = 0x2a27; {p++; goto _out; } }} + break; + case 1627: +#line 1943 "char_ref.rl" + {te = p+1;{ output->first = 0xb1; {p++; goto _out; } }} + break; + case 1628: +#line 1944 "char_ref.rl" + {te = p+1;{ output->first = 0x2a15; {p++; goto _out; } }} + break; + case 1629: +#line 1945 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d561; {p++; goto _out; } }} + break; + case 1630: +#line 1946 "char_ref.rl" + {te = p+1;{ output->first = 0xa3; {p++; goto _out; } }} + break; + case 1631: +#line 1948 "char_ref.rl" + {te = p+1;{ output->first = 0x227a; {p++; goto _out; } }} + break; + case 1632: +#line 1949 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab3; {p++; goto _out; } }} + break; + case 1633: +#line 1950 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab7; {p++; goto _out; } }} + break; + case 1634: +#line 1951 "char_ref.rl" + {te = p+1;{ output->first = 0x227c; {p++; goto _out; } }} + break; + case 1635: +#line 1952 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; {p++; goto _out; } }} + break; + case 1636: +#line 1953 "char_ref.rl" + {te = p+1;{ output->first = 0x227a; {p++; goto _out; } }} + break; + case 1637: +#line 1954 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab7; {p++; goto _out; } }} + break; + case 1638: +#line 1955 "char_ref.rl" + {te = p+1;{ output->first = 0x227c; {p++; goto _out; } }} + break; + case 1639: +#line 1956 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaf; {p++; goto _out; } }} + break; + case 1640: +#line 1957 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab9; {p++; goto _out; } }} + break; + case 1641: +#line 1958 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab5; {p++; goto _out; } }} + break; + case 1642: +#line 1959 "char_ref.rl" + {te = p+1;{ output->first = 0x22e8; {p++; goto _out; } }} + break; + case 1643: +#line 1960 "char_ref.rl" + {te = p+1;{ output->first = 0x227e; {p++; goto _out; } }} + break; + case 1644: +#line 1961 "char_ref.rl" + {te = p+1;{ output->first = 0x2032; {p++; goto _out; } }} + break; + case 1645: +#line 1962 "char_ref.rl" + {te = p+1;{ output->first = 0x2119; {p++; goto _out; } }} + break; + case 1646: +#line 1963 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab5; {p++; goto _out; } }} + break; + case 1647: +#line 1964 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab9; {p++; goto _out; } }} + break; + case 1648: +#line 1965 "char_ref.rl" + {te = p+1;{ output->first = 0x22e8; {p++; goto _out; } }} + break; + case 1649: +#line 1966 "char_ref.rl" + {te = p+1;{ output->first = 0x220f; {p++; goto _out; } }} + break; + case 1650: +#line 1967 "char_ref.rl" + {te = p+1;{ output->first = 0x232e; {p++; goto _out; } }} + break; + case 1651: +#line 1968 "char_ref.rl" + {te = p+1;{ output->first = 0x2312; {p++; goto _out; } }} + break; + case 1652: +#line 1969 "char_ref.rl" + {te = p+1;{ output->first = 0x2313; {p++; goto _out; } }} + break; + case 1653: +#line 1970 "char_ref.rl" + {te = p+1;{ output->first = 0x221d; {p++; goto _out; } }} + break; + case 1654: +#line 1971 "char_ref.rl" + {te = p+1;{ output->first = 0x221d; {p++; goto _out; } }} + break; + case 1655: +#line 1972 "char_ref.rl" + {te = p+1;{ output->first = 0x227e; {p++; goto _out; } }} + break; + case 1656: +#line 1973 "char_ref.rl" + {te = p+1;{ output->first = 0x22b0; {p++; goto _out; } }} + break; + case 1657: +#line 1974 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c5; {p++; goto _out; } }} + break; + case 1658: +#line 1975 "char_ref.rl" + {te = p+1;{ output->first = 0x03c8; {p++; goto _out; } }} + break; + case 1659: +#line 1976 "char_ref.rl" + {te = p+1;{ output->first = 0x2008; {p++; goto _out; } }} + break; + case 1660: +#line 1977 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52e; {p++; goto _out; } }} + break; + case 1661: +#line 1978 "char_ref.rl" + {te = p+1;{ output->first = 0x2a0c; {p++; goto _out; } }} + break; + case 1662: +#line 1979 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d562; {p++; goto _out; } }} + break; + case 1663: +#line 1980 "char_ref.rl" + {te = p+1;{ output->first = 0x2057; {p++; goto _out; } }} + break; + case 1664: +#line 1981 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c6; {p++; goto _out; } }} + break; + case 1665: +#line 1982 "char_ref.rl" + {te = p+1;{ output->first = 0x210d; {p++; goto _out; } }} + break; + case 1666: +#line 1983 "char_ref.rl" + {te = p+1;{ output->first = 0x2a16; {p++; goto _out; } }} + break; + case 1667: +#line 1984 "char_ref.rl" + {te = p+1;{ output->first = 0x3f; {p++; goto _out; } }} + break; + case 1668: +#line 1985 "char_ref.rl" + {te = p+1;{ output->first = 0x225f; {p++; goto _out; } }} + break; + case 1669: +#line 1986 "char_ref.rl" + {te = p+1;{ output->first = 0x22; {p++; goto _out; } }} + break; + case 1670: +#line 1988 "char_ref.rl" + {te = p+1;{ output->first = 0x21db; {p++; goto _out; } }} + break; + case 1671: +#line 1989 "char_ref.rl" + {te = p+1;{ output->first = 0x21d2; {p++; goto _out; } }} + break; + case 1672: +#line 1990 "char_ref.rl" + {te = p+1;{ output->first = 0x291c; {p++; goto _out; } }} + break; + case 1673: +#line 1991 "char_ref.rl" + {te = p+1;{ output->first = 0x290f; {p++; goto _out; } }} + break; + case 1674: +#line 1992 "char_ref.rl" + {te = p+1;{ output->first = 0x2964; {p++; goto _out; } }} + break; + case 1675: +#line 1993 "char_ref.rl" + {te = p+1;{ output->first = 0x223d; output->second = 0x0331; {p++; goto _out; } }} + break; + case 1676: +#line 1994 "char_ref.rl" + {te = p+1;{ output->first = 0x0155; {p++; goto _out; } }} + break; + case 1677: +#line 1995 "char_ref.rl" + {te = p+1;{ output->first = 0x221a; {p++; goto _out; } }} + break; + case 1678: +#line 1996 "char_ref.rl" + {te = p+1;{ output->first = 0x29b3; {p++; goto _out; } }} + break; + case 1679: +#line 1997 "char_ref.rl" + {te = p+1;{ output->first = 0x27e9; {p++; goto _out; } }} + break; + case 1680: +#line 1998 "char_ref.rl" + {te = p+1;{ output->first = 0x2992; {p++; goto _out; } }} + break; + case 1681: +#line 1999 "char_ref.rl" + {te = p+1;{ output->first = 0x29a5; {p++; goto _out; } }} + break; + case 1682: +#line 2000 "char_ref.rl" + {te = p+1;{ output->first = 0x27e9; {p++; goto _out; } }} + break; + case 1683: +#line 2001 "char_ref.rl" + {te = p+1;{ output->first = 0xbb; {p++; goto _out; } }} + break; + case 1684: +#line 2003 "char_ref.rl" + {te = p+1;{ output->first = 0x2192; {p++; goto _out; } }} + break; + case 1685: +#line 2004 "char_ref.rl" + {te = p+1;{ output->first = 0x2975; {p++; goto _out; } }} + break; + case 1686: +#line 2005 "char_ref.rl" + {te = p+1;{ output->first = 0x21e5; {p++; goto _out; } }} + break; + case 1687: +#line 2006 "char_ref.rl" + {te = p+1;{ output->first = 0x2920; {p++; goto _out; } }} + break; + case 1688: +#line 2007 "char_ref.rl" + {te = p+1;{ output->first = 0x2933; {p++; goto _out; } }} + break; + case 1689: +#line 2008 "char_ref.rl" + {te = p+1;{ output->first = 0x291e; {p++; goto _out; } }} + break; + case 1690: +#line 2009 "char_ref.rl" + {te = p+1;{ output->first = 0x21aa; {p++; goto _out; } }} + break; + case 1691: +#line 2010 "char_ref.rl" + {te = p+1;{ output->first = 0x21ac; {p++; goto _out; } }} + break; + case 1692: +#line 2011 "char_ref.rl" + {te = p+1;{ output->first = 0x2945; {p++; goto _out; } }} + break; + case 1693: +#line 2012 "char_ref.rl" + {te = p+1;{ output->first = 0x2974; {p++; goto _out; } }} + break; + case 1694: +#line 2013 "char_ref.rl" + {te = p+1;{ output->first = 0x21a3; {p++; goto _out; } }} + break; + case 1695: +#line 2014 "char_ref.rl" + {te = p+1;{ output->first = 0x219d; {p++; goto _out; } }} + break; + case 1696: +#line 2015 "char_ref.rl" + {te = p+1;{ output->first = 0x291a; {p++; goto _out; } }} + break; + case 1697: +#line 2016 "char_ref.rl" + {te = p+1;{ output->first = 0x2236; {p++; goto _out; } }} + break; + case 1698: +#line 2017 "char_ref.rl" + {te = p+1;{ output->first = 0x211a; {p++; goto _out; } }} + break; + case 1699: +#line 2018 "char_ref.rl" + {te = p+1;{ output->first = 0x290d; {p++; goto _out; } }} + break; + case 1700: +#line 2019 "char_ref.rl" + {te = p+1;{ output->first = 0x2773; {p++; goto _out; } }} + break; + case 1701: +#line 2020 "char_ref.rl" + {te = p+1;{ output->first = 0x7d; {p++; goto _out; } }} + break; + case 1702: +#line 2021 "char_ref.rl" + {te = p+1;{ output->first = 0x5d; {p++; goto _out; } }} + break; + case 1703: +#line 2022 "char_ref.rl" + {te = p+1;{ output->first = 0x298c; {p++; goto _out; } }} + break; + case 1704: +#line 2023 "char_ref.rl" + {te = p+1;{ output->first = 0x298e; {p++; goto _out; } }} + break; + case 1705: +#line 2024 "char_ref.rl" + {te = p+1;{ output->first = 0x2990; {p++; goto _out; } }} + break; + case 1706: +#line 2025 "char_ref.rl" + {te = p+1;{ output->first = 0x0159; {p++; goto _out; } }} + break; + case 1707: +#line 2026 "char_ref.rl" + {te = p+1;{ output->first = 0x0157; {p++; goto _out; } }} + break; + case 1708: +#line 2027 "char_ref.rl" + {te = p+1;{ output->first = 0x2309; {p++; goto _out; } }} + break; + case 1709: +#line 2028 "char_ref.rl" + {te = p+1;{ output->first = 0x7d; {p++; goto _out; } }} + break; + case 1710: +#line 2029 "char_ref.rl" + {te = p+1;{ output->first = 0x0440; {p++; goto _out; } }} + break; + case 1711: +#line 2030 "char_ref.rl" + {te = p+1;{ output->first = 0x2937; {p++; goto _out; } }} + break; + case 1712: +#line 2031 "char_ref.rl" + {te = p+1;{ output->first = 0x2969; {p++; goto _out; } }} + break; + case 1713: +#line 2032 "char_ref.rl" + {te = p+1;{ output->first = 0x201d; {p++; goto _out; } }} + break; + case 1714: +#line 2033 "char_ref.rl" + {te = p+1;{ output->first = 0x201d; {p++; goto _out; } }} + break; + case 1715: +#line 2034 "char_ref.rl" + {te = p+1;{ output->first = 0x21b3; {p++; goto _out; } }} + break; + case 1716: +#line 2035 "char_ref.rl" + {te = p+1;{ output->first = 0x211c; {p++; goto _out; } }} + break; + case 1717: +#line 2036 "char_ref.rl" + {te = p+1;{ output->first = 0x211b; {p++; goto _out; } }} + break; + case 1718: +#line 2037 "char_ref.rl" + {te = p+1;{ output->first = 0x211c; {p++; goto _out; } }} + break; + case 1719: +#line 2038 "char_ref.rl" + {te = p+1;{ output->first = 0x211d; {p++; goto _out; } }} + break; + case 1720: +#line 2039 "char_ref.rl" + {te = p+1;{ output->first = 0x25ad; {p++; goto _out; } }} + break; + case 1721: +#line 2040 "char_ref.rl" + {te = p+1;{ output->first = 0xae; {p++; goto _out; } }} + break; + case 1722: +#line 2042 "char_ref.rl" + {te = p+1;{ output->first = 0x297d; {p++; goto _out; } }} + break; + case 1723: +#line 2043 "char_ref.rl" + {te = p+1;{ output->first = 0x230b; {p++; goto _out; } }} + break; + case 1724: +#line 2044 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d52f; {p++; goto _out; } }} + break; + case 1725: +#line 2045 "char_ref.rl" + {te = p+1;{ output->first = 0x21c1; {p++; goto _out; } }} + break; + case 1726: +#line 2046 "char_ref.rl" + {te = p+1;{ output->first = 0x21c0; {p++; goto _out; } }} + break; + case 1727: +#line 2047 "char_ref.rl" + {te = p+1;{ output->first = 0x296c; {p++; goto _out; } }} + break; + case 1728: +#line 2048 "char_ref.rl" + {te = p+1;{ output->first = 0x03c1; {p++; goto _out; } }} + break; + case 1729: +#line 2049 "char_ref.rl" + {te = p+1;{ output->first = 0x03f1; {p++; goto _out; } }} + break; + case 1730: +#line 2050 "char_ref.rl" + {te = p+1;{ output->first = 0x2192; {p++; goto _out; } }} + break; + case 1731: +#line 2051 "char_ref.rl" + {te = p+1;{ output->first = 0x21a3; {p++; goto _out; } }} + break; + case 1732: +#line 2052 "char_ref.rl" + {te = p+1;{ output->first = 0x21c1; {p++; goto _out; } }} + break; + case 1733: +#line 2053 "char_ref.rl" + {te = p+1;{ output->first = 0x21c0; {p++; goto _out; } }} + break; + case 1734: +#line 2054 "char_ref.rl" + {te = p+1;{ output->first = 0x21c4; {p++; goto _out; } }} + break; + case 1735: +#line 2055 "char_ref.rl" + {te = p+1;{ output->first = 0x21cc; {p++; goto _out; } }} + break; + case 1736: +#line 2056 "char_ref.rl" + {te = p+1;{ output->first = 0x21c9; {p++; goto _out; } }} + break; + case 1737: +#line 2057 "char_ref.rl" + {te = p+1;{ output->first = 0x219d; {p++; goto _out; } }} + break; + case 1738: +#line 2058 "char_ref.rl" + {te = p+1;{ output->first = 0x22cc; {p++; goto _out; } }} + break; + case 1739: +#line 2059 "char_ref.rl" + {te = p+1;{ output->first = 0x02da; {p++; goto _out; } }} + break; + case 1740: +#line 2060 "char_ref.rl" + {te = p+1;{ output->first = 0x2253; {p++; goto _out; } }} + break; + case 1741: +#line 2061 "char_ref.rl" + {te = p+1;{ output->first = 0x21c4; {p++; goto _out; } }} + break; + case 1742: +#line 2062 "char_ref.rl" + {te = p+1;{ output->first = 0x21cc; {p++; goto _out; } }} + break; + case 1743: +#line 2063 "char_ref.rl" + {te = p+1;{ output->first = 0x200f; {p++; goto _out; } }} + break; + case 1744: +#line 2064 "char_ref.rl" + {te = p+1;{ output->first = 0x23b1; {p++; goto _out; } }} + break; + case 1745: +#line 2065 "char_ref.rl" + {te = p+1;{ output->first = 0x23b1; {p++; goto _out; } }} + break; + case 1746: +#line 2066 "char_ref.rl" + {te = p+1;{ output->first = 0x2aee; {p++; goto _out; } }} + break; + case 1747: +#line 2067 "char_ref.rl" + {te = p+1;{ output->first = 0x27ed; {p++; goto _out; } }} + break; + case 1748: +#line 2068 "char_ref.rl" + {te = p+1;{ output->first = 0x21fe; {p++; goto _out; } }} + break; + case 1749: +#line 2069 "char_ref.rl" + {te = p+1;{ output->first = 0x27e7; {p++; goto _out; } }} + break; + case 1750: +#line 2070 "char_ref.rl" + {te = p+1;{ output->first = 0x2986; {p++; goto _out; } }} + break; + case 1751: +#line 2071 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d563; {p++; goto _out; } }} + break; + case 1752: +#line 2072 "char_ref.rl" + {te = p+1;{ output->first = 0x2a2e; {p++; goto _out; } }} + break; + case 1753: +#line 2073 "char_ref.rl" + {te = p+1;{ output->first = 0x2a35; {p++; goto _out; } }} + break; + case 1754: +#line 2074 "char_ref.rl" + {te = p+1;{ output->first = 0x29; {p++; goto _out; } }} + break; + case 1755: +#line 2075 "char_ref.rl" + {te = p+1;{ output->first = 0x2994; {p++; goto _out; } }} + break; + case 1756: +#line 2076 "char_ref.rl" + {te = p+1;{ output->first = 0x2a12; {p++; goto _out; } }} + break; + case 1757: +#line 2077 "char_ref.rl" + {te = p+1;{ output->first = 0x21c9; {p++; goto _out; } }} + break; + case 1758: +#line 2078 "char_ref.rl" + {te = p+1;{ output->first = 0x203a; {p++; goto _out; } }} + break; + case 1759: +#line 2079 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c7; {p++; goto _out; } }} + break; + case 1760: +#line 2080 "char_ref.rl" + {te = p+1;{ output->first = 0x21b1; {p++; goto _out; } }} + break; + case 1761: +#line 2081 "char_ref.rl" + {te = p+1;{ output->first = 0x5d; {p++; goto _out; } }} + break; + case 1762: +#line 2082 "char_ref.rl" + {te = p+1;{ output->first = 0x2019; {p++; goto _out; } }} + break; + case 1763: +#line 2083 "char_ref.rl" + {te = p+1;{ output->first = 0x2019; {p++; goto _out; } }} + break; + case 1764: +#line 2084 "char_ref.rl" + {te = p+1;{ output->first = 0x22cc; {p++; goto _out; } }} + break; + case 1765: +#line 2085 "char_ref.rl" + {te = p+1;{ output->first = 0x22ca; {p++; goto _out; } }} + break; + case 1766: +#line 2086 "char_ref.rl" + {te = p+1;{ output->first = 0x25b9; {p++; goto _out; } }} + break; + case 1767: +#line 2087 "char_ref.rl" + {te = p+1;{ output->first = 0x22b5; {p++; goto _out; } }} + break; + case 1768: +#line 2088 "char_ref.rl" + {te = p+1;{ output->first = 0x25b8; {p++; goto _out; } }} + break; + case 1769: +#line 2089 "char_ref.rl" + {te = p+1;{ output->first = 0x29ce; {p++; goto _out; } }} + break; + case 1770: +#line 2090 "char_ref.rl" + {te = p+1;{ output->first = 0x2968; {p++; goto _out; } }} + break; + case 1771: +#line 2091 "char_ref.rl" + {te = p+1;{ output->first = 0x211e; {p++; goto _out; } }} + break; + case 1772: +#line 2092 "char_ref.rl" + {te = p+1;{ output->first = 0x015b; {p++; goto _out; } }} + break; + case 1773: +#line 2093 "char_ref.rl" + {te = p+1;{ output->first = 0x201a; {p++; goto _out; } }} + break; + case 1774: +#line 2094 "char_ref.rl" + {te = p+1;{ output->first = 0x227b; {p++; goto _out; } }} + break; + case 1775: +#line 2095 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab4; {p++; goto _out; } }} + break; + case 1776: +#line 2096 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab8; {p++; goto _out; } }} + break; + case 1777: +#line 2097 "char_ref.rl" + {te = p+1;{ output->first = 0x0161; {p++; goto _out; } }} + break; + case 1778: +#line 2098 "char_ref.rl" + {te = p+1;{ output->first = 0x227d; {p++; goto _out; } }} + break; + case 1779: +#line 2099 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; {p++; goto _out; } }} + break; + case 1780: +#line 2100 "char_ref.rl" + {te = p+1;{ output->first = 0x015f; {p++; goto _out; } }} + break; + case 1781: +#line 2101 "char_ref.rl" + {te = p+1;{ output->first = 0x015d; {p++; goto _out; } }} + break; + case 1782: +#line 2102 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab6; {p++; goto _out; } }} + break; + case 1783: +#line 2103 "char_ref.rl" + {te = p+1;{ output->first = 0x2aba; {p++; goto _out; } }} + break; + case 1784: +#line 2104 "char_ref.rl" + {te = p+1;{ output->first = 0x22e9; {p++; goto _out; } }} + break; + case 1785: +#line 2105 "char_ref.rl" + {te = p+1;{ output->first = 0x2a13; {p++; goto _out; } }} + break; + case 1786: +#line 2106 "char_ref.rl" + {te = p+1;{ output->first = 0x227f; {p++; goto _out; } }} + break; + case 1787: +#line 2107 "char_ref.rl" + {te = p+1;{ output->first = 0x0441; {p++; goto _out; } }} + break; + case 1788: +#line 2108 "char_ref.rl" + {te = p+1;{ output->first = 0x22c5; {p++; goto _out; } }} + break; + case 1789: +#line 2109 "char_ref.rl" + {te = p+1;{ output->first = 0x22a1; {p++; goto _out; } }} + break; + case 1790: +#line 2110 "char_ref.rl" + {te = p+1;{ output->first = 0x2a66; {p++; goto _out; } }} + break; + case 1791: +#line 2111 "char_ref.rl" + {te = p+1;{ output->first = 0x21d8; {p++; goto _out; } }} + break; + case 1792: +#line 2112 "char_ref.rl" + {te = p+1;{ output->first = 0x2925; {p++; goto _out; } }} + break; + case 1793: +#line 2113 "char_ref.rl" + {te = p+1;{ output->first = 0x2198; {p++; goto _out; } }} + break; + case 1794: +#line 2114 "char_ref.rl" + {te = p+1;{ output->first = 0x2198; {p++; goto _out; } }} + break; + case 1795: +#line 2115 "char_ref.rl" + {te = p+1;{ output->first = 0xa7; {p++; goto _out; } }} + break; + case 1796: +#line 2117 "char_ref.rl" + {te = p+1;{ output->first = 0x3b; {p++; goto _out; } }} + break; + case 1797: +#line 2118 "char_ref.rl" + {te = p+1;{ output->first = 0x2929; {p++; goto _out; } }} + break; + case 1798: +#line 2119 "char_ref.rl" + {te = p+1;{ output->first = 0x2216; {p++; goto _out; } }} + break; + case 1799: +#line 2120 "char_ref.rl" + {te = p+1;{ output->first = 0x2216; {p++; goto _out; } }} + break; + case 1800: +#line 2121 "char_ref.rl" + {te = p+1;{ output->first = 0x2736; {p++; goto _out; } }} + break; + case 1801: +#line 2122 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d530; {p++; goto _out; } }} + break; + case 1802: +#line 2123 "char_ref.rl" + {te = p+1;{ output->first = 0x2322; {p++; goto _out; } }} + break; + case 1803: +#line 2124 "char_ref.rl" + {te = p+1;{ output->first = 0x266f; {p++; goto _out; } }} + break; + case 1804: +#line 2125 "char_ref.rl" + {te = p+1;{ output->first = 0x0449; {p++; goto _out; } }} + break; + case 1805: +#line 2126 "char_ref.rl" + {te = p+1;{ output->first = 0x0448; {p++; goto _out; } }} + break; + case 1806: +#line 2127 "char_ref.rl" + {te = p+1;{ output->first = 0x2223; {p++; goto _out; } }} + break; + case 1807: +#line 2128 "char_ref.rl" + {te = p+1;{ output->first = 0x2225; {p++; goto _out; } }} + break; + case 1808: +#line 2129 "char_ref.rl" + {te = p+1;{ output->first = 0xad; {p++; goto _out; } }} + break; + case 1809: +#line 2131 "char_ref.rl" + {te = p+1;{ output->first = 0x03c3; {p++; goto _out; } }} + break; + case 1810: +#line 2132 "char_ref.rl" + {te = p+1;{ output->first = 0x03c2; {p++; goto _out; } }} + break; + case 1811: +#line 2133 "char_ref.rl" + {te = p+1;{ output->first = 0x03c2; {p++; goto _out; } }} + break; + case 1812: +#line 2134 "char_ref.rl" + {te = p+1;{ output->first = 0x223c; {p++; goto _out; } }} + break; + case 1813: +#line 2135 "char_ref.rl" + {te = p+1;{ output->first = 0x2a6a; {p++; goto _out; } }} + break; + case 1814: +#line 2136 "char_ref.rl" + {te = p+1;{ output->first = 0x2243; {p++; goto _out; } }} + break; + case 1815: +#line 2137 "char_ref.rl" + {te = p+1;{ output->first = 0x2243; {p++; goto _out; } }} + break; + case 1816: +#line 2138 "char_ref.rl" + {te = p+1;{ output->first = 0x2a9e; {p++; goto _out; } }} + break; + case 1817: +#line 2139 "char_ref.rl" + {te = p+1;{ output->first = 0x2aa0; {p++; goto _out; } }} + break; + case 1818: +#line 2140 "char_ref.rl" + {te = p+1;{ output->first = 0x2a9d; {p++; goto _out; } }} + break; + case 1819: +#line 2141 "char_ref.rl" + {te = p+1;{ output->first = 0x2a9f; {p++; goto _out; } }} + break; + case 1820: +#line 2142 "char_ref.rl" + {te = p+1;{ output->first = 0x2246; {p++; goto _out; } }} + break; + case 1821: +#line 2143 "char_ref.rl" + {te = p+1;{ output->first = 0x2a24; {p++; goto _out; } }} + break; + case 1822: +#line 2144 "char_ref.rl" + {te = p+1;{ output->first = 0x2972; {p++; goto _out; } }} + break; + case 1823: +#line 2145 "char_ref.rl" + {te = p+1;{ output->first = 0x2190; {p++; goto _out; } }} + break; + case 1824: +#line 2146 "char_ref.rl" + {te = p+1;{ output->first = 0x2216; {p++; goto _out; } }} + break; + case 1825: +#line 2147 "char_ref.rl" + {te = p+1;{ output->first = 0x2a33; {p++; goto _out; } }} + break; + case 1826: +#line 2148 "char_ref.rl" + {te = p+1;{ output->first = 0x29e4; {p++; goto _out; } }} + break; + case 1827: +#line 2149 "char_ref.rl" + {te = p+1;{ output->first = 0x2223; {p++; goto _out; } }} + break; + case 1828: +#line 2150 "char_ref.rl" + {te = p+1;{ output->first = 0x2323; {p++; goto _out; } }} + break; + case 1829: +#line 2151 "char_ref.rl" + {te = p+1;{ output->first = 0x2aaa; {p++; goto _out; } }} + break; + case 1830: +#line 2152 "char_ref.rl" + {te = p+1;{ output->first = 0x2aac; {p++; goto _out; } }} + break; + case 1831: +#line 2153 "char_ref.rl" + {te = p+1;{ output->first = 0x2aac; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1832: +#line 2154 "char_ref.rl" + {te = p+1;{ output->first = 0x044c; {p++; goto _out; } }} + break; + case 1833: +#line 2155 "char_ref.rl" + {te = p+1;{ output->first = 0x2f; {p++; goto _out; } }} + break; + case 1834: +#line 2156 "char_ref.rl" + {te = p+1;{ output->first = 0x29c4; {p++; goto _out; } }} + break; + case 1835: +#line 2157 "char_ref.rl" + {te = p+1;{ output->first = 0x233f; {p++; goto _out; } }} + break; + case 1836: +#line 2158 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d564; {p++; goto _out; } }} + break; + case 1837: +#line 2159 "char_ref.rl" + {te = p+1;{ output->first = 0x2660; {p++; goto _out; } }} + break; + case 1838: +#line 2160 "char_ref.rl" + {te = p+1;{ output->first = 0x2660; {p++; goto _out; } }} + break; + case 1839: +#line 2161 "char_ref.rl" + {te = p+1;{ output->first = 0x2225; {p++; goto _out; } }} + break; + case 1840: +#line 2162 "char_ref.rl" + {te = p+1;{ output->first = 0x2293; {p++; goto _out; } }} + break; + case 1841: +#line 2163 "char_ref.rl" + {te = p+1;{ output->first = 0x2293; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1842: +#line 2164 "char_ref.rl" + {te = p+1;{ output->first = 0x2294; {p++; goto _out; } }} + break; + case 1843: +#line 2165 "char_ref.rl" + {te = p+1;{ output->first = 0x2294; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 1844: +#line 2166 "char_ref.rl" + {te = p+1;{ output->first = 0x228f; {p++; goto _out; } }} + break; + case 1845: +#line 2167 "char_ref.rl" + {te = p+1;{ output->first = 0x2291; {p++; goto _out; } }} + break; + case 1846: +#line 2168 "char_ref.rl" + {te = p+1;{ output->first = 0x228f; {p++; goto _out; } }} + break; + case 1847: +#line 2169 "char_ref.rl" + {te = p+1;{ output->first = 0x2291; {p++; goto _out; } }} + break; + case 1848: +#line 2170 "char_ref.rl" + {te = p+1;{ output->first = 0x2290; {p++; goto _out; } }} + break; + case 1849: +#line 2171 "char_ref.rl" + {te = p+1;{ output->first = 0x2292; {p++; goto _out; } }} + break; + case 1850: +#line 2172 "char_ref.rl" + {te = p+1;{ output->first = 0x2290; {p++; goto _out; } }} + break; + case 1851: +#line 2173 "char_ref.rl" + {te = p+1;{ output->first = 0x2292; {p++; goto _out; } }} + break; + case 1852: +#line 2174 "char_ref.rl" + {te = p+1;{ output->first = 0x25a1; {p++; goto _out; } }} + break; + case 1853: +#line 2175 "char_ref.rl" + {te = p+1;{ output->first = 0x25a1; {p++; goto _out; } }} + break; + case 1854: +#line 2176 "char_ref.rl" + {te = p+1;{ output->first = 0x25aa; {p++; goto _out; } }} + break; + case 1855: +#line 2177 "char_ref.rl" + {te = p+1;{ output->first = 0x25aa; {p++; goto _out; } }} + break; + case 1856: +#line 2178 "char_ref.rl" + {te = p+1;{ output->first = 0x2192; {p++; goto _out; } }} + break; + case 1857: +#line 2179 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c8; {p++; goto _out; } }} + break; + case 1858: +#line 2180 "char_ref.rl" + {te = p+1;{ output->first = 0x2216; {p++; goto _out; } }} + break; + case 1859: +#line 2181 "char_ref.rl" + {te = p+1;{ output->first = 0x2323; {p++; goto _out; } }} + break; + case 1860: +#line 2182 "char_ref.rl" + {te = p+1;{ output->first = 0x22c6; {p++; goto _out; } }} + break; + case 1861: +#line 2183 "char_ref.rl" + {te = p+1;{ output->first = 0x2606; {p++; goto _out; } }} + break; + case 1862: +#line 2184 "char_ref.rl" + {te = p+1;{ output->first = 0x2605; {p++; goto _out; } }} + break; + case 1863: +#line 2185 "char_ref.rl" + {te = p+1;{ output->first = 0x03f5; {p++; goto _out; } }} + break; + case 1864: +#line 2186 "char_ref.rl" + {te = p+1;{ output->first = 0x03d5; {p++; goto _out; } }} + break; + case 1865: +#line 2187 "char_ref.rl" + {te = p+1;{ output->first = 0xaf; {p++; goto _out; } }} + break; + case 1866: +#line 2188 "char_ref.rl" + {te = p+1;{ output->first = 0x2282; {p++; goto _out; } }} + break; + case 1867: +#line 2189 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac5; {p++; goto _out; } }} + break; + case 1868: +#line 2190 "char_ref.rl" + {te = p+1;{ output->first = 0x2abd; {p++; goto _out; } }} + break; + case 1869: +#line 2191 "char_ref.rl" + {te = p+1;{ output->first = 0x2286; {p++; goto _out; } }} + break; + case 1870: +#line 2192 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac3; {p++; goto _out; } }} + break; + case 1871: +#line 2193 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac1; {p++; goto _out; } }} + break; + case 1872: +#line 2194 "char_ref.rl" + {te = p+1;{ output->first = 0x2acb; {p++; goto _out; } }} + break; + case 1873: +#line 2195 "char_ref.rl" + {te = p+1;{ output->first = 0x228a; {p++; goto _out; } }} + break; + case 1874: +#line 2196 "char_ref.rl" + {te = p+1;{ output->first = 0x2abf; {p++; goto _out; } }} + break; + case 1875: +#line 2197 "char_ref.rl" + {te = p+1;{ output->first = 0x2979; {p++; goto _out; } }} + break; + case 1876: +#line 2198 "char_ref.rl" + {te = p+1;{ output->first = 0x2282; {p++; goto _out; } }} + break; + case 1877: +#line 2199 "char_ref.rl" + {te = p+1;{ output->first = 0x2286; {p++; goto _out; } }} + break; + case 1878: +#line 2200 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac5; {p++; goto _out; } }} + break; + case 1879: +#line 2201 "char_ref.rl" + {te = p+1;{ output->first = 0x228a; {p++; goto _out; } }} + break; + case 1880: +#line 2202 "char_ref.rl" + {te = p+1;{ output->first = 0x2acb; {p++; goto _out; } }} + break; + case 1881: +#line 2203 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac7; {p++; goto _out; } }} + break; + case 1882: +#line 2204 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad5; {p++; goto _out; } }} + break; + case 1883: +#line 2205 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad3; {p++; goto _out; } }} + break; + case 1884: +#line 2206 "char_ref.rl" + {te = p+1;{ output->first = 0x227b; {p++; goto _out; } }} + break; + case 1885: +#line 2207 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab8; {p++; goto _out; } }} + break; + case 1886: +#line 2208 "char_ref.rl" + {te = p+1;{ output->first = 0x227d; {p++; goto _out; } }} + break; + case 1887: +#line 2209 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab0; {p++; goto _out; } }} + break; + case 1888: +#line 2210 "char_ref.rl" + {te = p+1;{ output->first = 0x2aba; {p++; goto _out; } }} + break; + case 1889: +#line 2211 "char_ref.rl" + {te = p+1;{ output->first = 0x2ab6; {p++; goto _out; } }} + break; + case 1890: +#line 2212 "char_ref.rl" + {te = p+1;{ output->first = 0x22e9; {p++; goto _out; } }} + break; + case 1891: +#line 2213 "char_ref.rl" + {te = p+1;{ output->first = 0x227f; {p++; goto _out; } }} + break; + case 1892: +#line 2214 "char_ref.rl" + {te = p+1;{ output->first = 0x2211; {p++; goto _out; } }} + break; + case 1893: +#line 2215 "char_ref.rl" + {te = p+1;{ output->first = 0x266a; {p++; goto _out; } }} + break; + case 1894: +#line 2216 "char_ref.rl" + {te = p+1;{ output->first = 0xb9; {p++; goto _out; } }} + break; + case 1895: +#line 2218 "char_ref.rl" + {te = p+1;{ output->first = 0xb2; {p++; goto _out; } }} + break; + case 1896: +#line 2220 "char_ref.rl" + {te = p+1;{ output->first = 0xb3; {p++; goto _out; } }} + break; + case 1897: +#line 2222 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; {p++; goto _out; } }} + break; + case 1898: +#line 2223 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac6; {p++; goto _out; } }} + break; + case 1899: +#line 2224 "char_ref.rl" + {te = p+1;{ output->first = 0x2abe; {p++; goto _out; } }} + break; + case 1900: +#line 2225 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad8; {p++; goto _out; } }} + break; + case 1901: +#line 2226 "char_ref.rl" + {te = p+1;{ output->first = 0x2287; {p++; goto _out; } }} + break; + case 1902: +#line 2227 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac4; {p++; goto _out; } }} + break; + case 1903: +#line 2228 "char_ref.rl" + {te = p+1;{ output->first = 0x27c9; {p++; goto _out; } }} + break; + case 1904: +#line 2229 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad7; {p++; goto _out; } }} + break; + case 1905: +#line 2230 "char_ref.rl" + {te = p+1;{ output->first = 0x297b; {p++; goto _out; } }} + break; + case 1906: +#line 2231 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac2; {p++; goto _out; } }} + break; + case 1907: +#line 2232 "char_ref.rl" + {te = p+1;{ output->first = 0x2acc; {p++; goto _out; } }} + break; + case 1908: +#line 2233 "char_ref.rl" + {te = p+1;{ output->first = 0x228b; {p++; goto _out; } }} + break; + case 1909: +#line 2234 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac0; {p++; goto _out; } }} + break; + case 1910: +#line 2235 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; {p++; goto _out; } }} + break; + case 1911: +#line 2236 "char_ref.rl" + {te = p+1;{ output->first = 0x2287; {p++; goto _out; } }} + break; + case 1912: +#line 2237 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac6; {p++; goto _out; } }} + break; + case 1913: +#line 2238 "char_ref.rl" + {te = p+1;{ output->first = 0x228b; {p++; goto _out; } }} + break; + case 1914: +#line 2239 "char_ref.rl" + {te = p+1;{ output->first = 0x2acc; {p++; goto _out; } }} + break; + case 1915: +#line 2240 "char_ref.rl" + {te = p+1;{ output->first = 0x2ac8; {p++; goto _out; } }} + break; + case 1916: +#line 2241 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad4; {p++; goto _out; } }} + break; + case 1917: +#line 2242 "char_ref.rl" + {te = p+1;{ output->first = 0x2ad6; {p++; goto _out; } }} + break; + case 1918: +#line 2243 "char_ref.rl" + {te = p+1;{ output->first = 0x21d9; {p++; goto _out; } }} + break; + case 1919: +#line 2244 "char_ref.rl" + {te = p+1;{ output->first = 0x2926; {p++; goto _out; } }} + break; + case 1920: +#line 2245 "char_ref.rl" + {te = p+1;{ output->first = 0x2199; {p++; goto _out; } }} + break; + case 1921: +#line 2246 "char_ref.rl" + {te = p+1;{ output->first = 0x2199; {p++; goto _out; } }} + break; + case 1922: +#line 2247 "char_ref.rl" + {te = p+1;{ output->first = 0x292a; {p++; goto _out; } }} + break; + case 1923: +#line 2248 "char_ref.rl" + {te = p+1;{ output->first = 0xdf; {p++; goto _out; } }} + break; + case 1924: +#line 2250 "char_ref.rl" + {te = p+1;{ output->first = 0x2316; {p++; goto _out; } }} + break; + case 1925: +#line 2251 "char_ref.rl" + {te = p+1;{ output->first = 0x03c4; {p++; goto _out; } }} + break; + case 1926: +#line 2252 "char_ref.rl" + {te = p+1;{ output->first = 0x23b4; {p++; goto _out; } }} + break; + case 1927: +#line 2253 "char_ref.rl" + {te = p+1;{ output->first = 0x0165; {p++; goto _out; } }} + break; + case 1928: +#line 2254 "char_ref.rl" + {te = p+1;{ output->first = 0x0163; {p++; goto _out; } }} + break; + case 1929: +#line 2255 "char_ref.rl" + {te = p+1;{ output->first = 0x0442; {p++; goto _out; } }} + break; + case 1930: +#line 2256 "char_ref.rl" + {te = p+1;{ output->first = 0x20db; {p++; goto _out; } }} + break; + case 1931: +#line 2257 "char_ref.rl" + {te = p+1;{ output->first = 0x2315; {p++; goto _out; } }} + break; + case 1932: +#line 2258 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d531; {p++; goto _out; } }} + break; + case 1933: +#line 2259 "char_ref.rl" + {te = p+1;{ output->first = 0x2234; {p++; goto _out; } }} + break; + case 1934: +#line 2260 "char_ref.rl" + {te = p+1;{ output->first = 0x2234; {p++; goto _out; } }} + break; + case 1935: +#line 2261 "char_ref.rl" + {te = p+1;{ output->first = 0x03b8; {p++; goto _out; } }} + break; + case 1936: +#line 2262 "char_ref.rl" + {te = p+1;{ output->first = 0x03d1; {p++; goto _out; } }} + break; + case 1937: +#line 2263 "char_ref.rl" + {te = p+1;{ output->first = 0x03d1; {p++; goto _out; } }} + break; + case 1938: +#line 2264 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 1939: +#line 2265 "char_ref.rl" + {te = p+1;{ output->first = 0x223c; {p++; goto _out; } }} + break; + case 1940: +#line 2266 "char_ref.rl" + {te = p+1;{ output->first = 0x2009; {p++; goto _out; } }} + break; + case 1941: +#line 2267 "char_ref.rl" + {te = p+1;{ output->first = 0x2248; {p++; goto _out; } }} + break; + case 1942: +#line 2268 "char_ref.rl" + {te = p+1;{ output->first = 0x223c; {p++; goto _out; } }} + break; + case 1943: +#line 2269 "char_ref.rl" + {te = p+1;{ output->first = 0xfe; {p++; goto _out; } }} + break; + case 1944: +#line 2271 "char_ref.rl" + {te = p+1;{ output->first = 0x02dc; {p++; goto _out; } }} + break; + case 1945: +#line 2272 "char_ref.rl" + {te = p+1;{ output->first = 0xd7; {p++; goto _out; } }} + break; + case 1946: +#line 2274 "char_ref.rl" + {te = p+1;{ output->first = 0x22a0; {p++; goto _out; } }} + break; + case 1947: +#line 2275 "char_ref.rl" + {te = p+1;{ output->first = 0x2a31; {p++; goto _out; } }} + break; + case 1948: +#line 2276 "char_ref.rl" + {te = p+1;{ output->first = 0x2a30; {p++; goto _out; } }} + break; + case 1949: +#line 2277 "char_ref.rl" + {te = p+1;{ output->first = 0x222d; {p++; goto _out; } }} + break; + case 1950: +#line 2278 "char_ref.rl" + {te = p+1;{ output->first = 0x2928; {p++; goto _out; } }} + break; + case 1951: +#line 2279 "char_ref.rl" + {te = p+1;{ output->first = 0x22a4; {p++; goto _out; } }} + break; + case 1952: +#line 2280 "char_ref.rl" + {te = p+1;{ output->first = 0x2336; {p++; goto _out; } }} + break; + case 1953: +#line 2281 "char_ref.rl" + {te = p+1;{ output->first = 0x2af1; {p++; goto _out; } }} + break; + case 1954: +#line 2282 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d565; {p++; goto _out; } }} + break; + case 1955: +#line 2283 "char_ref.rl" + {te = p+1;{ output->first = 0x2ada; {p++; goto _out; } }} + break; + case 1956: +#line 2284 "char_ref.rl" + {te = p+1;{ output->first = 0x2929; {p++; goto _out; } }} + break; + case 1957: +#line 2285 "char_ref.rl" + {te = p+1;{ output->first = 0x2034; {p++; goto _out; } }} + break; + case 1958: +#line 2286 "char_ref.rl" + {te = p+1;{ output->first = 0x2122; {p++; goto _out; } }} + break; + case 1959: +#line 2287 "char_ref.rl" + {te = p+1;{ output->first = 0x25b5; {p++; goto _out; } }} + break; + case 1960: +#line 2288 "char_ref.rl" + {te = p+1;{ output->first = 0x25bf; {p++; goto _out; } }} + break; + case 1961: +#line 2289 "char_ref.rl" + {te = p+1;{ output->first = 0x25c3; {p++; goto _out; } }} + break; + case 1962: +#line 2290 "char_ref.rl" + {te = p+1;{ output->first = 0x22b4; {p++; goto _out; } }} + break; + case 1963: +#line 2291 "char_ref.rl" + {te = p+1;{ output->first = 0x225c; {p++; goto _out; } }} + break; + case 1964: +#line 2292 "char_ref.rl" + {te = p+1;{ output->first = 0x25b9; {p++; goto _out; } }} + break; + case 1965: +#line 2293 "char_ref.rl" + {te = p+1;{ output->first = 0x22b5; {p++; goto _out; } }} + break; + case 1966: +#line 2294 "char_ref.rl" + {te = p+1;{ output->first = 0x25ec; {p++; goto _out; } }} + break; + case 1967: +#line 2295 "char_ref.rl" + {te = p+1;{ output->first = 0x225c; {p++; goto _out; } }} + break; + case 1968: +#line 2296 "char_ref.rl" + {te = p+1;{ output->first = 0x2a3a; {p++; goto _out; } }} + break; + case 1969: +#line 2297 "char_ref.rl" + {te = p+1;{ output->first = 0x2a39; {p++; goto _out; } }} + break; + case 1970: +#line 2298 "char_ref.rl" + {te = p+1;{ output->first = 0x29cd; {p++; goto _out; } }} + break; + case 1971: +#line 2299 "char_ref.rl" + {te = p+1;{ output->first = 0x2a3b; {p++; goto _out; } }} + break; + case 1972: +#line 2300 "char_ref.rl" + {te = p+1;{ output->first = 0x23e2; {p++; goto _out; } }} + break; + case 1973: +#line 2301 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4c9; {p++; goto _out; } }} + break; + case 1974: +#line 2302 "char_ref.rl" + {te = p+1;{ output->first = 0x0446; {p++; goto _out; } }} + break; + case 1975: +#line 2303 "char_ref.rl" + {te = p+1;{ output->first = 0x045b; {p++; goto _out; } }} + break; + case 1976: +#line 2304 "char_ref.rl" + {te = p+1;{ output->first = 0x0167; {p++; goto _out; } }} + break; + case 1977: +#line 2305 "char_ref.rl" + {te = p+1;{ output->first = 0x226c; {p++; goto _out; } }} + break; + case 1978: +#line 2306 "char_ref.rl" + {te = p+1;{ output->first = 0x219e; {p++; goto _out; } }} + break; + case 1979: +#line 2307 "char_ref.rl" + {te = p+1;{ output->first = 0x21a0; {p++; goto _out; } }} + break; + case 1980: +#line 2308 "char_ref.rl" + {te = p+1;{ output->first = 0x21d1; {p++; goto _out; } }} + break; + case 1981: +#line 2309 "char_ref.rl" + {te = p+1;{ output->first = 0x2963; {p++; goto _out; } }} + break; + case 1982: +#line 2310 "char_ref.rl" + {te = p+1;{ output->first = 0xfa; {p++; goto _out; } }} + break; + case 1983: +#line 2312 "char_ref.rl" + {te = p+1;{ output->first = 0x2191; {p++; goto _out; } }} + break; + case 1984: +#line 2313 "char_ref.rl" + {te = p+1;{ output->first = 0x045e; {p++; goto _out; } }} + break; + case 1985: +#line 2314 "char_ref.rl" + {te = p+1;{ output->first = 0x016d; {p++; goto _out; } }} + break; + case 1986: +#line 2315 "char_ref.rl" + {te = p+1;{ output->first = 0xfb; {p++; goto _out; } }} + break; + case 1987: +#line 2317 "char_ref.rl" + {te = p+1;{ output->first = 0x0443; {p++; goto _out; } }} + break; + case 1988: +#line 2318 "char_ref.rl" + {te = p+1;{ output->first = 0x21c5; {p++; goto _out; } }} + break; + case 1989: +#line 2319 "char_ref.rl" + {te = p+1;{ output->first = 0x0171; {p++; goto _out; } }} + break; + case 1990: +#line 2320 "char_ref.rl" + {te = p+1;{ output->first = 0x296e; {p++; goto _out; } }} + break; + case 1991: +#line 2321 "char_ref.rl" + {te = p+1;{ output->first = 0x297e; {p++; goto _out; } }} + break; + case 1992: +#line 2322 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d532; {p++; goto _out; } }} + break; + case 1993: +#line 2323 "char_ref.rl" + {te = p+1;{ output->first = 0xf9; {p++; goto _out; } }} + break; + case 1994: +#line 2325 "char_ref.rl" + {te = p+1;{ output->first = 0x21bf; {p++; goto _out; } }} + break; + case 1995: +#line 2326 "char_ref.rl" + {te = p+1;{ output->first = 0x21be; {p++; goto _out; } }} + break; + case 1996: +#line 2327 "char_ref.rl" + {te = p+1;{ output->first = 0x2580; {p++; goto _out; } }} + break; + case 1997: +#line 2328 "char_ref.rl" + {te = p+1;{ output->first = 0x231c; {p++; goto _out; } }} + break; + case 1998: +#line 2329 "char_ref.rl" + {te = p+1;{ output->first = 0x231c; {p++; goto _out; } }} + break; + case 1999: +#line 2330 "char_ref.rl" + {te = p+1;{ output->first = 0x230f; {p++; goto _out; } }} + break; + case 2000: +#line 2331 "char_ref.rl" + {te = p+1;{ output->first = 0x25f8; {p++; goto _out; } }} + break; + case 2001: +#line 2332 "char_ref.rl" + {te = p+1;{ output->first = 0x016b; {p++; goto _out; } }} + break; + case 2002: +#line 2333 "char_ref.rl" + {te = p+1;{ output->first = 0xa8; {p++; goto _out; } }} + break; + case 2003: +#line 2335 "char_ref.rl" + {te = p+1;{ output->first = 0x0173; {p++; goto _out; } }} + break; + case 2004: +#line 2336 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d566; {p++; goto _out; } }} + break; + case 2005: +#line 2337 "char_ref.rl" + {te = p+1;{ output->first = 0x2191; {p++; goto _out; } }} + break; + case 2006: +#line 2338 "char_ref.rl" + {te = p+1;{ output->first = 0x2195; {p++; goto _out; } }} + break; + case 2007: +#line 2339 "char_ref.rl" + {te = p+1;{ output->first = 0x21bf; {p++; goto _out; } }} + break; + case 2008: +#line 2340 "char_ref.rl" + {te = p+1;{ output->first = 0x21be; {p++; goto _out; } }} + break; + case 2009: +#line 2341 "char_ref.rl" + {te = p+1;{ output->first = 0x228e; {p++; goto _out; } }} + break; + case 2010: +#line 2342 "char_ref.rl" + {te = p+1;{ output->first = 0x03c5; {p++; goto _out; } }} + break; + case 2011: +#line 2343 "char_ref.rl" + {te = p+1;{ output->first = 0x03d2; {p++; goto _out; } }} + break; + case 2012: +#line 2344 "char_ref.rl" + {te = p+1;{ output->first = 0x03c5; {p++; goto _out; } }} + break; + case 2013: +#line 2345 "char_ref.rl" + {te = p+1;{ output->first = 0x21c8; {p++; goto _out; } }} + break; + case 2014: +#line 2346 "char_ref.rl" + {te = p+1;{ output->first = 0x231d; {p++; goto _out; } }} + break; + case 2015: +#line 2347 "char_ref.rl" + {te = p+1;{ output->first = 0x231d; {p++; goto _out; } }} + break; + case 2016: +#line 2348 "char_ref.rl" + {te = p+1;{ output->first = 0x230e; {p++; goto _out; } }} + break; + case 2017: +#line 2349 "char_ref.rl" + {te = p+1;{ output->first = 0x016f; {p++; goto _out; } }} + break; + case 2018: +#line 2350 "char_ref.rl" + {te = p+1;{ output->first = 0x25f9; {p++; goto _out; } }} + break; + case 2019: +#line 2351 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4ca; {p++; goto _out; } }} + break; + case 2020: +#line 2352 "char_ref.rl" + {te = p+1;{ output->first = 0x22f0; {p++; goto _out; } }} + break; + case 2021: +#line 2353 "char_ref.rl" + {te = p+1;{ output->first = 0x0169; {p++; goto _out; } }} + break; + case 2022: +#line 2354 "char_ref.rl" + {te = p+1;{ output->first = 0x25b5; {p++; goto _out; } }} + break; + case 2023: +#line 2355 "char_ref.rl" + {te = p+1;{ output->first = 0x25b4; {p++; goto _out; } }} + break; + case 2024: +#line 2356 "char_ref.rl" + {te = p+1;{ output->first = 0x21c8; {p++; goto _out; } }} + break; + case 2025: +#line 2357 "char_ref.rl" + {te = p+1;{ output->first = 0xfc; {p++; goto _out; } }} + break; + case 2026: +#line 2359 "char_ref.rl" + {te = p+1;{ output->first = 0x29a7; {p++; goto _out; } }} + break; + case 2027: +#line 2360 "char_ref.rl" + {te = p+1;{ output->first = 0x21d5; {p++; goto _out; } }} + break; + case 2028: +#line 2361 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae8; {p++; goto _out; } }} + break; + case 2029: +#line 2362 "char_ref.rl" + {te = p+1;{ output->first = 0x2ae9; {p++; goto _out; } }} + break; + case 2030: +#line 2363 "char_ref.rl" + {te = p+1;{ output->first = 0x22a8; {p++; goto _out; } }} + break; + case 2031: +#line 2364 "char_ref.rl" + {te = p+1;{ output->first = 0x299c; {p++; goto _out; } }} + break; + case 2032: +#line 2365 "char_ref.rl" + {te = p+1;{ output->first = 0x03f5; {p++; goto _out; } }} + break; + case 2033: +#line 2366 "char_ref.rl" + {te = p+1;{ output->first = 0x03f0; {p++; goto _out; } }} + break; + case 2034: +#line 2367 "char_ref.rl" + {te = p+1;{ output->first = 0x2205; {p++; goto _out; } }} + break; + case 2035: +#line 2368 "char_ref.rl" + {te = p+1;{ output->first = 0x03d5; {p++; goto _out; } }} + break; + case 2036: +#line 2369 "char_ref.rl" + {te = p+1;{ output->first = 0x03d6; {p++; goto _out; } }} + break; + case 2037: +#line 2370 "char_ref.rl" + {te = p+1;{ output->first = 0x221d; {p++; goto _out; } }} + break; + case 2038: +#line 2371 "char_ref.rl" + {te = p+1;{ output->first = 0x2195; {p++; goto _out; } }} + break; + case 2039: +#line 2372 "char_ref.rl" + {te = p+1;{ output->first = 0x03f1; {p++; goto _out; } }} + break; + case 2040: +#line 2373 "char_ref.rl" + {te = p+1;{ output->first = 0x03c2; {p++; goto _out; } }} + break; + case 2041: +#line 2374 "char_ref.rl" + {te = p+1;{ output->first = 0x228a; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2042: +#line 2375 "char_ref.rl" + {te = p+1;{ output->first = 0x2acb; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2043: +#line 2376 "char_ref.rl" + {te = p+1;{ output->first = 0x228b; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2044: +#line 2377 "char_ref.rl" + {te = p+1;{ output->first = 0x2acc; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2045: +#line 2378 "char_ref.rl" + {te = p+1;{ output->first = 0x03d1; {p++; goto _out; } }} + break; + case 2046: +#line 2379 "char_ref.rl" + {te = p+1;{ output->first = 0x22b2; {p++; goto _out; } }} + break; + case 2047: +#line 2380 "char_ref.rl" + {te = p+1;{ output->first = 0x22b3; {p++; goto _out; } }} + break; + case 2048: +#line 2381 "char_ref.rl" + {te = p+1;{ output->first = 0x0432; {p++; goto _out; } }} + break; + case 2049: +#line 2382 "char_ref.rl" + {te = p+1;{ output->first = 0x22a2; {p++; goto _out; } }} + break; + case 2050: +#line 2383 "char_ref.rl" + {te = p+1;{ output->first = 0x2228; {p++; goto _out; } }} + break; + case 2051: +#line 2384 "char_ref.rl" + {te = p+1;{ output->first = 0x22bb; {p++; goto _out; } }} + break; + case 2052: +#line 2385 "char_ref.rl" + {te = p+1;{ output->first = 0x225a; {p++; goto _out; } }} + break; + case 2053: +#line 2386 "char_ref.rl" + {te = p+1;{ output->first = 0x22ee; {p++; goto _out; } }} + break; + case 2054: +#line 2387 "char_ref.rl" + {te = p+1;{ output->first = 0x7c; {p++; goto _out; } }} + break; + case 2055: +#line 2388 "char_ref.rl" + {te = p+1;{ output->first = 0x7c; {p++; goto _out; } }} + break; + case 2056: +#line 2389 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d533; {p++; goto _out; } }} + break; + case 2057: +#line 2390 "char_ref.rl" + {te = p+1;{ output->first = 0x22b2; {p++; goto _out; } }} + break; + case 2058: +#line 2391 "char_ref.rl" + {te = p+1;{ output->first = 0x2282; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 2059: +#line 2392 "char_ref.rl" + {te = p+1;{ output->first = 0x2283; output->second = 0x20d2; {p++; goto _out; } }} + break; + case 2060: +#line 2393 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d567; {p++; goto _out; } }} + break; + case 2061: +#line 2394 "char_ref.rl" + {te = p+1;{ output->first = 0x221d; {p++; goto _out; } }} + break; + case 2062: +#line 2395 "char_ref.rl" + {te = p+1;{ output->first = 0x22b3; {p++; goto _out; } }} + break; + case 2063: +#line 2396 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4cb; {p++; goto _out; } }} + break; + case 2064: +#line 2397 "char_ref.rl" + {te = p+1;{ output->first = 0x2acb; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2065: +#line 2398 "char_ref.rl" + {te = p+1;{ output->first = 0x228a; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2066: +#line 2399 "char_ref.rl" + {te = p+1;{ output->first = 0x2acc; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2067: +#line 2400 "char_ref.rl" + {te = p+1;{ output->first = 0x228b; output->second = 0xfe00; {p++; goto _out; } }} + break; + case 2068: +#line 2401 "char_ref.rl" + {te = p+1;{ output->first = 0x299a; {p++; goto _out; } }} + break; + case 2069: +#line 2402 "char_ref.rl" + {te = p+1;{ output->first = 0x0175; {p++; goto _out; } }} + break; + case 2070: +#line 2403 "char_ref.rl" + {te = p+1;{ output->first = 0x2a5f; {p++; goto _out; } }} + break; + case 2071: +#line 2404 "char_ref.rl" + {te = p+1;{ output->first = 0x2227; {p++; goto _out; } }} + break; + case 2072: +#line 2405 "char_ref.rl" + {te = p+1;{ output->first = 0x2259; {p++; goto _out; } }} + break; + case 2073: +#line 2406 "char_ref.rl" + {te = p+1;{ output->first = 0x2118; {p++; goto _out; } }} + break; + case 2074: +#line 2407 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d534; {p++; goto _out; } }} + break; + case 2075: +#line 2408 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d568; {p++; goto _out; } }} + break; + case 2076: +#line 2409 "char_ref.rl" + {te = p+1;{ output->first = 0x2118; {p++; goto _out; } }} + break; + case 2077: +#line 2410 "char_ref.rl" + {te = p+1;{ output->first = 0x2240; {p++; goto _out; } }} + break; + case 2078: +#line 2411 "char_ref.rl" + {te = p+1;{ output->first = 0x2240; {p++; goto _out; } }} + break; + case 2079: +#line 2412 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4cc; {p++; goto _out; } }} + break; + case 2080: +#line 2413 "char_ref.rl" + {te = p+1;{ output->first = 0x22c2; {p++; goto _out; } }} + break; + case 2081: +#line 2414 "char_ref.rl" + {te = p+1;{ output->first = 0x25ef; {p++; goto _out; } }} + break; + case 2082: +#line 2415 "char_ref.rl" + {te = p+1;{ output->first = 0x22c3; {p++; goto _out; } }} + break; + case 2083: +#line 2416 "char_ref.rl" + {te = p+1;{ output->first = 0x25bd; {p++; goto _out; } }} + break; + case 2084: +#line 2417 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d535; {p++; goto _out; } }} + break; + case 2085: +#line 2418 "char_ref.rl" + {te = p+1;{ output->first = 0x27fa; {p++; goto _out; } }} + break; + case 2086: +#line 2419 "char_ref.rl" + {te = p+1;{ output->first = 0x27f7; {p++; goto _out; } }} + break; + case 2087: +#line 2420 "char_ref.rl" + {te = p+1;{ output->first = 0x03be; {p++; goto _out; } }} + break; + case 2088: +#line 2421 "char_ref.rl" + {te = p+1;{ output->first = 0x27f8; {p++; goto _out; } }} + break; + case 2089: +#line 2422 "char_ref.rl" + {te = p+1;{ output->first = 0x27f5; {p++; goto _out; } }} + break; + case 2090: +#line 2423 "char_ref.rl" + {te = p+1;{ output->first = 0x27fc; {p++; goto _out; } }} + break; + case 2091: +#line 2424 "char_ref.rl" + {te = p+1;{ output->first = 0x22fb; {p++; goto _out; } }} + break; + case 2092: +#line 2425 "char_ref.rl" + {te = p+1;{ output->first = 0x2a00; {p++; goto _out; } }} + break; + case 2093: +#line 2426 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d569; {p++; goto _out; } }} + break; + case 2094: +#line 2427 "char_ref.rl" + {te = p+1;{ output->first = 0x2a01; {p++; goto _out; } }} + break; + case 2095: +#line 2428 "char_ref.rl" + {te = p+1;{ output->first = 0x2a02; {p++; goto _out; } }} + break; + case 2096: +#line 2429 "char_ref.rl" + {te = p+1;{ output->first = 0x27f9; {p++; goto _out; } }} + break; + case 2097: +#line 2430 "char_ref.rl" + {te = p+1;{ output->first = 0x27f6; {p++; goto _out; } }} + break; + case 2098: +#line 2431 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4cd; {p++; goto _out; } }} + break; + case 2099: +#line 2432 "char_ref.rl" + {te = p+1;{ output->first = 0x2a06; {p++; goto _out; } }} + break; + case 2100: +#line 2433 "char_ref.rl" + {te = p+1;{ output->first = 0x2a04; {p++; goto _out; } }} + break; + case 2101: +#line 2434 "char_ref.rl" + {te = p+1;{ output->first = 0x25b3; {p++; goto _out; } }} + break; + case 2102: +#line 2435 "char_ref.rl" + {te = p+1;{ output->first = 0x22c1; {p++; goto _out; } }} + break; + case 2103: +#line 2436 "char_ref.rl" + {te = p+1;{ output->first = 0x22c0; {p++; goto _out; } }} + break; + case 2104: +#line 2437 "char_ref.rl" + {te = p+1;{ output->first = 0xfd; {p++; goto _out; } }} + break; + case 2105: +#line 2439 "char_ref.rl" + {te = p+1;{ output->first = 0x044f; {p++; goto _out; } }} + break; + case 2106: +#line 2440 "char_ref.rl" + {te = p+1;{ output->first = 0x0177; {p++; goto _out; } }} + break; + case 2107: +#line 2441 "char_ref.rl" + {te = p+1;{ output->first = 0x044b; {p++; goto _out; } }} + break; + case 2108: +#line 2442 "char_ref.rl" + {te = p+1;{ output->first = 0xa5; {p++; goto _out; } }} + break; + case 2109: +#line 2444 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d536; {p++; goto _out; } }} + break; + case 2110: +#line 2445 "char_ref.rl" + {te = p+1;{ output->first = 0x0457; {p++; goto _out; } }} + break; + case 2111: +#line 2446 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d56a; {p++; goto _out; } }} + break; + case 2112: +#line 2447 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4ce; {p++; goto _out; } }} + break; + case 2113: +#line 2448 "char_ref.rl" + {te = p+1;{ output->first = 0x044e; {p++; goto _out; } }} + break; + case 2114: +#line 2449 "char_ref.rl" + {te = p+1;{ output->first = 0xff; {p++; goto _out; } }} + break; + case 2115: +#line 2451 "char_ref.rl" + {te = p+1;{ output->first = 0x017a; {p++; goto _out; } }} + break; + case 2116: +#line 2452 "char_ref.rl" + {te = p+1;{ output->first = 0x017e; {p++; goto _out; } }} + break; + case 2117: +#line 2453 "char_ref.rl" + {te = p+1;{ output->first = 0x0437; {p++; goto _out; } }} + break; + case 2118: +#line 2454 "char_ref.rl" + {te = p+1;{ output->first = 0x017c; {p++; goto _out; } }} + break; + case 2119: +#line 2455 "char_ref.rl" + {te = p+1;{ output->first = 0x2128; {p++; goto _out; } }} + break; + case 2120: +#line 2456 "char_ref.rl" + {te = p+1;{ output->first = 0x03b6; {p++; goto _out; } }} + break; + case 2121: +#line 2457 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d537; {p++; goto _out; } }} + break; + case 2122: +#line 2458 "char_ref.rl" + {te = p+1;{ output->first = 0x0436; {p++; goto _out; } }} + break; + case 2123: +#line 2459 "char_ref.rl" + {te = p+1;{ output->first = 0x21dd; {p++; goto _out; } }} + break; + case 2124: +#line 2460 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d56b; {p++; goto _out; } }} + break; + case 2125: +#line 2461 "char_ref.rl" + {te = p+1;{ output->first = 0x0001d4cf; {p++; goto _out; } }} + break; + case 2126: +#line 2462 "char_ref.rl" + {te = p+1;{ output->first = 0x200d; {p++; goto _out; } }} + break; + case 2127: +#line 2463 "char_ref.rl" + {te = p+1;{ output->first = 0x200c; {p++; goto _out; } }} + break; + case 2128: +#line 234 "char_ref.rl" + {te = p;p--;{ output->first = 0xc6; {p++; goto _out; } }} + break; + case 2129: +#line 236 "char_ref.rl" + {te = p;p--;{ output->first = 0x26; {p++; goto _out; } }} + break; + case 2130: +#line 238 "char_ref.rl" + {te = p;p--;{ output->first = 0xc1; {p++; goto _out; } }} + break; + case 2131: +#line 241 "char_ref.rl" + {te = p;p--;{ output->first = 0xc2; {p++; goto _out; } }} + break; + case 2132: +#line 245 "char_ref.rl" + {te = p;p--;{ output->first = 0xc0; {p++; goto _out; } }} + break; + case 2133: +#line 253 "char_ref.rl" + {te = p;p--;{ output->first = 0xc5; {p++; goto _out; } }} + break; + case 2134: +#line 257 "char_ref.rl" + {te = p;p--;{ output->first = 0xc3; {p++; goto _out; } }} + break; + case 2135: +#line 259 "char_ref.rl" + {te = p;p--;{ output->first = 0xc4; {p++; goto _out; } }} + break; + case 2136: +#line 274 "char_ref.rl" + {te = p;p--;{ output->first = 0xa9; {p++; goto _out; } }} + break; + case 2137: +#line 281 "char_ref.rl" + {te = p;p--;{ output->first = 0xc7; {p++; goto _out; } }} + break; + case 2138: +#line 364 "char_ref.rl" + {te = p;p--;{ output->first = 0xd0; {p++; goto _out; } }} + break; + case 2139: +#line 366 "char_ref.rl" + {te = p;p--;{ output->first = 0xc9; {p++; goto _out; } }} + break; + case 2140: +#line 369 "char_ref.rl" + {te = p;p--;{ output->first = 0xca; {p++; goto _out; } }} + break; + case 2141: +#line 374 "char_ref.rl" + {te = p;p--;{ output->first = 0xc8; {p++; goto _out; } }} + break; + case 2142: +#line 389 "char_ref.rl" + {te = p;p--;{ output->first = 0xcb; {p++; goto _out; } }} + break; + case 2143: +#line 402 "char_ref.rl" + {te = p;p--;{ output->first = 0x3e; {p++; goto _out; } }} + break; + case 2144: +#line 438 "char_ref.rl" + {te = p;p--;{ output->first = 0xcd; {p++; goto _out; } }} + break; + case 2145: +#line 440 "char_ref.rl" + {te = p;p--;{ output->first = 0xce; {p++; goto _out; } }} + break; + case 2146: +#line 445 "char_ref.rl" + {te = p;p--;{ output->first = 0xcc; {p++; goto _out; } }} + break; + case 2147: +#line 462 "char_ref.rl" + {te = p;p--;{ output->first = 0xcf; {p++; goto _out; } }} + break; + case 2148: +#line 480 "char_ref.rl" + {te = p;p--;{ output->first = 0x3c; {p++; goto _out; } }} + break; + case 2149: +#line 617 "char_ref.rl" + {te = p;p--;{ output->first = 0xd1; {p++; goto _out; } }} + break; + case 2150: +#line 621 "char_ref.rl" + {te = p;p--;{ output->first = 0xd3; {p++; goto _out; } }} + break; + case 2151: +#line 623 "char_ref.rl" + {te = p;p--;{ output->first = 0xd4; {p++; goto _out; } }} + break; + case 2152: +#line 628 "char_ref.rl" + {te = p;p--;{ output->first = 0xd2; {p++; goto _out; } }} + break; + case 2153: +#line 638 "char_ref.rl" + {te = p;p--;{ output->first = 0xd8; {p++; goto _out; } }} + break; + case 2154: +#line 640 "char_ref.rl" + {te = p;p--;{ output->first = 0xd5; {p++; goto _out; } }} + break; + case 2155: +#line 643 "char_ref.rl" + {te = p;p--;{ output->first = 0xd6; {p++; goto _out; } }} + break; + case 2156: +#line 668 "char_ref.rl" + {te = p;p--;{ output->first = 0x22; {p++; goto _out; } }} + break; + case 2157: +#line 674 "char_ref.rl" + {te = p;p--;{ output->first = 0xae; {p++; goto _out; } }} + break; + case 2158: +#line 758 "char_ref.rl" + {te = p;p--;{ output->first = 0xde; {p++; goto _out; } }} + break; + case 2159: +#line 781 "char_ref.rl" + {te = p;p--;{ output->first = 0xda; {p++; goto _out; } }} + break; + case 2160: +#line 787 "char_ref.rl" + {te = p;p--;{ output->first = 0xdb; {p++; goto _out; } }} + break; + case 2161: +#line 792 "char_ref.rl" + {te = p;p--;{ output->first = 0xd9; {p++; goto _out; } }} + break; + case 2162: +#line 819 "char_ref.rl" + {te = p;p--;{ output->first = 0xdc; {p++; goto _out; } }} + break; + case 2163: +#line 850 "char_ref.rl" + {te = p;p--;{ output->first = 0xdd; {p++; goto _out; } }} + break; + case 2164: +#line 868 "char_ref.rl" + {te = p;p--;{ output->first = 0xe1; {p++; goto _out; } }} + break; + case 2165: +#line 874 "char_ref.rl" + {te = p;p--;{ output->first = 0xe2; {p++; goto _out; } }} + break; + case 2166: +#line 876 "char_ref.rl" + {te = p;p--;{ output->first = 0xb4; {p++; goto _out; } }} + break; + case 2167: +#line 879 "char_ref.rl" + {te = p;p--;{ output->first = 0xe6; {p++; goto _out; } }} + break; + case 2168: +#line 883 "char_ref.rl" + {te = p;p--;{ output->first = 0xe0; {p++; goto _out; } }} + break; + case 2169: +#line 890 "char_ref.rl" + {te = p;p--;{ output->first = 0x26; {p++; goto _out; } }} + break; + case 2170: +#line 925 "char_ref.rl" + {te = p;p--;{ output->first = 0xe5; {p++; goto _out; } }} + break; + case 2171: +#line 931 "char_ref.rl" + {te = p;p--;{ output->first = 0xe3; {p++; goto _out; } }} + break; + case 2172: +#line 933 "char_ref.rl" + {te = p;p--;{ output->first = 0xe4; {p++; goto _out; } }} + break; + case 2173: +#line 1038 "char_ref.rl" + {te = p;p--;{ output->first = 0xa6; {p++; goto _out; } }} + break; + case 2174: +#line 1065 "char_ref.rl" + {te = p;p--;{ output->first = 0xe7; {p++; goto _out; } }} + break; + case 2175: +#line 1071 "char_ref.rl" + {te = p;p--;{ output->first = 0xb8; {p++; goto _out; } }} + break; + case 2176: +#line 1074 "char_ref.rl" + {te = p;p--;{ output->first = 0xa2; {p++; goto _out; } }} + break; + case 2177: +#line 1113 "char_ref.rl" + {te = p;p--;{ output->first = 0xa9; {p++; goto _out; } }} + break; + case 2178: +#line 1143 "char_ref.rl" + {te = p;p--;{ output->first = 0xa4; {p++; goto _out; } }} + break; + case 2179: +#line 1167 "char_ref.rl" + {te = p;p--;{ output->first = 0xb0; {p++; goto _out; } }} + break; + case 2180: +#line 1183 "char_ref.rl" + {te = p;p--;{ output->first = 0xf7; {p++; goto _out; } }} + break; + case 2181: +#line 1220 "char_ref.rl" + {te = p;p--;{ output->first = 0xe9; {p++; goto _out; } }} + break; + case 2182: +#line 1225 "char_ref.rl" + {te = p;p--;{ output->first = 0xea; {p++; goto _out; } }} + break; + case 2183: +#line 1234 "char_ref.rl" + {te = p;p--;{ output->first = 0xe8; {p++; goto _out; } }} + break; + case 2184: +#line 1276 "char_ref.rl" + {te = p;p--;{ output->first = 0xf0; {p++; goto _out; } }} + break; + case 2185: +#line 1278 "char_ref.rl" + {te = p;p--;{ output->first = 0xeb; {p++; goto _out; } }} + break; + case 2186: +#line 1303 "char_ref.rl" + {te = p;p--;{ output->first = 0xbd; {p++; goto _out; } }} + break; + case 2187: +#line 1306 "char_ref.rl" + {te = p;p--;{ output->first = 0xbc; {p++; goto _out; } }} + break; + case 2188: +#line 1313 "char_ref.rl" + {te = p;p--;{ output->first = 0xbe; {p++; goto _out; } }} + break; + case 2189: +#line 1368 "char_ref.rl" + {te = p;p--;{ output->first = 0x3e; {p++; goto _out; } }} + break; + case 2190: +#line 1412 "char_ref.rl" + {te = p;p--;{ output->first = 0xed; {p++; goto _out; } }} + break; + case 2191: +#line 1415 "char_ref.rl" + {te = p;p--;{ output->first = 0xee; {p++; goto _out; } }} + break; + case 2192: +#line 1419 "char_ref.rl" + {te = p;p--;{ output->first = 0xa1; {p++; goto _out; } }} + break; + case 2193: +#line 1423 "char_ref.rl" + {te = p;p--;{ output->first = 0xec; {p++; goto _out; } }} + break; + case 2194: +#line 1454 "char_ref.rl" + {te = p;p--;{ output->first = 0xbf; {p++; goto _out; } }} + break; + case 2195: +#line 1466 "char_ref.rl" + {te = p;p--;{ output->first = 0xef; {p++; goto _out; } }} + break; + case 2196: +#line 1501 "char_ref.rl" + {te = p;p--;{ output->first = 0xab; {p++; goto _out; } }} + break; + case 2197: +#line 1623 "char_ref.rl" + {te = p;p--;{ output->first = 0x3c; {p++; goto _out; } }} + break; + case 2198: +#line 1641 "char_ref.rl" + {te = p;p--;{ output->first = 0xaf; {p++; goto _out; } }} + break; + case 2199: +#line 1658 "char_ref.rl" + {te = p;p--;{ output->first = 0xb5; {p++; goto _out; } }} + break; + case 2200: +#line 1663 "char_ref.rl" + {te = p;p--;{ output->first = 0xb7; {p++; goto _out; } }} + break; + case 2201: +#line 1702 "char_ref.rl" + {te = p;p--;{ output->first = 0xa0; {p++; goto _out; } }} + break; + case 2202: +#line 1771 "char_ref.rl" + {te = p;p--;{ output->first = 0xac; {p++; goto _out; } }} + break; + case 2203: +#line 1818 "char_ref.rl" + {te = p;p--;{ output->first = 0xf1; {p++; goto _out; } }} + break; + case 2204: +#line 1849 "char_ref.rl" + {te = p;p--;{ output->first = 0xf3; {p++; goto _out; } }} + break; + case 2205: +#line 1853 "char_ref.rl" + {te = p;p--;{ output->first = 0xf4; {p++; goto _out; } }} + break; + case 2206: +#line 1865 "char_ref.rl" + {te = p;p--;{ output->first = 0xf2; {p++; goto _out; } }} + break; + case 2207: +#line 1890 "char_ref.rl" + {te = p;p--;{ output->first = 0xaa; {p++; goto _out; } }} + break; + case 2208: +#line 1892 "char_ref.rl" + {te = p;p--;{ output->first = 0xba; {p++; goto _out; } }} + break; + case 2209: +#line 1899 "char_ref.rl" + {te = p;p--;{ output->first = 0xf8; {p++; goto _out; } }} + break; + case 2210: +#line 1902 "char_ref.rl" + {te = p;p--;{ output->first = 0xf5; {p++; goto _out; } }} + break; + case 2211: +#line 1906 "char_ref.rl" + {te = p;p--;{ output->first = 0xf6; {p++; goto _out; } }} + break; + case 2212: +#line 1910 "char_ref.rl" + {te = p;p--;{ output->first = 0xb6; {p++; goto _out; } }} + break; + case 2213: +#line 1940 "char_ref.rl" + {te = p;p--;{ output->first = 0xb1; {p++; goto _out; } }} + break; + case 2214: +#line 1947 "char_ref.rl" + {te = p;p--;{ output->first = 0xa3; {p++; goto _out; } }} + break; + case 2215: +#line 1987 "char_ref.rl" + {te = p;p--;{ output->first = 0x22; {p++; goto _out; } }} + break; + case 2216: +#line 2002 "char_ref.rl" + {te = p;p--;{ output->first = 0xbb; {p++; goto _out; } }} + break; + case 2217: +#line 2041 "char_ref.rl" + {te = p;p--;{ output->first = 0xae; {p++; goto _out; } }} + break; + case 2218: +#line 2116 "char_ref.rl" + {te = p;p--;{ output->first = 0xa7; {p++; goto _out; } }} + break; + case 2219: +#line 2130 "char_ref.rl" + {te = p;p--;{ output->first = 0xad; {p++; goto _out; } }} + break; + case 2220: +#line 2217 "char_ref.rl" + {te = p;p--;{ output->first = 0xb9; {p++; goto _out; } }} + break; + case 2221: +#line 2219 "char_ref.rl" + {te = p;p--;{ output->first = 0xb2; {p++; goto _out; } }} + break; + case 2222: +#line 2221 "char_ref.rl" + {te = p;p--;{ output->first = 0xb3; {p++; goto _out; } }} + break; + case 2223: +#line 2249 "char_ref.rl" + {te = p;p--;{ output->first = 0xdf; {p++; goto _out; } }} + break; + case 2224: +#line 2270 "char_ref.rl" + {te = p;p--;{ output->first = 0xfe; {p++; goto _out; } }} + break; + case 2225: +#line 2273 "char_ref.rl" + {te = p;p--;{ output->first = 0xd7; {p++; goto _out; } }} + break; + case 2226: +#line 2311 "char_ref.rl" + {te = p;p--;{ output->first = 0xfa; {p++; goto _out; } }} + break; + case 2227: +#line 2316 "char_ref.rl" + {te = p;p--;{ output->first = 0xfb; {p++; goto _out; } }} + break; + case 2228: +#line 2324 "char_ref.rl" + {te = p;p--;{ output->first = 0xf9; {p++; goto _out; } }} + break; + case 2229: +#line 2334 "char_ref.rl" + {te = p;p--;{ output->first = 0xa8; {p++; goto _out; } }} + break; + case 2230: +#line 2358 "char_ref.rl" + {te = p;p--;{ output->first = 0xfc; {p++; goto _out; } }} + break; + case 2231: +#line 2438 "char_ref.rl" + {te = p;p--;{ output->first = 0xfd; {p++; goto _out; } }} + break; + case 2232: +#line 2443 "char_ref.rl" + {te = p;p--;{ output->first = 0xa5; {p++; goto _out; } }} + break; + case 2233: +#line 2450 "char_ref.rl" + {te = p;p--;{ output->first = 0xff; {p++; goto _out; } }} + break; + case 2234: +#line 1074 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xa2; {p++; goto _out; } }} + break; + case 2235: +#line 1113 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xa9; {p++; goto _out; } }} + break; + case 2236: +#line 1183 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xf7; {p++; goto _out; } }} + break; + case 2237: +#line 1368 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0x3e; {p++; goto _out; } }} + break; + case 2238: +#line 1623 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0x3c; {p++; goto _out; } }} + break; + case 2239: +#line 1771 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xac; {p++; goto _out; } }} + break; + case 2240: +#line 1910 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xb6; {p++; goto _out; } }} + break; + case 2241: +#line 2273 "char_ref.rl" + {{p = ((te))-1;}{ output->first = 0xd7; {p++; goto _out; } }} + break; +#line 23006 "char_ref.c" + } + } + +_again: + _acts = _char_ref_actions + _char_ref_to_state_actions[cs]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) { + switch ( *_acts++ ) { + case 0: +#line 1 "NONE" + {ts = 0;} + break; +#line 23019 "char_ref.c" + } + } + + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + if ( _char_ref_eof_trans[cs] > 0 ) { + _trans = _char_ref_eof_trans[cs] - 1; + goto _eof_trans; + } + } + + _out: {} + } + +#line 2491 "char_ref.rl" + // clang-format on + + if (cs >= 7623) { + assert(output->first != kGumboNoChar); + char last_char = *(te - 1); + ptrdiff_t len = te - start; + if (last_char == ';') { + bool matched = utf8iterator_maybe_consume_match(input, start, len, true); + assert(matched); + return true; + } else if (is_in_attribute && (*te == '=' || isalnum(*te))) { + output->first = kGumboNoChar; + output->second = kGumboNoChar; + utf8iterator_reset(input); + return true; + } else { + GumboStringPiece bad_ref; + bad_ref.length = te - start; + bad_ref.data = start; + add_named_reference_error( + parser, input, GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON, bad_ref); + bool matched = utf8iterator_maybe_consume_match(input, start, len, true); + assert(matched); + return false; + } + } else { + output->first = kGumboNoChar; + output->second = kGumboNoChar; + bool status = maybe_add_invalid_named_reference(parser, input); + utf8iterator_reset(input); + return status; + } +} + +bool consume_char_ref(struct GumboInternalParser* parser, + struct GumboInternalUtf8Iterator* input, int additional_allowed_char, + bool is_in_attribute, OneOrTwoCodepoints* output) { + utf8iterator_mark(input); + utf8iterator_next(input); + int c = utf8iterator_current(input); + output->first = kGumboNoChar; + output->second = kGumboNoChar; + if (c == additional_allowed_char) { + utf8iterator_reset(input); + output->first = kGumboNoChar; + return true; + } + switch (utf8iterator_current(input)) { + case '\t': + case '\n': + case '\f': + case ' ': + case '<': + case '&': + case -1: + utf8iterator_reset(input); + return true; + case '#': + return consume_numeric_ref(parser, input, &output->first); + default: + return consume_named_ref(parser, input, is_in_attribute, output); + } +} diff --git a/libs/litehtml/src/gumbo/char_ref.rl b/libs/litehtml/src/gumbo/char_ref.rl new file mode 100644 index 0000000000..7c1c410d93 --- /dev/null +++ b/libs/litehtml/src/gumbo/char_ref.rl @@ -0,0 +1,2554 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This is a Ragel state machine re-implementation of the original char_ref.c, +// rewritten to improve efficiency. To generate the .c file from it, +// +// $ ragel -F0 char_ref.rl +// +// The generated source is also checked into source control so that most people +// hacking on the parser do not need to install ragel. + +#include "char_ref.h" + +#include <assert.h> +#include <ctype.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> // Only for debug assertions at present. + +#include "error.h" +#include "string_piece.h" +#include "utf8.h" +#include "util.h" + +struct GumboInternalParser; + +const int kGumboNoChar = -1; + +// Table of replacement characters. The spec specifies that any occurrence of +// the first character should be replaced by the second character, and a parse +// error recorded. +typedef struct { + int from_char; + int to_char; +} CharReplacement; + +static const CharReplacement kCharReplacements[] = { + { 0x00, 0xfffd }, + { 0x0d, 0x000d }, + { 0x80, 0x20ac }, + { 0x81, 0x0081 }, + { 0x82, 0x201A }, + { 0x83, 0x0192 }, + { 0x84, 0x201E }, + { 0x85, 0x2026 }, + { 0x86, 0x2020 }, + { 0x87, 0x2021 }, + { 0x88, 0x02C6 }, + { 0x89, 0x2030 }, + { 0x8A, 0x0160 }, + { 0x8B, 0x2039 }, + { 0x8C, 0x0152 }, + { 0x8D, 0x008D }, + { 0x8E, 0x017D }, + { 0x8F, 0x008F }, + { 0x90, 0x0090 }, + { 0x91, 0x2018 }, + { 0x92, 0x2019 }, + { 0x93, 0x201C }, + { 0x94, 0x201D }, + { 0x95, 0x2022 }, + { 0x96, 0x2013 }, + { 0x97, 0x2014 }, + { 0x98, 0x02DC }, + { 0x99, 0x2122 }, + { 0x9A, 0x0161 }, + { 0x9B, 0x203A }, + { 0x9C, 0x0153 }, + { 0x9D, 0x009D }, + { 0x9E, 0x017E }, + { 0x9F, 0x0178 }, + // Terminator. + { -1, -1 } +}; + +static int parse_digit(int c, bool allow_hex) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (allow_hex && c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (allow_hex && c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +static void add_no_digit_error( + struct GumboInternalParser* parser, Utf8Iterator* input) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS; +} + +static void add_codepoint_error( + struct GumboInternalParser* parser, Utf8Iterator* input, + GumboErrorType type, int codepoint) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = type; + error->v.codepoint = codepoint; +} + +static void add_named_reference_error( + struct GumboInternalParser* parser, Utf8Iterator* input, + GumboErrorType type, GumboStringPiece text) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + utf8iterator_fill_error_at_mark(input, error); + error->type = type; + error->v.text = text; +} + +static int maybe_replace_codepoint(int codepoint) { + for (int i = 0; kCharReplacements[i].from_char != -1; ++i) { + if (kCharReplacements[i].from_char == codepoint) { + return kCharReplacements[i].to_char; + } + } + return -1; +} + +static bool consume_numeric_ref( + struct GumboInternalParser* parser, Utf8Iterator* input, int* output) { + utf8iterator_next(input); + bool is_hex = false; + int c = utf8iterator_current(input); + if (c == 'x' || c == 'X') { + is_hex = true; + utf8iterator_next(input); + c = utf8iterator_current(input); + } + + int digit = parse_digit(c, is_hex); + if (digit == -1) { + // First digit was invalid; add a parse error and return. + add_no_digit_error(parser, input); + utf8iterator_reset(input); + *output = kGumboNoChar; + return false; + } + + int codepoint = 0; + bool status = true; + do { + codepoint = (codepoint * (is_hex ? 16 : 10)) + digit; + utf8iterator_next(input); + digit = parse_digit(utf8iterator_current(input), is_hex); + } while (digit != -1); + + if (utf8iterator_current(input) != ';') { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON, codepoint); + status = false; + } else { + utf8iterator_next(input); + } + + int replacement = maybe_replace_codepoint(codepoint); + if (replacement != -1) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + *output = replacement; + return false; + } + + if ((codepoint >= 0xd800 && codepoint <= 0xdfff) || codepoint > 0x10ffff) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + *output = 0xfffd; + return false; + } + + if (utf8_is_invalid_code_point(codepoint) || codepoint == 0xb) { + add_codepoint_error( + parser, input, GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, codepoint); + status = false; + // But return it anyway, per spec. + } + *output = codepoint; + return status; +} + +static bool maybe_add_invalid_named_reference( + struct GumboInternalParser* parser, Utf8Iterator* input) { + // The iterator will always be reset in this code path, so we don't need to + // worry about consuming characters. + const char* start = utf8iterator_get_char_pointer(input); + int c = utf8iterator_current(input); + while ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) { + utf8iterator_next(input); + c = utf8iterator_current(input); + } + if (c == ';') { + GumboStringPiece bad_ref; + bad_ref.data = start; + bad_ref.length = utf8iterator_get_char_pointer(input) - start; + add_named_reference_error( + parser, input, GUMBO_ERR_NAMED_CHAR_REF_INVALID, bad_ref); + return false; + } + return true; +} + +%%{ +machine char_ref; + +valid_named_ref := |* + 'AElig;' => { output->first = 0xc6; fbreak; }; + 'AElig' => { output->first = 0xc6; fbreak; }; + 'AMP;' => { output->first = 0x26; fbreak; }; + 'AMP' => { output->first = 0x26; fbreak; }; + 'Aacute;' => { output->first = 0xc1; fbreak; }; + 'Aacute' => { output->first = 0xc1; fbreak; }; + 'Abreve;' => { output->first = 0x0102; fbreak; }; + 'Acirc;' => { output->first = 0xc2; fbreak; }; + 'Acirc' => { output->first = 0xc2; fbreak; }; + 'Acy;' => { output->first = 0x0410; fbreak; }; + 'Afr;' => { output->first = 0x0001d504; fbreak; }; + 'Agrave;' => { output->first = 0xc0; fbreak; }; + 'Agrave' => { output->first = 0xc0; fbreak; }; + 'Alpha;' => { output->first = 0x0391; fbreak; }; + 'Amacr;' => { output->first = 0x0100; fbreak; }; + 'And;' => { output->first = 0x2a53; fbreak; }; + 'Aogon;' => { output->first = 0x0104; fbreak; }; + 'Aopf;' => { output->first = 0x0001d538; fbreak; }; + 'ApplyFunction;' => { output->first = 0x2061; fbreak; }; + 'Aring;' => { output->first = 0xc5; fbreak; }; + 'Aring' => { output->first = 0xc5; fbreak; }; + 'Ascr;' => { output->first = 0x0001d49c; fbreak; }; + 'Assign;' => { output->first = 0x2254; fbreak; }; + 'Atilde;' => { output->first = 0xc3; fbreak; }; + 'Atilde' => { output->first = 0xc3; fbreak; }; + 'Auml;' => { output->first = 0xc4; fbreak; }; + 'Auml' => { output->first = 0xc4; fbreak; }; + 'Backslash;' => { output->first = 0x2216; fbreak; }; + 'Barv;' => { output->first = 0x2ae7; fbreak; }; + 'Barwed;' => { output->first = 0x2306; fbreak; }; + 'Bcy;' => { output->first = 0x0411; fbreak; }; + 'Because;' => { output->first = 0x2235; fbreak; }; + 'Bernoullis;' => { output->first = 0x212c; fbreak; }; + 'Beta;' => { output->first = 0x0392; fbreak; }; + 'Bfr;' => { output->first = 0x0001d505; fbreak; }; + 'Bopf;' => { output->first = 0x0001d539; fbreak; }; + 'Breve;' => { output->first = 0x02d8; fbreak; }; + 'Bscr;' => { output->first = 0x212c; fbreak; }; + 'Bumpeq;' => { output->first = 0x224e; fbreak; }; + 'CHcy;' => { output->first = 0x0427; fbreak; }; + 'COPY;' => { output->first = 0xa9; fbreak; }; + 'COPY' => { output->first = 0xa9; fbreak; }; + 'Cacute;' => { output->first = 0x0106; fbreak; }; + 'Cap;' => { output->first = 0x22d2; fbreak; }; + 'CapitalDifferentialD;' => { output->first = 0x2145; fbreak; }; + 'Cayleys;' => { output->first = 0x212d; fbreak; }; + 'Ccaron;' => { output->first = 0x010c; fbreak; }; + 'Ccedil;' => { output->first = 0xc7; fbreak; }; + 'Ccedil' => { output->first = 0xc7; fbreak; }; + 'Ccirc;' => { output->first = 0x0108; fbreak; }; + 'Cconint;' => { output->first = 0x2230; fbreak; }; + 'Cdot;' => { output->first = 0x010a; fbreak; }; + 'Cedilla;' => { output->first = 0xb8; fbreak; }; + 'CenterDot;' => { output->first = 0xb7; fbreak; }; + 'Cfr;' => { output->first = 0x212d; fbreak; }; + 'Chi;' => { output->first = 0x03a7; fbreak; }; + 'CircleDot;' => { output->first = 0x2299; fbreak; }; + 'CircleMinus;' => { output->first = 0x2296; fbreak; }; + 'CirclePlus;' => { output->first = 0x2295; fbreak; }; + 'CircleTimes;' => { output->first = 0x2297; fbreak; }; + 'ClockwiseContourIntegral;' => { output->first = 0x2232; fbreak; }; + 'CloseCurlyDoubleQuote;' => { output->first = 0x201d; fbreak; }; + 'CloseCurlyQuote;' => { output->first = 0x2019; fbreak; }; + 'Colon;' => { output->first = 0x2237; fbreak; }; + 'Colone;' => { output->first = 0x2a74; fbreak; }; + 'Congruent;' => { output->first = 0x2261; fbreak; }; + 'Conint;' => { output->first = 0x222f; fbreak; }; + 'ContourIntegral;' => { output->first = 0x222e; fbreak; }; + 'Copf;' => { output->first = 0x2102; fbreak; }; + 'Coproduct;' => { output->first = 0x2210; fbreak; }; + 'CounterClockwiseContourIntegral;' => { output->first = 0x2233; fbreak; }; + 'Cross;' => { output->first = 0x2a2f; fbreak; }; + 'Cscr;' => { output->first = 0x0001d49e; fbreak; }; + 'Cup;' => { output->first = 0x22d3; fbreak; }; + 'CupCap;' => { output->first = 0x224d; fbreak; }; + 'DD;' => { output->first = 0x2145; fbreak; }; + 'DDotrahd;' => { output->first = 0x2911; fbreak; }; + 'DJcy;' => { output->first = 0x0402; fbreak; }; + 'DScy;' => { output->first = 0x0405; fbreak; }; + 'DZcy;' => { output->first = 0x040f; fbreak; }; + 'Dagger;' => { output->first = 0x2021; fbreak; }; + 'Darr;' => { output->first = 0x21a1; fbreak; }; + 'Dashv;' => { output->first = 0x2ae4; fbreak; }; + 'Dcaron;' => { output->first = 0x010e; fbreak; }; + 'Dcy;' => { output->first = 0x0414; fbreak; }; + 'Del;' => { output->first = 0x2207; fbreak; }; + 'Delta;' => { output->first = 0x0394; fbreak; }; + 'Dfr;' => { output->first = 0x0001d507; fbreak; }; + 'DiacriticalAcute;' => { output->first = 0xb4; fbreak; }; + 'DiacriticalDot;' => { output->first = 0x02d9; fbreak; }; + 'DiacriticalDoubleAcute;' => { output->first = 0x02dd; fbreak; }; + 'DiacriticalGrave;' => { output->first = 0x60; fbreak; }; + 'DiacriticalTilde;' => { output->first = 0x02dc; fbreak; }; + 'Diamond;' => { output->first = 0x22c4; fbreak; }; + 'DifferentialD;' => { output->first = 0x2146; fbreak; }; + 'Dopf;' => { output->first = 0x0001d53b; fbreak; }; + 'Dot;' => { output->first = 0xa8; fbreak; }; + 'DotDot;' => { output->first = 0x20dc; fbreak; }; + 'DotEqual;' => { output->first = 0x2250; fbreak; }; + 'DoubleContourIntegral;' => { output->first = 0x222f; fbreak; }; + 'DoubleDot;' => { output->first = 0xa8; fbreak; }; + 'DoubleDownArrow;' => { output->first = 0x21d3; fbreak; }; + 'DoubleLeftArrow;' => { output->first = 0x21d0; fbreak; }; + 'DoubleLeftRightArrow;' => { output->first = 0x21d4; fbreak; }; + 'DoubleLeftTee;' => { output->first = 0x2ae4; fbreak; }; + 'DoubleLongLeftArrow;' => { output->first = 0x27f8; fbreak; }; + 'DoubleLongLeftRightArrow;' => { output->first = 0x27fa; fbreak; }; + 'DoubleLongRightArrow;' => { output->first = 0x27f9; fbreak; }; + 'DoubleRightArrow;' => { output->first = 0x21d2; fbreak; }; + 'DoubleRightTee;' => { output->first = 0x22a8; fbreak; }; + 'DoubleUpArrow;' => { output->first = 0x21d1; fbreak; }; + 'DoubleUpDownArrow;' => { output->first = 0x21d5; fbreak; }; + 'DoubleVerticalBar;' => { output->first = 0x2225; fbreak; }; + 'DownArrow;' => { output->first = 0x2193; fbreak; }; + 'DownArrowBar;' => { output->first = 0x2913; fbreak; }; + 'DownArrowUpArrow;' => { output->first = 0x21f5; fbreak; }; + 'DownBreve;' => { output->first = 0x0311; fbreak; }; + 'DownLeftRightVector;' => { output->first = 0x2950; fbreak; }; + 'DownLeftTeeVector;' => { output->first = 0x295e; fbreak; }; + 'DownLeftVector;' => { output->first = 0x21bd; fbreak; }; + 'DownLeftVectorBar;' => { output->first = 0x2956; fbreak; }; + 'DownRightTeeVector;' => { output->first = 0x295f; fbreak; }; + 'DownRightVector;' => { output->first = 0x21c1; fbreak; }; + 'DownRightVectorBar;' => { output->first = 0x2957; fbreak; }; + 'DownTee;' => { output->first = 0x22a4; fbreak; }; + 'DownTeeArrow;' => { output->first = 0x21a7; fbreak; }; + 'Downarrow;' => { output->first = 0x21d3; fbreak; }; + 'Dscr;' => { output->first = 0x0001d49f; fbreak; }; + 'Dstrok;' => { output->first = 0x0110; fbreak; }; + 'ENG;' => { output->first = 0x014a; fbreak; }; + 'ETH;' => { output->first = 0xd0; fbreak; }; + 'ETH' => { output->first = 0xd0; fbreak; }; + 'Eacute;' => { output->first = 0xc9; fbreak; }; + 'Eacute' => { output->first = 0xc9; fbreak; }; + 'Ecaron;' => { output->first = 0x011a; fbreak; }; + 'Ecirc;' => { output->first = 0xca; fbreak; }; + 'Ecirc' => { output->first = 0xca; fbreak; }; + 'Ecy;' => { output->first = 0x042d; fbreak; }; + 'Edot;' => { output->first = 0x0116; fbreak; }; + 'Efr;' => { output->first = 0x0001d508; fbreak; }; + 'Egrave;' => { output->first = 0xc8; fbreak; }; + 'Egrave' => { output->first = 0xc8; fbreak; }; + 'Element;' => { output->first = 0x2208; fbreak; }; + 'Emacr;' => { output->first = 0x0112; fbreak; }; + 'EmptySmallSquare;' => { output->first = 0x25fb; fbreak; }; + 'EmptyVerySmallSquare;' => { output->first = 0x25ab; fbreak; }; + 'Eogon;' => { output->first = 0x0118; fbreak; }; + 'Eopf;' => { output->first = 0x0001d53c; fbreak; }; + 'Epsilon;' => { output->first = 0x0395; fbreak; }; + 'Equal;' => { output->first = 0x2a75; fbreak; }; + 'EqualTilde;' => { output->first = 0x2242; fbreak; }; + 'Equilibrium;' => { output->first = 0x21cc; fbreak; }; + 'Escr;' => { output->first = 0x2130; fbreak; }; + 'Esim;' => { output->first = 0x2a73; fbreak; }; + 'Eta;' => { output->first = 0x0397; fbreak; }; + 'Euml;' => { output->first = 0xcb; fbreak; }; + 'Euml' => { output->first = 0xcb; fbreak; }; + 'Exists;' => { output->first = 0x2203; fbreak; }; + 'ExponentialE;' => { output->first = 0x2147; fbreak; }; + 'Fcy;' => { output->first = 0x0424; fbreak; }; + 'Ffr;' => { output->first = 0x0001d509; fbreak; }; + 'FilledSmallSquare;' => { output->first = 0x25fc; fbreak; }; + 'FilledVerySmallSquare;' => { output->first = 0x25aa; fbreak; }; + 'Fopf;' => { output->first = 0x0001d53d; fbreak; }; + 'ForAll;' => { output->first = 0x2200; fbreak; }; + 'Fouriertrf;' => { output->first = 0x2131; fbreak; }; + 'Fscr;' => { output->first = 0x2131; fbreak; }; + 'GJcy;' => { output->first = 0x0403; fbreak; }; + 'GT;' => { output->first = 0x3e; fbreak; }; + 'GT' => { output->first = 0x3e; fbreak; }; + 'Gamma;' => { output->first = 0x0393; fbreak; }; + 'Gammad;' => { output->first = 0x03dc; fbreak; }; + 'Gbreve;' => { output->first = 0x011e; fbreak; }; + 'Gcedil;' => { output->first = 0x0122; fbreak; }; + 'Gcirc;' => { output->first = 0x011c; fbreak; }; + 'Gcy;' => { output->first = 0x0413; fbreak; }; + 'Gdot;' => { output->first = 0x0120; fbreak; }; + 'Gfr;' => { output->first = 0x0001d50a; fbreak; }; + 'Gg;' => { output->first = 0x22d9; fbreak; }; + 'Gopf;' => { output->first = 0x0001d53e; fbreak; }; + 'GreaterEqual;' => { output->first = 0x2265; fbreak; }; + 'GreaterEqualLess;' => { output->first = 0x22db; fbreak; }; + 'GreaterFullEqual;' => { output->first = 0x2267; fbreak; }; + 'GreaterGreater;' => { output->first = 0x2aa2; fbreak; }; + 'GreaterLess;' => { output->first = 0x2277; fbreak; }; + 'GreaterSlantEqual;' => { output->first = 0x2a7e; fbreak; }; + 'GreaterTilde;' => { output->first = 0x2273; fbreak; }; + 'Gscr;' => { output->first = 0x0001d4a2; fbreak; }; + 'Gt;' => { output->first = 0x226b; fbreak; }; + 'HARDcy;' => { output->first = 0x042a; fbreak; }; + 'Hacek;' => { output->first = 0x02c7; fbreak; }; + 'Hat;' => { output->first = 0x5e; fbreak; }; + 'Hcirc;' => { output->first = 0x0124; fbreak; }; + 'Hfr;' => { output->first = 0x210c; fbreak; }; + 'HilbertSpace;' => { output->first = 0x210b; fbreak; }; + 'Hopf;' => { output->first = 0x210d; fbreak; }; + 'HorizontalLine;' => { output->first = 0x2500; fbreak; }; + 'Hscr;' => { output->first = 0x210b; fbreak; }; + 'Hstrok;' => { output->first = 0x0126; fbreak; }; + 'HumpDownHump;' => { output->first = 0x224e; fbreak; }; + 'HumpEqual;' => { output->first = 0x224f; fbreak; }; + 'IEcy;' => { output->first = 0x0415; fbreak; }; + 'IJlig;' => { output->first = 0x0132; fbreak; }; + 'IOcy;' => { output->first = 0x0401; fbreak; }; + 'Iacute;' => { output->first = 0xcd; fbreak; }; + 'Iacute' => { output->first = 0xcd; fbreak; }; + 'Icirc;' => { output->first = 0xce; fbreak; }; + 'Icirc' => { output->first = 0xce; fbreak; }; + 'Icy;' => { output->first = 0x0418; fbreak; }; + 'Idot;' => { output->first = 0x0130; fbreak; }; + 'Ifr;' => { output->first = 0x2111; fbreak; }; + 'Igrave;' => { output->first = 0xcc; fbreak; }; + 'Igrave' => { output->first = 0xcc; fbreak; }; + 'Im;' => { output->first = 0x2111; fbreak; }; + 'Imacr;' => { output->first = 0x012a; fbreak; }; + 'ImaginaryI;' => { output->first = 0x2148; fbreak; }; + 'Implies;' => { output->first = 0x21d2; fbreak; }; + 'Int;' => { output->first = 0x222c; fbreak; }; + 'Integral;' => { output->first = 0x222b; fbreak; }; + 'Intersection;' => { output->first = 0x22c2; fbreak; }; + 'InvisibleComma;' => { output->first = 0x2063; fbreak; }; + 'InvisibleTimes;' => { output->first = 0x2062; fbreak; }; + 'Iogon;' => { output->first = 0x012e; fbreak; }; + 'Iopf;' => { output->first = 0x0001d540; fbreak; }; + 'Iota;' => { output->first = 0x0399; fbreak; }; + 'Iscr;' => { output->first = 0x2110; fbreak; }; + 'Itilde;' => { output->first = 0x0128; fbreak; }; + 'Iukcy;' => { output->first = 0x0406; fbreak; }; + 'Iuml;' => { output->first = 0xcf; fbreak; }; + 'Iuml' => { output->first = 0xcf; fbreak; }; + 'Jcirc;' => { output->first = 0x0134; fbreak; }; + 'Jcy;' => { output->first = 0x0419; fbreak; }; + 'Jfr;' => { output->first = 0x0001d50d; fbreak; }; + 'Jopf;' => { output->first = 0x0001d541; fbreak; }; + 'Jscr;' => { output->first = 0x0001d4a5; fbreak; }; + 'Jsercy;' => { output->first = 0x0408; fbreak; }; + 'Jukcy;' => { output->first = 0x0404; fbreak; }; + 'KHcy;' => { output->first = 0x0425; fbreak; }; + 'KJcy;' => { output->first = 0x040c; fbreak; }; + 'Kappa;' => { output->first = 0x039a; fbreak; }; + 'Kcedil;' => { output->first = 0x0136; fbreak; }; + 'Kcy;' => { output->first = 0x041a; fbreak; }; + 'Kfr;' => { output->first = 0x0001d50e; fbreak; }; + 'Kopf;' => { output->first = 0x0001d542; fbreak; }; + 'Kscr;' => { output->first = 0x0001d4a6; fbreak; }; + 'LJcy;' => { output->first = 0x0409; fbreak; }; + 'LT;' => { output->first = 0x3c; fbreak; }; + 'LT' => { output->first = 0x3c; fbreak; }; + 'Lacute;' => { output->first = 0x0139; fbreak; }; + 'Lambda;' => { output->first = 0x039b; fbreak; }; + 'Lang;' => { output->first = 0x27ea; fbreak; }; + 'Laplacetrf;' => { output->first = 0x2112; fbreak; }; + 'Larr;' => { output->first = 0x219e; fbreak; }; + 'Lcaron;' => { output->first = 0x013d; fbreak; }; + 'Lcedil;' => { output->first = 0x013b; fbreak; }; + 'Lcy;' => { output->first = 0x041b; fbreak; }; + 'LeftAngleBracket;' => { output->first = 0x27e8; fbreak; }; + 'LeftArrow;' => { output->first = 0x2190; fbreak; }; + 'LeftArrowBar;' => { output->first = 0x21e4; fbreak; }; + 'LeftArrowRightArrow;' => { output->first = 0x21c6; fbreak; }; + 'LeftCeiling;' => { output->first = 0x2308; fbreak; }; + 'LeftDoubleBracket;' => { output->first = 0x27e6; fbreak; }; + 'LeftDownTeeVector;' => { output->first = 0x2961; fbreak; }; + 'LeftDownVector;' => { output->first = 0x21c3; fbreak; }; + 'LeftDownVectorBar;' => { output->first = 0x2959; fbreak; }; + 'LeftFloor;' => { output->first = 0x230a; fbreak; }; + 'LeftRightArrow;' => { output->first = 0x2194; fbreak; }; + 'LeftRightVector;' => { output->first = 0x294e; fbreak; }; + 'LeftTee;' => { output->first = 0x22a3; fbreak; }; + 'LeftTeeArrow;' => { output->first = 0x21a4; fbreak; }; + 'LeftTeeVector;' => { output->first = 0x295a; fbreak; }; + 'LeftTriangle;' => { output->first = 0x22b2; fbreak; }; + 'LeftTriangleBar;' => { output->first = 0x29cf; fbreak; }; + 'LeftTriangleEqual;' => { output->first = 0x22b4; fbreak; }; + 'LeftUpDownVector;' => { output->first = 0x2951; fbreak; }; + 'LeftUpTeeVector;' => { output->first = 0x2960; fbreak; }; + 'LeftUpVector;' => { output->first = 0x21bf; fbreak; }; + 'LeftUpVectorBar;' => { output->first = 0x2958; fbreak; }; + 'LeftVector;' => { output->first = 0x21bc; fbreak; }; + 'LeftVectorBar;' => { output->first = 0x2952; fbreak; }; + 'Leftarrow;' => { output->first = 0x21d0; fbreak; }; + 'Leftrightarrow;' => { output->first = 0x21d4; fbreak; }; + 'LessEqualGreater;' => { output->first = 0x22da; fbreak; }; + 'LessFullEqual;' => { output->first = 0x2266; fbreak; }; + 'LessGreater;' => { output->first = 0x2276; fbreak; }; + 'LessLess;' => { output->first = 0x2aa1; fbreak; }; + 'LessSlantEqual;' => { output->first = 0x2a7d; fbreak; }; + 'LessTilde;' => { output->first = 0x2272; fbreak; }; + 'Lfr;' => { output->first = 0x0001d50f; fbreak; }; + 'Ll;' => { output->first = 0x22d8; fbreak; }; + 'Lleftarrow;' => { output->first = 0x21da; fbreak; }; + 'Lmidot;' => { output->first = 0x013f; fbreak; }; + 'LongLeftArrow;' => { output->first = 0x27f5; fbreak; }; + 'LongLeftRightArrow;' => { output->first = 0x27f7; fbreak; }; + 'LongRightArrow;' => { output->first = 0x27f6; fbreak; }; + 'Longleftarrow;' => { output->first = 0x27f8; fbreak; }; + 'Longleftrightarrow;' => { output->first = 0x27fa; fbreak; }; + 'Longrightarrow;' => { output->first = 0x27f9; fbreak; }; + 'Lopf;' => { output->first = 0x0001d543; fbreak; }; + 'LowerLeftArrow;' => { output->first = 0x2199; fbreak; }; + 'LowerRightArrow;' => { output->first = 0x2198; fbreak; }; + 'Lscr;' => { output->first = 0x2112; fbreak; }; + 'Lsh;' => { output->first = 0x21b0; fbreak; }; + 'Lstrok;' => { output->first = 0x0141; fbreak; }; + 'Lt;' => { output->first = 0x226a; fbreak; }; + 'Map;' => { output->first = 0x2905; fbreak; }; + 'Mcy;' => { output->first = 0x041c; fbreak; }; + 'MediumSpace;' => { output->first = 0x205f; fbreak; }; + 'Mellintrf;' => { output->first = 0x2133; fbreak; }; + 'Mfr;' => { output->first = 0x0001d510; fbreak; }; + 'MinusPlus;' => { output->first = 0x2213; fbreak; }; + 'Mopf;' => { output->first = 0x0001d544; fbreak; }; + 'Mscr;' => { output->first = 0x2133; fbreak; }; + 'Mu;' => { output->first = 0x039c; fbreak; }; + 'NJcy;' => { output->first = 0x040a; fbreak; }; + 'Nacute;' => { output->first = 0x0143; fbreak; }; + 'Ncaron;' => { output->first = 0x0147; fbreak; }; + 'Ncedil;' => { output->first = 0x0145; fbreak; }; + 'Ncy;' => { output->first = 0x041d; fbreak; }; + 'NegativeMediumSpace;' => { output->first = 0x200b; fbreak; }; + 'NegativeThickSpace;' => { output->first = 0x200b; fbreak; }; + 'NegativeThinSpace;' => { output->first = 0x200b; fbreak; }; + 'NegativeVeryThinSpace;' => { output->first = 0x200b; fbreak; }; + 'NestedGreaterGreater;' => { output->first = 0x226b; fbreak; }; + 'NestedLessLess;' => { output->first = 0x226a; fbreak; }; + 'NewLine;' => { output->first = 0x0a; fbreak; }; + 'Nfr;' => { output->first = 0x0001d511; fbreak; }; + 'NoBreak;' => { output->first = 0x2060; fbreak; }; + 'NonBreakingSpace;' => { output->first = 0xa0; fbreak; }; + 'Nopf;' => { output->first = 0x2115; fbreak; }; + 'Not;' => { output->first = 0x2aec; fbreak; }; + 'NotCongruent;' => { output->first = 0x2262; fbreak; }; + 'NotCupCap;' => { output->first = 0x226d; fbreak; }; + 'NotDoubleVerticalBar;' => { output->first = 0x2226; fbreak; }; + 'NotElement;' => { output->first = 0x2209; fbreak; }; + 'NotEqual;' => { output->first = 0x2260; fbreak; }; + 'NotEqualTilde;' => { output->first = 0x2242; output->second = 0x0338; fbreak; }; + 'NotExists;' => { output->first = 0x2204; fbreak; }; + 'NotGreater;' => { output->first = 0x226f; fbreak; }; + 'NotGreaterEqual;' => { output->first = 0x2271; fbreak; }; + 'NotGreaterFullEqual;' => { output->first = 0x2267; output->second = 0x0338; fbreak; }; + 'NotGreaterGreater;' => { output->first = 0x226b; output->second = 0x0338; fbreak; }; + 'NotGreaterLess;' => { output->first = 0x2279; fbreak; }; + 'NotGreaterSlantEqual;' => { output->first = 0x2a7e; output->second = 0x0338; fbreak; }; + 'NotGreaterTilde;' => { output->first = 0x2275; fbreak; }; + 'NotHumpDownHump;' => { output->first = 0x224e; output->second = 0x0338; fbreak; }; + 'NotHumpEqual;' => { output->first = 0x224f; output->second = 0x0338; fbreak; }; + 'NotLeftTriangle;' => { output->first = 0x22ea; fbreak; }; + 'NotLeftTriangleBar;' => { output->first = 0x29cf; output->second = 0x0338; fbreak; }; + 'NotLeftTriangleEqual;' => { output->first = 0x22ec; fbreak; }; + 'NotLess;' => { output->first = 0x226e; fbreak; }; + 'NotLessEqual;' => { output->first = 0x2270; fbreak; }; + 'NotLessGreater;' => { output->first = 0x2278; fbreak; }; + 'NotLessLess;' => { output->first = 0x226a; output->second = 0x0338; fbreak; }; + 'NotLessSlantEqual;' => { output->first = 0x2a7d; output->second = 0x0338; fbreak; }; + 'NotLessTilde;' => { output->first = 0x2274; fbreak; }; + 'NotNestedGreaterGreater;' => { output->first = 0x2aa2; output->second = 0x0338; fbreak; }; + 'NotNestedLessLess;' => { output->first = 0x2aa1; output->second = 0x0338; fbreak; }; + 'NotPrecedes;' => { output->first = 0x2280; fbreak; }; + 'NotPrecedesEqual;' => { output->first = 0x2aaf; output->second = 0x0338; fbreak; }; + 'NotPrecedesSlantEqual;' => { output->first = 0x22e0; fbreak; }; + 'NotReverseElement;' => { output->first = 0x220c; fbreak; }; + 'NotRightTriangle;' => { output->first = 0x22eb; fbreak; }; + 'NotRightTriangleBar;' => { output->first = 0x29d0; output->second = 0x0338; fbreak; }; + 'NotRightTriangleEqual;' => { output->first = 0x22ed; fbreak; }; + 'NotSquareSubset;' => { output->first = 0x228f; output->second = 0x0338; fbreak; }; + 'NotSquareSubsetEqual;' => { output->first = 0x22e2; fbreak; }; + 'NotSquareSuperset;' => { output->first = 0x2290; output->second = 0x0338; fbreak; }; + 'NotSquareSupersetEqual;' => { output->first = 0x22e3; fbreak; }; + 'NotSubset;' => { output->first = 0x2282; output->second = 0x20d2; fbreak; }; + 'NotSubsetEqual;' => { output->first = 0x2288; fbreak; }; + 'NotSucceeds;' => { output->first = 0x2281; fbreak; }; + 'NotSucceedsEqual;' => { output->first = 0x2ab0; output->second = 0x0338; fbreak; }; + 'NotSucceedsSlantEqual;' => { output->first = 0x22e1; fbreak; }; + 'NotSucceedsTilde;' => { output->first = 0x227f; output->second = 0x0338; fbreak; }; + 'NotSuperset;' => { output->first = 0x2283; output->second = 0x20d2; fbreak; }; + 'NotSupersetEqual;' => { output->first = 0x2289; fbreak; }; + 'NotTilde;' => { output->first = 0x2241; fbreak; }; + 'NotTildeEqual;' => { output->first = 0x2244; fbreak; }; + 'NotTildeFullEqual;' => { output->first = 0x2247; fbreak; }; + 'NotTildeTilde;' => { output->first = 0x2249; fbreak; }; + 'NotVerticalBar;' => { output->first = 0x2224; fbreak; }; + 'Nscr;' => { output->first = 0x0001d4a9; fbreak; }; + 'Ntilde;' => { output->first = 0xd1; fbreak; }; + 'Ntilde' => { output->first = 0xd1; fbreak; }; + 'Nu;' => { output->first = 0x039d; fbreak; }; + 'OElig;' => { output->first = 0x0152; fbreak; }; + 'Oacute;' => { output->first = 0xd3; fbreak; }; + 'Oacute' => { output->first = 0xd3; fbreak; }; + 'Ocirc;' => { output->first = 0xd4; fbreak; }; + 'Ocirc' => { output->first = 0xd4; fbreak; }; + 'Ocy;' => { output->first = 0x041e; fbreak; }; + 'Odblac;' => { output->first = 0x0150; fbreak; }; + 'Ofr;' => { output->first = 0x0001d512; fbreak; }; + 'Ograve;' => { output->first = 0xd2; fbreak; }; + 'Ograve' => { output->first = 0xd2; fbreak; }; + 'Omacr;' => { output->first = 0x014c; fbreak; }; + 'Omega;' => { output->first = 0x03a9; fbreak; }; + 'Omicron;' => { output->first = 0x039f; fbreak; }; + 'Oopf;' => { output->first = 0x0001d546; fbreak; }; + 'OpenCurlyDoubleQuote;' => { output->first = 0x201c; fbreak; }; + 'OpenCurlyQuote;' => { output->first = 0x2018; fbreak; }; + 'Or;' => { output->first = 0x2a54; fbreak; }; + 'Oscr;' => { output->first = 0x0001d4aa; fbreak; }; + 'Oslash;' => { output->first = 0xd8; fbreak; }; + 'Oslash' => { output->first = 0xd8; fbreak; }; + 'Otilde;' => { output->first = 0xd5; fbreak; }; + 'Otilde' => { output->first = 0xd5; fbreak; }; + 'Otimes;' => { output->first = 0x2a37; fbreak; }; + 'Ouml;' => { output->first = 0xd6; fbreak; }; + 'Ouml' => { output->first = 0xd6; fbreak; }; + 'OverBar;' => { output->first = 0x203e; fbreak; }; + 'OverBrace;' => { output->first = 0x23de; fbreak; }; + 'OverBracket;' => { output->first = 0x23b4; fbreak; }; + 'OverParenthesis;' => { output->first = 0x23dc; fbreak; }; + 'PartialD;' => { output->first = 0x2202; fbreak; }; + 'Pcy;' => { output->first = 0x041f; fbreak; }; + 'Pfr;' => { output->first = 0x0001d513; fbreak; }; + 'Phi;' => { output->first = 0x03a6; fbreak; }; + 'Pi;' => { output->first = 0x03a0; fbreak; }; + 'PlusMinus;' => { output->first = 0xb1; fbreak; }; + 'Poincareplane;' => { output->first = 0x210c; fbreak; }; + 'Popf;' => { output->first = 0x2119; fbreak; }; + 'Pr;' => { output->first = 0x2abb; fbreak; }; + 'Precedes;' => { output->first = 0x227a; fbreak; }; + 'PrecedesEqual;' => { output->first = 0x2aaf; fbreak; }; + 'PrecedesSlantEqual;' => { output->first = 0x227c; fbreak; }; + 'PrecedesTilde;' => { output->first = 0x227e; fbreak; }; + 'Prime;' => { output->first = 0x2033; fbreak; }; + 'Product;' => { output->first = 0x220f; fbreak; }; + 'Proportion;' => { output->first = 0x2237; fbreak; }; + 'Proportional;' => { output->first = 0x221d; fbreak; }; + 'Pscr;' => { output->first = 0x0001d4ab; fbreak; }; + 'Psi;' => { output->first = 0x03a8; fbreak; }; + 'QUOT;' => { output->first = 0x22; fbreak; }; + 'QUOT' => { output->first = 0x22; fbreak; }; + 'Qfr;' => { output->first = 0x0001d514; fbreak; }; + 'Qopf;' => { output->first = 0x211a; fbreak; }; + 'Qscr;' => { output->first = 0x0001d4ac; fbreak; }; + 'RBarr;' => { output->first = 0x2910; fbreak; }; + 'REG;' => { output->first = 0xae; fbreak; }; + 'REG' => { output->first = 0xae; fbreak; }; + 'Racute;' => { output->first = 0x0154; fbreak; }; + 'Rang;' => { output->first = 0x27eb; fbreak; }; + 'Rarr;' => { output->first = 0x21a0; fbreak; }; + 'Rarrtl;' => { output->first = 0x2916; fbreak; }; + 'Rcaron;' => { output->first = 0x0158; fbreak; }; + 'Rcedil;' => { output->first = 0x0156; fbreak; }; + 'Rcy;' => { output->first = 0x0420; fbreak; }; + 'Re;' => { output->first = 0x211c; fbreak; }; + 'ReverseElement;' => { output->first = 0x220b; fbreak; }; + 'ReverseEquilibrium;' => { output->first = 0x21cb; fbreak; }; + 'ReverseUpEquilibrium;' => { output->first = 0x296f; fbreak; }; + 'Rfr;' => { output->first = 0x211c; fbreak; }; + 'Rho;' => { output->first = 0x03a1; fbreak; }; + 'RightAngleBracket;' => { output->first = 0x27e9; fbreak; }; + 'RightArrow;' => { output->first = 0x2192; fbreak; }; + 'RightArrowBar;' => { output->first = 0x21e5; fbreak; }; + 'RightArrowLeftArrow;' => { output->first = 0x21c4; fbreak; }; + 'RightCeiling;' => { output->first = 0x2309; fbreak; }; + 'RightDoubleBracket;' => { output->first = 0x27e7; fbreak; }; + 'RightDownTeeVector;' => { output->first = 0x295d; fbreak; }; + 'RightDownVector;' => { output->first = 0x21c2; fbreak; }; + 'RightDownVectorBar;' => { output->first = 0x2955; fbreak; }; + 'RightFloor;' => { output->first = 0x230b; fbreak; }; + 'RightTee;' => { output->first = 0x22a2; fbreak; }; + 'RightTeeArrow;' => { output->first = 0x21a6; fbreak; }; + 'RightTeeVector;' => { output->first = 0x295b; fbreak; }; + 'RightTriangle;' => { output->first = 0x22b3; fbreak; }; + 'RightTriangleBar;' => { output->first = 0x29d0; fbreak; }; + 'RightTriangleEqual;' => { output->first = 0x22b5; fbreak; }; + 'RightUpDownVector;' => { output->first = 0x294f; fbreak; }; + 'RightUpTeeVector;' => { output->first = 0x295c; fbreak; }; + 'RightUpVector;' => { output->first = 0x21be; fbreak; }; + 'RightUpVectorBar;' => { output->first = 0x2954; fbreak; }; + 'RightVector;' => { output->first = 0x21c0; fbreak; }; + 'RightVectorBar;' => { output->first = 0x2953; fbreak; }; + 'Rightarrow;' => { output->first = 0x21d2; fbreak; }; + 'Ropf;' => { output->first = 0x211d; fbreak; }; + 'RoundImplies;' => { output->first = 0x2970; fbreak; }; + 'Rrightarrow;' => { output->first = 0x21db; fbreak; }; + 'Rscr;' => { output->first = 0x211b; fbreak; }; + 'Rsh;' => { output->first = 0x21b1; fbreak; }; + 'RuleDelayed;' => { output->first = 0x29f4; fbreak; }; + 'SHCHcy;' => { output->first = 0x0429; fbreak; }; + 'SHcy;' => { output->first = 0x0428; fbreak; }; + 'SOFTcy;' => { output->first = 0x042c; fbreak; }; + 'Sacute;' => { output->first = 0x015a; fbreak; }; + 'Sc;' => { output->first = 0x2abc; fbreak; }; + 'Scaron;' => { output->first = 0x0160; fbreak; }; + 'Scedil;' => { output->first = 0x015e; fbreak; }; + 'Scirc;' => { output->first = 0x015c; fbreak; }; + 'Scy;' => { output->first = 0x0421; fbreak; }; + 'Sfr;' => { output->first = 0x0001d516; fbreak; }; + 'ShortDownArrow;' => { output->first = 0x2193; fbreak; }; + 'ShortLeftArrow;' => { output->first = 0x2190; fbreak; }; + 'ShortRightArrow;' => { output->first = 0x2192; fbreak; }; + 'ShortUpArrow;' => { output->first = 0x2191; fbreak; }; + 'Sigma;' => { output->first = 0x03a3; fbreak; }; + 'SmallCircle;' => { output->first = 0x2218; fbreak; }; + 'Sopf;' => { output->first = 0x0001d54a; fbreak; }; + 'Sqrt;' => { output->first = 0x221a; fbreak; }; + 'Square;' => { output->first = 0x25a1; fbreak; }; + 'SquareIntersection;' => { output->first = 0x2293; fbreak; }; + 'SquareSubset;' => { output->first = 0x228f; fbreak; }; + 'SquareSubsetEqual;' => { output->first = 0x2291; fbreak; }; + 'SquareSuperset;' => { output->first = 0x2290; fbreak; }; + 'SquareSupersetEqual;' => { output->first = 0x2292; fbreak; }; + 'SquareUnion;' => { output->first = 0x2294; fbreak; }; + 'Sscr;' => { output->first = 0x0001d4ae; fbreak; }; + 'Star;' => { output->first = 0x22c6; fbreak; }; + 'Sub;' => { output->first = 0x22d0; fbreak; }; + 'Subset;' => { output->first = 0x22d0; fbreak; }; + 'SubsetEqual;' => { output->first = 0x2286; fbreak; }; + 'Succeeds;' => { output->first = 0x227b; fbreak; }; + 'SucceedsEqual;' => { output->first = 0x2ab0; fbreak; }; + 'SucceedsSlantEqual;' => { output->first = 0x227d; fbreak; }; + 'SucceedsTilde;' => { output->first = 0x227f; fbreak; }; + 'SuchThat;' => { output->first = 0x220b; fbreak; }; + 'Sum;' => { output->first = 0x2211; fbreak; }; + 'Sup;' => { output->first = 0x22d1; fbreak; }; + 'Superset;' => { output->first = 0x2283; fbreak; }; + 'SupersetEqual;' => { output->first = 0x2287; fbreak; }; + 'Supset;' => { output->first = 0x22d1; fbreak; }; + 'THORN;' => { output->first = 0xde; fbreak; }; + 'THORN' => { output->first = 0xde; fbreak; }; + 'TRADE;' => { output->first = 0x2122; fbreak; }; + 'TSHcy;' => { output->first = 0x040b; fbreak; }; + 'TScy;' => { output->first = 0x0426; fbreak; }; + 'Tab;' => { output->first = 0x09; fbreak; }; + 'Tau;' => { output->first = 0x03a4; fbreak; }; + 'Tcaron;' => { output->first = 0x0164; fbreak; }; + 'Tcedil;' => { output->first = 0x0162; fbreak; }; + 'Tcy;' => { output->first = 0x0422; fbreak; }; + 'Tfr;' => { output->first = 0x0001d517; fbreak; }; + 'Therefore;' => { output->first = 0x2234; fbreak; }; + 'Theta;' => { output->first = 0x0398; fbreak; }; + 'ThickSpace;' => { output->first = 0x205f; output->second = 0x200a; fbreak; }; + 'ThinSpace;' => { output->first = 0x2009; fbreak; }; + 'Tilde;' => { output->first = 0x223c; fbreak; }; + 'TildeEqual;' => { output->first = 0x2243; fbreak; }; + 'TildeFullEqual;' => { output->first = 0x2245; fbreak; }; + 'TildeTilde;' => { output->first = 0x2248; fbreak; }; + 'Topf;' => { output->first = 0x0001d54b; fbreak; }; + 'TripleDot;' => { output->first = 0x20db; fbreak; }; + 'Tscr;' => { output->first = 0x0001d4af; fbreak; }; + 'Tstrok;' => { output->first = 0x0166; fbreak; }; + 'Uacute;' => { output->first = 0xda; fbreak; }; + 'Uacute' => { output->first = 0xda; fbreak; }; + 'Uarr;' => { output->first = 0x219f; fbreak; }; + 'Uarrocir;' => { output->first = 0x2949; fbreak; }; + 'Ubrcy;' => { output->first = 0x040e; fbreak; }; + 'Ubreve;' => { output->first = 0x016c; fbreak; }; + 'Ucirc;' => { output->first = 0xdb; fbreak; }; + 'Ucirc' => { output->first = 0xdb; fbreak; }; + 'Ucy;' => { output->first = 0x0423; fbreak; }; + 'Udblac;' => { output->first = 0x0170; fbreak; }; + 'Ufr;' => { output->first = 0x0001d518; fbreak; }; + 'Ugrave;' => { output->first = 0xd9; fbreak; }; + 'Ugrave' => { output->first = 0xd9; fbreak; }; + 'Umacr;' => { output->first = 0x016a; fbreak; }; + 'UnderBar;' => { output->first = 0x5f; fbreak; }; + 'UnderBrace;' => { output->first = 0x23df; fbreak; }; + 'UnderBracket;' => { output->first = 0x23b5; fbreak; }; + 'UnderParenthesis;' => { output->first = 0x23dd; fbreak; }; + 'Union;' => { output->first = 0x22c3; fbreak; }; + 'UnionPlus;' => { output->first = 0x228e; fbreak; }; + 'Uogon;' => { output->first = 0x0172; fbreak; }; + 'Uopf;' => { output->first = 0x0001d54c; fbreak; }; + 'UpArrow;' => { output->first = 0x2191; fbreak; }; + 'UpArrowBar;' => { output->first = 0x2912; fbreak; }; + 'UpArrowDownArrow;' => { output->first = 0x21c5; fbreak; }; + 'UpDownArrow;' => { output->first = 0x2195; fbreak; }; + 'UpEquilibrium;' => { output->first = 0x296e; fbreak; }; + 'UpTee;' => { output->first = 0x22a5; fbreak; }; + 'UpTeeArrow;' => { output->first = 0x21a5; fbreak; }; + 'Uparrow;' => { output->first = 0x21d1; fbreak; }; + 'Updownarrow;' => { output->first = 0x21d5; fbreak; }; + 'UpperLeftArrow;' => { output->first = 0x2196; fbreak; }; + 'UpperRightArrow;' => { output->first = 0x2197; fbreak; }; + 'Upsi;' => { output->first = 0x03d2; fbreak; }; + 'Upsilon;' => { output->first = 0x03a5; fbreak; }; + 'Uring;' => { output->first = 0x016e; fbreak; }; + 'Uscr;' => { output->first = 0x0001d4b0; fbreak; }; + 'Utilde;' => { output->first = 0x0168; fbreak; }; + 'Uuml;' => { output->first = 0xdc; fbreak; }; + 'Uuml' => { output->first = 0xdc; fbreak; }; + 'VDash;' => { output->first = 0x22ab; fbreak; }; + 'Vbar;' => { output->first = 0x2aeb; fbreak; }; + 'Vcy;' => { output->first = 0x0412; fbreak; }; + 'Vdash;' => { output->first = 0x22a9; fbreak; }; + 'Vdashl;' => { output->first = 0x2ae6; fbreak; }; + 'Vee;' => { output->first = 0x22c1; fbreak; }; + 'Verbar;' => { output->first = 0x2016; fbreak; }; + 'Vert;' => { output->first = 0x2016; fbreak; }; + 'VerticalBar;' => { output->first = 0x2223; fbreak; }; + 'VerticalLine;' => { output->first = 0x7c; fbreak; }; + 'VerticalSeparator;' => { output->first = 0x2758; fbreak; }; + 'VerticalTilde;' => { output->first = 0x2240; fbreak; }; + 'VeryThinSpace;' => { output->first = 0x200a; fbreak; }; + 'Vfr;' => { output->first = 0x0001d519; fbreak; }; + 'Vopf;' => { output->first = 0x0001d54d; fbreak; }; + 'Vscr;' => { output->first = 0x0001d4b1; fbreak; }; + 'Vvdash;' => { output->first = 0x22aa; fbreak; }; + 'Wcirc;' => { output->first = 0x0174; fbreak; }; + 'Wedge;' => { output->first = 0x22c0; fbreak; }; + 'Wfr;' => { output->first = 0x0001d51a; fbreak; }; + 'Wopf;' => { output->first = 0x0001d54e; fbreak; }; + 'Wscr;' => { output->first = 0x0001d4b2; fbreak; }; + 'Xfr;' => { output->first = 0x0001d51b; fbreak; }; + 'Xi;' => { output->first = 0x039e; fbreak; }; + 'Xopf;' => { output->first = 0x0001d54f; fbreak; }; + 'Xscr;' => { output->first = 0x0001d4b3; fbreak; }; + 'YAcy;' => { output->first = 0x042f; fbreak; }; + 'YIcy;' => { output->first = 0x0407; fbreak; }; + 'YUcy;' => { output->first = 0x042e; fbreak; }; + 'Yacute;' => { output->first = 0xdd; fbreak; }; + 'Yacute' => { output->first = 0xdd; fbreak; }; + 'Ycirc;' => { output->first = 0x0176; fbreak; }; + 'Ycy;' => { output->first = 0x042b; fbreak; }; + 'Yfr;' => { output->first = 0x0001d51c; fbreak; }; + 'Yopf;' => { output->first = 0x0001d550; fbreak; }; + 'Yscr;' => { output->first = 0x0001d4b4; fbreak; }; + 'Yuml;' => { output->first = 0x0178; fbreak; }; + 'ZHcy;' => { output->first = 0x0416; fbreak; }; + 'Zacute;' => { output->first = 0x0179; fbreak; }; + 'Zcaron;' => { output->first = 0x017d; fbreak; }; + 'Zcy;' => { output->first = 0x0417; fbreak; }; + 'Zdot;' => { output->first = 0x017b; fbreak; }; + 'ZeroWidthSpace;' => { output->first = 0x200b; fbreak; }; + 'Zeta;' => { output->first = 0x0396; fbreak; }; + 'Zfr;' => { output->first = 0x2128; fbreak; }; + 'Zopf;' => { output->first = 0x2124; fbreak; }; + 'Zscr;' => { output->first = 0x0001d4b5; fbreak; }; + 'aacute;' => { output->first = 0xe1; fbreak; }; + 'aacute' => { output->first = 0xe1; fbreak; }; + 'abreve;' => { output->first = 0x0103; fbreak; }; + 'ac;' => { output->first = 0x223e; fbreak; }; + 'acE;' => { output->first = 0x223e; output->second = 0x0333; fbreak; }; + 'acd;' => { output->first = 0x223f; fbreak; }; + 'acirc;' => { output->first = 0xe2; fbreak; }; + 'acirc' => { output->first = 0xe2; fbreak; }; + 'acute;' => { output->first = 0xb4; fbreak; }; + 'acute' => { output->first = 0xb4; fbreak; }; + 'acy;' => { output->first = 0x0430; fbreak; }; + 'aelig;' => { output->first = 0xe6; fbreak; }; + 'aelig' => { output->first = 0xe6; fbreak; }; + 'af;' => { output->first = 0x2061; fbreak; }; + 'afr;' => { output->first = 0x0001d51e; fbreak; }; + 'agrave;' => { output->first = 0xe0; fbreak; }; + 'agrave' => { output->first = 0xe0; fbreak; }; + 'alefsym;' => { output->first = 0x2135; fbreak; }; + 'aleph;' => { output->first = 0x2135; fbreak; }; + 'alpha;' => { output->first = 0x03b1; fbreak; }; + 'amacr;' => { output->first = 0x0101; fbreak; }; + 'amalg;' => { output->first = 0x2a3f; fbreak; }; + 'amp;' => { output->first = 0x26; fbreak; }; + 'amp' => { output->first = 0x26; fbreak; }; + 'and;' => { output->first = 0x2227; fbreak; }; + 'andand;' => { output->first = 0x2a55; fbreak; }; + 'andd;' => { output->first = 0x2a5c; fbreak; }; + 'andslope;' => { output->first = 0x2a58; fbreak; }; + 'andv;' => { output->first = 0x2a5a; fbreak; }; + 'ang;' => { output->first = 0x2220; fbreak; }; + 'ange;' => { output->first = 0x29a4; fbreak; }; + 'angle;' => { output->first = 0x2220; fbreak; }; + 'angmsd;' => { output->first = 0x2221; fbreak; }; + 'angmsdaa;' => { output->first = 0x29a8; fbreak; }; + 'angmsdab;' => { output->first = 0x29a9; fbreak; }; + 'angmsdac;' => { output->first = 0x29aa; fbreak; }; + 'angmsdad;' => { output->first = 0x29ab; fbreak; }; + 'angmsdae;' => { output->first = 0x29ac; fbreak; }; + 'angmsdaf;' => { output->first = 0x29ad; fbreak; }; + 'angmsdag;' => { output->first = 0x29ae; fbreak; }; + 'angmsdah;' => { output->first = 0x29af; fbreak; }; + 'angrt;' => { output->first = 0x221f; fbreak; }; + 'angrtvb;' => { output->first = 0x22be; fbreak; }; + 'angrtvbd;' => { output->first = 0x299d; fbreak; }; + 'angsph;' => { output->first = 0x2222; fbreak; }; + 'angst;' => { output->first = 0xc5; fbreak; }; + 'angzarr;' => { output->first = 0x237c; fbreak; }; + 'aogon;' => { output->first = 0x0105; fbreak; }; + 'aopf;' => { output->first = 0x0001d552; fbreak; }; + 'ap;' => { output->first = 0x2248; fbreak; }; + 'apE;' => { output->first = 0x2a70; fbreak; }; + 'apacir;' => { output->first = 0x2a6f; fbreak; }; + 'ape;' => { output->first = 0x224a; fbreak; }; + 'apid;' => { output->first = 0x224b; fbreak; }; + 'apos;' => { output->first = 0x27; fbreak; }; + 'approx;' => { output->first = 0x2248; fbreak; }; + 'approxeq;' => { output->first = 0x224a; fbreak; }; + 'aring;' => { output->first = 0xe5; fbreak; }; + 'aring' => { output->first = 0xe5; fbreak; }; + 'ascr;' => { output->first = 0x0001d4b6; fbreak; }; + 'ast;' => { output->first = 0x2a; fbreak; }; + 'asymp;' => { output->first = 0x2248; fbreak; }; + 'asympeq;' => { output->first = 0x224d; fbreak; }; + 'atilde;' => { output->first = 0xe3; fbreak; }; + 'atilde' => { output->first = 0xe3; fbreak; }; + 'auml;' => { output->first = 0xe4; fbreak; }; + 'auml' => { output->first = 0xe4; fbreak; }; + 'awconint;' => { output->first = 0x2233; fbreak; }; + 'awint;' => { output->first = 0x2a11; fbreak; }; + 'bNot;' => { output->first = 0x2aed; fbreak; }; + 'backcong;' => { output->first = 0x224c; fbreak; }; + 'backepsilon;' => { output->first = 0x03f6; fbreak; }; + 'backprime;' => { output->first = 0x2035; fbreak; }; + 'backsim;' => { output->first = 0x223d; fbreak; }; + 'backsimeq;' => { output->first = 0x22cd; fbreak; }; + 'barvee;' => { output->first = 0x22bd; fbreak; }; + 'barwed;' => { output->first = 0x2305; fbreak; }; + 'barwedge;' => { output->first = 0x2305; fbreak; }; + 'bbrk;' => { output->first = 0x23b5; fbreak; }; + 'bbrktbrk;' => { output->first = 0x23b6; fbreak; }; + 'bcong;' => { output->first = 0x224c; fbreak; }; + 'bcy;' => { output->first = 0x0431; fbreak; }; + 'bdquo;' => { output->first = 0x201e; fbreak; }; + 'becaus;' => { output->first = 0x2235; fbreak; }; + 'because;' => { output->first = 0x2235; fbreak; }; + 'bemptyv;' => { output->first = 0x29b0; fbreak; }; + 'bepsi;' => { output->first = 0x03f6; fbreak; }; + 'bernou;' => { output->first = 0x212c; fbreak; }; + 'beta;' => { output->first = 0x03b2; fbreak; }; + 'beth;' => { output->first = 0x2136; fbreak; }; + 'between;' => { output->first = 0x226c; fbreak; }; + 'bfr;' => { output->first = 0x0001d51f; fbreak; }; + 'bigcap;' => { output->first = 0x22c2; fbreak; }; + 'bigcirc;' => { output->first = 0x25ef; fbreak; }; + 'bigcup;' => { output->first = 0x22c3; fbreak; }; + 'bigodot;' => { output->first = 0x2a00; fbreak; }; + 'bigoplus;' => { output->first = 0x2a01; fbreak; }; + 'bigotimes;' => { output->first = 0x2a02; fbreak; }; + 'bigsqcup;' => { output->first = 0x2a06; fbreak; }; + 'bigstar;' => { output->first = 0x2605; fbreak; }; + 'bigtriangledown;' => { output->first = 0x25bd; fbreak; }; + 'bigtriangleup;' => { output->first = 0x25b3; fbreak; }; + 'biguplus;' => { output->first = 0x2a04; fbreak; }; + 'bigvee;' => { output->first = 0x22c1; fbreak; }; + 'bigwedge;' => { output->first = 0x22c0; fbreak; }; + 'bkarow;' => { output->first = 0x290d; fbreak; }; + 'blacklozenge;' => { output->first = 0x29eb; fbreak; }; + 'blacksquare;' => { output->first = 0x25aa; fbreak; }; + 'blacktriangle;' => { output->first = 0x25b4; fbreak; }; + 'blacktriangledown;' => { output->first = 0x25be; fbreak; }; + 'blacktriangleleft;' => { output->first = 0x25c2; fbreak; }; + 'blacktriangleright;' => { output->first = 0x25b8; fbreak; }; + 'blank;' => { output->first = 0x2423; fbreak; }; + 'blk12;' => { output->first = 0x2592; fbreak; }; + 'blk14;' => { output->first = 0x2591; fbreak; }; + 'blk34;' => { output->first = 0x2593; fbreak; }; + 'block;' => { output->first = 0x2588; fbreak; }; + 'bne;' => { output->first = 0x3d; output->second = 0x20e5; fbreak; }; + 'bnequiv;' => { output->first = 0x2261; output->second = 0x20e5; fbreak; }; + 'bnot;' => { output->first = 0x2310; fbreak; }; + 'bopf;' => { output->first = 0x0001d553; fbreak; }; + 'bot;' => { output->first = 0x22a5; fbreak; }; + 'bottom;' => { output->first = 0x22a5; fbreak; }; + 'bowtie;' => { output->first = 0x22c8; fbreak; }; + 'boxDL;' => { output->first = 0x2557; fbreak; }; + 'boxDR;' => { output->first = 0x2554; fbreak; }; + 'boxDl;' => { output->first = 0x2556; fbreak; }; + 'boxDr;' => { output->first = 0x2553; fbreak; }; + 'boxH;' => { output->first = 0x2550; fbreak; }; + 'boxHD;' => { output->first = 0x2566; fbreak; }; + 'boxHU;' => { output->first = 0x2569; fbreak; }; + 'boxHd;' => { output->first = 0x2564; fbreak; }; + 'boxHu;' => { output->first = 0x2567; fbreak; }; + 'boxUL;' => { output->first = 0x255d; fbreak; }; + 'boxUR;' => { output->first = 0x255a; fbreak; }; + 'boxUl;' => { output->first = 0x255c; fbreak; }; + 'boxUr;' => { output->first = 0x2559; fbreak; }; + 'boxV;' => { output->first = 0x2551; fbreak; }; + 'boxVH;' => { output->first = 0x256c; fbreak; }; + 'boxVL;' => { output->first = 0x2563; fbreak; }; + 'boxVR;' => { output->first = 0x2560; fbreak; }; + 'boxVh;' => { output->first = 0x256b; fbreak; }; + 'boxVl;' => { output->first = 0x2562; fbreak; }; + 'boxVr;' => { output->first = 0x255f; fbreak; }; + 'boxbox;' => { output->first = 0x29c9; fbreak; }; + 'boxdL;' => { output->first = 0x2555; fbreak; }; + 'boxdR;' => { output->first = 0x2552; fbreak; }; + 'boxdl;' => { output->first = 0x2510; fbreak; }; + 'boxdr;' => { output->first = 0x250c; fbreak; }; + 'boxh;' => { output->first = 0x2500; fbreak; }; + 'boxhD;' => { output->first = 0x2565; fbreak; }; + 'boxhU;' => { output->first = 0x2568; fbreak; }; + 'boxhd;' => { output->first = 0x252c; fbreak; }; + 'boxhu;' => { output->first = 0x2534; fbreak; }; + 'boxminus;' => { output->first = 0x229f; fbreak; }; + 'boxplus;' => { output->first = 0x229e; fbreak; }; + 'boxtimes;' => { output->first = 0x22a0; fbreak; }; + 'boxuL;' => { output->first = 0x255b; fbreak; }; + 'boxuR;' => { output->first = 0x2558; fbreak; }; + 'boxul;' => { output->first = 0x2518; fbreak; }; + 'boxur;' => { output->first = 0x2514; fbreak; }; + 'boxv;' => { output->first = 0x2502; fbreak; }; + 'boxvH;' => { output->first = 0x256a; fbreak; }; + 'boxvL;' => { output->first = 0x2561; fbreak; }; + 'boxvR;' => { output->first = 0x255e; fbreak; }; + 'boxvh;' => { output->first = 0x253c; fbreak; }; + 'boxvl;' => { output->first = 0x2524; fbreak; }; + 'boxvr;' => { output->first = 0x251c; fbreak; }; + 'bprime;' => { output->first = 0x2035; fbreak; }; + 'breve;' => { output->first = 0x02d8; fbreak; }; + 'brvbar;' => { output->first = 0xa6; fbreak; }; + 'brvbar' => { output->first = 0xa6; fbreak; }; + 'bscr;' => { output->first = 0x0001d4b7; fbreak; }; + 'bsemi;' => { output->first = 0x204f; fbreak; }; + 'bsim;' => { output->first = 0x223d; fbreak; }; + 'bsime;' => { output->first = 0x22cd; fbreak; }; + 'bsol;' => { output->first = 0x5c; fbreak; }; + 'bsolb;' => { output->first = 0x29c5; fbreak; }; + 'bsolhsub;' => { output->first = 0x27c8; fbreak; }; + 'bull;' => { output->first = 0x2022; fbreak; }; + 'bullet;' => { output->first = 0x2022; fbreak; }; + 'bump;' => { output->first = 0x224e; fbreak; }; + 'bumpE;' => { output->first = 0x2aae; fbreak; }; + 'bumpe;' => { output->first = 0x224f; fbreak; }; + 'bumpeq;' => { output->first = 0x224f; fbreak; }; + 'cacute;' => { output->first = 0x0107; fbreak; }; + 'cap;' => { output->first = 0x2229; fbreak; }; + 'capand;' => { output->first = 0x2a44; fbreak; }; + 'capbrcup;' => { output->first = 0x2a49; fbreak; }; + 'capcap;' => { output->first = 0x2a4b; fbreak; }; + 'capcup;' => { output->first = 0x2a47; fbreak; }; + 'capdot;' => { output->first = 0x2a40; fbreak; }; + 'caps;' => { output->first = 0x2229; output->second = 0xfe00; fbreak; }; + 'caret;' => { output->first = 0x2041; fbreak; }; + 'caron;' => { output->first = 0x02c7; fbreak; }; + 'ccaps;' => { output->first = 0x2a4d; fbreak; }; + 'ccaron;' => { output->first = 0x010d; fbreak; }; + 'ccedil;' => { output->first = 0xe7; fbreak; }; + 'ccedil' => { output->first = 0xe7; fbreak; }; + 'ccirc;' => { output->first = 0x0109; fbreak; }; + 'ccups;' => { output->first = 0x2a4c; fbreak; }; + 'ccupssm;' => { output->first = 0x2a50; fbreak; }; + 'cdot;' => { output->first = 0x010b; fbreak; }; + 'cedil;' => { output->first = 0xb8; fbreak; }; + 'cedil' => { output->first = 0xb8; fbreak; }; + 'cemptyv;' => { output->first = 0x29b2; fbreak; }; + 'cent;' => { output->first = 0xa2; fbreak; }; + 'cent' => { output->first = 0xa2; fbreak; }; + 'centerdot;' => { output->first = 0xb7; fbreak; }; + 'cfr;' => { output->first = 0x0001d520; fbreak; }; + 'chcy;' => { output->first = 0x0447; fbreak; }; + 'check;' => { output->first = 0x2713; fbreak; }; + 'checkmark;' => { output->first = 0x2713; fbreak; }; + 'chi;' => { output->first = 0x03c7; fbreak; }; + 'cir;' => { output->first = 0x25cb; fbreak; }; + 'cirE;' => { output->first = 0x29c3; fbreak; }; + 'circ;' => { output->first = 0x02c6; fbreak; }; + 'circeq;' => { output->first = 0x2257; fbreak; }; + 'circlearrowleft;' => { output->first = 0x21ba; fbreak; }; + 'circlearrowright;' => { output->first = 0x21bb; fbreak; }; + 'circledR;' => { output->first = 0xae; fbreak; }; + 'circledS;' => { output->first = 0x24c8; fbreak; }; + 'circledast;' => { output->first = 0x229b; fbreak; }; + 'circledcirc;' => { output->first = 0x229a; fbreak; }; + 'circleddash;' => { output->first = 0x229d; fbreak; }; + 'cire;' => { output->first = 0x2257; fbreak; }; + 'cirfnint;' => { output->first = 0x2a10; fbreak; }; + 'cirmid;' => { output->first = 0x2aef; fbreak; }; + 'cirscir;' => { output->first = 0x29c2; fbreak; }; + 'clubs;' => { output->first = 0x2663; fbreak; }; + 'clubsuit;' => { output->first = 0x2663; fbreak; }; + 'colon;' => { output->first = 0x3a; fbreak; }; + 'colone;' => { output->first = 0x2254; fbreak; }; + 'coloneq;' => { output->first = 0x2254; fbreak; }; + 'comma;' => { output->first = 0x2c; fbreak; }; + 'commat;' => { output->first = 0x40; fbreak; }; + 'comp;' => { output->first = 0x2201; fbreak; }; + 'compfn;' => { output->first = 0x2218; fbreak; }; + 'complement;' => { output->first = 0x2201; fbreak; }; + 'complexes;' => { output->first = 0x2102; fbreak; }; + 'cong;' => { output->first = 0x2245; fbreak; }; + 'congdot;' => { output->first = 0x2a6d; fbreak; }; + 'conint;' => { output->first = 0x222e; fbreak; }; + 'copf;' => { output->first = 0x0001d554; fbreak; }; + 'coprod;' => { output->first = 0x2210; fbreak; }; + 'copy;' => { output->first = 0xa9; fbreak; }; + 'copy' => { output->first = 0xa9; fbreak; }; + 'copysr;' => { output->first = 0x2117; fbreak; }; + 'crarr;' => { output->first = 0x21b5; fbreak; }; + 'cross;' => { output->first = 0x2717; fbreak; }; + 'cscr;' => { output->first = 0x0001d4b8; fbreak; }; + 'csub;' => { output->first = 0x2acf; fbreak; }; + 'csube;' => { output->first = 0x2ad1; fbreak; }; + 'csup;' => { output->first = 0x2ad0; fbreak; }; + 'csupe;' => { output->first = 0x2ad2; fbreak; }; + 'ctdot;' => { output->first = 0x22ef; fbreak; }; + 'cudarrl;' => { output->first = 0x2938; fbreak; }; + 'cudarrr;' => { output->first = 0x2935; fbreak; }; + 'cuepr;' => { output->first = 0x22de; fbreak; }; + 'cuesc;' => { output->first = 0x22df; fbreak; }; + 'cularr;' => { output->first = 0x21b6; fbreak; }; + 'cularrp;' => { output->first = 0x293d; fbreak; }; + 'cup;' => { output->first = 0x222a; fbreak; }; + 'cupbrcap;' => { output->first = 0x2a48; fbreak; }; + 'cupcap;' => { output->first = 0x2a46; fbreak; }; + 'cupcup;' => { output->first = 0x2a4a; fbreak; }; + 'cupdot;' => { output->first = 0x228d; fbreak; }; + 'cupor;' => { output->first = 0x2a45; fbreak; }; + 'cups;' => { output->first = 0x222a; output->second = 0xfe00; fbreak; }; + 'curarr;' => { output->first = 0x21b7; fbreak; }; + 'curarrm;' => { output->first = 0x293c; fbreak; }; + 'curlyeqprec;' => { output->first = 0x22de; fbreak; }; + 'curlyeqsucc;' => { output->first = 0x22df; fbreak; }; + 'curlyvee;' => { output->first = 0x22ce; fbreak; }; + 'curlywedge;' => { output->first = 0x22cf; fbreak; }; + 'curren;' => { output->first = 0xa4; fbreak; }; + 'curren' => { output->first = 0xa4; fbreak; }; + 'curvearrowleft;' => { output->first = 0x21b6; fbreak; }; + 'curvearrowright;' => { output->first = 0x21b7; fbreak; }; + 'cuvee;' => { output->first = 0x22ce; fbreak; }; + 'cuwed;' => { output->first = 0x22cf; fbreak; }; + 'cwconint;' => { output->first = 0x2232; fbreak; }; + 'cwint;' => { output->first = 0x2231; fbreak; }; + 'cylcty;' => { output->first = 0x232d; fbreak; }; + 'dArr;' => { output->first = 0x21d3; fbreak; }; + 'dHar;' => { output->first = 0x2965; fbreak; }; + 'dagger;' => { output->first = 0x2020; fbreak; }; + 'daleth;' => { output->first = 0x2138; fbreak; }; + 'darr;' => { output->first = 0x2193; fbreak; }; + 'dash;' => { output->first = 0x2010; fbreak; }; + 'dashv;' => { output->first = 0x22a3; fbreak; }; + 'dbkarow;' => { output->first = 0x290f; fbreak; }; + 'dblac;' => { output->first = 0x02dd; fbreak; }; + 'dcaron;' => { output->first = 0x010f; fbreak; }; + 'dcy;' => { output->first = 0x0434; fbreak; }; + 'dd;' => { output->first = 0x2146; fbreak; }; + 'ddagger;' => { output->first = 0x2021; fbreak; }; + 'ddarr;' => { output->first = 0x21ca; fbreak; }; + 'ddotseq;' => { output->first = 0x2a77; fbreak; }; + 'deg;' => { output->first = 0xb0; fbreak; }; + 'deg' => { output->first = 0xb0; fbreak; }; + 'delta;' => { output->first = 0x03b4; fbreak; }; + 'demptyv;' => { output->first = 0x29b1; fbreak; }; + 'dfisht;' => { output->first = 0x297f; fbreak; }; + 'dfr;' => { output->first = 0x0001d521; fbreak; }; + 'dharl;' => { output->first = 0x21c3; fbreak; }; + 'dharr;' => { output->first = 0x21c2; fbreak; }; + 'diam;' => { output->first = 0x22c4; fbreak; }; + 'diamond;' => { output->first = 0x22c4; fbreak; }; + 'diamondsuit;' => { output->first = 0x2666; fbreak; }; + 'diams;' => { output->first = 0x2666; fbreak; }; + 'die;' => { output->first = 0xa8; fbreak; }; + 'digamma;' => { output->first = 0x03dd; fbreak; }; + 'disin;' => { output->first = 0x22f2; fbreak; }; + 'div;' => { output->first = 0xf7; fbreak; }; + 'divide;' => { output->first = 0xf7; fbreak; }; + 'divide' => { output->first = 0xf7; fbreak; }; + 'divideontimes;' => { output->first = 0x22c7; fbreak; }; + 'divonx;' => { output->first = 0x22c7; fbreak; }; + 'djcy;' => { output->first = 0x0452; fbreak; }; + 'dlcorn;' => { output->first = 0x231e; fbreak; }; + 'dlcrop;' => { output->first = 0x230d; fbreak; }; + 'dollar;' => { output->first = 0x24; fbreak; }; + 'dopf;' => { output->first = 0x0001d555; fbreak; }; + 'dot;' => { output->first = 0x02d9; fbreak; }; + 'doteq;' => { output->first = 0x2250; fbreak; }; + 'doteqdot;' => { output->first = 0x2251; fbreak; }; + 'dotminus;' => { output->first = 0x2238; fbreak; }; + 'dotplus;' => { output->first = 0x2214; fbreak; }; + 'dotsquare;' => { output->first = 0x22a1; fbreak; }; + 'doublebarwedge;' => { output->first = 0x2306; fbreak; }; + 'downarrow;' => { output->first = 0x2193; fbreak; }; + 'downdownarrows;' => { output->first = 0x21ca; fbreak; }; + 'downharpoonleft;' => { output->first = 0x21c3; fbreak; }; + 'downharpoonright;' => { output->first = 0x21c2; fbreak; }; + 'drbkarow;' => { output->first = 0x2910; fbreak; }; + 'drcorn;' => { output->first = 0x231f; fbreak; }; + 'drcrop;' => { output->first = 0x230c; fbreak; }; + 'dscr;' => { output->first = 0x0001d4b9; fbreak; }; + 'dscy;' => { output->first = 0x0455; fbreak; }; + 'dsol;' => { output->first = 0x29f6; fbreak; }; + 'dstrok;' => { output->first = 0x0111; fbreak; }; + 'dtdot;' => { output->first = 0x22f1; fbreak; }; + 'dtri;' => { output->first = 0x25bf; fbreak; }; + 'dtrif;' => { output->first = 0x25be; fbreak; }; + 'duarr;' => { output->first = 0x21f5; fbreak; }; + 'duhar;' => { output->first = 0x296f; fbreak; }; + 'dwangle;' => { output->first = 0x29a6; fbreak; }; + 'dzcy;' => { output->first = 0x045f; fbreak; }; + 'dzigrarr;' => { output->first = 0x27ff; fbreak; }; + 'eDDot;' => { output->first = 0x2a77; fbreak; }; + 'eDot;' => { output->first = 0x2251; fbreak; }; + 'eacute;' => { output->first = 0xe9; fbreak; }; + 'eacute' => { output->first = 0xe9; fbreak; }; + 'easter;' => { output->first = 0x2a6e; fbreak; }; + 'ecaron;' => { output->first = 0x011b; fbreak; }; + 'ecir;' => { output->first = 0x2256; fbreak; }; + 'ecirc;' => { output->first = 0xea; fbreak; }; + 'ecirc' => { output->first = 0xea; fbreak; }; + 'ecolon;' => { output->first = 0x2255; fbreak; }; + 'ecy;' => { output->first = 0x044d; fbreak; }; + 'edot;' => { output->first = 0x0117; fbreak; }; + 'ee;' => { output->first = 0x2147; fbreak; }; + 'efDot;' => { output->first = 0x2252; fbreak; }; + 'efr;' => { output->first = 0x0001d522; fbreak; }; + 'eg;' => { output->first = 0x2a9a; fbreak; }; + 'egrave;' => { output->first = 0xe8; fbreak; }; + 'egrave' => { output->first = 0xe8; fbreak; }; + 'egs;' => { output->first = 0x2a96; fbreak; }; + 'egsdot;' => { output->first = 0x2a98; fbreak; }; + 'el;' => { output->first = 0x2a99; fbreak; }; + 'elinters;' => { output->first = 0x23e7; fbreak; }; + 'ell;' => { output->first = 0x2113; fbreak; }; + 'els;' => { output->first = 0x2a95; fbreak; }; + 'elsdot;' => { output->first = 0x2a97; fbreak; }; + 'emacr;' => { output->first = 0x0113; fbreak; }; + 'empty;' => { output->first = 0x2205; fbreak; }; + 'emptyset;' => { output->first = 0x2205; fbreak; }; + 'emptyv;' => { output->first = 0x2205; fbreak; }; + 'emsp13;' => { output->first = 0x2004; fbreak; }; + 'emsp14;' => { output->first = 0x2005; fbreak; }; + 'emsp;' => { output->first = 0x2003; fbreak; }; + 'eng;' => { output->first = 0x014b; fbreak; }; + 'ensp;' => { output->first = 0x2002; fbreak; }; + 'eogon;' => { output->first = 0x0119; fbreak; }; + 'eopf;' => { output->first = 0x0001d556; fbreak; }; + 'epar;' => { output->first = 0x22d5; fbreak; }; + 'eparsl;' => { output->first = 0x29e3; fbreak; }; + 'eplus;' => { output->first = 0x2a71; fbreak; }; + 'epsi;' => { output->first = 0x03b5; fbreak; }; + 'epsilon;' => { output->first = 0x03b5; fbreak; }; + 'epsiv;' => { output->first = 0x03f5; fbreak; }; + 'eqcirc;' => { output->first = 0x2256; fbreak; }; + 'eqcolon;' => { output->first = 0x2255; fbreak; }; + 'eqsim;' => { output->first = 0x2242; fbreak; }; + 'eqslantgtr;' => { output->first = 0x2a96; fbreak; }; + 'eqslantless;' => { output->first = 0x2a95; fbreak; }; + 'equals;' => { output->first = 0x3d; fbreak; }; + 'equest;' => { output->first = 0x225f; fbreak; }; + 'equiv;' => { output->first = 0x2261; fbreak; }; + 'equivDD;' => { output->first = 0x2a78; fbreak; }; + 'eqvparsl;' => { output->first = 0x29e5; fbreak; }; + 'erDot;' => { output->first = 0x2253; fbreak; }; + 'erarr;' => { output->first = 0x2971; fbreak; }; + 'escr;' => { output->first = 0x212f; fbreak; }; + 'esdot;' => { output->first = 0x2250; fbreak; }; + 'esim;' => { output->first = 0x2242; fbreak; }; + 'eta;' => { output->first = 0x03b7; fbreak; }; + 'eth;' => { output->first = 0xf0; fbreak; }; + 'eth' => { output->first = 0xf0; fbreak; }; + 'euml;' => { output->first = 0xeb; fbreak; }; + 'euml' => { output->first = 0xeb; fbreak; }; + 'euro;' => { output->first = 0x20ac; fbreak; }; + 'excl;' => { output->first = 0x21; fbreak; }; + 'exist;' => { output->first = 0x2203; fbreak; }; + 'expectation;' => { output->first = 0x2130; fbreak; }; + 'exponentiale;' => { output->first = 0x2147; fbreak; }; + 'fallingdotseq;' => { output->first = 0x2252; fbreak; }; + 'fcy;' => { output->first = 0x0444; fbreak; }; + 'female;' => { output->first = 0x2640; fbreak; }; + 'ffilig;' => { output->first = 0xfb03; fbreak; }; + 'fflig;' => { output->first = 0xfb00; fbreak; }; + 'ffllig;' => { output->first = 0xfb04; fbreak; }; + 'ffr;' => { output->first = 0x0001d523; fbreak; }; + 'filig;' => { output->first = 0xfb01; fbreak; }; + 'fjlig;' => { output->first = 0x66; output->second = 0x6a; fbreak; }; + 'flat;' => { output->first = 0x266d; fbreak; }; + 'fllig;' => { output->first = 0xfb02; fbreak; }; + 'fltns;' => { output->first = 0x25b1; fbreak; }; + 'fnof;' => { output->first = 0x0192; fbreak; }; + 'fopf;' => { output->first = 0x0001d557; fbreak; }; + 'forall;' => { output->first = 0x2200; fbreak; }; + 'fork;' => { output->first = 0x22d4; fbreak; }; + 'forkv;' => { output->first = 0x2ad9; fbreak; }; + 'fpartint;' => { output->first = 0x2a0d; fbreak; }; + 'frac12;' => { output->first = 0xbd; fbreak; }; + 'frac12' => { output->first = 0xbd; fbreak; }; + 'frac13;' => { output->first = 0x2153; fbreak; }; + 'frac14;' => { output->first = 0xbc; fbreak; }; + 'frac14' => { output->first = 0xbc; fbreak; }; + 'frac15;' => { output->first = 0x2155; fbreak; }; + 'frac16;' => { output->first = 0x2159; fbreak; }; + 'frac18;' => { output->first = 0x215b; fbreak; }; + 'frac23;' => { output->first = 0x2154; fbreak; }; + 'frac25;' => { output->first = 0x2156; fbreak; }; + 'frac34;' => { output->first = 0xbe; fbreak; }; + 'frac34' => { output->first = 0xbe; fbreak; }; + 'frac35;' => { output->first = 0x2157; fbreak; }; + 'frac38;' => { output->first = 0x215c; fbreak; }; + 'frac45;' => { output->first = 0x2158; fbreak; }; + 'frac56;' => { output->first = 0x215a; fbreak; }; + 'frac58;' => { output->first = 0x215d; fbreak; }; + 'frac78;' => { output->first = 0x215e; fbreak; }; + 'frasl;' => { output->first = 0x2044; fbreak; }; + 'frown;' => { output->first = 0x2322; fbreak; }; + 'fscr;' => { output->first = 0x0001d4bb; fbreak; }; + 'gE;' => { output->first = 0x2267; fbreak; }; + 'gEl;' => { output->first = 0x2a8c; fbreak; }; + 'gacute;' => { output->first = 0x01f5; fbreak; }; + 'gamma;' => { output->first = 0x03b3; fbreak; }; + 'gammad;' => { output->first = 0x03dd; fbreak; }; + 'gap;' => { output->first = 0x2a86; fbreak; }; + 'gbreve;' => { output->first = 0x011f; fbreak; }; + 'gcirc;' => { output->first = 0x011d; fbreak; }; + 'gcy;' => { output->first = 0x0433; fbreak; }; + 'gdot;' => { output->first = 0x0121; fbreak; }; + 'ge;' => { output->first = 0x2265; fbreak; }; + 'gel;' => { output->first = 0x22db; fbreak; }; + 'geq;' => { output->first = 0x2265; fbreak; }; + 'geqq;' => { output->first = 0x2267; fbreak; }; + 'geqslant;' => { output->first = 0x2a7e; fbreak; }; + 'ges;' => { output->first = 0x2a7e; fbreak; }; + 'gescc;' => { output->first = 0x2aa9; fbreak; }; + 'gesdot;' => { output->first = 0x2a80; fbreak; }; + 'gesdoto;' => { output->first = 0x2a82; fbreak; }; + 'gesdotol;' => { output->first = 0x2a84; fbreak; }; + 'gesl;' => { output->first = 0x22db; output->second = 0xfe00; fbreak; }; + 'gesles;' => { output->first = 0x2a94; fbreak; }; + 'gfr;' => { output->first = 0x0001d524; fbreak; }; + 'gg;' => { output->first = 0x226b; fbreak; }; + 'ggg;' => { output->first = 0x22d9; fbreak; }; + 'gimel;' => { output->first = 0x2137; fbreak; }; + 'gjcy;' => { output->first = 0x0453; fbreak; }; + 'gl;' => { output->first = 0x2277; fbreak; }; + 'glE;' => { output->first = 0x2a92; fbreak; }; + 'gla;' => { output->first = 0x2aa5; fbreak; }; + 'glj;' => { output->first = 0x2aa4; fbreak; }; + 'gnE;' => { output->first = 0x2269; fbreak; }; + 'gnap;' => { output->first = 0x2a8a; fbreak; }; + 'gnapprox;' => { output->first = 0x2a8a; fbreak; }; + 'gne;' => { output->first = 0x2a88; fbreak; }; + 'gneq;' => { output->first = 0x2a88; fbreak; }; + 'gneqq;' => { output->first = 0x2269; fbreak; }; + 'gnsim;' => { output->first = 0x22e7; fbreak; }; + 'gopf;' => { output->first = 0x0001d558; fbreak; }; + 'grave;' => { output->first = 0x60; fbreak; }; + 'gscr;' => { output->first = 0x210a; fbreak; }; + 'gsim;' => { output->first = 0x2273; fbreak; }; + 'gsime;' => { output->first = 0x2a8e; fbreak; }; + 'gsiml;' => { output->first = 0x2a90; fbreak; }; + 'gt;' => { output->first = 0x3e; fbreak; }; + 'gt' => { output->first = 0x3e; fbreak; }; + 'gtcc;' => { output->first = 0x2aa7; fbreak; }; + 'gtcir;' => { output->first = 0x2a7a; fbreak; }; + 'gtdot;' => { output->first = 0x22d7; fbreak; }; + 'gtlPar;' => { output->first = 0x2995; fbreak; }; + 'gtquest;' => { output->first = 0x2a7c; fbreak; }; + 'gtrapprox;' => { output->first = 0x2a86; fbreak; }; + 'gtrarr;' => { output->first = 0x2978; fbreak; }; + 'gtrdot;' => { output->first = 0x22d7; fbreak; }; + 'gtreqless;' => { output->first = 0x22db; fbreak; }; + 'gtreqqless;' => { output->first = 0x2a8c; fbreak; }; + 'gtrless;' => { output->first = 0x2277; fbreak; }; + 'gtrsim;' => { output->first = 0x2273; fbreak; }; + 'gvertneqq;' => { output->first = 0x2269; output->second = 0xfe00; fbreak; }; + 'gvnE;' => { output->first = 0x2269; output->second = 0xfe00; fbreak; }; + 'hArr;' => { output->first = 0x21d4; fbreak; }; + 'hairsp;' => { output->first = 0x200a; fbreak; }; + 'half;' => { output->first = 0xbd; fbreak; }; + 'hamilt;' => { output->first = 0x210b; fbreak; }; + 'hardcy;' => { output->first = 0x044a; fbreak; }; + 'harr;' => { output->first = 0x2194; fbreak; }; + 'harrcir;' => { output->first = 0x2948; fbreak; }; + 'harrw;' => { output->first = 0x21ad; fbreak; }; + 'hbar;' => { output->first = 0x210f; fbreak; }; + 'hcirc;' => { output->first = 0x0125; fbreak; }; + 'hearts;' => { output->first = 0x2665; fbreak; }; + 'heartsuit;' => { output->first = 0x2665; fbreak; }; + 'hellip;' => { output->first = 0x2026; fbreak; }; + 'hercon;' => { output->first = 0x22b9; fbreak; }; + 'hfr;' => { output->first = 0x0001d525; fbreak; }; + 'hksearow;' => { output->first = 0x2925; fbreak; }; + 'hkswarow;' => { output->first = 0x2926; fbreak; }; + 'hoarr;' => { output->first = 0x21ff; fbreak; }; + 'homtht;' => { output->first = 0x223b; fbreak; }; + 'hookleftarrow;' => { output->first = 0x21a9; fbreak; }; + 'hookrightarrow;' => { output->first = 0x21aa; fbreak; }; + 'hopf;' => { output->first = 0x0001d559; fbreak; }; + 'horbar;' => { output->first = 0x2015; fbreak; }; + 'hscr;' => { output->first = 0x0001d4bd; fbreak; }; + 'hslash;' => { output->first = 0x210f; fbreak; }; + 'hstrok;' => { output->first = 0x0127; fbreak; }; + 'hybull;' => { output->first = 0x2043; fbreak; }; + 'hyphen;' => { output->first = 0x2010; fbreak; }; + 'iacute;' => { output->first = 0xed; fbreak; }; + 'iacute' => { output->first = 0xed; fbreak; }; + 'ic;' => { output->first = 0x2063; fbreak; }; + 'icirc;' => { output->first = 0xee; fbreak; }; + 'icirc' => { output->first = 0xee; fbreak; }; + 'icy;' => { output->first = 0x0438; fbreak; }; + 'iecy;' => { output->first = 0x0435; fbreak; }; + 'iexcl;' => { output->first = 0xa1; fbreak; }; + 'iexcl' => { output->first = 0xa1; fbreak; }; + 'iff;' => { output->first = 0x21d4; fbreak; }; + 'ifr;' => { output->first = 0x0001d526; fbreak; }; + 'igrave;' => { output->first = 0xec; fbreak; }; + 'igrave' => { output->first = 0xec; fbreak; }; + 'ii;' => { output->first = 0x2148; fbreak; }; + 'iiiint;' => { output->first = 0x2a0c; fbreak; }; + 'iiint;' => { output->first = 0x222d; fbreak; }; + 'iinfin;' => { output->first = 0x29dc; fbreak; }; + 'iiota;' => { output->first = 0x2129; fbreak; }; + 'ijlig;' => { output->first = 0x0133; fbreak; }; + 'imacr;' => { output->first = 0x012b; fbreak; }; + 'image;' => { output->first = 0x2111; fbreak; }; + 'imagline;' => { output->first = 0x2110; fbreak; }; + 'imagpart;' => { output->first = 0x2111; fbreak; }; + 'imath;' => { output->first = 0x0131; fbreak; }; + 'imof;' => { output->first = 0x22b7; fbreak; }; + 'imped;' => { output->first = 0x01b5; fbreak; }; + 'in;' => { output->first = 0x2208; fbreak; }; + 'incare;' => { output->first = 0x2105; fbreak; }; + 'infin;' => { output->first = 0x221e; fbreak; }; + 'infintie;' => { output->first = 0x29dd; fbreak; }; + 'inodot;' => { output->first = 0x0131; fbreak; }; + 'int;' => { output->first = 0x222b; fbreak; }; + 'intcal;' => { output->first = 0x22ba; fbreak; }; + 'integers;' => { output->first = 0x2124; fbreak; }; + 'intercal;' => { output->first = 0x22ba; fbreak; }; + 'intlarhk;' => { output->first = 0x2a17; fbreak; }; + 'intprod;' => { output->first = 0x2a3c; fbreak; }; + 'iocy;' => { output->first = 0x0451; fbreak; }; + 'iogon;' => { output->first = 0x012f; fbreak; }; + 'iopf;' => { output->first = 0x0001d55a; fbreak; }; + 'iota;' => { output->first = 0x03b9; fbreak; }; + 'iprod;' => { output->first = 0x2a3c; fbreak; }; + 'iquest;' => { output->first = 0xbf; fbreak; }; + 'iquest' => { output->first = 0xbf; fbreak; }; + 'iscr;' => { output->first = 0x0001d4be; fbreak; }; + 'isin;' => { output->first = 0x2208; fbreak; }; + 'isinE;' => { output->first = 0x22f9; fbreak; }; + 'isindot;' => { output->first = 0x22f5; fbreak; }; + 'isins;' => { output->first = 0x22f4; fbreak; }; + 'isinsv;' => { output->first = 0x22f3; fbreak; }; + 'isinv;' => { output->first = 0x2208; fbreak; }; + 'it;' => { output->first = 0x2062; fbreak; }; + 'itilde;' => { output->first = 0x0129; fbreak; }; + 'iukcy;' => { output->first = 0x0456; fbreak; }; + 'iuml;' => { output->first = 0xef; fbreak; }; + 'iuml' => { output->first = 0xef; fbreak; }; + 'jcirc;' => { output->first = 0x0135; fbreak; }; + 'jcy;' => { output->first = 0x0439; fbreak; }; + 'jfr;' => { output->first = 0x0001d527; fbreak; }; + 'jmath;' => { output->first = 0x0237; fbreak; }; + 'jopf;' => { output->first = 0x0001d55b; fbreak; }; + 'jscr;' => { output->first = 0x0001d4bf; fbreak; }; + 'jsercy;' => { output->first = 0x0458; fbreak; }; + 'jukcy;' => { output->first = 0x0454; fbreak; }; + 'kappa;' => { output->first = 0x03ba; fbreak; }; + 'kappav;' => { output->first = 0x03f0; fbreak; }; + 'kcedil;' => { output->first = 0x0137; fbreak; }; + 'kcy;' => { output->first = 0x043a; fbreak; }; + 'kfr;' => { output->first = 0x0001d528; fbreak; }; + 'kgreen;' => { output->first = 0x0138; fbreak; }; + 'khcy;' => { output->first = 0x0445; fbreak; }; + 'kjcy;' => { output->first = 0x045c; fbreak; }; + 'kopf;' => { output->first = 0x0001d55c; fbreak; }; + 'kscr;' => { output->first = 0x0001d4c0; fbreak; }; + 'lAarr;' => { output->first = 0x21da; fbreak; }; + 'lArr;' => { output->first = 0x21d0; fbreak; }; + 'lAtail;' => { output->first = 0x291b; fbreak; }; + 'lBarr;' => { output->first = 0x290e; fbreak; }; + 'lE;' => { output->first = 0x2266; fbreak; }; + 'lEg;' => { output->first = 0x2a8b; fbreak; }; + 'lHar;' => { output->first = 0x2962; fbreak; }; + 'lacute;' => { output->first = 0x013a; fbreak; }; + 'laemptyv;' => { output->first = 0x29b4; fbreak; }; + 'lagran;' => { output->first = 0x2112; fbreak; }; + 'lambda;' => { output->first = 0x03bb; fbreak; }; + 'lang;' => { output->first = 0x27e8; fbreak; }; + 'langd;' => { output->first = 0x2991; fbreak; }; + 'langle;' => { output->first = 0x27e8; fbreak; }; + 'lap;' => { output->first = 0x2a85; fbreak; }; + 'laquo;' => { output->first = 0xab; fbreak; }; + 'laquo' => { output->first = 0xab; fbreak; }; + 'larr;' => { output->first = 0x2190; fbreak; }; + 'larrb;' => { output->first = 0x21e4; fbreak; }; + 'larrbfs;' => { output->first = 0x291f; fbreak; }; + 'larrfs;' => { output->first = 0x291d; fbreak; }; + 'larrhk;' => { output->first = 0x21a9; fbreak; }; + 'larrlp;' => { output->first = 0x21ab; fbreak; }; + 'larrpl;' => { output->first = 0x2939; fbreak; }; + 'larrsim;' => { output->first = 0x2973; fbreak; }; + 'larrtl;' => { output->first = 0x21a2; fbreak; }; + 'lat;' => { output->first = 0x2aab; fbreak; }; + 'latail;' => { output->first = 0x2919; fbreak; }; + 'late;' => { output->first = 0x2aad; fbreak; }; + 'lates;' => { output->first = 0x2aad; output->second = 0xfe00; fbreak; }; + 'lbarr;' => { output->first = 0x290c; fbreak; }; + 'lbbrk;' => { output->first = 0x2772; fbreak; }; + 'lbrace;' => { output->first = 0x7b; fbreak; }; + 'lbrack;' => { output->first = 0x5b; fbreak; }; + 'lbrke;' => { output->first = 0x298b; fbreak; }; + 'lbrksld;' => { output->first = 0x298f; fbreak; }; + 'lbrkslu;' => { output->first = 0x298d; fbreak; }; + 'lcaron;' => { output->first = 0x013e; fbreak; }; + 'lcedil;' => { output->first = 0x013c; fbreak; }; + 'lceil;' => { output->first = 0x2308; fbreak; }; + 'lcub;' => { output->first = 0x7b; fbreak; }; + 'lcy;' => { output->first = 0x043b; fbreak; }; + 'ldca;' => { output->first = 0x2936; fbreak; }; + 'ldquo;' => { output->first = 0x201c; fbreak; }; + 'ldquor;' => { output->first = 0x201e; fbreak; }; + 'ldrdhar;' => { output->first = 0x2967; fbreak; }; + 'ldrushar;' => { output->first = 0x294b; fbreak; }; + 'ldsh;' => { output->first = 0x21b2; fbreak; }; + 'le;' => { output->first = 0x2264; fbreak; }; + 'leftarrow;' => { output->first = 0x2190; fbreak; }; + 'leftarrowtail;' => { output->first = 0x21a2; fbreak; }; + 'leftharpoondown;' => { output->first = 0x21bd; fbreak; }; + 'leftharpoonup;' => { output->first = 0x21bc; fbreak; }; + 'leftleftarrows;' => { output->first = 0x21c7; fbreak; }; + 'leftrightarrow;' => { output->first = 0x2194; fbreak; }; + 'leftrightarrows;' => { output->first = 0x21c6; fbreak; }; + 'leftrightharpoons;' => { output->first = 0x21cb; fbreak; }; + 'leftrightsquigarrow;' => { output->first = 0x21ad; fbreak; }; + 'leftthreetimes;' => { output->first = 0x22cb; fbreak; }; + 'leg;' => { output->first = 0x22da; fbreak; }; + 'leq;' => { output->first = 0x2264; fbreak; }; + 'leqq;' => { output->first = 0x2266; fbreak; }; + 'leqslant;' => { output->first = 0x2a7d; fbreak; }; + 'les;' => { output->first = 0x2a7d; fbreak; }; + 'lescc;' => { output->first = 0x2aa8; fbreak; }; + 'lesdot;' => { output->first = 0x2a7f; fbreak; }; + 'lesdoto;' => { output->first = 0x2a81; fbreak; }; + 'lesdotor;' => { output->first = 0x2a83; fbreak; }; + 'lesg;' => { output->first = 0x22da; output->second = 0xfe00; fbreak; }; + 'lesges;' => { output->first = 0x2a93; fbreak; }; + 'lessapprox;' => { output->first = 0x2a85; fbreak; }; + 'lessdot;' => { output->first = 0x22d6; fbreak; }; + 'lesseqgtr;' => { output->first = 0x22da; fbreak; }; + 'lesseqqgtr;' => { output->first = 0x2a8b; fbreak; }; + 'lessgtr;' => { output->first = 0x2276; fbreak; }; + 'lesssim;' => { output->first = 0x2272; fbreak; }; + 'lfisht;' => { output->first = 0x297c; fbreak; }; + 'lfloor;' => { output->first = 0x230a; fbreak; }; + 'lfr;' => { output->first = 0x0001d529; fbreak; }; + 'lg;' => { output->first = 0x2276; fbreak; }; + 'lgE;' => { output->first = 0x2a91; fbreak; }; + 'lhard;' => { output->first = 0x21bd; fbreak; }; + 'lharu;' => { output->first = 0x21bc; fbreak; }; + 'lharul;' => { output->first = 0x296a; fbreak; }; + 'lhblk;' => { output->first = 0x2584; fbreak; }; + 'ljcy;' => { output->first = 0x0459; fbreak; }; + 'll;' => { output->first = 0x226a; fbreak; }; + 'llarr;' => { output->first = 0x21c7; fbreak; }; + 'llcorner;' => { output->first = 0x231e; fbreak; }; + 'llhard;' => { output->first = 0x296b; fbreak; }; + 'lltri;' => { output->first = 0x25fa; fbreak; }; + 'lmidot;' => { output->first = 0x0140; fbreak; }; + 'lmoust;' => { output->first = 0x23b0; fbreak; }; + 'lmoustache;' => { output->first = 0x23b0; fbreak; }; + 'lnE;' => { output->first = 0x2268; fbreak; }; + 'lnap;' => { output->first = 0x2a89; fbreak; }; + 'lnapprox;' => { output->first = 0x2a89; fbreak; }; + 'lne;' => { output->first = 0x2a87; fbreak; }; + 'lneq;' => { output->first = 0x2a87; fbreak; }; + 'lneqq;' => { output->first = 0x2268; fbreak; }; + 'lnsim;' => { output->first = 0x22e6; fbreak; }; + 'loang;' => { output->first = 0x27ec; fbreak; }; + 'loarr;' => { output->first = 0x21fd; fbreak; }; + 'lobrk;' => { output->first = 0x27e6; fbreak; }; + 'longleftarrow;' => { output->first = 0x27f5; fbreak; }; + 'longleftrightarrow;' => { output->first = 0x27f7; fbreak; }; + 'longmapsto;' => { output->first = 0x27fc; fbreak; }; + 'longrightarrow;' => { output->first = 0x27f6; fbreak; }; + 'looparrowleft;' => { output->first = 0x21ab; fbreak; }; + 'looparrowright;' => { output->first = 0x21ac; fbreak; }; + 'lopar;' => { output->first = 0x2985; fbreak; }; + 'lopf;' => { output->first = 0x0001d55d; fbreak; }; + 'loplus;' => { output->first = 0x2a2d; fbreak; }; + 'lotimes;' => { output->first = 0x2a34; fbreak; }; + 'lowast;' => { output->first = 0x2217; fbreak; }; + 'lowbar;' => { output->first = 0x5f; fbreak; }; + 'loz;' => { output->first = 0x25ca; fbreak; }; + 'lozenge;' => { output->first = 0x25ca; fbreak; }; + 'lozf;' => { output->first = 0x29eb; fbreak; }; + 'lpar;' => { output->first = 0x28; fbreak; }; + 'lparlt;' => { output->first = 0x2993; fbreak; }; + 'lrarr;' => { output->first = 0x21c6; fbreak; }; + 'lrcorner;' => { output->first = 0x231f; fbreak; }; + 'lrhar;' => { output->first = 0x21cb; fbreak; }; + 'lrhard;' => { output->first = 0x296d; fbreak; }; + 'lrm;' => { output->first = 0x200e; fbreak; }; + 'lrtri;' => { output->first = 0x22bf; fbreak; }; + 'lsaquo;' => { output->first = 0x2039; fbreak; }; + 'lscr;' => { output->first = 0x0001d4c1; fbreak; }; + 'lsh;' => { output->first = 0x21b0; fbreak; }; + 'lsim;' => { output->first = 0x2272; fbreak; }; + 'lsime;' => { output->first = 0x2a8d; fbreak; }; + 'lsimg;' => { output->first = 0x2a8f; fbreak; }; + 'lsqb;' => { output->first = 0x5b; fbreak; }; + 'lsquo;' => { output->first = 0x2018; fbreak; }; + 'lsquor;' => { output->first = 0x201a; fbreak; }; + 'lstrok;' => { output->first = 0x0142; fbreak; }; + 'lt;' => { output->first = 0x3c; fbreak; }; + 'lt' => { output->first = 0x3c; fbreak; }; + 'ltcc;' => { output->first = 0x2aa6; fbreak; }; + 'ltcir;' => { output->first = 0x2a79; fbreak; }; + 'ltdot;' => { output->first = 0x22d6; fbreak; }; + 'lthree;' => { output->first = 0x22cb; fbreak; }; + 'ltimes;' => { output->first = 0x22c9; fbreak; }; + 'ltlarr;' => { output->first = 0x2976; fbreak; }; + 'ltquest;' => { output->first = 0x2a7b; fbreak; }; + 'ltrPar;' => { output->first = 0x2996; fbreak; }; + 'ltri;' => { output->first = 0x25c3; fbreak; }; + 'ltrie;' => { output->first = 0x22b4; fbreak; }; + 'ltrif;' => { output->first = 0x25c2; fbreak; }; + 'lurdshar;' => { output->first = 0x294a; fbreak; }; + 'luruhar;' => { output->first = 0x2966; fbreak; }; + 'lvertneqq;' => { output->first = 0x2268; output->second = 0xfe00; fbreak; }; + 'lvnE;' => { output->first = 0x2268; output->second = 0xfe00; fbreak; }; + 'mDDot;' => { output->first = 0x223a; fbreak; }; + 'macr;' => { output->first = 0xaf; fbreak; }; + 'macr' => { output->first = 0xaf; fbreak; }; + 'male;' => { output->first = 0x2642; fbreak; }; + 'malt;' => { output->first = 0x2720; fbreak; }; + 'maltese;' => { output->first = 0x2720; fbreak; }; + 'map;' => { output->first = 0x21a6; fbreak; }; + 'mapsto;' => { output->first = 0x21a6; fbreak; }; + 'mapstodown;' => { output->first = 0x21a7; fbreak; }; + 'mapstoleft;' => { output->first = 0x21a4; fbreak; }; + 'mapstoup;' => { output->first = 0x21a5; fbreak; }; + 'marker;' => { output->first = 0x25ae; fbreak; }; + 'mcomma;' => { output->first = 0x2a29; fbreak; }; + 'mcy;' => { output->first = 0x043c; fbreak; }; + 'mdash;' => { output->first = 0x2014; fbreak; }; + 'measuredangle;' => { output->first = 0x2221; fbreak; }; + 'mfr;' => { output->first = 0x0001d52a; fbreak; }; + 'mho;' => { output->first = 0x2127; fbreak; }; + 'micro;' => { output->first = 0xb5; fbreak; }; + 'micro' => { output->first = 0xb5; fbreak; }; + 'mid;' => { output->first = 0x2223; fbreak; }; + 'midast;' => { output->first = 0x2a; fbreak; }; + 'midcir;' => { output->first = 0x2af0; fbreak; }; + 'middot;' => { output->first = 0xb7; fbreak; }; + 'middot' => { output->first = 0xb7; fbreak; }; + 'minus;' => { output->first = 0x2212; fbreak; }; + 'minusb;' => { output->first = 0x229f; fbreak; }; + 'minusd;' => { output->first = 0x2238; fbreak; }; + 'minusdu;' => { output->first = 0x2a2a; fbreak; }; + 'mlcp;' => { output->first = 0x2adb; fbreak; }; + 'mldr;' => { output->first = 0x2026; fbreak; }; + 'mnplus;' => { output->first = 0x2213; fbreak; }; + 'models;' => { output->first = 0x22a7; fbreak; }; + 'mopf;' => { output->first = 0x0001d55e; fbreak; }; + 'mp;' => { output->first = 0x2213; fbreak; }; + 'mscr;' => { output->first = 0x0001d4c2; fbreak; }; + 'mstpos;' => { output->first = 0x223e; fbreak; }; + 'mu;' => { output->first = 0x03bc; fbreak; }; + 'multimap;' => { output->first = 0x22b8; fbreak; }; + 'mumap;' => { output->first = 0x22b8; fbreak; }; + 'nGg;' => { output->first = 0x22d9; output->second = 0x0338; fbreak; }; + 'nGt;' => { output->first = 0x226b; output->second = 0x20d2; fbreak; }; + 'nGtv;' => { output->first = 0x226b; output->second = 0x0338; fbreak; }; + 'nLeftarrow;' => { output->first = 0x21cd; fbreak; }; + 'nLeftrightarrow;' => { output->first = 0x21ce; fbreak; }; + 'nLl;' => { output->first = 0x22d8; output->second = 0x0338; fbreak; }; + 'nLt;' => { output->first = 0x226a; output->second = 0x20d2; fbreak; }; + 'nLtv;' => { output->first = 0x226a; output->second = 0x0338; fbreak; }; + 'nRightarrow;' => { output->first = 0x21cf; fbreak; }; + 'nVDash;' => { output->first = 0x22af; fbreak; }; + 'nVdash;' => { output->first = 0x22ae; fbreak; }; + 'nabla;' => { output->first = 0x2207; fbreak; }; + 'nacute;' => { output->first = 0x0144; fbreak; }; + 'nang;' => { output->first = 0x2220; output->second = 0x20d2; fbreak; }; + 'nap;' => { output->first = 0x2249; fbreak; }; + 'napE;' => { output->first = 0x2a70; output->second = 0x0338; fbreak; }; + 'napid;' => { output->first = 0x224b; output->second = 0x0338; fbreak; }; + 'napos;' => { output->first = 0x0149; fbreak; }; + 'napprox;' => { output->first = 0x2249; fbreak; }; + 'natur;' => { output->first = 0x266e; fbreak; }; + 'natural;' => { output->first = 0x266e; fbreak; }; + 'naturals;' => { output->first = 0x2115; fbreak; }; + 'nbsp;' => { output->first = 0xa0; fbreak; }; + 'nbsp' => { output->first = 0xa0; fbreak; }; + 'nbump;' => { output->first = 0x224e; output->second = 0x0338; fbreak; }; + 'nbumpe;' => { output->first = 0x224f; output->second = 0x0338; fbreak; }; + 'ncap;' => { output->first = 0x2a43; fbreak; }; + 'ncaron;' => { output->first = 0x0148; fbreak; }; + 'ncedil;' => { output->first = 0x0146; fbreak; }; + 'ncong;' => { output->first = 0x2247; fbreak; }; + 'ncongdot;' => { output->first = 0x2a6d; output->second = 0x0338; fbreak; }; + 'ncup;' => { output->first = 0x2a42; fbreak; }; + 'ncy;' => { output->first = 0x043d; fbreak; }; + 'ndash;' => { output->first = 0x2013; fbreak; }; + 'ne;' => { output->first = 0x2260; fbreak; }; + 'neArr;' => { output->first = 0x21d7; fbreak; }; + 'nearhk;' => { output->first = 0x2924; fbreak; }; + 'nearr;' => { output->first = 0x2197; fbreak; }; + 'nearrow;' => { output->first = 0x2197; fbreak; }; + 'nedot;' => { output->first = 0x2250; output->second = 0x0338; fbreak; }; + 'nequiv;' => { output->first = 0x2262; fbreak; }; + 'nesear;' => { output->first = 0x2928; fbreak; }; + 'nesim;' => { output->first = 0x2242; output->second = 0x0338; fbreak; }; + 'nexist;' => { output->first = 0x2204; fbreak; }; + 'nexists;' => { output->first = 0x2204; fbreak; }; + 'nfr;' => { output->first = 0x0001d52b; fbreak; }; + 'ngE;' => { output->first = 0x2267; output->second = 0x0338; fbreak; }; + 'nge;' => { output->first = 0x2271; fbreak; }; + 'ngeq;' => { output->first = 0x2271; fbreak; }; + 'ngeqq;' => { output->first = 0x2267; output->second = 0x0338; fbreak; }; + 'ngeqslant;' => { output->first = 0x2a7e; output->second = 0x0338; fbreak; }; + 'nges;' => { output->first = 0x2a7e; output->second = 0x0338; fbreak; }; + 'ngsim;' => { output->first = 0x2275; fbreak; }; + 'ngt;' => { output->first = 0x226f; fbreak; }; + 'ngtr;' => { output->first = 0x226f; fbreak; }; + 'nhArr;' => { output->first = 0x21ce; fbreak; }; + 'nharr;' => { output->first = 0x21ae; fbreak; }; + 'nhpar;' => { output->first = 0x2af2; fbreak; }; + 'ni;' => { output->first = 0x220b; fbreak; }; + 'nis;' => { output->first = 0x22fc; fbreak; }; + 'nisd;' => { output->first = 0x22fa; fbreak; }; + 'niv;' => { output->first = 0x220b; fbreak; }; + 'njcy;' => { output->first = 0x045a; fbreak; }; + 'nlArr;' => { output->first = 0x21cd; fbreak; }; + 'nlE;' => { output->first = 0x2266; output->second = 0x0338; fbreak; }; + 'nlarr;' => { output->first = 0x219a; fbreak; }; + 'nldr;' => { output->first = 0x2025; fbreak; }; + 'nle;' => { output->first = 0x2270; fbreak; }; + 'nleftarrow;' => { output->first = 0x219a; fbreak; }; + 'nleftrightarrow;' => { output->first = 0x21ae; fbreak; }; + 'nleq;' => { output->first = 0x2270; fbreak; }; + 'nleqq;' => { output->first = 0x2266; output->second = 0x0338; fbreak; }; + 'nleqslant;' => { output->first = 0x2a7d; output->second = 0x0338; fbreak; }; + 'nles;' => { output->first = 0x2a7d; output->second = 0x0338; fbreak; }; + 'nless;' => { output->first = 0x226e; fbreak; }; + 'nlsim;' => { output->first = 0x2274; fbreak; }; + 'nlt;' => { output->first = 0x226e; fbreak; }; + 'nltri;' => { output->first = 0x22ea; fbreak; }; + 'nltrie;' => { output->first = 0x22ec; fbreak; }; + 'nmid;' => { output->first = 0x2224; fbreak; }; + 'nopf;' => { output->first = 0x0001d55f; fbreak; }; + 'not;' => { output->first = 0xac; fbreak; }; + 'notin;' => { output->first = 0x2209; fbreak; }; + 'notinE;' => { output->first = 0x22f9; output->second = 0x0338; fbreak; }; + 'notindot;' => { output->first = 0x22f5; output->second = 0x0338; fbreak; }; + 'notinva;' => { output->first = 0x2209; fbreak; }; + 'notinvb;' => { output->first = 0x22f7; fbreak; }; + 'notinvc;' => { output->first = 0x22f6; fbreak; }; + 'notni;' => { output->first = 0x220c; fbreak; }; + 'notniva;' => { output->first = 0x220c; fbreak; }; + 'notnivb;' => { output->first = 0x22fe; fbreak; }; + 'notnivc;' => { output->first = 0x22fd; fbreak; }; + 'not' => { output->first = 0xac; fbreak; }; + 'npar;' => { output->first = 0x2226; fbreak; }; + 'nparallel;' => { output->first = 0x2226; fbreak; }; + 'nparsl;' => { output->first = 0x2afd; output->second = 0x20e5; fbreak; }; + 'npart;' => { output->first = 0x2202; output->second = 0x0338; fbreak; }; + 'npolint;' => { output->first = 0x2a14; fbreak; }; + 'npr;' => { output->first = 0x2280; fbreak; }; + 'nprcue;' => { output->first = 0x22e0; fbreak; }; + 'npre;' => { output->first = 0x2aaf; output->second = 0x0338; fbreak; }; + 'nprec;' => { output->first = 0x2280; fbreak; }; + 'npreceq;' => { output->first = 0x2aaf; output->second = 0x0338; fbreak; }; + 'nrArr;' => { output->first = 0x21cf; fbreak; }; + 'nrarr;' => { output->first = 0x219b; fbreak; }; + 'nrarrc;' => { output->first = 0x2933; output->second = 0x0338; fbreak; }; + 'nrarrw;' => { output->first = 0x219d; output->second = 0x0338; fbreak; }; + 'nrightarrow;' => { output->first = 0x219b; fbreak; }; + 'nrtri;' => { output->first = 0x22eb; fbreak; }; + 'nrtrie;' => { output->first = 0x22ed; fbreak; }; + 'nsc;' => { output->first = 0x2281; fbreak; }; + 'nsccue;' => { output->first = 0x22e1; fbreak; }; + 'nsce;' => { output->first = 0x2ab0; output->second = 0x0338; fbreak; }; + 'nscr;' => { output->first = 0x0001d4c3; fbreak; }; + 'nshortmid;' => { output->first = 0x2224; fbreak; }; + 'nshortparallel;' => { output->first = 0x2226; fbreak; }; + 'nsim;' => { output->first = 0x2241; fbreak; }; + 'nsime;' => { output->first = 0x2244; fbreak; }; + 'nsimeq;' => { output->first = 0x2244; fbreak; }; + 'nsmid;' => { output->first = 0x2224; fbreak; }; + 'nspar;' => { output->first = 0x2226; fbreak; }; + 'nsqsube;' => { output->first = 0x22e2; fbreak; }; + 'nsqsupe;' => { output->first = 0x22e3; fbreak; }; + 'nsub;' => { output->first = 0x2284; fbreak; }; + 'nsubE;' => { output->first = 0x2ac5; output->second = 0x0338; fbreak; }; + 'nsube;' => { output->first = 0x2288; fbreak; }; + 'nsubset;' => { output->first = 0x2282; output->second = 0x20d2; fbreak; }; + 'nsubseteq;' => { output->first = 0x2288; fbreak; }; + 'nsubseteqq;' => { output->first = 0x2ac5; output->second = 0x0338; fbreak; }; + 'nsucc;' => { output->first = 0x2281; fbreak; }; + 'nsucceq;' => { output->first = 0x2ab0; output->second = 0x0338; fbreak; }; + 'nsup;' => { output->first = 0x2285; fbreak; }; + 'nsupE;' => { output->first = 0x2ac6; output->second = 0x0338; fbreak; }; + 'nsupe;' => { output->first = 0x2289; fbreak; }; + 'nsupset;' => { output->first = 0x2283; output->second = 0x20d2; fbreak; }; + 'nsupseteq;' => { output->first = 0x2289; fbreak; }; + 'nsupseteqq;' => { output->first = 0x2ac6; output->second = 0x0338; fbreak; }; + 'ntgl;' => { output->first = 0x2279; fbreak; }; + 'ntilde;' => { output->first = 0xf1; fbreak; }; + 'ntilde' => { output->first = 0xf1; fbreak; }; + 'ntlg;' => { output->first = 0x2278; fbreak; }; + 'ntriangleleft;' => { output->first = 0x22ea; fbreak; }; + 'ntrianglelefteq;' => { output->first = 0x22ec; fbreak; }; + 'ntriangleright;' => { output->first = 0x22eb; fbreak; }; + 'ntrianglerighteq;' => { output->first = 0x22ed; fbreak; }; + 'nu;' => { output->first = 0x03bd; fbreak; }; + 'num;' => { output->first = 0x23; fbreak; }; + 'numero;' => { output->first = 0x2116; fbreak; }; + 'numsp;' => { output->first = 0x2007; fbreak; }; + 'nvDash;' => { output->first = 0x22ad; fbreak; }; + 'nvHarr;' => { output->first = 0x2904; fbreak; }; + 'nvap;' => { output->first = 0x224d; output->second = 0x20d2; fbreak; }; + 'nvdash;' => { output->first = 0x22ac; fbreak; }; + 'nvge;' => { output->first = 0x2265; output->second = 0x20d2; fbreak; }; + 'nvgt;' => { output->first = 0x3e; output->second = 0x20d2; fbreak; }; + 'nvinfin;' => { output->first = 0x29de; fbreak; }; + 'nvlArr;' => { output->first = 0x2902; fbreak; }; + 'nvle;' => { output->first = 0x2264; output->second = 0x20d2; fbreak; }; + 'nvlt;' => { output->first = 0x3c; output->second = 0x20d2; fbreak; }; + 'nvltrie;' => { output->first = 0x22b4; output->second = 0x20d2; fbreak; }; + 'nvrArr;' => { output->first = 0x2903; fbreak; }; + 'nvrtrie;' => { output->first = 0x22b5; output->second = 0x20d2; fbreak; }; + 'nvsim;' => { output->first = 0x223c; output->second = 0x20d2; fbreak; }; + 'nwArr;' => { output->first = 0x21d6; fbreak; }; + 'nwarhk;' => { output->first = 0x2923; fbreak; }; + 'nwarr;' => { output->first = 0x2196; fbreak; }; + 'nwarrow;' => { output->first = 0x2196; fbreak; }; + 'nwnear;' => { output->first = 0x2927; fbreak; }; + 'oS;' => { output->first = 0x24c8; fbreak; }; + 'oacute;' => { output->first = 0xf3; fbreak; }; + 'oacute' => { output->first = 0xf3; fbreak; }; + 'oast;' => { output->first = 0x229b; fbreak; }; + 'ocir;' => { output->first = 0x229a; fbreak; }; + 'ocirc;' => { output->first = 0xf4; fbreak; }; + 'ocirc' => { output->first = 0xf4; fbreak; }; + 'ocy;' => { output->first = 0x043e; fbreak; }; + 'odash;' => { output->first = 0x229d; fbreak; }; + 'odblac;' => { output->first = 0x0151; fbreak; }; + 'odiv;' => { output->first = 0x2a38; fbreak; }; + 'odot;' => { output->first = 0x2299; fbreak; }; + 'odsold;' => { output->first = 0x29bc; fbreak; }; + 'oelig;' => { output->first = 0x0153; fbreak; }; + 'ofcir;' => { output->first = 0x29bf; fbreak; }; + 'ofr;' => { output->first = 0x0001d52c; fbreak; }; + 'ogon;' => { output->first = 0x02db; fbreak; }; + 'ograve;' => { output->first = 0xf2; fbreak; }; + 'ograve' => { output->first = 0xf2; fbreak; }; + 'ogt;' => { output->first = 0x29c1; fbreak; }; + 'ohbar;' => { output->first = 0x29b5; fbreak; }; + 'ohm;' => { output->first = 0x03a9; fbreak; }; + 'oint;' => { output->first = 0x222e; fbreak; }; + 'olarr;' => { output->first = 0x21ba; fbreak; }; + 'olcir;' => { output->first = 0x29be; fbreak; }; + 'olcross;' => { output->first = 0x29bb; fbreak; }; + 'oline;' => { output->first = 0x203e; fbreak; }; + 'olt;' => { output->first = 0x29c0; fbreak; }; + 'omacr;' => { output->first = 0x014d; fbreak; }; + 'omega;' => { output->first = 0x03c9; fbreak; }; + 'omicron;' => { output->first = 0x03bf; fbreak; }; + 'omid;' => { output->first = 0x29b6; fbreak; }; + 'ominus;' => { output->first = 0x2296; fbreak; }; + 'oopf;' => { output->first = 0x0001d560; fbreak; }; + 'opar;' => { output->first = 0x29b7; fbreak; }; + 'operp;' => { output->first = 0x29b9; fbreak; }; + 'oplus;' => { output->first = 0x2295; fbreak; }; + 'or;' => { output->first = 0x2228; fbreak; }; + 'orarr;' => { output->first = 0x21bb; fbreak; }; + 'ord;' => { output->first = 0x2a5d; fbreak; }; + 'order;' => { output->first = 0x2134; fbreak; }; + 'orderof;' => { output->first = 0x2134; fbreak; }; + 'ordf;' => { output->first = 0xaa; fbreak; }; + 'ordf' => { output->first = 0xaa; fbreak; }; + 'ordm;' => { output->first = 0xba; fbreak; }; + 'ordm' => { output->first = 0xba; fbreak; }; + 'origof;' => { output->first = 0x22b6; fbreak; }; + 'oror;' => { output->first = 0x2a56; fbreak; }; + 'orslope;' => { output->first = 0x2a57; fbreak; }; + 'orv;' => { output->first = 0x2a5b; fbreak; }; + 'oscr;' => { output->first = 0x2134; fbreak; }; + 'oslash;' => { output->first = 0xf8; fbreak; }; + 'oslash' => { output->first = 0xf8; fbreak; }; + 'osol;' => { output->first = 0x2298; fbreak; }; + 'otilde;' => { output->first = 0xf5; fbreak; }; + 'otilde' => { output->first = 0xf5; fbreak; }; + 'otimes;' => { output->first = 0x2297; fbreak; }; + 'otimesas;' => { output->first = 0x2a36; fbreak; }; + 'ouml;' => { output->first = 0xf6; fbreak; }; + 'ouml' => { output->first = 0xf6; fbreak; }; + 'ovbar;' => { output->first = 0x233d; fbreak; }; + 'par;' => { output->first = 0x2225; fbreak; }; + 'para;' => { output->first = 0xb6; fbreak; }; + 'para' => { output->first = 0xb6; fbreak; }; + 'parallel;' => { output->first = 0x2225; fbreak; }; + 'parsim;' => { output->first = 0x2af3; fbreak; }; + 'parsl;' => { output->first = 0x2afd; fbreak; }; + 'part;' => { output->first = 0x2202; fbreak; }; + 'pcy;' => { output->first = 0x043f; fbreak; }; + 'percnt;' => { output->first = 0x25; fbreak; }; + 'period;' => { output->first = 0x2e; fbreak; }; + 'permil;' => { output->first = 0x2030; fbreak; }; + 'perp;' => { output->first = 0x22a5; fbreak; }; + 'pertenk;' => { output->first = 0x2031; fbreak; }; + 'pfr;' => { output->first = 0x0001d52d; fbreak; }; + 'phi;' => { output->first = 0x03c6; fbreak; }; + 'phiv;' => { output->first = 0x03d5; fbreak; }; + 'phmmat;' => { output->first = 0x2133; fbreak; }; + 'phone;' => { output->first = 0x260e; fbreak; }; + 'pi;' => { output->first = 0x03c0; fbreak; }; + 'pitchfork;' => { output->first = 0x22d4; fbreak; }; + 'piv;' => { output->first = 0x03d6; fbreak; }; + 'planck;' => { output->first = 0x210f; fbreak; }; + 'planckh;' => { output->first = 0x210e; fbreak; }; + 'plankv;' => { output->first = 0x210f; fbreak; }; + 'plus;' => { output->first = 0x2b; fbreak; }; + 'plusacir;' => { output->first = 0x2a23; fbreak; }; + 'plusb;' => { output->first = 0x229e; fbreak; }; + 'pluscir;' => { output->first = 0x2a22; fbreak; }; + 'plusdo;' => { output->first = 0x2214; fbreak; }; + 'plusdu;' => { output->first = 0x2a25; fbreak; }; + 'pluse;' => { output->first = 0x2a72; fbreak; }; + 'plusmn;' => { output->first = 0xb1; fbreak; }; + 'plusmn' => { output->first = 0xb1; fbreak; }; + 'plussim;' => { output->first = 0x2a26; fbreak; }; + 'plustwo;' => { output->first = 0x2a27; fbreak; }; + 'pm;' => { output->first = 0xb1; fbreak; }; + 'pointint;' => { output->first = 0x2a15; fbreak; }; + 'popf;' => { output->first = 0x0001d561; fbreak; }; + 'pound;' => { output->first = 0xa3; fbreak; }; + 'pound' => { output->first = 0xa3; fbreak; }; + 'pr;' => { output->first = 0x227a; fbreak; }; + 'prE;' => { output->first = 0x2ab3; fbreak; }; + 'prap;' => { output->first = 0x2ab7; fbreak; }; + 'prcue;' => { output->first = 0x227c; fbreak; }; + 'pre;' => { output->first = 0x2aaf; fbreak; }; + 'prec;' => { output->first = 0x227a; fbreak; }; + 'precapprox;' => { output->first = 0x2ab7; fbreak; }; + 'preccurlyeq;' => { output->first = 0x227c; fbreak; }; + 'preceq;' => { output->first = 0x2aaf; fbreak; }; + 'precnapprox;' => { output->first = 0x2ab9; fbreak; }; + 'precneqq;' => { output->first = 0x2ab5; fbreak; }; + 'precnsim;' => { output->first = 0x22e8; fbreak; }; + 'precsim;' => { output->first = 0x227e; fbreak; }; + 'prime;' => { output->first = 0x2032; fbreak; }; + 'primes;' => { output->first = 0x2119; fbreak; }; + 'prnE;' => { output->first = 0x2ab5; fbreak; }; + 'prnap;' => { output->first = 0x2ab9; fbreak; }; + 'prnsim;' => { output->first = 0x22e8; fbreak; }; + 'prod;' => { output->first = 0x220f; fbreak; }; + 'profalar;' => { output->first = 0x232e; fbreak; }; + 'profline;' => { output->first = 0x2312; fbreak; }; + 'profsurf;' => { output->first = 0x2313; fbreak; }; + 'prop;' => { output->first = 0x221d; fbreak; }; + 'propto;' => { output->first = 0x221d; fbreak; }; + 'prsim;' => { output->first = 0x227e; fbreak; }; + 'prurel;' => { output->first = 0x22b0; fbreak; }; + 'pscr;' => { output->first = 0x0001d4c5; fbreak; }; + 'psi;' => { output->first = 0x03c8; fbreak; }; + 'puncsp;' => { output->first = 0x2008; fbreak; }; + 'qfr;' => { output->first = 0x0001d52e; fbreak; }; + 'qint;' => { output->first = 0x2a0c; fbreak; }; + 'qopf;' => { output->first = 0x0001d562; fbreak; }; + 'qprime;' => { output->first = 0x2057; fbreak; }; + 'qscr;' => { output->first = 0x0001d4c6; fbreak; }; + 'quaternions;' => { output->first = 0x210d; fbreak; }; + 'quatint;' => { output->first = 0x2a16; fbreak; }; + 'quest;' => { output->first = 0x3f; fbreak; }; + 'questeq;' => { output->first = 0x225f; fbreak; }; + 'quot;' => { output->first = 0x22; fbreak; }; + 'quot' => { output->first = 0x22; fbreak; }; + 'rAarr;' => { output->first = 0x21db; fbreak; }; + 'rArr;' => { output->first = 0x21d2; fbreak; }; + 'rAtail;' => { output->first = 0x291c; fbreak; }; + 'rBarr;' => { output->first = 0x290f; fbreak; }; + 'rHar;' => { output->first = 0x2964; fbreak; }; + 'race;' => { output->first = 0x223d; output->second = 0x0331; fbreak; }; + 'racute;' => { output->first = 0x0155; fbreak; }; + 'radic;' => { output->first = 0x221a; fbreak; }; + 'raemptyv;' => { output->first = 0x29b3; fbreak; }; + 'rang;' => { output->first = 0x27e9; fbreak; }; + 'rangd;' => { output->first = 0x2992; fbreak; }; + 'range;' => { output->first = 0x29a5; fbreak; }; + 'rangle;' => { output->first = 0x27e9; fbreak; }; + 'raquo;' => { output->first = 0xbb; fbreak; }; + 'raquo' => { output->first = 0xbb; fbreak; }; + 'rarr;' => { output->first = 0x2192; fbreak; }; + 'rarrap;' => { output->first = 0x2975; fbreak; }; + 'rarrb;' => { output->first = 0x21e5; fbreak; }; + 'rarrbfs;' => { output->first = 0x2920; fbreak; }; + 'rarrc;' => { output->first = 0x2933; fbreak; }; + 'rarrfs;' => { output->first = 0x291e; fbreak; }; + 'rarrhk;' => { output->first = 0x21aa; fbreak; }; + 'rarrlp;' => { output->first = 0x21ac; fbreak; }; + 'rarrpl;' => { output->first = 0x2945; fbreak; }; + 'rarrsim;' => { output->first = 0x2974; fbreak; }; + 'rarrtl;' => { output->first = 0x21a3; fbreak; }; + 'rarrw;' => { output->first = 0x219d; fbreak; }; + 'ratail;' => { output->first = 0x291a; fbreak; }; + 'ratio;' => { output->first = 0x2236; fbreak; }; + 'rationals;' => { output->first = 0x211a; fbreak; }; + 'rbarr;' => { output->first = 0x290d; fbreak; }; + 'rbbrk;' => { output->first = 0x2773; fbreak; }; + 'rbrace;' => { output->first = 0x7d; fbreak; }; + 'rbrack;' => { output->first = 0x5d; fbreak; }; + 'rbrke;' => { output->first = 0x298c; fbreak; }; + 'rbrksld;' => { output->first = 0x298e; fbreak; }; + 'rbrkslu;' => { output->first = 0x2990; fbreak; }; + 'rcaron;' => { output->first = 0x0159; fbreak; }; + 'rcedil;' => { output->first = 0x0157; fbreak; }; + 'rceil;' => { output->first = 0x2309; fbreak; }; + 'rcub;' => { output->first = 0x7d; fbreak; }; + 'rcy;' => { output->first = 0x0440; fbreak; }; + 'rdca;' => { output->first = 0x2937; fbreak; }; + 'rdldhar;' => { output->first = 0x2969; fbreak; }; + 'rdquo;' => { output->first = 0x201d; fbreak; }; + 'rdquor;' => { output->first = 0x201d; fbreak; }; + 'rdsh;' => { output->first = 0x21b3; fbreak; }; + 'real;' => { output->first = 0x211c; fbreak; }; + 'realine;' => { output->first = 0x211b; fbreak; }; + 'realpart;' => { output->first = 0x211c; fbreak; }; + 'reals;' => { output->first = 0x211d; fbreak; }; + 'rect;' => { output->first = 0x25ad; fbreak; }; + 'reg;' => { output->first = 0xae; fbreak; }; + 'reg' => { output->first = 0xae; fbreak; }; + 'rfisht;' => { output->first = 0x297d; fbreak; }; + 'rfloor;' => { output->first = 0x230b; fbreak; }; + 'rfr;' => { output->first = 0x0001d52f; fbreak; }; + 'rhard;' => { output->first = 0x21c1; fbreak; }; + 'rharu;' => { output->first = 0x21c0; fbreak; }; + 'rharul;' => { output->first = 0x296c; fbreak; }; + 'rho;' => { output->first = 0x03c1; fbreak; }; + 'rhov;' => { output->first = 0x03f1; fbreak; }; + 'rightarrow;' => { output->first = 0x2192; fbreak; }; + 'rightarrowtail;' => { output->first = 0x21a3; fbreak; }; + 'rightharpoondown;' => { output->first = 0x21c1; fbreak; }; + 'rightharpoonup;' => { output->first = 0x21c0; fbreak; }; + 'rightleftarrows;' => { output->first = 0x21c4; fbreak; }; + 'rightleftharpoons;' => { output->first = 0x21cc; fbreak; }; + 'rightrightarrows;' => { output->first = 0x21c9; fbreak; }; + 'rightsquigarrow;' => { output->first = 0x219d; fbreak; }; + 'rightthreetimes;' => { output->first = 0x22cc; fbreak; }; + 'ring;' => { output->first = 0x02da; fbreak; }; + 'risingdotseq;' => { output->first = 0x2253; fbreak; }; + 'rlarr;' => { output->first = 0x21c4; fbreak; }; + 'rlhar;' => { output->first = 0x21cc; fbreak; }; + 'rlm;' => { output->first = 0x200f; fbreak; }; + 'rmoust;' => { output->first = 0x23b1; fbreak; }; + 'rmoustache;' => { output->first = 0x23b1; fbreak; }; + 'rnmid;' => { output->first = 0x2aee; fbreak; }; + 'roang;' => { output->first = 0x27ed; fbreak; }; + 'roarr;' => { output->first = 0x21fe; fbreak; }; + 'robrk;' => { output->first = 0x27e7; fbreak; }; + 'ropar;' => { output->first = 0x2986; fbreak; }; + 'ropf;' => { output->first = 0x0001d563; fbreak; }; + 'roplus;' => { output->first = 0x2a2e; fbreak; }; + 'rotimes;' => { output->first = 0x2a35; fbreak; }; + 'rpar;' => { output->first = 0x29; fbreak; }; + 'rpargt;' => { output->first = 0x2994; fbreak; }; + 'rppolint;' => { output->first = 0x2a12; fbreak; }; + 'rrarr;' => { output->first = 0x21c9; fbreak; }; + 'rsaquo;' => { output->first = 0x203a; fbreak; }; + 'rscr;' => { output->first = 0x0001d4c7; fbreak; }; + 'rsh;' => { output->first = 0x21b1; fbreak; }; + 'rsqb;' => { output->first = 0x5d; fbreak; }; + 'rsquo;' => { output->first = 0x2019; fbreak; }; + 'rsquor;' => { output->first = 0x2019; fbreak; }; + 'rthree;' => { output->first = 0x22cc; fbreak; }; + 'rtimes;' => { output->first = 0x22ca; fbreak; }; + 'rtri;' => { output->first = 0x25b9; fbreak; }; + 'rtrie;' => { output->first = 0x22b5; fbreak; }; + 'rtrif;' => { output->first = 0x25b8; fbreak; }; + 'rtriltri;' => { output->first = 0x29ce; fbreak; }; + 'ruluhar;' => { output->first = 0x2968; fbreak; }; + 'rx;' => { output->first = 0x211e; fbreak; }; + 'sacute;' => { output->first = 0x015b; fbreak; }; + 'sbquo;' => { output->first = 0x201a; fbreak; }; + 'sc;' => { output->first = 0x227b; fbreak; }; + 'scE;' => { output->first = 0x2ab4; fbreak; }; + 'scap;' => { output->first = 0x2ab8; fbreak; }; + 'scaron;' => { output->first = 0x0161; fbreak; }; + 'sccue;' => { output->first = 0x227d; fbreak; }; + 'sce;' => { output->first = 0x2ab0; fbreak; }; + 'scedil;' => { output->first = 0x015f; fbreak; }; + 'scirc;' => { output->first = 0x015d; fbreak; }; + 'scnE;' => { output->first = 0x2ab6; fbreak; }; + 'scnap;' => { output->first = 0x2aba; fbreak; }; + 'scnsim;' => { output->first = 0x22e9; fbreak; }; + 'scpolint;' => { output->first = 0x2a13; fbreak; }; + 'scsim;' => { output->first = 0x227f; fbreak; }; + 'scy;' => { output->first = 0x0441; fbreak; }; + 'sdot;' => { output->first = 0x22c5; fbreak; }; + 'sdotb;' => { output->first = 0x22a1; fbreak; }; + 'sdote;' => { output->first = 0x2a66; fbreak; }; + 'seArr;' => { output->first = 0x21d8; fbreak; }; + 'searhk;' => { output->first = 0x2925; fbreak; }; + 'searr;' => { output->first = 0x2198; fbreak; }; + 'searrow;' => { output->first = 0x2198; fbreak; }; + 'sect;' => { output->first = 0xa7; fbreak; }; + 'sect' => { output->first = 0xa7; fbreak; }; + 'semi;' => { output->first = 0x3b; fbreak; }; + 'seswar;' => { output->first = 0x2929; fbreak; }; + 'setminus;' => { output->first = 0x2216; fbreak; }; + 'setmn;' => { output->first = 0x2216; fbreak; }; + 'sext;' => { output->first = 0x2736; fbreak; }; + 'sfr;' => { output->first = 0x0001d530; fbreak; }; + 'sfrown;' => { output->first = 0x2322; fbreak; }; + 'sharp;' => { output->first = 0x266f; fbreak; }; + 'shchcy;' => { output->first = 0x0449; fbreak; }; + 'shcy;' => { output->first = 0x0448; fbreak; }; + 'shortmid;' => { output->first = 0x2223; fbreak; }; + 'shortparallel;' => { output->first = 0x2225; fbreak; }; + 'shy;' => { output->first = 0xad; fbreak; }; + 'shy' => { output->first = 0xad; fbreak; }; + 'sigma;' => { output->first = 0x03c3; fbreak; }; + 'sigmaf;' => { output->first = 0x03c2; fbreak; }; + 'sigmav;' => { output->first = 0x03c2; fbreak; }; + 'sim;' => { output->first = 0x223c; fbreak; }; + 'simdot;' => { output->first = 0x2a6a; fbreak; }; + 'sime;' => { output->first = 0x2243; fbreak; }; + 'simeq;' => { output->first = 0x2243; fbreak; }; + 'simg;' => { output->first = 0x2a9e; fbreak; }; + 'simgE;' => { output->first = 0x2aa0; fbreak; }; + 'siml;' => { output->first = 0x2a9d; fbreak; }; + 'simlE;' => { output->first = 0x2a9f; fbreak; }; + 'simne;' => { output->first = 0x2246; fbreak; }; + 'simplus;' => { output->first = 0x2a24; fbreak; }; + 'simrarr;' => { output->first = 0x2972; fbreak; }; + 'slarr;' => { output->first = 0x2190; fbreak; }; + 'smallsetminus;' => { output->first = 0x2216; fbreak; }; + 'smashp;' => { output->first = 0x2a33; fbreak; }; + 'smeparsl;' => { output->first = 0x29e4; fbreak; }; + 'smid;' => { output->first = 0x2223; fbreak; }; + 'smile;' => { output->first = 0x2323; fbreak; }; + 'smt;' => { output->first = 0x2aaa; fbreak; }; + 'smte;' => { output->first = 0x2aac; fbreak; }; + 'smtes;' => { output->first = 0x2aac; output->second = 0xfe00; fbreak; }; + 'softcy;' => { output->first = 0x044c; fbreak; }; + 'sol;' => { output->first = 0x2f; fbreak; }; + 'solb;' => { output->first = 0x29c4; fbreak; }; + 'solbar;' => { output->first = 0x233f; fbreak; }; + 'sopf;' => { output->first = 0x0001d564; fbreak; }; + 'spades;' => { output->first = 0x2660; fbreak; }; + 'spadesuit;' => { output->first = 0x2660; fbreak; }; + 'spar;' => { output->first = 0x2225; fbreak; }; + 'sqcap;' => { output->first = 0x2293; fbreak; }; + 'sqcaps;' => { output->first = 0x2293; output->second = 0xfe00; fbreak; }; + 'sqcup;' => { output->first = 0x2294; fbreak; }; + 'sqcups;' => { output->first = 0x2294; output->second = 0xfe00; fbreak; }; + 'sqsub;' => { output->first = 0x228f; fbreak; }; + 'sqsube;' => { output->first = 0x2291; fbreak; }; + 'sqsubset;' => { output->first = 0x228f; fbreak; }; + 'sqsubseteq;' => { output->first = 0x2291; fbreak; }; + 'sqsup;' => { output->first = 0x2290; fbreak; }; + 'sqsupe;' => { output->first = 0x2292; fbreak; }; + 'sqsupset;' => { output->first = 0x2290; fbreak; }; + 'sqsupseteq;' => { output->first = 0x2292; fbreak; }; + 'squ;' => { output->first = 0x25a1; fbreak; }; + 'square;' => { output->first = 0x25a1; fbreak; }; + 'squarf;' => { output->first = 0x25aa; fbreak; }; + 'squf;' => { output->first = 0x25aa; fbreak; }; + 'srarr;' => { output->first = 0x2192; fbreak; }; + 'sscr;' => { output->first = 0x0001d4c8; fbreak; }; + 'ssetmn;' => { output->first = 0x2216; fbreak; }; + 'ssmile;' => { output->first = 0x2323; fbreak; }; + 'sstarf;' => { output->first = 0x22c6; fbreak; }; + 'star;' => { output->first = 0x2606; fbreak; }; + 'starf;' => { output->first = 0x2605; fbreak; }; + 'straightepsilon;' => { output->first = 0x03f5; fbreak; }; + 'straightphi;' => { output->first = 0x03d5; fbreak; }; + 'strns;' => { output->first = 0xaf; fbreak; }; + 'sub;' => { output->first = 0x2282; fbreak; }; + 'subE;' => { output->first = 0x2ac5; fbreak; }; + 'subdot;' => { output->first = 0x2abd; fbreak; }; + 'sube;' => { output->first = 0x2286; fbreak; }; + 'subedot;' => { output->first = 0x2ac3; fbreak; }; + 'submult;' => { output->first = 0x2ac1; fbreak; }; + 'subnE;' => { output->first = 0x2acb; fbreak; }; + 'subne;' => { output->first = 0x228a; fbreak; }; + 'subplus;' => { output->first = 0x2abf; fbreak; }; + 'subrarr;' => { output->first = 0x2979; fbreak; }; + 'subset;' => { output->first = 0x2282; fbreak; }; + 'subseteq;' => { output->first = 0x2286; fbreak; }; + 'subseteqq;' => { output->first = 0x2ac5; fbreak; }; + 'subsetneq;' => { output->first = 0x228a; fbreak; }; + 'subsetneqq;' => { output->first = 0x2acb; fbreak; }; + 'subsim;' => { output->first = 0x2ac7; fbreak; }; + 'subsub;' => { output->first = 0x2ad5; fbreak; }; + 'subsup;' => { output->first = 0x2ad3; fbreak; }; + 'succ;' => { output->first = 0x227b; fbreak; }; + 'succapprox;' => { output->first = 0x2ab8; fbreak; }; + 'succcurlyeq;' => { output->first = 0x227d; fbreak; }; + 'succeq;' => { output->first = 0x2ab0; fbreak; }; + 'succnapprox;' => { output->first = 0x2aba; fbreak; }; + 'succneqq;' => { output->first = 0x2ab6; fbreak; }; + 'succnsim;' => { output->first = 0x22e9; fbreak; }; + 'succsim;' => { output->first = 0x227f; fbreak; }; + 'sum;' => { output->first = 0x2211; fbreak; }; + 'sung;' => { output->first = 0x266a; fbreak; }; + 'sup1;' => { output->first = 0xb9; fbreak; }; + 'sup1' => { output->first = 0xb9; fbreak; }; + 'sup2;' => { output->first = 0xb2; fbreak; }; + 'sup2' => { output->first = 0xb2; fbreak; }; + 'sup3;' => { output->first = 0xb3; fbreak; }; + 'sup3' => { output->first = 0xb3; fbreak; }; + 'sup;' => { output->first = 0x2283; fbreak; }; + 'supE;' => { output->first = 0x2ac6; fbreak; }; + 'supdot;' => { output->first = 0x2abe; fbreak; }; + 'supdsub;' => { output->first = 0x2ad8; fbreak; }; + 'supe;' => { output->first = 0x2287; fbreak; }; + 'supedot;' => { output->first = 0x2ac4; fbreak; }; + 'suphsol;' => { output->first = 0x27c9; fbreak; }; + 'suphsub;' => { output->first = 0x2ad7; fbreak; }; + 'suplarr;' => { output->first = 0x297b; fbreak; }; + 'supmult;' => { output->first = 0x2ac2; fbreak; }; + 'supnE;' => { output->first = 0x2acc; fbreak; }; + 'supne;' => { output->first = 0x228b; fbreak; }; + 'supplus;' => { output->first = 0x2ac0; fbreak; }; + 'supset;' => { output->first = 0x2283; fbreak; }; + 'supseteq;' => { output->first = 0x2287; fbreak; }; + 'supseteqq;' => { output->first = 0x2ac6; fbreak; }; + 'supsetneq;' => { output->first = 0x228b; fbreak; }; + 'supsetneqq;' => { output->first = 0x2acc; fbreak; }; + 'supsim;' => { output->first = 0x2ac8; fbreak; }; + 'supsub;' => { output->first = 0x2ad4; fbreak; }; + 'supsup;' => { output->first = 0x2ad6; fbreak; }; + 'swArr;' => { output->first = 0x21d9; fbreak; }; + 'swarhk;' => { output->first = 0x2926; fbreak; }; + 'swarr;' => { output->first = 0x2199; fbreak; }; + 'swarrow;' => { output->first = 0x2199; fbreak; }; + 'swnwar;' => { output->first = 0x292a; fbreak; }; + 'szlig;' => { output->first = 0xdf; fbreak; }; + 'szlig' => { output->first = 0xdf; fbreak; }; + 'target;' => { output->first = 0x2316; fbreak; }; + 'tau;' => { output->first = 0x03c4; fbreak; }; + 'tbrk;' => { output->first = 0x23b4; fbreak; }; + 'tcaron;' => { output->first = 0x0165; fbreak; }; + 'tcedil;' => { output->first = 0x0163; fbreak; }; + 'tcy;' => { output->first = 0x0442; fbreak; }; + 'tdot;' => { output->first = 0x20db; fbreak; }; + 'telrec;' => { output->first = 0x2315; fbreak; }; + 'tfr;' => { output->first = 0x0001d531; fbreak; }; + 'there4;' => { output->first = 0x2234; fbreak; }; + 'therefore;' => { output->first = 0x2234; fbreak; }; + 'theta;' => { output->first = 0x03b8; fbreak; }; + 'thetasym;' => { output->first = 0x03d1; fbreak; }; + 'thetav;' => { output->first = 0x03d1; fbreak; }; + 'thickapprox;' => { output->first = 0x2248; fbreak; }; + 'thicksim;' => { output->first = 0x223c; fbreak; }; + 'thinsp;' => { output->first = 0x2009; fbreak; }; + 'thkap;' => { output->first = 0x2248; fbreak; }; + 'thksim;' => { output->first = 0x223c; fbreak; }; + 'thorn;' => { output->first = 0xfe; fbreak; }; + 'thorn' => { output->first = 0xfe; fbreak; }; + 'tilde;' => { output->first = 0x02dc; fbreak; }; + 'times;' => { output->first = 0xd7; fbreak; }; + 'times' => { output->first = 0xd7; fbreak; }; + 'timesb;' => { output->first = 0x22a0; fbreak; }; + 'timesbar;' => { output->first = 0x2a31; fbreak; }; + 'timesd;' => { output->first = 0x2a30; fbreak; }; + 'tint;' => { output->first = 0x222d; fbreak; }; + 'toea;' => { output->first = 0x2928; fbreak; }; + 'top;' => { output->first = 0x22a4; fbreak; }; + 'topbot;' => { output->first = 0x2336; fbreak; }; + 'topcir;' => { output->first = 0x2af1; fbreak; }; + 'topf;' => { output->first = 0x0001d565; fbreak; }; + 'topfork;' => { output->first = 0x2ada; fbreak; }; + 'tosa;' => { output->first = 0x2929; fbreak; }; + 'tprime;' => { output->first = 0x2034; fbreak; }; + 'trade;' => { output->first = 0x2122; fbreak; }; + 'triangle;' => { output->first = 0x25b5; fbreak; }; + 'triangledown;' => { output->first = 0x25bf; fbreak; }; + 'triangleleft;' => { output->first = 0x25c3; fbreak; }; + 'trianglelefteq;' => { output->first = 0x22b4; fbreak; }; + 'triangleq;' => { output->first = 0x225c; fbreak; }; + 'triangleright;' => { output->first = 0x25b9; fbreak; }; + 'trianglerighteq;' => { output->first = 0x22b5; fbreak; }; + 'tridot;' => { output->first = 0x25ec; fbreak; }; + 'trie;' => { output->first = 0x225c; fbreak; }; + 'triminus;' => { output->first = 0x2a3a; fbreak; }; + 'triplus;' => { output->first = 0x2a39; fbreak; }; + 'trisb;' => { output->first = 0x29cd; fbreak; }; + 'tritime;' => { output->first = 0x2a3b; fbreak; }; + 'trpezium;' => { output->first = 0x23e2; fbreak; }; + 'tscr;' => { output->first = 0x0001d4c9; fbreak; }; + 'tscy;' => { output->first = 0x0446; fbreak; }; + 'tshcy;' => { output->first = 0x045b; fbreak; }; + 'tstrok;' => { output->first = 0x0167; fbreak; }; + 'twixt;' => { output->first = 0x226c; fbreak; }; + 'twoheadleftarrow;' => { output->first = 0x219e; fbreak; }; + 'twoheadrightarrow;' => { output->first = 0x21a0; fbreak; }; + 'uArr;' => { output->first = 0x21d1; fbreak; }; + 'uHar;' => { output->first = 0x2963; fbreak; }; + 'uacute;' => { output->first = 0xfa; fbreak; }; + 'uacute' => { output->first = 0xfa; fbreak; }; + 'uarr;' => { output->first = 0x2191; fbreak; }; + 'ubrcy;' => { output->first = 0x045e; fbreak; }; + 'ubreve;' => { output->first = 0x016d; fbreak; }; + 'ucirc;' => { output->first = 0xfb; fbreak; }; + 'ucirc' => { output->first = 0xfb; fbreak; }; + 'ucy;' => { output->first = 0x0443; fbreak; }; + 'udarr;' => { output->first = 0x21c5; fbreak; }; + 'udblac;' => { output->first = 0x0171; fbreak; }; + 'udhar;' => { output->first = 0x296e; fbreak; }; + 'ufisht;' => { output->first = 0x297e; fbreak; }; + 'ufr;' => { output->first = 0x0001d532; fbreak; }; + 'ugrave;' => { output->first = 0xf9; fbreak; }; + 'ugrave' => { output->first = 0xf9; fbreak; }; + 'uharl;' => { output->first = 0x21bf; fbreak; }; + 'uharr;' => { output->first = 0x21be; fbreak; }; + 'uhblk;' => { output->first = 0x2580; fbreak; }; + 'ulcorn;' => { output->first = 0x231c; fbreak; }; + 'ulcorner;' => { output->first = 0x231c; fbreak; }; + 'ulcrop;' => { output->first = 0x230f; fbreak; }; + 'ultri;' => { output->first = 0x25f8; fbreak; }; + 'umacr;' => { output->first = 0x016b; fbreak; }; + 'uml;' => { output->first = 0xa8; fbreak; }; + 'uml' => { output->first = 0xa8; fbreak; }; + 'uogon;' => { output->first = 0x0173; fbreak; }; + 'uopf;' => { output->first = 0x0001d566; fbreak; }; + 'uparrow;' => { output->first = 0x2191; fbreak; }; + 'updownarrow;' => { output->first = 0x2195; fbreak; }; + 'upharpoonleft;' => { output->first = 0x21bf; fbreak; }; + 'upharpoonright;' => { output->first = 0x21be; fbreak; }; + 'uplus;' => { output->first = 0x228e; fbreak; }; + 'upsi;' => { output->first = 0x03c5; fbreak; }; + 'upsih;' => { output->first = 0x03d2; fbreak; }; + 'upsilon;' => { output->first = 0x03c5; fbreak; }; + 'upuparrows;' => { output->first = 0x21c8; fbreak; }; + 'urcorn;' => { output->first = 0x231d; fbreak; }; + 'urcorner;' => { output->first = 0x231d; fbreak; }; + 'urcrop;' => { output->first = 0x230e; fbreak; }; + 'uring;' => { output->first = 0x016f; fbreak; }; + 'urtri;' => { output->first = 0x25f9; fbreak; }; + 'uscr;' => { output->first = 0x0001d4ca; fbreak; }; + 'utdot;' => { output->first = 0x22f0; fbreak; }; + 'utilde;' => { output->first = 0x0169; fbreak; }; + 'utri;' => { output->first = 0x25b5; fbreak; }; + 'utrif;' => { output->first = 0x25b4; fbreak; }; + 'uuarr;' => { output->first = 0x21c8; fbreak; }; + 'uuml;' => { output->first = 0xfc; fbreak; }; + 'uuml' => { output->first = 0xfc; fbreak; }; + 'uwangle;' => { output->first = 0x29a7; fbreak; }; + 'vArr;' => { output->first = 0x21d5; fbreak; }; + 'vBar;' => { output->first = 0x2ae8; fbreak; }; + 'vBarv;' => { output->first = 0x2ae9; fbreak; }; + 'vDash;' => { output->first = 0x22a8; fbreak; }; + 'vangrt;' => { output->first = 0x299c; fbreak; }; + 'varepsilon;' => { output->first = 0x03f5; fbreak; }; + 'varkappa;' => { output->first = 0x03f0; fbreak; }; + 'varnothing;' => { output->first = 0x2205; fbreak; }; + 'varphi;' => { output->first = 0x03d5; fbreak; }; + 'varpi;' => { output->first = 0x03d6; fbreak; }; + 'varpropto;' => { output->first = 0x221d; fbreak; }; + 'varr;' => { output->first = 0x2195; fbreak; }; + 'varrho;' => { output->first = 0x03f1; fbreak; }; + 'varsigma;' => { output->first = 0x03c2; fbreak; }; + 'varsubsetneq;' => { output->first = 0x228a; output->second = 0xfe00; fbreak; }; + 'varsubsetneqq;' => { output->first = 0x2acb; output->second = 0xfe00; fbreak; }; + 'varsupsetneq;' => { output->first = 0x228b; output->second = 0xfe00; fbreak; }; + 'varsupsetneqq;' => { output->first = 0x2acc; output->second = 0xfe00; fbreak; }; + 'vartheta;' => { output->first = 0x03d1; fbreak; }; + 'vartriangleleft;' => { output->first = 0x22b2; fbreak; }; + 'vartriangleright;' => { output->first = 0x22b3; fbreak; }; + 'vcy;' => { output->first = 0x0432; fbreak; }; + 'vdash;' => { output->first = 0x22a2; fbreak; }; + 'vee;' => { output->first = 0x2228; fbreak; }; + 'veebar;' => { output->first = 0x22bb; fbreak; }; + 'veeeq;' => { output->first = 0x225a; fbreak; }; + 'vellip;' => { output->first = 0x22ee; fbreak; }; + 'verbar;' => { output->first = 0x7c; fbreak; }; + 'vert;' => { output->first = 0x7c; fbreak; }; + 'vfr;' => { output->first = 0x0001d533; fbreak; }; + 'vltri;' => { output->first = 0x22b2; fbreak; }; + 'vnsub;' => { output->first = 0x2282; output->second = 0x20d2; fbreak; }; + 'vnsup;' => { output->first = 0x2283; output->second = 0x20d2; fbreak; }; + 'vopf;' => { output->first = 0x0001d567; fbreak; }; + 'vprop;' => { output->first = 0x221d; fbreak; }; + 'vrtri;' => { output->first = 0x22b3; fbreak; }; + 'vscr;' => { output->first = 0x0001d4cb; fbreak; }; + 'vsubnE;' => { output->first = 0x2acb; output->second = 0xfe00; fbreak; }; + 'vsubne;' => { output->first = 0x228a; output->second = 0xfe00; fbreak; }; + 'vsupnE;' => { output->first = 0x2acc; output->second = 0xfe00; fbreak; }; + 'vsupne;' => { output->first = 0x228b; output->second = 0xfe00; fbreak; }; + 'vzigzag;' => { output->first = 0x299a; fbreak; }; + 'wcirc;' => { output->first = 0x0175; fbreak; }; + 'wedbar;' => { output->first = 0x2a5f; fbreak; }; + 'wedge;' => { output->first = 0x2227; fbreak; }; + 'wedgeq;' => { output->first = 0x2259; fbreak; }; + 'weierp;' => { output->first = 0x2118; fbreak; }; + 'wfr;' => { output->first = 0x0001d534; fbreak; }; + 'wopf;' => { output->first = 0x0001d568; fbreak; }; + 'wp;' => { output->first = 0x2118; fbreak; }; + 'wr;' => { output->first = 0x2240; fbreak; }; + 'wreath;' => { output->first = 0x2240; fbreak; }; + 'wscr;' => { output->first = 0x0001d4cc; fbreak; }; + 'xcap;' => { output->first = 0x22c2; fbreak; }; + 'xcirc;' => { output->first = 0x25ef; fbreak; }; + 'xcup;' => { output->first = 0x22c3; fbreak; }; + 'xdtri;' => { output->first = 0x25bd; fbreak; }; + 'xfr;' => { output->first = 0x0001d535; fbreak; }; + 'xhArr;' => { output->first = 0x27fa; fbreak; }; + 'xharr;' => { output->first = 0x27f7; fbreak; }; + 'xi;' => { output->first = 0x03be; fbreak; }; + 'xlArr;' => { output->first = 0x27f8; fbreak; }; + 'xlarr;' => { output->first = 0x27f5; fbreak; }; + 'xmap;' => { output->first = 0x27fc; fbreak; }; + 'xnis;' => { output->first = 0x22fb; fbreak; }; + 'xodot;' => { output->first = 0x2a00; fbreak; }; + 'xopf;' => { output->first = 0x0001d569; fbreak; }; + 'xoplus;' => { output->first = 0x2a01; fbreak; }; + 'xotime;' => { output->first = 0x2a02; fbreak; }; + 'xrArr;' => { output->first = 0x27f9; fbreak; }; + 'xrarr;' => { output->first = 0x27f6; fbreak; }; + 'xscr;' => { output->first = 0x0001d4cd; fbreak; }; + 'xsqcup;' => { output->first = 0x2a06; fbreak; }; + 'xuplus;' => { output->first = 0x2a04; fbreak; }; + 'xutri;' => { output->first = 0x25b3; fbreak; }; + 'xvee;' => { output->first = 0x22c1; fbreak; }; + 'xwedge;' => { output->first = 0x22c0; fbreak; }; + 'yacute;' => { output->first = 0xfd; fbreak; }; + 'yacute' => { output->first = 0xfd; fbreak; }; + 'yacy;' => { output->first = 0x044f; fbreak; }; + 'ycirc;' => { output->first = 0x0177; fbreak; }; + 'ycy;' => { output->first = 0x044b; fbreak; }; + 'yen;' => { output->first = 0xa5; fbreak; }; + 'yen' => { output->first = 0xa5; fbreak; }; + 'yfr;' => { output->first = 0x0001d536; fbreak; }; + 'yicy;' => { output->first = 0x0457; fbreak; }; + 'yopf;' => { output->first = 0x0001d56a; fbreak; }; + 'yscr;' => { output->first = 0x0001d4ce; fbreak; }; + 'yucy;' => { output->first = 0x044e; fbreak; }; + 'yuml;' => { output->first = 0xff; fbreak; }; + 'yuml' => { output->first = 0xff; fbreak; }; + 'zacute;' => { output->first = 0x017a; fbreak; }; + 'zcaron;' => { output->first = 0x017e; fbreak; }; + 'zcy;' => { output->first = 0x0437; fbreak; }; + 'zdot;' => { output->first = 0x017c; fbreak; }; + 'zeetrf;' => { output->first = 0x2128; fbreak; }; + 'zeta;' => { output->first = 0x03b6; fbreak; }; + 'zfr;' => { output->first = 0x0001d537; fbreak; }; + 'zhcy;' => { output->first = 0x0436; fbreak; }; + 'zigrarr;' => { output->first = 0x21dd; fbreak; }; + 'zopf;' => { output->first = 0x0001d56b; fbreak; }; + 'zscr;' => { output->first = 0x0001d4cf; fbreak; }; + 'zwj;' => { output->first = 0x200d; fbreak; }; + 'zwnj;' => { output->first = 0x200c; fbreak; }; +*|; +}%% + +// clang-format off +%% write data noerror nofinal; +// clang-format on + +static bool consume_named_ref( + struct GumboInternalParser* parser, Utf8Iterator* input, bool is_in_attribute, + OneOrTwoCodepoints* output) { + assert(output->first == kGumboNoChar); + const char* p = utf8iterator_get_char_pointer(input); + const char* pe = utf8iterator_get_end_pointer(input); + const char* eof = pe; + const char* te = 0; + const char *ts, *start; + int cs, act; + + // clang-format off + %% write init; + // Avoid unused variable warnings. + (void) act; + (void) ts; + (void) char_ref_en_valid_named_ref; + + start = p; + %% write exec; + // clang-format on + + if (cs >= %%{ write first_final; }%%) { + assert(output->first != kGumboNoChar); + char last_char = *(te - 1); + ptrdiff_t len = te - start; + if (last_char == ';') { + bool matched = utf8iterator_maybe_consume_match(input, start, len, true); + assert(matched); + return true; + } else if (is_in_attribute && (*te == '=' || isalnum(*te))) { + output->first = kGumboNoChar; + output->second = kGumboNoChar; + utf8iterator_reset(input); + return true; + } else { + GumboStringPiece bad_ref; + bad_ref.length = te - start; + bad_ref.data = start; + add_named_reference_error( + parser, input, GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON, bad_ref); + bool matched = utf8iterator_maybe_consume_match(input, start, len, true); + assert(matched); + return false; + } + } else { + output->first = kGumboNoChar; + output->second = kGumboNoChar; + bool status = maybe_add_invalid_named_reference(parser, input); + utf8iterator_reset(input); + return status; + } +} + +bool consume_char_ref( + struct GumboInternalParser* parser, struct GumboInternalUtf8Iterator* input, + int additional_allowed_char, bool is_in_attribute, + OneOrTwoCodepoints* output) { + utf8iterator_mark(input); + utf8iterator_next(input); + int c = utf8iterator_current(input); + output->first = kGumboNoChar; + output->second = kGumboNoChar; + if (c == additional_allowed_char) { + utf8iterator_reset(input); + output->first = kGumboNoChar; + return true; + } + switch (utf8iterator_current(input)) { + case '\t': + case '\n': + case '\f': + case ' ': + case '<': + case '&': + case -1: + utf8iterator_reset(input); + return true; + case '#': + return consume_numeric_ref(parser, input, &output->first); + default: + return consume_named_ref(parser, input, is_in_attribute, output); + } +} diff --git a/libs/litehtml/src/gumbo/error.c b/libs/litehtml/src/gumbo/error.c new file mode 100644 index 0000000000..369e7c11e8 --- /dev/null +++ b/libs/litehtml/src/gumbo/error.c @@ -0,0 +1,279 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "error.h" + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "gumbo.h" +#include "parser.h" +#include "string_buffer.h" +#include "util.h" +#include "vector.h" + +// Prints a formatted message to a StringBuffer. This automatically resizes the +// StringBuffer as necessary to fit the message. Returns the number of bytes +// written. +static int print_message( + GumboParser* parser, GumboStringBuffer* output, const char* format, ...) { + va_list args; + size_t remaining_capacity = output->capacity - output->length; + va_start(args, format); + int bytes_written = vsnprintf( + output->data + output->length, remaining_capacity, format, args); + va_end(args); +#ifdef _MSC_VER + if (bytes_written == -1) { + // vsnprintf returns -1 on MSVC++ if there's not enough capacity, instead of + // returning the number of bytes that would've been written had there been + // enough. In this case, we'll double the buffer size and hope it fits when + // we retry (letting it fail and returning 0 if it doesn't), since there's + // no way to smartly resize the buffer. + gumbo_string_buffer_reserve(parser, output->capacity * 2, output); + va_start(args, format); + int result = vsnprintf( + output->data + output->length, remaining_capacity, format, args); + va_end(args); + return result == -1 ? 0 : result; + } +#else + // -1 in standard C99 indicates an encoding error. Return 0 and do nothing. + if (bytes_written == -1) { + return 0; + } +#endif + + if (bytes_written > remaining_capacity) { + gumbo_string_buffer_reserve( + parser, output->capacity + bytes_written, output); + remaining_capacity = output->capacity - output->length; + va_start(args, format); + bytes_written = vsnprintf( + output->data + output->length, remaining_capacity, format, args); + va_end(args); + } + output->length += bytes_written; + return bytes_written; +} + +static void print_tag_stack(GumboParser* parser, const GumboParserError* error, + GumboStringBuffer* output) { + print_message(parser, output, " Currently open tags: "); + for (unsigned int i = 0; i < error->tag_stack.length; ++i) { + if (i) { + print_message(parser, output, ", "); + } + GumboTag tag = (GumboTag)(uintptr_t) error->tag_stack.data[i]; + print_message(parser, output, gumbo_normalized_tagname(tag)); + } + gumbo_string_buffer_append_codepoint(parser, '.', output); +} + +static void handle_parser_error(GumboParser* parser, + const GumboParserError* error, GumboStringBuffer* output) { + if (error->parser_state == GUMBO_INSERTION_MODE_INITIAL && + error->input_type != GUMBO_TOKEN_DOCTYPE) { + print_message( + parser, output, "The doctype must be the first token in the document"); + return; + } + + switch (error->input_type) { + case GUMBO_TOKEN_DOCTYPE: + print_message(parser, output, "This is not a legal doctype"); + return; + case GUMBO_TOKEN_COMMENT: + // Should never happen; comments are always legal. + assert(0); + // But just in case... + print_message(parser, output, "Comments aren't legal here"); + return; + case GUMBO_TOKEN_CDATA: + case GUMBO_TOKEN_WHITESPACE: + case GUMBO_TOKEN_CHARACTER: + print_message(parser, output, "Character tokens aren't legal here"); + return; + case GUMBO_TOKEN_NULL: + print_message(parser, output, "Null bytes are not allowed in HTML5"); + return; + case GUMBO_TOKEN_EOF: + if (error->parser_state == GUMBO_INSERTION_MODE_INITIAL) { + print_message(parser, output, "You must provide a doctype"); + } else { + print_message(parser, output, "Premature end of file"); + print_tag_stack(parser, error, output); + } + return; + case GUMBO_TOKEN_START_TAG: + case GUMBO_TOKEN_END_TAG: + print_message(parser, output, "That tag isn't allowed here"); + print_tag_stack(parser, error, output); + // TODO(jdtang): Give more specific messaging. + return; + } +} + +// Finds the preceding newline in an original source buffer from a given byte +// location. Returns a character pointer to the character after that, or a +// pointer to the beginning of the string if this is the first line. +static const char* find_last_newline( + const char* original_text, const char* error_location) { + assert(error_location >= original_text); + const char* c = error_location; + for (; c != original_text && *c != '\n'; --c) { + // There may be an error at EOF, which would be a nul byte. + assert(*c || c == error_location); + } + return c == original_text ? c : c + 1; +} + +// Finds the next newline in the original source buffer from a given byte +// location. Returns a character pointer to that newline, or a pointer to the +// terminating null byte if this is the last line. +static const char* find_next_newline( + const char* original_text, const char* error_location) { + const char* c = error_location; + for (; *c && *c != '\n'; ++c) + ; + return c; +} + +GumboError* gumbo_add_error(GumboParser* parser) { + int max_errors = parser->_options->max_errors; + if (max_errors >= 0 && parser->_output->errors.length >= (unsigned int) max_errors) { + return NULL; + } + GumboError* error = gumbo_parser_allocate(parser, sizeof(GumboError)); + gumbo_vector_add(parser, error, &parser->_output->errors); + return error; +} + +void gumbo_error_to_string( + GumboParser* parser, const GumboError* error, GumboStringBuffer* output) { + print_message( + parser, output, "@%d:%d: ", error->position.line, error->position.column); + switch (error->type) { + case GUMBO_ERR_UTF8_INVALID: + print_message( + parser, output, "Invalid UTF8 character 0x%x", error->v.codepoint); + break; + case GUMBO_ERR_UTF8_TRUNCATED: + print_message(parser, output, + "Input stream ends with a truncated UTF8 character 0x%x", + error->v.codepoint); + break; + case GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS: + print_message( + parser, output, "No digits after &# in numeric character reference"); + break; + case GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON: + print_message(parser, output, + "The numeric character reference &#%d should be followed " + "by a semicolon", + error->v.codepoint); + break; + case GUMBO_ERR_NUMERIC_CHAR_REF_INVALID: + print_message(parser, output, + "The numeric character reference &#%d; encodes an invalid " + "unicode codepoint", + error->v.codepoint); + break; + case GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON: + // The textual data came from one of the literal strings in the table, and + // so it'll be null-terminated. + print_message(parser, output, + "The named character reference &%.*s should be followed by a " + "semicolon", + (int) error->v.text.length, error->v.text.data); + break; + case GUMBO_ERR_NAMED_CHAR_REF_INVALID: + print_message(parser, output, + "The named character reference &%.*s; is not a valid entity name", + (int) error->v.text.length, error->v.text.data); + break; + case GUMBO_ERR_DUPLICATE_ATTR: + print_message(parser, output, + "Attribute %s occurs multiple times, at positions %d and %d", + error->v.duplicate_attr.name, error->v.duplicate_attr.original_index, + error->v.duplicate_attr.new_index); + break; + case GUMBO_ERR_PARSER: + case GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG: + handle_parser_error(parser, &error->v.parser, output); + break; + default: + print_message(parser, output, + "Tokenizer error with an unimplemented error message"); + break; + } + gumbo_string_buffer_append_codepoint(parser, '.', output); +} + +void gumbo_caret_diagnostic_to_string(GumboParser* parser, + const GumboError* error, const char* source_text, + GumboStringBuffer* output) { + gumbo_error_to_string(parser, error, output); + + const char* line_start = find_last_newline(source_text, error->original_text); + const char* line_end = find_next_newline(source_text, error->original_text); + GumboStringPiece original_line; + original_line.data = line_start; + original_line.length = line_end - line_start; + + gumbo_string_buffer_append_codepoint(parser, '\n', output); + gumbo_string_buffer_append_string(parser, &original_line, output); + gumbo_string_buffer_append_codepoint(parser, '\n', output); + gumbo_string_buffer_reserve( + parser, output->length + error->position.column, output); + int num_spaces = error->position.column - 1; + memset(output->data + output->length, ' ', num_spaces); + output->length += num_spaces; + gumbo_string_buffer_append_codepoint(parser, '^', output); + gumbo_string_buffer_append_codepoint(parser, '\n', output); +} + +void gumbo_print_caret_diagnostic( + GumboParser* parser, const GumboError* error, const char* source_text) { + GumboStringBuffer text; + gumbo_string_buffer_init(parser, &text); + gumbo_caret_diagnostic_to_string(parser, error, source_text, &text); + printf("%.*s", (int) text.length, text.data); + gumbo_string_buffer_destroy(parser, &text); +} + +void gumbo_error_destroy(GumboParser* parser, GumboError* error) { + if (error->type == GUMBO_ERR_PARSER || + error->type == GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG) { + gumbo_vector_destroy(parser, &error->v.parser.tag_stack); + } else if (error->type == GUMBO_ERR_DUPLICATE_ATTR) { + gumbo_parser_deallocate(parser, (void*) error->v.duplicate_attr.name); + } + gumbo_parser_deallocate(parser, error); +} + +void gumbo_init_errors(GumboParser* parser) { + gumbo_vector_init(parser, 5, &parser->_output->errors); +} + +void gumbo_destroy_errors(GumboParser* parser) { + for (unsigned int i = 0; i < parser->_output->errors.length; ++i) { + gumbo_error_destroy(parser, parser->_output->errors.data[i]); + } + gumbo_vector_destroy(parser, &parser->_output->errors); +} diff --git a/libs/litehtml/src/gumbo/include/gumbo.h b/libs/litehtml/src/gumbo/include/gumbo.h new file mode 100644 index 0000000000..27e6c6c575 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo.h @@ -0,0 +1,675 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// We use Gumbo as a prefix for types, gumbo_ as a prefix for functions, and +// GUMBO_ as a prefix for enum constants (static constants get the Google-style +// kGumbo prefix). + +/** + * @file + * @mainpage Gumbo HTML Parser + * + * This provides a conformant, no-dependencies implementation of the HTML5 + * parsing algorithm. It supports only UTF8; if you need to parse a different + * encoding, run a preprocessing step to convert to UTF8. It returns a parse + * tree made of the structs in this file. + * + * Example: + * @code + * GumboOutput* output = gumbo_parse(input); + * do_something_with_doctype(output->document); + * do_something_with_html_tree(output->root); + * gumbo_destroy_output(&options, output); + * @endcode + * HTML5 Spec: + * + * http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html + */ + +#ifndef GUMBO_GUMBO_H_ +#define GUMBO_GUMBO_H_ + +#ifdef _MSC_VER +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#ifndef fileno +#define fileno _fileno +#endif +#endif + +#include <stdbool.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A struct representing a character position within the original text buffer. + * Line and column numbers are 1-based and offsets are 0-based, which matches + * how most editors and command-line tools work. Also, columns measure + * positions in terms of characters while offsets measure by bytes; this is + * because the offset field is often used to pull out a particular region of + * text (which in most languages that bind to C implies pointer arithmetic on a + * buffer of bytes), while the column field is often used to reference a + * particular column on a printable display, which nowadays is usually UTF-8. + */ +typedef struct { + unsigned int line; + unsigned int column; + unsigned int offset; +} GumboSourcePosition; + +/** + * A SourcePosition used for elements that have no source position, i.e. + * parser-inserted elements. + */ +extern const GumboSourcePosition kGumboEmptySourcePosition; + +/** + * A struct representing a string or part of a string. Strings within the + * parser are represented by a char* and a length; the char* points into + * an existing data buffer owned by some other code (often the original input). + * GumboStringPieces are assumed (by convention) to be immutable, because they + * may share data. Use GumboStringBuffer if you need to construct a string. + * Clients should assume that it is not NUL-terminated, and should always use + * explicit lengths when manipulating them. + */ +typedef struct { + /** A pointer to the beginning of the string. NULL iff length == 0. */ + const char* data; + + /** The length of the string fragment, in bytes. May be zero. */ + size_t length; +} GumboStringPiece; + +/** A constant to represent a 0-length null string. */ +extern const GumboStringPiece kGumboEmptyString; + +/** + * Compares two GumboStringPieces, and returns true if they're equal or false + * otherwise. + */ +bool gumbo_string_equals( + const GumboStringPiece* str1, const GumboStringPiece* str2); + +/** + * Compares two GumboStringPieces ignoring case, and returns true if they're + * equal or false otherwise. + */ +bool gumbo_string_equals_ignore_case( + const GumboStringPiece* str1, const GumboStringPiece* str2); + +/** + * A simple vector implementation. This stores a pointer to a data array and a + * length. All elements are stored as void*; client code must cast to the + * appropriate type. Overflows upon addition result in reallocation of the data + * array, with the size doubling to maintain O(1) amortized cost. There is no + * removal function, as this isn't needed for any of the operations within this + * library. Iteration can be done through inspecting the structure directly in + * a for-loop. + */ +typedef struct { + /** Data elements. This points to a dynamically-allocated array of capacity + * elements, each a void* to the element itself. + */ + void** data; + + /** Number of elements currently in the vector. */ + unsigned int length; + + /** Current array capacity. */ + unsigned int capacity; +} GumboVector; + +/** An empty (0-length, 0-capacity) GumboVector. */ +extern const GumboVector kGumboEmptyVector; + +/** + * Returns the first index at which an element appears in this vector (testing + * by pointer equality), or -1 if it never does. + */ +int gumbo_vector_index_of(GumboVector* vector, const void* element); + +/** + * An enum for all the tags defined in the HTML5 standard. These correspond to + * the tag names themselves. Enum constants exist only for tags which appear in + * the spec itself (or for tags with special handling in the SVG and MathML + * namespaces); any other tags appear as GUMBO_TAG_UNKNOWN and the actual tag + * name can be obtained through original_tag. + * + * This is mostly for API convenience, so that clients of this library don't + * need to perform a strcasecmp to find the normalized tag name. It also has + * efficiency benefits, by letting the parser work with enums instead of + * strings. + */ +typedef enum { +// Load all the tags from an external source, generated from tag.in. +#include "gumbo/tag_enum.h" + // Used for all tags that don't have special handling in HTML. Add new tags + // to the end of tag.in so as to preserve backwards-compatibility. + GUMBO_TAG_UNKNOWN, + // A marker value to indicate the end of the enum, for iterating over it. + // Also used as the terminator for varargs functions that take tags. + GUMBO_TAG_LAST, +} GumboTag; + +/** + * Returns the normalized (usually all-lowercased, except for foreign content) + * tag name for an GumboTag enum. Return value is static data owned by the + * library. + */ +const char* gumbo_normalized_tagname(GumboTag tag); + +/** + * Extracts the tag name from the original_text field of an element or token by + * stripping off </> characters and attributes and adjusting the passed-in + * GumboStringPiece appropriately. The tag name is in the original case and + * shares a buffer with the original text, to simplify memory management. + * Behavior is undefined if a string-piece that doesn't represent an HTML tag + * (<tagname> or </tagname>) is passed in. If the string piece is completely + * empty (NULL data pointer), then this function will exit successfully as a + * no-op. + */ +void gumbo_tag_from_original_text(GumboStringPiece* text); + +/** + * Fixes the case of SVG elements that are not all lowercase. + * http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inforeign + * This is not done at parse time because there's no place to store a mutated + * tag name. tag_name is an enum (which will be TAG_UNKNOWN for most SVG tags + * without special handling), while original_tag_name is a pointer into the + * original buffer. Instead, we provide this helper function that clients can + * use to rename SVG tags as appropriate. + * Returns the case-normalized SVG tagname if a replacement is found, or NULL if + * no normalization is called for. The return value is static data and owned by + * the library. + */ +const char* gumbo_normalize_svg_tagname(const GumboStringPiece* tagname); + +/** + * Converts a tag name string (which may be in upper or mixed case) to a tag + * enum. The `tag` version expects `tagname` to be NULL-terminated + */ +GumboTag gumbo_tag_enum(const char* tagname); +GumboTag gumbo_tagn_enum(const char* tagname, unsigned int length); + +/** + * Attribute namespaces. + * HTML includes special handling for XLink, XML, and XMLNS namespaces on + * attributes. Everything else goes in the generic "NONE" namespace. + */ +typedef enum { + GUMBO_ATTR_NAMESPACE_NONE, + GUMBO_ATTR_NAMESPACE_XLINK, + GUMBO_ATTR_NAMESPACE_XML, + GUMBO_ATTR_NAMESPACE_XMLNS, +} GumboAttributeNamespaceEnum; + +/** + * A struct representing a single attribute on an HTML tag. This is a + * name-value pair, but also includes information about source locations and + * original source text. + */ +typedef struct { + /** + * The namespace for the attribute. This will usually be + * GUMBO_ATTR_NAMESPACE_NONE, but some XLink/XMLNS/XML attributes take special + * values, per: + * http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adjust-foreign-attributes + */ + GumboAttributeNamespaceEnum attr_namespace; + + /** + * The name of the attribute. This is in a freshly-allocated buffer to deal + * with case-normalization, and is null-terminated. + */ + const char* name; + + /** + * The original text of the attribute name, as a pointer into the original + * source buffer. + */ + GumboStringPiece original_name; + + /** + * The value of the attribute. This is in a freshly-allocated buffer to deal + * with unescaping, and is null-terminated. It does not include any quotes + * that surround the attribute. If the attribute has no value (for example, + * 'selected' on a checkbox), this will be an empty string. + */ + const char* value; + + /** + * The original text of the value of the attribute. This points into the + * original source buffer. It includes any quotes that surround the + * attribute, and you can look at original_value.data[0] and + * original_value.data[original_value.length - 1] to determine what the quote + * characters were. If the attribute has no value, this will be a 0-length + * string. + */ + GumboStringPiece original_value; + + /** The starting position of the attribute name. */ + GumboSourcePosition name_start; + + /** + * The ending position of the attribute name. This is not always derivable + * from the starting position of the value because of the possibility of + * whitespace around the = sign. + */ + GumboSourcePosition name_end; + + /** The starting position of the attribute value. */ + GumboSourcePosition value_start; + + /** The ending position of the attribute value. */ + GumboSourcePosition value_end; +} GumboAttribute; + +/** + * Given a vector of GumboAttributes, look up the one with the specified name + * and return it, or NULL if no such attribute exists. This uses a + * case-insensitive match, as HTML is case-insensitive. + */ +GumboAttribute* gumbo_get_attribute(const GumboVector* attrs, const char* name); + +/** + * Enum denoting the type of node. This determines the type of the node.v + * union. + */ +typedef enum { + /** Document node. v will be a GumboDocument. */ + GUMBO_NODE_DOCUMENT, + /** Element node. v will be a GumboElement. */ + GUMBO_NODE_ELEMENT, + /** Text node. v will be a GumboText. */ + GUMBO_NODE_TEXT, + /** CDATA node. v will be a GumboText. */ + GUMBO_NODE_CDATA, + /** Comment node. v will be a GumboText, excluding comment delimiters. */ + GUMBO_NODE_COMMENT, + /** Text node, where all contents is whitespace. v will be a GumboText. */ + GUMBO_NODE_WHITESPACE, + /** Template node. This is separate from GUMBO_NODE_ELEMENT because many + * client libraries will want to ignore the contents of template nodes, as + * the spec suggests. Recursing on GUMBO_NODE_ELEMENT will do the right thing + * here, while clients that want to include template contents should also + * check for GUMBO_NODE_TEMPLATE. v will be a GumboElement. */ + GUMBO_NODE_TEMPLATE +} GumboNodeType; + +/** + * Forward declaration of GumboNode so it can be used recursively in + * GumboNode.parent. + */ +typedef struct GumboInternalNode GumboNode; + +/** + * http://www.whatwg.org/specs/web-apps/current-work/complete/dom.html#quirks-mode + */ +typedef enum { + GUMBO_DOCTYPE_NO_QUIRKS, + GUMBO_DOCTYPE_QUIRKS, + GUMBO_DOCTYPE_LIMITED_QUIRKS +} GumboQuirksModeEnum; + +/** + * Namespaces. + * Unlike in X(HT)ML, namespaces in HTML5 are not denoted by a prefix. Rather, + * anything inside an <svg> tag is in the SVG namespace, anything inside the + * <math> tag is in the MathML namespace, and anything else is inside the HTML + * namespace. No other namespaces are supported, so this can be an enum only. + */ +typedef enum { + GUMBO_NAMESPACE_HTML, + GUMBO_NAMESPACE_SVG, + GUMBO_NAMESPACE_MATHML +} GumboNamespaceEnum; + +/** + * Parse flags. + * We track the reasons for parser insertion of nodes and store them in a + * bitvector in the node itself. This lets client code optimize out nodes that + * are implied by the HTML structure of the document, or flag constructs that + * may not be allowed by a style guide, or track the prevalence of incorrect or + * tricky HTML code. + */ +typedef enum { + /** + * A normal node - both start and end tags appear in the source, nothing has + * been reparented. + */ + GUMBO_INSERTION_NORMAL = 0, + + /** + * A node inserted by the parser to fulfill some implicit insertion rule. + * This is usually set in addition to some other flag giving a more specific + * insertion reason; it's a generic catch-all term meaning "The start tag for + * this node did not appear in the document source". + */ + GUMBO_INSERTION_BY_PARSER = 1 << 0, + + /** + * A flag indicating that the end tag for this node did not appear in the + * document source. Note that in some cases, you can still have + * parser-inserted nodes with an explicit end tag: for example, "Text</html>" + * has GUMBO_INSERTED_BY_PARSER set on the <html> node, but + * GUMBO_INSERTED_END_TAG_IMPLICITLY is unset, as the </html> tag actually + * exists. This flag will be set only if the end tag is completely missing; + * in some cases, the end tag may be misplaced (eg. a </body> tag with text + * afterwards), which will leave this flag unset and require clients to + * inspect the parse errors for that case. + */ + GUMBO_INSERTION_IMPLICIT_END_TAG = 1 << 1, + + // Value 1 << 2 was for a flag that has since been removed. + + /** + * A flag for nodes that are inserted because their presence is implied by + * other tags, eg. <html>, <head>, <body>, <tbody>, etc. + */ + GUMBO_INSERTION_IMPLIED = 1 << 3, + + /** + * A flag for nodes that are converted from their end tag equivalents. For + * example, </p> when no paragraph is open implies that the parser should + * create a <p> tag and immediately close it, while </br> means the same thing + * as <br>. + */ + GUMBO_INSERTION_CONVERTED_FROM_END_TAG = 1 << 4, + + /** A flag for nodes that are converted from the parse of an <isindex> tag. */ + GUMBO_INSERTION_FROM_ISINDEX = 1 << 5, + + /** A flag for <image> tags that are rewritten as <img>. */ + GUMBO_INSERTION_FROM_IMAGE = 1 << 6, + + /** + * A flag for nodes that are cloned as a result of the reconstruction of + * active formatting elements. This is set only on the clone; the initial + * portion of the formatting run is a NORMAL node with an IMPLICIT_END_TAG. + */ + GUMBO_INSERTION_RECONSTRUCTED_FORMATTING_ELEMENT = 1 << 7, + + /** A flag for nodes that are cloned by the adoption agency algorithm. */ + GUMBO_INSERTION_ADOPTION_AGENCY_CLONED = 1 << 8, + + /** A flag for nodes that are moved by the adoption agency algorithm. */ + GUMBO_INSERTION_ADOPTION_AGENCY_MOVED = 1 << 9, + + /** + * A flag for nodes that have been foster-parented out of a table (or + * should've been foster-parented, if verbatim mode is set). + */ + GUMBO_INSERTION_FOSTER_PARENTED = 1 << 10, +} GumboParseFlags; + +/** + * Information specific to document nodes. + */ +typedef struct { + /** + * An array of GumboNodes, containing the children of this element. This will + * normally consist of the <html> element and any comment nodes found. + * Pointers are owned. + */ + GumboVector /* GumboNode* */ children; + + // True if there was an explicit doctype token as opposed to it being omitted. + bool has_doctype; + + // Fields from the doctype token, copied verbatim. + const char* name; + const char* public_identifier; + const char* system_identifier; + + /** + * Whether or not the document is in QuirksMode, as determined by the values + * in the GumboTokenDocType template. + */ + GumboQuirksModeEnum doc_type_quirks_mode; +} GumboDocument; + +/** + * The struct used to represent TEXT, CDATA, COMMENT, and WHITESPACE elements. + * This contains just a block of text and its position. + */ +typedef struct { + /** + * The text of this node, after entities have been parsed and decoded. For + * comment/cdata nodes, this does not include the comment delimiters. + */ + const char* text; + + /** + * The original text of this node, as a pointer into the original buffer. For + * comment/cdata nodes, this includes the comment delimiters. + */ + GumboStringPiece original_text; + + /** + * The starting position of this node. This corresponds to the position of + * original_text, before entities are decoded. + * */ + GumboSourcePosition start_pos; +} GumboText; + +/** + * The struct used to represent all HTML elements. This contains information + * about the tag, attributes, and child nodes. + */ +typedef struct { + /** + * An array of GumboNodes, containing the children of this element. Pointers + * are owned. + */ + GumboVector /* GumboNode* */ children; + + /** The GumboTag enum for this element. */ + GumboTag tag; + + /** The GumboNamespaceEnum for this element. */ + GumboNamespaceEnum tag_namespace; + + /** + * A GumboStringPiece pointing to the original tag text for this element, + * pointing directly into the source buffer. If the tag was inserted + * algorithmically (for example, <head> or <tbody> insertion), this will be a + * zero-length string. + */ + GumboStringPiece original_tag; + + /** + * A GumboStringPiece pointing to the original end tag text for this element. + * If the end tag was inserted algorithmically, (for example, closing a + * self-closing tag), this will be a zero-length string. + */ + GumboStringPiece original_end_tag; + + /** The source position for the start of the start tag. */ + GumboSourcePosition start_pos; + + /** The source position for the start of the end tag. */ + GumboSourcePosition end_pos; + + /** + * An array of GumboAttributes, containing the attributes for this tag in the + * order that they were parsed. Pointers are owned. + */ + GumboVector /* GumboAttribute* */ attributes; +} GumboElement; + +/** + * A supertype for GumboElement and GumboText, so that we can include one + * generic type in lists of children and cast as necessary to subtypes. + */ +struct GumboInternalNode { + /** The type of node that this is. */ + GumboNodeType type; + + /** Pointer back to parent node. Not owned. */ + GumboNode* parent; + + /** The index within the parent's children vector of this node. */ + size_t index_within_parent; + + /** + * A bitvector of flags containing information about why this element was + * inserted into the parse tree, including a variety of special parse + * situations. + */ + GumboParseFlags parse_flags; + + /** The actual node data. */ + union { + GumboDocument document; // For GUMBO_NODE_DOCUMENT. + GumboElement element; // For GUMBO_NODE_ELEMENT. + GumboText text; // For everything else. + } v; +}; + +/** + * The type for an allocator function. Takes the 'userdata' member of the + * GumboParser struct as its first argument. Semantics should be the same as + * malloc, i.e. return a block of size_t bytes on success or NULL on failure. + * Allocating a block of 0 bytes behaves as per malloc. + */ +// TODO(jdtang): Add checks throughout the codebase for out-of-memory condition. +typedef void* (*GumboAllocatorFunction)(void* userdata, size_t size); + +/** + * The type for a deallocator function. Takes the 'userdata' member of the + * GumboParser struct as its first argument. + */ +typedef void (*GumboDeallocatorFunction)(void* userdata, void* ptr); + +/** + * Input struct containing configuration options for the parser. + * These let you specify alternate memory managers, provide different error + * handling, etc. + * Use kGumboDefaultOptions for sensible defaults, and only set what you need. + */ +typedef struct GumboInternalOptions { + /** A memory allocator function. Default: malloc. */ + GumboAllocatorFunction allocator; + + /** A memory deallocator function. Default: free. */ + GumboDeallocatorFunction deallocator; + + /** + * An opaque object that's passed in as the first argument to all callbacks + * used by this library. Default: NULL. + */ + void* userdata; + + /** + * The tab-stop size, for computing positions in source code that uses tabs. + * Default: 8. + */ + int tab_stop; + + /** + * Whether or not to stop parsing when the first error is encountered. + * Default: false. + */ + bool stop_on_first_error; + + /** + * The maximum number of errors before the parser stops recording them. This + * is provided so that if the page is totally borked, we don't completely fill + * up the errors vector and exhaust memory with useless redundant errors. Set + * to -1 to disable the limit. + * Default: -1 + */ + int max_errors; + + /** + * The fragment context for parsing: + * https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments + * + * If GUMBO_TAG_LAST is passed here, it is assumed to be "no fragment", i.e. + * the regular parsing algorithm. Otherwise, pass the tag enum for the + * intended parent of the parsed fragment. We use just the tag enum rather + * than a full node because that's enough to set all the parsing context we + * need, and it provides some additional flexibility for client code to act as + * if parsing a fragment even when a full HTML tree isn't available. + * + * Default: GUMBO_TAG_LAST + */ + GumboTag fragment_context; + + /** + * The namespace for the fragment context. This lets client code + * differentiate between, say, parsing a <title> tag in SVG vs. parsing it in + * HTML. + * Default: GUMBO_NAMESPACE_HTML + */ + GumboNamespaceEnum fragment_namespace; +} GumboOptions; + +/** Default options struct; use this with gumbo_parse_with_options. */ +extern const GumboOptions kGumboDefaultOptions; + +/** The output struct containing the results of the parse. */ +typedef struct GumboInternalOutput { + /** + * Pointer to the document node. This is a GumboNode of type NODE_DOCUMENT + * that contains the entire document as its child. + */ + GumboNode* document; + + /** + * Pointer to the root node. This the <html> tag that forms the root of the + * document. + */ + GumboNode* root; + + /** + * A list of errors that occurred during the parse. + * NOTE: In version 1.0 of this library, the API for errors hasn't been fully + * fleshed out and may change in the future. For this reason, the GumboError + * header isn't part of the public API. Contact us if you need errors + * reported so we can work out something appropriate for your use-case. + */ + GumboVector /* GumboError */ errors; +} GumboOutput; + +/** + * Parses a buffer of UTF8 text into an GumboNode parse tree. The buffer must + * live at least as long as the parse tree, as some fields (eg. original_text) + * point directly into the original buffer. + * + * This doesn't support buffers longer than 4 gigabytes. + */ +GumboOutput* gumbo_parse(const char* buffer); + +/** + * Extended version of gumbo_parse that takes an explicit options structure, + * buffer, and length. + */ +GumboOutput* gumbo_parse_with_options( + const GumboOptions* options, const char* buffer, size_t buffer_length); + +/** Release the memory used for the parse tree & parse errors. */ +void gumbo_destroy_output(const GumboOptions* options, GumboOutput* output); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_GUMBO_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/attribute.h b/libs/litehtml/src/gumbo/include/gumbo/attribute.h new file mode 100644 index 0000000000..f9b8aea576 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/attribute.h @@ -0,0 +1,37 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#ifndef GUMBO_ATTRIBUTE_H_ +#define GUMBO_ATTRIBUTE_H_ + +#include "gumbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; + +// Release the memory used for an GumboAttribute, including the attribute +// itself. +void gumbo_destroy_attribute( + struct GumboInternalParser* parser, GumboAttribute* attribute); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_ATTRIBUTE_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/char_ref.h b/libs/litehtml/src/gumbo/include/gumbo/char_ref.h new file mode 100644 index 0000000000..09d2598f45 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/char_ref.h @@ -0,0 +1,60 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// Internal header for character reference handling; this should not be exposed +// transitively by any public API header. This is why the functions aren't +// namespaced. + +#ifndef GUMBO_CHAR_REF_H_ +#define GUMBO_CHAR_REF_H_ + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; +struct GumboInternalUtf8Iterator; + +// Value that indicates no character was produced. +extern const int kGumboNoChar; + +// Certain named character references generate two codepoints, not one, and so +// the consume_char_ref subroutine needs to return this instead of an int. The +// first field will be kGumboNoChar if no character reference was found; the +// second field will be kGumboNoChar if that is the case or if the character +// reference returns only a single codepoint. +typedef struct { + int first; + int second; +} OneOrTwoCodepoints; + +// Implements the "consume a character reference" section of the spec. +// This reads in characters from the input as necessary, and fills in a +// OneOrTwoCodepoints struct containing the characters read. It may add parse +// errors to the GumboParser's errors vector, if the spec calls for it. Pass a +// space for the "additional allowed char" when the spec says "with no +// additional allowed char". Returns false on parse error, true otherwise. +bool consume_char_ref(struct GumboInternalParser* parser, + struct GumboInternalUtf8Iterator* input, int additional_allowed_char, + bool is_in_attribute, OneOrTwoCodepoints* output); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_CHAR_REF_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/error.h b/libs/litehtml/src/gumbo/include/gumbo/error.h new file mode 100644 index 0000000000..3aa54a6b27 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/error.h @@ -0,0 +1,227 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// Error types, enums, and handling functions. + +#ifndef GUMBO_ERROR_H_ +#define GUMBO_ERROR_H_ +#ifdef _MSC_VER +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif +#include <stdint.h> + +#include "gumbo.h" +#include "insertion_mode.h" +#include "string_buffer.h" +#include "token_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; + +typedef enum { + GUMBO_ERR_UTF8_INVALID, + GUMBO_ERR_UTF8_TRUNCATED, + GUMBO_ERR_UTF8_NULL, + GUMBO_ERR_NUMERIC_CHAR_REF_NO_DIGITS, + GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON, + GUMBO_ERR_NUMERIC_CHAR_REF_INVALID, + GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON, + GUMBO_ERR_NAMED_CHAR_REF_INVALID, + GUMBO_ERR_TAG_STARTS_WITH_QUESTION, + GUMBO_ERR_TAG_EOF, + GUMBO_ERR_TAG_INVALID, + GUMBO_ERR_CLOSE_TAG_EMPTY, + GUMBO_ERR_CLOSE_TAG_EOF, + GUMBO_ERR_CLOSE_TAG_INVALID, + GUMBO_ERR_SCRIPT_EOF, + GUMBO_ERR_ATTR_NAME_EOF, + GUMBO_ERR_ATTR_NAME_INVALID, + GUMBO_ERR_ATTR_DOUBLE_QUOTE_EOF, + GUMBO_ERR_ATTR_SINGLE_QUOTE_EOF, + GUMBO_ERR_ATTR_UNQUOTED_EOF, + GUMBO_ERR_ATTR_UNQUOTED_RIGHT_BRACKET, + GUMBO_ERR_ATTR_UNQUOTED_EQUALS, + GUMBO_ERR_ATTR_AFTER_EOF, + GUMBO_ERR_ATTR_AFTER_INVALID, + GUMBO_ERR_DUPLICATE_ATTR, + GUMBO_ERR_SOLIDUS_EOF, + GUMBO_ERR_SOLIDUS_INVALID, + GUMBO_ERR_DASHES_OR_DOCTYPE, + GUMBO_ERR_COMMENT_EOF, + GUMBO_ERR_COMMENT_INVALID, + GUMBO_ERR_COMMENT_BANG_AFTER_DOUBLE_DASH, + GUMBO_ERR_COMMENT_DASH_AFTER_DOUBLE_DASH, + GUMBO_ERR_COMMENT_SPACE_AFTER_DOUBLE_DASH, + GUMBO_ERR_COMMENT_END_BANG_EOF, + GUMBO_ERR_DOCTYPE_EOF, + GUMBO_ERR_DOCTYPE_INVALID, + GUMBO_ERR_DOCTYPE_SPACE, + GUMBO_ERR_DOCTYPE_RIGHT_BRACKET, + GUMBO_ERR_DOCTYPE_SPACE_OR_RIGHT_BRACKET, + GUMBO_ERR_DOCTYPE_END, + GUMBO_ERR_PARSER, + GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG, +} GumboErrorType; + +// Additional data for duplicated attributes. +typedef struct GumboInternalDuplicateAttrError { + // The name of the attribute. Owned by this struct. + const char* name; + + // The (0-based) index within the attributes vector of the original + // occurrence. + unsigned int original_index; + + // The (0-based) index where the new occurrence would be. + unsigned int new_index; +} GumboDuplicateAttrError; + +// A simplified representation of the tokenizer state, designed to be more +// useful to clients of this library than the internal representation. This +// condenses the actual states used in the tokenizer state machine into a few +// values that will be familiar to users of HTML. +typedef enum { + GUMBO_ERR_TOKENIZER_DATA, + GUMBO_ERR_TOKENIZER_CHAR_REF, + GUMBO_ERR_TOKENIZER_RCDATA, + GUMBO_ERR_TOKENIZER_RAWTEXT, + GUMBO_ERR_TOKENIZER_PLAINTEXT, + GUMBO_ERR_TOKENIZER_SCRIPT, + GUMBO_ERR_TOKENIZER_TAG, + GUMBO_ERR_TOKENIZER_SELF_CLOSING_TAG, + GUMBO_ERR_TOKENIZER_ATTR_NAME, + GUMBO_ERR_TOKENIZER_ATTR_VALUE, + GUMBO_ERR_TOKENIZER_MARKUP_DECLARATION, + GUMBO_ERR_TOKENIZER_COMMENT, + GUMBO_ERR_TOKENIZER_DOCTYPE, + GUMBO_ERR_TOKENIZER_CDATA, +} GumboTokenizerErrorState; + +// Additional data for tokenizer errors. +// This records the current state and codepoint encountered - this is usually +// enough to reconstruct what went wrong and provide a friendly error message. +typedef struct GumboInternalTokenizerError { + // The bad codepoint encountered. + int codepoint; + + // The state that the tokenizer was in at the time. + GumboTokenizerErrorState state; +} GumboTokenizerError; + +// Additional data for parse errors. +typedef struct GumboInternalParserError { + // The type of input token that resulted in this error. + GumboTokenType input_type; + + // The HTML tag of the input token. TAG_UNKNOWN if this was not a tag token. + GumboTag input_tag; + + // The insertion mode that the parser was in at the time. + GumboInsertionMode parser_state; + + // The tag stack at the point of the error. Note that this is an GumboVector + // of GumboTag's *stored by value* - cast the void* to an GumboTag directly to + // get at the tag. + GumboVector /* GumboTag */ tag_stack; +} GumboParserError; + +// The overall error struct representing an error in decoding/tokenizing/parsing +// the HTML. This contains an enumerated type flag, a source position, and then +// a union of fields containing data specific to the error. +typedef struct GumboInternalError { + // The type of error. + GumboErrorType type; + + // The position within the source file where the error occurred. + GumboSourcePosition position; + + // A pointer to the byte within the original source file text where the error + // occurred (note that this is not the same as position.offset, as that gives + // character-based instead of byte-based offsets). + const char* original_text; + + // Type-specific error information. + union { + // The code point we encountered, for: + // * GUMBO_ERR_UTF8_INVALID + // * GUMBO_ERR_UTF8_TRUNCATED + // * GUMBO_ERR_NUMERIC_CHAR_REF_WITHOUT_SEMICOLON + // * GUMBO_ERR_NUMERIC_CHAR_REF_INVALID + uint64_t codepoint; + + // Tokenizer errors. + GumboTokenizerError tokenizer; + + // Short textual data, for: + // * GUMBO_ERR_NAMED_CHAR_REF_WITHOUT_SEMICOLON + // * GUMBO_ERR_NAMED_CHAR_REF_INVALID + GumboStringPiece text; + + // Duplicate attribute data, for GUMBO_ERR_DUPLICATE_ATTR. + GumboDuplicateAttrError duplicate_attr; + + // Parser state, for GUMBO_ERR_PARSER and + // GUMBO_ERR_UNACKNOWLEDGE_SELF_CLOSING_TAG. + struct GumboInternalParserError parser; + } v; +} GumboError; + +// Adds a new error to the parser's error list, and returns a pointer to it so +// that clients can fill out the rest of its fields. May return NULL if we're +// already over the max_errors field specified in GumboOptions. +GumboError* gumbo_add_error(struct GumboInternalParser* parser); + +// Initializes the errors vector in the parser. +void gumbo_init_errors(struct GumboInternalParser* errors); + +// Frees all the errors in the 'errors_' field of the parser. +void gumbo_destroy_errors(struct GumboInternalParser* errors); + +// Frees the memory used for a single GumboError. +void gumbo_error_destroy(struct GumboInternalParser* parser, GumboError* error); + +// Prints an error to a string. This fills an empty GumboStringBuffer with a +// freshly-allocated buffer containing the error message text. The caller is +// responsible for deleting the buffer. (Note that the buffer is allocated with +// the allocator specified in the GumboParser ~config and hence should be freed +// by gumbo_parser_deallocate().) +void gumbo_error_to_string(struct GumboInternalParser* parser, + const GumboError* error, GumboStringBuffer* output); + +// Prints a caret diagnostic to a string. This fills an empty GumboStringBuffer +// with a freshly-allocated buffer containing the error message text. The +// caller is responsible for deleting the buffer. (Note that the buffer is +// allocated with the allocator specified in the GumboParser ~config and hence +// should be freed by gumbo_parser_deallocate().) +void gumbo_caret_diagnostic_to_string(struct GumboInternalParser* parser, + const GumboError* error, const char* source_text, + GumboStringBuffer* output); + +// Like gumbo_caret_diagnostic_to_string, but prints the text to stdout instead +// of writing to a string. +void gumbo_print_caret_diagnostic(struct GumboInternalParser* parser, + const GumboError* error, const char* source_text); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_ERROR_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/insertion_mode.h b/libs/litehtml/src/gumbo/include/gumbo/insertion_mode.h new file mode 100644 index 0000000000..45134c13b3 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/insertion_mode.h @@ -0,0 +1,57 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#ifndef GUMBO_INSERTION_MODE_H_ +#define GUMBO_INSERTION_MODE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#insertion-mode +// If new enum values are added, be sure to update the kTokenHandlers dispatch +// table in parser.c. +typedef enum { + GUMBO_INSERTION_MODE_INITIAL, + GUMBO_INSERTION_MODE_BEFORE_HTML, + GUMBO_INSERTION_MODE_BEFORE_HEAD, + GUMBO_INSERTION_MODE_IN_HEAD, + GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT, + GUMBO_INSERTION_MODE_AFTER_HEAD, + GUMBO_INSERTION_MODE_IN_BODY, + GUMBO_INSERTION_MODE_TEXT, + GUMBO_INSERTION_MODE_IN_TABLE, + GUMBO_INSERTION_MODE_IN_TABLE_TEXT, + GUMBO_INSERTION_MODE_IN_CAPTION, + GUMBO_INSERTION_MODE_IN_COLUMN_GROUP, + GUMBO_INSERTION_MODE_IN_TABLE_BODY, + GUMBO_INSERTION_MODE_IN_ROW, + GUMBO_INSERTION_MODE_IN_CELL, + GUMBO_INSERTION_MODE_IN_SELECT, + GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE, + GUMBO_INSERTION_MODE_IN_TEMPLATE, + GUMBO_INSERTION_MODE_AFTER_BODY, + GUMBO_INSERTION_MODE_IN_FRAMESET, + GUMBO_INSERTION_MODE_AFTER_FRAMESET, + GUMBO_INSERTION_MODE_AFTER_AFTER_BODY, + GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET +} GumboInsertionMode; + +#ifdef __cplusplus +} // extern C +#endif + +#endif // GUMBO_INSERTION_MODE_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/parser.h b/libs/litehtml/src/gumbo/include/gumbo/parser.h new file mode 100644 index 0000000000..95019e3eca --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/parser.h @@ -0,0 +1,57 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// Contains the definition of the top-level GumboParser structure that's +// threaded through basically every internal function in the library. + +#ifndef GUMBO_PARSER_H_ +#define GUMBO_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParserState; +struct GumboInternalOutput; +struct GumboInternalOptions; +struct GumboInternalTokenizerState; + +// An overarching struct that's threaded through (nearly) all functions in the +// library, OOP-style. This gives each function access to the options and +// output, along with any internal state needed for the parse. +typedef struct GumboInternalParser { + // Settings for this parse run. + const struct GumboInternalOptions* _options; + + // Output for the parse. + struct GumboInternalOutput* _output; + + // The internal tokenizer state, defined as a pointer to avoid a cyclic + // dependency on html5tokenizer.h. The main parse routine is responsible for + // initializing this on parse start, and destroying it on parse end. + // End-users will never see a non-garbage value in this pointer. + struct GumboInternalTokenizerState* _tokenizer_state; + + // The internal parser state. Initialized on parse start and destroyed on + // parse end; end-users will never see a non-garbage value in this pointer. + struct GumboInternalParserState* _parser_state; +} GumboParser; + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_PARSER_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/string_buffer.h b/libs/litehtml/src/gumbo/include/gumbo/string_buffer.h new file mode 100644 index 0000000000..ee7956acc8 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/string_buffer.h @@ -0,0 +1,84 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +#ifndef GUMBO_STRING_BUFFER_H_ +#define GUMBO_STRING_BUFFER_H_ + +#include <stdbool.h> +#include <stddef.h> + +#include "gumbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; + +// A struct representing a mutable, growable string. This consists of a +// heap-allocated buffer that may grow (by doubling) as necessary. When +// converting to a string, this allocates a new buffer that is only as long as +// it needs to be. Note that the internal buffer here is *not* nul-terminated, +// so be sure not to use ordinary string manipulation functions on it. +typedef struct { + // A pointer to the beginning of the string. NULL iff length == 0. + char* data; + + // The length of the string fragment, in bytes. May be zero. + size_t length; + + // The capacity of the buffer, in bytes. + size_t capacity; +} GumboStringBuffer; + +// Initializes a new GumboStringBuffer. +void gumbo_string_buffer_init( + struct GumboInternalParser* parser, GumboStringBuffer* output); + +// Ensures that the buffer contains at least a certain amount of space. Most +// useful with snprintf and the other length-delimited string functions, which +// may want to write directly into the buffer. +void gumbo_string_buffer_reserve(struct GumboInternalParser* parser, + size_t min_capacity, GumboStringBuffer* output); + +// Appends a single Unicode codepoint onto the end of the GumboStringBuffer. +// This is essentially a UTF-8 encoder, and may add 1-4 bytes depending on the +// value of the codepoint. +void gumbo_string_buffer_append_codepoint( + struct GumboInternalParser* parser, int c, GumboStringBuffer* output); + +// Appends a string onto the end of the GumboStringBuffer. +void gumbo_string_buffer_append_string(struct GumboInternalParser* parser, + GumboStringPiece* str, GumboStringBuffer* output); + +// Converts this string buffer to const char*, alloctaing a new buffer for it. +char* gumbo_string_buffer_to_string( + struct GumboInternalParser* parser, GumboStringBuffer* input); + +// Reinitialize this string buffer. This clears it by setting length=0. It +// does not zero out the buffer itself. +void gumbo_string_buffer_clear( + struct GumboInternalParser* parser, GumboStringBuffer* input); + +// Deallocates this GumboStringBuffer. +void gumbo_string_buffer_destroy( + struct GumboInternalParser* parser, GumboStringBuffer* buffer); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_STRING_BUFFER_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/string_piece.h b/libs/litehtml/src/gumbo/include/gumbo/string_piece.h new file mode 100644 index 0000000000..8c8188c500 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/string_piece.h @@ -0,0 +1,38 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#ifndef GUMBO_STRING_PIECE_H_ +#define GUMBO_STRING_PIECE_H_ + +#include "gumbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; + +// Performs a deep-copy of an GumboStringPiece, allocating a fresh buffer in the +// destination and copying over the characters from source. Dest should be +// empty, with no buffer allocated; otherwise, this leaks it. +void gumbo_string_copy(struct GumboInternalParser* parser, + GumboStringPiece* dest, const GumboStringPiece* source); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_STRING_PIECE_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/tag_enum.h b/libs/litehtml/src/gumbo/include/gumbo/tag_enum.h new file mode 100644 index 0000000000..6d7aeb3d7d --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tag_enum.h @@ -0,0 +1,153 @@ +// Generated via `gentags.py src/tag.in`. +// Do not edit; edit src/tag.in instead. +// clang-format off +GUMBO_TAG_HTML, +GUMBO_TAG_HEAD, +GUMBO_TAG_TITLE, +GUMBO_TAG_BASE, +GUMBO_TAG_LINK, +GUMBO_TAG_META, +GUMBO_TAG_STYLE, +GUMBO_TAG_SCRIPT, +GUMBO_TAG_NOSCRIPT, +GUMBO_TAG_TEMPLATE, +GUMBO_TAG_BODY, +GUMBO_TAG_ARTICLE, +GUMBO_TAG_SECTION, +GUMBO_TAG_NAV, +GUMBO_TAG_ASIDE, +GUMBO_TAG_H1, +GUMBO_TAG_H2, +GUMBO_TAG_H3, +GUMBO_TAG_H4, +GUMBO_TAG_H5, +GUMBO_TAG_H6, +GUMBO_TAG_HGROUP, +GUMBO_TAG_HEADER, +GUMBO_TAG_FOOTER, +GUMBO_TAG_ADDRESS, +GUMBO_TAG_P, +GUMBO_TAG_HR, +GUMBO_TAG_PRE, +GUMBO_TAG_BLOCKQUOTE, +GUMBO_TAG_OL, +GUMBO_TAG_UL, +GUMBO_TAG_LI, +GUMBO_TAG_DL, +GUMBO_TAG_DT, +GUMBO_TAG_DD, +GUMBO_TAG_FIGURE, +GUMBO_TAG_FIGCAPTION, +GUMBO_TAG_MAIN, +GUMBO_TAG_DIV, +GUMBO_TAG_A, +GUMBO_TAG_EM, +GUMBO_TAG_STRONG, +GUMBO_TAG_SMALL, +GUMBO_TAG_S, +GUMBO_TAG_CITE, +GUMBO_TAG_Q, +GUMBO_TAG_DFN, +GUMBO_TAG_ABBR, +GUMBO_TAG_DATA, +GUMBO_TAG_TIME, +GUMBO_TAG_CODE, +GUMBO_TAG_VAR, +GUMBO_TAG_SAMP, +GUMBO_TAG_KBD, +GUMBO_TAG_SUB, +GUMBO_TAG_SUP, +GUMBO_TAG_I, +GUMBO_TAG_B, +GUMBO_TAG_U, +GUMBO_TAG_MARK, +GUMBO_TAG_RUBY, +GUMBO_TAG_RT, +GUMBO_TAG_RP, +GUMBO_TAG_BDI, +GUMBO_TAG_BDO, +GUMBO_TAG_SPAN, +GUMBO_TAG_BR, +GUMBO_TAG_WBR, +GUMBO_TAG_INS, +GUMBO_TAG_DEL, +GUMBO_TAG_IMAGE, +GUMBO_TAG_IMG, +GUMBO_TAG_IFRAME, +GUMBO_TAG_EMBED, +GUMBO_TAG_OBJECT, +GUMBO_TAG_PARAM, +GUMBO_TAG_VIDEO, +GUMBO_TAG_AUDIO, +GUMBO_TAG_SOURCE, +GUMBO_TAG_TRACK, +GUMBO_TAG_CANVAS, +GUMBO_TAG_MAP, +GUMBO_TAG_AREA, +GUMBO_TAG_MATH, +GUMBO_TAG_MI, +GUMBO_TAG_MO, +GUMBO_TAG_MN, +GUMBO_TAG_MS, +GUMBO_TAG_MTEXT, +GUMBO_TAG_MGLYPH, +GUMBO_TAG_MALIGNMARK, +GUMBO_TAG_ANNOTATION_XML, +GUMBO_TAG_SVG, +GUMBO_TAG_FOREIGNOBJECT, +GUMBO_TAG_DESC, +GUMBO_TAG_TABLE, +GUMBO_TAG_CAPTION, +GUMBO_TAG_COLGROUP, +GUMBO_TAG_COL, +GUMBO_TAG_TBODY, +GUMBO_TAG_THEAD, +GUMBO_TAG_TFOOT, +GUMBO_TAG_TR, +GUMBO_TAG_TD, +GUMBO_TAG_TH, +GUMBO_TAG_FORM, +GUMBO_TAG_FIELDSET, +GUMBO_TAG_LEGEND, +GUMBO_TAG_LABEL, +GUMBO_TAG_INPUT, +GUMBO_TAG_BUTTON, +GUMBO_TAG_SELECT, +GUMBO_TAG_DATALIST, +GUMBO_TAG_OPTGROUP, +GUMBO_TAG_OPTION, +GUMBO_TAG_TEXTAREA, +GUMBO_TAG_KEYGEN, +GUMBO_TAG_OUTPUT, +GUMBO_TAG_PROGRESS, +GUMBO_TAG_METER, +GUMBO_TAG_DETAILS, +GUMBO_TAG_SUMMARY, +GUMBO_TAG_MENU, +GUMBO_TAG_MENUITEM, +GUMBO_TAG_APPLET, +GUMBO_TAG_ACRONYM, +GUMBO_TAG_BGSOUND, +GUMBO_TAG_DIR, +GUMBO_TAG_FRAME, +GUMBO_TAG_FRAMESET, +GUMBO_TAG_NOFRAMES, +GUMBO_TAG_ISINDEX, +GUMBO_TAG_LISTING, +GUMBO_TAG_XMP, +GUMBO_TAG_NEXTID, +GUMBO_TAG_NOEMBED, +GUMBO_TAG_PLAINTEXT, +GUMBO_TAG_RB, +GUMBO_TAG_STRIKE, +GUMBO_TAG_BASEFONT, +GUMBO_TAG_BIG, +GUMBO_TAG_BLINK, +GUMBO_TAG_CENTER, +GUMBO_TAG_FONT, +GUMBO_TAG_MARQUEE, +GUMBO_TAG_MULTICOL, +GUMBO_TAG_NOBR, +GUMBO_TAG_SPACER, +GUMBO_TAG_TT, +GUMBO_TAG_RTC, diff --git a/libs/litehtml/src/gumbo/include/gumbo/tag_gperf.h b/libs/litehtml/src/gumbo/include/gumbo/tag_gperf.h new file mode 100644 index 0000000000..378eaf958c --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tag_gperf.h @@ -0,0 +1,105 @@ +static unsigned int tag_hash( + register const char *str, register unsigned int len) { + static unsigned short asso_values[] = {296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 6, 4, 3, 1, 1, 0, + 1, 0, 0, 296, 296, 296, 296, 296, 296, 296, 22, 73, 151, 4, 13, 59, 65, 2, + 69, 0, 134, 9, 16, 52, 55, 28, 101, 0, 1, 6, 63, 126, 104, 93, 124, 296, + 296, 296, 296, 296, 296, 296, 22, 73, 151, 4, 13, 59, 65, 2, 69, 0, 134, + 9, 16, 52, 55, 28, 101, 0, 1, 6, 63, 126, 104, 93, 124, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296}; + register unsigned int hval = len; + + switch (hval) { + default: + hval += asso_values[(unsigned char) str[1] + 3]; + /*FALLTHROUGH*/ + case 1: + hval += asso_values[(unsigned char) str[0]]; + break; + } + return hval + asso_values[(unsigned char) str[len - 1]]; +} + +static const unsigned char kGumboTagMap[] = {GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_S, GUMBO_TAG_H6, GUMBO_TAG_H5, GUMBO_TAG_H4, + GUMBO_TAG_H3, GUMBO_TAG_SPACER, GUMBO_TAG_H2, GUMBO_TAG_HEADER, + GUMBO_TAG_H1, GUMBO_TAG_HEAD, GUMBO_TAG_LAST, GUMBO_TAG_DETAILS, + GUMBO_TAG_SELECT, GUMBO_TAG_DIR, GUMBO_TAG_LAST, GUMBO_TAG_DEL, + GUMBO_TAG_LAST, GUMBO_TAG_SOURCE, GUMBO_TAG_LEGEND, GUMBO_TAG_DATALIST, + GUMBO_TAG_METER, GUMBO_TAG_MGLYPH, GUMBO_TAG_LAST, GUMBO_TAG_MATH, + GUMBO_TAG_LABEL, GUMBO_TAG_TABLE, GUMBO_TAG_TEMPLATE, GUMBO_TAG_LAST, + GUMBO_TAG_RP, GUMBO_TAG_TIME, GUMBO_TAG_TITLE, GUMBO_TAG_DATA, + GUMBO_TAG_APPLET, GUMBO_TAG_HGROUP, GUMBO_TAG_SAMP, GUMBO_TAG_TEXTAREA, + GUMBO_TAG_ABBR, GUMBO_TAG_MARQUEE, GUMBO_TAG_LAST, GUMBO_TAG_MENUITEM, + GUMBO_TAG_SMALL, GUMBO_TAG_META, GUMBO_TAG_A, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_EMBED, + GUMBO_TAG_MAP, GUMBO_TAG_LAST, GUMBO_TAG_PARAM, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_NOBR, GUMBO_TAG_P, GUMBO_TAG_SPAN, GUMBO_TAG_EM, + GUMBO_TAG_LAST, GUMBO_TAG_NOFRAMES, GUMBO_TAG_SECTION, GUMBO_TAG_NOEMBED, + GUMBO_TAG_NEXTID, GUMBO_TAG_FOOTER, GUMBO_TAG_NOSCRIPT, GUMBO_TAG_HR, + GUMBO_TAG_LAST, GUMBO_TAG_FONT, GUMBO_TAG_DL, GUMBO_TAG_TR, + GUMBO_TAG_SCRIPT, GUMBO_TAG_MO, GUMBO_TAG_LAST, GUMBO_TAG_DD, + GUMBO_TAG_MAIN, GUMBO_TAG_TD, GUMBO_TAG_FOREIGNOBJECT, GUMBO_TAG_FORM, + GUMBO_TAG_OBJECT, GUMBO_TAG_LAST, GUMBO_TAG_FIELDSET, GUMBO_TAG_LAST, + GUMBO_TAG_BGSOUND, GUMBO_TAG_MENU, GUMBO_TAG_TFOOT, GUMBO_TAG_FIGURE, + GUMBO_TAG_RB, GUMBO_TAG_LI, GUMBO_TAG_LISTING, GUMBO_TAG_BASEFONT, + GUMBO_TAG_OPTGROUP, GUMBO_TAG_LAST, GUMBO_TAG_BASE, GUMBO_TAG_ADDRESS, + GUMBO_TAG_MI, GUMBO_TAG_LAST, GUMBO_TAG_PLAINTEXT, GUMBO_TAG_LAST, + GUMBO_TAG_PROGRESS, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_ACRONYM, GUMBO_TAG_ARTICLE, GUMBO_TAG_LAST, GUMBO_TAG_PRE, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_AREA, + GUMBO_TAG_RT, GUMBO_TAG_LAST, GUMBO_TAG_OPTION, GUMBO_TAG_IMAGE, + GUMBO_TAG_DT, GUMBO_TAG_LAST, GUMBO_TAG_TT, GUMBO_TAG_HTML, GUMBO_TAG_WBR, + GUMBO_TAG_OL, GUMBO_TAG_LAST, GUMBO_TAG_STYLE, GUMBO_TAG_STRIKE, + GUMBO_TAG_SUP, GUMBO_TAG_MULTICOL, GUMBO_TAG_U, GUMBO_TAG_DFN, GUMBO_TAG_UL, + GUMBO_TAG_FIGCAPTION, GUMBO_TAG_MTEXT, GUMBO_TAG_LAST, GUMBO_TAG_VAR, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_FRAMESET, GUMBO_TAG_LAST, + GUMBO_TAG_BR, GUMBO_TAG_I, GUMBO_TAG_FRAME, GUMBO_TAG_LAST, GUMBO_TAG_DIV, + GUMBO_TAG_LAST, GUMBO_TAG_TH, GUMBO_TAG_MS, GUMBO_TAG_ANNOTATION_XML, + GUMBO_TAG_B, GUMBO_TAG_TBODY, GUMBO_TAG_THEAD, GUMBO_TAG_BIG, + GUMBO_TAG_BLOCKQUOTE, GUMBO_TAG_XMP, GUMBO_TAG_LAST, GUMBO_TAG_KBD, + GUMBO_TAG_LAST, GUMBO_TAG_LINK, GUMBO_TAG_IFRAME, GUMBO_TAG_MARK, + GUMBO_TAG_CENTER, GUMBO_TAG_OUTPUT, GUMBO_TAG_DESC, GUMBO_TAG_CANVAS, + GUMBO_TAG_COL, GUMBO_TAG_MALIGNMARK, GUMBO_TAG_IMG, GUMBO_TAG_ASIDE, + GUMBO_TAG_LAST, GUMBO_TAG_CODE, GUMBO_TAG_LAST, GUMBO_TAG_SUB, GUMBO_TAG_MN, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_INS, GUMBO_TAG_AUDIO, + GUMBO_TAG_STRONG, GUMBO_TAG_CITE, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_INPUT, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_NAV, GUMBO_TAG_LAST, GUMBO_TAG_COLGROUP, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_SVG, GUMBO_TAG_KEYGEN, GUMBO_TAG_VIDEO, + GUMBO_TAG_BDO, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_BODY, GUMBO_TAG_LAST, GUMBO_TAG_Q, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_TRACK, + GUMBO_TAG_LAST, GUMBO_TAG_BDI, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_CAPTION, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_RUBY, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_BUTTON, + GUMBO_TAG_SUMMARY, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_RTC, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_BLINK, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_LAST, + GUMBO_TAG_LAST, GUMBO_TAG_LAST, GUMBO_TAG_ISINDEX}; diff --git a/libs/litehtml/src/gumbo/include/gumbo/tag_sizes.h b/libs/litehtml/src/gumbo/include/gumbo/tag_sizes.h new file mode 100644 index 0000000000..7c92de073b --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tag_sizes.h @@ -0,0 +1,4 @@ +// Generated via `gentags.py src/tag.in`. +// Do not edit; edit src/tag.in instead. +// clang-format off +4, 4, 5, 4, 4, 4, 5, 6, 8, 8, 4, 7, 7, 3, 5, 2, 2, 2, 2, 2, 2, 6, 6, 6, 7, 1, 2, 3, 10, 2, 2, 2, 2, 2, 2, 6, 10, 4, 3, 1, 2, 6, 5, 1, 4, 1, 3, 4, 4, 4, 4, 3, 4, 3, 3, 3, 1, 1, 1, 4, 4, 2, 2, 3, 3, 4, 2, 3, 3, 3, 5, 3, 6, 5, 6, 5, 5, 5, 6, 5, 6, 3, 4, 4, 2, 2, 2, 2, 5, 6, 10, 14, 3, 13, 4, 5, 7, 8, 3, 5, 5, 5, 2, 2, 2, 4, 8, 6, 5, 5, 6, 6, 8, 8, 6, 8, 6, 6, 8, 5, 7, 7, 4, 8, 6, 7, 7, 3, 5, 8, 8, 7, 7, 3, 6, 7, 9, 2, 6, 8, 3, 5, 6, 4, 7, 8, 4, 6, 2, 3,
\ No newline at end of file diff --git a/libs/litehtml/src/gumbo/include/gumbo/tag_strings.h b/libs/litehtml/src/gumbo/include/gumbo/tag_strings.h new file mode 100644 index 0000000000..6540e2e6ba --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tag_strings.h @@ -0,0 +1,153 @@ +// Generated via `gentags.py src/tag.in`. +// Do not edit; edit src/tag.in instead. +// clang-format off +"html", +"head", +"title", +"base", +"link", +"meta", +"style", +"script", +"noscript", +"template", +"body", +"article", +"section", +"nav", +"aside", +"h1", +"h2", +"h3", +"h4", +"h5", +"h6", +"hgroup", +"header", +"footer", +"address", +"p", +"hr", +"pre", +"blockquote", +"ol", +"ul", +"li", +"dl", +"dt", +"dd", +"figure", +"figcaption", +"main", +"div", +"a", +"em", +"strong", +"small", +"s", +"cite", +"q", +"dfn", +"abbr", +"data", +"time", +"code", +"var", +"samp", +"kbd", +"sub", +"sup", +"i", +"b", +"u", +"mark", +"ruby", +"rt", +"rp", +"bdi", +"bdo", +"span", +"br", +"wbr", +"ins", +"del", +"image", +"img", +"iframe", +"embed", +"object", +"param", +"video", +"audio", +"source", +"track", +"canvas", +"map", +"area", +"math", +"mi", +"mo", +"mn", +"ms", +"mtext", +"mglyph", +"malignmark", +"annotation-xml", +"svg", +"foreignobject", +"desc", +"table", +"caption", +"colgroup", +"col", +"tbody", +"thead", +"tfoot", +"tr", +"td", +"th", +"form", +"fieldset", +"legend", +"label", +"input", +"button", +"select", +"datalist", +"optgroup", +"option", +"textarea", +"keygen", +"output", +"progress", +"meter", +"details", +"summary", +"menu", +"menuitem", +"applet", +"acronym", +"bgsound", +"dir", +"frame", +"frameset", +"noframes", +"isindex", +"listing", +"xmp", +"nextid", +"noembed", +"plaintext", +"rb", +"strike", +"basefont", +"big", +"blink", +"center", +"font", +"marquee", +"multicol", +"nobr", +"spacer", +"tt", +"rtc", diff --git a/libs/litehtml/src/gumbo/include/gumbo/token_type.h b/libs/litehtml/src/gumbo/include/gumbo/token_type.h new file mode 100644 index 0000000000..eeab507869 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/token_type.h @@ -0,0 +1,41 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#ifndef GUMBO_TOKEN_TYPE_H_ +#define GUMBO_TOKEN_TYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// An enum representing the type of token. +typedef enum { + GUMBO_TOKEN_DOCTYPE, + GUMBO_TOKEN_START_TAG, + GUMBO_TOKEN_END_TAG, + GUMBO_TOKEN_COMMENT, + GUMBO_TOKEN_WHITESPACE, + GUMBO_TOKEN_CHARACTER, + GUMBO_TOKEN_CDATA, + GUMBO_TOKEN_NULL, + GUMBO_TOKEN_EOF +} GumboTokenType; + +#ifdef __cplusplus +} // extern C +#endif + +#endif // GUMBO_TOKEN_TYPE_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/tokenizer.h b/libs/litehtml/src/gumbo/include/gumbo/tokenizer.h new file mode 100644 index 0000000000..1e2a2ca730 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tokenizer.h @@ -0,0 +1,123 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This contains an implementation of a tokenizer for HTML5. It consumes a +// buffer of UTF-8 characters, and then emits a stream of tokens. + +#ifndef GUMBO_TOKENIZER_H_ +#define GUMBO_TOKENIZER_H_ + +#include <stdbool.h> +#include <stddef.h> + +#include "gumbo.h" +#include "token_type.h" +#include "tokenizer_states.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalParser; + +// Struct containing all information pertaining to doctype tokens. +typedef struct GumboInternalTokenDocType { + const char* name; + const char* public_identifier; + const char* system_identifier; + bool force_quirks; + // There's no way to tell a 0-length public or system ID apart from the + // absence of a public or system ID, but they're handled different by the + // spec, so we need bool flags for them. + bool has_public_identifier; + bool has_system_identifier; +} GumboTokenDocType; + +// Struct containing all information pertaining to start tag tokens. +typedef struct GumboInternalTokenStartTag { + GumboTag tag; + GumboVector /* GumboAttribute */ attributes; + bool is_self_closing; +} GumboTokenStartTag; + +// A data structure representing a single token in the input stream. This +// contains an enum for the type, the source position, a GumboStringPiece +// pointing to the original text, and then a union for any parsed data. +typedef struct GumboInternalToken { + GumboTokenType type; + GumboSourcePosition position; + GumboStringPiece original_text; + union { + GumboTokenDocType doc_type; + GumboTokenStartTag start_tag; + GumboTag end_tag; + const char* text; // For comments. + int character; // For character, whitespace, null, and EOF tokens. + } v; +} GumboToken; + +// Initializes the tokenizer state within the GumboParser object, setting up a +// parse of the specified text. +void gumbo_tokenizer_state_init( + struct GumboInternalParser* parser, const char* text, size_t text_length); + +// Destroys the tokenizer state within the GumboParser object, freeing any +// dynamically-allocated structures within it. +void gumbo_tokenizer_state_destroy(struct GumboInternalParser* parser); + +// Sets the tokenizer state to the specified value. This is needed by some +// parser states, which alter the state of the tokenizer in response to tags +// seen. +void gumbo_tokenizer_set_state( + struct GumboInternalParser* parser, GumboTokenizerEnum state); + +// Flags whether the current node is a foreign content element. This is +// necessary for the markup declaration open state, where the tokenizer must be +// aware of the state of the parser to properly tokenize bad comment tags. +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#markup-declaration-open-state +void gumbo_tokenizer_set_is_current_node_foreign( + struct GumboInternalParser* parser, bool is_foreign); + +// Lexes a single token from the specified buffer, filling the output with the +// parsed GumboToken data structure. Returns true for a successful +// tokenization, false if a parse error occurs. +// +// Example: +// struct GumboInternalParser parser; +// GumboToken output; +// gumbo_tokenizer_state_init(&parser, text, strlen(text)); +// while (gumbo_lex(&parser, &output)) { +// ...do stuff with output. +// gumbo_token_destroy(&parser, &token); +// } +// gumbo_tokenizer_state_destroy(&parser); +bool gumbo_lex(struct GumboInternalParser* parser, GumboToken* output); + +// Frees the internally-allocated pointers within an GumboToken. Note that this +// doesn't free the token itself, since oftentimes it will be allocated on the +// stack. A simple call to free() (or GumboParser->deallocator, if +// appropriate) can handle that. +// +// Note that if you are handing over ownership of the internal strings to some +// other data structure - for example, a parse tree - these do not need to be +// freed. +void gumbo_token_destroy(struct GumboInternalParser* parser, GumboToken* token); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_TOKENIZER_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/tokenizer_states.h b/libs/litehtml/src/gumbo/include/gumbo/tokenizer_states.h new file mode 100644 index 0000000000..80659f5f1a --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/tokenizer_states.h @@ -0,0 +1,103 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This contains the list of states used in the tokenizer. Although at first +// glance it seems like these could be kept internal to the tokenizer, several +// of the actions in the parser require that it reach into the tokenizer and +// reset the tokenizer state. For that to work, it needs to have the +// definitions of individual states available. +// +// This may also be useful for providing more detailed error messages for parse +// errors, as we can match up states and inputs in a table without having to +// clutter the tokenizer code with lots of precise error messages. + +#ifndef GUMBO_TOKENIZER_STATES_H_ +#define GUMBO_TOKENIZER_STATES_H_ + +// The ordering of this enum is also used to build the dispatch table for the +// tokenizer state machine, so if it is changed, be sure to update that too. +typedef enum { + GUMBO_LEX_DATA, + GUMBO_LEX_CHAR_REF_IN_DATA, + GUMBO_LEX_RCDATA, + GUMBO_LEX_CHAR_REF_IN_RCDATA, + GUMBO_LEX_RAWTEXT, + GUMBO_LEX_SCRIPT, + GUMBO_LEX_PLAINTEXT, + GUMBO_LEX_TAG_OPEN, + GUMBO_LEX_END_TAG_OPEN, + GUMBO_LEX_TAG_NAME, + GUMBO_LEX_RCDATA_LT, + GUMBO_LEX_RCDATA_END_TAG_OPEN, + GUMBO_LEX_RCDATA_END_TAG_NAME, + GUMBO_LEX_RAWTEXT_LT, + GUMBO_LEX_RAWTEXT_END_TAG_OPEN, + GUMBO_LEX_RAWTEXT_END_TAG_NAME, + GUMBO_LEX_SCRIPT_LT, + GUMBO_LEX_SCRIPT_END_TAG_OPEN, + GUMBO_LEX_SCRIPT_END_TAG_NAME, + GUMBO_LEX_SCRIPT_ESCAPED_START, + GUMBO_LEX_SCRIPT_ESCAPED_START_DASH, + GUMBO_LEX_SCRIPT_ESCAPED, + GUMBO_LEX_SCRIPT_ESCAPED_DASH, + GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH, + GUMBO_LEX_SCRIPT_ESCAPED_LT, + GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN, + GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT, + GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END, + GUMBO_LEX_BEFORE_ATTR_NAME, + GUMBO_LEX_ATTR_NAME, + GUMBO_LEX_AFTER_ATTR_NAME, + GUMBO_LEX_BEFORE_ATTR_VALUE, + GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED, + GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED, + GUMBO_LEX_ATTR_VALUE_UNQUOTED, + GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE, + GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED, + GUMBO_LEX_SELF_CLOSING_START_TAG, + GUMBO_LEX_BOGUS_COMMENT, + GUMBO_LEX_MARKUP_DECLARATION, + GUMBO_LEX_COMMENT_START, + GUMBO_LEX_COMMENT_START_DASH, + GUMBO_LEX_COMMENT, + GUMBO_LEX_COMMENT_END_DASH, + GUMBO_LEX_COMMENT_END, + GUMBO_LEX_COMMENT_END_BANG, + GUMBO_LEX_DOCTYPE, + GUMBO_LEX_BEFORE_DOCTYPE_NAME, + GUMBO_LEX_DOCTYPE_NAME, + GUMBO_LEX_AFTER_DOCTYPE_NAME, + GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD, + GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID, + GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED, + GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED, + GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID, + GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID, + GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD, + GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID, + GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED, + GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED, + GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID, + GUMBO_LEX_BOGUS_DOCTYPE, + GUMBO_LEX_CDATA +} GumboTokenizerEnum; + +#endif // GUMBO_TOKENIZER_STATES_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/utf8.h b/libs/litehtml/src/gumbo/include/gumbo/utf8.h new file mode 100644 index 0000000000..ee852abfba --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/utf8.h @@ -0,0 +1,132 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This contains an implementation of a UTF8 iterator and decoder suitable for +// an HTML5 parser. This does a bit more than straight UTF-8 decoding. The +// HTML5 spec specifies that: +// 1. Decoding errors are parse errors. +// 2. Certain other codepoints (eg. control characters) are parse errors. +// 3. Carriage returns and CR/LF groups are converted to line feeds. +// http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#decoded-as-utf-8,-with-error-handling +// +// Also, we want to keep track of source positions for error handling. As a +// result, we fold all that functionality into this decoder, and can't use an +// off-the-shelf library. +// +// This header is internal-only, which is why we prefix functions with only +// utf8_ or utf8_iterator_ instead of gumbo_utf8_. + +#ifndef GUMBO_UTF8_H_ +#define GUMBO_UTF8_H_ + +#include <stdbool.h> +#include <stddef.h> + +#include "gumbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GumboInternalError; +struct GumboInternalParser; + +// Unicode replacement char. +extern const int kUtf8ReplacementChar; + +typedef struct GumboInternalUtf8Iterator { + // Points at the start of the code point most recently read into 'current'. + const char* _start; + + // Points at the mark. The mark is initially set to the beginning of the + // input. + const char* _mark; + + // Points past the end of the iter, like a past-the-end iterator in the STL. + const char* _end; + + // The code point under the cursor. + int _current; + + // The width in bytes of the current code point. + ptrdiff_t _width; + + // The SourcePosition for the current location. + GumboSourcePosition _pos; + + // The SourcePosition for the mark. + GumboSourcePosition _mark_pos; + + // Pointer back to the GumboParser instance, for configuration options and + // error recording. + struct GumboInternalParser* _parser; +} Utf8Iterator; + +// Returns true if this Unicode code point is in the list of characters +// forbidden by the HTML5 spec, such as NUL bytes and undefined control chars. +bool utf8_is_invalid_code_point(int c); + +// Initializes a new Utf8Iterator from the given byte buffer. The source does +// not have to be NUL-terminated, but the length must be passed in explicitly. +void utf8iterator_init(struct GumboInternalParser* parser, const char* source, + size_t source_length, Utf8Iterator* iter); + +// Advances the current position by one code point. +void utf8iterator_next(Utf8Iterator* iter); + +// Returns the current code point as an integer. +int utf8iterator_current(const Utf8Iterator* iter); + +// Retrieves and fills the output parameter with the current source position. +void utf8iterator_get_position( + const Utf8Iterator* iter, GumboSourcePosition* output); + +// Retrieves a character pointer to the start of the current character. +const char* utf8iterator_get_char_pointer(const Utf8Iterator* iter); + +// Retrieves a character pointer to 1 past the end of the buffer. This is +// necessary for certain state machines and string comparisons that would like +// to look directly for ASCII text in the buffer without going through the +// decoder. +const char* utf8iterator_get_end_pointer(const Utf8Iterator* iter); + +// If the upcoming text in the buffer matches the specified prefix (which has +// length 'length'), consume it and return true. Otherwise, return false with +// no other effects. If the length of the string would overflow the buffer, +// this returns false. Note that prefix should not contain null bytes because +// of the use of strncmp/strncasecmp internally. All existing use-cases adhere +// to this. +bool utf8iterator_maybe_consume_match( + Utf8Iterator* iter, const char* prefix, size_t length, bool case_sensitive); + +// "Marks" a particular location of interest in the input stream, so that it can +// later be reset() to. There's also the ability to record an error at the +// point that was marked, as oftentimes that's more useful than the last +// character before the error was detected. +void utf8iterator_mark(Utf8Iterator* iter); + +// Returns the current input stream position to the mark. +void utf8iterator_reset(Utf8Iterator* iter); + +// Sets the position and original text fields of an error to the value at the +// mark. +void utf8iterator_fill_error_at_mark( + Utf8Iterator* iter, struct GumboInternalError* error); + +#ifdef __cplusplus +} +#endif +#endif // GUMBO_UTF8_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/util.h b/libs/litehtml/src/gumbo/include/gumbo/util.h new file mode 100644 index 0000000000..98a7d1c466 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/util.h @@ -0,0 +1,62 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// This contains some utility functions that didn't fit into any of the other +// headers. + +#ifndef GUMBO_UTIL_H_ +#define GUMBO_UTIL_H_ +#ifdef _MSC_VER +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif +#include <stdbool.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Forward declaration since it's passed into some of the functions in this +// header. +struct GumboInternalParser; + +// Utility function for allocating & copying a null-terminated string into a +// freshly-allocated buffer. This is necessary for proper memory management; we +// have the convention that all const char* in parse tree structures are +// freshly-allocated, so if we didn't copy, we'd try to delete a literal string +// when the parse tree is destroyed. +char* gumbo_copy_stringz(struct GumboInternalParser* parser, const char* str); + +// Allocate a chunk of memory, using the allocator specified in the Parser's +// ~config options. +void* gumbo_parser_allocate( + struct GumboInternalParser* parser, size_t num_bytes); + +// Deallocate a chunk of memory, using the deallocator specified in the Parser's +// ~config options. +void gumbo_parser_deallocate(struct GumboInternalParser* parser, void* ptr); + +// Debug wrapper for printf, to make it easier to turn off debugging info when +// required. +void gumbo_debug(const char* format, ...); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_UTIL_H_ diff --git a/libs/litehtml/src/gumbo/include/gumbo/vector.h b/libs/litehtml/src/gumbo/include/gumbo/vector.h new file mode 100644 index 0000000000..70fe6fa689 --- /dev/null +++ b/libs/litehtml/src/gumbo/include/gumbo/vector.h @@ -0,0 +1,67 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#ifndef GUMBO_VECTOR_H_ +#define GUMBO_VECTOR_H_ + +#include "gumbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Forward declaration since it's passed into some of the functions in this +// header. +struct GumboInternalParser; + +// Initializes a new GumboVector with the specified initial capacity. +void gumbo_vector_init(struct GumboInternalParser* parser, + size_t initial_capacity, GumboVector* vector); + +// Frees the memory used by an GumboVector. Does not free the contained +// pointers. +void gumbo_vector_destroy( + struct GumboInternalParser* parser, GumboVector* vector); + +// Adds a new element to an GumboVector. +void gumbo_vector_add( + struct GumboInternalParser* parser, void* element, GumboVector* vector); + +// Removes and returns the element most recently added to the GumboVector. +// Ownership is transferred to caller. Capacity is unchanged. If the vector is +// empty, NULL is returned. +void* gumbo_vector_pop(struct GumboInternalParser* parser, GumboVector* vector); + +// Inserts an element at a specific index. This is potentially O(N) time, but +// is necessary for some of the spec's behavior. +void gumbo_vector_insert_at(struct GumboInternalParser* parser, void* element, + unsigned int index, GumboVector* vector); + +// Removes an element from the vector, or does nothing if the element is not in +// the vector. +void gumbo_vector_remove( + struct GumboInternalParser* parser, void* element, GumboVector* vector); + +// Removes and returns an element at a specific index. Note that this is +// potentially O(N) time and should be used sparingly. +void* gumbo_vector_remove_at(struct GumboInternalParser* parser, + unsigned int index, GumboVector* vector); + +#ifdef __cplusplus +} +#endif + +#endif // GUMBO_VECTOR_H_ diff --git a/libs/litehtml/src/gumbo/parser.c b/libs/litehtml/src/gumbo/parser.c new file mode 100644 index 0000000000..653fd85acc --- /dev/null +++ b/libs/litehtml/src/gumbo/parser.c @@ -0,0 +1,4188 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "attribute.h" +#include "error.h" +#include "gumbo.h" +#include "insertion_mode.h" +#include "parser.h" +#include "tokenizer.h" +#include "tokenizer_states.h" +#include "utf8.h" +#include "util.h" +#include "vector.h" + +#define AVOID_UNUSED_VARIABLE_WARNING(i) (void)(i) + +#define GUMBO_STRING(literal) \ + { literal, sizeof(literal) - 1 } +#define TERMINATOR \ + { "", 0 } + +typedef char gumbo_tagset[GUMBO_TAG_LAST]; +#define TAG(tag) [GUMBO_TAG_##tag] = (1 << GUMBO_NAMESPACE_HTML) +#define TAG_SVG(tag) [GUMBO_TAG_##tag] = (1 << GUMBO_NAMESPACE_SVG) +#define TAG_MATHML(tag) [GUMBO_TAG_##tag] = (1 << GUMBO_NAMESPACE_MATHML) + +#define TAGSET_INCLUDES(tagset, namespace, tag) \ + (tag < GUMBO_TAG_LAST && tagset[(int) tag] == (1 << (int) namespace)) + +// selected forward declarations as it is getting hard to find +// an appropriate order +static bool node_html_tag_is(const GumboNode*, GumboTag); +static GumboInsertionMode get_current_template_insertion_mode( + const GumboParser*); +static bool handle_in_template(GumboParser*, GumboToken*); +static void destroy_node(GumboParser*, GumboNode*); + +static void* malloc_wrapper(void* unused, size_t size) { return malloc(size); } + +static void free_wrapper(void* unused, void* ptr) { free(ptr); } + +const GumboOptions kGumboDefaultOptions = {&malloc_wrapper, &free_wrapper, NULL, + 8, false, -1, GUMBO_TAG_LAST, GUMBO_NAMESPACE_HTML}; + +static const GumboStringPiece kDoctypeHtml = GUMBO_STRING("html"); +static const GumboStringPiece kPublicIdHtml4_0 = + GUMBO_STRING("-//W3C//DTD HTML 4.0//EN"); +static const GumboStringPiece kPublicIdHtml4_01 = + GUMBO_STRING("-//W3C//DTD HTML 4.01//EN"); +static const GumboStringPiece kPublicIdXhtml1_0 = + GUMBO_STRING("-//W3C//DTD XHTML 1.0 Strict//EN"); +static const GumboStringPiece kPublicIdXhtml1_1 = + GUMBO_STRING("-//W3C//DTD XHTML 1.1//EN"); +static const GumboStringPiece kSystemIdRecHtml4_0 = + GUMBO_STRING("http://www.w3.org/TR/REC-html40/strict.dtd"); +static const GumboStringPiece kSystemIdHtml4 = + GUMBO_STRING("http://www.w3.org/TR/html4/strict.dtd"); +static const GumboStringPiece kSystemIdXhtmlStrict1_1 = + GUMBO_STRING("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); +static const GumboStringPiece kSystemIdXhtml1_1 = + GUMBO_STRING("http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"); +static const GumboStringPiece kSystemIdLegacyCompat = + GUMBO_STRING("about:legacy-compat"); + +// The doctype arrays have an explicit terminator because we want to pass them +// to a helper function, and passing them as a pointer discards sizeof +// information. The SVG arrays are used only by one-off functions, and so loops +// over them use sizeof directly instead of a terminator. + +static const GumboStringPiece kQuirksModePublicIdPrefixes[] = { + GUMBO_STRING("+//Silmaril//dtd html Pro v0r11 19970101//"), + GUMBO_STRING("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//"), + GUMBO_STRING("-//AS//DTD HTML 3.0 asWedit + extensions//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0 Level 1//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0 Level 2//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0 Strict Level 1//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0 Strict Level 2//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0 Strict//"), + GUMBO_STRING("-//IETF//DTD HTML 2.0//"), + GUMBO_STRING("-//IETF//DTD HTML 2.1E//"), + GUMBO_STRING("-//IETF//DTD HTML 3.0//"), + GUMBO_STRING("-//IETF//DTD HTML 3.2 Final//"), + GUMBO_STRING("-//IETF//DTD HTML 3.2//"), + GUMBO_STRING("-//IETF//DTD HTML 3//"), + GUMBO_STRING("-//IETF//DTD HTML Level 0//"), + GUMBO_STRING("-//IETF//DTD HTML Level 1//"), + GUMBO_STRING("-//IETF//DTD HTML Level 2//"), + GUMBO_STRING("-//IETF//DTD HTML Level 3//"), + GUMBO_STRING("-//IETF//DTD HTML Strict Level 0//"), + GUMBO_STRING("-//IETF//DTD HTML Strict Level 1//"), + GUMBO_STRING("-//IETF//DTD HTML Strict Level 2//"), + GUMBO_STRING("-//IETF//DTD HTML Strict Level 3//"), + GUMBO_STRING("-//IETF//DTD HTML Strict//"), + GUMBO_STRING("-//IETF//DTD HTML//"), + GUMBO_STRING("-//Metrius//DTD Metrius Presentational//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 2.0 HTML//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 2.0 Tables//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 3.0 HTML//"), + GUMBO_STRING("-//Microsoft//DTD Internet Explorer 3.0 Tables//"), + GUMBO_STRING("-//Netscape Comm. Corp.//DTD HTML//"), + GUMBO_STRING("-//Netscape Comm. Corp.//DTD Strict HTML//"), + GUMBO_STRING("-//O'Reilly and Associates//DTD HTML 2.0//"), + GUMBO_STRING("-//O'Reilly and Associates//DTD HTML Extended 1.0//"), + GUMBO_STRING("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//"), + GUMBO_STRING( + "-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::)" + "extensions to HTML 4.0//"), + GUMBO_STRING( + "-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::" + "extensions to HTML 4.0//"), + GUMBO_STRING("-//Spyglass//DTD HTML 2.0 Extended//"), + GUMBO_STRING("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//"), + GUMBO_STRING("-//Sun Microsystems Corp.//DTD HotJava HTML//"), + GUMBO_STRING("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//"), + GUMBO_STRING("-//W3C//DTD HTML 3 1995-03-24//"), + GUMBO_STRING("-//W3C//DTD HTML 3.2 Draft//"), + GUMBO_STRING("-//W3C//DTD HTML 3.2 Final//"), + GUMBO_STRING("-//W3C//DTD HTML 3.2//"), + GUMBO_STRING("-//W3C//DTD HTML 3.2S Draft//"), + GUMBO_STRING("-//W3C//DTD HTML 4.0 Frameset//"), + GUMBO_STRING("-//W3C//DTD HTML 4.0 Transitional//"), + GUMBO_STRING("-//W3C//DTD HTML Experimental 19960712//"), + GUMBO_STRING("-//W3C//DTD HTML Experimental 970421//"), + GUMBO_STRING("-//W3C//DTD W3 HTML//"), + GUMBO_STRING("-//W3O//DTD W3 HTML 3.0//"), + GUMBO_STRING("-//WebTechs//DTD Mozilla HTML 2.0//"), + GUMBO_STRING("-//WebTechs//DTD Mozilla HTML//"), TERMINATOR}; + +static const GumboStringPiece kQuirksModePublicIdExactMatches[] = { + GUMBO_STRING("-//W3O//DTD W3 HTML Strict 3.0//EN//"), + GUMBO_STRING("-/W3C/DTD HTML 4.0 Transitional/EN"), GUMBO_STRING("HTML"), + TERMINATOR}; + +static const GumboStringPiece kQuirksModeSystemIdExactMatches[] = { + GUMBO_STRING("http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"), + TERMINATOR}; + +static const GumboStringPiece kLimitedQuirksPublicIdPrefixes[] = { + GUMBO_STRING("-//W3C//DTD XHTML 1.0 Frameset//"), + GUMBO_STRING("-//W3C//DTD XHTML 1.0 Transitional//"), TERMINATOR}; + +static const GumboStringPiece kLimitedQuirksRequiresSystemIdPublicIdPrefixes[] = + {GUMBO_STRING("-//W3C//DTD HTML 4.01 Frameset//"), + GUMBO_STRING("-//W3C//DTD HTML 4.01 Transitional//"), TERMINATOR}; + +// Indexed by GumboNamespaceEnum; keep in sync with that. +static const char* kLegalXmlns[] = {"http://www.w3.org/1999/xhtml", + "http://www.w3.org/2000/svg", "http://www.w3.org/1998/Math/MathML"}; + +typedef struct _ReplacementEntry { + const GumboStringPiece from; + const GumboStringPiece to; +} ReplacementEntry; + +#define REPLACEMENT_ENTRY(from, to) \ + { GUMBO_STRING(from), GUMBO_STRING(to) } + +// Static data for SVG attribute replacements. +// https://html.spec.whatwg.org/multipage/syntax.html#creating-and-inserting-nodes +static const ReplacementEntry kSvgAttributeReplacements[] = { + REPLACEMENT_ENTRY("attributename", "attributeName"), + REPLACEMENT_ENTRY("attributetype", "attributeType"), + REPLACEMENT_ENTRY("basefrequency", "baseFrequency"), + REPLACEMENT_ENTRY("baseprofile", "baseProfile"), + REPLACEMENT_ENTRY("calcmode", "calcMode"), + REPLACEMENT_ENTRY("clippathunits", "clipPathUnits"), + // REPLACEMENT_ENTRY("contentscripttype", "contentScriptType"), + // REPLACEMENT_ENTRY("contentstyletype", "contentStyleType"), + REPLACEMENT_ENTRY("diffuseconstant", "diffuseConstant"), + REPLACEMENT_ENTRY("edgemode", "edgeMode"), + // REPLACEMENT_ENTRY("externalresourcesrequired", + // "externalResourcesRequired"), + // REPLACEMENT_ENTRY("filterres", "filterRes"), + REPLACEMENT_ENTRY("filterunits", "filterUnits"), + REPLACEMENT_ENTRY("glyphref", "glyphRef"), + REPLACEMENT_ENTRY("gradienttransform", "gradientTransform"), + REPLACEMENT_ENTRY("gradientunits", "gradientUnits"), + REPLACEMENT_ENTRY("kernelmatrix", "kernelMatrix"), + REPLACEMENT_ENTRY("kernelunitlength", "kernelUnitLength"), + REPLACEMENT_ENTRY("keypoints", "keyPoints"), + REPLACEMENT_ENTRY("keysplines", "keySplines"), + REPLACEMENT_ENTRY("keytimes", "keyTimes"), + REPLACEMENT_ENTRY("lengthadjust", "lengthAdjust"), + REPLACEMENT_ENTRY("limitingconeangle", "limitingConeAngle"), + REPLACEMENT_ENTRY("markerheight", "markerHeight"), + REPLACEMENT_ENTRY("markerunits", "markerUnits"), + REPLACEMENT_ENTRY("markerwidth", "markerWidth"), + REPLACEMENT_ENTRY("maskcontentunits", "maskContentUnits"), + REPLACEMENT_ENTRY("maskunits", "maskUnits"), + REPLACEMENT_ENTRY("numoctaves", "numOctaves"), + REPLACEMENT_ENTRY("pathlength", "pathLength"), + REPLACEMENT_ENTRY("patterncontentunits", "patternContentUnits"), + REPLACEMENT_ENTRY("patterntransform", "patternTransform"), + REPLACEMENT_ENTRY("patternunits", "patternUnits"), + REPLACEMENT_ENTRY("pointsatx", "pointsAtX"), + REPLACEMENT_ENTRY("pointsaty", "pointsAtY"), + REPLACEMENT_ENTRY("pointsatz", "pointsAtZ"), + REPLACEMENT_ENTRY("preservealpha", "preserveAlpha"), + REPLACEMENT_ENTRY("preserveaspectratio", "preserveAspectRatio"), + REPLACEMENT_ENTRY("primitiveunits", "primitiveUnits"), + REPLACEMENT_ENTRY("refx", "refX"), REPLACEMENT_ENTRY("refy", "refY"), + REPLACEMENT_ENTRY("repeatcount", "repeatCount"), + REPLACEMENT_ENTRY("repeatdur", "repeatDur"), + REPLACEMENT_ENTRY("requiredextensions", "requiredExtensions"), + REPLACEMENT_ENTRY("requiredfeatures", "requiredFeatures"), + REPLACEMENT_ENTRY("specularconstant", "specularConstant"), + REPLACEMENT_ENTRY("specularexponent", "specularExponent"), + REPLACEMENT_ENTRY("spreadmethod", "spreadMethod"), + REPLACEMENT_ENTRY("startoffset", "startOffset"), + REPLACEMENT_ENTRY("stddeviation", "stdDeviation"), + REPLACEMENT_ENTRY("stitchtiles", "stitchTiles"), + REPLACEMENT_ENTRY("surfacescale", "surfaceScale"), + REPLACEMENT_ENTRY("systemlanguage", "systemLanguage"), + REPLACEMENT_ENTRY("tablevalues", "tableValues"), + REPLACEMENT_ENTRY("targetx", "targetX"), + REPLACEMENT_ENTRY("targety", "targetY"), + REPLACEMENT_ENTRY("textlength", "textLength"), + REPLACEMENT_ENTRY("viewbox", "viewBox"), + REPLACEMENT_ENTRY("viewtarget", "viewTarget"), + REPLACEMENT_ENTRY("xchannelselector", "xChannelSelector"), + REPLACEMENT_ENTRY("ychannelselector", "yChannelSelector"), + REPLACEMENT_ENTRY("zoomandpan", "zoomAndPan"), +}; + +static const ReplacementEntry kSvgTagReplacements[] = { + REPLACEMENT_ENTRY("altglyph", "altGlyph"), + REPLACEMENT_ENTRY("altglyphdef", "altGlyphDef"), + REPLACEMENT_ENTRY("altglyphitem", "altGlyphItem"), + REPLACEMENT_ENTRY("animatecolor", "animateColor"), + REPLACEMENT_ENTRY("animatemotion", "animateMotion"), + REPLACEMENT_ENTRY("animatetransform", "animateTransform"), + REPLACEMENT_ENTRY("clippath", "clipPath"), + REPLACEMENT_ENTRY("feblend", "feBlend"), + REPLACEMENT_ENTRY("fecolormatrix", "feColorMatrix"), + REPLACEMENT_ENTRY("fecomponenttransfer", "feComponentTransfer"), + REPLACEMENT_ENTRY("fecomposite", "feComposite"), + REPLACEMENT_ENTRY("feconvolvematrix", "feConvolveMatrix"), + REPLACEMENT_ENTRY("fediffuselighting", "feDiffuseLighting"), + REPLACEMENT_ENTRY("fedisplacementmap", "feDisplacementMap"), + REPLACEMENT_ENTRY("fedistantlight", "feDistantLight"), + REPLACEMENT_ENTRY("feflood", "feFlood"), + REPLACEMENT_ENTRY("fefunca", "feFuncA"), + REPLACEMENT_ENTRY("fefuncb", "feFuncB"), + REPLACEMENT_ENTRY("fefuncg", "feFuncG"), + REPLACEMENT_ENTRY("fefuncr", "feFuncR"), + REPLACEMENT_ENTRY("fegaussianblur", "feGaussianBlur"), + REPLACEMENT_ENTRY("feimage", "feImage"), + REPLACEMENT_ENTRY("femerge", "feMerge"), + REPLACEMENT_ENTRY("femergenode", "feMergeNode"), + REPLACEMENT_ENTRY("femorphology", "feMorphology"), + REPLACEMENT_ENTRY("feoffset", "feOffset"), + REPLACEMENT_ENTRY("fepointlight", "fePointLight"), + REPLACEMENT_ENTRY("fespecularlighting", "feSpecularLighting"), + REPLACEMENT_ENTRY("fespotlight", "feSpotLight"), + REPLACEMENT_ENTRY("fetile", "feTile"), + REPLACEMENT_ENTRY("feturbulence", "feTurbulence"), + REPLACEMENT_ENTRY("foreignobject", "foreignObject"), + REPLACEMENT_ENTRY("glyphref", "glyphRef"), + REPLACEMENT_ENTRY("lineargradient", "linearGradient"), + REPLACEMENT_ENTRY("radialgradient", "radialGradient"), + REPLACEMENT_ENTRY("textpath", "textPath"), +}; + +typedef struct _NamespacedAttributeReplacement { + const char* from; + const char* local_name; + const GumboAttributeNamespaceEnum attr_namespace; +} NamespacedAttributeReplacement; + +static const NamespacedAttributeReplacement kForeignAttributeReplacements[] = { + {"xlink:actuate", "actuate", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:actuate", "actuate", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:href", "href", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:role", "role", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:show", "show", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:title", "title", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xlink:type", "type", GUMBO_ATTR_NAMESPACE_XLINK}, + {"xml:base", "base", GUMBO_ATTR_NAMESPACE_XML}, + {"xml:lang", "lang", GUMBO_ATTR_NAMESPACE_XML}, + {"xml:space", "space", GUMBO_ATTR_NAMESPACE_XML}, + {"xmlns", "xmlns", GUMBO_ATTR_NAMESPACE_XMLNS}, + {"xmlns:xlink", "xlink", GUMBO_ATTR_NAMESPACE_XMLNS}, +}; + +// The "scope marker" for the list of active formatting elements. We use a +// pointer to this as a generic marker element, since the particular element +// scope doesn't matter. +static const GumboNode kActiveFormattingScopeMarker; + +// The tag_is and tag_in function use true & false to denote start & end tags, +// but for readability, we define constants for them here. +static const bool kStartTag = true; +static const bool kEndTag = false; + +// Because GumboStringPieces are immutable, we can't insert a character directly +// into a text node. Instead, we accumulate all pending characters here and +// flush them out to a text node whenever a new element is inserted. +// +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#insert-a-character +typedef struct _TextNodeBufferState { + // The accumulated text to be inserted into the current text node. + GumboStringBuffer _buffer; + + // A pointer to the original text represented by this text node. Note that + // because of foster parenting and other strange DOM manipulations, this may + // include other non-text HTML tags in it; it is defined as the span of + // original text from the first character in this text node to the last + // character in this text node. + const char* _start_original_text; + + // The source position of the start of this text node. + GumboSourcePosition _start_position; + + // The type of node that will be inserted (TEXT, CDATA, or WHITESPACE). + GumboNodeType _type; +} TextNodeBufferState; + +typedef struct GumboInternalParserState { + // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#insertion-mode + GumboInsertionMode _insertion_mode; + + // Used for run_generic_parsing_algorithm, which needs to switch back to the + // original insertion mode at its conclusion. + GumboInsertionMode _original_insertion_mode; + + // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-stack-of-open-elements + GumboVector /*GumboNode*/ _open_elements; + + // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-list-of-active-formatting-elements + GumboVector /*GumboNode*/ _active_formatting_elements; + + // The stack of template insertion modes. + // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-insertion-mode + GumboVector /*InsertionMode*/ _template_insertion_modes; + + // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#the-element-pointers + GumboNode* _head_element; + GumboNode* _form_element; + + // The element used as fragment context when parsing in fragment mode + GumboNode* _fragment_ctx; + + // The flag for when the spec says "Reprocess the current token in..." + bool _reprocess_current_token; + + // The flag for "acknowledge the token's self-closing flag". + bool _self_closing_flag_acknowledged; + + // The "frameset-ok" flag from the spec. + bool _frameset_ok; + + // The flag for "If the next token is a LINE FEED, ignore that token...". + bool _ignore_next_linefeed; + + // The flag for "whenever a node would be inserted into the current node, it + // must instead be foster parented". This is used for misnested table + // content, which needs to be handled according to "in body" rules yet foster + // parented outside of the table. + // It would perhaps be more explicit to have this as a parameter to + // handle_in_body and insert_element, but given how special-purpose this is + // and the number of call-sites that would need to take the extra parameter, + // it's easier just to have a state flag. + bool _foster_parent_insertions; + + // The accumulated text node buffer state. + TextNodeBufferState _text_node; + + // The current token. + GumboToken* _current_token; + + // The way that the spec is written, the </body> and </html> tags are *always* + // implicit, because encountering one of those tokens merely switches the + // insertion mode out of "in body". So we have individual state flags for + // those end tags that are then inspected by pop_current_node when the <body> + // and <html> nodes are popped to set the GUMBO_INSERTION_IMPLICIT_END_TAG + // flag appropriately. + bool _closed_body_tag; + bool _closed_html_tag; +} GumboParserState; + +static bool token_has_attribute(const GumboToken* token, const char* name) { + assert(token->type == GUMBO_TOKEN_START_TAG); + return gumbo_get_attribute(&token->v.start_tag.attributes, name) != NULL; +} + +// Checks if the value of the specified attribute is a case-insensitive match +// for the specified string. +static bool attribute_matches( + const GumboVector* attributes, const char* name, const char* value) { + const GumboAttribute* attr = gumbo_get_attribute(attributes, name); + return attr ? strcasecmp(value, attr->value) == 0 : false; +} + +// Checks if the value of the specified attribute is a case-sensitive match +// for the specified string. +static bool attribute_matches_case_sensitive( + const GumboVector* attributes, const char* name, const char* value) { + const GumboAttribute* attr = gumbo_get_attribute(attributes, name); + return attr ? strcmp(value, attr->value) == 0 : false; +} + +// Checks if the specified attribute vectors are identical. +static bool all_attributes_match( + const GumboVector* attr1, const GumboVector* attr2) { + unsigned int num_unmatched_attr2_elements = attr2->length; + for (unsigned int i = 0; i < attr1->length; ++i) { + const GumboAttribute* attr = attr1->data[i]; + if (attribute_matches_case_sensitive(attr2, attr->name, attr->value)) { + --num_unmatched_attr2_elements; + } else { + return false; + } + } + return num_unmatched_attr2_elements == 0; +} + +static void set_frameset_not_ok(GumboParser* parser) { + gumbo_debug("Setting frameset_ok to false.\n"); + parser->_parser_state->_frameset_ok = false; +} + +static GumboNode* create_node(GumboParser* parser, GumboNodeType type) { + GumboNode* node = gumbo_parser_allocate(parser, sizeof(GumboNode)); + node->parent = NULL; + node->index_within_parent = -1; + node->type = type; + node->parse_flags = GUMBO_INSERTION_NORMAL; + return node; +} + +static GumboNode* new_document_node(GumboParser* parser) { + GumboNode* document_node = create_node(parser, GUMBO_NODE_DOCUMENT); + document_node->parse_flags = GUMBO_INSERTION_BY_PARSER; + gumbo_vector_init(parser, 1, &document_node->v.document.children); + + // Must be initialized explicitly, as there's no guarantee that we'll see a + // doc type token. + GumboDocument* document = &document_node->v.document; + document->has_doctype = false; + document->name = NULL; + document->public_identifier = NULL; + document->system_identifier = NULL; + return document_node; +} + +static void output_init(GumboParser* parser) { + GumboOutput* output = gumbo_parser_allocate(parser, sizeof(GumboOutput)); + output->root = NULL; + output->document = new_document_node(parser); + parser->_output = output; + gumbo_init_errors(parser); +} + +static void parser_state_init(GumboParser* parser) { + GumboParserState* parser_state = + gumbo_parser_allocate(parser, sizeof(GumboParserState)); + parser_state->_insertion_mode = GUMBO_INSERTION_MODE_INITIAL; + parser_state->_reprocess_current_token = false; + parser_state->_frameset_ok = true; + parser_state->_ignore_next_linefeed = false; + parser_state->_foster_parent_insertions = false; + parser_state->_text_node._type = GUMBO_NODE_WHITESPACE; + gumbo_string_buffer_init(parser, &parser_state->_text_node._buffer); + gumbo_vector_init(parser, 10, &parser_state->_open_elements); + gumbo_vector_init(parser, 5, &parser_state->_active_formatting_elements); + gumbo_vector_init(parser, 5, &parser_state->_template_insertion_modes); + parser_state->_head_element = NULL; + parser_state->_form_element = NULL; + parser_state->_fragment_ctx = NULL; + parser_state->_current_token = NULL; + parser_state->_closed_body_tag = false; + parser_state->_closed_html_tag = false; + parser->_parser_state = parser_state; +} + +static void parser_state_destroy(GumboParser* parser) { + GumboParserState* state = parser->_parser_state; + if (state->_fragment_ctx) { + destroy_node(parser, state->_fragment_ctx); + } + gumbo_vector_destroy(parser, &state->_active_formatting_elements); + gumbo_vector_destroy(parser, &state->_open_elements); + gumbo_vector_destroy(parser, &state->_template_insertion_modes); + gumbo_string_buffer_destroy(parser, &state->_text_node._buffer); + gumbo_parser_deallocate(parser, state); +} + +static GumboNode* get_document_node(GumboParser* parser) { + return parser->_output->document; +} + +static bool is_fragment_parser(const GumboParser* parser) { + return !!parser->_parser_state->_fragment_ctx; +} + +// Returns the node at the bottom of the stack of open elements, or NULL if no +// elements have been added yet. +static GumboNode* get_current_node(GumboParser* parser) { + GumboVector* open_elements = &parser->_parser_state->_open_elements; + if (open_elements->length == 0) { + assert(!parser->_output->root); + return NULL; + } + assert(open_elements->length > 0); + assert(open_elements->data != NULL); + return open_elements->data[open_elements->length - 1]; +} + +static GumboNode* get_adjusted_current_node(GumboParser* parser) { + GumboParserState* state = parser->_parser_state; + if (state->_open_elements.length == 1 && state->_fragment_ctx) { + return state->_fragment_ctx; + } + return get_current_node(parser); +} + +// Returns true if the given needle is in the given array of literal +// GumboStringPieces. If exact_match is true, this requires that they match +// exactly; otherwise, this performs a prefix match to check if any of the +// elements in haystack start with needle. This always performs a +// case-insensitive match. +static bool is_in_static_list( + const char* needle, const GumboStringPiece* haystack, bool exact_match) { + for (unsigned int i = 0; haystack[i].length > 0; ++i) { + if ((exact_match && !strcmp(needle, haystack[i].data)) || + (!exact_match && !strcasecmp(needle, haystack[i].data))) { + return true; + } + } + return false; +} + +static void set_insertion_mode(GumboParser* parser, GumboInsertionMode mode) { + parser->_parser_state->_insertion_mode = mode; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#reset-the-insertion-mode-appropriately +// This is a helper function that returns the appropriate insertion mode instead +// of setting it. Returns GUMBO_INSERTION_MODE_INITIAL as a sentinel value to +// indicate that there is no appropriate insertion mode, and the loop should +// continue. +static GumboInsertionMode get_appropriate_insertion_mode( + const GumboParser* parser, int index) { + const GumboVector* open_elements = &parser->_parser_state->_open_elements; + const GumboNode* node = open_elements->data[index]; + const bool is_last = index == 0; + + if (is_last && is_fragment_parser(parser)) { + node = parser->_parser_state->_fragment_ctx; + } + + assert(node->type == GUMBO_NODE_ELEMENT || node->type == GUMBO_NODE_TEMPLATE); + switch (node->v.element.tag) { + case GUMBO_TAG_SELECT: { + if (is_last) { + return GUMBO_INSERTION_MODE_IN_SELECT; + } + for (int i = index; i > 0; --i) { + const GumboNode* ancestor = open_elements->data[i]; + if (node_html_tag_is(ancestor, GUMBO_TAG_TEMPLATE)) { + return GUMBO_INSERTION_MODE_IN_SELECT; + } + if (node_html_tag_is(ancestor, GUMBO_TAG_TABLE)) { + return GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE; + } + } + return GUMBO_INSERTION_MODE_IN_SELECT; + } + case GUMBO_TAG_TD: + case GUMBO_TAG_TH: + if (!is_last) return GUMBO_INSERTION_MODE_IN_CELL; + break; + case GUMBO_TAG_TR: + return GUMBO_INSERTION_MODE_IN_ROW; + case GUMBO_TAG_TBODY: + case GUMBO_TAG_THEAD: + case GUMBO_TAG_TFOOT: + return GUMBO_INSERTION_MODE_IN_TABLE_BODY; + case GUMBO_TAG_CAPTION: + return GUMBO_INSERTION_MODE_IN_CAPTION; + case GUMBO_TAG_COLGROUP: + return GUMBO_INSERTION_MODE_IN_COLUMN_GROUP; + case GUMBO_TAG_TABLE: + return GUMBO_INSERTION_MODE_IN_TABLE; + case GUMBO_TAG_TEMPLATE: + return get_current_template_insertion_mode(parser); + case GUMBO_TAG_HEAD: + if (!is_last) return GUMBO_INSERTION_MODE_IN_HEAD; + break; + case GUMBO_TAG_BODY: + return GUMBO_INSERTION_MODE_IN_BODY; + case GUMBO_TAG_FRAMESET: + return GUMBO_INSERTION_MODE_IN_FRAMESET; + case GUMBO_TAG_HTML: + return parser->_parser_state->_head_element + ? GUMBO_INSERTION_MODE_AFTER_HEAD + : GUMBO_INSERTION_MODE_BEFORE_HEAD; + default: + break; + } + return is_last ? GUMBO_INSERTION_MODE_IN_BODY : GUMBO_INSERTION_MODE_INITIAL; +} + +// This performs the actual "reset the insertion mode" loop. +static void reset_insertion_mode_appropriately(GumboParser* parser) { + const GumboVector* open_elements = &parser->_parser_state->_open_elements; + for (int i = open_elements->length; --i >= 0;) { + GumboInsertionMode mode = get_appropriate_insertion_mode(parser, i); + if (mode != GUMBO_INSERTION_MODE_INITIAL) { + set_insertion_mode(parser, mode); + return; + } + } + // Should never get here, because is_last will be set on the last iteration + // and will force GUMBO_INSERTION_MODE_IN_BODY. + assert(0); +} + +static GumboError* parser_add_parse_error( + GumboParser* parser, const GumboToken* token) { + gumbo_debug("Adding parse error.\n"); + GumboError* error = gumbo_add_error(parser); + if (!error) { + return NULL; + } + error->type = GUMBO_ERR_PARSER; + error->position = token->position; + error->original_text = token->original_text.data; + GumboParserError* extra_data = &error->v.parser; + extra_data->input_type = token->type; + extra_data->input_tag = GUMBO_TAG_UNKNOWN; + if (token->type == GUMBO_TOKEN_START_TAG) { + extra_data->input_tag = token->v.start_tag.tag; + } else if (token->type == GUMBO_TOKEN_END_TAG) { + extra_data->input_tag = token->v.end_tag; + } + GumboParserState* state = parser->_parser_state; + extra_data->parser_state = state->_insertion_mode; + gumbo_vector_init( + parser, state->_open_elements.length, &extra_data->tag_stack); + for (unsigned int i = 0; i < state->_open_elements.length; ++i) { + const GumboNode* node = state->_open_elements.data[i]; + assert( + node->type == GUMBO_NODE_ELEMENT || node->type == GUMBO_NODE_TEMPLATE); + gumbo_vector_add( + parser, (void*) node->v.element.tag, &extra_data->tag_stack); + } + return error; +} + +// Returns true if the specified token is either a start or end tag (specified +// by is_start) with one of the tag types in the varargs list. Terminate the +// list with GUMBO_TAG_LAST; this functions as a sentinel since no portion of +// the spec references tags that are not in the spec. +static bool tag_in( + const GumboToken* token, bool is_start, const gumbo_tagset tags) { + GumboTag token_tag; + if (is_start && token->type == GUMBO_TOKEN_START_TAG) { + token_tag = token->v.start_tag.tag; + } else if (!is_start && token->type == GUMBO_TOKEN_END_TAG) { + token_tag = token->v.end_tag; + } else { + return false; + } + return (token_tag < GUMBO_TAG_LAST && tags[(int) token_tag] != 0); +} + +// Like tag_in, but for the single-tag case. +static bool tag_is(const GumboToken* token, bool is_start, GumboTag tag) { + if (is_start && token->type == GUMBO_TOKEN_START_TAG) { + return token->v.start_tag.tag == tag; + } else if (!is_start && token->type == GUMBO_TOKEN_END_TAG) { + return token->v.end_tag == tag; + } else { + return false; + } +} + +// Like tag_in, but checks for the tag of a node, rather than a token. +static bool node_tag_in_set(const GumboNode* node, const gumbo_tagset tags) { + assert(node != NULL); + if (node->type != GUMBO_NODE_ELEMENT && node->type != GUMBO_NODE_TEMPLATE) { + return false; + } + return TAGSET_INCLUDES( + tags, node->v.element.tag_namespace, node->v.element.tag); +} + +// Like node_tag_in, but for the single-tag case. +static bool node_qualified_tag_is( + const GumboNode* node, GumboNamespaceEnum ns, GumboTag tag) { + assert(node); + return (node->type == GUMBO_NODE_ELEMENT || + node->type == GUMBO_NODE_TEMPLATE) && + node->v.element.tag == tag && node->v.element.tag_namespace == ns; +} + +// Like node_tag_in, but for the single-tag case in the HTML namespace +static bool node_html_tag_is(const GumboNode* node, GumboTag tag) { + return node_qualified_tag_is(node, GUMBO_NAMESPACE_HTML, tag); +} + +static void push_template_insertion_mode( + GumboParser* parser, GumboInsertionMode mode) { + gumbo_vector_add( + parser, (void*) mode, &parser->_parser_state->_template_insertion_modes); +} + +static void pop_template_insertion_mode(GumboParser* parser) { + gumbo_vector_pop(parser, &parser->_parser_state->_template_insertion_modes); +} + +// Returns the current template insertion mode. If the stack of template +// insertion modes is empty, this returns GUMBO_INSERTION_MODE_INITIAL. +static GumboInsertionMode get_current_template_insertion_mode( + const GumboParser* parser) { + GumboVector* template_insertion_modes = + &parser->_parser_state->_template_insertion_modes; + if (template_insertion_modes->length == 0) { + return GUMBO_INSERTION_MODE_INITIAL; + } + return (GumboInsertionMode) + template_insertion_modes->data[(template_insertion_modes->length - 1)]; +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#mathml-text-integration-point +static bool is_mathml_integration_point(const GumboNode* node) { + return node_tag_in_set( + node, (gumbo_tagset){TAG_MATHML(MI), TAG_MATHML(MO), TAG_MATHML(MN), + TAG_MATHML(MS), TAG_MATHML(MTEXT)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#html-integration-point +static bool is_html_integration_point(const GumboNode* node) { + return node_tag_in_set(node, (gumbo_tagset){TAG_SVG(FOREIGNOBJECT), + TAG_SVG(DESC), TAG_SVG(TITLE)}) || + (node_qualified_tag_is( + node, GUMBO_NAMESPACE_MATHML, GUMBO_TAG_ANNOTATION_XML) && + (attribute_matches( + &node->v.element.attributes, "encoding", "text/html") || + attribute_matches(&node->v.element.attributes, "encoding", + "application/xhtml+xml"))); +} + +// This represents a place to insert a node, consisting of a target parent and a +// child index within that parent. If the node should be inserted at the end of +// the parent's child, index will be -1. +typedef struct { + GumboNode* target; + int index; +} InsertionLocation; + +InsertionLocation get_appropriate_insertion_location( + GumboParser* parser, GumboNode* override_target) { + InsertionLocation retval = {override_target, -1}; + if (retval.target == NULL) { + // No override target; default to the current node, but special-case the + // root node since get_current_node() assumes the stack of open elements is + // non-empty. + retval.target = parser->_output->root != NULL ? get_current_node(parser) + : get_document_node(parser); + } + if (!parser->_parser_state->_foster_parent_insertions || + !node_tag_in_set(retval.target, (gumbo_tagset){TAG(TABLE), TAG(TBODY), + TAG(TFOOT), TAG(THEAD), TAG(TR)})) { + return retval; + } + + // Foster-parenting case. + int last_template_index = -1; + int last_table_index = -1; + GumboVector* open_elements = &parser->_parser_state->_open_elements; + for (unsigned int i = 0; i < open_elements->length; ++i) { + if (node_html_tag_is(open_elements->data[i], GUMBO_TAG_TEMPLATE)) { + last_template_index = i; + } + if (node_html_tag_is(open_elements->data[i], GUMBO_TAG_TABLE)) { + last_table_index = i; + } + } + if (last_template_index != -1 && + (last_table_index == -1 || last_template_index > last_table_index)) { + retval.target = open_elements->data[last_template_index]; + return retval; + } + if (last_table_index == -1) { + retval.target = open_elements->data[0]; + return retval; + } + GumboNode* last_table = open_elements->data[last_table_index]; + if (last_table->parent != NULL) { + retval.target = last_table->parent; + retval.index = (int)last_table->index_within_parent; + return retval; + } + + retval.target = open_elements->data[last_table_index - 1]; + return retval; +} + +// Appends a node to the end of its parent, setting the "parent" and +// "index_within_parent" fields appropriately. +static void append_node( + GumboParser* parser, GumboNode* parent, GumboNode* node) { + assert(node->parent == NULL); + assert(node->index_within_parent == -1); + GumboVector* children; + if (parent->type == GUMBO_NODE_ELEMENT || + parent->type == GUMBO_NODE_TEMPLATE) { + children = &parent->v.element.children; + } else { + assert(parent->type == GUMBO_NODE_DOCUMENT); + children = &parent->v.document.children; + } + node->parent = parent; + node->index_within_parent = children->length; + gumbo_vector_add(parser, (void*) node, children); + assert(node->index_within_parent < children->length); +} + +// Inserts a node at the specified InsertionLocation, updating the +// "parent" and "index_within_parent" fields of it and all its siblings. +// If the index of the location is -1, this calls append_node. +static void insert_node( + GumboParser* parser, GumboNode* node, InsertionLocation location) { + assert(node->parent == NULL); + assert(node->index_within_parent == -1); + GumboNode* parent = location.target; + int index = location.index; + if (index != -1) { + GumboVector* children = NULL; + if (parent->type == GUMBO_NODE_ELEMENT || + parent->type == GUMBO_NODE_TEMPLATE) { + children = &parent->v.element.children; + } else if (parent->type == GUMBO_NODE_DOCUMENT) { + children = &parent->v.document.children; + assert(children->length == 0); + } else { + assert(0); + } + + assert(index >= 0); + assert((unsigned int) index < children->length); + node->parent = parent; + node->index_within_parent = index; + gumbo_vector_insert_at(parser, (void*) node, index, children); + assert(node->index_within_parent < children->length); + for (unsigned int i = index + 1; i < children->length; ++i) { + GumboNode* sibling = children->data[i]; + sibling->index_within_parent = i; + assert(sibling->index_within_parent < children->length); + } + } else { + append_node(parser, parent, node); + } +} + +static void maybe_flush_text_node_buffer(GumboParser* parser) { + GumboParserState* state = parser->_parser_state; + TextNodeBufferState* buffer_state = &state->_text_node; + if (buffer_state->_buffer.length == 0) { + return; + } + + assert(buffer_state->_type == GUMBO_NODE_WHITESPACE || + buffer_state->_type == GUMBO_NODE_TEXT || + buffer_state->_type == GUMBO_NODE_CDATA); + GumboNode* text_node = create_node(parser, buffer_state->_type); + GumboText* text_node_data = &text_node->v.text; + text_node_data->text = + gumbo_string_buffer_to_string(parser, &buffer_state->_buffer); + text_node_data->original_text.data = buffer_state->_start_original_text; + text_node_data->original_text.length = + state->_current_token->original_text.data - + buffer_state->_start_original_text; + text_node_data->start_pos = buffer_state->_start_position; + + gumbo_debug("Flushing text node buffer of %.*s.\n", + (int) buffer_state->_buffer.length, buffer_state->_buffer.data); + + InsertionLocation location = get_appropriate_insertion_location(parser, NULL); + if (location.target->type == GUMBO_NODE_DOCUMENT) { + // The DOM does not allow Document nodes to have Text children, so per the + // spec, they are dropped on the floor. + destroy_node(parser, text_node); + } else { + insert_node(parser, text_node, location); + } + + gumbo_string_buffer_clear(parser, &buffer_state->_buffer); + buffer_state->_type = GUMBO_NODE_WHITESPACE; + assert(buffer_state->_buffer.length == 0); +} + +static void record_end_of_element( + GumboToken* current_token, GumboElement* element) { + element->end_pos = current_token->position; + element->original_end_tag = current_token->type == GUMBO_TOKEN_END_TAG + ? current_token->original_text + : kGumboEmptyString; +} + +static GumboNode* pop_current_node(GumboParser* parser) { + GumboParserState* state = parser->_parser_state; + maybe_flush_text_node_buffer(parser); + if (state->_open_elements.length > 0) { + assert(node_html_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML)); + gumbo_debug("Popping %s node.\n", + gumbo_normalized_tagname(get_current_node(parser)->v.element.tag)); + } + GumboNode* current_node = gumbo_vector_pop(parser, &state->_open_elements); + if (!current_node) { + assert(state->_open_elements.length == 0); + return NULL; + } + assert(current_node->type == GUMBO_NODE_ELEMENT || + current_node->type == GUMBO_NODE_TEMPLATE); + bool is_closed_body_or_html_tag = + (node_html_tag_is(current_node, GUMBO_TAG_BODY) && + state->_closed_body_tag) || + (node_html_tag_is(current_node, GUMBO_TAG_HTML) && + state->_closed_html_tag); + if ((state->_current_token->type != GUMBO_TOKEN_END_TAG || + !node_html_tag_is(current_node, state->_current_token->v.end_tag)) && + !is_closed_body_or_html_tag) { + current_node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG; + } + if (!is_closed_body_or_html_tag) { + record_end_of_element(state->_current_token, ¤t_node->v.element); + } + return current_node; +} + +static void append_comment_node( + GumboParser* parser, GumboNode* node, const GumboToken* token) { + maybe_flush_text_node_buffer(parser); + GumboNode* comment = create_node(parser, GUMBO_NODE_COMMENT); + comment->type = GUMBO_NODE_COMMENT; + comment->parse_flags = GUMBO_INSERTION_NORMAL; + comment->v.text.text = token->v.text; + comment->v.text.original_text = token->original_text; + comment->v.text.start_pos = token->position; + append_node(parser, node, comment); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-row-context +static void clear_stack_to_table_row_context(GumboParser* parser) { + while (!node_tag_in_set(get_current_node(parser), + (gumbo_tagset){TAG(HTML), TAG(TR), TAG(TEMPLATE)})) { + pop_current_node(parser); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-context +static void clear_stack_to_table_context(GumboParser* parser) { + while (!node_tag_in_set(get_current_node(parser), + (gumbo_tagset){TAG(HTML), TAG(TABLE), TAG(TEMPLATE)})) { + pop_current_node(parser); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#clear-the-stack-back-to-a-table-body-context +void clear_stack_to_table_body_context(GumboParser* parser) { + while (!node_tag_in_set(get_current_node(parser), + (gumbo_tagset){TAG(HTML), TAG(TBODY), TAG(TFOOT), TAG(THEAD), + TAG(TEMPLATE)})) { + pop_current_node(parser); + } +} + +// Creates a parser-inserted element in the HTML namespace and returns it. +static GumboNode* create_element(GumboParser* parser, GumboTag tag) { + GumboNode* node = create_node(parser, GUMBO_NODE_ELEMENT); + GumboElement* element = &node->v.element; + gumbo_vector_init(parser, 1, &element->children); + gumbo_vector_init(parser, 0, &element->attributes); + element->tag = tag; + element->tag_namespace = GUMBO_NAMESPACE_HTML; + element->original_tag = kGumboEmptyString; + element->original_end_tag = kGumboEmptyString; + element->start_pos = (parser->_parser_state->_current_token) + ? parser->_parser_state->_current_token->position + : kGumboEmptySourcePosition; + element->end_pos = kGumboEmptySourcePosition; + return node; +} + +// Constructs an element from the given start tag token. +static GumboNode* create_element_from_token( + GumboParser* parser, GumboToken* token, GumboNamespaceEnum tag_namespace) { + assert(token->type == GUMBO_TOKEN_START_TAG); + GumboTokenStartTag* start_tag = &token->v.start_tag; + + GumboNodeType type = (tag_namespace == GUMBO_NAMESPACE_HTML && + start_tag->tag == GUMBO_TAG_TEMPLATE) + ? GUMBO_NODE_TEMPLATE + : GUMBO_NODE_ELEMENT; + + GumboNode* node = create_node(parser, type); + GumboElement* element = &node->v.element; + gumbo_vector_init(parser, 1, &element->children); + element->attributes = start_tag->attributes; + element->tag = start_tag->tag; + element->tag_namespace = tag_namespace; + + assert(token->original_text.length >= 2); + assert(token->original_text.data[0] == '<'); + assert(token->original_text.data[token->original_text.length - 1] == '>'); + element->original_tag = token->original_text; + element->start_pos = token->position; + element->original_end_tag = kGumboEmptyString; + element->end_pos = kGumboEmptySourcePosition; + + // The element takes ownership of the attributes from the token, so any + // allocated-memory fields should be nulled out. + start_tag->attributes = kGumboEmptyVector; + return node; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#insert-an-html-element +static void insert_element(GumboParser* parser, GumboNode* node, + bool is_reconstructing_formatting_elements) { + GumboParserState* state = parser->_parser_state; + // NOTE(jdtang): The text node buffer must always be flushed before inserting + // a node, otherwise we're handling nodes in a different order than the spec + // mandated. However, one clause of the spec (character tokens in the body) + // requires that we reconstruct the active formatting elements *before* adding + // the character, and reconstructing the active formatting elements may itself + // result in the insertion of new elements (which should be pushed onto the + // stack of open elements before the buffer is flushed). We solve this (for + // the time being, the spec has been rewritten for <template> and the new + // version may be simpler here) with a boolean flag to this method. + if (!is_reconstructing_formatting_elements) { + maybe_flush_text_node_buffer(parser); + } + InsertionLocation location = get_appropriate_insertion_location(parser, NULL); + insert_node(parser, node, location); + gumbo_vector_add(parser, (void*) node, &state->_open_elements); +} + +// Convenience method that combines create_element_from_token and +// insert_element, inserting the generated element directly into the current +// node. Returns the node inserted. +static GumboNode* insert_element_from_token( + GumboParser* parser, GumboToken* token) { + GumboNode* element = + create_element_from_token(parser, token, GUMBO_NAMESPACE_HTML); + insert_element(parser, element, false); + gumbo_debug("Inserting <%s> element (@%x) from token.\n", + gumbo_normalized_tagname(element->v.element.tag), element); + return element; +} + +// Convenience method that combines create_element and insert_element, inserting +// a parser-generated element of a specific tag type. Returns the node +// inserted. +static GumboNode* insert_element_of_tag_type( + GumboParser* parser, GumboTag tag, GumboParseFlags reason) { + GumboNode* element = create_element(parser, tag); + element->parse_flags |= GUMBO_INSERTION_BY_PARSER | reason; + insert_element(parser, element, false); + gumbo_debug("Inserting %s element (@%x) from tag type.\n", + gumbo_normalized_tagname(tag), element); + return element; +} + +// Convenience method for creating foreign namespaced element. Returns the node +// inserted. +static GumboNode* insert_foreign_element( + GumboParser* parser, GumboToken* token, GumboNamespaceEnum tag_namespace) { + assert(token->type == GUMBO_TOKEN_START_TAG); + GumboNode* element = create_element_from_token(parser, token, tag_namespace); + insert_element(parser, element, false); + if (token_has_attribute(token, "xmlns") && + !attribute_matches_case_sensitive(&token->v.start_tag.attributes, "xmlns", + kLegalXmlns[tag_namespace])) { + // TODO(jdtang): Since there're multiple possible error codes here, we + // eventually need reason codes to differentiate them. + parser_add_parse_error(parser, token); + } + if (token_has_attribute(token, "xmlns:xlink") && + !attribute_matches_case_sensitive(&token->v.start_tag.attributes, + "xmlns:xlink", "http://www.w3.org/1999/xlink")) { + parser_add_parse_error(parser, token); + } + return element; +} + +static void insert_text_token(GumboParser* parser, GumboToken* token) { + assert(token->type == GUMBO_TOKEN_WHITESPACE || + token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_NULL || token->type == GUMBO_TOKEN_CDATA); + TextNodeBufferState* buffer_state = &parser->_parser_state->_text_node; + if (buffer_state->_buffer.length == 0) { + // Initialize position fields. + buffer_state->_start_original_text = token->original_text.data; + buffer_state->_start_position = token->position; + } + gumbo_string_buffer_append_codepoint( + parser, token->v.character, &buffer_state->_buffer); + if (token->type == GUMBO_TOKEN_CHARACTER) { + buffer_state->_type = GUMBO_NODE_TEXT; + } else if (token->type == GUMBO_TOKEN_CDATA) { + buffer_state->_type = GUMBO_NODE_CDATA; + } + gumbo_debug("Inserting text token '%c'.\n", token->v.character); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#generic-rcdata-element-parsing-algorithm +static void run_generic_parsing_algorithm( + GumboParser* parser, GumboToken* token, GumboTokenizerEnum lexer_state) { + insert_element_from_token(parser, token); + gumbo_tokenizer_set_state(parser, lexer_state); + parser->_parser_state->_original_insertion_mode = + parser->_parser_state->_insertion_mode; + parser->_parser_state->_insertion_mode = GUMBO_INSERTION_MODE_TEXT; +} + +static void acknowledge_self_closing_tag(GumboParser* parser) { + parser->_parser_state->_self_closing_flag_acknowledged = true; +} + +// Returns true if there's an anchor tag in the list of active formatting +// elements, and fills in its index if so. +static bool find_last_anchor_index(GumboParser* parser, int* anchor_index) { + GumboVector* elements = &parser->_parser_state->_active_formatting_elements; + for (int i = elements->length; --i >= 0;) { + GumboNode* node = elements->data[i]; + if (node == &kActiveFormattingScopeMarker) { + return false; + } + if (node_html_tag_is(node, GUMBO_TAG_A)) { + *anchor_index = i; + return true; + } + } + return false; +} + +// Counts the number of open formatting elements in the list of active +// formatting elements (after the last active scope marker) that have a specific +// tag. If this is > 0, then earliest_matching_index will be filled in with the +// index of the first such element. +static int count_formatting_elements_of_tag(GumboParser* parser, + const GumboNode* desired_node, int* earliest_matching_index) { + const GumboElement* desired_element = &desired_node->v.element; + GumboVector* elements = &parser->_parser_state->_active_formatting_elements; + int num_identical_elements = 0; + for (int i = elements->length; --i >= 0;) { + GumboNode* node = elements->data[i]; + if (node == &kActiveFormattingScopeMarker) { + break; + } + assert(node->type == GUMBO_NODE_ELEMENT); + if (node_qualified_tag_is( + node, desired_element->tag_namespace, desired_element->tag) && + all_attributes_match( + &node->v.element.attributes, &desired_element->attributes)) { + num_identical_elements++; + *earliest_matching_index = i; + } + } + return num_identical_elements; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#reconstruct-the-active-formatting-elements +static void add_formatting_element(GumboParser* parser, const GumboNode* node) { + assert(node == &kActiveFormattingScopeMarker || + node->type == GUMBO_NODE_ELEMENT); + GumboVector* elements = &parser->_parser_state->_active_formatting_elements; + if (node == &kActiveFormattingScopeMarker) { + gumbo_debug("Adding a scope marker.\n"); + } else { + gumbo_debug("Adding a formatting element.\n"); + } + + // Hunt for identical elements. + int earliest_identical_element = elements->length; + int num_identical_elements = count_formatting_elements_of_tag( + parser, node, &earliest_identical_element); + + // Noah's Ark clause: if there're at least 3, remove the earliest. + if (num_identical_elements >= 3) { + gumbo_debug("Noah's ark clause: removing element at %d.\n", + earliest_identical_element); + gumbo_vector_remove_at(parser, earliest_identical_element, elements); + } + + gumbo_vector_add(parser, (void*) node, elements); +} + +static bool is_open_element(GumboParser* parser, const GumboNode* node) { + GumboVector* open_elements = &parser->_parser_state->_open_elements; + for (unsigned int i = 0; i < open_elements->length; ++i) { + if (open_elements->data[i] == node) { + return true; + } + } + return false; +} + +// Clones attributes, tags, etc. of a node, but does not copy the content. The +// clone shares no structure with the original node: all owned strings and +// values are fresh copies. +GumboNode* clone_node( + GumboParser* parser, GumboNode* node, GumboParseFlags reason) { + assert(node->type == GUMBO_NODE_ELEMENT || node->type == GUMBO_NODE_TEMPLATE); + GumboNode* new_node = gumbo_parser_allocate(parser, sizeof(GumboNode)); + *new_node = *node; + new_node->parent = NULL; + new_node->index_within_parent = -1; + // Clear the GUMBO_INSERTION_IMPLICIT_END_TAG flag, as the cloned node may + // have a separate end tag. + new_node->parse_flags &= ~GUMBO_INSERTION_IMPLICIT_END_TAG; + new_node->parse_flags |= reason | GUMBO_INSERTION_BY_PARSER; + GumboElement* element = &new_node->v.element; + gumbo_vector_init(parser, 1, &element->children); + + const GumboVector* old_attributes = &node->v.element.attributes; + gumbo_vector_init(parser, old_attributes->length, &element->attributes); + for (unsigned int i = 0; i < old_attributes->length; ++i) { + const GumboAttribute* old_attr = old_attributes->data[i]; + GumboAttribute* attr = + gumbo_parser_allocate(parser, sizeof(GumboAttribute)); + *attr = *old_attr; + attr->name = gumbo_copy_stringz(parser, old_attr->name); + attr->value = gumbo_copy_stringz(parser, old_attr->value); + gumbo_vector_add(parser, attr, &element->attributes); + } + return new_node; +} + +// "Reconstruct active formatting elements" part of the spec. +// This implementation is based on the html5lib translation from the mess of +// GOTOs in the spec to reasonably structured programming. +// http://code.google.com/p/html5lib/source/browse/python/html5lib/treebuilders/_base.py +static void reconstruct_active_formatting_elements(GumboParser* parser) { + GumboVector* elements = &parser->_parser_state->_active_formatting_elements; + // Step 1 + if (elements->length == 0) { + return; + } + + // Step 2 & 3 + unsigned int i = elements->length - 1; + GumboNode* element = elements->data[i]; + if (element == &kActiveFormattingScopeMarker || + is_open_element(parser, element)) { + return; + } + + // Step 6 + do { + if (i == 0) { + // Step 4 + i = -1; // Incremented to 0 below. + break; + } + // Step 5 + element = elements->data[--i]; + } while (element != &kActiveFormattingScopeMarker && + !is_open_element(parser, element)); + + ++i; + gumbo_debug("Reconstructing elements from %d on %s parent.\n", i, + gumbo_normalized_tagname(get_current_node(parser)->v.element.tag)); + for (; i < elements->length; ++i) { + // Step 7 & 8. + assert(elements->length > 0); + assert(i < elements->length); + element = elements->data[i]; + assert(element != &kActiveFormattingScopeMarker); + GumboNode* clone = clone_node( + parser, element, GUMBO_INSERTION_RECONSTRUCTED_FORMATTING_ELEMENT); + // Step 9. + InsertionLocation location = + get_appropriate_insertion_location(parser, NULL); + insert_node(parser, clone, location); + gumbo_vector_add( + parser, (void*) clone, &parser->_parser_state->_open_elements); + + // Step 10. + elements->data[i] = clone; + gumbo_debug("Reconstructed %s element at %d.\n", + gumbo_normalized_tagname(clone->v.element.tag), i); + } +} + +static void clear_active_formatting_elements(GumboParser* parser) { + GumboVector* elements = &parser->_parser_state->_active_formatting_elements; + int num_elements_cleared = 0; + const GumboNode* node; + do { + node = gumbo_vector_pop(parser, elements); + ++num_elements_cleared; + } while (node && node != &kActiveFormattingScopeMarker); + gumbo_debug("Cleared %d elements from active formatting list.\n", + num_elements_cleared); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-initial-insertion-mode +static GumboQuirksModeEnum compute_quirks_mode( + const GumboTokenDocType* doctype) { + if (doctype->force_quirks || strcmp(doctype->name, kDoctypeHtml.data) || + is_in_static_list( + doctype->public_identifier, kQuirksModePublicIdPrefixes, false) || + is_in_static_list( + doctype->public_identifier, kQuirksModePublicIdExactMatches, true) || + is_in_static_list( + doctype->system_identifier, kQuirksModeSystemIdExactMatches, true) || + (is_in_static_list(doctype->public_identifier, + kLimitedQuirksRequiresSystemIdPublicIdPrefixes, false) && + !doctype->has_system_identifier)) { + return GUMBO_DOCTYPE_QUIRKS; + } else if (is_in_static_list(doctype->public_identifier, + kLimitedQuirksPublicIdPrefixes, false) || + (is_in_static_list(doctype->public_identifier, + kLimitedQuirksRequiresSystemIdPublicIdPrefixes, false) && + doctype->has_system_identifier)) { + return GUMBO_DOCTYPE_LIMITED_QUIRKS; + } + return GUMBO_DOCTYPE_NO_QUIRKS; +} + +// The following functions are all defined by the "has an element in __ scope" +// sections of the HTML5 spec: +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-the-specific-scope +// The basic idea behind them is that they check for an element of the given +// qualified name, contained within a scope formed by a set of other qualified +// names. For example, "has an element in list scope" looks for an element of +// the given qualified name within the nearest enclosing <ol> or <ul>, along +// with a bunch of generic element types that serve to "firewall" their content +// from the rest of the document. Note that because of the way the spec is +// written, +// all elements are expected to be in the HTML namespace +static bool has_an_element_in_specific_scope(GumboParser* parser, + int expected_size, const GumboTag* expected, bool negate, + const gumbo_tagset tags) { + GumboVector* open_elements = &parser->_parser_state->_open_elements; + for (int i = open_elements->length; --i >= 0;) { + const GumboNode* node = open_elements->data[i]; + if (node->type != GUMBO_NODE_ELEMENT && node->type != GUMBO_NODE_TEMPLATE) + continue; + + GumboTag node_tag = node->v.element.tag; + GumboNamespaceEnum node_ns = node->v.element.tag_namespace; + for (int j = 0; j < expected_size; ++j) { + if (node_tag == expected[j] && node_ns == GUMBO_NAMESPACE_HTML) + return true; + } + + bool found = TAGSET_INCLUDES(tags, node_ns, node_tag); + if (negate != found) return false; + } + return false; +} + +// Checks for the presence of an open element of the specified tag type. +static bool has_open_element(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope( + parser, 1, &tag, false, (gumbo_tagset){TAG(HTML)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-scope +static bool has_an_element_in_scope(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope(parser, 1, &tag, false, + (gumbo_tagset){TAG(APPLET), TAG(CAPTION), TAG(HTML), TAG(TABLE), TAG(TD), + TAG(TH), TAG(MARQUEE), TAG(OBJECT), TAG(TEMPLATE), TAG_MATHML(MI), + TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), TAG_MATHML(MTEXT), + TAG_MATHML(ANNOTATION_XML), TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC), + TAG_SVG(TITLE)}); +} + +// Like "has an element in scope", but for the specific case of looking for a +// unique target node, not for any node with a given tag name. This duplicates +// much of the algorithm from has_an_element_in_specific_scope because the +// predicate is different when checking for an exact node, and it's easier & +// faster just to duplicate the code for this one case than to try and +// parameterize it. +static bool has_node_in_scope(GumboParser* parser, const GumboNode* node) { + GumboVector* open_elements = &parser->_parser_state->_open_elements; + for (int i = open_elements->length; --i >= 0;) { + const GumboNode* current = open_elements->data[i]; + if (current == node) { + return true; + } + if (current->type != GUMBO_NODE_ELEMENT && + current->type != GUMBO_NODE_TEMPLATE) { + continue; + } + if (node_tag_in_set(current, + (gumbo_tagset){TAG(APPLET), TAG(CAPTION), TAG(HTML), TAG(TABLE), + TAG(TD), TAG(TH), TAG(MARQUEE), TAG(OBJECT), TAG(TEMPLATE), + TAG_MATHML(MI), TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), + TAG_MATHML(MTEXT), TAG_MATHML(ANNOTATION_XML), + TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC), TAG_SVG(TITLE)})) { + return false; + } + } + assert(false); + return false; +} + +// Like has_an_element_in_scope, but restricts the expected qualified name to a +// range of possible qualified names instead of just a single one. +static bool has_an_element_in_scope_with_tagname( + GumboParser* parser, int expected_len, const GumboTag expected[]) { + return has_an_element_in_specific_scope(parser, expected_len, expected, false, + (gumbo_tagset){TAG(APPLET), TAG(CAPTION), TAG(HTML), TAG(TABLE), TAG(TD), + TAG(TH), TAG(MARQUEE), TAG(OBJECT), TAG(TEMPLATE), TAG_MATHML(MI), + TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), TAG_MATHML(MTEXT), + TAG_MATHML(ANNOTATION_XML), TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC), + TAG_SVG(TITLE)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-list-item-scope +static bool has_an_element_in_list_scope(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope(parser, 1, &tag, false, + (gumbo_tagset){TAG(APPLET), TAG(CAPTION), TAG(HTML), TAG(TABLE), TAG(TD), + TAG(TH), TAG(MARQUEE), TAG(OBJECT), TAG(TEMPLATE), TAG_MATHML(MI), + TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), TAG_MATHML(MTEXT), + TAG_MATHML(ANNOTATION_XML), TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC), + TAG_SVG(TITLE), TAG(OL), TAG(UL)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-button-scope +static bool has_an_element_in_button_scope(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope(parser, 1, &tag, false, + (gumbo_tagset){TAG(APPLET), TAG(CAPTION), TAG(HTML), TAG(TABLE), TAG(TD), + TAG(TH), TAG(MARQUEE), TAG(OBJECT), TAG(TEMPLATE), TAG_MATHML(MI), + TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), TAG_MATHML(MTEXT), + TAG_MATHML(ANNOTATION_XML), TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC), + TAG_SVG(TITLE), TAG(BUTTON)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-table-scope +static bool has_an_element_in_table_scope(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope(parser, 1, &tag, false, + (gumbo_tagset){TAG(HTML), TAG(TABLE), TAG(TEMPLATE)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#has-an-element-in-select-scope +static bool has_an_element_in_select_scope(GumboParser* parser, GumboTag tag) { + return has_an_element_in_specific_scope( + parser, 1, &tag, true, (gumbo_tagset){TAG(OPTGROUP), TAG(OPTION)}); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#generate-implied-end-tags +// "exception" is the "element to exclude from the process" listed in the spec. +// Pass GUMBO_TAG_LAST to not exclude any of them. +static void generate_implied_end_tags(GumboParser* parser, GumboTag exception) { + for (; node_tag_in_set(get_current_node(parser), + (gumbo_tagset){TAG(DD), TAG(DT), TAG(LI), TAG(OPTION), + TAG(OPTGROUP), TAG(P), TAG(RP), TAG(RB), TAG(RT), TAG(RTC)}) && + !node_html_tag_is(get_current_node(parser), exception); + pop_current_node(parser)) + ; +} + +// This is the "generate all implied end tags thoroughly" clause of the spec. +// https://html.spec.whatwg.org/multipage/syntax.html#closing-elements-that-have-implied-end-tags +static void generate_all_implied_end_tags_thoroughly(GumboParser* parser) { + for ( + ; node_tag_in_set(get_current_node(parser), + (gumbo_tagset){TAG(CAPTION), TAG(COLGROUP), TAG(DD), TAG(DT), TAG(LI), + TAG(OPTION), TAG(OPTGROUP), TAG(P), TAG(RP), TAG(RT), TAG(RTC), + TAG(TBODY), TAG(TD), TAG(TFOOT), TAG(TH), TAG(HEAD), TAG(TR)}); + pop_current_node(parser)) + ; +} + +// This factors out the clauses relating to "act as if an end tag token with tag +// name "table" had been seen. Returns true if there's a table element in table +// scope which was successfully closed, false if not and the token should be +// ignored. Does not add parse errors; callers should handle that. +static bool close_table(GumboParser* parser) { + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TABLE)) { + return false; + } + + GumboNode* node = pop_current_node(parser); + while (!node_html_tag_is(node, GUMBO_TAG_TABLE)) { + node = pop_current_node(parser); + } + reset_insertion_mode_appropriately(parser); + return true; +} + +// This factors out the clauses relating to "act as if an end tag token with tag +// name `cell_tag` had been seen". +static bool close_table_cell( + GumboParser* parser, const GumboToken* token, GumboTag cell_tag) { + bool result = true; + generate_implied_end_tags(parser, GUMBO_TAG_LAST); + const GumboNode* node = get_current_node(parser); + if (!node_html_tag_is(node, cell_tag)) { + parser_add_parse_error(parser, token); + result = false; + } + do { + node = pop_current_node(parser); + } while (!node_html_tag_is(node, cell_tag)); + + clear_active_formatting_elements(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW); + return result; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#close-the-cell +// This holds the logic to determine whether we should close a <td> or a <th>. +static bool close_current_cell(GumboParser* parser, const GumboToken* token) { + if (has_an_element_in_table_scope(parser, GUMBO_TAG_TD)) { + assert(!has_an_element_in_table_scope(parser, GUMBO_TAG_TH)); + return close_table_cell(parser, token, GUMBO_TAG_TD); + } else { + assert(has_an_element_in_table_scope(parser, GUMBO_TAG_TH)); + return close_table_cell(parser, token, GUMBO_TAG_TH); + } +} + +// This factors out the "act as if an end tag of tag name 'select' had been +// seen" clause of the spec, since it's referenced in several places. It pops +// all nodes from the stack until the current <select> has been closed, then +// resets the insertion mode appropriately. +static void close_current_select(GumboParser* parser) { + GumboNode* node = pop_current_node(parser); + while (!node_html_tag_is(node, GUMBO_TAG_SELECT)) { + node = pop_current_node(parser); + } + reset_insertion_mode_appropriately(parser); +} + +// The list of nodes in the "special" category: +// http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#special +static bool is_special_node(const GumboNode* node) { + assert(node->type == GUMBO_NODE_ELEMENT || node->type == GUMBO_NODE_TEMPLATE); + return node_tag_in_set(node, + (gumbo_tagset){TAG(ADDRESS), TAG(APPLET), TAG(AREA), TAG(ARTICLE), + TAG(ASIDE), TAG(BASE), TAG(BASEFONT), TAG(BGSOUND), TAG(BLOCKQUOTE), + TAG(BODY), TAG(BR), TAG(BUTTON), TAG(CAPTION), TAG(CENTER), TAG(COL), + TAG(COLGROUP), TAG(MENUITEM), TAG(DD), TAG(DETAILS), TAG(DIR), + TAG(DIV), TAG(DL), TAG(DT), TAG(EMBED), TAG(FIELDSET), + TAG(FIGCAPTION), TAG(FIGURE), TAG(FOOTER), TAG(FORM), TAG(FRAME), + TAG(FRAMESET), TAG(H1), TAG(H2), TAG(H3), TAG(H4), TAG(H5), TAG(H6), + TAG(HEAD), TAG(HEADER), TAG(HGROUP), TAG(HR), TAG(HTML), TAG(IFRAME), + TAG(IMG), TAG(INPUT), TAG(ISINDEX), TAG(LI), TAG(LINK), TAG(LISTING), + TAG(MARQUEE), TAG(MENU), TAG(META), TAG(NAV), TAG(NOEMBED), + TAG(NOFRAMES), TAG(NOSCRIPT), TAG(OBJECT), TAG(OL), TAG(P), + TAG(PARAM), TAG(PLAINTEXT), TAG(PRE), TAG(SCRIPT), TAG(SECTION), + TAG(SELECT), TAG(STYLE), TAG(SUMMARY), TAG(TABLE), TAG(TBODY), + TAG(TD), TAG(TEMPLATE), TAG(TEXTAREA), TAG(TFOOT), TAG(TH), + TAG(THEAD), TAG(TITLE), TAG(TR), TAG(UL), TAG(WBR), TAG(XMP), + + TAG_MATHML(MI), TAG_MATHML(MO), TAG_MATHML(MN), TAG_MATHML(MS), + TAG_MATHML(MTEXT), TAG_MATHML(ANNOTATION_XML), + + TAG_SVG(FOREIGNOBJECT), TAG_SVG(DESC)}); +} + +// Implicitly closes currently open elements until it reaches an element with +// the +// specified qualified name. If the elements closed are in the set handled by +// generate_implied_end_tags, this is normal operation and this function returns +// true. Otherwise, a parse error is recorded and this function returns false. +static bool implicitly_close_tags(GumboParser* parser, GumboToken* token, + GumboNamespaceEnum target_ns, GumboTag target) { + bool result = true; + generate_implied_end_tags(parser, target); + if (!node_qualified_tag_is(get_current_node(parser), target_ns, target)) { + parser_add_parse_error(parser, token); + while ( + !node_qualified_tag_is(get_current_node(parser), target_ns, target)) { + pop_current_node(parser); + } + result = false; + } + assert(node_qualified_tag_is(get_current_node(parser), target_ns, target)); + pop_current_node(parser); + return result; +} + +// If the stack of open elements has a <p> tag in button scope, this acts as if +// a </p> tag was encountered, implicitly closing tags. Returns false if a +// parse error occurs. This is a convenience function because this particular +// clause appears several times in the spec. +static bool maybe_implicitly_close_p_tag( + GumboParser* parser, GumboToken* token) { + if (has_an_element_in_button_scope(parser, GUMBO_TAG_P)) { + return implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, GUMBO_TAG_P); + } + return true; +} + +// Convenience function to encapsulate the logic for closing <li> or <dd>/<dt> +// tags. Pass true to is_li for handling <li> tags, false for <dd> and <dt>. +static void maybe_implicitly_close_list_tag( + GumboParser* parser, GumboToken* token, bool is_li) { + GumboParserState* state = parser->_parser_state; + state->_frameset_ok = false; + for (int i = state->_open_elements.length; --i >= 0;) { + const GumboNode* node = state->_open_elements.data[i]; + bool is_list_tag = + is_li ? node_html_tag_is(node, GUMBO_TAG_LI) + : node_tag_in_set(node, (gumbo_tagset){TAG(DD), TAG(DT)}); + if (is_list_tag) { + implicitly_close_tags( + parser, token, node->v.element.tag_namespace, node->v.element.tag); + return; + } + if (is_special_node(node) && + !node_tag_in_set( + node, (gumbo_tagset){TAG(ADDRESS), TAG(DIV), TAG(P)})) { + return; + } + } +} + +static void merge_attributes( + GumboParser* parser, GumboToken* token, GumboNode* node) { + assert(token->type == GUMBO_TOKEN_START_TAG); + assert(node->type == GUMBO_NODE_ELEMENT); + const GumboVector* token_attr = &token->v.start_tag.attributes; + GumboVector* node_attr = &node->v.element.attributes; + + for (unsigned int i = 0; i < token_attr->length; ++i) { + GumboAttribute* attr = token_attr->data[i]; + if (!gumbo_get_attribute(node_attr, attr->name)) { + // Ownership of the attribute is transferred by this gumbo_vector_add, + // so it has to be nulled out of the original token so it doesn't get + // double-deleted. + gumbo_vector_add(parser, attr, node_attr); + token_attr->data[i] = NULL; + } + } + // When attributes are merged, it means the token has been ignored and merged + // with another token, so we need to free its memory. The attributes that are + // transferred need to be nulled-out in the vector above so that they aren't + // double-deleted. + gumbo_token_destroy(parser, token); + +#ifndef NDEBUG + // Mark this sentinel so the assertion in the main loop knows it's been + // destroyed. + token->v.start_tag.attributes = kGumboEmptyVector; +#endif +} + +const char* gumbo_normalize_svg_tagname(const GumboStringPiece* tag) { + for (size_t i = 0; i < sizeof(kSvgTagReplacements) / sizeof(ReplacementEntry); + ++i) { + const ReplacementEntry* entry = &kSvgTagReplacements[i]; + if (gumbo_string_equals_ignore_case(tag, &entry->from)) { + return entry->to.data; + } + } + return NULL; +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adjust-foreign-attributes +// This destructively modifies any matching attributes on the token and sets the +// namespace appropriately. +static void adjust_foreign_attributes(GumboParser* parser, GumboToken* token) { + assert(token->type == GUMBO_TOKEN_START_TAG); + const GumboVector* attributes = &token->v.start_tag.attributes; + for (size_t i = 0; i < sizeof(kForeignAttributeReplacements) / + sizeof(NamespacedAttributeReplacement); + ++i) { + const NamespacedAttributeReplacement* entry = + &kForeignAttributeReplacements[i]; + GumboAttribute* attr = gumbo_get_attribute(attributes, entry->from); + if (!attr) { + continue; + } + gumbo_parser_deallocate(parser, (void*) attr->name); + attr->attr_namespace = entry->attr_namespace; + attr->name = gumbo_copy_stringz(parser, entry->local_name); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#adjust-svg-attributes +// This destructively modifies any matching attributes on the token. +static void adjust_svg_attributes(GumboParser* parser, GumboToken* token) { + assert(token->type == GUMBO_TOKEN_START_TAG); + const GumboVector* attributes = &token->v.start_tag.attributes; + for (size_t i = 0; + i < sizeof(kSvgAttributeReplacements) / sizeof(ReplacementEntry); ++i) { + const ReplacementEntry* entry = &kSvgAttributeReplacements[i]; + GumboAttribute* attr = gumbo_get_attribute(attributes, entry->from.data); + if (!attr) { + continue; + } + gumbo_parser_deallocate(parser, (void*) attr->name); + attr->name = gumbo_copy_stringz(parser, entry->to.data); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#adjust-mathml-attributes +// Note that this may destructively modify the token with the new attribute +// value. +static void adjust_mathml_attributes(GumboParser* parser, GumboToken* token) { + assert(token->type == GUMBO_TOKEN_START_TAG); + GumboAttribute* attr = + gumbo_get_attribute(&token->v.start_tag.attributes, "definitionurl"); + if (!attr) { + return; + } + gumbo_parser_deallocate(parser, (void*) attr->name); + attr->name = gumbo_copy_stringz(parser, "definitionURL"); +} + +static bool doctype_matches(const GumboTokenDocType* doctype, + const GumboStringPiece* public_id, const GumboStringPiece* system_id, + bool allow_missing_system_id) { + return !strcmp(doctype->public_identifier, public_id->data) && + (allow_missing_system_id || doctype->has_system_identifier) && + !strcmp(doctype->system_identifier, system_id->data); +} + +static bool maybe_add_doctype_error( + GumboParser* parser, const GumboToken* token) { + const GumboTokenDocType* doctype = &token->v.doc_type; + bool html_doctype = !strcmp(doctype->name, kDoctypeHtml.data); + if ((!html_doctype || doctype->has_public_identifier || + (doctype->has_system_identifier && + !strcmp( + doctype->system_identifier, kSystemIdLegacyCompat.data))) && + !(html_doctype && (doctype_matches(doctype, &kPublicIdHtml4_0, + &kSystemIdRecHtml4_0, true) || + doctype_matches(doctype, &kPublicIdHtml4_01, + &kSystemIdHtml4, true) || + doctype_matches(doctype, &kPublicIdXhtml1_0, + &kSystemIdXhtmlStrict1_1, false) || + doctype_matches(doctype, &kPublicIdXhtml1_1, + &kSystemIdXhtml1_1, false)))) { + parser_add_parse_error(parser, token); + return false; + } + return true; +} + +static void remove_from_parent(GumboParser* parser, GumboNode* node) { + if (!node->parent) { + // The node may not have a parent if, for example, it is a newly-cloned copy + // of an active formatting element. DOM manipulations continue with the + // orphaned fragment of the DOM tree until it's appended/foster-parented to + // the common ancestor at the end of the adoption agency algorithm. + return; + } + assert(node->parent->type == GUMBO_NODE_ELEMENT); + GumboVector* children = &node->parent->v.element.children; + int index = gumbo_vector_index_of(children, node); + assert(index != -1); + + gumbo_vector_remove_at(parser, index, children); + node->parent = NULL; + node->index_within_parent = -1; + for (unsigned int i = index; i < children->length; ++i) { + GumboNode* child = children->data[i]; + child->index_within_parent = i; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser +// Also described in the "in body" handling for end formatting tags. +static bool adoption_agency_algorithm( + GumboParser* parser, GumboToken* token, GumboTag subject) { + GumboParserState* state = parser->_parser_state; + gumbo_debug("Entering adoption agency algorithm.\n"); + // Step 1. + GumboNode* current_node = get_current_node(parser); + if (current_node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML && + current_node->v.element.tag == subject && + gumbo_vector_index_of( + &state->_active_formatting_elements, current_node) == -1) { + pop_current_node(parser); + return false; + } + // Steps 2-4 & 20: + for (unsigned int i = 0; i < 8; ++i) { + // Step 5. + GumboNode* formatting_node = NULL; + int formatting_node_in_open_elements = -1; + for (int j = state->_active_formatting_elements.length; --j >= 0;) { + GumboNode* current_node = state->_active_formatting_elements.data[j]; + if (current_node == &kActiveFormattingScopeMarker) { + gumbo_debug("Broke on scope marker; aborting.\n"); + // Last scope marker; abort the algorithm. + return false; + } + if (node_html_tag_is(current_node, subject)) { + // Found it. + formatting_node = current_node; + formatting_node_in_open_elements = + gumbo_vector_index_of(&state->_open_elements, formatting_node); + gumbo_debug("Formatting element of tag %s at %d.\n", + gumbo_normalized_tagname(subject), + formatting_node_in_open_elements); + break; + } + } + if (!formatting_node) { + // No matching tag; not a parse error outright, but fall through to the + // "any other end tag" clause (which may potentially add a parse error, + // but not always). + gumbo_debug("No active formatting elements; aborting.\n"); + return false; + } + + // Step 6 + if (formatting_node_in_open_elements == -1) { + gumbo_debug("Formatting node not on stack of open elements.\n"); + parser_add_parse_error(parser, token); + gumbo_vector_remove( + parser, formatting_node, &state->_active_formatting_elements); + return false; + } + + // Step 7 + if (!has_an_element_in_scope(parser, formatting_node->v.element.tag)) { + parser_add_parse_error(parser, token); + gumbo_debug("Element not in scope.\n"); + return false; + } + + // Step 8 + if (formatting_node != get_current_node(parser)) { + parser_add_parse_error(parser, token); // But continue onwards. + } + assert(formatting_node); + assert(!node_html_tag_is(formatting_node, GUMBO_TAG_HTML)); + assert(!node_html_tag_is(formatting_node, GUMBO_TAG_BODY)); + + // Step 9 & 10 + GumboNode* furthest_block = NULL; + for (unsigned int j = formatting_node_in_open_elements; + j < state->_open_elements.length; ++j) { + assert(j > 0); + GumboNode* current = state->_open_elements.data[j]; + if (is_special_node(current)) { + // Step 9. + furthest_block = current; + break; + } + } + if (!furthest_block) { + // Step 10. + while (get_current_node(parser) != formatting_node) { + pop_current_node(parser); + } + // And the formatting element itself. + pop_current_node(parser); + gumbo_vector_remove( + parser, formatting_node, &state->_active_formatting_elements); + return false; + } + assert(!node_html_tag_is(furthest_block, GUMBO_TAG_HTML)); + assert(furthest_block); + + // Step 11. + // Elements may be moved and reparented by this algorithm, so + // common_ancestor is not necessarily the same as formatting_node->parent. + GumboNode* common_ancestor = + state->_open_elements.data[gumbo_vector_index_of(&state->_open_elements, + formatting_node) - + 1]; + gumbo_debug("Common ancestor tag = %s, furthest block tag = %s.\n", + gumbo_normalized_tagname(common_ancestor->v.element.tag), + gumbo_normalized_tagname(furthest_block->v.element.tag)); + + // Step 12. + int bookmark = gumbo_vector_index_of( + &state->_active_formatting_elements, formatting_node) + + 1; + gumbo_debug("Bookmark at %d.\n", bookmark); + // Step 13. + GumboNode* node = furthest_block; + GumboNode* last_node = furthest_block; + // Must be stored explicitly, in case node is removed from the stack of open + // elements, to handle step 9.4. + int saved_node_index = gumbo_vector_index_of(&state->_open_elements, node); + assert(saved_node_index > 0); + // Step 13.1. + for (int j = 0;;) { + // Step 13.2. + ++j; + // Step 13.3. + int node_index = gumbo_vector_index_of(&state->_open_elements, node); + gumbo_debug( + "Current index: %d, last index: %d.\n", node_index, saved_node_index); + if (node_index == -1) { + node_index = saved_node_index; + } + saved_node_index = --node_index; + assert(node_index > 0); + assert((unsigned int) node_index < state->_open_elements.capacity); + node = state->_open_elements.data[node_index]; + assert(node->parent); + if (node == formatting_node) { + // Step 13.4. + break; + } + int formatting_index = + gumbo_vector_index_of(&state->_active_formatting_elements, node); + if (j > 3 && formatting_index != -1) { + // Step 13.5. + gumbo_debug("Removing formatting element at %d.\n", formatting_index); + gumbo_vector_remove_at( + parser, formatting_index, &state->_active_formatting_elements); + // Removing the element shifts all indices over by one, so we may need + // to move the bookmark. + if (formatting_index < bookmark) { + --bookmark; + gumbo_debug("Moving bookmark to %d.\n", bookmark); + } + continue; + } + if (formatting_index == -1) { + // Step 13.6. + gumbo_vector_remove_at(parser, node_index, &state->_open_elements); + continue; + } + // Step 13.7. + // "common ancestor as the intended parent" doesn't actually mean insert + // it into the common ancestor; that happens below. + node = clone_node(parser, node, GUMBO_INSERTION_ADOPTION_AGENCY_CLONED); + assert(formatting_index >= 0); + state->_active_formatting_elements.data[formatting_index] = node; + assert(node_index >= 0); + state->_open_elements.data[node_index] = node; + // Step 13.8. + if (last_node == furthest_block) { + bookmark = formatting_index + 1; + gumbo_debug("Bookmark moved to %d.\n", bookmark); + assert((unsigned int) bookmark <= state->_active_formatting_elements.length); + } + // Step 13.9. + last_node->parse_flags |= GUMBO_INSERTION_ADOPTION_AGENCY_MOVED; + remove_from_parent(parser, last_node); + append_node(parser, node, last_node); + // Step 13.10. + last_node = node; + } // Step 13.11. + + // Step 14. + gumbo_debug("Removing %s node from parent ", + gumbo_normalized_tagname(last_node->v.element.tag)); + remove_from_parent(parser, last_node); + last_node->parse_flags |= GUMBO_INSERTION_ADOPTION_AGENCY_MOVED; + InsertionLocation location = + get_appropriate_insertion_location(parser, common_ancestor); + gumbo_debug("and inserting it into %s.\n", + gumbo_normalized_tagname(location.target->v.element.tag)); + insert_node(parser, last_node, location); + + // Step 15. + GumboNode* new_formatting_node = clone_node( + parser, formatting_node, GUMBO_INSERTION_ADOPTION_AGENCY_CLONED); + formatting_node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG; + + // Step 16. Instead of appending nodes one-by-one, we swap the children + // vector of furthest_block with the empty children of new_formatting_node, + // reducing memory traffic and allocations. We still have to reset their + // parent pointers, though. + GumboVector temp = new_formatting_node->v.element.children; + new_formatting_node->v.element.children = + furthest_block->v.element.children; + furthest_block->v.element.children = temp; + + temp = new_formatting_node->v.element.children; + for (unsigned int i = 0; i < temp.length; ++i) { + GumboNode* child = temp.data[i]; + child->parent = new_formatting_node; + } + + // Step 17. + append_node(parser, furthest_block, new_formatting_node); + + // Step 18. + // If the formatting node was before the bookmark, it may shift over all + // indices after it, so we need to explicitly find the index and possibly + // adjust the bookmark. + int formatting_node_index = gumbo_vector_index_of( + &state->_active_formatting_elements, formatting_node); + assert(formatting_node_index != -1); + if (formatting_node_index < bookmark) { + gumbo_debug( + "Formatting node at %d is before bookmark at %d; decrementing.\n", + formatting_node_index, bookmark); + --bookmark; + } + gumbo_vector_remove_at( + parser, formatting_node_index, &state->_active_formatting_elements); + assert(bookmark >= 0); + assert((unsigned int) bookmark <= state->_active_formatting_elements.length); + gumbo_vector_insert_at(parser, new_formatting_node, bookmark, + &state->_active_formatting_elements); + + // Step 19. + gumbo_vector_remove(parser, formatting_node, &state->_open_elements); + int insert_at = + gumbo_vector_index_of(&state->_open_elements, furthest_block) + 1; + assert(insert_at >= 0); + assert((unsigned int) insert_at <= state->_open_elements.length); + gumbo_vector_insert_at( + parser, new_formatting_node, insert_at, &state->_open_elements); + } // Step 20. + return true; +} + +// This is here to clean up memory when the spec says "Ignore current token." +static void ignore_token(GumboParser* parser) { + GumboToken* token = parser->_parser_state->_current_token; + // Ownership of the token's internal buffers are normally transferred to the + // element, but if no element is emitted (as happens in non-verbatim-mode + // when a token is ignored), we need to free it here to prevent a memory + // leak. + gumbo_token_destroy(parser, token); +#ifndef NDEBUG + if (token->type == GUMBO_TOKEN_START_TAG) { + // Mark this sentinel so the assertion in the main loop knows it's been + // destroyed. + token->v.start_tag.attributes = kGumboEmptyVector; + } +#endif +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/the-end.html +static void finish_parsing(GumboParser* parser) { + gumbo_debug("Finishing parsing"); + maybe_flush_text_node_buffer(parser); + GumboParserState* state = parser->_parser_state; + for (GumboNode* node = pop_current_node(parser); node; + node = pop_current_node(parser)) { + if ((node_html_tag_is(node, GUMBO_TAG_BODY) && state->_closed_body_tag) || + (node_html_tag_is(node, GUMBO_TAG_HTML) && state->_closed_html_tag)) { + continue; + } + node->parse_flags |= GUMBO_INSERTION_IMPLICIT_END_TAG; + } + while (pop_current_node(parser)) + ; // Pop them all. +} + +static bool handle_initial(GumboParser* parser, GumboToken* token) { + GumboDocument* document = &get_document_node(parser)->v.document; + if (token->type == GUMBO_TOKEN_WHITESPACE) { + ignore_token(parser); + return true; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_document_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + document->has_doctype = true; + document->name = token->v.doc_type.name; + document->public_identifier = token->v.doc_type.public_identifier; + document->system_identifier = token->v.doc_type.system_identifier; + document->doc_type_quirks_mode = compute_quirks_mode(&token->v.doc_type); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML); + return maybe_add_doctype_error(parser, token); + } + parser_add_parse_error(parser, token); + document->doc_type_quirks_mode = GUMBO_DOCTYPE_QUIRKS; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HTML); + parser->_parser_state->_reprocess_current_token = true; + return true; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-before-html-insertion-mode +static bool handle_before_html(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_document_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_WHITESPACE) { + ignore_token(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + GumboNode* html_node = insert_element_from_token(parser, token); + parser->_output->root = html_node; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD); + return true; + } else if (token->type == GUMBO_TOKEN_END_TAG && + !tag_in(token, false, + (gumbo_tagset){TAG(HEAD), TAG(BODY), TAG(HTML), TAG(BR)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + GumboNode* html_node = insert_element_of_tag_type( + parser, GUMBO_TAG_HTML, GUMBO_INSERTION_IMPLIED); + assert(html_node); + parser->_output->root = html_node; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_BEFORE_HEAD); + parser->_parser_state->_reprocess_current_token = true; + return true; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-before-head-insertion-mode +static bool handle_before_head(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_WHITESPACE) { + ignore_token(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD)) { + GumboNode* node = insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD); + parser->_parser_state->_head_element = node; + return true; + } else if (token->type == GUMBO_TOKEN_END_TAG && + !tag_in(token, false, + (gumbo_tagset){TAG(HEAD), TAG(BODY), TAG(HTML), TAG(BR)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + GumboNode* node = insert_element_of_tag_type( + parser, GUMBO_TAG_HEAD, GUMBO_INSERTION_IMPLIED); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD); + parser->_parser_state->_head_element = node; + parser->_parser_state->_reprocess_current_token = true; + return true; + } +} + +// Forward declarations because of mutual dependencies. +static bool handle_token(GumboParser* parser, GumboToken* token); +static bool handle_in_body(GumboParser* parser, GumboToken* token); + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inhead +static bool handle_in_head(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(BASE), TAG(BASEFONT), TAG(BGSOUND), + TAG(MENUITEM), TAG(LINK)})) { + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_META)) { + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + // NOTE(jdtang): Gumbo handles only UTF-8, so the encoding clause of the + // spec doesn't apply. If clients want to handle meta-tag re-encoding, they + // should specifically look for that string in the document and re-encode it + // before passing to Gumbo. + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TITLE)) { + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA); + return true; + } else if (tag_in( + token, kStartTag, (gumbo_tagset){TAG(NOFRAMES), TAG(STYLE)})) { + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOSCRIPT)) { + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_SCRIPT)) { + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_SCRIPT); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_HEAD)) { + GumboNode* head = pop_current_node(parser); + AVOID_UNUSED_VARIABLE_WARNING(head); + assert(node_html_tag_is(head, GUMBO_TAG_HEAD)); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD); + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(HTML), TAG(BR)})) { + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD); + parser->_parser_state->_reprocess_current_token = true; + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TEMPLATE)) { + insert_element_from_token(parser, token); + add_formatting_element(parser, &kActiveFormattingScopeMarker); + parser->_parser_state->_frameset_ok = false; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TEMPLATE); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TEMPLATE); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + generate_all_implied_end_tags_thoroughly(parser); + bool success = true; + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_TEMPLATE)) { + parser_add_parse_error(parser, token); + success = false; + } + while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_TEMPLATE)) + ; + clear_active_formatting_elements(parser); + pop_template_insertion_mode(parser); + reset_insertion_mode_appropriately(parser); + return success; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD) || + (token->type == GUMBO_TOKEN_END_TAG)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_HEAD); + parser->_parser_state->_reprocess_current_token = true; + return true; + } + return true; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inheadnoscript +static bool handle_in_head_noscript(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kEndTag, GUMBO_TAG_NOSCRIPT)) { + const GumboNode* node = pop_current_node(parser); + assert(node_html_tag_is(node, GUMBO_TAG_NOSCRIPT)); + AVOID_UNUSED_VARIABLE_WARNING(node); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD); + return true; + } else if (token->type == GUMBO_TOKEN_WHITESPACE || + token->type == GUMBO_TOKEN_COMMENT || + tag_in(token, kStartTag, + (gumbo_tagset){TAG(BASEFONT), TAG(BGSOUND), TAG(LINK), + TAG(META), TAG(NOFRAMES), TAG(STYLE)})) { + return handle_in_head(parser, token); + } else if (tag_in( + token, kStartTag, (gumbo_tagset){TAG(HEAD), TAG(NOSCRIPT)}) || + (token->type == GUMBO_TOKEN_END_TAG && + !tag_is(token, kEndTag, GUMBO_TAG_BR))) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + parser_add_parse_error(parser, token); + const GumboNode* node = pop_current_node(parser); + assert(node_html_tag_is(node, GUMBO_TAG_NOSCRIPT)); + AVOID_UNUSED_VARIABLE_WARNING(node); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_HEAD); + parser->_parser_state->_reprocess_current_token = true; + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-head-insertion-mode +static bool handle_after_head(GumboParser* parser, GumboToken* token) { + GumboParserState* state = parser->_parser_state; + if (token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) { + insert_element_from_token(parser, token); + state->_frameset_ok = false; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) { + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(BASE), TAG(BASEFONT), TAG(BGSOUND), + TAG(LINK), TAG(META), TAG(NOFRAMES), TAG(SCRIPT), + TAG(STYLE), TAG(TEMPLATE), TAG(TITLE)})) { + parser_add_parse_error(parser, token); + assert(state->_head_element != NULL); + // This must be flushed before we push the head element on, as there may be + // pending character tokens that should be attached to the root. + maybe_flush_text_node_buffer(parser); + gumbo_vector_add(parser, state->_head_element, &state->_open_elements); + bool result = handle_in_head(parser, token); + gumbo_vector_remove(parser, state->_head_element, &state->_open_elements); + return result; + } else if (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + return handle_in_head(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_HEAD) || + (token->type == GUMBO_TOKEN_END_TAG && + !tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(HTML), TAG(BR)}))) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + insert_element_of_tag_type(parser, GUMBO_TAG_BODY, GUMBO_INSERTION_IMPLIED); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + state->_reprocess_current_token = true; + return true; + } +} + +static void destroy_node(GumboParser* parser, GumboNode* node) { + switch (node->type) { + case GUMBO_NODE_DOCUMENT: { + GumboDocument* doc = &node->v.document; + for (unsigned int i = 0; i < doc->children.length; ++i) { + destroy_node(parser, doc->children.data[i]); + } + gumbo_parser_deallocate(parser, (void*) doc->children.data); + gumbo_parser_deallocate(parser, (void*) doc->name); + gumbo_parser_deallocate(parser, (void*) doc->public_identifier); + gumbo_parser_deallocate(parser, (void*) doc->system_identifier); + } break; + case GUMBO_NODE_TEMPLATE: + case GUMBO_NODE_ELEMENT: + for (unsigned int i = 0; i < node->v.element.attributes.length; ++i) { + gumbo_destroy_attribute(parser, node->v.element.attributes.data[i]); + } + gumbo_parser_deallocate(parser, node->v.element.attributes.data); + for (unsigned int i = 0; i < node->v.element.children.length; ++i) { + destroy_node(parser, node->v.element.children.data[i]); + } + gumbo_parser_deallocate(parser, node->v.element.children.data); + break; + case GUMBO_NODE_TEXT: + case GUMBO_NODE_CDATA: + case GUMBO_NODE_COMMENT: + case GUMBO_NODE_WHITESPACE: + gumbo_parser_deallocate(parser, (void*) node->v.text.text); + break; + } + gumbo_parser_deallocate(parser, node); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inbody +static bool handle_in_body(GumboParser* parser, GumboToken* token) { + GumboParserState* state = parser->_parser_state; + assert(state->_open_elements.length > 0); + if (token->type == GUMBO_TOKEN_NULL) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_WHITESPACE) { + reconstruct_active_formatting_elements(parser); + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_CDATA) { + reconstruct_active_formatting_elements(parser); + insert_text_token(parser, token); + set_frameset_not_ok(parser); + return true; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + parser_add_parse_error(parser, token); + if (has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + ignore_token(parser); + return false; + } + assert(parser->_output->root != NULL); + assert(parser->_output->root->type == GUMBO_NODE_ELEMENT); + merge_attributes(parser, token, parser->_output->root); + return false; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(BASE), TAG(BASEFONT), TAG(BGSOUND), + TAG(MENUITEM), TAG(LINK), TAG(META), TAG(NOFRAMES), + TAG(SCRIPT), TAG(STYLE), TAG(TEMPLATE), TAG(TITLE)}) || + tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + return handle_in_head(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_BODY)) { + parser_add_parse_error(parser, token); + if (state->_open_elements.length < 2 || + !node_html_tag_is(state->_open_elements.data[1], GUMBO_TAG_BODY) || + has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + ignore_token(parser); + return false; + } + state->_frameset_ok = false; + merge_attributes(parser, token, state->_open_elements.data[1]); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) { + parser_add_parse_error(parser, token); + if (state->_open_elements.length < 2 || + !node_html_tag_is(state->_open_elements.data[1], GUMBO_TAG_BODY) || + !state->_frameset_ok) { + ignore_token(parser); + return false; + } + // Save the body node for later removal. + GumboNode* body_node = state->_open_elements.data[1]; + + // Pop all nodes except root HTML element. + GumboNode* node; + do { + node = pop_current_node(parser); + } while (node != state->_open_elements.data[1]); + + // Removing & destroying the body node is going to kill any nodes that have + // been added to the list of active formatting elements, and so we should + // clear it to prevent a use-after-free if the list of active formatting + // elements is reconstructed afterwards. This may happen if whitespace + // follows the </frameset>. + clear_active_formatting_elements(parser); + + // Remove the body node. We may want to factor this out into a generic + // helper, but right now this is the only code that needs to do this. + GumboVector* children = &parser->_output->root->v.element.children; + for (unsigned int i = 0; i < children->length; ++i) { + if (children->data[i] == body_node) { + gumbo_vector_remove_at(parser, i, children); + break; + } + } + destroy_node(parser, body_node); + + // Insert the <frameset>, and switch the insertion mode. + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_FRAMESET); + return true; + } else if (token->type == GUMBO_TOKEN_EOF) { + for (unsigned int i = 0; i < state->_open_elements.length; ++i) { + if (!node_tag_in_set(state->_open_elements.data[i], + (gumbo_tagset){TAG(DD), TAG(DT), TAG(LI), TAG(P), TAG(TBODY), + TAG(TD), TAG(TFOOT), TAG(TH), TAG(THEAD), TAG(TR), TAG(BODY), + TAG(HTML)})) { + parser_add_parse_error(parser, token); + } + } + if (get_current_template_insertion_mode(parser) != + GUMBO_INSERTION_MODE_INITIAL) { + return handle_in_template(parser, token); + } + return true; + } else if (tag_in(token, kEndTag, (gumbo_tagset){TAG(BODY), TAG(HTML)})) { + if (!has_an_element_in_scope(parser, GUMBO_TAG_BODY)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + bool success = true; + for (unsigned int i = 0; i < state->_open_elements.length; ++i) { + if (!node_tag_in_set(state->_open_elements.data[i], + (gumbo_tagset){TAG(DD), TAG(DT), TAG(LI), TAG(OPTGROUP), + TAG(OPTION), TAG(P), TAG(RB), TAG(RP), TAG(RT), TAG(RTC), + TAG(TBODY), TAG(TD), TAG(TFOOT), TAG(TH), TAG(THEAD), TAG(TR), + TAG(BODY), TAG(HTML)})) { + parser_add_parse_error(parser, token); + success = false; + break; + } + } + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_BODY); + if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) { + parser->_parser_state->_reprocess_current_token = true; + } else { + GumboNode* body = state->_open_elements.data[1]; + assert(node_html_tag_is(body, GUMBO_TAG_BODY)); + record_end_of_element(state->_current_token, &body->v.element); + } + return success; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(ADDRESS), TAG(ARTICLE), TAG(ASIDE), + TAG(BLOCKQUOTE), TAG(CENTER), TAG(DETAILS), TAG(DIR), + TAG(DIV), TAG(DL), TAG(FIELDSET), TAG(FIGCAPTION), + TAG(FIGURE), TAG(FOOTER), TAG(HEADER), TAG(HGROUP), + TAG(MENU), TAG(MAIN), TAG(NAV), TAG(OL), TAG(P), + TAG(SECTION), TAG(SUMMARY), TAG(UL)})) { + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + return result; + } else if (tag_in(token, kStartTag, (gumbo_tagset){TAG(H1), TAG(H2), TAG(H3), + TAG(H4), TAG(H5), TAG(H6)})) { + bool result = maybe_implicitly_close_p_tag(parser, token); + if (node_tag_in_set( + get_current_node(parser), (gumbo_tagset){TAG(H1), TAG(H2), TAG(H3), + TAG(H4), TAG(H5), TAG(H6)})) { + parser_add_parse_error(parser, token); + pop_current_node(parser); + result = false; + } + insert_element_from_token(parser, token); + return result; + } else if (tag_in(token, kStartTag, (gumbo_tagset){TAG(PRE), TAG(LISTING)})) { + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + state->_ignore_next_linefeed = true; + state->_frameset_ok = false; + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) { + if (state->_form_element != NULL && + !has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + gumbo_debug("Ignoring nested form.\n"); + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + bool result = maybe_implicitly_close_p_tag(parser, token); + GumboNode* form_element = insert_element_from_token(parser, token); + if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + state->_form_element = form_element; + } + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_LI)) { + maybe_implicitly_close_list_tag(parser, token, true); + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + return result; + } else if (tag_in(token, kStartTag, (gumbo_tagset){TAG(DD), TAG(DT)})) { + maybe_implicitly_close_list_tag(parser, token, false); + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_PLAINTEXT)) { + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_PLAINTEXT); + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_BUTTON)) { + if (has_an_element_in_scope(parser, GUMBO_TAG_BUTTON)) { + parser_add_parse_error(parser, token); + implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, GUMBO_TAG_BUTTON); + state->_reprocess_current_token = true; + return false; + } + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + state->_frameset_ok = false; + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(ADDRESS), TAG(ARTICLE), TAG(ASIDE), + TAG(BLOCKQUOTE), TAG(BUTTON), TAG(CENTER), TAG(DETAILS), + TAG(DIR), TAG(DIV), TAG(DL), TAG(FIELDSET), + TAG(FIGCAPTION), TAG(FIGURE), TAG(FOOTER), TAG(HEADER), + TAG(HGROUP), TAG(LISTING), TAG(MAIN), TAG(MENU), TAG(NAV), + TAG(OL), TAG(PRE), TAG(SECTION), TAG(SUMMARY), TAG(UL)})) { + GumboTag tag = token->v.end_tag; + if (!has_an_element_in_scope(parser, tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, token->v.end_tag); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_FORM)) { + if (has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + if (!has_an_element_in_scope(parser, GUMBO_TAG_FORM)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + bool success = true; + generate_implied_end_tags(parser, GUMBO_TAG_LAST); + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_FORM)) { + parser_add_parse_error(parser, token); + return false; + } + while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_FORM)) + ; + return success; + } else { + bool result = true; + const GumboNode* node = state->_form_element; + assert(!node || node->type == GUMBO_NODE_ELEMENT); + state->_form_element = NULL; + if (!node || !has_node_in_scope(parser, node)) { + gumbo_debug("Closing an unopened form.\n"); + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + // This differs from implicitly_close_tags because we remove *only* the + // <form> element; other nodes are left in scope. + generate_implied_end_tags(parser, GUMBO_TAG_LAST); + if (get_current_node(parser) != node) { + parser_add_parse_error(parser, token); + result = false; + } + + GumboVector* open_elements = &state->_open_elements; + int index = gumbo_vector_index_of(open_elements, node); + assert(index >= 0); + gumbo_vector_remove_at(parser, index, open_elements); + return result; + } + } else if (tag_is(token, kEndTag, GUMBO_TAG_P)) { + if (!has_an_element_in_button_scope(parser, GUMBO_TAG_P)) { + parser_add_parse_error(parser, token); + // reconstruct_active_formatting_elements(parser); + insert_element_of_tag_type( + parser, GUMBO_TAG_P, GUMBO_INSERTION_CONVERTED_FROM_END_TAG); + state->_reprocess_current_token = true; + return false; + } + return implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, GUMBO_TAG_P); + } else if (tag_is(token, kEndTag, GUMBO_TAG_LI)) { + if (!has_an_element_in_list_scope(parser, GUMBO_TAG_LI)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + return implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, GUMBO_TAG_LI); + } else if (tag_in(token, kEndTag, (gumbo_tagset){TAG(DD), TAG(DT)})) { + assert(token->type == GUMBO_TOKEN_END_TAG); + GumboTag token_tag = token->v.end_tag; + if (!has_an_element_in_scope(parser, token_tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + return implicitly_close_tags( + parser, token, GUMBO_NAMESPACE_HTML, token_tag); + } else if (tag_in(token, kEndTag, (gumbo_tagset){TAG(H1), TAG(H2), TAG(H3), + TAG(H4), TAG(H5), TAG(H6)})) { + if (!has_an_element_in_scope_with_tagname( + parser, 6, (GumboTag[]){GUMBO_TAG_H1, GUMBO_TAG_H2, GUMBO_TAG_H3, + GUMBO_TAG_H4, GUMBO_TAG_H5, GUMBO_TAG_H6})) { + // No heading open; ignore the token entirely. + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + generate_implied_end_tags(parser, GUMBO_TAG_LAST); + const GumboNode* current_node = get_current_node(parser); + bool success = node_html_tag_is(current_node, token->v.end_tag); + if (!success) { + // There're children of the heading currently open; close them below and + // record a parse error. + // TODO(jdtang): Add a way to distinguish this error case from the one + // above. + parser_add_parse_error(parser, token); + } + do { + current_node = pop_current_node(parser); + } while (!node_tag_in_set( + current_node, (gumbo_tagset){TAG(H1), TAG(H2), TAG(H3), + TAG(H4), TAG(H5), TAG(H6)})); + return success; + } + } else if (tag_is(token, kStartTag, GUMBO_TAG_A)) { + bool success = true; + int last_a; + int has_matching_a = find_last_anchor_index(parser, &last_a); + if (has_matching_a) { + assert(has_matching_a == 1); + parser_add_parse_error(parser, token); + adoption_agency_algorithm(parser, token, GUMBO_TAG_A); + // The adoption agency algorithm usually removes all instances of <a> + // from the list of active formatting elements, but in case it doesn't, + // we're supposed to do this. (The conditions where it might not are + // listed in the spec.) + if (find_last_anchor_index(parser, &last_a)) { + void* last_element = gumbo_vector_remove_at( + parser, last_a, &state->_active_formatting_elements); + gumbo_vector_remove(parser, last_element, &state->_open_elements); + } + success = false; + } + reconstruct_active_formatting_elements(parser); + add_formatting_element(parser, insert_element_from_token(parser, token)); + return success; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(B), TAG(BIG), TAG(CODE), TAG(EM), TAG(FONT), + TAG(I), TAG(S), TAG(SMALL), TAG(STRIKE), TAG(STRONG), + TAG(TT), TAG(U)})) { + reconstruct_active_formatting_elements(parser); + add_formatting_element(parser, insert_element_from_token(parser, token)); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOBR)) { + bool result = true; + reconstruct_active_formatting_elements(parser); + if (has_an_element_in_scope(parser, GUMBO_TAG_NOBR)) { + result = false; + parser_add_parse_error(parser, token); + adoption_agency_algorithm(parser, token, GUMBO_TAG_NOBR); + reconstruct_active_formatting_elements(parser); + } + insert_element_from_token(parser, token); + add_formatting_element(parser, get_current_node(parser)); + return result; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(A), TAG(B), TAG(BIG), TAG(CODE), TAG(EM), + TAG(FONT), TAG(I), TAG(NOBR), TAG(S), TAG(SMALL), + TAG(STRIKE), TAG(STRONG), TAG(TT), TAG(U)})) { + return adoption_agency_algorithm(parser, token, token->v.end_tag); + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(APPLET), TAG(MARQUEE), TAG(OBJECT)})) { + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + add_formatting_element(parser, &kActiveFormattingScopeMarker); + set_frameset_not_ok(parser); + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(APPLET), TAG(MARQUEE), TAG(OBJECT)})) { + GumboTag token_tag = token->v.end_tag; + if (!has_an_element_in_table_scope(parser, token_tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + implicitly_close_tags(parser, token, GUMBO_NAMESPACE_HTML, token_tag); + clear_active_formatting_elements(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) { + if (get_document_node(parser)->v.document.doc_type_quirks_mode != + GUMBO_DOCTYPE_QUIRKS) { + maybe_implicitly_close_p_tag(parser, token); + } + insert_element_from_token(parser, token); + set_frameset_not_ok(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(AREA), TAG(BR), TAG(EMBED), TAG(IMG), + TAG(IMAGE), TAG(KEYGEN), TAG(WBR)})) { + bool success = true; + if (tag_is(token, kStartTag, GUMBO_TAG_IMAGE)) { + success = false; + parser_add_parse_error(parser, token); + token->v.start_tag.tag = GUMBO_TAG_IMG; + } + reconstruct_active_formatting_elements(parser); + GumboNode* node = insert_element_from_token(parser, token); + if (tag_is(token, kStartTag, GUMBO_TAG_IMAGE)) { + success = false; + parser_add_parse_error(parser, token); + node->v.element.tag = GUMBO_TAG_IMG; + node->parse_flags |= GUMBO_INSERTION_FROM_IMAGE; + } + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + set_frameset_not_ok(parser); + return success; + } else if (tag_is(token, kStartTag, GUMBO_TAG_INPUT)) { + if (!attribute_matches(&token->v.start_tag.attributes, "type", "hidden")) { + // Must be before the element is inserted, as that takes ownership of the + // token's attribute vector. + set_frameset_not_ok(parser); + } + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(PARAM), TAG(SOURCE), TAG(TRACK)})) { + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HR)) { + bool result = maybe_implicitly_close_p_tag(parser, token); + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + set_frameset_not_ok(parser); + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_ISINDEX)) { + parser_add_parse_error(parser, token); + if (parser->_parser_state->_form_element != NULL && + !has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + ignore_token(parser); + return false; + } + acknowledge_self_closing_tag(parser); + maybe_implicitly_close_p_tag(parser, token); + set_frameset_not_ok(parser); + + GumboVector* token_attrs = &token->v.start_tag.attributes; + GumboAttribute* prompt_attr = gumbo_get_attribute(token_attrs, "prompt"); + GumboAttribute* action_attr = gumbo_get_attribute(token_attrs, "action"); + GumboAttribute* name_attr = gumbo_get_attribute(token_attrs, "name"); + + GumboNode* form = insert_element_of_tag_type( + parser, GUMBO_TAG_FORM, GUMBO_INSERTION_FROM_ISINDEX); + if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + parser->_parser_state->_form_element = form; + } + if (action_attr) { + gumbo_vector_add(parser, action_attr, &form->v.element.attributes); + } + insert_element_of_tag_type( + parser, GUMBO_TAG_HR, GUMBO_INSERTION_FROM_ISINDEX); + pop_current_node(parser); // <hr> + + insert_element_of_tag_type( + parser, GUMBO_TAG_LABEL, GUMBO_INSERTION_FROM_ISINDEX); + TextNodeBufferState* text_state = &parser->_parser_state->_text_node; + text_state->_start_original_text = token->original_text.data; + text_state->_start_position = token->position; + text_state->_type = GUMBO_NODE_TEXT; + if (prompt_attr) { + size_t prompt_attr_length = strlen(prompt_attr->value); + gumbo_string_buffer_destroy(parser, &text_state->_buffer); + text_state->_buffer.data = gumbo_copy_stringz(parser, prompt_attr->value); + text_state->_buffer.length = prompt_attr_length; + text_state->_buffer.capacity = prompt_attr_length + 1; + gumbo_destroy_attribute(parser, prompt_attr); + } else { + GumboStringPiece prompt_text = + GUMBO_STRING("This is a searchable index. Enter search keywords: "); + gumbo_string_buffer_append_string( + parser, &prompt_text, &text_state->_buffer); + } + + GumboNode* input = insert_element_of_tag_type( + parser, GUMBO_TAG_INPUT, GUMBO_INSERTION_FROM_ISINDEX); + for (unsigned int i = 0; i < token_attrs->length; ++i) { + GumboAttribute* attr = token_attrs->data[i]; + if (attr != prompt_attr && attr != action_attr && attr != name_attr) { + gumbo_vector_add(parser, attr, &input->v.element.attributes); + } + token_attrs->data[i] = NULL; + } + + // All attributes have been successfully transferred and nulled out at this + // point, so the call to ignore_token will free the memory for it without + // touching the attributes. + ignore_token(parser); + + // The name attribute, if present, should be destroyed since it's ignored + // when copying over. The action attribute should be kept since it's moved + // to the form. + if (name_attr) { + gumbo_destroy_attribute(parser, name_attr); + } + + GumboAttribute* name = + gumbo_parser_allocate(parser, sizeof(GumboAttribute)); + GumboStringPiece name_str = GUMBO_STRING("name"); + GumboStringPiece isindex_str = GUMBO_STRING("isindex"); + name->attr_namespace = GUMBO_ATTR_NAMESPACE_NONE; + name->name = gumbo_copy_stringz(parser, "name"); + name->value = gumbo_copy_stringz(parser, "isindex"); + name->original_name = name_str; + name->original_value = isindex_str; + name->name_start = kGumboEmptySourcePosition; + name->name_end = kGumboEmptySourcePosition; + name->value_start = kGumboEmptySourcePosition; + name->value_end = kGumboEmptySourcePosition; + gumbo_vector_add(parser, name, &input->v.element.attributes); + + pop_current_node(parser); // <input> + pop_current_node(parser); // <label> + insert_element_of_tag_type( + parser, GUMBO_TAG_HR, GUMBO_INSERTION_FROM_ISINDEX); + pop_current_node(parser); // <hr> + pop_current_node(parser); // <form> + if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + parser->_parser_state->_form_element = NULL; + } + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TEXTAREA)) { + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RCDATA); + parser->_parser_state->_ignore_next_linefeed = true; + set_frameset_not_ok(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_XMP)) { + bool result = maybe_implicitly_close_p_tag(parser, token); + reconstruct_active_formatting_elements(parser); + set_frameset_not_ok(parser); + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT); + return result; + } else if (tag_is(token, kStartTag, GUMBO_TAG_IFRAME)) { + set_frameset_not_ok(parser); + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOEMBED)) { + run_generic_parsing_algorithm(parser, token, GUMBO_LEX_RAWTEXT); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) { + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + set_frameset_not_ok(parser); + GumboInsertionMode state = parser->_parser_state->_insertion_mode; + if (state == GUMBO_INSERTION_MODE_IN_TABLE || + state == GUMBO_INSERTION_MODE_IN_CAPTION || + state == GUMBO_INSERTION_MODE_IN_TABLE_BODY || + state == GUMBO_INSERTION_MODE_IN_ROW || + state == GUMBO_INSERTION_MODE_IN_CELL) { + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE); + } else { + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_SELECT); + } + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(OPTION), TAG(OPTGROUP)})) { + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) { + pop_current_node(parser); + } + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(RB), TAG(RP), TAG(RT), TAG(RTC)})) { + bool success = true; + GumboTag exception = + tag_in(token, kStartTag, (gumbo_tagset){TAG(RT), TAG(RP)}) + ? GUMBO_TAG_RTC + : GUMBO_TAG_LAST; + if (has_an_element_in_scope(parser, GUMBO_TAG_RUBY)) { + generate_implied_end_tags(parser, exception); + } + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_RUBY) && + !(exception == GUMBO_TAG_LAST || + node_html_tag_is(get_current_node(parser), GUMBO_TAG_RTC))) { + parser_add_parse_error(parser, token); + success = false; + } + insert_element_from_token(parser, token); + return success; + } else if (tag_is(token, kEndTag, GUMBO_TAG_BR)) { + parser_add_parse_error(parser, token); + reconstruct_active_formatting_elements(parser); + insert_element_of_tag_type( + parser, GUMBO_TAG_BR, GUMBO_INSERTION_CONVERTED_FROM_END_TAG); + pop_current_node(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_MATH)) { + reconstruct_active_formatting_elements(parser); + adjust_mathml_attributes(parser, token); + adjust_foreign_attributes(parser, token); + insert_foreign_element(parser, token, GUMBO_NAMESPACE_MATHML); + if (token->v.start_tag.is_self_closing) { + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + } + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_SVG)) { + reconstruct_active_formatting_elements(parser); + adjust_svg_attributes(parser, token); + adjust_foreign_attributes(parser, token); + insert_foreign_element(parser, token, GUMBO_NAMESPACE_SVG); + if (token->v.start_tag.is_self_closing) { + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + } + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(COL), TAG(COLGROUP), + TAG(FRAME), TAG(HEAD), TAG(TBODY), TAG(TD), TAG(TFOOT), + TAG(TH), TAG(THEAD), TAG(TR)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_START_TAG) { + reconstruct_active_formatting_elements(parser); + insert_element_from_token(parser, token); + return true; + } else { + assert(token->type == GUMBO_TOKEN_END_TAG); + GumboTag end_tag = token->v.end_tag; + assert(state->_open_elements.length > 0); + assert(node_html_tag_is(state->_open_elements.data[0], GUMBO_TAG_HTML)); + // Walk up the stack of open elements until we find one that either: + // a) Matches the tag name we saw + // b) Is in the "special" category. + // If we see a), implicitly close everything up to and including it. If we + // see b), then record a parse error, don't close anything (except the + // implied end tags) and ignore the end tag token. + for (int i = state->_open_elements.length; --i >= 0;) { + const GumboNode* node = state->_open_elements.data[i]; + if (node_html_tag_is(node, end_tag)) { + generate_implied_end_tags(parser, end_tag); + // TODO(jdtang): Do I need to add a parse error here? The condition in + // the spec seems like it's the inverse of the loop condition above, and + // so would never fire. + while (node != pop_current_node(parser)) + ; // Pop everything. + return true; + } else if (is_special_node(node)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + } + // <html> is in the special category, so we should never get here. + assert(0); + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incdata +static bool handle_text(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + } else { + // We provide only bare-bones script handling that doesn't involve any of + // the parser-pause/already-started/script-nesting flags or re-entrant + // invocations of the tokenizer. Because the intended usage of this library + // is mostly for templating, refactoring, and static-analysis libraries, we + // provide the script body as a text-node child of the <script> element. + // This behavior doesn't support document.write of partial HTML elements, + // but should be adequate for almost all other scripting support. + if (token->type == GUMBO_TOKEN_EOF) { + parser_add_parse_error(parser, token); + parser->_parser_state->_reprocess_current_token = true; + } + pop_current_node(parser); + set_insertion_mode(parser, parser->_parser_state->_original_insertion_mode); + } + return true; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intable +static bool handle_in_table(GumboParser* parser, GumboToken* token) { + GumboParserState* state = parser->_parser_state; + if (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_WHITESPACE) { + // The "pending table character tokens" list described in the spec is + // nothing more than the TextNodeBufferState. We accumulate text tokens as + // normal, except that when we go to flush them in the handle_in_table_text, + // we set _foster_parent_insertions if there're non-whitespace characters in + // the buffer. + assert(state->_text_node._buffer.length == 0); + state->_original_insertion_mode = state->_insertion_mode; + state->_reprocess_current_token = true; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_TEXT); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_CAPTION)) { + clear_stack_to_table_context(parser); + add_formatting_element(parser, &kActiveFormattingScopeMarker); + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CAPTION); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_COLGROUP)) { + clear_stack_to_table_context(parser); + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_COL)) { + clear_stack_to_table_context(parser); + insert_element_of_tag_type( + parser, GUMBO_TAG_COLGROUP, GUMBO_INSERTION_IMPLIED); + parser->_parser_state->_reprocess_current_token = true; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(TBODY), TAG(TFOOT), TAG(THEAD), TAG(TD), + TAG(TH), TAG(TR)})) { + clear_stack_to_table_context(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + if (tag_in(token, kStartTag, (gumbo_tagset){TAG(TD), TAG(TH), TAG(TR)})) { + insert_element_of_tag_type( + parser, GUMBO_TAG_TBODY, GUMBO_INSERTION_IMPLIED); + state->_reprocess_current_token = true; + } else { + insert_element_from_token(parser, token); + } + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TABLE)) { + parser_add_parse_error(parser, token); + if (close_table(parser)) { + parser->_parser_state->_reprocess_current_token = true; + } else { + ignore_token(parser); + } + return false; + } else if (tag_is(token, kEndTag, GUMBO_TAG_TABLE)) { + if (!close_table(parser)) { + parser_add_parse_error(parser, token); + return false; + } + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(CAPTION), TAG(COL), + TAG(COLGROUP), TAG(HTML), TAG(TBODY), TAG(TD), TAG(TFOOT), + TAG(TH), TAG(THEAD), TAG(TR)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(STYLE), TAG(SCRIPT), TAG(TEMPLATE)}) || + (tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE))) { + return handle_in_head(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_INPUT) && + attribute_matches( + &token->v.start_tag.attributes, "type", "hidden")) { + parser_add_parse_error(parser, token); + insert_element_from_token(parser, token); + pop_current_node(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_FORM)) { + parser_add_parse_error(parser, token); + if (state->_form_element || has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + ignore_token(parser); + return false; + } + state->_form_element = insert_element_from_token(parser, token); + pop_current_node(parser); + return false; + } else if (token->type == GUMBO_TOKEN_EOF) { + return handle_in_body(parser, token); + } else { + parser_add_parse_error(parser, token); + state->_foster_parent_insertions = true; + bool result = handle_in_body(parser, token); + state->_foster_parent_insertions = false; + return result; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intabletext +static bool handle_in_table_text(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_NULL) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else { + GumboParserState* state = parser->_parser_state; + GumboStringBuffer* buffer = &state->_text_node._buffer; + // Can't use strspn for this because GumboStringBuffers are not + // null-terminated. + // Note that TextNodeBuffer may contain UTF-8 characters, but the presence + // of any one byte that is not whitespace means we flip the flag, so this + // loop is still valid. + for (unsigned int i = 0; i < buffer->length; ++i) { + if (!isspace((unsigned char) buffer->data[i]) || + buffer->data[i] == '\v') { + state->_foster_parent_insertions = true; + reconstruct_active_formatting_elements(parser); + break; + } + } + maybe_flush_text_node_buffer(parser); + state->_foster_parent_insertions = false; + state->_reprocess_current_token = true; + state->_insertion_mode = state->_original_insertion_mode; + return true; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incaption +static bool handle_in_caption(GumboParser* parser, GumboToken* token) { + if (tag_is(token, kEndTag, GUMBO_TAG_CAPTION)) { + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_CAPTION)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + generate_implied_end_tags(parser, GUMBO_TAG_LAST); + bool result = true; + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_CAPTION)) { + parser_add_parse_error(parser, token); + } + while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_CAPTION)) + ; + clear_active_formatting_elements(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + return result; + } + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(COL), TAG(COLGROUP), + TAG(TBODY), TAG(TD), TAG(TFOOT), TAG(TH), TAG(THEAD), + TAG(TR)}) || + (tag_is(token, kEndTag, GUMBO_TAG_TABLE))) { + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_CAPTION)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_CAPTION)) + ; + clear_active_formatting_elements(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + parser->_parser_state->_reprocess_current_token = true; + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(COL), TAG(COLGROUP), TAG(HTML), + TAG(TBODY), TAG(TD), TAG(TFOOT), TAG(TH), TAG(THEAD), + TAG(TR)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + return handle_in_body(parser, token); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-incolgroup +static bool handle_in_column_group(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_COL)) { + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_COLGROUP)) { + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_COLGROUP)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + return false; + } else if (tag_is(token, kEndTag, GUMBO_TAG_COL)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TEMPLATE) || + tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + return handle_in_head(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + return handle_in_body(parser, token); + } else { + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_COLGROUP)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + parser->_parser_state->_reprocess_current_token = true; + return true; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intbody +static bool handle_in_table_body(GumboParser* parser, GumboToken* token) { + if (tag_is(token, kStartTag, GUMBO_TAG_TR)) { + clear_stack_to_table_body_context(parser); + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW); + return true; + } else if (tag_in(token, kStartTag, (gumbo_tagset){TAG(TD), TAG(TH)})) { + parser_add_parse_error(parser, token); + clear_stack_to_table_body_context(parser); + insert_element_of_tag_type(parser, GUMBO_TAG_TR, GUMBO_INSERTION_IMPLIED); + parser->_parser_state->_reprocess_current_token = true; + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW); + return false; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(TBODY), TAG(TFOOT), TAG(THEAD)})) { + if (!has_an_element_in_table_scope(parser, token->v.end_tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + clear_stack_to_table_body_context(parser); + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + return true; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(COL), TAG(COLGROUP), + TAG(TBODY), TAG(TFOOT), TAG(THEAD)}) || + tag_is(token, kEndTag, GUMBO_TAG_TABLE)) { + if (!(has_an_element_in_table_scope(parser, GUMBO_TAG_TBODY) || + has_an_element_in_table_scope(parser, GUMBO_TAG_THEAD) || + has_an_element_in_table_scope(parser, GUMBO_TAG_TFOOT))) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + clear_stack_to_table_body_context(parser); + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + parser->_parser_state->_reprocess_current_token = true; + return true; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(CAPTION), TAG(COL), TAG(TR), + TAG(COLGROUP), TAG(HTML), TAG(TD), TAG(TH)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + return handle_in_table(parser, token); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intr +static bool handle_in_row(GumboParser* parser, GumboToken* token) { + if (tag_in(token, kStartTag, (gumbo_tagset){TAG(TH), TAG(TD)})) { + clear_stack_to_table_row_context(parser); + insert_element_from_token(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_CELL); + add_formatting_element(parser, &kActiveFormattingScopeMarker); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_TR)) { + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + clear_stack_to_table_row_context(parser); + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + return true; + } + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(COL), TAG(COLGROUP), + TAG(TBODY), TAG(TFOOT), TAG(THEAD), TAG(TR)}) || + tag_is(token, kEndTag, GUMBO_TAG_TABLE)) { + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + clear_stack_to_table_row_context(parser); + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + parser->_parser_state->_reprocess_current_token = true; + return true; + } + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(TBODY), TAG(TFOOT), TAG(THEAD)})) { + if (!has_an_element_in_table_scope(parser, token->v.end_tag) || + (!has_an_element_in_table_scope(parser, GUMBO_TAG_TR))) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + clear_stack_to_table_row_context(parser); + pop_current_node(parser); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + parser->_parser_state->_reprocess_current_token = true; + return true; + } + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(BODY), TAG(CAPTION), TAG(COL), + TAG(COLGROUP), TAG(HTML), TAG(TD), TAG(TH)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else { + return handle_in_table(parser, token); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-intd +static bool handle_in_cell(GumboParser* parser, GumboToken* token) { + if (tag_in(token, kEndTag, (gumbo_tagset){TAG(TD), TAG(TH)})) { + GumboTag token_tag = token->v.end_tag; + if (!has_an_element_in_table_scope(parser, token_tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + return close_table_cell(parser, token, token_tag); + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(COL), TAG(COLGROUP), + TAG(TBODY), TAG(TD), TAG(TFOOT), TAG(TH), TAG(THEAD), + TAG(TR)})) { + gumbo_debug("Handling <td> in cell.\n"); + if (!has_an_element_in_table_scope(parser, GUMBO_TAG_TH) && + !has_an_element_in_table_scope(parser, GUMBO_TAG_TD)) { + gumbo_debug("Bailing out because there's no <td> or <th> in scope.\n"); + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + parser->_parser_state->_reprocess_current_token = true; + return close_current_cell(parser, token); + } else if (tag_in(token, kEndTag, (gumbo_tagset){TAG(BODY), TAG(CAPTION), + TAG(COL), TAG(COLGROUP), TAG(HTML)})) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_in(token, kEndTag, (gumbo_tagset){TAG(TABLE), TAG(TBODY), + TAG(TFOOT), TAG(THEAD), TAG(TR)})) { + if (!has_an_element_in_table_scope(parser, token->v.end_tag)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + parser->_parser_state->_reprocess_current_token = true; + return close_current_cell(parser, token); + } else { + return handle_in_body(parser, token); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inselect +static bool handle_in_select(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_NULL) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_OPTION)) { + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) { + pop_current_node(parser); + } + insert_element_from_token(parser, token); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_OPTGROUP)) { + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) { + pop_current_node(parser); + } + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTGROUP)) { + pop_current_node(parser); + } + insert_element_from_token(parser, token); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_OPTGROUP)) { + GumboVector* open_elements = &parser->_parser_state->_open_elements; + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION) && + node_html_tag_is(open_elements->data[open_elements->length - 2], + GUMBO_TAG_OPTGROUP)) { + pop_current_node(parser); + } + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTGROUP)) { + pop_current_node(parser); + return true; + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + } else if (tag_is(token, kEndTag, GUMBO_TAG_OPTION)) { + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_OPTION)) { + pop_current_node(parser); + return true; + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + } else if (tag_is(token, kEndTag, GUMBO_TAG_SELECT)) { + if (!has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + close_current_select(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_SELECT)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + if (has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) { + close_current_select(parser); + } + return false; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(INPUT), TAG(KEYGEN), TAG(TEXTAREA)})) { + parser_add_parse_error(parser, token); + if (!has_an_element_in_select_scope(parser, GUMBO_TAG_SELECT)) { + ignore_token(parser); + } else { + close_current_select(parser); + parser->_parser_state->_reprocess_current_token = true; + } + return false; + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(SCRIPT), TAG(TEMPLATE)}) || + tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + return handle_in_head(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + return handle_in_body(parser, token); + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inselectintable +static bool handle_in_select_in_table(GumboParser* parser, GumboToken* token) { + if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(CAPTION), TAG(TABLE), TAG(TBODY), TAG(TFOOT), + TAG(THEAD), TAG(TR), TAG(TD), TAG(TH)})) { + parser_add_parse_error(parser, token); + close_current_select(parser); + parser->_parser_state->_reprocess_current_token = true; + return false; + } else if (tag_in(token, kEndTag, + (gumbo_tagset){TAG(CAPTION), TAG(TABLE), TAG(TBODY), + TAG(TFOOT), TAG(THEAD), TAG(TR), TAG(TD), TAG(TH)})) { + parser_add_parse_error(parser, token); + if (!has_an_element_in_table_scope(parser, token->v.end_tag)) { + ignore_token(parser); + return false; + } else { + close_current_select(parser); + // close_current_select already does the + // reset_insertion_mode_appropriately + // reset_insertion_mode_appropriately(parser); + parser->_parser_state->_reprocess_current_token = true; + return false; + } + } else { + return handle_in_select(parser, token); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-intemplate +static bool handle_in_template(GumboParser* parser, GumboToken* token) { + GumboParserState* state = parser->_parser_state; + if (token->type == GUMBO_TOKEN_WHITESPACE || + token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_COMMENT || token->type == GUMBO_TOKEN_NULL || + token->type == GUMBO_TOKEN_DOCTYPE) { + return handle_in_body(parser, token); + } else if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(BASE), TAG(BASEFONT), TAG(BGSOUND), + TAG(LINK), TAG(META), TAG(NOFRAMES), TAG(SCRIPT), + TAG(STYLE), TAG(TEMPLATE), TAG(TITLE)}) || + tag_is(token, kEndTag, GUMBO_TAG_TEMPLATE)) { + return handle_in_head(parser, token); + } else if (tag_in( + token, kStartTag, (gumbo_tagset){TAG(CAPTION), TAG(COLGROUP), + TAG(TBODY), TAG(TFOOT), TAG(THEAD)})) { + pop_template_insertion_mode(parser); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE); + state->_reprocess_current_token = true; + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_COL)) { + pop_template_insertion_mode(parser); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_COLUMN_GROUP); + state->_reprocess_current_token = true; + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_TR)) { + pop_template_insertion_mode(parser); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TABLE_BODY); + state->_reprocess_current_token = true; + return true; + } else if (tag_in(token, kStartTag, (gumbo_tagset){TAG(TD), TAG(TH)})) { + pop_template_insertion_mode(parser); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_ROW); + state->_reprocess_current_token = true; + return true; + } else if (token->type == GUMBO_TOKEN_START_TAG) { + pop_template_insertion_mode(parser); + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + state->_reprocess_current_token = true; + return true; + } else if (token->type == GUMBO_TOKEN_END_TAG) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (token->type == GUMBO_TOKEN_EOF) { + if (!has_open_element(parser, GUMBO_TAG_TEMPLATE)) { + // Stop parsing. + return true; + } + parser_add_parse_error(parser, token); + while (!node_html_tag_is(pop_current_node(parser), GUMBO_TAG_TEMPLATE)) + ; + clear_active_formatting_elements(parser); + pop_template_insertion_mode(parser); + reset_insertion_mode_appropriately(parser); + state->_reprocess_current_token = true; + return false; + } else { + assert(0); + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-afterbody +static bool handle_after_body(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_WHITESPACE || + tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (token->type == GUMBO_TOKEN_COMMENT) { + GumboNode* html_node = parser->_output->root; + assert(html_node != NULL); + append_comment_node(parser, html_node, token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) { + /* fragment case: ignore the closing HTML token */ + if (is_fragment_parser(parser)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_BODY); + GumboNode* html = parser->_parser_state->_open_elements.data[0]; + assert(node_html_tag_is(html, GUMBO_TAG_HTML)); + record_end_of_element( + parser->_parser_state->_current_token, &html->v.element); + return true; + } else if (token->type == GUMBO_TOKEN_EOF) { + return true; + } else { + parser_add_parse_error(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + parser->_parser_state->_reprocess_current_token = true; + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inframeset +static bool handle_in_frameset(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAMESET)) { + insert_element_from_token(parser, token); + return true; + } else if (tag_is(token, kEndTag, GUMBO_TAG_FRAMESET)) { + if (node_html_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } + pop_current_node(parser); + if (!is_fragment_parser(parser) && + !node_html_tag_is(get_current_node(parser), GUMBO_TAG_FRAMESET)) { + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_FRAMESET); + } + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_FRAME)) { + insert_element_from_token(parser, token); + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) { + return handle_in_head(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + if (!node_html_tag_is(get_current_node(parser), GUMBO_TAG_HTML)) { + parser_add_parse_error(parser, token); + return false; + } + return true; + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-afterframeset +static bool handle_after_frameset(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_WHITESPACE) { + insert_text_token(parser, token); + return true; + } else if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_current_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE) { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } else if (tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) { + GumboNode* html = parser->_parser_state->_open_elements.data[0]; + assert(node_html_tag_is(html, GUMBO_TAG_HTML)); + record_end_of_element( + parser->_parser_state->_current_token, &html->v.element); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET); + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) { + return handle_in_head(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + return true; + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-after-body-insertion-mode +static bool handle_after_after_body(GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_document_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE || + token->type == GUMBO_TOKEN_WHITESPACE || + tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + return true; + } else { + parser_add_parse_error(parser, token); + set_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_BODY); + parser->_parser_state->_reprocess_current_token = true; + return false; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#the-after-after-frameset-insertion-mode +static bool handle_after_after_frameset( + GumboParser* parser, GumboToken* token) { + if (token->type == GUMBO_TOKEN_COMMENT) { + append_comment_node(parser, get_document_node(parser), token); + return true; + } else if (token->type == GUMBO_TOKEN_DOCTYPE || + token->type == GUMBO_TOKEN_WHITESPACE || + tag_is(token, kStartTag, GUMBO_TAG_HTML)) { + return handle_in_body(parser, token); + } else if (token->type == GUMBO_TOKEN_EOF) { + return true; + } else if (tag_is(token, kStartTag, GUMBO_TAG_NOFRAMES)) { + return handle_in_head(parser, token); + } else { + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + } +} + +// Function pointers for each insertion mode. Keep in sync with +// insertion_mode.h. +typedef bool (*TokenHandler)(GumboParser* parser, GumboToken* token); +static const TokenHandler kTokenHandlers[] = {handle_initial, + handle_before_html, handle_before_head, handle_in_head, + handle_in_head_noscript, handle_after_head, handle_in_body, handle_text, + handle_in_table, handle_in_table_text, handle_in_caption, + handle_in_column_group, handle_in_table_body, handle_in_row, handle_in_cell, + handle_in_select, handle_in_select_in_table, handle_in_template, + handle_after_body, handle_in_frameset, handle_after_frameset, + handle_after_after_body, handle_after_after_frameset}; + +static bool handle_html_content(GumboParser* parser, GumboToken* token) { + return kTokenHandlers[(unsigned int) parser->_parser_state->_insertion_mode]( + parser, token); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete/tokenization.html#parsing-main-inforeign +static bool handle_in_foreign_content(GumboParser* parser, GumboToken* token) { + gumbo_debug("Handling foreign content"); + switch (token->type) { + case GUMBO_TOKEN_NULL: + parser_add_parse_error(parser, token); + token->v.character = kUtf8ReplacementChar; + insert_text_token(parser, token); + return false; + case GUMBO_TOKEN_WHITESPACE: + insert_text_token(parser, token); + return true; + case GUMBO_TOKEN_CDATA: + case GUMBO_TOKEN_CHARACTER: + insert_text_token(parser, token); + set_frameset_not_ok(parser); + return true; + case GUMBO_TOKEN_COMMENT: + append_comment_node(parser, get_current_node(parser), token); + return true; + case GUMBO_TOKEN_DOCTYPE: + parser_add_parse_error(parser, token); + ignore_token(parser); + return false; + default: + // Fall through to the if-statements below. + break; + } + // Order matters for these clauses. + if (tag_in(token, kStartTag, + (gumbo_tagset){TAG(B), TAG(BIG), TAG(BLOCKQUOTE), TAG(BODY), TAG(BR), + TAG(CENTER), TAG(CODE), TAG(DD), TAG(DIV), TAG(DL), TAG(DT), + TAG(EM), TAG(EMBED), TAG(H1), TAG(H2), TAG(H3), TAG(H4), TAG(H5), + TAG(H6), TAG(HEAD), TAG(HR), TAG(I), TAG(IMG), TAG(LI), + TAG(LISTING), TAG(MENU), TAG(META), TAG(NOBR), TAG(OL), TAG(P), + TAG(PRE), TAG(RUBY), TAG(S), TAG(SMALL), TAG(SPAN), TAG(STRONG), + TAG(STRIKE), TAG(SUB), TAG(SUP), TAG(TABLE), TAG(TT), TAG(U), + TAG(UL), TAG(VAR)}) || + (tag_is(token, kStartTag, GUMBO_TAG_FONT) && + (token_has_attribute(token, "color") || + token_has_attribute(token, "face") || + token_has_attribute(token, "size")))) { + /* Parse error */ + parser_add_parse_error(parser, token); + + /* + * Fragment case: If the parser was originally created for the HTML + * fragment parsing algorithm, then act as described in the "any other + * start tag" entry below. + */ + if (!is_fragment_parser(parser)) { + do { + pop_current_node(parser); + } while (!(is_mathml_integration_point(get_current_node(parser)) || + is_html_integration_point(get_current_node(parser)) || + get_current_node(parser)->v.element.tag_namespace == + GUMBO_NAMESPACE_HTML)); + parser->_parser_state->_reprocess_current_token = true; + return false; + } + + assert(token->type == GUMBO_TOKEN_START_TAG); + } + + if (token->type == GUMBO_TOKEN_START_TAG) { + const GumboNamespaceEnum current_namespace = + get_adjusted_current_node(parser)->v.element.tag_namespace; + if (current_namespace == GUMBO_NAMESPACE_MATHML) { + adjust_mathml_attributes(parser, token); + } + if (current_namespace == GUMBO_NAMESPACE_SVG) { + // Tag adjustment is left to the gumbo_normalize_svg_tagname helper + // function. + adjust_svg_attributes(parser, token); + } + adjust_foreign_attributes(parser, token); + insert_foreign_element(parser, token, current_namespace); + if (token->v.start_tag.is_self_closing) { + pop_current_node(parser); + acknowledge_self_closing_tag(parser); + } + return true; + // </script> tags are handled like any other end tag, putting the script's + // text into a text node child and closing the current node. + } else { + assert(token->type == GUMBO_TOKEN_END_TAG); + GumboNode* node = get_current_node(parser); + assert(node != NULL); + GumboStringPiece token_tagname = token->original_text; + GumboStringPiece node_tagname = node->v.element.original_tag; + gumbo_tag_from_original_text(&token_tagname); + gumbo_tag_from_original_text(&node_tagname); + + bool is_success = true; + if (!gumbo_string_equals_ignore_case(&node_tagname, &token_tagname)) { + parser_add_parse_error(parser, token); + is_success = false; + } + int i = parser->_parser_state->_open_elements.length; + for (--i; i > 0;) { + // Here we move up the stack until we find an HTML element (in which + // case we do nothing) or we find the element that we're about to + // close (in which case we pop everything we've seen until that + // point.) + gumbo_debug("Foreign %.*s node at %d.\n", node_tagname.length, + node_tagname.data, i); + if (gumbo_string_equals_ignore_case(&node_tagname, &token_tagname)) { + gumbo_debug("Matches.\n"); + while (pop_current_node(parser) != node) { + // Pop all the nodes below the current one. Node is guaranteed to + // be an element on the stack of open elements (set below), so + // this loop is guaranteed to terminate. + } + return is_success; + } + --i; + node = parser->_parser_state->_open_elements.data[i]; + if (node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML) { + // Must break before gumbo_tag_from_original_text to avoid passing + // parser-inserted nodes through. + break; + } + node_tagname = node->v.element.original_tag; + gumbo_tag_from_original_text(&node_tagname); + } + assert(node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML); + // We can't call handle_token directly because the current node is still in + // the SVG namespace, so it would re-enter this and result in infinite + // recursion. + return handle_html_content(parser, token) && is_success; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction +static bool handle_token(GumboParser* parser, GumboToken* token) { + if (parser->_parser_state->_ignore_next_linefeed && + token->type == GUMBO_TOKEN_WHITESPACE && token->v.character == '\n') { + parser->_parser_state->_ignore_next_linefeed = false; + ignore_token(parser); + return true; + } + // This needs to be reset both here and in the conditional above to catch both + // the case where the next token is not whitespace (so we don't ignore + // whitespace in the middle of <pre> tags) and where there are multiple + // whitespace tokens (so we don't ignore the second one). + parser->_parser_state->_ignore_next_linefeed = false; + + if (tag_is(token, kEndTag, GUMBO_TAG_BODY)) { + parser->_parser_state->_closed_body_tag = true; + } + if (tag_is(token, kEndTag, GUMBO_TAG_HTML)) { + parser->_parser_state->_closed_html_tag = true; + } + + const GumboNode* current_node = get_adjusted_current_node(parser); + assert(!current_node || current_node->type == GUMBO_NODE_ELEMENT || + current_node->type == GUMBO_NODE_TEMPLATE); + if (current_node) { + gumbo_debug("Current node: <%s>.\n", + gumbo_normalized_tagname(current_node->v.element.tag)); + } + if (!current_node || + current_node->v.element.tag_namespace == GUMBO_NAMESPACE_HTML || + (is_mathml_integration_point(current_node) && + (token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_WHITESPACE || + token->type == GUMBO_TOKEN_NULL || + (token->type == GUMBO_TOKEN_START_TAG && + !tag_in(token, kStartTag, + (gumbo_tagset){TAG(MGLYPH), TAG(MALIGNMARK)})))) || + (current_node->v.element.tag_namespace == GUMBO_NAMESPACE_MATHML && + node_qualified_tag_is( + current_node, GUMBO_NAMESPACE_MATHML, GUMBO_TAG_ANNOTATION_XML) && + tag_is(token, kStartTag, GUMBO_TAG_SVG)) || + (is_html_integration_point(current_node) && + (token->type == GUMBO_TOKEN_START_TAG || + token->type == GUMBO_TOKEN_CHARACTER || + token->type == GUMBO_TOKEN_NULL || + token->type == GUMBO_TOKEN_WHITESPACE)) || + token->type == GUMBO_TOKEN_EOF) { + return handle_html_content(parser, token); + } else { + return handle_in_foreign_content(parser, token); + } +} + +static void fragment_parser_init(GumboParser* parser, GumboTag fragment_ctx, + GumboNamespaceEnum fragment_namespace) { + GumboNode* root; + assert(fragment_ctx != GUMBO_TAG_LAST); + + // 3 + parser->_parser_state->_fragment_ctx = create_element(parser, fragment_ctx); + parser->_parser_state->_fragment_ctx->v.element.tag_namespace = + fragment_namespace; + + // 4 + if (fragment_namespace == GUMBO_NAMESPACE_HTML) { + // Non-HTML namespaces always start in the DATA state. + switch (fragment_ctx) { + case GUMBO_TAG_TITLE: + case GUMBO_TAG_TEXTAREA: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA); + break; + + case GUMBO_TAG_STYLE: + case GUMBO_TAG_XMP: + case GUMBO_TAG_IFRAME: + case GUMBO_TAG_NOEMBED: + case GUMBO_TAG_NOFRAMES: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT); + break; + + case GUMBO_TAG_SCRIPT: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + break; + + case GUMBO_TAG_NOSCRIPT: + /* scripting is disabled in Gumbo, so leave the tokenizer + * in the default data state */ + break; + + case GUMBO_TAG_PLAINTEXT: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_PLAINTEXT); + break; + + default: + /* default data state */ + break; + } + } + + // 5. 6. 7. + root = insert_element_of_tag_type( + parser, GUMBO_TAG_HTML, GUMBO_INSERTION_IMPLIED); + parser->_output->root = root; + + // 8. + if (fragment_ctx == GUMBO_TAG_TEMPLATE) { + push_template_insertion_mode(parser, GUMBO_INSERTION_MODE_IN_TEMPLATE); + } + + // 10. + reset_insertion_mode_appropriately(parser); +} + +GumboOutput* gumbo_parse(const char* buffer) { + return gumbo_parse_with_options( + &kGumboDefaultOptions, buffer, strlen(buffer)); +} + +GumboOutput* gumbo_parse_with_options( + const GumboOptions* options, const char* buffer, size_t length) { + GumboParser parser; + parser._options = options; + output_init(&parser); + gumbo_tokenizer_state_init(&parser, buffer, length); + parser_state_init(&parser); + + if (options->fragment_context != GUMBO_TAG_LAST) { + fragment_parser_init( + &parser, options->fragment_context, options->fragment_namespace); + } + + GumboParserState* state = parser._parser_state; + gumbo_debug("Parsing %.*s.\n", length, buffer); + + // Sanity check so that infinite loops die with an assertion failure instead + // of hanging the process before we ever get an error. + int loop_count = 0; + + GumboToken token; + bool has_error = false; + + do { + if (state->_reprocess_current_token) { + state->_reprocess_current_token = false; + } else { + GumboNode* current_node = get_current_node(&parser); + gumbo_tokenizer_set_is_current_node_foreign(&parser, + current_node && + current_node->v.element.tag_namespace != GUMBO_NAMESPACE_HTML); + has_error = !gumbo_lex(&parser, &token) || has_error; + } + const char* token_type = "text"; + switch (token.type) { + case GUMBO_TOKEN_DOCTYPE: + token_type = "doctype"; + break; + case GUMBO_TOKEN_START_TAG: + token_type = gumbo_normalized_tagname(token.v.start_tag.tag); + break; + case GUMBO_TOKEN_END_TAG: + token_type = gumbo_normalized_tagname(token.v.end_tag); + break; + case GUMBO_TOKEN_COMMENT: + token_type = "comment"; + break; + default: + break; + } + gumbo_debug("Handling %s token @%d:%d in state %d.\n", (char*) token_type, + token.position.line, token.position.column, state->_insertion_mode); + + state->_current_token = &token; + state->_self_closing_flag_acknowledged = + !(token.type == GUMBO_TOKEN_START_TAG && + token.v.start_tag.is_self_closing); + + has_error = !handle_token(&parser, &token) || has_error; + + // Check for memory leaks when ownership is transferred from start tag + // tokens to nodes. + assert(state->_reprocess_current_token || + token.type != GUMBO_TOKEN_START_TAG || + token.v.start_tag.attributes.data == NULL); + + if (!state->_self_closing_flag_acknowledged) { + GumboError* error = parser_add_parse_error(&parser, &token); + if (error) { + error->type = GUMBO_ERR_UNACKNOWLEDGED_SELF_CLOSING_TAG; + } + } + + ++loop_count; + assert(loop_count < 1000000000); + + } while ((token.type != GUMBO_TOKEN_EOF || state->_reprocess_current_token) && + !(options->stop_on_first_error && has_error)); + + finish_parsing(&parser); + // For API uniformity reasons, if the doctype still has nulls, convert them to + // empty strings. + GumboDocument* doc_type = &parser._output->document->v.document; + if (doc_type->name == NULL) { + doc_type->name = gumbo_copy_stringz(&parser, ""); + } + if (doc_type->public_identifier == NULL) { + doc_type->public_identifier = gumbo_copy_stringz(&parser, ""); + } + if (doc_type->system_identifier == NULL) { + doc_type->system_identifier = gumbo_copy_stringz(&parser, ""); + } + + parser_state_destroy(&parser); + gumbo_tokenizer_state_destroy(&parser); + return parser._output; +} + +void gumbo_destroy_node(GumboOptions* options, GumboNode* node) { + // Need a dummy GumboParser because the allocator comes along with the + // options object. + GumboParser parser; + parser._options = options; + destroy_node(&parser, node); +} + +void gumbo_destroy_output(const GumboOptions* options, GumboOutput* output) { + // Need a dummy GumboParser because the allocator comes along with the + // options object. + GumboParser parser; + parser._options = options; + destroy_node(&parser, output->document); + for (unsigned int i = 0; i < output->errors.length; ++i) { + gumbo_error_destroy(&parser, output->errors.data[i]); + } + gumbo_vector_destroy(&parser, &output->errors); + gumbo_parser_deallocate(&parser, output); +} diff --git a/libs/litehtml/src/gumbo/string_buffer.c b/libs/litehtml/src/gumbo/string_buffer.c new file mode 100644 index 0000000000..d9be2f6bd6 --- /dev/null +++ b/libs/litehtml/src/gumbo/string_buffer.c @@ -0,0 +1,110 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "string_buffer.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "string_piece.h" +#include "util.h" + +struct GumboInternalParser; + +// Size chosen via statistical analysis of ~60K websites. +// 99% of text nodes and 98% of attribute names/values fit in this initial size. +static const size_t kDefaultStringBufferSize = 5; + +static void maybe_resize_string_buffer(struct GumboInternalParser* parser, + size_t additional_chars, GumboStringBuffer* buffer) { + size_t new_length = buffer->length + additional_chars; + size_t new_capacity = buffer->capacity; + while (new_capacity < new_length) { + new_capacity *= 2; + } + if (new_capacity != buffer->capacity) { + char* new_data = gumbo_parser_allocate(parser, new_capacity); + memcpy(new_data, buffer->data, buffer->length); + gumbo_parser_deallocate(parser, buffer->data); + buffer->data = new_data; + buffer->capacity = new_capacity; + } +} + +void gumbo_string_buffer_init( + struct GumboInternalParser* parser, GumboStringBuffer* output) { + output->data = gumbo_parser_allocate(parser, kDefaultStringBufferSize); + output->length = 0; + output->capacity = kDefaultStringBufferSize; +} + +void gumbo_string_buffer_reserve(struct GumboInternalParser* parser, + size_t min_capacity, GumboStringBuffer* output) { + maybe_resize_string_buffer(parser, min_capacity - output->length, output); +} + +void gumbo_string_buffer_append_codepoint( + struct GumboInternalParser* parser, int c, GumboStringBuffer* output) { + // num_bytes is actually the number of continuation bytes, 1 less than the + // total number of bytes. This is done to keep the loop below simple and + // should probably change if we unroll it. + int num_bytes, prefix; + if (c <= 0x7f) { + num_bytes = 0; + prefix = 0; + } else if (c <= 0x7ff) { + num_bytes = 1; + prefix = 0xc0; + } else if (c <= 0xffff) { + num_bytes = 2; + prefix = 0xe0; + } else { + num_bytes = 3; + prefix = 0xf0; + } + maybe_resize_string_buffer(parser, num_bytes + 1, output); + output->data[output->length++] = prefix | (c >> (num_bytes * 6)); + for (int i = num_bytes - 1; i >= 0; --i) { + output->data[output->length++] = 0x80 | (0x3f & (c >> (i * 6))); + } +} + +void gumbo_string_buffer_append_string(struct GumboInternalParser* parser, + GumboStringPiece* str, GumboStringBuffer* output) { + maybe_resize_string_buffer(parser, str->length, output); + memcpy(output->data + output->length, str->data, str->length); + output->length += str->length; +} + +char* gumbo_string_buffer_to_string( + struct GumboInternalParser* parser, GumboStringBuffer* input) { + char* buffer = gumbo_parser_allocate(parser, input->length + 1); + memcpy(buffer, input->data, input->length); + buffer[input->length] = '\0'; + return buffer; +} + +void gumbo_string_buffer_clear( + struct GumboInternalParser* parser, GumboStringBuffer* input) { + input->length = 0; +} + +void gumbo_string_buffer_destroy( + struct GumboInternalParser* parser, GumboStringBuffer* buffer) { + gumbo_parser_deallocate(parser, buffer->data); +} diff --git a/libs/litehtml/src/gumbo/string_piece.c b/libs/litehtml/src/gumbo/string_piece.c new file mode 100644 index 0000000000..8ad5b8460e --- /dev/null +++ b/libs/litehtml/src/gumbo/string_piece.c @@ -0,0 +1,48 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "string_piece.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "util.h" + +struct GumboInternalParser; + +const GumboStringPiece kGumboEmptyString = {NULL, 0}; + +bool gumbo_string_equals( + const GumboStringPiece* str1, const GumboStringPiece* str2) { + return str1->length == str2->length && + !memcmp(str1->data, str2->data, str1->length); +} + +bool gumbo_string_equals_ignore_case( + const GumboStringPiece* str1, const GumboStringPiece* str2) { + return str1->length == str2->length && + !strncasecmp(str1->data, str2->data, str1->length); +} + +void gumbo_string_copy(struct GumboInternalParser* parser, + GumboStringPiece* dest, const GumboStringPiece* source) { + dest->length = source->length; + char* buffer = gumbo_parser_allocate(parser, source->length); + memcpy(buffer, source->data, source->length); + dest->data = buffer; +} diff --git a/libs/litehtml/src/gumbo/tag.c b/libs/litehtml/src/gumbo/tag.c new file mode 100644 index 0000000000..a394c0a677 --- /dev/null +++ b/libs/litehtml/src/gumbo/tag.c @@ -0,0 +1,95 @@ +// Copyright 2011 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "gumbo.h" + +#include <assert.h> +#include <ctype.h> +#include <string.h> + +const char* kGumboTagNames[] = { +#include "tag_strings.h" + "", // TAG_UNKNOWN + "", // TAG_LAST +}; + +static const unsigned char kGumboTagSizes[] = { +#include "tag_sizes.h" + 0, // TAG_UNKNOWN + 0, // TAG_LAST +}; + +const char* gumbo_normalized_tagname(GumboTag tag) { + assert(tag <= GUMBO_TAG_LAST); + return kGumboTagNames[tag]; +} + +void gumbo_tag_from_original_text(GumboStringPiece* text) { + if (text->data == NULL) { + return; + } + + assert(text->length >= 2); + assert(text->data[0] == '<'); + assert(text->data[text->length - 1] == '>'); + if (text->data[1] == '/') { + // End tag. + assert(text->length >= 3); + text->data += 2; // Move past </ + text->length -= 3; + } else { + // Start tag. + text->data += 1; // Move past < + text->length -= 2; + // strnchr is apparently not a standard C library function, so I loop + // explicitly looking for whitespace or other illegal tag characters. + for (const char* c = text->data; c != text->data + text->length; ++c) { + if (isspace(*c) || *c == '/') { + text->length = c - text->data; + break; + } + } + } +} + +static int case_memcmp(const char* s1, const char* s2, unsigned int n) { + while (n--) { + unsigned char c1 = tolower(*s1++); + unsigned char c2 = tolower(*s2++); + if (c1 != c2) return (int) c1 - (int) c2; + } + return 0; +} + +#include "tag_gperf.h" +#define TAG_MAP_SIZE (sizeof(kGumboTagMap) / sizeof(kGumboTagMap[0])) + +GumboTag gumbo_tagn_enum(const char* tagname, unsigned int length) { + if (length) { + unsigned int key = tag_hash(tagname, length); + if (key < TAG_MAP_SIZE) { + GumboTag tag = kGumboTagMap[key]; + if (length == kGumboTagSizes[(int) tag] && + !case_memcmp(tagname, kGumboTagNames[(int) tag], length)) + return tag; + } + } + return GUMBO_TAG_UNKNOWN; +} + +GumboTag gumbo_tag_enum(const char* tagname) { + return gumbo_tagn_enum(tagname, (unsigned)strlen(tagname)); +} diff --git a/libs/litehtml/src/gumbo/tag.in b/libs/litehtml/src/gumbo/tag.in new file mode 100644 index 0000000000..4c25264857 --- /dev/null +++ b/libs/litehtml/src/gumbo/tag.in @@ -0,0 +1,150 @@ +html +head +title +base +link +meta +style +script +noscript +template +body +article +section +nav +aside +h1 +h2 +h3 +h4 +h5 +h6 +hgroup +header +footer +address +p +hr +pre +blockquote +ol +ul +li +dl +dt +dd +figure +figcaption +main +div +a +em +strong +small +s +cite +q +dfn +abbr +data +time +code +var +samp +kbd +sub +sup +i +b +u +mark +ruby +rt +rp +bdi +bdo +span +br +wbr +ins +del +image +img +iframe +embed +object +param +video +audio +source +track +canvas +map +area +math +mi +mo +mn +ms +mtext +mglyph +malignmark +annotation-xml +svg +foreignobject +desc +table +caption +colgroup +col +tbody +thead +tfoot +tr +td +th +form +fieldset +legend +label +input +button +select +datalist +optgroup +option +textarea +keygen +output +progress +meter +details +summary +menu +menuitem +applet +acronym +bgsound +dir +frame +frameset +noframes +isindex +listing +xmp +nextid +noembed +plaintext +rb +strike +basefont +big +blink +center +font +marquee +multicol +nobr +spacer +tt +rtc diff --git a/libs/litehtml/src/gumbo/tokenizer.c b/libs/litehtml/src/gumbo/tokenizer.c new file mode 100644 index 0000000000..0d0ea0f241 --- /dev/null +++ b/libs/litehtml/src/gumbo/tokenizer.c @@ -0,0 +1,2897 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) +// +// Coding conventions specific to this file: +// +// 1. Functions that fill in a token should be named emit_*, and should be +// followed immediately by a return from the tokenizer (true if no error +// occurred, false if an error occurred). Sometimes the emit functions +// themselves return a boolean so that they can be combined with the return +// statement; in this case, they should match this convention. +// 2. Functions that shuffle data from temporaries to final API structures +// should be named finish_*, and be called just before the tokenizer exits the +// state that accumulates the temporary. +// 3. All internal data structures should be kept in an initialized state from +// tokenizer creation onwards, ready to accept input. When a buffer's flushed +// and reset, it should be deallocated and immediately reinitialized. +// 4. Make sure there are appropriate break statements following each state. +// 5. Assertions on the state of the temporary and tag buffers are usually a +// good idea, and should go at the entry point of each state when added. +// 6. Statement order within states goes: +// 1. Add parse errors, if appropriate. +// 2. Call finish_* functions to build up tag state. +// 2. Switch to new state. Set _reconsume flag if appropriate. +// 3. Perform any other temporary buffer manipulation. +// 4. Emit tokens +// 5. Return/break. +// This order ensures that we can verify that every emit is followed by a +// return, ensures that the correct state is recorded with any parse errors, and +// prevents parse error position from being messed up by possible mark/resets in +// temporary buffer manipulation. + +#include "tokenizer.h" + +#include <assert.h> +#include <stdbool.h> +#include <string.h> + +#include "attribute.h" +#include "char_ref.h" +#include "error.h" +#include "gumbo.h" +#include "parser.h" +#include "string_buffer.h" +#include "string_piece.h" +#include "token_type.h" +#include "tokenizer_states.h" +#include "utf8.h" +#include "util.h" +#include "vector.h" + +// Compared against _script_data_buffer to determine if we're in double-escaped +// script mode. +const GumboStringPiece kScriptTag = {"script", 6}; + +// An enum for the return value of each individual state. +typedef enum { + RETURN_ERROR, // Return false (error) from the tokenizer. + RETURN_SUCCESS, // Return true (success) from the tokenizer. + NEXT_CHAR // Proceed to the next character and continue lexing. +} StateResult; + +// This is a struct containing state necessary to build up a tag token, +// character by character. +typedef struct GumboInternalTagState { + // A buffer to accumulate characters for various GumboStringPiece fields. + GumboStringBuffer _buffer; + + // A pointer to the start of the original text corresponding to the contents + // of the buffer. + const char* _original_text; + + // The current tag enum, computed once the tag name state has finished so that + // the buffer can be re-used for building up attributes. + GumboTag _tag; + + // The starting location of the text in the buffer. + GumboSourcePosition _start_pos; + + // The current list of attributes. This is copied (and ownership of its data + // transferred) to the GumboStartTag token upon completion of the tag. New + // attributes are added as soon as their attribute name state is complete, and + // values are filled in by operating on _attributes.data[attributes.length-1]. + GumboVector /* GumboAttribute */ _attributes; + + // If true, the next attribute value to be finished should be dropped. This + // happens if a duplicate attribute name is encountered - we want to consume + // the attribute value, but shouldn't overwrite the existing value. + bool _drop_next_attr_value; + + // The state that caused the tokenizer to switch into a character reference in + // attribute value state. This is used to set the additional allowed + // character, and is switched back to on completion. Initialized as the + // tokenizer enters the character reference state. + GumboTokenizerEnum _attr_value_state; + + // The last start tag to have been emitted by the tokenizer. This is + // necessary to check for appropriate end tags. + GumboTag _last_start_tag; + + // If true, then this is a start tag. If false, it's an end tag. This is + // necessary to generate the appropriate token type at tag-closing time. + bool _is_start_tag; + + // If true, then this tag is "self-closing" and doesn't have an end tag. + bool _is_self_closing; +} GumboTagState; + +// This is the main tokenizer state struct, containing all state used by in +// tokenizing the input stream. +typedef struct GumboInternalTokenizerState { + // The current lexer state. Starts in GUMBO_LEX_DATA. + GumboTokenizerEnum _state; + + // A flag indicating whether the current input character needs to reconsumed + // in another state, or whether the next input character should be read for + // the next iteration of the state loop. This is set when the spec reads + // "Reconsume the current input character in..." + bool _reconsume_current_input; + + // A flag indicating whether the current node is a foreign element. This is + // set by gumbo_tokenizer_set_is_current_node_foreign and checked in the + // markup declaration state. + bool _is_current_node_foreign; + + // A flag indicating whether the tokenizer is in a CDATA section. If so, then + // text tokens emitted will be GUMBO_TOKEN_CDATA. + bool _is_in_cdata; + + // Certain states (notably character references) may emit two character tokens + // at once, but the contract for lex() fills in only one token at a time. The + // extra character is buffered here, and then this is checked on entry to + // lex(). If a character is stored here, it's immediately emitted and control + // returns from the lexer. kGumboNoChar is used to represent 'no character + // stored.' + // + // Note that characters emitted through this mechanism will have their source + // position marked as the character under the mark, i.e. multiple characters + // may be emitted with the same position. This is desirable for character + // references, but unsuitable for many other cases. Use the _temporary_buffer + // mechanism if the buffered characters must have their original positions in + // the document. + int _buffered_emit_char; + + // A temporary buffer to accumulate characters, as described by the "temporary + // buffer" phrase in the tokenizer spec. We use this in a somewhat unorthodox + // way: we record the specific character to go into the buffer, which may + // sometimes be a lowercased version of the actual input character. However, + // we *also* use utf8iterator_mark() to record the position at tag start. + // When we start flushing the temporary buffer, we set _temporary_buffer_emit + // to the start of it, and then increment it for each call to the tokenizer. + // We also call utf8iterator_reset(), and utf8iterator_next() through the + // input stream, so that tokens emitted by emit_char have the correct position + // and original text. + GumboStringBuffer _temporary_buffer; + + // The current cursor position we're emitting from within + // _temporary_buffer.data. NULL whenever we're not flushing the buffer. + const char* _temporary_buffer_emit; + + // The temporary buffer is also used by the spec to check whether we should + // enter the script data double escaped state, but we can't use the same + // buffer for both because we have to flush out "<s" as emits while still + // maintaining the context that will eventually become "script". This is a + // separate buffer that's used in place of the temporary buffer for states + // that may enter the script data double escape start state. + GumboStringBuffer _script_data_buffer; + + // Pointer to the beginning of the current token in the original buffer; used + // to record the original text. + const char* _token_start; + + // GumboSourcePosition recording the source location of the start of the + // current token. + GumboSourcePosition _token_start_pos; + + // Current tag state. + GumboTagState _tag_state; + + // Doctype state. We use the temporary buffer to accumulate characters (it's + // not used for anything else in the doctype states), and then freshly + // allocate the strings in the doctype token, then copy it over on emit. + GumboTokenDocType _doc_type_state; + + // The UTF8Iterator over the tokenizer input. + Utf8Iterator _input; +} GumboTokenizerState; + +// Adds an ERR_UNEXPECTED_CODE_POINT parse error to the parser's error struct. +static void tokenizer_add_parse_error( + GumboParser* parser, GumboErrorType type) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + utf8iterator_get_position(&tokenizer->_input, &error->position); + error->original_text = utf8iterator_get_char_pointer(&tokenizer->_input); + error->type = type; + error->v.tokenizer.codepoint = utf8iterator_current(&tokenizer->_input); + switch (tokenizer->_state) { + case GUMBO_LEX_DATA: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_DATA; + break; + case GUMBO_LEX_CHAR_REF_IN_DATA: + case GUMBO_LEX_CHAR_REF_IN_RCDATA: + case GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_CHAR_REF; + break; + case GUMBO_LEX_RCDATA: + case GUMBO_LEX_RCDATA_LT: + case GUMBO_LEX_RCDATA_END_TAG_OPEN: + case GUMBO_LEX_RCDATA_END_TAG_NAME: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_RCDATA; + break; + case GUMBO_LEX_RAWTEXT: + case GUMBO_LEX_RAWTEXT_LT: + case GUMBO_LEX_RAWTEXT_END_TAG_OPEN: + case GUMBO_LEX_RAWTEXT_END_TAG_NAME: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_RAWTEXT; + break; + case GUMBO_LEX_PLAINTEXT: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_PLAINTEXT; + break; + case GUMBO_LEX_SCRIPT: + case GUMBO_LEX_SCRIPT_LT: + case GUMBO_LEX_SCRIPT_END_TAG_OPEN: + case GUMBO_LEX_SCRIPT_END_TAG_NAME: + case GUMBO_LEX_SCRIPT_ESCAPED_START: + case GUMBO_LEX_SCRIPT_ESCAPED_START_DASH: + case GUMBO_LEX_SCRIPT_ESCAPED: + case GUMBO_LEX_SCRIPT_ESCAPED_DASH: + case GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH: + case GUMBO_LEX_SCRIPT_ESCAPED_LT: + case GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN: + case GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT: + case GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_SCRIPT; + break; + case GUMBO_LEX_TAG_OPEN: + case GUMBO_LEX_END_TAG_OPEN: + case GUMBO_LEX_TAG_NAME: + case GUMBO_LEX_BEFORE_ATTR_NAME: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_TAG; + break; + case GUMBO_LEX_SELF_CLOSING_START_TAG: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_SELF_CLOSING_TAG; + break; + case GUMBO_LEX_ATTR_NAME: + case GUMBO_LEX_AFTER_ATTR_NAME: + case GUMBO_LEX_BEFORE_ATTR_VALUE: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_ATTR_NAME; + break; + case GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED: + case GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED: + case GUMBO_LEX_ATTR_VALUE_UNQUOTED: + case GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_ATTR_VALUE; + break; + case GUMBO_LEX_BOGUS_COMMENT: + case GUMBO_LEX_COMMENT_START: + case GUMBO_LEX_COMMENT_START_DASH: + case GUMBO_LEX_COMMENT: + case GUMBO_LEX_COMMENT_END_DASH: + case GUMBO_LEX_COMMENT_END: + case GUMBO_LEX_COMMENT_END_BANG: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_COMMENT; + break; + case GUMBO_LEX_MARKUP_DECLARATION: + case GUMBO_LEX_DOCTYPE: + case GUMBO_LEX_BEFORE_DOCTYPE_NAME: + case GUMBO_LEX_DOCTYPE_NAME: + case GUMBO_LEX_AFTER_DOCTYPE_NAME: + case GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD: + case GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID: + case GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED: + case GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED: + case GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID: + case GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID: + case GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD: + case GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID: + case GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED: + case GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED: + case GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID: + case GUMBO_LEX_BOGUS_DOCTYPE: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_DOCTYPE; + break; + case GUMBO_LEX_CDATA: + error->v.tokenizer.state = GUMBO_ERR_TOKENIZER_CDATA; + break; + } +} + +static bool is_alpha(int c) { + // We don't use ISO C isupper/islower functions here because they + // depend upon the program's locale, while the behavior of the HTML5 spec is + // independent of which locale the program is run in. + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +static int ensure_lowercase(int c) { + return c >= 'A' && c <= 'Z' ? c + 0x20 : c; +} + +static GumboTokenType get_char_token_type(bool is_in_cdata, int c) { + if (is_in_cdata && c > 0) { + return GUMBO_TOKEN_CDATA; + } + + switch (c) { + case '\t': + case '\n': + case '\r': + case '\f': + case ' ': + return GUMBO_TOKEN_WHITESPACE; + case 0: + gumbo_debug("Emitted null byte.\n"); + return GUMBO_TOKEN_NULL; + case -1: + return GUMBO_TOKEN_EOF; + default: + return GUMBO_TOKEN_CHARACTER; + } +} + +// Starts recording characters in the temporary buffer. +// Because this needs to reset the utf8iterator_mark to the beginning of the +// text that will eventually be emitted, it needs to be called a couple of +// states before the spec says "Set the temporary buffer to the empty string". +// In general, this should be called whenever there's a transition to a +// "less-than sign state". The initial < and possibly / then need to be +// appended to the temporary buffer, their presence needs to be accounted for in +// states that compare the temporary buffer against a literal value, and +// spec stanzas that say "emit a < and / character token along with a character +// token for each character in the temporary buffer" need to be adjusted to +// account for the presence of the < and / inside the temporary buffer. +static void clear_temporary_buffer(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + assert(!tokenizer->_temporary_buffer_emit); + utf8iterator_mark(&tokenizer->_input); + gumbo_string_buffer_clear(parser, &tokenizer->_temporary_buffer); + // The temporary buffer and script data buffer are the same object in the + // spec, so the script data buffer should be cleared as well. + gumbo_string_buffer_clear(parser, &tokenizer->_script_data_buffer); +} + +// Appends a codepoint to the temporary buffer. +static void append_char_to_temporary_buffer( + GumboParser* parser, int codepoint) { + gumbo_string_buffer_append_codepoint( + parser, codepoint, &parser->_tokenizer_state->_temporary_buffer); +} + +// Checks to see if the temporary buffer equals a certain string. +// Make sure this remains side-effect free; it's used in assertions. +#ifndef NDEBUG +static bool temporary_buffer_equals(GumboParser* parser, const char* text) { + GumboStringBuffer* buffer = &parser->_tokenizer_state->_temporary_buffer; + // TODO(jdtang): See if the extra strlen is a performance problem, and replace + // it with an explicit sizeof(literal) if necessary. I don't think it will + // be, as this is only used in a couple of rare states. + size_t text_len = strlen(text); + return text_len == buffer->length && + memcmp(buffer->data, text, text_len) == 0; +} +#endif + +static void doc_type_state_init(GumboParser* parser) { + GumboTokenDocType* doc_type_state = + &parser->_tokenizer_state->_doc_type_state; + // We initialize these to NULL here so that we don't end up leaking memory if + // we never see a doctype token. When we do see a doctype token, we reset + // them to a freshly-allocated empty string so that we can present a uniform + // interface to client code and not make them check for null. Ownership is + // transferred to the doctype token when it's emitted. + doc_type_state->name = NULL; + doc_type_state->public_identifier = NULL; + doc_type_state->system_identifier = NULL; + doc_type_state->force_quirks = false; + doc_type_state->has_public_identifier = false; + doc_type_state->has_system_identifier = false; +} + +// Sets the token original_text and position to the current iterator position. +// This is necessary because [CDATA[ sections may include text that is ignored +// by the tokenizer. +static void reset_token_start_point(GumboTokenizerState* tokenizer) { + tokenizer->_token_start = utf8iterator_get_char_pointer(&tokenizer->_input); + utf8iterator_get_position(&tokenizer->_input, &tokenizer->_token_start_pos); +} + +// Sets the tag buffer original text and start point to the current iterator +// position. This is necessary because attribute names & values may have +// whitespace preceeding them, and so we can't assume that the actual token +// starting point was the end of the last tag buffer usage. +static void reset_tag_buffer_start_point(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + + utf8iterator_get_position(&tokenizer->_input, &tag_state->_start_pos); + tag_state->_original_text = utf8iterator_get_char_pointer(&tokenizer->_input); +} + +// Moves the temporary buffer contents over to the specified output string, +// and clears the temporary buffer. +static void finish_temporary_buffer(GumboParser* parser, const char** output) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + *output = + gumbo_string_buffer_to_string(parser, &tokenizer->_temporary_buffer); + clear_temporary_buffer(parser); +} + +// Advances the iterator past the end of the token, and then fills in the +// relevant position fields. It's assumed that after every emit, the tokenizer +// will immediately return (letting the tree-construction stage read the filled +// in Token). Thus, it's safe to advance the input stream here, since it will +// bypass the advance at the bottom of the state machine loop. +// +// Since this advances the iterator and resets the current input, make sure to +// call it after you've recorded any other data you need for the token. +static void finish_token(GumboParser* parser, GumboToken* token) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + if (!tokenizer->_reconsume_current_input) { + utf8iterator_next(&tokenizer->_input); + } + + token->position = tokenizer->_token_start_pos; + token->original_text.data = tokenizer->_token_start; + reset_token_start_point(tokenizer); + token->original_text.length = + tokenizer->_token_start - token->original_text.data; + if (token->original_text.length > 0 && + token->original_text.data[token->original_text.length - 1] == '\r') { + // The UTF8 iterator will ignore carriage returns in the input stream, which + // means that the next token may start one past a \r character. The pointer + // arithmetic above results in that \r being appended to the original text + // of the preceding token, so we have to adjust its length here to chop the + // \r off. + --token->original_text.length; + } +} + +// Records the doctype public ID, assumed to be in the temporary buffer. +// Convenience method that also sets has_public_identifier to true. +static void finish_doctype_public_id(GumboParser* parser) { + GumboTokenDocType* doc_type_state = + &parser->_tokenizer_state->_doc_type_state; + gumbo_parser_deallocate(parser, (void*) doc_type_state->public_identifier); + finish_temporary_buffer(parser, &doc_type_state->public_identifier); + doc_type_state->has_public_identifier = true; +} + +// Records the doctype system ID, assumed to be in the temporary buffer. +// Convenience method that also sets has_system_identifier to true. +static void finish_doctype_system_id(GumboParser* parser) { + GumboTokenDocType* doc_type_state = + &parser->_tokenizer_state->_doc_type_state; + gumbo_parser_deallocate(parser, (void*) doc_type_state->system_identifier); + finish_temporary_buffer(parser, &doc_type_state->system_identifier); + doc_type_state->has_system_identifier = true; +} + +// Writes a single specified character to the output token. +static void emit_char(GumboParser* parser, int c, GumboToken* output) { + output->type = get_char_token_type(parser->_tokenizer_state->_is_in_cdata, c); + output->v.character = c; + finish_token(parser, output); +} + +// Writes a replacement character token and records a parse error. +// Always returns RETURN_ERROR, per gumbo_lex return value. +static StateResult emit_replacement_char( + GumboParser* parser, GumboToken* output) { + // In all cases, this is because of a null byte in the input stream. + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + emit_char(parser, kUtf8ReplacementChar, output); + return RETURN_ERROR; +} + +// Writes an EOF character token. Always returns RETURN_SUCCESS. +static StateResult emit_eof(GumboParser* parser, GumboToken* output) { + emit_char(parser, -1, output); + return RETURN_SUCCESS; +} + +// Writes the current input character out as a character token. +// Always returns RETURN_SUCCESS. +static bool emit_current_char(GumboParser* parser, GumboToken* output) { + emit_char( + parser, utf8iterator_current(&parser->_tokenizer_state->_input), output); + return RETURN_SUCCESS; +} + +// Writes out a doctype token, copying it from the tokenizer state. +static void emit_doctype(GumboParser* parser, GumboToken* output) { + output->type = GUMBO_TOKEN_DOCTYPE; + output->v.doc_type = parser->_tokenizer_state->_doc_type_state; + finish_token(parser, output); + doc_type_state_init(parser); +} + +// Debug-only function that explicitly sets the attribute vector data to NULL so +// it can be asserted on tag creation, verifying that there are no memory leaks. +static void mark_tag_state_as_empty(GumboTagState* tag_state) { +#ifndef NDEBUG + tag_state->_attributes = kGumboEmptyVector; +#endif +} + +// Writes out the current tag as a start or end tag token. +// Always returns RETURN_SUCCESS. +static StateResult emit_current_tag(GumboParser* parser, GumboToken* output) { + GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state; + if (tag_state->_is_start_tag) { + output->type = GUMBO_TOKEN_START_TAG; + output->v.start_tag.tag = tag_state->_tag; + output->v.start_tag.attributes = tag_state->_attributes; + output->v.start_tag.is_self_closing = tag_state->_is_self_closing; + tag_state->_last_start_tag = tag_state->_tag; + mark_tag_state_as_empty(tag_state); + gumbo_debug( + "Emitted start tag %s.\n", gumbo_normalized_tagname(tag_state->_tag)); + } else { + output->type = GUMBO_TOKEN_END_TAG; + output->v.end_tag = tag_state->_tag; + // In end tags, ownership of the attributes vector is not transferred to the + // token, but it's still initialized as normal, so it must be manually + // deallocated. There may also be attributes to destroy, in certain broken + // cases like </div</th> (the "th" is an attribute there). + for (unsigned int i = 0; i < tag_state->_attributes.length; ++i) { + gumbo_destroy_attribute(parser, tag_state->_attributes.data[i]); + } + gumbo_parser_deallocate(parser, tag_state->_attributes.data); + mark_tag_state_as_empty(tag_state); + gumbo_debug( + "Emitted end tag %s.\n", gumbo_normalized_tagname(tag_state->_tag)); + } + gumbo_string_buffer_destroy(parser, &tag_state->_buffer); + finish_token(parser, output); + gumbo_debug("Original text = %.*s.\n", output->original_text.length, + output->original_text.data); + assert(output->original_text.length >= 2); + assert(output->original_text.data[0] == '<'); + assert(output->original_text.data[output->original_text.length - 1] == '>'); + return RETURN_SUCCESS; +} + +// In some states, we speculatively start a tag, but don't know whether it'll be +// emitted as tag token or as a series of character tokens until we finish it. +// We need to abandon the tag we'd started & free its memory in that case to +// avoid a memory leak. +static void abandon_current_tag(GumboParser* parser) { + GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state; + for (unsigned int i = 0; i < tag_state->_attributes.length; ++i) { + gumbo_destroy_attribute(parser, tag_state->_attributes.data[i]); + } + gumbo_parser_deallocate(parser, tag_state->_attributes.data); + mark_tag_state_as_empty(tag_state); + gumbo_string_buffer_destroy(parser, &tag_state->_buffer); + gumbo_debug("Abandoning current tag.\n"); +} + +// Wraps the consume_char_ref function to handle its output and make the +// appropriate TokenizerState modifications. Returns RETURN_ERROR if a parse +// error occurred, RETURN_SUCCESS otherwise. +static StateResult emit_char_ref(GumboParser* parser, + int additional_allowed_char, bool is_in_attribute, GumboToken* output) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + OneOrTwoCodepoints char_ref; + bool status = consume_char_ref( + parser, &tokenizer->_input, additional_allowed_char, false, &char_ref); + if (char_ref.first != kGumboNoChar) { + // consume_char_ref ends with the iterator pointing at the next character, + // so we need to be sure not advance it again before reading the next token. + tokenizer->_reconsume_current_input = true; + emit_char(parser, char_ref.first, output); + tokenizer->_buffered_emit_char = char_ref.second; + } else { + emit_char(parser, '&', output); + } + return status ? RETURN_SUCCESS : RETURN_ERROR; +} + +// Emits a comment token. Comments use the temporary buffer to accumulate their +// data, and then it's copied over and released to the 'text' field of the +// GumboToken union. Always returns RETURN_SUCCESS. +static StateResult emit_comment(GumboParser* parser, GumboToken* output) { + output->type = GUMBO_TOKEN_COMMENT; + finish_temporary_buffer(parser, &output->v.text); + finish_token(parser, output); + return RETURN_SUCCESS; +} + +// Checks to see we should be flushing accumulated characters in the temporary +// buffer, and fills the output token with the next output character if so. +// Returns true if a character has been emitted and the tokenizer should +// immediately return, false if we're at the end of the temporary buffer and +// should resume normal operation. +static bool maybe_emit_from_temporary_buffer( + GumboParser* parser, GumboToken* output) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + const char* c = tokenizer->_temporary_buffer_emit; + GumboStringBuffer* buffer = &tokenizer->_temporary_buffer; + + if (!c || c >= buffer->data + buffer->length) { + tokenizer->_temporary_buffer_emit = NULL; + return false; + } + + assert(*c == utf8iterator_current(&tokenizer->_input)); + // emit_char also advances the input stream. We need to do some juggling of + // the _reconsume_current_input flag to get the proper behavior when emitting + // previous tokens. Basically, _reconsume_current_input should *never* be set + // when emitting anything from the temporary buffer, since those characters + // have already been advanced past. However, it should be preserved so that + // when the *next* character is encountered again, the tokenizer knows not to + // advance past it. + bool saved_reconsume_state = tokenizer->_reconsume_current_input; + tokenizer->_reconsume_current_input = false; + emit_char(parser, *c, output); + ++tokenizer->_temporary_buffer_emit; + tokenizer->_reconsume_current_input = saved_reconsume_state; + return true; +} + +// Sets up the tokenizer to begin flushing the temporary buffer. +// This resets the input iterator stream to the start of the last tag, sets up +// _temporary_buffer_emit, and then (if the temporary buffer is non-empty) emits +// the first character in it. It returns true if a character was emitted, false +// otherwise. +static bool emit_temporary_buffer(GumboParser* parser, GumboToken* output) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + assert(tokenizer->_temporary_buffer.data); + utf8iterator_reset(&tokenizer->_input); + tokenizer->_temporary_buffer_emit = tokenizer->_temporary_buffer.data; + return maybe_emit_from_temporary_buffer(parser, output); +} + +// Appends a codepoint to the current tag buffer. If +// reinitilize_position_on_first is set, this also initializes the tag buffer +// start point; the only time you would *not* want to pass true for this +// parameter is if you want the original_text to include character (like an +// opening quote) that doesn't appear in the value. +static void append_char_to_tag_buffer( + GumboParser* parser, int codepoint, bool reinitilize_position_on_first) { + GumboStringBuffer* buffer = &parser->_tokenizer_state->_tag_state._buffer; + if (buffer->length == 0 && reinitilize_position_on_first) { + reset_tag_buffer_start_point(parser); + } + gumbo_string_buffer_append_codepoint(parser, codepoint, buffer); +} + +// (Re-)initialize the tag buffer. This also resets the original_text pointer +// and _start_pos field to point to the current position. +static void initialize_tag_buffer(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + + gumbo_string_buffer_init(parser, &tag_state->_buffer); + reset_tag_buffer_start_point(parser); +} + +// Initializes the tag_state to start a new tag, keeping track of the opening +// positions and original text. Takes a boolean indicating whether this is a +// start or end tag. +static void start_new_tag(GumboParser* parser, bool is_start_tag) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + int c = utf8iterator_current(&tokenizer->_input); + assert(is_alpha(c)); + c = ensure_lowercase(c); + assert(is_alpha(c)); + + initialize_tag_buffer(parser); + gumbo_string_buffer_append_codepoint(parser, c, &tag_state->_buffer); + + assert(tag_state->_attributes.data == NULL); + // Initial size chosen by statistical analysis of a corpus of 60k webpages. + // 99.5% of elements have 0 attributes, 93% of the remainder have 1. These + // numbers are a bit higher for more modern websites (eg. ~45% = 0, ~40% = 1 + // for the HTML5 Spec), but still have basically 99% of nodes with <= 2 attrs. + gumbo_vector_init(parser, 1, &tag_state->_attributes); + tag_state->_drop_next_attr_value = false; + tag_state->_is_start_tag = is_start_tag; + tag_state->_is_self_closing = false; + gumbo_debug("Starting new tag.\n"); +} + +// Fills in the specified char* with the contents of the tag buffer. +static void copy_over_tag_buffer(GumboParser* parser, const char** output) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + *output = gumbo_string_buffer_to_string(parser, &tag_state->_buffer); +} + +// Fills in: +// * The original_text GumboStringPiece with the portion of the original +// buffer that corresponds to the tag buffer. +// * The start_pos GumboSourcePosition with the start position of the tag +// buffer. +// * The end_pos GumboSourcePosition with the current source position. +static void copy_over_original_tag_text(GumboParser* parser, + GumboStringPiece* original_text, GumboSourcePosition* start_pos, + GumboSourcePosition* end_pos) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + + original_text->data = tag_state->_original_text; + original_text->length = utf8iterator_get_char_pointer(&tokenizer->_input) - + tag_state->_original_text; + if (original_text->data[original_text->length - 1] == '\r') { + // Since \r is skipped by the UTF-8 iterator, it can sometimes end up + // appended to the end of original text even when it's really the first part + // of the next character. If we detect this situation, shrink the length of + // the original text by 1 to remove the carriage return. + --original_text->length; + } + *start_pos = tag_state->_start_pos; + utf8iterator_get_position(&tokenizer->_input, end_pos); +} + +// Releases and then re-initializes the tag buffer. +static void reinitialize_tag_buffer(GumboParser* parser) { + gumbo_parser_deallocate( + parser, parser->_tokenizer_state->_tag_state._buffer.data); + initialize_tag_buffer(parser); +} + +// Moves some data from the temporary buffer over the the tag-based fields in +// TagState. +static void finish_tag_name(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + + tag_state->_tag = + gumbo_tagn_enum(tag_state->_buffer.data, (unsigned)tag_state->_buffer.length); + reinitialize_tag_buffer(parser); +} + +// Adds an ERR_DUPLICATE_ATTR parse error to the parser's error struct. +static void add_duplicate_attr_error(GumboParser* parser, const char* attr_name, + int original_index, int new_index) { + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state; + error->type = GUMBO_ERR_DUPLICATE_ATTR; + error->position = tag_state->_start_pos; + error->original_text = tag_state->_original_text; + error->v.duplicate_attr.original_index = original_index; + error->v.duplicate_attr.new_index = new_index; + copy_over_tag_buffer(parser, &error->v.duplicate_attr.name); + reinitialize_tag_buffer(parser); +} + +// Creates a new attribute in the current tag, copying the current tag buffer to +// the attribute's name. The attribute's value starts out as the empty string +// (following the "Boolean attributes" section of the spec) and is only +// overwritten on finish_attribute_value(). If the attribute has already been +// specified, the new attribute is dropped, a parse error is added, and the +// function returns false. Otherwise, this returns true. +static bool finish_attribute_name(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + GumboTagState* tag_state = &tokenizer->_tag_state; + // May've been set by a previous attribute without a value; reset it here. + tag_state->_drop_next_attr_value = false; + assert(tag_state->_attributes.data); + assert(tag_state->_attributes.capacity); + + GumboVector* /* GumboAttribute* */ attributes = &tag_state->_attributes; + for (unsigned int i = 0; i < attributes->length; ++i) { + GumboAttribute* attr = attributes->data[i]; + if (strlen(attr->name) == tag_state->_buffer.length && + memcmp(attr->name, tag_state->_buffer.data, + tag_state->_buffer.length) == 0) { + // Identical attribute; bail. + add_duplicate_attr_error(parser, attr->name, i, attributes->length); + tag_state->_drop_next_attr_value = true; + return false; + } + } + + GumboAttribute* attr = gumbo_parser_allocate(parser, sizeof(GumboAttribute)); + attr->attr_namespace = GUMBO_ATTR_NAMESPACE_NONE; + copy_over_tag_buffer(parser, &attr->name); + copy_over_original_tag_text( + parser, &attr->original_name, &attr->name_start, &attr->name_end); + attr->value = gumbo_copy_stringz(parser, ""); + copy_over_original_tag_text( + parser, &attr->original_value, &attr->name_start, &attr->name_end); + gumbo_vector_add(parser, attr, attributes); + reinitialize_tag_buffer(parser); + return true; +} + +// Finishes an attribute value. This sets the value of the most recently added +// attribute to the current contents of the tag buffer. +static void finish_attribute_value(GumboParser* parser) { + GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state; + if (tag_state->_drop_next_attr_value) { + // Duplicate attribute name detected in an earlier state, so we have to + // ignore the value. + tag_state->_drop_next_attr_value = false; + reinitialize_tag_buffer(parser); + return; + } + + GumboAttribute* attr = + tag_state->_attributes.data[tag_state->_attributes.length - 1]; + gumbo_parser_deallocate(parser, (void*) attr->value); + copy_over_tag_buffer(parser, &attr->value); + copy_over_original_tag_text( + parser, &attr->original_value, &attr->value_start, &attr->value_end); + reinitialize_tag_buffer(parser); +} + +// Returns true if the current end tag matches the last start tag emitted. +static bool is_appropriate_end_tag(GumboParser* parser) { + GumboTagState* tag_state = &parser->_tokenizer_state->_tag_state; + assert(!tag_state->_is_start_tag); + return tag_state->_last_start_tag != GUMBO_TAG_LAST && + tag_state->_last_start_tag == gumbo_tagn_enum(tag_state->_buffer.data, + (unsigned)tag_state->_buffer.length); +} + +void gumbo_tokenizer_state_init( + GumboParser* parser, const char* text, size_t text_length) { + GumboTokenizerState* tokenizer = + gumbo_parser_allocate(parser, sizeof(GumboTokenizerState)); + parser->_tokenizer_state = tokenizer; + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_reconsume_current_input = false; + tokenizer->_is_current_node_foreign = false; + tokenizer->_is_in_cdata = false; + tokenizer->_tag_state._last_start_tag = GUMBO_TAG_LAST; + + tokenizer->_buffered_emit_char = kGumboNoChar; + gumbo_string_buffer_init(parser, &tokenizer->_temporary_buffer); + tokenizer->_temporary_buffer_emit = NULL; + + mark_tag_state_as_empty(&tokenizer->_tag_state); + + gumbo_string_buffer_init(parser, &tokenizer->_script_data_buffer); + tokenizer->_token_start = text; + utf8iterator_init(parser, text, text_length, &tokenizer->_input); + utf8iterator_get_position(&tokenizer->_input, &tokenizer->_token_start_pos); + doc_type_state_init(parser); +} + +void gumbo_tokenizer_state_destroy(GumboParser* parser) { + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + assert(tokenizer->_doc_type_state.name == NULL); + assert(tokenizer->_doc_type_state.public_identifier == NULL); + assert(tokenizer->_doc_type_state.system_identifier == NULL); + gumbo_string_buffer_destroy(parser, &tokenizer->_temporary_buffer); + gumbo_string_buffer_destroy(parser, &tokenizer->_script_data_buffer); + gumbo_parser_deallocate(parser, tokenizer); +} + +void gumbo_tokenizer_set_state(GumboParser* parser, GumboTokenizerEnum state) { + parser->_tokenizer_state->_state = state; +} + +void gumbo_tokenizer_set_is_current_node_foreign( + GumboParser* parser, bool is_foreign) { + if (is_foreign != parser->_tokenizer_state->_is_current_node_foreign) { + gumbo_debug("Toggling is_current_node_foreign to %s.\n", + is_foreign ? "true" : "false"); + } + parser->_tokenizer_state->_is_current_node_foreign = is_foreign; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#data-state +static StateResult handle_data_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '&': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_DATA); + // The char_ref machinery expects to be on the & so it can mark that + // and return to it if the text isn't a char ref, so we need to + // reconsume it. + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_OPEN); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, '<'); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + emit_char(parser, c, output); + return RETURN_ERROR; + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-data-state +static StateResult handle_char_ref_in_data_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_char_ref(parser, ' ', false, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rcdata-state +static StateResult handle_rcdata_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '&': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_RCDATA); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, '<'); + return NEXT_CHAR; + case '\0': + return emit_replacement_char(parser, output); + case -1: + return emit_eof(parser, output); + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-rcdata-state +static StateResult handle_char_ref_in_rcdata_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA); + return emit_char_ref(parser, ' ', false, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-state +static StateResult handle_rawtext_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, '<'); + return NEXT_CHAR; + case '\0': + return emit_replacement_char(parser, output); + case -1: + return emit_eof(parser, output); + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-state +static StateResult handle_script_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, '<'); + return NEXT_CHAR; + case '\0': + return emit_replacement_char(parser, output); + case -1: + return emit_eof(parser, output); + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#plaintext-state +static StateResult handle_plaintext_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\0': + return emit_replacement_char(parser, output); + case -1: + return emit_eof(parser, output); + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#tag-open-state +static StateResult handle_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "<")); + switch (c) { + case '!': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_MARKUP_DECLARATION); + clear_temporary_buffer(parser); + return NEXT_CHAR; + case '/': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_END_TAG_OPEN); + append_char_to_temporary_buffer(parser, '/'); + return NEXT_CHAR; + case '?': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, '?'); + tokenizer_add_parse_error(parser, GUMBO_ERR_TAG_STARTS_WITH_QUESTION); + return NEXT_CHAR; + default: + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_NAME); + start_new_tag(parser, true); + return NEXT_CHAR; + } else { + tokenizer_add_parse_error(parser, GUMBO_ERR_TAG_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_temporary_buffer(parser, output); + return RETURN_ERROR; + } + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#end-tag-open-state +static StateResult handle_end_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "</")); + switch (c) { + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_EMPTY); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_temporary_buffer(parser, output); + default: + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_TAG_NAME); + start_new_tag(parser, false); + } else { + tokenizer_add_parse_error(parser, GUMBO_ERR_CLOSE_TAG_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, c); + } + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#tag-name-state +static StateResult handle_tag_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_TAG_EOF); + abandon_current_tag(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-less-than-sign-state +static StateResult handle_rcdata_lt_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "<")); + if (c == '/') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_END_TAG_OPEN); + append_char_to_temporary_buffer(parser, '/'); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA); + tokenizer->_reconsume_current_input = true; + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-end-tag-open-state +static StateResult handle_rcdata_end_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "</")); + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA_END_TAG_NAME); + start_new_tag(parser, false); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA); + return emit_temporary_buffer(parser, output); + } + return true; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#rcdata-end-tag-name-state +static StateResult handle_rcdata_end_tag_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(tokenizer->_temporary_buffer.length >= 2); + if (is_alpha(c)) { + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else if (is_appropriate_end_tag(parser)) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + } + } + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RCDATA); + abandon_current_tag(parser); + return emit_temporary_buffer(parser, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-less-than-sign-state +static StateResult handle_rawtext_lt_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "<")); + if (c == '/') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_END_TAG_OPEN); + append_char_to_temporary_buffer(parser, '/'); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT); + tokenizer->_reconsume_current_input = true; + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-end-tag-open-state +static StateResult handle_rawtext_end_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "</")); + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT_END_TAG_NAME); + start_new_tag(parser, false); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT); + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#rawtext-end-tag-name-state +static StateResult handle_rawtext_end_tag_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(tokenizer->_temporary_buffer.length >= 2); + gumbo_debug("Last end tag: %*s\n", (int) tokenizer->_tag_state._buffer.length, + tokenizer->_tag_state._buffer.data); + if (is_alpha(c)) { + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else if (is_appropriate_end_tag(parser)) { + gumbo_debug("Is an appropriate end tag.\n"); + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + } + } + gumbo_tokenizer_set_state(parser, GUMBO_LEX_RAWTEXT); + abandon_current_tag(parser); + return emit_temporary_buffer(parser, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-less-than-sign-state +static StateResult handle_script_lt_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "<")); + if (c == '/') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_END_TAG_OPEN); + append_char_to_temporary_buffer(parser, '/'); + return NEXT_CHAR; + } else if (c == '!') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_START); + append_char_to_temporary_buffer(parser, '!'); + return emit_temporary_buffer(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + tokenizer->_reconsume_current_input = true; + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-end-tag-open-state +static StateResult handle_script_end_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "</")); + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_END_TAG_NAME); + start_new_tag(parser, false); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-end-tag-name-state +static StateResult handle_script_end_tag_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(tokenizer->_temporary_buffer.length >= 2); + if (is_alpha(c)) { + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else if (is_appropriate_end_tag(parser)) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + } + } + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + abandon_current_tag(parser); + return emit_temporary_buffer(parser, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escape-start-state +static StateResult handle_script_escaped_start_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (c == '-') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_START_DASH); + return emit_current_char(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escape-start-dash-state +static StateResult handle_script_escaped_start_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (c == '-') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH); + return emit_current_char(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-state +static StateResult handle_script_escaped_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH); + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + case '\0': + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + return emit_eof(parser, output); + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-dash-state +static StateResult handle_script_escaped_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH); + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + case '\0': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-dash-dash-state +static StateResult handle_script_escaped_dash_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_LT); + clear_temporary_buffer(parser); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + return emit_current_char(parser, output); + case '\0': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-less-than-sign-state +static StateResult handle_script_escaped_lt_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "<")); + assert(!tokenizer->_script_data_buffer.length); + if (c == '/') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START); + append_char_to_temporary_buffer(parser, c); + gumbo_string_buffer_append_codepoint( + parser, ensure_lowercase(c), &tokenizer->_script_data_buffer); + return emit_temporary_buffer(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-end-tag-open-state +static StateResult handle_script_escaped_end_tag_open_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(temporary_buffer_equals(parser, "</")); + if (is_alpha(c)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME); + start_new_tag(parser, false); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + return emit_temporary_buffer(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-escaped-end-tag-name-state +static StateResult handle_script_escaped_end_tag_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(tokenizer->_temporary_buffer.length >= 2); + if (is_alpha(c)) { + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } else if (is_appropriate_end_tag(parser)) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + finish_tag_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + } + } + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + abandon_current_tag(parser); + return emit_temporary_buffer(parser, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escape-start-state +static StateResult handle_script_double_escaped_start_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + case '/': + case '>': + gumbo_tokenizer_set_state( + parser, gumbo_string_equals(&kScriptTag, + (GumboStringPiece*) &tokenizer->_script_data_buffer) + ? GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED + : GUMBO_LEX_SCRIPT_ESCAPED); + return emit_current_char(parser, output); + default: + if (is_alpha(c)) { + gumbo_string_buffer_append_codepoint( + parser, ensure_lowercase(c), &tokenizer->_script_data_buffer); + return emit_current_char(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_ESCAPED); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-state +static StateResult handle_script_double_escaped_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH); + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT); + return emit_current_char(parser, output); + case '\0': + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-dash-state +static StateResult handle_script_double_escaped_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH); + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT); + return emit_current_char(parser, output); + case '\0': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-dash-dash-state +static StateResult handle_script_double_escaped_dash_dash_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '-': + return emit_current_char(parser, output); + case '<': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT); + return emit_current_char(parser, output); + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT); + return emit_current_char(parser, output); + case '\0': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + return emit_replacement_char(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SCRIPT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return NEXT_CHAR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + return emit_current_char(parser, output); + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escaped-less-than-sign-state +static StateResult handle_script_double_escaped_lt_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (c == '/') { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END); + gumbo_string_buffer_clear(parser, &tokenizer->_script_data_buffer); + return emit_current_char(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#script-data-double-escape-end-state +static StateResult handle_script_double_escaped_end_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + case '/': + case '>': + gumbo_tokenizer_set_state( + parser, gumbo_string_equals(&kScriptTag, + (GumboStringPiece*) &tokenizer->_script_data_buffer) + ? GUMBO_LEX_SCRIPT_ESCAPED + : GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + return emit_current_char(parser, output); + default: + if (is_alpha(c)) { + gumbo_string_buffer_append_codepoint( + parser, ensure_lowercase(c), &tokenizer->_script_data_buffer); + return emit_current_char(parser, output); + } else { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-attribute-name-state +static StateResult handle_before_attr_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '/': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME); + append_char_to_temporary_buffer(parser, 0xfffd); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + return NEXT_CHAR; + case '"': + case '\'': + case '<': + case '=': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID); + // Fall through. + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME); + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-name-state +static StateResult handle_attr_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + finish_attribute_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_NAME); + return NEXT_CHAR; + case '/': + finish_attribute_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '=': + finish_attribute_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_VALUE); + return NEXT_CHAR; + case '>': + finish_attribute_name(parser); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true); + return NEXT_CHAR; + case -1: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF); + return NEXT_CHAR; + case '"': + case '\'': + case '<': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID); + // Fall through. + default: + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#after-attribute-name-state +static StateResult handle_after_attr_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '/': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '=': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_VALUE); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME); + append_char_to_temporary_buffer(parser, 0xfffd); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + return NEXT_CHAR; + case '"': + case '\'': + case '<': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_NAME_INVALID); + // Fall through. + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_NAME); + append_char_to_tag_buffer(parser, ensure_lowercase(c), true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-attribute-value-state +static StateResult handle_before_attr_value_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '"': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED); + reset_tag_buffer_start_point(parser); + return NEXT_CHAR; + case '&': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '\'': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED); + reset_tag_buffer_start_point(parser); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_RIGHT_BRACKET); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_current_tag(parser, output); + return RETURN_ERROR; + case '<': + case '=': + case '`': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EQUALS); + // Fall through. + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_ATTR_VALUE_UNQUOTED); + append_char_to_tag_buffer(parser, c, true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-double-quoted-state +static StateResult handle_attr_value_double_quoted_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '"': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED); + return NEXT_CHAR; + case '&': + tokenizer->_tag_state._attr_value_state = tokenizer->_state; + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, false); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_DOUBLE_QUOTE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + default: + append_char_to_tag_buffer(parser, c, false); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-single-quoted-state +static StateResult handle_attr_value_single_quoted_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\'': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED); + return NEXT_CHAR; + case '&': + tokenizer->_tag_state._attr_value_state = tokenizer->_state; + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, false); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_SINGLE_QUOTE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + default: + append_char_to_tag_buffer(parser, c, false); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#attribute-value-unquoted-state +static StateResult handle_attr_value_unquoted_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + finish_attribute_value(parser); + return NEXT_CHAR; + case '&': + tokenizer->_tag_state._attr_value_state = tokenizer->_state; + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + finish_attribute_value(parser); + return emit_current_tag(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_tag_buffer(parser, kUtf8ReplacementChar, true); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_reconsume_current_input = true; + abandon_current_tag(parser); + return NEXT_CHAR; + case '<': + case '=': + case '"': + case '\'': + case '`': + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_UNQUOTED_EQUALS); + // Fall through. + default: + append_char_to_tag_buffer(parser, c, true); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#character-reference-in-attribute-value-state +static StateResult handle_char_ref_in_attr_value_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + OneOrTwoCodepoints char_ref; + int allowed_char; + bool is_unquoted = false; + switch (tokenizer->_tag_state._attr_value_state) { + case GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED: + allowed_char = '"'; + break; + case GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED: + allowed_char = '\''; + break; + case GUMBO_LEX_ATTR_VALUE_UNQUOTED: + allowed_char = '>'; + is_unquoted = true; + break; + default: + // -Wmaybe-uninitialized is a little overzealous here, and doesn't + // get that the assert(0) means this codepath will never happen. + allowed_char = ' '; + assert(0); + } + + // Ignore the status, since we don't have a convenient way of signalling that + // a parser error has occurred when the error occurs in the middle of a + // multi-state token. We'd need a flag inside the TokenizerState to do this, + // but that's a low priority fix. + consume_char_ref(parser, &tokenizer->_input, allowed_char, true, &char_ref); + if (char_ref.first != kGumboNoChar) { + tokenizer->_reconsume_current_input = true; + append_char_to_tag_buffer(parser, char_ref.first, is_unquoted); + if (char_ref.second != kGumboNoChar) { + append_char_to_tag_buffer(parser, char_ref.second, is_unquoted); + } + } else { + append_char_to_tag_buffer(parser, '&', is_unquoted); + } + gumbo_tokenizer_set_state(parser, tokenizer->_tag_state._attr_value_state); + return NEXT_CHAR; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#after-attribute-value-quoted-state +static StateResult handle_after_attr_value_quoted_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + finish_attribute_value(parser); + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + return NEXT_CHAR; + case '/': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_SELF_CLOSING_START_TAG); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_current_tag(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_AFTER_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_ATTR_AFTER_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#self-closing-start-tag-state +static StateResult handle_self_closing_start_tag_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_tag_state._is_self_closing = true; + return emit_current_tag(parser, output); + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_SOLIDUS_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + abandon_current_tag(parser); + return NEXT_CHAR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_SOLIDUS_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_ATTR_NAME); + tokenizer->_reconsume_current_input = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#bogus-comment-state +static StateResult handle_bogus_comment_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + while (c != '>' && c != -1) { + if (c == '\0') { + c = 0xFFFD; + } + append_char_to_temporary_buffer(parser, c); + utf8iterator_next(&tokenizer->_input); + c = utf8iterator_current(&tokenizer->_input); + } + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_comment(parser, output); +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#markup-declaration-open-state +static StateResult handle_markup_declaration_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (utf8iterator_maybe_consume_match( + &tokenizer->_input, "--", sizeof("--") - 1, true)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_START); + tokenizer->_reconsume_current_input = true; + } else if (utf8iterator_maybe_consume_match( + &tokenizer->_input, "DOCTYPE", sizeof("DOCTYPE") - 1, false)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE); + tokenizer->_reconsume_current_input = true; + // If we get here, we know we'll eventually emit a doctype token, so now is + // the time to initialize the doctype strings. (Not in doctype_state_init, + // since then they'll leak if ownership never gets transferred to the + // doctype token. + tokenizer->_doc_type_state.name = gumbo_copy_stringz(parser, ""); + tokenizer->_doc_type_state.public_identifier = + gumbo_copy_stringz(parser, ""); + tokenizer->_doc_type_state.system_identifier = + gumbo_copy_stringz(parser, ""); + } else if (tokenizer->_is_current_node_foreign && + utf8iterator_maybe_consume_match( + &tokenizer->_input, "[CDATA[", sizeof("[CDATA[") - 1, true)) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_CDATA); + tokenizer->_is_in_cdata = true; + tokenizer->_reconsume_current_input = true; + } else { + tokenizer_add_parse_error(parser, GUMBO_ERR_DASHES_OR_DOCTYPE); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_COMMENT); + tokenizer->_reconsume_current_input = true; + clear_temporary_buffer(parser); + } + return NEXT_CHAR; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-start-state +static StateResult handle_comment_start_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_START_DASH); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-start-dash-state +static StateResult handle_comment_start_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-state +static StateResult handle_comment_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_DASH); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-dash-state +static StateResult handle_comment_end_dash_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-state +static StateResult handle_comment_end_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_comment(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '!': + tokenizer_add_parse_error( + parser, GUMBO_ERR_COMMENT_BANG_AFTER_DOUBLE_DASH); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_BANG); + return NEXT_CHAR; + case '-': + tokenizer_add_parse_error( + parser, GUMBO_ERR_COMMENT_DASH_AFTER_DOUBLE_DASH); + append_char_to_temporary_buffer(parser, '-'); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#comment-end-bang-state +static StateResult handle_comment_end_bang_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '-': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT_END_DASH); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '!'); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + return emit_comment(parser, output); + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '!'); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_COMMENT_END_BANG_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_comment(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_COMMENT); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '-'); + append_char_to_temporary_buffer(parser, '!'); + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#doctype-state +static StateResult handle_doctype_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + assert(!tokenizer->_temporary_buffer.length); + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_NAME); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_SPACE); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_NAME); + tokenizer->_reconsume_current_input = true; + tokenizer->_doc_type_state.force_quirks = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#before-doctype-name-state +static StateResult handle_before_doctype_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME); + tokenizer->_doc_type_state.force_quirks = true; + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_RIGHT_BRACKET); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME); + tokenizer->_doc_type_state.force_quirks = false; + append_char_to_temporary_buffer(parser, ensure_lowercase(c)); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete5/tokenization.html#doctype-name-state +static StateResult handle_doctype_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_NAME); + gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name); + finish_temporary_buffer(parser, &tokenizer->_doc_type_state.name); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name); + finish_temporary_buffer(parser, &tokenizer->_doc_type_state.name); + emit_doctype(parser, output); + return RETURN_SUCCESS; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + gumbo_parser_deallocate(parser, (void*) tokenizer->_doc_type_state.name); + finish_temporary_buffer(parser, &tokenizer->_doc_type_state.name); + emit_doctype(parser, output); + return RETURN_ERROR; + default: + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DOCTYPE_NAME); + tokenizer->_doc_type_state.force_quirks = false; + append_char_to_temporary_buffer(parser, ensure_lowercase(c)); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-name-state +static StateResult handle_after_doctype_name_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_doctype(parser, output); + return RETURN_SUCCESS; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + if (utf8iterator_maybe_consume_match( + &tokenizer->_input, "PUBLIC", sizeof("PUBLIC") - 1, false)) { + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD); + tokenizer->_reconsume_current_input = true; + } else if (utf8iterator_maybe_consume_match(&tokenizer->_input, "SYSTEM", + sizeof("SYSTEM") - 1, false)) { + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD); + tokenizer->_reconsume_current_input = true; + } else { + tokenizer_add_parse_error( + parser, GUMBO_ERR_DOCTYPE_SPACE_OR_RIGHT_BRACKET); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + } + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-public-keyword-state +static StateResult handle_after_doctype_public_keyword_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID); + return NEXT_CHAR; + case '"': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_RIGHT_BRACKET); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#before-doctype-public-identifier-state +static StateResult handle_before_doctype_public_id_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '"': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-public-identifier-(double-quoted)-state +static StateResult handle_doctype_public_id_double_quoted_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '"': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID); + finish_doctype_public_id(parser); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_public_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_public_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + default: + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-public-identifier-(single-quoted)-state +static StateResult handle_doctype_public_id_single_quoted_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '\'': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID); + finish_doctype_public_id(parser); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_public_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_public_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + default: + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-public-identifier-state +static StateResult handle_after_doctype_public_id_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID); + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_doctype(parser, output); + return RETURN_SUCCESS; + case '"': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_reconsume_current_input = true; + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#between-doctype-public-and-system-identifiers-state +static StateResult handle_between_doctype_public_system_id_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_doctype(parser, output); + return RETURN_SUCCESS; + case '"': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-system-keyword-state +static StateResult handle_after_doctype_system_keyword_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID); + return NEXT_CHAR; + case '"': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#before-doctype-system-identifier-state +static StateResult handle_before_doctype_system_id_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '"': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED); + return NEXT_CHAR; + case '\'': + assert(temporary_buffer_equals(parser, "")); + gumbo_tokenizer_set_state( + parser, GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + tokenizer->_doc_type_state.force_quirks = true; + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-system-identifier-(double-quoted)-state +static StateResult handle_doctype_system_id_double_quoted_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '"': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID); + finish_doctype_system_id(parser); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_system_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_system_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + default: + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#doctype-system-identifier-(single-quoted)-state +static StateResult handle_doctype_system_id_single_quoted_state( + GumboParser* parser, GumboTokenizerState* tokenizer, int c, + GumboToken* output) { + switch (c) { + case '\'': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID); + finish_doctype_system_id(parser); + return NEXT_CHAR; + case '\0': + tokenizer_add_parse_error(parser, GUMBO_ERR_UTF8_NULL); + append_char_to_temporary_buffer(parser, kUtf8ReplacementChar); + return NEXT_CHAR; + case '>': + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_END); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_system_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + finish_doctype_system_id(parser); + emit_doctype(parser, output); + return RETURN_ERROR; + default: + append_char_to_temporary_buffer(parser, c); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#after-doctype-system-identifier-state +static StateResult handle_after_doctype_system_id_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + switch (c) { + case '\t': + case '\n': + case '\f': + case ' ': + return NEXT_CHAR; + case '>': + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_doctype(parser, output); + return RETURN_SUCCESS; + case -1: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_EOF); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_doc_type_state.force_quirks = true; + emit_doctype(parser, output); + return RETURN_ERROR; + default: + tokenizer_add_parse_error(parser, GUMBO_ERR_DOCTYPE_INVALID); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_BOGUS_DOCTYPE); + return NEXT_CHAR; + } +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#bogus-doctype-state +static StateResult handle_bogus_doctype_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (c == '>' || c == -1) { + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + emit_doctype(parser, output); + return RETURN_ERROR; + } + return NEXT_CHAR; +} + +// http://www.whatwg.org/specs/web-apps/current-work/complete.html#cdata-section-state +static StateResult handle_cdata_state(GumboParser* parser, + GumboTokenizerState* tokenizer, int c, GumboToken* output) { + if (c == -1 || utf8iterator_maybe_consume_match( + &tokenizer->_input, "]]>", sizeof("]]>") - 1, true)) { + tokenizer->_reconsume_current_input = true; + reset_token_start_point(tokenizer); + gumbo_tokenizer_set_state(parser, GUMBO_LEX_DATA); + tokenizer->_is_in_cdata = false; + return NEXT_CHAR; + } else { + return emit_current_char(parser, output); + } +} + +typedef StateResult (*GumboLexerStateFunction)( + GumboParser*, GumboTokenizerState*, int, GumboToken*); + +static GumboLexerStateFunction dispatch_table[] = {handle_data_state, + handle_char_ref_in_data_state, handle_rcdata_state, + handle_char_ref_in_rcdata_state, handle_rawtext_state, handle_script_state, + handle_plaintext_state, handle_tag_open_state, handle_end_tag_open_state, + handle_tag_name_state, handle_rcdata_lt_state, + handle_rcdata_end_tag_open_state, handle_rcdata_end_tag_name_state, + handle_rawtext_lt_state, handle_rawtext_end_tag_open_state, + handle_rawtext_end_tag_name_state, handle_script_lt_state, + handle_script_end_tag_open_state, handle_script_end_tag_name_state, + handle_script_escaped_start_state, handle_script_escaped_start_dash_state, + handle_script_escaped_state, handle_script_escaped_dash_state, + handle_script_escaped_dash_dash_state, handle_script_escaped_lt_state, + handle_script_escaped_end_tag_open_state, + handle_script_escaped_end_tag_name_state, + handle_script_double_escaped_start_state, + handle_script_double_escaped_state, handle_script_double_escaped_dash_state, + handle_script_double_escaped_dash_dash_state, + handle_script_double_escaped_lt_state, + handle_script_double_escaped_end_state, handle_before_attr_name_state, + handle_attr_name_state, handle_after_attr_name_state, + handle_before_attr_value_state, handle_attr_value_double_quoted_state, + handle_attr_value_single_quoted_state, handle_attr_value_unquoted_state, + handle_char_ref_in_attr_value_state, handle_after_attr_value_quoted_state, + handle_self_closing_start_tag_state, handle_bogus_comment_state, + handle_markup_declaration_state, handle_comment_start_state, + handle_comment_start_dash_state, handle_comment_state, + handle_comment_end_dash_state, handle_comment_end_state, + handle_comment_end_bang_state, handle_doctype_state, + handle_before_doctype_name_state, handle_doctype_name_state, + handle_after_doctype_name_state, handle_after_doctype_public_keyword_state, + handle_before_doctype_public_id_state, + handle_doctype_public_id_double_quoted_state, + handle_doctype_public_id_single_quoted_state, + handle_after_doctype_public_id_state, + handle_between_doctype_public_system_id_state, + handle_after_doctype_system_keyword_state, + handle_before_doctype_system_id_state, + handle_doctype_system_id_double_quoted_state, + handle_doctype_system_id_single_quoted_state, + handle_after_doctype_system_id_state, handle_bogus_doctype_state, + handle_cdata_state}; + +bool gumbo_lex(GumboParser* parser, GumboToken* output) { + // Because of the spec requirements that... + // + // 1. Tokens be handled immediately by the parser upon emission. + // 2. Some states (eg. CDATA, or various error conditions) require the + // emission of multiple tokens in the same states. + // 3. The tokenizer often has to reconsume the same character in a different + // state. + // + // ...all state must be held in the GumboTokenizer struct instead of in local + // variables in this function. That allows us to return from this method with + // a token, and then immediately jump back to the same state with the same + // input if we need to return a different token. The various emit_* functions + // are responsible for changing state (eg. flushing the chardata buffer, + // reading the next input character) to avoid an infinite loop. + GumboTokenizerState* tokenizer = parser->_tokenizer_state; + + if (tokenizer->_buffered_emit_char != kGumboNoChar) { + tokenizer->_reconsume_current_input = true; + emit_char(parser, tokenizer->_buffered_emit_char, output); + // And now that we've avoided advancing the input, make sure we set + // _reconsume_current_input back to false to make sure the *next* character + // isn't consumed twice. + tokenizer->_reconsume_current_input = false; + tokenizer->_buffered_emit_char = kGumboNoChar; + return true; + } + + if (maybe_emit_from_temporary_buffer(parser, output)) { + return true; + } + + while (1) { + assert(!tokenizer->_temporary_buffer_emit); + assert(tokenizer->_buffered_emit_char == kGumboNoChar); + int c = utf8iterator_current(&tokenizer->_input); + gumbo_debug( + "Lexing character '%c' (%d) in state %d.\n", c, c, tokenizer->_state); + StateResult result = + dispatch_table[tokenizer->_state](parser, tokenizer, c, output); + // We need to clear reconsume_current_input before returning to prevent + // certain infinite loop states. + bool should_advance = !tokenizer->_reconsume_current_input; + tokenizer->_reconsume_current_input = false; + + if (result == RETURN_SUCCESS) { + return true; + } else if (result == RETURN_ERROR) { + return false; + } + + if (should_advance) { + utf8iterator_next(&tokenizer->_input); + } + } +} + +void gumbo_token_destroy(GumboParser* parser, GumboToken* token) { + if (!token) return; + + switch (token->type) { + case GUMBO_TOKEN_DOCTYPE: + gumbo_parser_deallocate(parser, (void*) token->v.doc_type.name); + gumbo_parser_deallocate( + parser, (void*) token->v.doc_type.public_identifier); + gumbo_parser_deallocate( + parser, (void*) token->v.doc_type.system_identifier); + return; + case GUMBO_TOKEN_START_TAG: + for (unsigned int i = 0; i < token->v.start_tag.attributes.length; ++i) { + GumboAttribute* attr = token->v.start_tag.attributes.data[i]; + if (attr) { + // May have been nulled out if this token was merged with another. + gumbo_destroy_attribute(parser, attr); + } + } + gumbo_parser_deallocate( + parser, (void*) token->v.start_tag.attributes.data); + return; + case GUMBO_TOKEN_COMMENT: + gumbo_parser_deallocate(parser, (void*) token->v.text); + return; + default: + return; + } +} diff --git a/libs/litehtml/src/gumbo/utf8.c b/libs/litehtml/src/gumbo/utf8.c new file mode 100644 index 0000000000..ad73cefa6a --- /dev/null +++ b/libs/litehtml/src/gumbo/utf8.c @@ -0,0 +1,270 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "utf8.h" + +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> // For strncasecmp. + +#include "error.h" +#include "gumbo.h" +#include "parser.h" +#include "util.h" +#include "vector.h" + +const int kUtf8ReplacementChar = 0xFFFD; + +// Reference material: +// Wikipedia: http://en.wikipedia.org/wiki/UTF-8#Description +// RFC 3629: http://tools.ietf.org/html/rfc3629 +// HTML5 Unicode handling: +// http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#preprocessing-the-input-stream +// +// This implementation is based on a DFA-based decoder by Bjoern Hoehrmann +// <bjoern@hoehrmann.de>. We wrap the inner table-based decoder routine in our +// own handling for newlines, tabs, invalid continuation bytes, and other +// conditions that the HTML5 spec fully specifies but normal UTF8 decoders do +// not handle. +// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. Full text of +// the license agreement and code follows. + +// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to +// do +// so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 12 + +static const uint8_t utf8d[] = { + // The first part of the table maps bytes to character classes that + // to reduce the size of the transition table and create bitmasks. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, + + // The second part is a transition table that maps a combination + // of a state of the automaton and a character class to a state. + 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, + 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, + 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, + 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +}; + +uint32_t static inline decode(uint32_t* state, uint32_t* codep, uint32_t byte) { + uint32_t type = utf8d[byte]; + + *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) + : (0xff >> type) & (byte); + + *state = utf8d[256 + *state + type]; + return *state; +} + +// END COPIED CODE. + +// Adds a decoding error to the parser's error list, based on the current state +// of the Utf8Iterator. +static void add_error(Utf8Iterator* iter, GumboErrorType type) { + GumboParser* parser = iter->_parser; + + GumboError* error = gumbo_add_error(parser); + if (!error) { + return; + } + error->type = type; + error->position = iter->_pos; + error->original_text = iter->_start; + + // At the point the error is recorded, the code point hasn't been computed + // yet (and can't be, because it's invalid), so we need to build up the raw + // hex value from the bytes under the cursor. + uint64_t code_point = 0; + for (int i = 0; i < iter->_width; ++i) { + code_point = (code_point << 8) | (unsigned char) iter->_start[i]; + } + error->v.codepoint = code_point; +} + +// Reads the next UTF-8 character in the iter. +// This assumes that iter->_start points to the beginning of the character. +// When this method returns, iter->_width and iter->_current will be set +// appropriately, as well as any error flags. +static void read_char(Utf8Iterator* iter) { + if (iter->_start >= iter->_end) { + // No input left to consume; emit an EOF and set width = 0. + iter->_current = -1; + iter->_width = 0; + return; + } + + uint32_t code_point = 0; + uint32_t state = UTF8_ACCEPT; + for (const char* c = iter->_start; c < iter->_end; ++c) { + decode(&state, &code_point, (uint32_t)(unsigned char) (*c)); + if (state == UTF8_ACCEPT) { + iter->_width = (int)(c - iter->_start + 1); + // This is the special handling for carriage returns that is mandated by + // the HTML5 spec. Since we're looking for particular 7-bit literal + // characters, we operate in terms of chars and only need a check for iter + // overrun, instead of having to read in a full next code point. + // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#preprocessing-the-input-stream + if (code_point == '\r') { + assert(iter->_width == 1); + const char* next = c + 1; + if (next < iter->_end && *next == '\n') { + // Advance the iter, as if the carriage return didn't exist. + ++iter->_start; + // Preserve the true offset, since other tools that look at it may be + // unaware of HTML5's rules for converting \r into \n. + ++iter->_pos.offset; + } + code_point = '\n'; + } + if (utf8_is_invalid_code_point(code_point)) { + add_error(iter, GUMBO_ERR_UTF8_INVALID); + code_point = kUtf8ReplacementChar; + } + iter->_current = code_point; + return; + } else if (state == UTF8_REJECT) { + // We don't want to consume the invalid continuation byte of a multi-byte + // run, but we do want to skip past an invalid first byte. + iter->_width = c - iter->_start + (c == iter->_start); + iter->_current = kUtf8ReplacementChar; + add_error(iter, GUMBO_ERR_UTF8_INVALID); + return; + } + } + // If we got here without exiting early, then we've reached the end of the + // iterator. Add an error for truncated input, set the width to consume the + // rest of the iterator, and emit a replacement character. The next time we + // enter this method, it will detect that there's no input to consume and + // output an EOF. + iter->_current = kUtf8ReplacementChar; + iter->_width = iter->_end - iter->_start; + add_error(iter, GUMBO_ERR_UTF8_TRUNCATED); +} + +static void update_position(Utf8Iterator* iter) { + iter->_pos.offset += (int)iter->_width; + if (iter->_current == '\n') { + ++iter->_pos.line; + iter->_pos.column = 1; + } else if (iter->_current == '\t') { + int tab_stop = iter->_parser->_options->tab_stop; + iter->_pos.column = ((iter->_pos.column / tab_stop) + 1) * tab_stop; + } else if (iter->_current != -1) { + ++iter->_pos.column; + } +} + +// Returns true if this Unicode code point is in the list of characters +// forbidden by the HTML5 spec, such as undefined control chars. +bool utf8_is_invalid_code_point(int c) { + return (c >= 0x1 && c <= 0x8) || c == 0xB || (c >= 0xE && c <= 0x1F) || + (c >= 0x7F && c <= 0x9F) || (c >= 0xFDD0 && c <= 0xFDEF) || + ((c & 0xFFFF) == 0xFFFE) || ((c & 0xFFFF) == 0xFFFF); +} + +void utf8iterator_init(GumboParser* parser, const char* source, + size_t source_length, Utf8Iterator* iter) { + iter->_start = source; + iter->_end = source + source_length; + iter->_pos.line = 1; + iter->_pos.column = 1; + iter->_pos.offset = 0; + iter->_parser = parser; + read_char(iter); +} + +void utf8iterator_next(Utf8Iterator* iter) { + // We update positions based on the *last* character read, so that the first + // character following a newline is at column 1 in the next line. + update_position(iter); + iter->_start += iter->_width; + read_char(iter); +} + +int utf8iterator_current(const Utf8Iterator* iter) { return iter->_current; } + +void utf8iterator_get_position( + const Utf8Iterator* iter, GumboSourcePosition* output) { + *output = iter->_pos; +} + +const char* utf8iterator_get_char_pointer(const Utf8Iterator* iter) { + return iter->_start; +} + +const char* utf8iterator_get_end_pointer(const Utf8Iterator* iter) { + return iter->_end; +} + +bool utf8iterator_maybe_consume_match(Utf8Iterator* iter, const char* prefix, + size_t length, bool case_sensitive) { + bool matched = (iter->_start + length <= iter->_end) && + (case_sensitive ? !strncmp(iter->_start, prefix, length) + : !strncasecmp(iter->_start, prefix, length)); + if (matched) { + for (unsigned int i = 0; i < length; ++i) { + utf8iterator_next(iter); + } + return true; + } else { + return false; + } +} + +void utf8iterator_mark(Utf8Iterator* iter) { + iter->_mark = iter->_start; + iter->_mark_pos = iter->_pos; +} + +// Returns the current input stream position to the mark. +void utf8iterator_reset(Utf8Iterator* iter) { + iter->_start = iter->_mark; + iter->_pos = iter->_mark_pos; + read_char(iter); +} + +// Sets the position and original text fields of an error to the value at the +// mark. +void utf8iterator_fill_error_at_mark(Utf8Iterator* iter, GumboError* error) { + error->position = iter->_mark_pos; + error->original_text = iter->_mark; +} diff --git a/libs/litehtml/src/gumbo/util.c b/libs/litehtml/src/gumbo/util.c new file mode 100644 index 0000000000..5a24c115e6 --- /dev/null +++ b/libs/litehtml/src/gumbo/util.c @@ -0,0 +1,58 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "util.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdarg.h> +#include <stdio.h> + +#include "gumbo.h" +#include "parser.h" + +// TODO(jdtang): This should be elsewhere, but there's no .c file for +// SourcePositions and yet the constant needs some linkage, so this is as good +// as any. +const GumboSourcePosition kGumboEmptySourcePosition = {0, 0, 0}; + +void* gumbo_parser_allocate(GumboParser* parser, size_t num_bytes) { + return parser->_options->allocator(parser->_options->userdata, num_bytes); +} + +void gumbo_parser_deallocate(GumboParser* parser, void* ptr) { + parser->_options->deallocator(parser->_options->userdata, ptr); +} + +char* gumbo_copy_stringz(GumboParser* parser, const char* str) { + char* buffer = gumbo_parser_allocate(parser, strlen(str) + 1); + strcpy(buffer, str); + return buffer; +} + +// Debug function to trace operation of the parser. Pass --copts=-DGUMBO_DEBUG +// to use. +void gumbo_debug(const char* format, ...) { +#ifdef GUMBO_DEBUG + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + fflush(stdout); +#endif +} diff --git a/libs/litehtml/src/gumbo/vector.c b/libs/litehtml/src/gumbo/vector.c new file mode 100644 index 0000000000..b9aa474e67 --- /dev/null +++ b/libs/litehtml/src/gumbo/vector.c @@ -0,0 +1,123 @@ +// Copyright 2010 Google Inc. 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. +// +// Author: jdtang@google.com (Jonathan Tang) + +#include "vector.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "util.h" + +struct GumboInternalParser; + +const GumboVector kGumboEmptyVector = {NULL, 0, 0}; + +void gumbo_vector_init(struct GumboInternalParser* parser, + size_t initial_capacity, GumboVector* vector) { + vector->length = 0; + vector->capacity = (unsigned)initial_capacity; + if (initial_capacity > 0) { + vector->data = + gumbo_parser_allocate(parser, sizeof(void*) * initial_capacity); + } else { + vector->data = NULL; + } +} + +void gumbo_vector_destroy( + struct GumboInternalParser* parser, GumboVector* vector) { + if (vector->capacity > 0) { + gumbo_parser_deallocate(parser, vector->data); + } +} + +static void enlarge_vector_if_full( + struct GumboInternalParser* parser, GumboVector* vector) { + if (vector->length >= vector->capacity) { + if (vector->capacity) { + size_t old_num_bytes = sizeof(void*) * vector->capacity; + vector->capacity *= 2; + size_t num_bytes = sizeof(void*) * vector->capacity; + void** temp = gumbo_parser_allocate(parser, num_bytes); + memcpy(temp, vector->data, old_num_bytes); + gumbo_parser_deallocate(parser, vector->data); + vector->data = temp; + } else { + // 0-capacity vector; no previous array to deallocate. + vector->capacity = 2; + vector->data = + gumbo_parser_allocate(parser, sizeof(void*) * vector->capacity); + } + } +} + +void gumbo_vector_add( + struct GumboInternalParser* parser, void* element, GumboVector* vector) { + enlarge_vector_if_full(parser, vector); + assert(vector->data); + assert(vector->length < vector->capacity); + vector->data[vector->length++] = element; +} + +void* gumbo_vector_pop( + struct GumboInternalParser* parser, GumboVector* vector) { + if (vector->length == 0) { + return NULL; + } + return vector->data[--vector->length]; +} + +int gumbo_vector_index_of(GumboVector* vector, const void* element) { + for (unsigned int i = 0; i < vector->length; ++i) { + if (vector->data[i] == element) { + return i; + } + } + return -1; +} + +void gumbo_vector_insert_at(struct GumboInternalParser* parser, void* element, + unsigned int index, GumboVector* vector) { + assert(index >= 0); + assert(index <= vector->length); + enlarge_vector_if_full(parser, vector); + ++vector->length; + memmove(&vector->data[index + 1], &vector->data[index], + sizeof(void*) * (vector->length - index - 1)); + vector->data[index] = element; +} + +void gumbo_vector_remove( + struct GumboInternalParser* parser, void* node, GumboVector* vector) { + int index = gumbo_vector_index_of(vector, node); + if (index == -1) { + return; + } + gumbo_vector_remove_at(parser, index, vector); +} + +void* gumbo_vector_remove_at(struct GumboInternalParser* parser, + unsigned int index, GumboVector* vector) { + assert(index >= 0); + assert(index < vector->length); + void* result = vector->data[index]; + memmove(&vector->data[index], &vector->data[index + 1], + sizeof(void*) * (vector->length - index - 1)); + --vector->length; + return result; +} diff --git a/libs/litehtml/src/gumbo/visualc/include/strings.h b/libs/litehtml/src/gumbo/visualc/include/strings.h new file mode 100644 index 0000000000..59750dec1d --- /dev/null +++ b/libs/litehtml/src/gumbo/visualc/include/strings.h @@ -0,0 +1,4 @@ +/*Dummy file to satisfy source file dependencies on Windows platform*/ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define inline __inline diff --git a/libs/litehtml/src/html.cpp b/libs/litehtml/src/html.cpp new file mode 100644 index 0000000000..a4632f8602 --- /dev/null +++ b/libs/litehtml/src/html.cpp @@ -0,0 +1,290 @@ +#include "html.h" +#include "types.h" +#include "utf8_strings.h" + +void litehtml::trim(string &s, const string& chars_to_trim) +{ + string::size_type pos = s.find_first_not_of(chars_to_trim); + if(pos != string::npos) + { + s.erase(s.begin(), s.begin() + pos); + } + else + { + s = ""; + return; + } + pos = s.find_last_not_of(chars_to_trim); + if(pos != string::npos) + { + s.erase(s.begin() + pos + 1, s.end()); + } +} + +void litehtml::lcase(string &s) +{ + for(char & i : s) + { + i = t_tolower(i); + } +} + +litehtml::string::size_type litehtml::find_close_bracket(const string &s, string::size_type off, char open_b, char close_b) +{ + int cnt = 0; + for(string::size_type i = off; i < s.length(); i++) + { + if(s[i] == open_b) + { + cnt++; + } else if(s[i] == close_b) + { + cnt--; + if(!cnt) + { + return i; + } + } + } + return string::npos; +} + +litehtml::string litehtml::index_value(int index, const string& strings, char delim) +{ + std::vector<string> vals; + string delims; + delims.push_back(delim); + split_string(strings, vals, delims); + if(index >= 0 && index < (int) vals.size()) + { + return vals[index]; + } + return std::to_string(index); +} + +int litehtml::value_index( const string& val, const string& strings, int defValue, char delim ) +{ + if(val.empty() || strings.empty() || !delim) + { + return defValue; + } + + int idx = 0; + string::size_type delim_start = 0; + string::size_type delim_end = strings.find(delim, delim_start); + string::size_type item_len; + while(true) + { + if(delim_end == string::npos) + { + item_len = strings.length() - delim_start; + } else + { + item_len = delim_end - delim_start; + } + if(item_len == val.length()) + { + if(val == strings.substr(delim_start, item_len)) + { + return idx; + } + } + idx++; + delim_start = delim_end; + if(delim_start == string::npos) break; + delim_start++; + if(delim_start == strings.length()) break; + delim_end = strings.find(delim, delim_start); + } + return defValue; +} + +bool litehtml::value_in_list( const string& val, const string& strings, char delim ) +{ + int idx = value_index(val, strings, -1, delim); + if(idx >= 0) + { + return true; + } + return false; +} + +void litehtml::split_string(const string& str, string_vector& tokens, const string& delims, const string& delims_preserve, const string& quote) +{ + if(str.empty() || (delims.empty() && delims_preserve.empty())) + { + return; + } + + string all_delims = delims + delims_preserve + quote; + + string::size_type token_start = 0; + string::size_type token_end = str.find_first_of(all_delims, token_start); + string::size_type token_len; + string token; + while(true) + { + while( token_end != string::npos && quote.find_first_of(str[token_end]) != string::npos ) + { + if(str[token_end] == '(') + { + token_end = find_close_bracket(str, token_end, '(', ')'); + } else if(str[token_end] == '[') + { + token_end = find_close_bracket(str, token_end, '[', ']'); + } else if(str[token_end] == '{') + { + token_end = find_close_bracket(str, token_end, '{', '}'); + } else + { + token_end = str.find_first_of(str[token_end], token_end + 1); + } + if(token_end != string::npos) + { + token_end = str.find_first_of(all_delims, token_end + 1); + } + } + + if(token_end == string::npos) + { + token_len = string::npos; + } else + { + token_len = token_end - token_start; + } + + token = str.substr(token_start, token_len); + if(!token.empty()) + { + tokens.push_back( token ); + } + if(token_end != string::npos && !delims_preserve.empty() && delims_preserve.find_first_of(str[token_end]) != string::npos) + { + tokens.push_back( str.substr(token_end, 1) ); + } + + token_start = token_end; + if(token_start == string::npos) break; + token_start++; + if(token_start == str.length()) break; + token_end = str.find_first_of(all_delims, token_start); + } +} + +void litehtml::join_string(string& str, const string_vector& tokens, const string& delims) +{ + str = ""; + for (size_t i = 0; i < tokens.size(); i++) + { + if (i != 0) + { + str += delims; + } + str += tokens[i]; + } +} + +int litehtml::t_strcasecmp(const char *s1, const char *s2) +{ + int i, d, c; + + for (i = 0;; i++) + { + c = t_tolower((unsigned char)s1[i]); + d = c - t_tolower((unsigned char)s2[i]); + if (d < 0) + return -1; + else if (d > 0) + return 1; + else if (c == 0) + return 0; + } +} + +int litehtml::t_strncasecmp(const char *s1, const char *s2, size_t n) +{ + int i, d, c; + + for (i = 0; i < (int) n; i++) + { + c = t_tolower((unsigned char)s1[i]); + d = c - t_tolower((unsigned char)s2[i]); + if (d < 0) + return -1; + else if (d > 0) + return 1; + else if (c == 0) + return 0; + } + + return 0; +} + +litehtml::string litehtml::get_escaped_string(const string& in_str) +{ + string ret; + for (auto ch : in_str) + { + switch (ch) + { + case '\'': + ret += "\\'"; + break; + + case '\"': + ret += "\\\""; + break; + + case '\?': + ret += "\\?"; + break; + + case '\\': + ret += "\\\\"; + break; + + case '\a': + ret += "\\a"; + break; + + case '\b': + ret += "\\b"; + break; + + case '\f': + ret += "\\f"; + break; + + case '\n': + ret += "\\n"; + break; + + case '\r': + ret += "\\r"; + break; + + case '\t': + ret += "\\t"; + break; + + case '\v': + ret += "\\v"; + break; + + default: + ret += ch; + } + } + return ret; +} + +bool litehtml::is_number(const string& string, const bool allow_dot) { + for (auto ch : string) + { + if (!(t_isdigit(ch) || (allow_dot && ch == '.'))) + { + return false; + } + } + return true; +} diff --git a/libs/litehtml/src/html_tag.cpp b/libs/litehtml/src/html_tag.cpp new file mode 100644 index 0000000000..231b368c06 --- /dev/null +++ b/libs/litehtml/src/html_tag.cpp @@ -0,0 +1,1711 @@ +#include "html.h" +#include "html_tag.h" +#include "document.h" +#include "iterators.h" +#include "stylesheet.h" +#include "table.h" +#include <algorithm> +#include <locale> +#include "el_before_after.h" +#include "num_cvt.h" +#include "line_box.h" +#include <stack> +#include "render_item.h" + +litehtml::html_tag::html_tag(const std::shared_ptr<document>& doc) : element(doc) +{ + m_tag = empty_id; + m_id = empty_id; +} + +litehtml::html_tag::html_tag(const element::ptr& parent, const string& style) : element(parent->get_document()), + m_tag(empty_id), + m_id(empty_id) +{ + litehtml::style st; + st.add(style); + add_style(st); + this->parent(parent); + compute_styles(); +} + +bool litehtml::html_tag::appendChild(const element::ptr &el) +{ + if(el) + { + el->parent(shared_from_this()); + m_children.push_back(el); + return true; + } + return false; +} + +bool litehtml::html_tag::removeChild(const element::ptr &el) +{ + if(el && el->parent() == shared_from_this()) + { + el->parent(nullptr); + m_children.erase(std::remove(m_children.begin(), m_children.end(), el), m_children.end()); + return true; + } + return false; +} + +void litehtml::html_tag::clearRecursive() +{ + for(auto& el : m_children) + { + el->clearRecursive(); + el->parent(nullptr); + } + m_children.clear(); +} + +litehtml::string_id litehtml::html_tag::id() const +{ + return m_id; +} + +litehtml::string_id litehtml::html_tag::tag() const +{ + return m_tag; +} + +const char* litehtml::html_tag::get_tagName() const +{ + return _s(m_tag).c_str(); +} + +void litehtml::html_tag::set_tagName( const char* _tag ) +{ + string tag = _tag; + lcase(tag); + m_tag = _id(tag); +} + +void litehtml::html_tag::set_attr( const char* _name, const char* _val ) +{ + if(_name && _val) + { + string name = _name; + lcase(name); + m_attrs[name] = _val; + + if( name == "class" ) + { + string val = _val; + // class names are matched case-insensitively in quirks mode + // we match them case-insensitively in all modes (same for id) + lcase(val); + m_str_classes.resize( 0 ); + split_string( val, m_str_classes, " " ); + m_classes.clear(); + for (auto& cls : m_str_classes) m_classes.push_back(_id(cls)); + } + else if (name == "id") + { + string val = _val; + lcase(val); + m_id = _id(val); + } + } +} + +const char* litehtml::html_tag::get_attr( const char* name, const char* def ) const +{ + auto attr = m_attrs.find(name); + if(attr != m_attrs.end()) + { + return attr->second.c_str(); + } + return def; +} + +litehtml::elements_list litehtml::html_tag::select_all(const string& selector ) +{ + css_selector sel; + sel.parse(selector); + + return select_all(sel); +} + +litehtml::elements_list litehtml::html_tag::select_all(const css_selector& selector ) +{ + litehtml::elements_list res; + select_all(selector, res); + return res; +} + +void litehtml::html_tag::select_all(const css_selector& selector, elements_list& res) +{ + if(select(selector)) + { + res.push_back(shared_from_this()); + } + + for(auto& el : m_children) + { + el->select_all(selector, res); + } +} + + +litehtml::element::ptr litehtml::html_tag::select_one( const string& selector ) +{ + css_selector sel; + sel.parse(selector); + + return select_one(sel); +} + +litehtml::element::ptr litehtml::html_tag::select_one( const css_selector& selector ) +{ + if(select(selector)) + { + return shared_from_this(); + } + + for(auto& el : m_children) + { + element::ptr res = el->select_one(selector); + if(res) + { + return res; + } + } + return nullptr; +} + +void litehtml::html_tag::apply_stylesheet( const litehtml::css& stylesheet ) +{ + if(is_root()) + { + int i = 0; + i++; + } + for(const auto& sel : stylesheet.selectors()) + { + // optimization + { + const auto& r = sel->m_right; + if (r.m_tag != star_id && r.m_tag != m_tag) + continue; + + if (!r.m_attrs.empty()) + { + const auto& attr = r.m_attrs[0]; + if (attr.type == select_class && + std::find(m_classes.begin(), m_classes.end(), attr.name) == m_classes.end()) + continue; + } + } + + int apply = select(*sel, false); + + if(apply != select_no_match) + { + used_selector::ptr us = std::unique_ptr<used_selector>(new used_selector(sel, false)); + + if(sel->is_media_valid()) + { + auto apply_before_after = [&]() + { + const auto& content_property = sel->m_style->get_property(_content_); + bool content_none = content_property.m_type == prop_type_string && content_property.m_string == "none"; + bool create = !content_none && (sel->m_right.m_attrs.size() > 1 || sel->m_right.m_tag != star_id); + + element::ptr el; + if(apply & select_match_with_after) + { + el = get_element_after(*sel->m_style, create); + } else if(apply & select_match_with_before) + { + el = get_element_before(*sel->m_style, create); + } else + { + return; + } + if(el) + { + if(!content_none) + { + el->add_style(*sel->m_style); + } else + { + el->parent()->removeChild(el); + } + } else + { + if(!content_none) + { + add_style(*sel->m_style); + } + } + us->m_used = true; + }; + + + if(apply & select_match_pseudo_class) + { + if(select(*sel, true)) + { + if((apply & (select_match_with_after | select_match_with_before))) + { + apply_before_after(); + } else + { + add_style(*sel->m_style); + us->m_used = true; + } + } + } else if((apply & (select_match_with_after | select_match_with_before))) + { + apply_before_after(); + } else + { + add_style(*sel->m_style); + us->m_used = true; + } + } + m_used_styles.push_back(std::move(us)); + } + } + + for(auto& el : m_children) + { + if(el->css().get_display() != display_inline_text) + { + el->apply_stylesheet(stylesheet); + } + } +} + +void litehtml::html_tag::get_content_size( size& sz, int max_width ) +{ + sz.height = 0; + if(m_css.get_display() == display_block) + { + sz.width = max_width; + } else + { + sz.width = 0; + } +} + +void litehtml::html_tag::draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr<render_item> &ri) +{ + position pos = ri->pos(); + pos.x += x; + pos.y += y; + + draw_background(hdc, x, y, clip, ri); + + if(m_css.get_display() == display_list_item && m_css.get_list_style_type() != list_style_type_none) + { + if(m_css.get_overflow() > overflow_visible) + { + position border_box = pos; + border_box += ri->get_paddings(); + border_box += ri->get_borders(); + + border_radiuses bdr_radius = m_css.get_borders().radius.calc_percents(border_box.width, border_box.height); + + bdr_radius -= ri->get_borders(); + bdr_radius -= ri->get_paddings(); + + get_document()->container()->set_clip(pos, bdr_radius); + } + + draw_list_marker(hdc, pos); + + if(m_css.get_overflow() > overflow_visible) + { + get_document()->container()->del_clip(); + } + } +} + +litehtml::string litehtml::html_tag::get_custom_property(string_id name, const string& default_value) const +{ + const property_value& value = m_style.get_property(name); + + if (value.m_type == prop_type_string) + { + return value.m_string; + } + else if (auto _parent = parent()) + { + return _parent->get_custom_property(name, default_value); + } + return default_value; +} + +template<class Type, litehtml::property_type property_value_type, Type litehtml::property_value::* property_value_member> +const Type& litehtml::html_tag::get_property_impl(string_id name, bool inherited, const Type& default_value, uint_ptr css_properties_member_offset) const +{ + const property_value& value = m_style.get_property(name); + + if (value.m_type == property_value_type) + { + return value.*property_value_member; + } + else if (inherited || value.m_type == prop_type_inherit) + { + if (auto _parent = parent()) + { + return *(Type*)((byte*)&_parent->css() + css_properties_member_offset); + } + return default_value; + } + // value must be invalid here + //assert(value.m_type == prop_type_invalid); + return default_value; +} + +int litehtml::html_tag::get_enum_property(string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<int, prop_type_enum_item, &property_value::m_enum_item>(name, inherited, default_value, css_properties_member_offset); +} + +int litehtml::html_tag::get_int_property(string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<int, prop_type_enum_item, &property_value::m_enum_item>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::css_length litehtml::html_tag::get_length_property(string_id name, bool inherited, css_length default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<css_length, prop_type_length, &property_value::m_length>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::web_color litehtml::html_tag::get_color_property(string_id name, bool inherited, web_color default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<web_color, prop_type_color, &property_value::m_color>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::string litehtml::html_tag::get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<string, prop_type_string, &property_value::m_string>(name, inherited, default_value, css_properties_member_offset); +} + +float litehtml::html_tag::get_number_property(string_id name, bool inherited, float default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<float, prop_type_number, &property_value::m_number>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::string_vector litehtml::html_tag::get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<string_vector, prop_type_string_vector, &property_value::m_string_vector>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::int_vector litehtml::html_tag::get_int_vector_property(string_id name, bool inherited, const int_vector& default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<int_vector, prop_type_enum_item_vector, &property_value::m_enum_item_vector>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::length_vector litehtml::html_tag::get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<length_vector, prop_type_length_vector, &property_value::m_length_vector>(name, inherited, default_value, css_properties_member_offset); +} + +litehtml::size_vector litehtml::html_tag::get_size_vector_property(string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const +{ + return get_property_impl<size_vector, prop_type_size_vector, &property_value::m_size_vector>(name, inherited, default_value, css_properties_member_offset); +} + +void litehtml::html_tag::compute_styles(bool recursive) +{ + const char* style = get_attr("style"); + document::ptr doc = get_document(); + + if (style) + { + m_style.add(style, "", doc->container()); + } + + m_style.subst_vars(this); + + m_css.compute(this, doc); + + if (recursive) + { + for (const auto& el : m_children) + { + el->compute_styles(); + } + } +} + +bool litehtml::html_tag::is_white_space() const +{ + return false; +} + +int litehtml::html_tag::select(const string& selector) +{ + css_selector sel; + sel.parse(selector); + return select(sel, true); +} + +int litehtml::html_tag::select(const css_selector& selector, bool apply_pseudo) +{ + int right_res = select(selector.m_right, apply_pseudo); + if(right_res == select_no_match) + { + return select_no_match; + } + element::ptr el_parent = parent(); + if(selector.m_left) + { + if (!el_parent) + { + return select_no_match; + } + switch(selector.m_combinator) + { + case combinator_descendant: + { + bool is_pseudo = false; + element::ptr res = find_ancestor(*selector.m_left, apply_pseudo, &is_pseudo); + if(!res) + { + return select_no_match; + } else + { + if(is_pseudo) + { + right_res |= select_match_pseudo_class; + } + } + } + break; + case combinator_child: + { + int res = el_parent->select(*selector.m_left, apply_pseudo); + if(res == select_no_match) + { + return select_no_match; + } else + { + if(right_res != select_match_pseudo_class) + { + right_res |= res; + } + } + } + break; + case combinator_adjacent_sibling: + { + bool is_pseudo = false; + element::ptr res = el_parent->find_adjacent_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo); + if(!res) + { + return select_no_match; + } else + { + if(is_pseudo) + { + right_res |= select_match_pseudo_class; + } + } + } + break; + case combinator_general_sibling: + { + bool is_pseudo = false; + element::ptr res = el_parent->find_sibling(shared_from_this(), *selector.m_left, apply_pseudo, &is_pseudo); + if(!res) + { + return select_no_match; + } else + { + if(is_pseudo) + { + right_res |= select_match_pseudo_class; + } + } + } + break; + default: + right_res = select_no_match; + } + } + return right_res; +} + +int litehtml::html_tag::select(const css_element_selector& selector, bool apply_pseudo) +{ + if(selector.m_tag != star_id && selector.m_tag != m_tag) + { + return select_no_match; + } + + int res = select_match; + + for(const auto& attr : selector.m_attrs) + { + switch(attr.type) + { + case select_class: + if (std::find(m_classes.begin(), m_classes.end(), attr.name) == m_classes.end()) + { + return select_no_match; + } + break; + case select_id: + if (attr.name != m_id) + { + return select_no_match; + } + break; + case select_pseudo_element: + if(attr.name == _after_) + { + if(selector.m_attrs.size() == 1 && selector.m_tag == star_id && m_tag != __tag_after_) + { + return select_no_match; + } + res |= select_match_with_after; + } else if(attr.name == _before_) + { + if(selector.m_attrs.size() == 1 && selector.m_tag == star_id && m_tag != __tag_before_) + { + return select_no_match; + } + res |= select_match_with_before; + } else + { + return select_no_match; + } + break; + case select_pseudo_class: + if(apply_pseudo) + { + if (select_pseudoclass(attr) == select_no_match) + { + return select_no_match; + } + } else + { + res |= select_match_pseudo_class; + } + break; + default: + if (select_attribute(attr) == select_no_match) + { + return select_no_match; + } + } + } + return res; +} + +int litehtml::html_tag::select_pseudoclass(const css_attribute_selector& sel) +{ + element::ptr el_parent = parent(); + + switch (sel.name) + { + case _only_child_: + if (!el_parent || !el_parent->is_only_child(shared_from_this(), false)) + { + return select_no_match; + } + break; + case _only_of_type_: + if (!el_parent || !el_parent->is_only_child(shared_from_this(), true)) + { + return select_no_match; + } + break; + case _first_child_: + if (!el_parent || !el_parent->is_nth_child(shared_from_this(), 0, 1, false)) + { + return select_no_match; + } + break; + case _first_of_type_: + if (!el_parent || !el_parent->is_nth_child(shared_from_this(), 0, 1, true)) + { + return select_no_match; + } + break; + case _last_child_: + if (!el_parent || !el_parent->is_nth_last_child(shared_from_this(), 0, 1, false)) + { + return select_no_match; + } + break; + case _last_of_type_: + if (!el_parent || !el_parent->is_nth_last_child(shared_from_this(), 0, 1, true)) + { + return select_no_match; + } + break; + case _nth_child_: + case _nth_of_type_: + case _nth_last_child_: + case _nth_last_of_type_: + { + if (!el_parent) return select_no_match; + + int num = sel.a; + int off = sel.b; + if (!num && !off) return select_no_match; + + switch (sel.name) + { + case _nth_child_: + if (!el_parent->is_nth_child(shared_from_this(), num, off, false)) + { + return select_no_match; + } + break; + case _nth_of_type_: + if (!el_parent->is_nth_child(shared_from_this(), num, off, true)) + { + return select_no_match; + } + break; + case _nth_last_child_: + if (!el_parent->is_nth_last_child(shared_from_this(), num, off, false)) + { + return select_no_match; + } + break; + case _nth_last_of_type_: + if (!el_parent->is_nth_last_child(shared_from_this(), num, off, true)) + { + return select_no_match; + } + break; + default: + break; + } + + } + break; + case _not_: + if (select(*sel.sel, true)) + { + return select_no_match; + } + break; + case _lang_: + if (!get_document()->match_lang(sel.val)) + { + return select_no_match; + } + break; + default: + if (std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), sel.name) == m_pseudo_classes.end()) + { + return select_no_match; + } + break; + } + return select_match; +} + +int litehtml::html_tag::select_attribute(const css_attribute_selector& sel) +{ + const char* attr_value = get_attr(_s(sel.name).c_str()); + + switch (sel.type) + { + case select_exists: + if (!attr_value) + { + return select_no_match; + } + break; + case select_equal: + if (!attr_value || strcmp(attr_value, sel.val.c_str())) + { + return select_no_match; + } + break; + case select_contain_str: + if (!attr_value || !strstr(attr_value, sel.val.c_str())) + { + return select_no_match; + } + break; + case select_start_str: + if (!attr_value || strncmp(attr_value, sel.val.c_str(), sel.val.length())) + { + return select_no_match; + } + break; + case select_end_str: + if (!attr_value) + { + return select_no_match; + } + else if (strncmp(attr_value, sel.val.c_str(), sel.val.length())) + { + const char* s = attr_value + strlen(attr_value) - sel.val.length() - 1; + if (s < attr_value) + { + return select_no_match; + } + if (sel.val != s) + { + return select_no_match; + } + } + break; + default: + break; + } + return select_match; +} + +litehtml::element::ptr litehtml::html_tag::find_ancestor(const css_selector& selector, bool apply_pseudo, bool* is_pseudo) +{ + element::ptr el_parent = parent(); + if (!el_parent) + { + return nullptr; + } + int res = el_parent->select(selector, apply_pseudo); + if(res != select_no_match) + { + if(is_pseudo) + { + if(res & select_match_pseudo_class) + { + *is_pseudo = true; + } else + { + *is_pseudo = false; + } + } + return el_parent; + } + return el_parent->find_ancestor(selector, apply_pseudo, is_pseudo); +} + +void litehtml::html_tag::parse_attributes() +{ + for(auto& el : m_children) + { + el->parse_attributes(); + } +} + +void litehtml::html_tag::get_text( string& text ) +{ + for (auto& el : m_children) + { + el->get_text(text); + } +} + +bool litehtml::html_tag::is_body() const +{ + return false; +} + +void litehtml::html_tag::set_data( const char* /*data*/ ) +{ + +} + +bool litehtml::html_tag::on_mouse_over() +{ + bool ret = false; + + element::ptr el = shared_from_this(); + while(el) + { + if(el->set_pseudo_class(_hover_, true)) + { + ret = true; + } + el = el->parent(); + } + + return ret; +} + +bool litehtml::html_tag::on_mouse_leave() +{ + bool ret = false; + + element::ptr el = shared_from_this(); + while(el) + { + if(el->set_pseudo_class(_hover_, false)) + { + ret = true; + } + if(el->set_pseudo_class(_active_, false)) + { + ret = true; + } + el = el->parent(); + } + + return ret; +} + +bool litehtml::html_tag::on_lbutton_down() +{ + bool ret = false; + + element::ptr el = shared_from_this(); + while (el) + { + if (el->set_pseudo_class(_active_, true)) + { + ret = true; + } + el = el->parent(); + } + + return ret; +} + +bool litehtml::html_tag::on_lbutton_up() +{ + bool ret = false; + + element::ptr el = shared_from_this(); + while (el) + { + if (el->set_pseudo_class(_active_, false)) + { + ret = true; + } + el = el->parent(); + } + + on_click(); + + return ret; +} + +void litehtml::html_tag::on_click() +{ + if (!is_root()) + { + element::ptr el_parent = parent(); + if (el_parent) + { + el_parent->on_click(); + } + } +} + +bool litehtml::html_tag::is_break() const +{ + return false; +} + +void litehtml::html_tag::draw_background(uint_ptr hdc, int x, int y, const position *clip, + const std::shared_ptr<render_item> &ri) +{ + position pos = ri->pos(); + pos.x += x; + pos.y += y; + + position el_pos = pos; + el_pos += ri->get_paddings(); + el_pos += ri->get_margins(); + + if(m_css.get_display() != display_inline && m_css.get_display() != display_table_row) + { + if(el_pos.does_intersect(clip) || is_root()) + { + auto v_offset = ri->get_draw_vertical_offset(); + pos.y += v_offset; + pos.height -= v_offset; + + const background* bg = get_background(); + if(bg) + { + std::vector<background_paint> bg_paint; + init_background_paint(pos, bg_paint, bg, ri); + if(is_root()) + { + for(auto& b : bg_paint) + { + b.clip_box = *clip; + b.border_box = *clip; + } + } + + get_document()->container()->draw_background(hdc, bg_paint); + } + position border_box = pos; + border_box += ri->get_paddings(); + border_box += ri->get_borders(); + + borders bdr = m_css.get_borders(); + if(bdr.is_visible()) + { + bdr.radius = m_css.get_borders().radius.calc_percents(border_box.width, border_box.height); + get_document()->container()->draw_borders(hdc, bdr, border_box, is_root()); + } + } + } else + { + const background* bg = get_background(); + + position::vector boxes; + ri->get_inline_boxes(boxes); + + std::vector<background_paint> bg_paint; + position content_box; + + for(auto box = boxes.begin(); box != boxes.end(); box++) + { + box->x += x; + box->y += y; + + if(box->does_intersect(clip)) + { + content_box = *box; + content_box -= ri->get_borders(); + content_box -= ri->get_paddings(); + + if(bg) + { + init_background_paint(content_box, bg_paint, bg, ri); + } + + css_borders bdr; + + // set left borders radius for the first box + if(box == boxes.begin()) + { + bdr.radius.bottom_left_x = m_css.get_borders().radius.bottom_left_x; + bdr.radius.bottom_left_y = m_css.get_borders().radius.bottom_left_y; + bdr.radius.top_left_x = m_css.get_borders().radius.top_left_x; + bdr.radius.top_left_y = m_css.get_borders().radius.top_left_y; + } + + // set right borders radius for the last box + if(box == boxes.end() - 1) + { + bdr.radius.bottom_right_x = m_css.get_borders().radius.bottom_right_x; + bdr.radius.bottom_right_y = m_css.get_borders().radius.bottom_right_y; + bdr.radius.top_right_x = m_css.get_borders().radius.top_right_x; + bdr.radius.top_right_y = m_css.get_borders().radius.top_right_y; + } + + + bdr.top = m_css.get_borders().top; + bdr.bottom = m_css.get_borders().bottom; + if(box == boxes.begin()) + { + bdr.left = m_css.get_borders().left; + } + if(box == boxes.end() - 1) + { + bdr.right = m_css.get_borders().right; + } + + if(bg) + { + for (auto& bgp : bg_paint) + { + bgp.border_radius = bdr.radius.calc_percents(bgp.border_box.width, bgp.border_box.width); + } + get_document()->container()->draw_background(hdc, bg_paint); + } + if(bdr.is_visible()) + { + borders b = bdr; + b.radius = bdr.radius.calc_percents(box->width, box->height); + get_document()->container()->draw_borders(hdc, b, *box, false); + } + } + } + } +} + +bool litehtml::html_tag::set_pseudo_class( string_id cls, bool add ) +{ + bool ret = false; + if(add) + { + if(std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), cls) == m_pseudo_classes.end()) + { + m_pseudo_classes.push_back(cls); + ret = true; + } + } else + { + auto pi = std::find(m_pseudo_classes.begin(), m_pseudo_classes.end(), cls); + if(pi != m_pseudo_classes.end()) + { + m_pseudo_classes.erase(pi); + ret = true; + } + } + return ret; +} + +bool litehtml::html_tag::set_class( const char* pclass, bool add ) +{ + string_vector classes; + bool changed = false; + + split_string( pclass, classes, " " ); + + if(add) + { + for( auto & _class : classes ) + { + if(std::find(m_str_classes.begin(), m_str_classes.end(), _class) == m_str_classes.end()) + { + m_str_classes.push_back( std::move( _class ) ); + changed = true; + } + } + } else + { + for( const auto & _class : classes ) + { + auto end = std::remove(m_str_classes.begin(), m_str_classes.end(), _class); + + if(end != m_str_classes.end()) + { + m_str_classes.erase(end, m_str_classes.end()); + changed = true; + } + } + } + + if( changed ) + { + string class_string; + join_string(class_string, m_str_classes, " "); + set_attr("class", class_string.c_str()); + + return true; + } + else + { + return false; + } + +} + +bool litehtml::html_tag::is_replaced() const +{ + return false; +} + +void litehtml::html_tag::init_background_paint(position pos, std::vector<background_paint>& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri) +{ + bg_paint = { background_paint() }; + if (!bg) return; + + int bg_count = std::max((int)bg->m_image.size(), 1); + bg_paint.resize(bg_count); + + for (int i = 0; i < bg_count; i++) + { + init_one_background_paint(i, pos, bg_paint[i], bg, ri); + } + + bg_paint.back().color = bg->m_color; +} + +void litehtml::html_tag::init_one_background_paint(int i, position pos, background_paint& bg_paint, const background* bg, const std::shared_ptr<render_item>& ri) +{ + bg_paint.image = i < (int) bg->m_image.size() ? bg->m_image[i] : ""; + bg_paint.baseurl = bg->m_baseurl; + bg_paint.attachment = i < (int) bg->m_attachment.size() ? (background_attachment)bg->m_attachment[i] : background_attachment_scroll; + bg_paint.repeat = i < (int) bg->m_repeat.size() ? (background_repeat)bg->m_repeat[i] : background_repeat_repeat; + int clip = i < (int) bg->m_clip.size() ? bg->m_clip[i] : background_box_border; + int origin = i < (int) bg->m_origin.size() ? bg->m_origin[i] : background_box_padding; + const css_size auto_auto(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)); + css_size size = i < (int) bg->m_size.size() ? bg->m_size[i] : auto_auto; + css_length position_x = i < (int) bg->m_position_x.size() ? bg->m_position_x[i] : css_length(0, css_units_percentage); + css_length position_y = i < (int) bg->m_position_y.size() ? bg->m_position_y[i] : css_length(0, css_units_percentage); + + position content_box = pos; + position padding_box = pos; + padding_box += ri->get_paddings(); + position border_box = padding_box; + border_box += ri->get_borders(); + + switch(clip) + { + case background_box_padding: + bg_paint.clip_box = padding_box; + break; + case background_box_content: + bg_paint.clip_box = content_box; + break; + default: + bg_paint.clip_box = border_box; + break; + } + + switch(origin) + { + case background_box_border: + bg_paint.origin_box = border_box; + break; + case background_box_content: + bg_paint.origin_box = content_box; + break; + default: + bg_paint.origin_box = padding_box; + break; + } + + if(!bg_paint.image.empty()) + { + get_document()->container()->get_image_size(bg_paint.image.c_str(), bg_paint.baseurl.c_str(), bg_paint.image_size); + if(bg_paint.image_size.width && bg_paint.image_size.height) + { + litehtml::size img_new_sz = bg_paint.image_size; + double img_ar_width = (double) bg_paint.image_size.width / (double) bg_paint.image_size.height; + double img_ar_height = (double) bg_paint.image_size.height / (double) bg_paint.image_size.width; + + + if(size.width.is_predefined()) + { + switch(size.width.predef()) + { + case background_size_contain: + if( (int) ((double) bg_paint.origin_box.width * img_ar_height) <= bg_paint.origin_box.height ) + { + img_new_sz.width = bg_paint.origin_box.width; + img_new_sz.height = (int) ((double) bg_paint.origin_box.width * img_ar_height); + } else + { + img_new_sz.height = bg_paint.origin_box.height; + img_new_sz.width = (int) ((double) bg_paint.origin_box.height * img_ar_width); + } + break; + case background_size_cover: + if( (int) ((double) bg_paint.origin_box.width * img_ar_height) >= bg_paint.origin_box.height ) + { + img_new_sz.width = bg_paint.origin_box.width; + img_new_sz.height = (int) ((double) bg_paint.origin_box.width * img_ar_height); + } else + { + img_new_sz.height = bg_paint.origin_box.height; + img_new_sz.width = (int) ((double) bg_paint.origin_box.height * img_ar_width); + } + break; + case background_size_auto: + if(!size.height.is_predefined()) + { + img_new_sz.height = size.height.calc_percent(bg_paint.origin_box.height); + img_new_sz.width = (int) ((double) img_new_sz.height * img_ar_width); + } + break; + } + } else + { + img_new_sz.width = size.width.calc_percent(bg_paint.origin_box.width); + if(size.height.is_predefined()) + { + img_new_sz.height = (int) ((double) img_new_sz.width * img_ar_height); + } else + { + img_new_sz.height = size.height.calc_percent(bg_paint.origin_box.height); + } + } + + bg_paint.image_size = img_new_sz; + bg_paint.position_x = bg_paint.origin_box.x + (int) position_x.calc_percent(bg_paint.origin_box.width - bg_paint.image_size.width); + bg_paint.position_y = bg_paint.origin_box.y + (int) position_y.calc_percent(bg_paint.origin_box.height - bg_paint.image_size.height); + } + } + bg_paint.border_radius = m_css.get_borders().radius.calc_percents(border_box.width, border_box.height); + bg_paint.border_box = border_box; + bg_paint.is_root = is_root(); +} + +void litehtml::html_tag::draw_list_marker( uint_ptr hdc, const position& pos ) +{ + list_marker lm; + + size img_size; + if (css().get_list_style_image() != "") + { + lm.image = css().get_list_style_image(); + lm.baseurl = css().get_list_style_image_baseurl().c_str(); + get_document()->container()->get_image_size(lm.image.c_str(), lm.baseurl, img_size); + } else + { + lm.baseurl = nullptr; + } + + int ln_height = css().get_line_height(); + int sz_font = css().get_font_size(); + lm.pos.x = pos.x; + lm.pos.width = sz_font - sz_font * 2 / 3; + lm.color = css().get_color(); + lm.marker_type = css().get_list_style_type(); + lm.font = css().get_font(); + + if (css().get_list_style_type() >= list_style_type_armenian) + { + lm.pos.y = pos.y; + lm.pos.height = pos.height; + lm.index = atoi(get_attr("list_index", "0")); + } + else + { + lm.pos.height = sz_font - sz_font * 2 / 3; + lm.pos.y = pos.y + ln_height / 2 - lm.pos.height / 2; + lm.index = -1; + } + + if(img_size.width && img_size.height) + { + if(lm.pos.y + img_size.height > pos.y + pos.height) + { + lm.pos.y = pos.y + pos.height - img_size.height; + } + if(img_size.width > lm.pos.width) + { + lm.pos.x -= img_size.width - lm.pos.width; + } + + lm.pos.width = img_size.width; + lm.pos.height = img_size.height; + } + + if (m_css.get_list_style_position() == list_style_position_outside) + { + if (m_css.get_list_style_type() >= list_style_type_armenian) + { + if(lm.font) + { + auto tw_space = get_document()->container()->text_width(" ", lm.font); + lm.pos.x = pos.x - tw_space * 2; + lm.pos.width = tw_space; + } else + { + lm.pos.width = 0; + } + } + else + { + lm.pos.x -= sz_font; + } + } + + if (m_css.get_list_style_type() >= list_style_type_armenian) + { + auto marker_text = get_list_marker_text(lm.index); + lm.pos.height = ln_height; + if (marker_text.empty()) + { + get_document()->container()->draw_list_marker(hdc, lm); + } + else + { + if(lm.font) + { + marker_text += "."; + auto tw = get_document()->container()->text_width(marker_text.c_str(), lm.font); + auto text_pos = lm.pos; + text_pos.move_to(text_pos.right() - tw, text_pos.y); + text_pos.width = tw; + get_document()->container()->draw_text(hdc, marker_text.c_str(), lm.font, lm.color, text_pos); + } + } + } + else + { + get_document()->container()->draw_list_marker(hdc, lm); + } +} + +litehtml::string litehtml::html_tag::get_list_marker_text(int index) +{ + switch (m_css.get_list_style_type()) + { + case litehtml::list_style_type_decimal: + return std::to_string(index); + case litehtml::list_style_type_decimal_leading_zero: + { + auto txt = std::to_string(index); + if (txt.length() == 1) + { + txt = "0" + txt; + } + return txt; + } + case litehtml::list_style_type_lower_latin: + case litehtml::list_style_type_lower_alpha: + return num_cvt::to_latin_lower(index); + case litehtml::list_style_type_lower_greek: + return num_cvt::to_greek_lower(index); + case litehtml::list_style_type_upper_alpha: + case litehtml::list_style_type_upper_latin: + return num_cvt::to_latin_upper(index); + case litehtml::list_style_type_lower_roman: + return num_cvt::to_roman_lower(index); + case litehtml::list_style_type_upper_roman: + return num_cvt::to_roman_upper(index); + default: + return ""; +// case litehtml::list_style_type_armenian: +// case litehtml::list_style_type_georgian: +// case litehtml::list_style_type_hebrew: +// case litehtml::list_style_type_hiragana: +// case litehtml::list_style_type_hiragana_iroha: +// case litehtml::list_style_type_katakana: +// case litehtml::list_style_type_katakana_iroha: +// case litehtml::list_style_type_none: +// case litehtml::list_style_type_circle: +// case litehtml::list_style_type_disc: +// case litehtml::list_style_type_square: +// case litehtml::list_style_type_cjk_ideographic: +// break; + } +} + +bool litehtml::html_tag::is_nth_child(const element::ptr& el, int num, int off, bool of_type) const +{ + int idx = 1; + for(const auto& child : m_children) + { + if(child->css().get_display() != display_inline_text) + { + if( (!of_type) || (of_type && el->tag() == child->tag()) ) + { + if(el == child) + { + if(num != 0) + { + if((idx - off) >= 0 && (idx - off) % num == 0) + { + return true; + } + + } else if(idx == off) + { + return true; + } + return false; + } + idx++; + } + if(el == child) break; + } + } + return false; +} + +bool litehtml::html_tag::is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const +{ + int idx = 1; + for(auto child = m_children.rbegin(); child != m_children.rend(); child++) + { + if((*child)->css().get_display() != display_inline_text) + { + if( !of_type || (of_type && el->tag() == (*child)->tag()) ) + { + if(el == (*child)) + { + if(num != 0) + { + if((idx - off) >= 0 && (idx - off) % num == 0) + { + return true; + } + + } else if(idx == off) + { + return true; + } + return false; + } + idx++; + } + if(el == (*child)) break; + } + } + return false; +} + +litehtml::element::ptr litehtml::html_tag::find_adjacent_sibling( const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/ ) +{ + element::ptr ret; + for(auto& e : m_children) + { + if(e->css().get_display() != display_inline_text) + { + if(e == el) + { + if(ret) + { + int res = ret->select(selector, apply_pseudo); + if(res != select_no_match) + { + if(is_pseudo) + { + if(res & select_match_pseudo_class) + { + *is_pseudo = true; + } else + { + *is_pseudo = false; + } + } + return ret; + } + } + return nullptr; + } else + { + ret = e; + } + } + } + return nullptr; +} + +litehtml::element::ptr litehtml::html_tag::find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo /*= true*/, bool* is_pseudo /*= 0*/) +{ + element::ptr ret = nullptr; + for(auto& e : m_children) + { + if(e->css().get_display() != display_inline_text) + { + if(e == el) + { + return ret; + } else if(!ret) + { + int res = e->select(selector, apply_pseudo); + if(res != select_no_match) + { + if(is_pseudo) + { + if(res & select_match_pseudo_class) + { + *is_pseudo = true; + } else + { + *is_pseudo = false; + } + } + ret = e; + } + } + } + } + return nullptr; +} + +bool litehtml::html_tag::is_only_child(const element::ptr& el, bool of_type) const +{ + int child_count = 0; + for(const auto& child : m_children) + { + if(child->css().get_display() != display_inline_text) + { + if( !of_type || (of_type && el->tag() == child->tag()) ) + { + child_count++; + } + if(child_count > 1) break; + } + } + if(child_count > 1) + { + return false; + } + return true; +} + +litehtml::element::ptr litehtml::html_tag::get_element_before(const style& style, bool create) +{ + if(!m_children.empty()) + { + if( m_children.front()->tag() == __tag_before_ ) + { + return m_children.front(); + } + } + if(create) + { + return add_pseudo_before(style); + } + return nullptr; +} + +litehtml::element::ptr litehtml::html_tag::get_element_after(const style& style, bool create) +{ + if(!m_children.empty()) + { + if( m_children.back()->tag() == __tag_after_ ) + { + return m_children.back(); + } + } + if(create) + { + return add_pseudo_after(style); + } + return nullptr; +} + + +void litehtml::html_tag::handle_counter_properties() +{ + const auto& reset_property = m_style.get_property(string_id::_counter_reset_); + if (reset_property.m_type == prop_type_string_vector) { + auto reset_function = [&](const string_id&name_id, const int value) { + reset_counter(name_id, value); + }; + parse_counter_tokens(reset_property.m_string_vector, 0, reset_function); + return; + } + + const auto& inc_property = m_style.get_property(string_id::_counter_increment_); + if (inc_property.m_type == prop_type_string_vector) { + auto inc_function = [&](const string_id&name_id, const int value) { + increment_counter(name_id, value); + }; + parse_counter_tokens(inc_property.m_string_vector, 1, inc_function); + return; + } +} + + +void litehtml::html_tag::add_style(const style& style) +{ + m_style.combine(style); + handle_counter_properties(); +} + +void litehtml::html_tag::refresh_styles() +{ + for (auto& el : m_children) + { + if(el->css().get_display() != display_inline_text) + { + el->refresh_styles(); + } + } + + m_style.clear(); + + for (auto& usel : m_used_styles) + { + usel->m_used = false; + + if(usel->m_selector->is_media_valid()) + { + int apply = select(*usel->m_selector, false); + + if(apply != select_no_match) + { + if(apply & select_match_pseudo_class) + { + if(select(*usel->m_selector, true)) + { + if(apply & select_match_with_after) + { + element::ptr el = get_element_after(*usel->m_selector->m_style, false); + if(el) + { + el->add_style(*usel->m_selector->m_style); + } + } else if(apply & select_match_with_before) + { + element::ptr el = get_element_before(*usel->m_selector->m_style, false); + if(el) + { + el->add_style(*usel->m_selector->m_style); + } + } + else + { + add_style(*usel->m_selector->m_style); + usel->m_used = true; + } + } + } else if(apply & select_match_with_after) + { + element::ptr el = get_element_after(*usel->m_selector->m_style, false); + if(el) + { + el->add_style(*usel->m_selector->m_style); + } + } else if(apply & select_match_with_before) + { + element::ptr el = get_element_before(*usel->m_selector->m_style, false); + if(el) + { + el->add_style(*usel->m_selector->m_style); + } + } else + { + add_style(*usel->m_selector->m_style); + usel->m_used = true; + } + } + } + } +} + +const litehtml::background* litehtml::html_tag::get_background(bool own_only) +{ + if(own_only) + { + // return own background with check for empty one + if(m_css.get_bg().is_empty()) + { + return nullptr; + } + return &m_css.get_bg(); + } + + if(m_css.get_bg().is_empty()) + { + // if this is root element (<html>) try to get background from body + if (is_root()) + { + for (const auto& el : m_children) + { + if( el->is_body() ) + { + // return own body background + return el->get_background(true); + } + } + } + return nullptr; + } + + if(is_body()) + { + element::ptr el_parent = parent(); + if (el_parent) + { + if (!el_parent->get_background(true)) + { + // parent of body will draw background for body + return nullptr; + } + } + } + + return &m_css.get_bg(); +} + +litehtml::string litehtml::html_tag::dump_get_name() +{ + if(m_tag == empty_id) + { + return "anon [html_tag]"; + } + return _s(m_tag) + " [html_tag]"; +} diff --git a/libs/litehtml/src/iterators.cpp b/libs/litehtml/src/iterators.cpp new file mode 100644 index 0000000000..f0a87555c2 --- /dev/null +++ b/libs/litehtml/src/iterators.cpp @@ -0,0 +1,101 @@ +#include "html.h" +#include "iterators.h" +#include "html_tag.h" +#include "render_item.h" +#include <iterator> + +litehtml::elements_iterator::elements_iterator(bool return_parents, iterator_selector* go_inside, iterator_selector* select) : + m_go_inside(go_inside), + m_select(select), + m_return_parent(return_parents) +{ +} + +bool litehtml::elements_iterator::go_inside(const std::shared_ptr<render_item>& el) +{ + return /*!el->children().empty() &&*/ m_go_inside && m_go_inside->select(el); +} + +void litehtml::elements_iterator::process(const std::shared_ptr<render_item>& container, const std::function<void (std::shared_ptr<render_item>&, iterator_item_type)>& func) +{ + for(auto& el : container->children()) + { + if(go_inside(el)) + { + if(m_return_parent) + { + // call function for parent + func(el, iterator_item_type_start_parent); + } + // go inside element and process its items + process(el, func); + if(m_return_parent) + { + // call function for parent + func(el, iterator_item_type_end_parent); + } + } else + { + // call function for element + if(!m_select || m_select->select(el)) + { + func(el, iterator_item_type_child); + } + } + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + +bool litehtml::go_inside_inline::select(const std::shared_ptr<render_item>& el) +{ + if(el->src_el()->css().get_display() == display_inline && el->src_el()->css().get_float() == float_none) + { + return true; + } + return false; +} + +bool litehtml::inline_selector::select(const std::shared_ptr<render_item>& el) +{ + if(el->src_el()->css().get_display() == display_inline_text || + el->src_el()->css().get_display() == display_inline_table || + el->src_el()->css().get_display() == display_inline_block || + el->src_el()->css().get_display() == display_inline_flex || + el->src_el()->css().get_float() != float_none) + { + return true; + } + return false; +} + +bool litehtml::go_inside_table::select(const std::shared_ptr<render_item>& el) +{ + if( el->src_el()->css().get_display() == display_table_row_group || + el->src_el()->css().get_display() == display_table_header_group || + el->src_el()->css().get_display() == display_table_footer_group) + { + return true; + } + return false; +} + +bool litehtml::table_rows_selector::select(const std::shared_ptr<render_item>& el) +{ + if( el->src_el()->css().get_display() == display_table_row) + { + return true; + } + return false; +} + +bool litehtml::table_cells_selector::select(const std::shared_ptr<render_item>& el) +{ + if( el->src_el()->css().get_display() == display_table_cell) + { + return true; + } + return false; +} diff --git a/libs/litehtml/src/line_box.cpp b/libs/litehtml/src/line_box.cpp new file mode 100644 index 0000000000..e8c5034633 --- /dev/null +++ b/libs/litehtml/src/line_box.cpp @@ -0,0 +1,717 @@ +#include "html.h" +#include "line_box.h" +#include "element.h" +#include "render_item.h" +#include <algorithm> + +////////////////////////////////////////////////////////////////////////////////////////// + +void litehtml::line_box_item::place_to(int x, int y) +{ + m_element->pos().x = x + m_element->content_offset_left(); + m_element->pos().y = y + m_element->content_offset_top(); +} + +litehtml::position& litehtml::line_box_item::pos() +{ + return m_element->pos(); +} + + +int litehtml::line_box_item::width() const +{ + return m_element->width(); +} + +int litehtml::line_box_item::top() const +{ + return m_element->top(); +} + +int litehtml::line_box_item::bottom() const +{ + return m_element->bottom(); +} + +int litehtml::line_box_item::right() const +{ + return m_element->right(); +} + +int litehtml::line_box_item::left() const +{ + return m_element->left(); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +litehtml::lbi_start::lbi_start(const std::shared_ptr<render_item>& element) : line_box_item(element) +{ + m_pos.height = m_element->src_el()->css().get_font_metrics().height; + m_pos.width = m_element->content_offset_left(); +} + +void litehtml::lbi_start::place_to(int x, int y) +{ + m_pos.x = x + m_element->content_offset_left(); + m_pos.y = y; +} + +int litehtml::lbi_start::width() const +{ + return m_pos.width; +} + +int litehtml::lbi_start::top() const +{ + return m_pos.y; +} + +int litehtml::lbi_start::bottom() const +{ + return m_pos.y + m_pos.height; +} + +int litehtml::lbi_start::right() const +{ + return m_pos.x; +} + +int litehtml::lbi_start::left() const +{ + return m_pos.x - m_element->content_offset_left(); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +litehtml::lbi_end::lbi_end(const std::shared_ptr<render_item>& element) : lbi_start(element) +{ + m_pos.height = m_element->src_el()->css().get_font_metrics().height; + m_pos.width = m_element->content_offset_right(); +} + +void litehtml::lbi_end::place_to(int x, int y) +{ + m_pos.x = x; + m_pos.y = y; +} + +int litehtml::lbi_end::right() const +{ + return m_pos.x + m_pos.width; +} + +int litehtml::lbi_end::left() const +{ + return m_pos.x; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +litehtml::lbi_continue::lbi_continue(const std::shared_ptr<render_item>& element) : lbi_start(element) +{ + m_pos.height = m_element->src_el()->css().get_font_metrics().height; + m_pos.width = 0; +} + +void litehtml::lbi_continue::place_to(int x, int y) +{ + m_pos.x = x; + m_pos.y = y; +} + +int litehtml::lbi_continue::right() const +{ + return m_pos.x; +} + +int litehtml::lbi_continue::left() const +{ + return m_pos.x; +} + +int litehtml::lbi_continue::width() const +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void litehtml::line_box::add_item(std::unique_ptr<line_box_item> item) +{ + item->get_el()->skip(false); + bool add = true; + switch (item->get_type()) + { + case line_box_item::type_text_part: + if(item->get_el()->src_el()->is_white_space()) + { + add = !is_empty() && !have_last_space(); + } + break; + case line_box_item::type_inline_start: + case line_box_item::type_inline_end: + case line_box_item::type_inline_continue: + add = true; + break; + } + if(add) + { + item->place_to(m_left + m_width, m_top); + m_width += item->width(); + m_height = std::max(m_height, item->get_el()->height()); + m_items.emplace_back(std::move(item)); + } else + { + item->get_el()->skip(true); + } +} + +int litehtml::line_box::calc_va_baseline(const va_context& current, vertical_align va, const font_metrics& new_font, int top, int bottom) +{ + switch(va) + { + case va_super: + return current.baseline - current.fm.height / 3; + case va_sub: + return current.baseline + current.fm.height / 3; + case va_middle: + return current.baseline - current.fm.x_height / 2; + case va_text_top: + return current.baseline - (current.fm.height - current.fm.base_line()) + + new_font.height - new_font.base_line(); + case va_text_bottom: + return current.baseline + current.fm.base_line() - new_font.base_line(); + case va_top: + return top + new_font.height - new_font.base_line(); + case va_bottom: + return bottom - new_font.height + new_font.base_line(); + default: + return current.baseline; + } +} + +std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::finish(bool last_box, const containing_block_context &containing_block_size) +{ + std::list< std::unique_ptr<line_box_item> > ret_items; + + if(!last_box) + { + while(!m_items.empty()) + { + if (m_items.back()->get_type() == line_box_item::type_text_part) + { + // remove trailing spaces + if (m_items.back()->get_el()->src_el()->is_break() || + m_items.back()->get_el()->src_el()->is_white_space()) + { + m_width -= m_items.back()->width(); + m_items.back()->get_el()->skip(true); + m_items.pop_back(); + } else + { + break; + } + } else if (m_items.back()->get_type() == line_box_item::type_inline_start) + { + // remove trailing empty inline_start markers + // these markers will be added at the beginning of the next line box + m_width -= m_items.back()->width(); + ret_items.emplace_back(std::move(m_items.back())); + m_items.pop_back(); + } else + { + break; + } + } + } else + { + // remove trailing spaces + auto iter = m_items.rbegin(); + while(iter != m_items.rend()) + { + if ((*iter)->get_type() == line_box_item::type_text_part) + { + if((*iter)->get_el()->src_el()->is_white_space()) + { + (*iter)->get_el()->skip(true); + m_width -= (*iter)->width(); + // Space can be between text and inline_end marker + // We have to shift all items on the right side + if(iter != m_items.rbegin()) + { + auto r_iter = iter; + r_iter--; + while (true) + { + (*r_iter)->pos().x -= (*iter)->width(); + if (r_iter == m_items.rbegin()) + { + break; + } + r_iter--; + } + } + // erase white space element + iter = decltype(iter) (m_items.erase( std::next(iter).base() )); + } else + { + break; + } + } else + { + iter++; + } + } + } + + if( is_empty() || (!is_empty() && last_box && is_break_only()) ) + { + m_height = m_default_line_height; + m_baseline = m_font_metrics.base_line(); + return ret_items; + } + + int spc_x = 0; + + int add_x = 0; + switch(m_text_align) + { + case text_align_right: + if(m_width < (m_right - m_left)) + { + add_x = (m_right - m_left) - m_width; + } + break; + case text_align_center: + if(m_width < (m_right - m_left)) + { + add_x = ((m_right - m_left) - m_width) / 2; + } + break; + case text_align_justify: + if (m_width < (m_right - m_left)) + { + add_x = 0; + spc_x = (m_right - m_left) - m_width; + if (spc_x > m_width/4) + spc_x = 0; + } + break; + default: + add_x = 0; + } + + int counter = 0; + float offj = float(spc_x) / std::max(1.f, float(m_items.size())-1.f); + float cixx = 0.0f; + + int line_top = 0; + int line_bottom = 0; + + va_context current_context; + std::list<va_context> contexts; + + current_context.baseline = 0; + current_context.fm = m_font_metrics; + + m_min_width = 0; + + for (const auto& lbi : m_items) + { + m_min_width += lbi->get_rendered_min_width(); + { // start text_align_justify + if (spc_x && counter) + { + cixx += offj; + if ((counter + 1) == int(m_items.size())) + cixx += 0.99f; + lbi->pos().x += int(cixx); + } + counter++; + if ((m_text_align == text_align_right || spc_x) && counter == int(m_items.size())) + { + // Forcible justify the last element to the right side for text align right and justify; + lbi->pos().x = m_right - lbi->pos().width; + } else if (add_x) + { + lbi->pos().x += add_x; + } + } // end text_align_justify + + if (lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue) + { + contexts.push_back(current_context); + current_context.baseline = calc_va_baseline(current_context, + lbi->get_el()->css().get_vertical_align(), + lbi->get_el()->css().get_font_metrics(), + line_top, line_bottom); + current_context.fm = lbi->get_el()->css().get_font_metrics(); + } + + // Align elements vertically by baseline. + if(lbi->get_el()->src_el()->css().get_display() == display_inline_text || lbi->get_el()->src_el()->css().get_display() == display_inline) + { + // inline elements and text are aligned by baseline only + // at this point the baseline for text is properly aligned already + lbi->pos().y = current_context.baseline - lbi->get_el()->css().get_font_metrics().height + lbi->get_el()->css().get_font_metrics().base_line(); + } else + { + switch(lbi->get_el()->css().get_vertical_align()) + { + case va_sub: + case va_super: + { + int bl = calc_va_baseline(current_context, lbi->get_el()->css().get_vertical_align(), current_context.fm, line_top, line_bottom); + lbi->pos().y = bl - lbi->get_el()->get_last_baseline() + + lbi->get_el()->content_offset_top(); + } + break; + case va_bottom: + lbi->pos().y = line_bottom - lbi->get_el()->height() + lbi->get_el()->content_offset_top(); + break; + case va_top: + lbi->pos().y = line_top + lbi->get_el()->content_offset_top(); + break; + case va_baseline: + lbi->pos().y = current_context.baseline - lbi->get_el()->get_last_baseline() + + lbi->get_el()->content_offset_top(); + break; + case va_text_top: + lbi->pos().y = current_context.baseline - current_context.fm.height + current_context.fm.base_line() + + lbi->get_el()->content_offset_top(); + break; + case va_text_bottom: + lbi->pos().y = current_context.baseline + current_context.fm.base_line() - lbi->get_el()->height() + + lbi->get_el()->content_offset_top(); + break; + case va_middle: + lbi->pos().y = current_context.baseline - current_context.fm.x_height / 2 - lbi->get_el()->height() / 2 + + lbi->get_el()->content_offset_top(); + break; + } + } + + if (lbi->get_type() == line_box_item::type_inline_end) + { + if(!contexts.empty()) + { + current_context = contexts.back(); + contexts.pop_back(); + } + } + + // calculate line height + line_top = std::min(line_top, lbi->top()); + line_bottom = std::max(line_bottom, lbi->bottom()); + + if(lbi->get_el()->src_el()->css().get_display() == display_inline_text) + { + m_line_height = std::max(m_line_height, lbi->get_el()->css().get_line_height()); + } + } + + m_height = line_bottom - line_top; + int top_shift = line_top; + if(m_height < m_line_height) + { + top_shift -= (m_line_height - m_height) / 2; + m_height = m_line_height; + } + m_baseline = line_bottom; + + struct inline_item_box + { + std::shared_ptr<render_item> element; + position box; + + inline_item_box() = default; + explicit inline_item_box(const std::shared_ptr<render_item>& el) : element(el) {} + }; + + std::list<inline_item_box> inlines; + + contexts.clear(); + + current_context.baseline = 0; + current_context.fm = m_font_metrics; + bool va_top_bottom = false; + + for (const auto& lbi : m_items) + { + // Calculate baseline. Now we calculate baseline for vertical alignment top and bottom + if (lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue) + { + contexts.push_back(current_context); + va_top_bottom = lbi->get_el()->css().get_vertical_align() == va_bottom || lbi->get_el()->css().get_vertical_align() == va_top; + current_context.baseline = calc_va_baseline(current_context, + lbi->get_el()->css().get_vertical_align(), + lbi->get_el()->css().get_font_metrics(), + top_shift, top_shift + m_height); + current_context.fm = lbi->get_el()->css().get_font_metrics(); + } + + // Align inlines and text by baseline if current vertical alignment is top or bottom + if(va_top_bottom) + { + if (lbi->get_el()->src_el()->css().get_display() == display_inline_text || + lbi->get_el()->src_el()->css().get_display() == display_inline) + { + // inline elements and text are aligned by baseline only + // at this point the baseline for text is properly aligned already + lbi->pos().y = current_context.baseline - lbi->get_el()->css().get_font_metrics().height + + lbi->get_el()->css().get_font_metrics().base_line(); + } + } + + // Pop the prev context + if (lbi->get_type() == line_box_item::type_inline_end) + { + if(!contexts.empty()) + { + current_context = contexts.back(); + contexts.pop_back(); + } + } + + // move element to the correct position + lbi->pos().y += m_top - top_shift; + + // Perform vertical align top and bottom for inline boxes + if(lbi->get_el()->css().get_display() != display_inline_text && lbi->get_el()->css().get_display() != display_inline) + { + if(lbi->get_el()->css().get_vertical_align() == va_top) + { + lbi->pos().y = m_top + lbi->get_el()->content_offset_top(); + } else if(lbi->get_el()->css().get_vertical_align() == va_bottom) + { + lbi->pos().y = m_top + m_height - lbi->get_el()->height() + lbi->get_el()->content_offset_top(); + } + } + lbi->get_el()->apply_relative_shift(containing_block_size); + + // Calculate and push inline box into the render item element + if(lbi->get_type() == line_box_item::type_inline_start || lbi->get_type() == line_box_item::type_inline_continue) + { + if(lbi->get_type() == line_box_item::type_inline_start) + { + lbi->get_el()->clear_inline_boxes(); + } + inlines.emplace_back(lbi->get_el()); + inlines.back().box.x = lbi->left(); + inlines.back().box.y = lbi->top() - lbi->get_el()->content_offset_top(); + inlines.back().box.height = lbi->bottom() - lbi->top() + lbi->get_el()->content_offset_height(); + } else if(lbi->get_type() == line_box_item::type_inline_end) + { + if(!inlines.empty()) + { + inlines.back().box.width = lbi->right() - inlines.back().box.x; + inlines.back().element->add_inline_box(inlines.back().box); + inlines.pop_back(); + } + } + } + + for(auto iter = inlines.rbegin(); iter != inlines.rend(); ++iter) + { + iter->box.width = m_items.back()->right() - iter->box.x; + iter->element->add_inline_box(iter->box); + + ret_items.emplace_front(std::unique_ptr<line_box_item>(new lbi_continue(iter->element))); + } + + return ret_items; +} + +std::shared_ptr<litehtml::render_item> litehtml::line_box::get_first_text_part() const +{ + for(const auto & item : m_items) + { + if(item->get_type() == line_box_item::type_text_part) + { + return item->get_el(); + } + } + return nullptr; +} + + +std::shared_ptr<litehtml::render_item> litehtml::line_box::get_last_text_part() const +{ + for(auto iter = m_items.rbegin(); iter != m_items.rend(); iter++) + { + if((*iter)->get_type() == line_box_item::type_text_part) + { + return (*iter)->get_el(); + } + } + return nullptr; +} + + +bool litehtml::line_box::can_hold(const std::unique_ptr<line_box_item>& item, white_space ws) const +{ + if(!item->get_el()->src_el()->is_inline()) return false; + + if(item->get_type() == line_box_item::type_text_part) + { + // force new line on floats clearing + if (item->get_el()->src_el()->is_break() && item->get_el()->src_el()->css().get_clear() != clear_none) + { + return false; + } + + auto last_el = get_last_text_part(); + + // the first word is always can be hold + if(!last_el) + { + return true; + } + + // force new line if the last placed element was line break + // Skip If there are the only break item - this is float clearing + if (last_el && last_el->src_el()->is_break() && m_items.size() > 1) + { + return false; + } + + // line break should stay in current line box + if (item->get_el()->src_el()->is_break()) + { + return true; + } + + if (ws == white_space_nowrap || ws == white_space_pre || + (ws == white_space_pre_wrap && item->get_el()->src_el()->is_space())) + { + return true; + } + + if (m_left + m_width + item->width() > m_right) + { + return false; + } + } + + return true; +} + +bool litehtml::line_box::have_last_space() const +{ + auto last_el = get_last_text_part(); + if(last_el) + { + return last_el->src_el()->is_white_space() || last_el->src_el()->is_break(); + } + return false; +} + +bool litehtml::line_box::is_empty() const +{ + if(m_items.empty()) return true; + if(m_items.size() == 1 && + m_items.front()->get_el()->src_el()->is_break() && + m_items.front()->get_el()->src_el()->css().get_clear() != clear_none) + { + return true; + } + for (const auto& el : m_items) + { + if(el->get_type() == line_box_item::type_text_part) + { + if (!el->get_el()->skip() || el->get_el()->src_el()->is_break()) + { + return false; + } + } + } + return true; +} + +int litehtml::line_box::baseline() const +{ + return m_baseline; +} + +int litehtml::line_box::top_margin() const +{ + return 0; +} + +int litehtml::line_box::bottom_margin() const +{ + return 0; +} + +void litehtml::line_box::y_shift( int shift ) +{ + m_top += shift; + for (auto& el : m_items) + { + el->pos().y += shift; + } +} + +bool litehtml::line_box::is_break_only() const +{ + if(m_items.empty()) return false; + + bool break_found = false; + + for (auto iter = m_items.rbegin(); iter != m_items.rend(); iter++) + { + if((*iter)->get_type() == line_box_item::type_text_part) + { + if((*iter)->get_el()->src_el()->is_break()) + { + break_found = true; + } else if(!(*iter)->get_el()->skip()) + { + return false; + } + } + } + return break_found; +} + +std::list< std::unique_ptr<litehtml::line_box_item> > litehtml::line_box::new_width( int left, int right) +{ + std::list< std::unique_ptr<line_box_item> > ret_items; + int add = left - m_left; + if(add) + { + m_left = left; + m_right = right; + m_width = 0; + auto remove_begin = m_items.end(); + auto i = m_items.begin(); + i++; + while (i != m_items.end()) + { + if(!(*i)->get_el()->skip()) + { + if(m_left + m_width + (*i)->width() > m_right) + { + remove_begin = i; + break; + } else + { + (*i)->pos().x += add; + m_width += (*i)->get_el()->width(); + } + } + i++; + } + if(remove_begin != m_items.end()) + { + while(remove_begin != m_items.end()) + { + ret_items.emplace_back(std::move(*remove_begin)); + } + m_items.erase(remove_begin, m_items.end()); + } + } + return ret_items; +} + diff --git a/libs/litehtml/src/media_query.cpp b/libs/litehtml/src/media_query.cpp new file mode 100644 index 0000000000..8c2afff271 --- /dev/null +++ b/libs/litehtml/src/media_query.cpp @@ -0,0 +1,430 @@ +#include "html.h" +#include "media_query.h" +#include "document.h" + + +litehtml::media_query::media_query() +{ + m_media_type = media_type_all; + m_not = false; +} + +litehtml::media_query::media_query( const media_query& val ) +{ + m_not = val.m_not; + m_expressions = val.m_expressions; + m_media_type = val.m_media_type; +} + +litehtml::media_query::ptr litehtml::media_query::create_from_string(const string& str, const std::shared_ptr<document>& doc) +{ + media_query::ptr query = std::make_shared<media_query>(); + + string_vector tokens; + split_string(str, tokens, " \t\r\n", "", "("); + + for(auto & token : tokens) + { + if(token == "not") + { + query->m_not = true; + } else if(token.at(0) == '(') + { + token.erase(0, 1); + if(!token.empty() && token.at(token.length() - 1) == ')') + { + token.erase(token.length() - 1, 1); + } + media_query_expression expr; + string_vector expr_tokens; + split_string(token, expr_tokens, ":"); + if(!expr_tokens.empty()) + { + trim(expr_tokens[0]); + expr.feature = (media_feature) value_index(expr_tokens[0], media_feature_strings, media_feature_none); + if(expr.feature != media_feature_none) + { + if(expr_tokens.size() == 1) + { + expr.check_as_bool = true; + } else + { + trim(expr_tokens[1]); + expr.check_as_bool = false; + if(expr.feature == media_feature_orientation) + { + expr.val = value_index(expr_tokens[1], media_orientation_strings, media_orientation_landscape); + } else + { + string::size_type slash_pos = expr_tokens[1].find('/'); + if( slash_pos != string::npos ) + { + string val1 = expr_tokens[1].substr(0, slash_pos); + string val2 = expr_tokens[1].substr(slash_pos + 1); + trim(val1); + trim(val2); + expr.val = atoi(val1.c_str()); + expr.val2 = atoi(val2.c_str()); + } else + { + css_length length; + length.fromString(expr_tokens[1]); + if(length.units() == css_units_dpcm || length.units() == css_units_dpi) + { + expr.val = (int) (length.val() * 2.54); + } else + { + if(doc) + { + doc->cvt_units(length, doc->container()->get_default_font_size()); + } + expr.val = (int) length.val(); + } + } + } + } + query->m_expressions.push_back(expr); + } + } + } else + { + query->m_media_type = (media_type) value_index(token, media_type_strings, media_type_none); + } + } + + return query; +} + +bool litehtml::media_query::check( const media_features& features ) const +{ + bool res = false; + if(m_media_type == media_type_all || m_media_type == features.type) + { + res = true; + for(auto expression : m_expressions) + { + if(!expression.check(features)) + { + res = false; + break; + } + } + } + + if(m_not) + { + res = !res; + } + + return res; +} + +////////////////////////////////////////////////////////////////////////// + +litehtml::media_query_list::ptr litehtml::media_query_list::create_from_string(const string& str, const std::shared_ptr<document>& doc) +{ + media_query_list::ptr list = std::make_shared<media_query_list>(); + + string_vector tokens; + split_string(str, tokens, ","); + + for(auto & token : tokens) + { + trim(token); + lcase(token); + + litehtml::media_query::ptr query = media_query::create_from_string(token, doc); + if(query) + { + list->m_queries.push_back(query); + } + } + if(list->m_queries.empty()) + { + list = nullptr; + } + + return list; +} + +bool litehtml::media_query_list::apply_media_features( const media_features& features ) +{ + bool apply = false; + + for(auto & query : m_queries) + { + if(query->check(features)) + { + apply = true; + break; + } + } + + bool ret = (apply != m_is_used); + m_is_used = apply; + return ret; +} + +bool litehtml::media_query_expression::check( const media_features& features ) const +{ + switch(feature) + { + case media_feature_width: + if(check_as_bool) + { + return (features.width != 0); + } else if(features.width == val) + { + return true; + } + break; + case media_feature_min_width: + if(features.width >= val) + { + return true; + } + break; + case media_feature_max_width: + if(features.width <= val) + { + return true; + } + break; + case media_feature_height: + if(check_as_bool) + { + return (features.height != 0); + } else if(features.height == val) + { + return true; + } + break; + case media_feature_min_height: + if(features.height >= val) + { + return true; + } + break; + case media_feature_max_height: + if(features.height <= val) + { + return true; + } + break; + + case media_feature_device_width: + if(check_as_bool) + { + return (features.device_width != 0); + } else if(features.device_width == val) + { + return true; + } + break; + case media_feature_min_device_width: + if(features.device_width >= val) + { + return true; + } + break; + case media_feature_max_device_width: + if(features.device_width <= val) + { + return true; + } + break; + case media_feature_device_height: + if(check_as_bool) + { + return (features.device_height != 0); + } else if(features.device_height == val) + { + return true; + } + break; + case media_feature_min_device_height: + if(features.device_height >= val) + { + return true; + } + break; + case media_feature_max_device_height: + if(features.device_height <= val) + { + return true; + } + break; + + case media_feature_orientation: + if(features.height >= features.width) + { + if(val == media_orientation_portrait) + { + return true; + } + } else + { + if(val == media_orientation_landscape) + { + return true; + } + } + break; + case media_feature_aspect_ratio: + if(features.height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); + if(ratio_this == ratio_feat) + { + return true; + } + } + break; + case media_feature_min_aspect_ratio: + if(features.height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); + if(ratio_feat >= ratio_this) + { + return true; + } + } + break; + case media_feature_max_aspect_ratio: + if(features.height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.width / (double) features.height * 100.0 ); + if(ratio_feat <= ratio_this) + { + return true; + } + } + break; + + case media_feature_device_aspect_ratio: + if(features.device_height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); + if(ratio_feat == ratio_this) + { + return true; + } + } + break; + case media_feature_min_device_aspect_ratio: + if(features.device_height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); + if(ratio_feat >= ratio_this) + { + return true; + } + } + break; + case media_feature_max_device_aspect_ratio: + if(features.device_height && val2) + { + int ratio_this = round_d( (double) val / (double) val2 * 100 ); + int ratio_feat = round_d( (double) features.device_width / (double) features.device_height * 100.0 ); + if(ratio_feat <= ratio_this) + { + return true; + } + } + break; + + case media_feature_color: + if(check_as_bool) + { + return (features.color != 0); + } else if(features.color == val) + { + return true; + } + break; + case media_feature_min_color: + if(features.color >= val) + { + return true; + } + break; + case media_feature_max_color: + if(features.color <= val) + { + return true; + } + break; + + case media_feature_color_index: + if(check_as_bool) + { + return (features.color_index != 0); + } else if(features.color_index == val) + { + return true; + } + break; + case media_feature_min_color_index: + if(features.color_index >= val) + { + return true; + } + break; + case media_feature_max_color_index: + if(features.color_index <= val) + { + return true; + } + break; + + case media_feature_monochrome: + if(check_as_bool) + { + return (features.monochrome != 0); + } else if(features.monochrome == val) + { + return true; + } + break; + case media_feature_min_monochrome: + if(features.monochrome >= val) + { + return true; + } + break; + case media_feature_max_monochrome: + if(features.monochrome <= val) + { + return true; + } + break; + + case media_feature_resolution: + if(features.resolution == val) + { + return true; + } + break; + case media_feature_min_resolution: + if(features.resolution >= val) + { + return true; + } + break; + case media_feature_max_resolution: + if(features.resolution <= val) + { + return true; + } + break; + default: + return false; + } + + return false; +} diff --git a/libs/litehtml/src/num_cvt.cpp b/libs/litehtml/src/num_cvt.cpp new file mode 100644 index 0000000000..23d594b5c9 --- /dev/null +++ b/libs/litehtml/src/num_cvt.cpp @@ -0,0 +1,108 @@ +#include "num_cvt.h" +#include "utf8_strings.h" +#include <vector> + +static std::vector<char> latin_lower = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; +static std::vector<char> latin_upper = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; +static std::vector<std::wstring> greek_lower = { L"α", L"β", L"γ", L"δ", L"ε", L"ζ", L"η", L"θ", L"ι", L"κ", L"λ", L"μ", L"ν", L"ξ", L"ο", L"π", L"ρ", L"σ", L"τ", L"υ", L"φ", L"χ", L"ψ", L"ω" }; + +static litehtml::string to_mapped_alpha(int num, const std::vector<char>& map) +{ + int dividend = num; + litehtml::string out; + int modulo; + + while (dividend > 0) + { + modulo = (dividend - 1) % map.size(); + out = map[modulo] + out; + dividend = (int)((dividend - modulo) / map.size()); + } + + return out; +} + +static litehtml::string to_mapped_alpha(int num, const std::vector<std::wstring>& map) +{ + int dividend = num; + litehtml::string out; + int modulo; + + while (dividend > 0) + { + modulo = (dividend - 1) % map.size(); + out = litehtml_from_wchar(map[modulo]).c_str() + out; + dividend = (int)((dividend - modulo) / map.size()); + } + + return out; +} + +litehtml::string litehtml::num_cvt::to_latin_lower(int val) +{ + return to_mapped_alpha(val, latin_lower); +} + +litehtml::string litehtml::num_cvt::to_latin_upper(int val) +{ + return to_mapped_alpha(val, latin_upper); +} + +litehtml::string litehtml::num_cvt::to_greek_lower(int val) +{ + return to_mapped_alpha(val, greek_lower); +} + +litehtml::string litehtml::num_cvt::to_roman_lower(int value) +{ + struct romandata_t { int value; const char* numeral; }; + const struct romandata_t romandata[] = + { + { 1000, "m" }, { 900, "cm" }, + { 500, "d" }, { 400, "cd" }, + { 100, "c" }, { 90, "xc" }, + { 50, "l" }, { 40, "xl" }, + { 10, "x" }, { 9, "ix" }, + { 5, "v" }, { 4, "iv" }, + { 1, "i" }, + { 0, nullptr } // end marker + }; + + litehtml::string result; + for (const romandata_t* current = romandata; current->value > 0; ++current) + { + while (value >= current->value) + { + result += current->numeral; + value -= current->value; + } + } + return result; +} + +litehtml::string litehtml::num_cvt::to_roman_upper(int value) +{ + struct romandata_t { int value; const char* numeral; }; + const struct romandata_t romandata[] = + { + { 1000, "M" }, { 900, "CM" }, + { 500, "D" }, { 400, "CD" }, + { 100, "C" }, { 90, "XC" }, + { 50, "L" }, { 40, "XL" }, + { 10, "X" }, { 9, "IX" }, + { 5, "V" }, { 4, "IV" }, + { 1, "I" }, + { 0, nullptr } // end marker + }; + + litehtml::string result; + for (const romandata_t* current = romandata; current->value > 0; ++current) + { + while (value >= current->value) + { + result += current->numeral; + value -= current->value; + } + } + return result; +} diff --git a/libs/litehtml/src/render_block.cpp b/libs/litehtml/src/render_block.cpp new file mode 100644 index 0000000000..49e6f8fa2d --- /dev/null +++ b/libs/litehtml/src/render_block.cpp @@ -0,0 +1,348 @@ +#include "html.h" +#include "render_block.h" +#include "render_inline_context.h" +#include "render_block_context.h" +#include "document.h" + +int litehtml::render_item_block::place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + int line_top = fmt_ctx->get_cleared_top(el, top); + int line_left = 0; + int line_right = self_size.render_width; + fmt_ctx->get_line_left_right(line_top, self_size.render_width, line_left, line_right); + + int ret_width = 0; + + int min_rendered_width = el->render(line_left, line_top, self_size.new_width(line_right), fmt_ctx); + if(min_rendered_width < el->width() && el->src_el()->css().get_width().is_predefined()) + { + el->render(line_left, line_top, self_size.new_width(min_rendered_width), fmt_ctx); + } + + if (el->src_el()->css().get_float() == float_left) + { + if(el->right() > line_right) + { + line_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width); + el->pos().x = fmt_ctx->get_line_left(line_top) + el->content_offset_left(); + el->pos().y = line_top + el->content_offset_top(); + } + fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx); + fix_line_width(float_left, self_size, fmt_ctx); + + ret_width = fmt_ctx->find_min_left(line_top, self_size.context_idx); + } else if (el->src_el()->css().get_float() == float_right) + { + if(line_left + el->width() > line_right) + { + int new_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width); + el->pos().x = fmt_ctx->get_line_right(new_top, self_size.render_width) - el->width() + el->content_offset_left(); + el->pos().y = new_top + el->content_offset_top(); + } else + { + el->pos().x = line_right - el->width() + el->content_offset_left(); + } + fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx); + fix_line_width(float_right, self_size, fmt_ctx); + line_right = fmt_ctx->find_min_right(line_top, self_size.render_width, self_size.context_idx); + ret_width = self_size.render_width - line_right; + } + return ret_width; +} + +std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init() +{ + { + css_selector sel; + sel.parse(".inline_rating"); + if(src_el()->select(sel)) + { + int i = 0; + i++; + } + } + std::shared_ptr<render_item> ret; + + // Initialize indexes for list items + if(src_el()->css().get_display() == display_list_item && src_el()->css().get_list_style_type() >= list_style_type_armenian) + { + if (auto p = src_el()->parent()) + { + int val = atoi(p->get_attr("start", "1")); + for(const auto &child : p->children()) + { + if (child == src_el()) + { + src_el()->set_attr("list_index", std::to_string(val).c_str()); + break; + } + else if (child->css().get_display() == display_list_item) + val++; + } + } + } + // Split inline blocks with box blocks inside + auto iter = m_children.begin(); + while (iter != m_children.end()) + { + const auto& el = *iter; + if(el->src_el()->css().get_display() == display_inline && !el->children().empty()) + { + auto split_el = el->split_inlines(); + if(std::get<0>(split_el)) + { + iter = m_children.erase(iter); + iter = m_children.insert(iter, std::get<2>(split_el)); + iter = m_children.insert(iter, std::get<1>(split_el)); + iter = m_children.insert(iter, std::get<0>(split_el)); + + std::get<0>(split_el)->parent(shared_from_this()); + std::get<1>(split_el)->parent(shared_from_this()); + std::get<2>(split_el)->parent(shared_from_this()); + continue; + } + } + ++iter; + } + + bool has_block_level = false; + bool has_inlines = false; + for (const auto& el : m_children) + { + if(!el->src_el()->is_float()) + { + if (el->src_el()->is_block_box()) + { + has_block_level = true; + } else if (el->src_el()->is_inline()) + { + has_inlines = true; + } + } + if(has_block_level && has_inlines) + break; + } + if(has_block_level) + { + ret = std::make_shared<render_item_block_context>(src_el()); + ret->parent(parent()); + + auto doc = src_el()->get_document(); + decltype(m_children) new_children; + decltype(m_children) inlines; + bool not_ws_added = false; + for (const auto& el : m_children) + { + if(el->src_el()->is_inline()) + { + inlines.push_back(el); + if(!el->src_el()->is_white_space()) + not_ws_added = true; + } else + { + if(not_ws_added) + { + auto anon_el = std::make_shared<html_tag>(src_el()); + auto anon_ri = std::make_shared<render_item_block>(anon_el); + for(const auto& inl : inlines) + { + anon_ri->add_child(inl); + } + + not_ws_added = false; + new_children.push_back(anon_ri); + anon_ri->parent(ret); + } + new_children.push_back(el); + el->parent(ret); + inlines.clear(); + } + } + if(!inlines.empty() && not_ws_added) + { + auto anon_el = std::make_shared<html_tag>(src_el()); + auto anon_ri = std::make_shared<render_item_block>(anon_el); + for(const auto& inl : inlines) + { + anon_ri->add_child(inl); + } + + new_children.push_back(anon_ri); + anon_ri->parent(ret); + } + ret->children() = new_children; + } + + if(!ret) + { + ret = std::make_shared<render_item_inline_context>(src_el()); + ret->parent(parent()); + ret->children() = children(); + for (const auto &el: ret->children()) + { + el->parent(ret); + } + } + + ret->src_el()->add_render(ret); + + for(auto& el : ret->children()) + { + el = el->init(); + } + + return ret; +} + +int litehtml::render_item_block::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) +{ + containing_block_context self_size = calculate_containing_block_context(containing_block_size); + + //***************************************** + // Render content + //***************************************** + int ret_width = _render_content(x, y, second_pass, self_size, fmt_ctx); + //***************************************** + + bool requires_rerender = false; // when true, the second pass for content rendering is required + + // Set block width + if(!(containing_block_size.size_mode & containing_block_context::size_mode_content)) + { + if(self_size.width.type == containing_block_context::cbc_value_type_absolute) + { + ret_width = m_pos.width = self_size.render_width; + } else + { + m_pos.width = self_size.render_width; + } + } else + { + m_pos.width = ret_width; + if(self_size.width.type == containing_block_context::cbc_value_type_absolute && ret_width > self_size.width) + { + ret_width = self_size.width; + } + } + + // Fix width with max-width attribute + if(self_size.max_width.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.width > self_size.max_width) + { + m_pos.width = self_size.max_width; + requires_rerender = true; + } + } + + // Fix width with min-width attribute + if(self_size.min_width.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.width < self_size.min_width) + { + m_pos.width = self_size.min_width; + requires_rerender = true; + } + } else if(m_pos.width < 0) + { + m_pos.width = 0; + } + + // re-render content with new width if required + if (requires_rerender && !second_pass && !is_root()) + { + if(src_el()->is_block_formatting_context()) + { + fmt_ctx->clear_floats(-1); + } else + { + fmt_ctx->clear_floats(self_size.context_idx); + } + + _render_content(x, y, true, self_size.new_width(m_pos.width), fmt_ctx); + } + + // Set block height + if (self_size.height.type != containing_block_context::cbc_value_type_auto && + !(containing_block_size.size_mode & containing_block_context::size_mode_content)) + { + // TODO: Something wrong here + // Percentage height from undefined containing block height is usually <= 0 + if(self_size.height.type == containing_block_context::cbc_value_type_percentage) + { + if (self_size.height > 0) + { + m_pos.height = self_size.height; + } + } else + { + m_pos.height = self_size.height; + } + if (src_el()->css().get_box_sizing() == box_sizing_border_box) + { + m_pos.height -= box_sizing_height(); + } + } else if (src_el()->is_block_formatting_context()) + { + // add the floats' height to the block height + int floats_height = fmt_ctx->get_floats_height(); + if (floats_height > m_pos.height) + { + m_pos.height = floats_height; + } + } + if(containing_block_size.size_mode & containing_block_context::size_mode_content) + { + if(self_size.height.type == containing_block_context::cbc_value_type_absolute) + { + if(m_pos.height > self_size.height) + { + m_pos.height = self_size.height; + } + } + } + + // Fix height with min-height attribute + if(self_size.min_height.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.height < self_size.min_height) + { + m_pos.height = self_size.min_height; + } + } else if(m_pos.height < 0) + { + m_pos.height = 0; + } + + // Fix width with max-width attribute + if(self_size.max_height.type != containing_block_context::cbc_value_type_none) + { + if(m_pos.height > self_size.max_height) + { + m_pos.height = self_size.max_height; + } + } + + // calculate the final position + m_pos.move_to(x, y); + m_pos.x += content_offset_left(); + m_pos.y += content_offset_top(); + + if (src_el()->css().get_display() == display_list_item) + { + string list_image = src_el()->css().get_list_style_image(); + if (!list_image.empty()) + { + size sz; + string list_image_baseurl = src_el()->css().get_list_style_image_baseurl(); + src_el()->get_document()->container()->get_image_size(list_image.c_str(), list_image_baseurl.c_str(), sz); + if (m_pos.height < sz.height) + { + m_pos.height = sz.height; + } + } + + } + + return ret_width + content_offset_width(); +} diff --git a/libs/litehtml/src/render_block_context.cpp b/libs/litehtml/src/render_block_context.cpp new file mode 100644 index 0000000000..205485d478 --- /dev/null +++ b/libs/litehtml/src/render_block_context.cpp @@ -0,0 +1,154 @@ +#include "html.h" +#include "render_block_context.h" +#include "document.h" + +int litehtml::render_item_block_context::_render_content(int /*x*/, int /*y*/, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + element_position el_position; + + int ret_width = 0; + int child_top = 0; + int last_margin = 0; + std::shared_ptr<render_item> last_margin_el; + bool is_first = true; + for (const auto& el : m_children) + { + // we don't need to process absolute and fixed positioned element on the second pass + if (second_pass) + { + el_position = el->src_el()->css().get_position(); + if ((el_position == element_position_absolute || el_position == element_position_fixed)) continue; + } + + if(el->src_el()->css().get_float() != float_none) + { + int rw = place_float(el, child_top, self_size, fmt_ctx); + if (rw > ret_width) + { + ret_width = rw; + } + } else if(el->src_el()->css().get_display() != display_none) + { + if(el->src_el()->css().get_position() == element_position_absolute || el->src_el()->css().get_position() == element_position_fixed) + { + int min_rendered_width = el->render(0, child_top, self_size, fmt_ctx); + if(min_rendered_width < el->width() && el->src_el()->css().get_width().is_predefined()) + { + el->render(0, child_top, self_size.new_width(min_rendered_width), fmt_ctx); + } + } else + { + child_top = fmt_ctx->get_cleared_top(el, child_top); + int child_x = 0; + int child_width = self_size.render_width; + + el->calc_outlines(self_size.width); + + // Collapse top margin + if(is_first && collapse_top_margin()) + { + if(el->get_margins().top > 0) + { + child_top -= el->get_margins().top; + if (el->get_margins().top > get_margins().top) + { + m_margins.top = el->get_margins().top; + } + } + } else + { + if(el->get_margins().top > 0) + { + if (last_margin > el->get_margins().top) + { + child_top -= el->get_margins().top; + } else + { + child_top -= last_margin; + } + } + } + + if(el->src_el()->is_replaced() || el->src_el()->is_block_formatting_context() || el->src_el()->css().get_display() == display_table) + { + int ln_left = 0; + int ln_right = child_width; + fmt_ctx->get_line_left_right(child_top, child_width, ln_left, ln_right); + child_x = ln_left; + child_width = ln_right - ln_left; + + auto el_parent = el->parent(); + el->pos().width = el->src_el()->css().get_width().calc_percent(child_width); + el->pos().height = el->src_el()->css().get_height().calc_percent(el_parent ? el_parent->pos().height : 0); + } + + int rw = el->render(child_x, child_top, self_size.new_width(child_width), fmt_ctx); + // Render table with "width: auto" into returned width + if(el->src_el()->css().get_display() == display_table && rw < child_width && el->src_el()->css().get_width().is_predefined()) + { + el->render(child_x, child_top, self_size.new_width(rw), fmt_ctx); + } + int auto_margin = el->calc_auto_margins(child_width); + if(auto_margin) + { + el->pos().x += auto_margin; + } + if (rw > ret_width) + { + ret_width = rw; + } + child_top += el->height(); + last_margin = el->get_margins().bottom; + last_margin_el = el; + is_first = false; + + if (el->src_el()->css().get_position() == element_position_relative) + { + el->apply_relative_shift(self_size); + } + } + } + } + + if (self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0) + { + m_pos.height = self_size.height; + } else + { + m_pos.height = child_top; + if(collapse_bottom_margin()) + { + m_pos.height -= last_margin; + if(m_margins.bottom < last_margin) + { + m_margins.bottom = last_margin; + } + if(last_margin_el) + { + last_margin_el->get_margins().bottom = 0; + } + } + } + + return ret_width; +} + +int litehtml::render_item_block_context::get_first_baseline() +{ + if(m_children.empty()) + { + return height() - margin_bottom(); + } + const auto &item = m_children.front(); + return content_offset_top() + item->top() + item->get_first_baseline(); +} + +int litehtml::render_item_block_context::get_last_baseline() +{ + if(m_children.empty()) + { + return height() - margin_bottom(); + } + const auto &item = m_children.back(); + return content_offset_top() + item->top() + item->get_last_baseline(); +} diff --git a/libs/litehtml/src/render_flex.cpp b/libs/litehtml/src/render_flex.cpp new file mode 100644 index 0000000000..7b497cf312 --- /dev/null +++ b/libs/litehtml/src/render_flex.cpp @@ -0,0 +1,448 @@ +#include "html.h" +#include "types.h" +#include "render_flex.h" + +int litehtml::render_item_flex::_render_content(int x, int y, bool /*second_pass*/, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + bool is_row_direction = true; + bool reverse = false; + int container_main_size = self_size.render_width; + + switch (css().get_flex_direction()) + { + case flex_direction_column: + is_row_direction = false; + reverse = false; + break; + case flex_direction_column_reverse: + is_row_direction = false; + reverse = true; + break; + case flex_direction_row: + is_row_direction = true; + reverse = false; + break; + case flex_direction_row_reverse: + is_row_direction = true; + reverse = true; + break; + } + + bool single_line = css().get_flex_wrap() == flex_wrap_nowrap; + bool fit_container = false; + + if(!is_row_direction) + { + if(self_size.height.type != containing_block_context::cbc_value_type_auto) + { + container_main_size = self_size.height; + if (css().get_box_sizing() == box_sizing_border_box) + { + container_main_size -= box_sizing_height(); + } + } else + { + // Direction columns, height is auto - always in single line + container_main_size = 0; + single_line = true; + fit_container = true; + } + if(self_size.min_height.type != containing_block_context::cbc_value_type_auto && self_size.min_height > container_main_size) + { + container_main_size = self_size.min_height; + } + if(self_size.max_height.type != containing_block_context::cbc_value_type_auto && self_size.max_height > container_main_size) + { + container_main_size = self_size.max_height; + single_line = false; + } + } + + ///////////////////////////////////////////////////////////////// + /// Split flex items to lines + ///////////////////////////////////////////////////////////////// + m_lines = get_lines(self_size, fmt_ctx, is_row_direction, container_main_size, single_line); + + int sum_cross_size = 0; + int sum_main_size = 0; + int ret_width = 0; + + ///////////////////////////////////////////////////////////////// + /// Resolving Flexible Lengths + /// REF: https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths + ///////////////////////////////////////////////////////////////// + for(auto& ln : m_lines) + { + if(is_row_direction) + { + ret_width += ln.base_size; + } + ln.init(container_main_size, fit_container, is_row_direction, self_size, fmt_ctx); + sum_cross_size += ln.cross_size; + sum_main_size = std::max(sum_main_size, ln.main_size); + if(reverse) + { + ln.items.reverse(); + } + } + + int free_cross_size = 0; + bool is_wrap_reverse = css().get_flex_wrap() == flex_wrap_wrap_reverse; + if(container_main_size == 0) + { + container_main_size = sum_main_size; + } + + ///////////////////////////////////////////////////////////////// + /// Calculate free cross size + ///////////////////////////////////////////////////////////////// + if (is_row_direction) + { + if (self_size.height.type != containing_block_context::cbc_value_type_auto) + { + int height = self_size.height; + if (src_el()->css().get_box_sizing() == box_sizing_border_box) + { + height -= box_sizing_height(); + } + free_cross_size = height - sum_cross_size; + } + } else + { + free_cross_size = self_size.render_width - sum_cross_size; + ret_width = sum_cross_size; + } + + ///////////////////////////////////////////////////////////////// + /// Fix align-content property + ///////////////////////////////////////////////////////////////// + flex_align_content align_content = css().get_flex_align_content(); + if(align_content == flex_align_content_space_between) + { + // If the leftover free-space is negative or there is only a single flex line in the flex + // container, this value is identical to flex-start. + if (m_lines.size() == 1 || free_cross_size < 0) align_content = flex_align_content_flex_start; + } + if(align_content == flex_align_content_space_around) + { + // If the leftover free-space is negative or there is only a single flex line in the flex + // container, this value is identical to flex-start. + if (m_lines.size() == 1 || free_cross_size < 0) align_content = flex_align_content_center; + } + + ///////////////////////////////////////////////////////////////// + /// Distribute free cross size for align-content: stretch + ///////////////////////////////////////////////////////////////// + if(css().get_flex_align_content() == flex_align_content_stretch && free_cross_size > 0) + { + int add = (int)((double) free_cross_size / (double) m_lines.size()); + if(add > 0) + { + for (auto &ln: m_lines) + { + ln.cross_size += add; + free_cross_size -= add; + } + } + if(!m_lines.empty()) + { + while (free_cross_size > 0) + { + for (auto &ln: m_lines) + { + ln.cross_size++; + free_cross_size--; + } + } + } + } + + /// Reverse lines for flex-wrap: wrap-reverse + if(css().get_flex_wrap() == flex_wrap_wrap_reverse) + { + m_lines.reverse(); + } + + ///////////////////////////////////////////////////////////////// + /// Align flex lines + ///////////////////////////////////////////////////////////////// + int line_pos = 0; + int add_before_line = 0; + int add_after_line = 0; + switch (align_content) + { + case flex_align_content_flex_start: + if(is_wrap_reverse) + { + line_pos = free_cross_size; + } + break; + case flex_align_content_flex_end: + if(!is_wrap_reverse) + { + line_pos = free_cross_size; + } + break; + case flex_align_content_end: + line_pos = free_cross_size; + break; + case flex_align_content_center: + line_pos = free_cross_size / 2; + break; + case flex_align_content_space_between: + add_after_line = free_cross_size / ((int) m_lines.size() - 1); + break; + case flex_align_content_space_around: + add_before_line = add_after_line = free_cross_size / ((int) m_lines.size() * 2); + break; + default: + if(is_wrap_reverse) + { + line_pos = free_cross_size; + } + break; + } + for(auto &ln : m_lines) + { + line_pos += add_before_line; + ln.cross_start = line_pos; + line_pos += ln.cross_size + add_after_line; + } + + /// Fix justify-content property + flex_justify_content justify_content = css().get_flex_justify_content(); + if((justify_content == flex_justify_content_right || justify_content == flex_justify_content_left) && !is_row_direction) + { + justify_content = flex_justify_content_start; + } + + ///////////////////////////////////////////////////////////////// + /// Align flex items in flex lines + ///////////////////////////////////////////////////////////////// + for(auto &ln : m_lines) + { + int height = ln.calculate_items_position(container_main_size, + justify_content, + is_row_direction, + self_size, + fmt_ctx); + m_pos.height = std::max(m_pos.height, height); + } + + // calculate the final position + m_pos.move_to(x, y); + m_pos.x += content_offset_left(); + m_pos.y += content_offset_top(); + + return ret_width; +} + +std::list<litehtml::flex_line> litehtml::render_item_flex::get_lines(const litehtml::containing_block_context &self_size, + litehtml::formatting_context *fmt_ctx, + bool is_row_direction, int container_main_size, + bool single_line) +{ + bool reverse_main; + bool reverse_cross = css().get_flex_wrap() == flex_wrap_wrap_reverse; + + if(is_row_direction) + { + reverse_main = css().get_flex_direction() == flex_direction_row_reverse; + } else + { + reverse_main = css().get_flex_direction() == flex_direction_column_reverse; + } + + std::list<flex_line> lines; + flex_line line(reverse_main, reverse_cross); + std::list<std::shared_ptr<flex_item>> items; + int src_order = 0; + bool sort_required = false; + def_value<int> prev_order(0); + + for( auto& el : m_children) + { + std::shared_ptr<flex_item> item = nullptr; + if(is_row_direction) + { + item = std::make_shared<flex_item_row_direction>(el); + } else + { + item = std::make_shared<flex_item_column_direction>(el); + } + item->init(self_size, fmt_ctx, css().get_flex_align_items()); + item->src_order = src_order++; + + if(prev_order.is_default()) + { + prev_order = item->order; + } else if(!sort_required && item->order != prev_order) + { + sort_required = true; + } + + items.emplace_back(item); + } + + if(sort_required) + { + items.sort([](const std::shared_ptr<flex_item>& item1, const std::shared_ptr<flex_item>& item2) + { + if(item1->order < item2->order) return true; + if(item1->order == item2->order) + { + return item1->src_order < item2->src_order; + } + return false; + }); + } + + // Add flex items to lines + for(auto& item : items) + { + if(!line.items.empty() && !single_line && line.base_size + item->base_size > container_main_size) + { + lines.emplace_back(line); + line = flex_line(reverse_main, reverse_cross); + } + line.base_size += item->base_size; + line.total_grow += item->grow; + line.total_shrink += item->shrink; + if(!item->auto_margin_main_start.is_default()) line.num_auto_margin_main_start++; + if(!item->auto_margin_main_end.is_default()) line.num_auto_margin_main_end++; + line.items.push_back(item); + } + // Add the last line to the lines list + if(!line.items.empty()) + { + lines.emplace_back(line); + } + return lines; +} + +std::shared_ptr<litehtml::render_item> litehtml::render_item_flex::init() +{ + auto doc = src_el()->get_document(); + decltype(m_children) new_children; + decltype(m_children) inlines; + + auto convert_inlines = [&]() + { + if(!inlines.empty()) + { + // Find last not space + auto not_space = std::find_if(inlines.rbegin(), inlines.rend(), [&](const std::shared_ptr<render_item>& el) + { + return !el->src_el()->is_space(); + }); + if(not_space != inlines.rend()) + { + // Erase all spaces at the end + inlines.erase((not_space.base()), inlines.end()); + } + + auto anon_el = std::make_shared<html_tag>(src_el()); + auto anon_ri = std::make_shared<render_item_block>(anon_el); + for(const auto& inl : inlines) + { + anon_ri->add_child(inl); + } + anon_ri->parent(shared_from_this()); + + new_children.push_back(anon_ri->init()); + inlines.clear(); + } + }; + + for (const auto& el : m_children) + { + if(el->src_el()->css().get_display() == display_inline_text) + { + if(!inlines.empty()) + { + inlines.push_back(el); + } else + { + if (!el->src_el()->is_white_space()) + { + inlines.push_back(el); + } + } + } else + { + convert_inlines(); + if(el->src_el()->is_block_box()) + { + // Add block boxes as is + el->parent(shared_from_this()); + new_children.push_back(el->init()); + } else + { + // Wrap inlines with anonymous block box + auto anon_el = std::make_shared<html_tag>(el->src_el()); + auto anon_ri = std::make_shared<render_item_block>(anon_el); + anon_ri->add_child(el->init()); + anon_ri->parent(shared_from_this()); + new_children.push_back(anon_ri->init()); + } + } + } + convert_inlines(); + children() = new_children; + + return shared_from_this(); +} + +int litehtml::render_item_flex::get_first_baseline() +{ + if(css().get_flex_direction() == flex_direction_row || css().get_flex_direction() == flex_direction_row_reverse) + { + if(!m_lines.empty()) + { + const auto &first_line = m_lines.front(); + if(first_line.first_baseline.type() != baseline::baseline_type_none) + { + return first_line.cross_start + first_line.first_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top(); + } + if(first_line.last_baseline.type() != baseline::baseline_type_none) + { + return first_line.cross_start + first_line.last_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top(); + } + } + } + if(!m_lines.empty()) + { + if(!m_lines.front().items.empty()) + { + return m_lines.front().items.front()->el->get_first_baseline() + content_offset_top(); + } + } + return height(); +} + +int litehtml::render_item_flex::get_last_baseline() +{ + if(css().get_flex_direction() == flex_direction_row || css().get_flex_direction() == flex_direction_row_reverse) + { + if(!m_lines.empty()) + { + const auto &first_line = m_lines.front(); + if(first_line.last_baseline.type() != baseline::baseline_type_none) + { + return first_line.cross_start + first_line.last_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top(); + } + if(first_line.first_baseline.type() != baseline::baseline_type_none) + { + return first_line.cross_start + first_line.first_baseline.get_offset_from_top(first_line.cross_size) + content_offset_top(); + } + } + } + if(!m_lines.empty()) + { + if(!m_lines.front().items.empty()) + { + return m_lines.front().items.front()->el->get_last_baseline() + content_offset_top(); + } + } + return height(); +} diff --git a/libs/litehtml/src/render_image.cpp b/libs/litehtml/src/render_image.cpp new file mode 100644 index 0000000000..122344651b --- /dev/null +++ b/libs/litehtml/src/render_image.cpp @@ -0,0 +1,148 @@ +#include "html.h" +#include "render_image.h" +#include "document.h" + +int litehtml::render_item_image::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* /*fmt_ctx*/, bool /*second_pass*/) +{ + int parent_width = containing_block_size.width; + containing_block_context self_size = calculate_containing_block_context(containing_block_size); + + calc_outlines(parent_width); + + m_pos.move_to(x, y); + + document::ptr doc = src_el()->get_document(); + + litehtml::size sz; + src_el()->get_content_size(sz, containing_block_size.width); + + m_pos.width = sz.width; + m_pos.height = sz.height; + + src_el()->css_w().set_line_height(height()); + + if(src_el()->css().get_height().is_predefined() && src_el()->css().get_width().is_predefined()) + { + m_pos.height = sz.height; + m_pos.width = sz.width; + + // check for max-width + if(!src_el()->css().get_max_width().is_predefined()) + { + int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width); + if(m_pos.width > max_width) + { + m_pos.width = max_width; + } + if(sz.width) + { + m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width); + } else + { + m_pos.height = sz.height; + } + } + + // check for max-height + if(!src_el()->css().get_max_height().is_predefined()) + { + int max_height = calc_max_height(sz.height, containing_block_size.height); + if(m_pos.height > max_height) + { + m_pos.height = max_height; + } + if(sz.height) + { + m_pos.width = (int) ((float )m_pos.height * (float)sz.width / (float)sz.height); + } else + { + m_pos.width = sz.width; + } + } + } else if(!src_el()->css().get_height().is_predefined() && src_el()->css().get_width().is_predefined()) + { + if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0) + { + m_pos.height = self_size.height; + } + + // check for max-height + if(!src_el()->css().get_max_height().is_predefined()) + { + int max_height = calc_max_height(sz.height, containing_block_size.height); + if(m_pos.height > max_height) + { + m_pos.height = max_height; + } + } + + if(sz.height) + { + m_pos.width = (int) ((float )m_pos.height * (float)sz.width / (float)sz.height); + } else + { + m_pos.width = sz.width; + } + } else if(src_el()->css().get_height().is_predefined() && !src_el()->css().get_width().is_predefined()) + { + m_pos.width = (int) src_el()->css().get_width().calc_percent(parent_width); + + // check for max-width + if(!src_el()->css().get_max_width().is_predefined()) + { + int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width); + if(m_pos.width > max_width) + { + m_pos.width = max_width; + } + } + + if(sz.width) + { + m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width); + } else + { + m_pos.height = sz.height; + } + } else + { + m_pos.width = (int) src_el()->css().get_width().calc_percent(parent_width); + m_pos.height = 0; + if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0) + { + m_pos.height = self_size.height; + } + + // check for max-height + if(!src_el()->css().get_max_height().is_predefined()) + { + int max_height = calc_max_height(sz.height, containing_block_size.height); + if(m_pos.height > max_height) + { + m_pos.height = max_height; + } + } + + // check for max-height + if(!src_el()->css().get_max_width().is_predefined()) + { + int max_width = doc->to_pixels(src_el()->css().get_max_width(), src_el()->css().get_font_size(), parent_width); + if(m_pos.width > max_width) + { + m_pos.width = max_width; + } + } + } + + m_pos.x += content_offset_left(); + m_pos.y += content_offset_top(); + + return m_pos.width + content_offset_left() + content_offset_right(); +} + +int litehtml::render_item_image::calc_max_height(int image_height, int containing_block_height) +{ + document::ptr doc = src_el()->get_document(); + return doc->to_pixels(src_el()->css().get_max_height(), src_el()->css().get_font_size(), + containing_block_height == 0 ? image_height : containing_block_height); +} diff --git a/libs/litehtml/src/render_inline_context.cpp b/libs/litehtml/src/render_inline_context.cpp new file mode 100644 index 0000000000..b1ca1fcadc --- /dev/null +++ b/libs/litehtml/src/render_inline_context.cpp @@ -0,0 +1,409 @@ +#include "html.h" +#include "render_inline_context.h" +#include "document.h" +#include "iterators.h" + +int litehtml::render_item_inline_context::_render_content(int /*x*/, int /*y*/, bool /*second_pass*/, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + m_line_boxes.clear(); + m_max_line_width = 0; + + white_space ws = src_el()->css().get_white_space(); + bool skip_spaces = false; + if (ws == white_space_normal || + ws == white_space_nowrap || + ws == white_space_pre_line) + { + skip_spaces = true; + } + + bool was_space = false; + + go_inside_inline go_inside_inlines_selector; + inline_selector select_inlines; + elements_iterator inlines_iter(true, &go_inside_inlines_selector, &select_inlines); + + inlines_iter.process(shared_from_this(), [&](const std::shared_ptr<render_item>& el, iterator_item_type item_type) + { + switch (item_type) + { + case iterator_item_type_child: + { + // skip spaces to make rendering a bit faster + if (skip_spaces) + { + if (el->src_el()->is_white_space()) + { + if (was_space) + { + el->skip(true); + return; + } else + { + was_space = true; + } + } else + { + // skip all spaces after line break + was_space = el->src_el()->is_break(); + } + } + // place element into rendering flow + place_inline(std::unique_ptr<line_box_item>(new line_box_item(el)), self_size, fmt_ctx); + } + break; + + case iterator_item_type_start_parent: + { + el->clear_inline_boxes(); + place_inline(std::unique_ptr<lbi_start>(new lbi_start(el)), self_size, fmt_ctx); + } + break; + + case iterator_item_type_end_parent: + { + place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size, fmt_ctx); + } + break; + } + }); + + finish_last_box(true, self_size); + + if (!m_line_boxes.empty()) + { + if (collapse_top_margin()) + { + int old_top = m_margins.top; + m_margins.top = std::max(m_line_boxes.front()->top_margin(), m_margins.top); + if (m_margins.top != old_top) + { + fmt_ctx->update_floats(m_margins.top - old_top, shared_from_this()); + } + } + if (collapse_bottom_margin()) + { + m_margins.bottom = std::max(m_line_boxes.back()->bottom_margin(), m_margins.bottom); + m_pos.height = m_line_boxes.back()->bottom() - m_line_boxes.back()->bottom_margin(); + } + else + { + m_pos.height = m_line_boxes.back()->bottom(); + } + } + + return m_max_line_width; +} + +void litehtml::render_item_inline_context::fix_line_width(element_float flt, + const containing_block_context &self_size, + formatting_context* fmt_ctx) +{ + if(!m_line_boxes.empty()) + { + auto el_front = m_line_boxes.back()->get_first_text_part(); + + std::vector<std::shared_ptr<render_item>> els; + bool was_cleared = false; + if(el_front && el_front->src_el()->css().get_clear() != clear_none) + { + if(el_front->src_el()->css().get_clear() == clear_both) + { + was_cleared = true; + } else + { + if( (flt == float_left && el_front->src_el()->css().get_clear() == clear_left) || + (flt == float_right && el_front->src_el()->css().get_clear() == clear_right) ) + { + was_cleared = true; + } + } + } + + if(!was_cleared) + { + std::list<std::unique_ptr<line_box_item> > items = std::move(m_line_boxes.back()->items()); + m_line_boxes.pop_back(); + + for(auto& item : items) + { + place_inline(std::move(item), self_size, fmt_ctx); + } + } else + { + int line_top = 0; + line_top = m_line_boxes.back()->top(); + + int line_left = 0; + int line_right = self_size.render_width; + fmt_ctx->get_line_left_right(line_top, self_size.render_width, line_left, line_right); + + if(m_line_boxes.size() == 1) + { + if (src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside) + { + int sz_font = src_el()->css().get_font_size(); + line_left += sz_font; + } + + if (src_el()->css().get_text_indent().val() != 0) + { + line_left += src_el()->css().get_text_indent().calc_percent(self_size.width); + } + + } + + auto items = m_line_boxes.back()->new_width(line_left, line_right); + for(auto& item : items) + { + place_inline(std::move(item), self_size, fmt_ctx); + } + } + } +} + +std::list<std::unique_ptr<litehtml::line_box_item> > litehtml::render_item_inline_context::finish_last_box(bool end_of_render, const containing_block_context &self_size) +{ + std::list<std::unique_ptr<line_box_item> > ret; + + if(!m_line_boxes.empty()) + { + ret = m_line_boxes.back()->finish(end_of_render, self_size); + + if(m_line_boxes.back()->is_empty() && end_of_render) + { + // remove the last empty line + m_line_boxes.pop_back(); + } else + { + m_max_line_width = std::max(m_max_line_width, m_line_boxes.back()->min_width()); + } + } + return ret; +} + +int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + auto items = finish_last_box(false, self_size); + int line_top = 0; + if(!m_line_boxes.empty()) + { + line_top = m_line_boxes.back()->bottom(); + } + line_ctx.top = fmt_ctx->get_cleared_top(el->get_el(), line_top); + + line_ctx.left = 0; + line_ctx.right = self_size.render_width; + line_ctx.fix_top(); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + + if(el->get_el()->src_el()->is_inline() || el->get_el()->src_el()->is_block_formatting_context()) + { + if (el->get_el()->width() > line_ctx.right - line_ctx.left) + { + line_ctx.top = fmt_ctx->find_next_line_top(line_ctx.top, el->get_el()->width(), self_size.render_width); + line_ctx.left = 0; + line_ctx.right = self_size.render_width; + line_ctx.fix_top(); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + } + } + + int first_line_margin = 0; + int text_indent = 0; + if(m_line_boxes.empty()) + { + if(src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside) + { + int sz_font = src_el()->css().get_font_size(); + first_line_margin = sz_font; + } + if(src_el()->css().get_text_indent().val() != 0) + { + text_indent = src_el()->css().get_text_indent().calc_percent(self_size.width); + } + } + + m_line_boxes.emplace_back(std::unique_ptr<line_box>(new line_box( + line_ctx.top, + line_ctx.left + first_line_margin + text_indent, line_ctx.right, + css().get_line_height(), + css().get_font_metrics(), + css().get_text_align()))); + + // Add items returned by finish_last_box function into the new line + for(auto& it : items) + { + m_line_boxes.back()->add_item(std::move(it)); + } + + return line_ctx.top; +} + +void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size, formatting_context* fmt_ctx) +{ + if(item->get_el()->src_el()->css().get_display() == display_none) return; + + if(item->get_el()->src_el()->is_float()) + { + int line_top = 0; + if(!m_line_boxes.empty()) + { + line_top = m_line_boxes.back()->top(); + } + int ret = place_float(item->get_el(), line_top, self_size, fmt_ctx); + if(ret > m_max_line_width) + { + m_max_line_width = ret; + } + return; + } + + line_context line_ctx; + if (!m_line_boxes.empty()) + { + line_ctx.top = m_line_boxes.back().get()->top(); + } + line_ctx.right = self_size.render_width; + line_ctx.fix_top(); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + + if(item->get_type() == line_box_item::type_text_part) + { + if(item->get_el()->src_el()->is_inline_box()) + { + int min_rendered_width = item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(line_ctx.right), fmt_ctx); + if(min_rendered_width < item->get_el()->width() && item->get_el()->src_el()->css().get_width().is_predefined()) + { + item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(min_rendered_width), fmt_ctx); + } + item->set_rendered_min_width(min_rendered_width); + } else if(item->get_el()->src_el()->css().get_display() == display_inline_text) + { + litehtml::size sz; + item->get_el()->src_el()->get_content_size(sz, line_ctx.right); + item->get_el()->pos() = sz; + item->set_rendered_min_width(sz.width); + } + } + + bool add_box = true; + if(!m_line_boxes.empty()) + { + if(m_line_boxes.back()->can_hold(item, src_el()->css().get_white_space())) + { + add_box = false; + } + } + if(add_box) + { + new_box(item, line_ctx, self_size, fmt_ctx); + } else if(!m_line_boxes.empty()) + { + line_ctx.top = m_line_boxes.back()->top(); + } + + if (line_ctx.top != line_ctx.calculatedTop) + { + line_ctx.left = 0; + line_ctx.right = self_size.render_width; + line_ctx.fix_top(); + fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right); + } + + if(!item->get_el()->src_el()->is_inline()) + { + if(m_line_boxes.size() == 1) + { + if(collapse_top_margin()) + { + int shift = item->get_el()->margin_top(); + if(shift >= 0) + { + line_ctx.top -= shift; + m_line_boxes.back()->y_shift(-shift); + } + } + } else + { + int shift = 0; + int prev_margin = m_line_boxes[m_line_boxes.size() - 2]->bottom_margin(); + + if(prev_margin > item->get_el()->margin_top()) + { + shift = item->get_el()->margin_top(); + } else + { + shift = prev_margin; + } + if(shift >= 0) + { + line_ctx.top -= shift; + m_line_boxes.back()->y_shift(-shift); + } + } + } + + m_line_boxes.back()->add_item(std::move(item)); +} + +void litehtml::render_item_inline_context::apply_vertical_align() +{ + if(!m_line_boxes.empty()) + { + int add = 0; + int content_height = m_line_boxes.back()->bottom(); + + if(m_pos.height > content_height) + { + switch(src_el()->css().get_vertical_align()) + { + case va_middle: + add = (m_pos.height - content_height) / 2; + break; + case va_bottom: + add = m_pos.height - content_height; + break; + default: + add = 0; + break; + } + } + + if(add) + { + for(auto & box : m_line_boxes) + { + box->y_shift(add); + } + } + } +} + +int litehtml::render_item_inline_context::get_first_baseline() +{ + int bl; + if(!m_line_boxes.empty()) + { + const auto &line = m_line_boxes.front(); + bl = line->bottom() - line->baseline() + content_offset_top(); + } else + { + bl = height() - margin_bottom(); + } + return bl; +} + +int litehtml::render_item_inline_context::get_last_baseline() +{ + int bl; + if(!m_line_boxes.empty()) + { + const auto &line = m_line_boxes.back(); + bl = line->bottom() - line->baseline() + content_offset_top(); + } else + { + bl = height() - margin_bottom(); + } + return bl; +} diff --git a/libs/litehtml/src/render_item.cpp b/libs/litehtml/src/render_item.cpp new file mode 100644 index 0000000000..fa39510e5a --- /dev/null +++ b/libs/litehtml/src/render_item.cpp @@ -0,0 +1,1096 @@ +#include "html.h" +#include "render_item.h" +#include "document.h" +#include <typeinfo> +#include <utf8_strings.h> + +litehtml::render_item::render_item(std::shared_ptr<element> _src_el) : + m_element(std::move(_src_el)), + m_skip(false) +{ + document::ptr doc = src_el()->get_document(); + auto fnt_size = src_el()->css().get_font_size(); + + m_margins.left = doc->to_pixels(src_el()->css().get_margins().left, fnt_size); + m_margins.right = doc->to_pixels(src_el()->css().get_margins().right, fnt_size); + m_margins.top = doc->to_pixels(src_el()->css().get_margins().top, fnt_size); + m_margins.bottom = doc->to_pixels(src_el()->css().get_margins().bottom, fnt_size); + + m_padding.left = doc->to_pixels(src_el()->css().get_padding().left, fnt_size); + m_padding.right = doc->to_pixels(src_el()->css().get_padding().right, fnt_size); + m_padding.top = doc->to_pixels(src_el()->css().get_padding().top, fnt_size); + m_padding.bottom = doc->to_pixels(src_el()->css().get_padding().bottom, fnt_size); + + m_borders.left = doc->to_pixels(src_el()->css().get_borders().left.width, fnt_size); + m_borders.right = doc->to_pixels(src_el()->css().get_borders().right.width, fnt_size); + m_borders.top = doc->to_pixels(src_el()->css().get_borders().top.width, fnt_size); + m_borders.bottom = doc->to_pixels(src_el()->css().get_borders().bottom.width, fnt_size); +} + +int litehtml::render_item::render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass) +{ + int ret; + + calc_outlines(containing_block_size.width); + + m_pos.clear(); + m_pos.move_to(x, y); + + int content_left = content_offset_left(); + int content_top = content_offset_top(); + + m_pos.x += content_left; + m_pos.y += content_top; + + + if(src_el()->is_block_formatting_context() || ! fmt_ctx) + { + formatting_context fmt; + fmt.push_position(content_left, content_top); + ret = _render(x, y, containing_block_size, &fmt, second_pass); + fmt.apply_relative_shift(containing_block_size); + } else + { + fmt_ctx->push_position(x + content_left, y + content_top); + ret = _render(x, y, containing_block_size, fmt_ctx, second_pass); + fmt_ctx->pop_position(x + content_left, y + content_top); + } + return ret; +} + +void litehtml::render_item::calc_outlines( int parent_width ) +{ + m_padding.left = m_element->css().get_padding().left.calc_percent(parent_width); + m_padding.right = m_element->css().get_padding().right.calc_percent(parent_width); + + m_borders.left = m_element->css().get_borders().left.width.calc_percent(parent_width); + m_borders.right = m_element->css().get_borders().right.width.calc_percent(parent_width); + + m_margins.left = m_element->css().get_margins().left.calc_percent(parent_width); + m_margins.right = m_element->css().get_margins().right.calc_percent(parent_width); + + m_margins.top = m_element->css().get_margins().top.calc_percent(parent_width); + m_margins.bottom = m_element->css().get_margins().bottom.calc_percent(parent_width); + + m_padding.top = m_element->css().get_padding().top.calc_percent(parent_width); + m_padding.bottom = m_element->css().get_padding().bottom.calc_percent(parent_width); +} + +int litehtml::render_item::calc_auto_margins(int parent_width) +{ + if ((src_el()->css().get_display() == display_block || src_el()->css().get_display() == display_table) && + src_el()->css().get_position() != element_position_absolute && + src_el()->css().get_float() == float_none) + { + if (src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined()) + { + int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right; + if (el_width <= parent_width) + { + m_margins.left = (parent_width - el_width) / 2; + m_margins.right = (parent_width - el_width) - m_margins.left; + } + else + { + m_margins.left = 0; + m_margins.right = 0; + } + return m_margins.left; + } + else if (src_el()->css().get_margins().left.is_predefined() && !src_el()->css().get_margins().right.is_predefined()) + { + int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right; + m_margins.left = parent_width - el_width; + if (m_margins.left < 0) m_margins.left = 0; + return m_margins.left; + } + else if (!src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined()) + { + int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left; + m_margins.right = parent_width - el_width; + if (m_margins.right < 0) m_margins.right = 0; + } + } + return 0; +} + +void litehtml::render_item::apply_relative_shift(const containing_block_context &containing_block_size) +{ + if (src_el()->css().get_position() == element_position_relative) + { + css_offsets offsets = src_el()->css().get_offsets(); + if (!offsets.left.is_predefined()) + { + m_pos.x += offsets.left.calc_percent(containing_block_size.width); + } + else if (!offsets.right.is_predefined()) + { + m_pos.x -= offsets.right.calc_percent(containing_block_size.width); + } + if (!offsets.top.is_predefined()) + { + m_pos.y += offsets.top.calc_percent(containing_block_size.height); + } + else if (!offsets.bottom.is_predefined()) + { + m_pos.y -= offsets.bottom.calc_percent(containing_block_size.height); + } + } +} + +std::tuple< + std::shared_ptr<litehtml::render_item>, + std::shared_ptr<litehtml::render_item>, + std::shared_ptr<litehtml::render_item> + > litehtml::render_item::split_inlines() +{ + std::tuple< + std::shared_ptr<litehtml::render_item>, + std::shared_ptr<litehtml::render_item>, + std::shared_ptr<litehtml::render_item> + > ret; + for(const auto& child: m_children) + { + if(child->src_el()->is_block_box() && child->src_el()->css().get_float() == float_none) + { + std::get<0>(ret) = clone(); + std::get<1>(ret) = child; + std::get<2>(ret) = clone(); + + std::get<1>(ret)->parent(std::get<0>(ret)); + std::get<2>(ret)->parent(std::get<0>(ret)); + + bool found = false; + for(const auto& ch: m_children) + { + if(ch == child) + { + found = true; + continue; + } + if(!found) + { + std::get<0>(ret)->add_child(ch); + } else + { + std::get<2>(ret)->add_child(ch); + } + } + break; + } + if(!child->children().empty()) + { + auto child_split = child->split_inlines(); + if(std::get<0>(child_split)) + { + std::get<0>(ret) = clone(); + std::get<1>(ret) = std::get<1>(child_split); + std::get<2>(ret) = clone(); + + std::get<2>(ret)->parent(std::get<0>(ret)); + + bool found = false; + for(const auto& ch: m_children) + { + if(ch == child) + { + found = true; + continue; + } + if(!found) + { + std::get<0>(ret)->add_child(ch); + } else + { + std::get<2>(ret)->add_child(ch); + } + } + std::get<0>(ret)->add_child(std::get<0>(child_split)); + std::get<2>(ret)->add_child(std::get<2>(child_split)); + break; + } + } + } + return ret; +} + +bool litehtml::render_item::fetch_positioned() +{ + bool ret = false; + + m_positioned.clear(); + + litehtml::element_position el_pos; + + for(auto& el : m_children) + { + el_pos = el->src_el()->css().get_position(); + if (el_pos != element_position_static) + { + add_positioned(el); + } + if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed)) + { + ret = true; + } + if(el->fetch_positioned()) + { + ret = true; + } + } + return ret; +} + +void litehtml::render_item::render_positioned(render_type rt) +{ + position wnd_position; + src_el()->get_document()->container()->get_client_rect(wnd_position); + + element_position el_position; + bool process; + for (auto& el : m_positioned) + { + el_position = el->src_el()->css().get_position(); + + process = false; + if(el->src_el()->css().get_display() != display_none) + { + if(el_position == element_position_absolute) + { + if(rt != render_fixed_only) + { + process = true; + } + } else if(el_position == element_position_fixed) + { + if(rt != render_no_fixed) + { + process = true; + } + } + } + + if(process) + { + containing_block_context containing_block_size; + if(el_position == element_position_fixed) + { + containing_block_size.height = wnd_position.height; + containing_block_size.width = wnd_position.width; + } else + { + containing_block_size.height = m_pos.height; + containing_block_size.width = m_pos.width; + } + + css_length css_left = el->src_el()->css().get_offsets().left; + css_length css_right = el->src_el()->css().get_offsets().right; + css_length css_top = el->src_el()->css().get_offsets().top; + css_length css_bottom = el->src_el()->css().get_offsets().bottom; + + bool need_render = false; + + css_length el_w = el->src_el()->css().get_width(); + css_length el_h = el->src_el()->css().get_height(); + + int new_width = -1; + int new_height = -1; + if(el_w.units() == css_units_percentage && containing_block_size.width) + { + new_width = el_w.calc_percent(containing_block_size.width); + if(el->m_pos.width != new_width) + { + need_render = true; + el->m_pos.width = new_width; + } + } + + if(el_h.units() == css_units_percentage && containing_block_size.height) + { + new_height = el_h.calc_percent(containing_block_size.height); + if(el->m_pos.height != new_height) + { + need_render = true; + el->m_pos.height = new_height; + } + } + + bool cvt_x = false; + bool cvt_y = false; + + if(el_position == element_position_fixed) + { + if(!css_left.is_predefined() || !css_right.is_predefined()) + { + if(!css_left.is_predefined() && css_right.is_predefined()) + { + el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left(); + } else if(css_left.is_predefined() && !css_right.is_predefined()) + { + el->m_pos.x = containing_block_size.width - css_right.calc_percent(containing_block_size.width) - el->m_pos.width - + el->content_offset_right(); + } else + { + el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left(); + el->m_pos.width = containing_block_size.width - + css_left.calc_percent(containing_block_size.width) - + css_right.calc_percent(containing_block_size.width) - + (el->content_offset_left() + el->content_offset_right()); + need_render = true; + } + } + + if(!css_top.is_predefined() || !css_bottom.is_predefined()) + { + if(!css_top.is_predefined() && css_bottom.is_predefined()) + { + el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top(); + } else if(css_top.is_predefined() && !css_bottom.is_predefined()) + { + el->m_pos.y = containing_block_size.height - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height - + el->content_offset_bottom(); + } else + { + el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top(); + el->m_pos.height = containing_block_size.height - + css_top.calc_percent(containing_block_size.height) - + css_bottom.calc_percent(containing_block_size.height) - + (el->content_offset_top() + el->content_offset_bottom()); + need_render = true; + } + } + } else + { + if(!css_left.is_predefined() || !css_right.is_predefined()) + { + if(!css_left.is_predefined() && css_right.is_predefined()) + { + el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left; + } else if(css_left.is_predefined() && !css_right.is_predefined()) + { + el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(containing_block_size.height) - el->m_pos.width - + el->content_offset_right(); + } else + { + el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left; + el->m_pos.width = m_pos.width + m_padding.left + m_padding.right - + css_left.calc_percent(containing_block_size.height) - + css_right.calc_percent(containing_block_size.height) - + (el->content_offset_left() + el->content_offset_right()); + if (new_width != -1) + { + el->m_pos.x += (el->m_pos.width - new_width) / 2; + el->m_pos.width = new_width; + } + need_render = true; + } + cvt_x = true; + } + + if(!css_top.is_predefined() || !css_bottom.is_predefined()) + { + if(!css_top.is_predefined() && css_bottom.is_predefined()) + { + el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top; + } else if(css_top.is_predefined() && !css_bottom.is_predefined()) + { + el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height - + el->content_offset_bottom(); + } else + { + el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top; + el->m_pos.height = m_pos.height + m_padding.top + m_padding.bottom - + css_top.calc_percent(containing_block_size.height) - + css_bottom.calc_percent(containing_block_size.height) - + (el->content_offset_top() + el->content_offset_bottom()); + if (new_height != -1) + { + el->m_pos.y += (el->m_pos.height - new_height) / 2; + el->m_pos.height = new_height; + } + need_render = true; + } + cvt_y = true; + } + } + + if(cvt_x || cvt_y) + { + int offset_x = 0; + int offset_y = 0; + auto cur_el = el->parent(); + auto this_el = shared_from_this(); + while(cur_el && cur_el != this_el) + { + offset_x += cur_el->m_pos.x; + offset_y += cur_el->m_pos.y; + cur_el = cur_el->parent(); + } + if(cvt_x) el->m_pos.x -= offset_x; + if(cvt_y) el->m_pos.y -= offset_y; + } + + if(need_render) + { + position pos = el->m_pos; + el->render(el->left(), el->top(), containing_block_size.new_width(el->width()), nullptr, true); + el->m_pos = pos; + } + + if(el_position == element_position_fixed) + { + position fixed_pos; + el->get_redraw_box(fixed_pos); + src_el()->get_document()->add_fixed_box(fixed_pos); + } + } + + el->render_positioned(); + } + + if(!m_positioned.empty()) + { + std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const std::shared_ptr<render_item>& Left, const std::shared_ptr<render_item>& Right) + { + return (Left->src_el()->css().get_z_index() < Right->src_el()->css().get_z_index()); + }); + } +} + +void litehtml::render_item::add_positioned(const std::shared_ptr<litehtml::render_item> &el) +{ + if (src_el()->css().get_position() != element_position_static || is_root()) + { + m_positioned.push_back(el); + } else + { + auto el_parent = parent(); + if (el_parent) + { + el_parent->add_positioned(el); + } + } +} + +void litehtml::render_item::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/) +{ + if(is_visible()) + { + int p_left = std::min(pos.left(), x + m_pos.left() - m_padding.left - m_borders.left); + int p_right = std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left); + int p_top = std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top); + int p_bottom = std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom); + + pos.x = p_left; + pos.y = p_top; + pos.width = p_right - p_left; + pos.height = p_bottom - p_top; + + if(src_el()->css().get_overflow() == overflow_visible) + { + for(auto& el : m_children) + { + if(el->src_el()->css().get_position() != element_position_fixed) + { + el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y); + } + } + } + } +} + +void litehtml::render_item::calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x /*= 0*/, int y /*= 0*/ ) +{ + if(is_visible() && src_el()->css().get_position() != element_position_fixed) + { + sz.width = std::max(sz.width, x + right()); + sz.height = std::max(sz.height, y + bottom()); + + if(!src_el()->is_root() && !src_el()->is_body()) + { + content_size.width = std::max(content_size.width, x + right()); + content_size.height = std::max(content_size.height, y + bottom()); + } + + // All children of tables and blocks with style other than "overflow: visible" are inside element. + // We can skip calculating size of children + if(src_el()->css().get_overflow() == overflow_visible && src_el()->css().get_display() != display_table) + { + for(auto& el : m_children) + { + el->calc_document_size(sz, content_size, x + m_pos.x, y + m_pos.y); + } + } + + if(src_el()->is_root() || src_el()->is_body()) + { + content_size.width += content_offset_right(); + content_size.height += content_offset_bottom(); + } + } +} + +void litehtml::render_item::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) +{ + if(!is_visible()) return; + + std::map<int, bool> z_indexes; + if(with_positioned) + { + for(const auto& idx : m_positioned) + { + z_indexes[idx->src_el()->css().get_z_index()]; + } + + for(const auto& idx : z_indexes) + { + if(idx.first < 0) + { + draw_children(hdc, x, y, clip, draw_positioned, idx.first); + } + } + } + draw_children(hdc, x, y, clip, draw_block, 0); + draw_children(hdc, x, y, clip, draw_floats, 0); + draw_children(hdc, x, y, clip, draw_inlines, 0); + if(with_positioned) + { + for(auto& z_index : z_indexes) + { + if(z_index.first == 0) + { + draw_children(hdc, x, y, clip, draw_positioned, z_index.first); + } + } + + for(auto& z_index : z_indexes) + { + if(z_index.first > 0) + { + draw_children(hdc, x, y, clip, draw_positioned, z_index.first); + } + } + } +} + +void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) +{ + position pos = m_pos; + pos.x += x; + pos.y += y; + + document::ptr doc = src_el()->get_document(); + + if (src_el()->css().get_overflow() > overflow_visible) + { + // TODO: Process overflow for inline elements + if(src_el()->css().get_display() != display_inline) + { + position border_box = pos; + border_box += m_padding; + border_box += m_borders; + + border_radiuses bdr_radius = src_el()->css().get_borders().radius.calc_percents(border_box.width, + border_box.height); + + bdr_radius -= m_borders; + bdr_radius -= m_padding; + + doc->container()->set_clip(pos, bdr_radius); + } + } + + for (const auto& el : m_children) + { + if (el->is_visible()) + { + bool process = true; + switch (flag) + { + case draw_positioned: + if (el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex) + { + if (el->src_el()->css().get_position() == element_position_fixed) + { + position browser_wnd; + doc->container()->get_client_rect(browser_wnd); + + el->src_el()->draw(hdc, browser_wnd.x, browser_wnd.y, clip, el); + el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true); + } + else + { + el->src_el()->draw(hdc, pos.x, pos.y, clip, el); + el->draw_stacking_context(hdc, pos.x, pos.y, clip, true); + } + process = false; + } + break; + case draw_block: + if (!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + { + el->src_el()->draw(hdc, pos.x, pos.y, clip, el); + } + break; + case draw_floats: + if (el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned()) + { + el->src_el()->draw(hdc, pos.x, pos.y, clip, el); + el->draw_stacking_context(hdc, pos.x, pos.y, clip, false); + process = false; + } + break; + case draw_inlines: + if (el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + { + el->src_el()->draw(hdc, pos.x, pos.y, clip, el); + if (el->src_el()->css().get_display() == display_inline_block || el->src_el()->css().get_display() == display_inline_flex) + { + el->draw_stacking_context(hdc, pos.x, pos.y, clip, false); + process = false; + } + } + break; + default: + break; + } + + if (process) + { + if (flag == draw_positioned) + { + if (!el->src_el()->is_positioned()) + { + el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex); + } + } + else + { + if (el->src_el()->css().get_float() == float_none && + el->src_el()->css().get_display() != display_inline_block && + !el->src_el()->is_positioned()) + { + el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex); + } + } + } + } + } + + if (src_el()->css().get_overflow() > overflow_visible) + { + doc->container()->del_clip(); + } +} + +std::shared_ptr<litehtml::element> litehtml::render_item::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex) +{ + element::ptr ret = nullptr; + + if(src_el()->css().get_overflow() > overflow_visible) + { + if(!m_pos.is_point_inside(x, y)) + { + return ret; + } + } + + position el_pos = m_pos; + el_pos.x = x - el_pos.x; + el_pos.y = y - el_pos.y; + + for(auto i = m_children.rbegin(); i != m_children.rend() && !ret; std::advance(i, 1)) + { + auto el = (*i); + + if(el->is_visible() && el->src_el()->css().get_display() != display_inline_text) + { + switch(flag) + { + case draw_positioned: + if(el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex) + { + if(el->src_el()->css().get_position() == element_position_fixed) + { + ret = el->get_element_by_point(client_x, client_y, client_x, client_y); + if(!ret && (*i)->is_point_inside(client_x, client_y)) + { + ret = (*i)->src_el(); + } + } else + { + ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y); + if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y)) + { + ret = (*i)->src_el(); + } + } + el = nullptr; + } + break; + case draw_block: + if(!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + { + if(el->is_point_inside(el_pos.x, el_pos.y)) + { + ret = el->src_el(); + } + } + break; + case draw_floats: + if(el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned()) + { + ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y); + + if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y)) + { + ret = (*i)->src_el(); + } + el = nullptr; + } + break; + case draw_inlines: + if(el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned()) + { + if(el->src_el()->css().get_display() == display_inline_block || + el->src_el()->css().get_display() == display_inline_table || + el->src_el()->css().get_display() == display_inline_flex) + { + ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y); + el = nullptr; + } + if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y)) + { + ret = (*i)->src_el(); + } + } + break; + default: + break; + } + + if(el && !el->src_el()->is_positioned()) + { + if(flag == draw_positioned) + { + element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex); + if(child) + { + ret = child; + } + } else + { + if( el->src_el()->css().get_float() == float_none && + el->src_el()->css().get_display() != display_inline_block && el->src_el()->css().get_display() != display_inline_flex) + { + element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex); + if(child) + { + ret = child; + } + } + } + } + } + } + + return ret; +} + +std::shared_ptr<litehtml::element> litehtml::render_item::get_element_by_point(int x, int y, int client_x, int client_y) +{ + if(!is_visible()) return nullptr; + + element::ptr ret; + + std::map<int, bool> z_indexes; + + for(const auto& i : m_positioned) + { + z_indexes[i->src_el()->css().get_z_index()]; + } + + for(auto iter = z_indexes.rbegin(); iter != z_indexes.rend(); iter++) + { + if(iter->first > 0) + { + ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, iter->first); + if(ret) return ret; + } + } + + for(const auto& z_index : z_indexes) + { + if(z_index.first == 0) + { + ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first); + if(ret) return ret; + } + } + + ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0); + if(ret) return ret; + + ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0); + if(ret) return ret; + + ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0); + if(ret) return ret; + + + for(auto iter = z_indexes.rbegin(); iter != z_indexes.rend(); iter++) + { + if(iter->first < 0) + { + ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, iter->first); + if(ret) return ret; + } + } + + if(src_el()->css().get_position() == element_position_fixed) + { + if(is_point_inside(client_x, client_y)) + { + ret = src_el(); + } + } else + { + if(is_point_inside(x, y)) + { + ret = src_el(); + } + } + + return ret; +} + +bool litehtml::render_item::is_point_inside( int x, int y ) +{ + if(src_el()->css().get_display() != display_inline && src_el()->css().get_display() != display_table_row) + { + position pos = m_pos; + pos += m_padding; + pos += m_borders; + if(pos.is_point_inside(x, y)) + { + return true; + } else + { + return false; + } + } else + { + position::vector boxes; + get_inline_boxes(boxes); + for(auto & box : boxes) + { + if(box.is_point_inside(x, y)) + { + return true; + } + } + } + return false; +} + +void litehtml::render_item::get_rendering_boxes( position::vector& redraw_boxes) +{ + if(src_el()->css().get_display() == display_inline || src_el()->css().get_display() == display_table_row) + { + get_inline_boxes(redraw_boxes); + } else + { + position pos = m_pos; + pos += m_padding; + pos += m_borders; + redraw_boxes.push_back(pos); + } + + if(src_el()->css().get_position() != element_position_fixed) + { + auto cur_el = parent(); + while(cur_el) + { + for(auto& box : redraw_boxes) + { + box.x += cur_el->m_pos.x; + box.y += cur_el->m_pos.y; + } + cur_el = cur_el->parent(); + } + } +} + +void litehtml::render_item::dump(litehtml::dumper& cout) +{ + cout.begin_node(src_el()->dump_get_name() + "{" + string(typeid(*this).name()) + "}"); + + auto attrs = src_el()->dump_get_attrs(); + if(!attrs.empty()) + { + cout.begin_attrs_group("attributes"); + for (const auto &attr: attrs) + { + cout.add_attr(std::get<0>(attr), std::get<1>(attr)); + } + cout.end_attrs_group(); + } + + if(!m_children.empty()) + { + cout.begin_attrs_group("children"); + for (const auto &el: m_children) + { + el->dump(cout); + } + cout.end_attrs_group(); + } + + cout.end_node(); +} + +litehtml::position litehtml::render_item::get_placement() const +{ + litehtml::position pos = m_pos; + auto cur_el = parent(); + while(cur_el) + { + pos.x += cur_el->m_pos.x; + pos.y += cur_el->m_pos.y; + cur_el = cur_el->parent(); + } + return pos; +} + +std::shared_ptr<litehtml::render_item> litehtml::render_item::init() +{ + src_el()->add_render(shared_from_this()); + + for(auto& el : children()) + { + el = el->init(); + } + + return shared_from_this(); +} + +void litehtml::render_item::calc_cb_length(const css_length& len, int percent_base, containing_block_context::typed_int& out_value) const +{ + if (!len.is_predefined()) + { + if(len.units() == litehtml::css_units_percentage) + { + out_value.value = len.calc_percent(percent_base); + out_value.type = litehtml::containing_block_context::cbc_value_type_percentage; + } else + { + out_value.value = src_el()->get_document()->to_pixels(len, src_el()->css().get_font_size()); + out_value.type = containing_block_context::cbc_value_type_absolute; + } + } +} + +litehtml::containing_block_context litehtml::render_item::calculate_containing_block_context(const containing_block_context& cb_context) +{ + containing_block_context ret; + ret.context_idx = cb_context.context_idx + 1; + ret.width.value = ret.max_width.value = cb_context.width.value - content_offset_width(); + if(src_el()->css().get_position() != element_position_absolute && src_el()->css().get_position() != element_position_fixed) + { + ret.height.value = cb_context.height.value - content_offset_height(); + } + + // Calculate width if css property is not auto + // We have to use aut value for display_table_cell also. + if (src_el()->css().get_display() != display_table_cell) + { + auto par = parent(); + if(cb_context.size_mode & containing_block_context::size_mode_exact_width) + { + ret.width.value = cb_context.width; + ret.width.type = containing_block_context::cbc_value_type_absolute; + } else + { + auto *width = &css().get_width(); + if(par && (par->css().get_display() == display_flex || par->css().get_display() == display_inline_flex)) + { + if(!css().get_flex_basis().is_predefined() && css().get_flex_basis().val() >= 0) + { + if(par->css().get_flex_direction() == flex_direction_row || par->css().get_flex_direction() == flex_direction_row_reverse) + { + ret.width.type = containing_block_context::cbc_value_type_auto; + ret.width.value = 0; + width = nullptr; + } + } + } + if(width) + { + calc_cb_length(*width, cb_context.width, ret.width); + } + } + if(cb_context.size_mode & containing_block_context::size_mode_exact_height) + { + ret.height.value = cb_context.height; + ret.height.type = containing_block_context::cbc_value_type_absolute; + } else + { + auto *height = &css().get_height(); + if(par && (par->css().get_display() == display_flex || par->css().get_display() == display_inline_flex)) + { + if(!css().get_flex_basis().is_predefined() && css().get_flex_basis().val() >= 0) + { + if(par->css().get_flex_direction() == flex_direction_column || par->css().get_flex_direction() == flex_direction_column_reverse) + { + ret.height.type = containing_block_context::cbc_value_type_auto; + ret.height.value = 0; + height = nullptr; + } + } + } + if(height) + { + calc_cb_length(*height, cb_context.height, ret.height); + } + } + if (ret.width.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root())) + { + ret.width.value -= content_offset_width(); + } + if (ret.height.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root())) + { + ret.height.value -= content_offset_height(); + } + } + ret.render_width = ret.width; + + calc_cb_length(src_el()->css().get_min_width(), cb_context.width, ret.min_width); + calc_cb_length(src_el()->css().get_max_width(), cb_context.width, ret.max_width); + + calc_cb_length(src_el()->css().get_min_height(), cb_context.height, ret.min_height); + calc_cb_length(src_el()->css().get_max_height(), cb_context.height, ret.max_height); + + // Fix box sizing + if(ret.width.type != containing_block_context::cbc_value_type_auto) + { + ret.render_width = ret.width - box_sizing_width(); + } + if(ret.min_width.type != containing_block_context::cbc_value_type_none) + { + ret.min_width.value -= box_sizing_width(); + } + if(ret.max_width.type != containing_block_context::cbc_value_type_none) + { + ret.max_width.value -= box_sizing_width(); + } + if(ret.min_height.type != containing_block_context::cbc_value_type_none) + { + ret.min_height.value -= box_sizing_height(); + } + if(ret.max_height.type != containing_block_context::cbc_value_type_none) + { + ret.max_height.value -= box_sizing_height(); + } + + return ret; +} diff --git a/libs/litehtml/src/render_table.cpp b/libs/litehtml/src/render_table.cpp new file mode 100644 index 0000000000..543749ed12 --- /dev/null +++ b/libs/litehtml/src/render_table.cpp @@ -0,0 +1,496 @@ +#include "html.h" +#include "render_table.h" +#include "document.h" +#include "iterators.h" + + +litehtml::render_item_table::render_item_table(std::shared_ptr<element> _src_el) : + render_item(std::move(_src_el)), + m_border_spacing_x(0), + m_border_spacing_y(0) +{ +} + +int litehtml::render_item_table::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool /*second_pass*/) +{ + if (!m_grid) return 0; + + containing_block_context self_size = calculate_containing_block_context(containing_block_size); + + // Calculate table spacing + int table_width_spacing = 0; + if (src_el()->css().get_border_collapse() == border_collapse_separate) + { + table_width_spacing = m_border_spacing_x * (m_grid->cols_count() + 1); + } + else + { + table_width_spacing = 0; + + if (m_grid->cols_count()) + { + table_width_spacing -= std::min(border_left(), m_grid->column(0).border_left); + table_width_spacing -= std::min(border_right(), m_grid->column(m_grid->cols_count() - 1).border_right); + } + + for (int col = 1; col < m_grid->cols_count(); col++) + { + table_width_spacing -= std::min(m_grid->column(col).border_left, m_grid->column(col - 1).border_right); + } + } + + + // Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. + // If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum + // cell width. + // + // Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur. + + if (m_grid->cols_count() == 1 && self_size.width.type != containing_block_context::cbc_value_type_auto) + { + for (int row = 0; row < m_grid->rows_count(); row++) + { + table_cell* cell = m_grid->cell(0, row); + if (cell && cell->el) + { + cell->min_width = cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing), fmt_ctx); + cell->el->pos().width = cell->min_width - cell->el->content_offset_left() - + cell->el->content_offset_right(); + } + } + } + else + { + for (int row = 0; row < m_grid->rows_count(); row++) + { + for (int col = 0; col < m_grid->cols_count(); col++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell && cell->el) + { + if (!m_grid->column(col).css_width.is_predefined() && m_grid->column(col).css_width.units() != css_units_percentage) + { + int css_w = m_grid->column(col).css_width.calc_percent(self_size.width); + int el_w = cell->el->render(0, 0, self_size.new_width(css_w),fmt_ctx); + cell->min_width = cell->max_width = std::max(css_w, el_w); + cell->el->pos().width = cell->min_width - cell->el->content_offset_left() - + cell->el->content_offset_right(); + } + else + { + // calculate minimum content width + cell->min_width = cell->el->render(0, 0, self_size.new_width(cell->el->content_offset_width()), fmt_ctx); + // calculate maximum content width + cell->max_width = cell->el->render(0, 0, self_size.new_width(self_size.render_width - table_width_spacing), fmt_ctx); + } + } + } + } + } + + // For each column, determine a maximum and minimum column width from the cells that span only that column. + // The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). + // The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger). + + for (int col = 0; col < m_grid->cols_count(); col++) + { + m_grid->column(col).max_width = 0; + m_grid->column(col).min_width = 0; + for (int row = 0; row < m_grid->rows_count(); row++) + { + if (m_grid->cell(col, row)->colspan <= 1) + { + m_grid->column(col).max_width = std::max(m_grid->column(col).max_width, m_grid->cell(col, row)->max_width); + m_grid->column(col).min_width = std::max(m_grid->column(col).min_width, m_grid->cell(col, row)->min_width); + } + } + } + + // For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, + // they are at least as wide as the cell. Do the same for the maximum widths. + // If possible, widen all spanned columns by approximately the same amount. + + for (int col = 0; col < m_grid->cols_count(); col++) + { + for (int row = 0; row < m_grid->rows_count(); row++) + { + if (m_grid->cell(col, row)->colspan > 1) + { + int max_total_width = m_grid->column(col).max_width; + int min_total_width = m_grid->column(col).min_width; + for (int col2 = col + 1; col2 < col + m_grid->cell(col, row)->colspan; col2++) + { + max_total_width += m_grid->column(col2).max_width; + min_total_width += m_grid->column(col2).min_width; + } + if (min_total_width < m_grid->cell(col, row)->min_width) + { + m_grid->distribute_min_width(m_grid->cell(col, row)->min_width - min_total_width, col, col + m_grid->cell(col, row)->colspan - 1); + } + if (max_total_width < m_grid->cell(col, row)->max_width) + { + m_grid->distribute_max_width(m_grid->cell(col, row)->max_width - max_total_width, col, col + m_grid->cell(col, row)->colspan - 1); + } + } + } + } + + // If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the + // greater of W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN). + // If the used width is greater than MIN, the extra width should be distributed over the columns. + // + // If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width, + // CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is + // less than that of the containing block, use max(MAX, CAPMIN). + + + int table_width = 0; + int min_table_width = 0; + int max_table_width = 0; + + if (self_size.width.type == containing_block_context::cbc_value_type_absolute) + { + table_width = m_grid->calc_table_width(self_size.render_width - table_width_spacing, false, min_table_width, max_table_width); + } + else + { + table_width = m_grid->calc_table_width(self_size.render_width - table_width_spacing, self_size.width.type == containing_block_context::cbc_value_type_auto, min_table_width, max_table_width); + } + + min_table_width += table_width_spacing; + max_table_width += table_width_spacing; + table_width += table_width_spacing; + m_grid->calc_horizontal_positions(m_borders, src_el()->css().get_border_collapse(), m_border_spacing_x); + + bool row_span_found = false; + + // render cells with computed width + for (int row = 0; row < m_grid->rows_count(); row++) + { + m_grid->row(row).height = 0; + for (int col = 0; col < m_grid->cols_count(); col++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell->el) + { + int span_col = col + cell->colspan - 1; + if (span_col >= m_grid->cols_count()) + { + span_col = m_grid->cols_count() - 1; + } + int cell_width = m_grid->column(span_col).right - m_grid->column(col).left; + + //if (cell->el->pos().width != cell_width - cell->el->content_offset_left() - + // cell->el->content_offset_right()) + { + cell->el->render(m_grid->column(col).left, 0, self_size.new_width(cell_width), fmt_ctx, true); + cell->el->pos().width = cell_width - cell->el->content_offset_left() - + cell->el->content_offset_right(); + } + /*else + { + cell->el->pos().x = m_grid->column(col).left + cell->el->content_offset_left(); + }*/ + + if (cell->rowspan <= 1) + { + m_grid->row(row).height = std::max(m_grid->row(row).height, cell->el->height()); + } + else + { + row_span_found = true; + } + + } + } + } + + if (row_span_found) + { + for (int col = 0; col < m_grid->cols_count(); col++) + { + for (int row = 0; row < m_grid->rows_count(); row++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell->el) + { + int span_row = row + cell->rowspan - 1; + if (span_row >= m_grid->rows_count()) + { + span_row = m_grid->rows_count() - 1; + } + if (span_row != row) + { + int h = 0; + for (int i = row; i <= span_row; i++) + { + h += m_grid->row(i).height; + } + if (h < cell->el->height()) + { + m_grid->row(span_row).height += cell->el->height() - h; + } + } + } + } + } + } + + // Calculate vertical table spacing + int table_height_spacing = 0; + if (src_el()->css().get_border_collapse() == border_collapse_separate) + { + table_height_spacing = m_border_spacing_y * (m_grid->rows_count() + 1); + } + else + { + table_height_spacing = 0; + + if (m_grid->rows_count()) + { + table_height_spacing -= std::min(border_top(), m_grid->row(0).border_top); + table_height_spacing -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom); + } + + for (int row = 1; row < m_grid->rows_count(); row++) + { + table_height_spacing -= std::min(m_grid->row(row).border_top, m_grid->row(row - 1).border_bottom); + } + } + + + // calculate block height + int block_height = 0; + if(self_size.height.type != containing_block_context::cbc_value_type_auto && self_size.height > 0) + { + block_height = self_size.height - (m_padding.height() + m_borders.height()); + } + + // calculate minimum height from m_css.get_min_height() + int min_height = 0; + if (!src_el()->css().get_min_height().is_predefined() && src_el()->css().get_min_height().units() == css_units_percentage) + { + min_height = src_el()->css().get_min_height().calc_percent(containing_block_size.height); + } + else + { + min_height = (int)src_el()->css().get_min_height().val(); + } + + int minimum_table_height = std::max(block_height, min_height); + + m_grid->calc_rows_height(minimum_table_height - table_height_spacing, m_border_spacing_y); + m_grid->calc_vertical_positions(m_borders, src_el()->css().get_border_collapse(), m_border_spacing_y); + + int table_height = 0; + + // place cells vertically + for (int col = 0; col < m_grid->cols_count(); col++) + { + for (int row = 0; row < m_grid->rows_count(); row++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell->el) + { + int span_row = row + cell->rowspan - 1; + if (span_row >= m_grid->rows_count()) + { + span_row = m_grid->rows_count() - 1; + } + cell->el->pos().y = m_grid->row(row).top + cell->el->content_offset_top(); + cell->el->pos().height = m_grid->row(span_row).bottom - m_grid->row(row).top - + cell->el->content_offset_top() - + cell->el->content_offset_bottom(); + table_height = std::max(table_height, m_grid->row(span_row).bottom); + cell->el->apply_vertical_align(); + } + } + } + + if (src_el()->css().get_border_collapse() == border_collapse_collapse) + { + if (m_grid->rows_count()) + { + table_height -= std::min(border_bottom(), m_grid->row(m_grid->rows_count() - 1).border_bottom); + } + } + else + { + table_height += m_border_spacing_y; + } + + // Render table captions + // Table border doesn't round the caption, so we have to start caption in the border position + int top_captions = -border_top(); + + for (auto& caption : m_grid->captions()) + { + if(caption->css().get_caption_side() == caption_side_top) + { + caption->render(-border_left(), top_captions, self_size.new_width(table_width + border_left() + border_right()), fmt_ctx); + top_captions += caption->height(); + } + } + + if (top_captions) + { + // Add border height to get the top of cells + top_captions += border_top(); + + // Save caption height for draw_background + m_grid->top_captions_height(top_captions); + + // Move table cells to the bottom side + for (int row = 0; row < m_grid->rows_count(); row++) + { + m_grid->row(row).el_row->pos().y += top_captions; + for (int col = 0; col < m_grid->cols_count(); col++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell->el) + { + cell->el->pos().y += top_captions; + } + } + } + } + + int bottom_captions = 0; + + for (auto& caption : m_grid->captions()) + { + if(caption->css().get_caption_side() == caption_side_bottom) + { + caption->render(-border_left(), table_height + top_captions + bottom_captions, self_size.new_width(table_width + border_left() + border_right()), fmt_ctx); + bottom_captions += caption->height(); + } + } + + m_pos.move_to(x + content_offset_left(), y + content_offset_top()); + m_pos.width = table_width; + m_pos.height = table_height + top_captions + bottom_captions; + + if(self_size.width.type != containing_block_context::cbc_value_type_absolute) + { + return std::min(table_width, max_table_width) + content_offset_width(); + } + return table_width + content_offset_width(); +} + +std::shared_ptr<litehtml::render_item> litehtml::render_item_table::init() +{ + // Initialize Grid + m_grid = std::unique_ptr<table_grid>(new table_grid()); + + go_inside_table table_selector; + table_rows_selector row_selector; + table_cells_selector cell_selector; + + elements_iterator row_iter(false, &table_selector, &row_selector); + + row_iter.process(shared_from_this(), [&](std::shared_ptr<render_item>& el, iterator_item_type /*item_type*/) + { + m_grid->begin_row(el); + + + elements_iterator cell_iter(true, &table_selector, &cell_selector); + cell_iter.process(el, [&](std::shared_ptr<render_item>& el, iterator_item_type item_type) + { + if(item_type != iterator_item_type_end_parent) + { + el = el->init(); + m_grid->add_cell(el); + } + }); + }); + + for (auto& el : m_children) + { + if (el->src_el()->css().get_display() == display_table_caption) + { + el = el->init(); + m_grid->captions().push_back(el); + } + } + + m_grid->finish(); + + if(src_el()->css().get_border_collapse() == border_collapse_separate) + { + int font_size = src_el()->css().get_font_size(); + document::ptr doc = src_el()->get_document(); + m_border_spacing_x = doc->to_pixels(src_el()->css().get_border_spacing_x(), font_size); + m_border_spacing_y = doc->to_pixels(src_el()->css().get_border_spacing_y(), font_size); + } else + { + m_border_spacing_x = 0; + m_border_spacing_y = 0; + } + + src_el()->add_render(shared_from_this()); + + return shared_from_this(); +} + +void litehtml::render_item_table::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) +{ + if (!m_grid) return; + + position pos = m_pos; + pos.x += x; + pos.y += y; + for (auto& caption : m_grid->captions()) + { + if (flag == draw_block) + { + caption->src_el()->draw(hdc, pos.x, pos.y, clip, caption); + } + caption->draw_children(hdc, pos.x, pos.y, clip, flag, zindex); + } + for (int row = 0; row < m_grid->rows_count(); row++) + { + if (flag == draw_block) + { + m_grid->row(row).el_row->src_el()->draw_background(hdc, pos.x, pos.y, clip, m_grid->row(row).el_row); + } + for (int col = 0; col < m_grid->cols_count(); col++) + { + table_cell* cell = m_grid->cell(col, row); + if (cell->el) + { + if (flag == draw_block) + { + cell->el->src_el()->draw(hdc, pos.x, pos.y, clip, cell->el); + } + cell->el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex); + } + } + } +} + +int litehtml::render_item_table::get_draw_vertical_offset() +{ + if(m_grid) + { + return m_grid->top_captions_height(); + } + return 0; +} + +void litehtml::render_item_table_row::get_inline_boxes( position::vector& boxes ) const +{ + position pos; + for(auto& el : m_children) + { + if(el->src_el()->css().get_display() == display_table_cell) + { + pos.x = el->left() + el->margin_left(); + pos.y = el->top() - m_padding.top - m_borders.top; + + pos.width = el->right() - pos.x - el->margin_right() - el->margin_left(); + pos.height = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom; + + boxes.push_back(pos); + } + } +} diff --git a/libs/litehtml/src/string_id.cpp b/libs/litehtml/src/string_id.cpp new file mode 100644 index 0000000000..9f8390303e --- /dev/null +++ b/libs/litehtml/src/string_id.cpp @@ -0,0 +1,54 @@ +#include "html.h" +#include "string_id.h" +#include <assert.h> + +#ifndef LITEHTML_NO_THREADS + #include <mutex> + static std::mutex mutex; + #define lock_guard std::lock_guard<std::mutex> lock(mutex) +#else + #define lock_guard +#endif + +namespace litehtml +{ + +static std::map<string, string_id> map; +static std::vector<string> array; + +static int init() +{ + string_vector names; + split_string(initial_string_ids, names, ","); + for (auto& name : names) + { + trim(name); + assert(name[0] == '_' && name.back() == '_'); + name = name.substr(1, name.size() - 2); // _border_color_ -> border_color + std::replace(name.begin(), name.end(), '_', '-'); // border_color -> border-color + _id(name); // this will create association _border_color_ <-> "border-color" + } + return 0; +} +static int dummy = init(); + +const string_id empty_id = _id(""); +const string_id star_id = _id("*"); + +string_id _id(const string& str) +{ + lock_guard; + auto it = map.find(str); + if (it != map.end()) return it->second; + // else: str not found, add it to the array and the map + array.push_back(str); + return map[str] = (string_id)(array.size() - 1); +} + +const string& _s(string_id id) +{ + lock_guard; + return array[id]; +} + +} // namespace litehtml
\ No newline at end of file diff --git a/libs/litehtml/src/strtod.cpp b/libs/litehtml/src/strtod.cpp new file mode 100644 index 0000000000..22392c4943 --- /dev/null +++ b/libs/litehtml/src/strtod.cpp @@ -0,0 +1,275 @@ +/* + * strtod.c -- + * + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id$ + */ + +#include "html.h" +#include <cstdlib> +#include <cctype> +#include <cerrno> + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + +static int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* + *---------------------------------------------------------------------- + * + * strtod -- + * + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Results: + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double litehtml::t_strtod(const char* string, char** endPtr) +{ + int sign, expSign = FALSE; + double fraction, dblExp, *d; + const char *p; + int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) + { + p += 1; + } + if (*p == '-') + { + sign = TRUE; + p += 1; + } else + { + if (*p == '+') + { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!t_isdigit(c)) + { + if ((c != '.') || (decPt >= 0)) + { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) + { + decPt = mantSize; + } else + { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) + { + fracExp = decPt - 18; + mantSize = 18; + } else + { + fracExp = decPt - mantSize; + } + if (mantSize == 0) + { + fraction = 0.0; + p = string; + goto done; + } else + { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') + { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') + { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) + { + p += 1; + if (*p == '-') + { + expSign = TRUE; + p += 1; + } else + { + if (*p == '+') + { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) + { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) + { + exp = fracExp - exp; + } else + { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) + { + expSign = TRUE; + exp = -exp; + } else + { + expSign = FALSE; + } + if (exp > maxExponent) + { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) + { + if (exp & 01) + { + dblExp *= *d; + } + } + if (expSign) + { + fraction /= dblExp; + } else + { + fraction *= dblExp; + } + +done: + if (endPtr != nullptr) + { + *endPtr = (char *) p; + } + + if (sign) + { + return -fraction; + } + return fraction; +} diff --git a/libs/litehtml/src/style.cpp b/libs/litehtml/src/style.cpp new file mode 100644 index 0000000000..727f01aa10 --- /dev/null +++ b/libs/litehtml/src/style.cpp @@ -0,0 +1,1220 @@ +#include "html.h" +#include "style.h" + +namespace litehtml +{ + +std::map<string_id, string> style::m_valid_values = +{ + { _display_, style_display_strings }, + { _visibility_, visibility_strings }, + { _position_, element_position_strings }, + { _float_, element_float_strings }, + { _clear_, element_clear_strings }, + { _overflow_, overflow_strings }, + { _box_sizing_, box_sizing_strings }, + + { _text_align_, text_align_strings }, + { _vertical_align_, vertical_align_strings }, + { _text_transform_, text_transform_strings }, + { _white_space_, white_space_strings }, + + { _font_style_, font_style_strings }, + { _font_variant_, font_variant_strings }, + { _font_weight_, font_weight_strings }, + + { _list_style_type_, list_style_type_strings }, + { _list_style_position_, list_style_position_strings }, + + { _border_left_style_, border_style_strings }, + { _border_right_style_, border_style_strings }, + { _border_top_style_, border_style_strings }, + { _border_bottom_style_, border_style_strings }, + { _border_collapse_, border_collapse_strings }, + + // these 4 properties are comma-separated lists of keywords, see parse_keyword_comma_list + { _background_attachment_, background_attachment_strings }, + { _background_repeat_, background_repeat_strings }, + { _background_clip_, background_box_strings }, + { _background_origin_, background_box_strings }, + + { _flex_direction_, flex_direction_strings }, + { _flex_wrap_, flex_wrap_strings }, + { _justify_content_, flex_justify_content_strings }, + { _align_items_, flex_align_items_strings }, + { _align_content_, flex_align_content_strings }, + { _align_self_, flex_align_items_strings }, + + { _caption_side_, caption_side_strings }, +}; + +void style::parse(const string& txt, const string& baseurl, document_container* container) +{ + std::vector<string> properties; + split_string(txt, properties, ";", "", "\"'"); + + for(const auto & property : properties) + { + parse_property(property, baseurl, container); + } +} + +void style::parse_property(const string& txt, const string& baseurl, document_container* container) +{ + string::size_type pos = txt.find_first_of(':'); + if(pos != string::npos) + { + string name = txt.substr(0, pos); + string val = txt.substr(pos + 1); + + trim(name); lcase(name); + trim(val); + + if(!name.empty() && !val.empty()) + { + string_vector vals; + split_string(val, vals, "!"); + if(vals.size() == 1) + { + add_property(_id(name), val, baseurl, false, container); + } else if(vals.size() > 1) + { + trim(vals[0]); + lcase(vals[1]); + add_property(_id(name), vals[0], baseurl, vals[1] == "important", container); + } + } + } +} + +void style::add_property(string_id name, const string& val, const string& baseurl, bool important, document_container* container) +{ + if (val.find("var(") != string::npos) return add_parsed_property(name, property_value(val, important, prop_type_var)); + if (val == "inherit" && name != _font_) return add_parsed_property(name, property_value(important, prop_type_inherit)); + + int idx; + string url; + css_length len[4], length; + + switch (name) + { + // keyword-only properties + case _display_: + case _visibility_: + case _position_: + case _float_: + case _clear_: + case _box_sizing_: + case _overflow_: + + case _text_align_: + case _vertical_align_: + case _text_transform_: + case _white_space_: + + case _font_style_: + case _font_variant_: + case _font_weight_: + + case _list_style_type_: + case _list_style_position_: + + case _border_top_style_: + case _border_bottom_style_: + case _border_left_style_: + case _border_right_style_: + case _border_collapse_: + + case _flex_direction_: + case _flex_wrap_: + case _justify_content_: + case _align_content_: + + case _caption_side_: + + idx = value_index(val, m_valid_values[name]); + if (idx >= 0) + { + add_parsed_property(name, property_value(idx, important)); + } + break; + + case _align_items_: + case _align_self_: + parse_align_self(name, val, important); + break; + + // <length> + case _text_indent_: + case _padding_left_: + case _padding_right_: + case _padding_top_: + case _padding_bottom_: + length.fromString(val); + add_parsed_property(name, property_value(length, important)); + break; + + // <length> | auto + case _left_: + case _right_: + case _top_: + case _bottom_: + case _z_index_: // <integer> | auto + case _width_: + case _height_: + case _min_width_: + case _min_height_: + case _margin_left_: + case _margin_right_: + case _margin_top_: + case _margin_bottom_: + length.fromString(val, "auto", -1); + add_parsed_property(name, property_value(length, important)); + break; + + // <length> | none + case _max_width_: + case _max_height_: + length.fromString(val, "none", -1); + add_parsed_property(name, property_value(length, important)); + break; + + case _line_height_: + length.fromString(val, "normal", -1); + add_parsed_property(name, property_value(length, important)); + break; + + case _font_size_: + length.fromString(val, font_size_strings, -1); + add_parsed_property(name, property_value(length, important)); + break; + + // Parse background shorthand properties + case _background_: + parse_background(val, baseurl, important, container); + break; + + case _background_image_: + parse_background_image(val, baseurl, important); + break; + + case _background_attachment_: + case _background_repeat_: + case _background_clip_: + case _background_origin_: + parse_keyword_comma_list(name, val, important); + break; + + case _background_position_: + parse_background_position(val, important); + break; + + case _background_size_: + parse_background_size(val, important); + break; + + // Parse border spacing properties + case _border_spacing_: + parse_two_lengths(val, len); + add_parsed_property(__litehtml_border_spacing_x_, property_value(len[0], important)); + add_parsed_property(__litehtml_border_spacing_y_, property_value(len[1], important)); + break; + + // Parse borders shorthand properties + case _border_: + { + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, border_style_strings); + if (idx >= 0) + { + property_value style(idx, important); + add_parsed_property(_border_left_style_, style); + add_parsed_property(_border_right_style_, style); + add_parsed_property(_border_top_style_, style); + add_parsed_property(_border_bottom_style_, style); + } + else if (t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, border_width_strings)) + { + property_value width(parse_border_width(token), important); + add_parsed_property(_border_left_width_, width); + add_parsed_property(_border_right_width_, width); + add_parsed_property(_border_top_width_, width); + add_parsed_property(_border_bottom_width_, width); + } + else if (web_color::is_color(token, container)) + { + web_color _color = web_color::from_string(token, container); + property_value color(_color, important); + add_parsed_property(_border_left_color_, color); + add_parsed_property(_border_right_color_, color); + add_parsed_property(_border_top_color_, color); + add_parsed_property(_border_bottom_color_, color); + } + } + break; + } + + case _border_left_: + case _border_right_: + case _border_top_: + case _border_bottom_: + { + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, border_style_strings); + if (idx >= 0) + { + add_parsed_property(_id(_s(name) + "-style"), property_value(idx, important)); + } + else if (t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, border_width_strings)) + { + property_value width(parse_border_width(token), important); + add_parsed_property(_id(_s(name) + "-width"), width); + } + else if (web_color::is_color(token, container)) + { + web_color color = web_color::from_string(token, container); + add_parsed_property(_id(_s(name) + "-color"), property_value(color, important)); + } + } + break; + } + + // Parse border-width/style/color shorthand properties + case _border_width_: + case _border_style_: + case _border_color_: + { + string prop = name == _border_width_ ? "-width" : name == _border_style_ ? "-style" : "-color"; + + string_vector tokens; + split_string(val, tokens, " "); + if (tokens.size() == 4) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[3], baseurl, important, container); + } + else if (tokens.size() == 3) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[2], baseurl, important, container); + } + else if (tokens.size() == 2) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[1], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[1], baseurl, important, container); + } + else if (tokens.size() == 1) + { + add_property(_id("border-top" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-bottom" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-right" + prop), tokens[0], baseurl, important, container); + add_property(_id("border-left" + prop), tokens[0], baseurl, important, container); + } + break; + } + + case _border_top_width_: + case _border_bottom_width_: + case _border_left_width_: + case _border_right_width_: + length = parse_border_width(val); + add_parsed_property(name, property_value(length, important)); + break; + + case _color_: + case _background_color_: + case _border_top_color_: + case _border_bottom_color_: + case _border_left_color_: + case _border_right_color_: + if (web_color::is_color(val, container)) + { + web_color color = web_color::from_string(val, container); + add_parsed_property(name, property_value(color, important)); + } + break; + + // Parse border radius shorthand properties + case _border_bottom_left_radius_: + case _border_bottom_right_radius_: + case _border_top_right_radius_: + case _border_top_left_radius_: + parse_two_lengths(val, len); + add_parsed_property(_id(_s(name) + "-x"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-y"), property_value(len[1], important)); + break; + + // Parse border-radius shorthand properties + case _border_radius_: + { + string_vector tokens; + split_string(val, tokens, "/"); + if (tokens.size() == 1) + { + add_property(_border_radius_x_, tokens[0], baseurl, important, container); + add_property(_border_radius_y_, tokens[0], baseurl, important, container); + } + else if (tokens.size() >= 2) + { + add_property(_border_radius_x_, tokens[0], baseurl, important, container); + add_property(_border_radius_y_, tokens[1], baseurl, important, container); + } + break; + } + case _border_radius_x_: + case _border_radius_y_: + { + string_id top_left, top_right, bottom_right, bottom_left; + if (name == _border_radius_x_) + { + top_left = _border_top_left_radius_x_; + top_right = _border_top_right_radius_x_; + bottom_right = _border_bottom_right_radius_x_; + bottom_left = _border_bottom_left_radius_x_; + } + else + { + top_left = _border_top_left_radius_y_; + top_right = _border_top_right_radius_y_; + bottom_right = _border_bottom_right_radius_y_; + bottom_left = _border_bottom_left_radius_y_; + } + + switch (parse_four_lengths(val, len)) + { + case 1: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[0], important)); + add_parsed_property(bottom_right, property_value(len[0], important)); + add_parsed_property(bottom_left, property_value(len[0], important)); + break; + case 2: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[0], important)); + add_parsed_property(bottom_left, property_value(len[1], important)); + break; + case 3: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[2], important)); + add_parsed_property(bottom_left, property_value(len[1], important)); + break; + case 4: + add_parsed_property(top_left, property_value(len[0], important)); + add_parsed_property(top_right, property_value(len[1], important)); + add_parsed_property(bottom_right, property_value(len[2], important)); + add_parsed_property(bottom_left, property_value(len[3], important)); + break; + } + break; + } + + // Parse list-style shorthand properties + case _list_style_: + { + add_parsed_property(_list_style_type_, property_value(list_style_type_disc, important)); + add_parsed_property(_list_style_position_, property_value(list_style_position_outside, important)); + add_parsed_property(_list_style_image_, property_value("", important)); + add_parsed_property(_list_style_image_baseurl_, property_value("", important)); + + string_vector tokens; + split_string(val, tokens, " ", "", "("); + for (const auto& token : tokens) + { + int idx = value_index(token, list_style_type_strings); + if (idx >= 0) + { + add_parsed_property(_list_style_type_, property_value(idx, important)); + } + else + { + idx = value_index(token, list_style_position_strings); + if (idx >= 0) + { + add_parsed_property(_list_style_position_, property_value(idx, important)); + } + else if (!strncmp(token.c_str(), "url", 3)) + { + css::parse_css_url(token, url); + add_parsed_property(_list_style_image_, property_value(url, important)); + add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important)); + } + } + } + break; + } + + case _list_style_image_: + css::parse_css_url(val, url); + add_parsed_property(_list_style_image_, property_value(url, important)); + add_parsed_property(_list_style_image_baseurl_, property_value(baseurl, important)); + break; + + // Parse margin and padding shorthand properties + case _margin_: + case _padding_: + { + switch (parse_four_lengths(val, len)) + { + case 4: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[3], important)); + break; + case 3: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[2], important)); + break; + case 2: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[1], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[1], important)); + break; + case 1: + add_parsed_property(_id(_s(name) + "-top"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-bottom"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-right"), property_value(len[0], important)); + add_parsed_property(_id(_s(name) + "-left"), property_value(len[0], important)); + break; + } + break; + } + + // Parse font shorthand properties + case _font_: + parse_font(val, important); + break; + + // Parse flex-flow shorthand properties + case _flex_flow_: + { + string_vector tokens; + split_string(val, tokens, " "); + for (const auto& tok : tokens) + { + int idx; + if ((idx = value_index(tok, flex_direction_strings)) >= 0) + { + add_parsed_property(_flex_direction_, property_value(idx, important)); + } + else if ((idx = value_index(tok, flex_wrap_strings)) >= 0) + { + add_parsed_property(_flex_wrap_, property_value(idx, important)); + } + } + break; + } + + // Parse flex shorthand properties + case _flex_: + parse_flex(val, important); + break; + + case _flex_grow_: + case _flex_shrink_: + add_parsed_property(name, property_value(t_strtof(val), important)); + break; + + case _flex_basis_: + length.fromString(val, flex_basis_strings, -1); + add_parsed_property(_flex_basis_, property_value(length, important)); + break; + + case _order_: // <integer> + { + char* end; + int int_val = (int) strtol(val.c_str(), &end, 10); + if(end[0] == '\0') + { + add_parsed_property(name, property_value(int_val, important)); + } + } + break; + case _counter_increment_: + case _counter_reset_: + { + string_vector tokens; + split_string(val, tokens, " "); + add_parsed_property(name, property_value(tokens, important)); + break; + } + + default: + add_parsed_property(name, property_value(val, important)); + } +} + +css_length style::parse_border_width(const string& str) +{ + css_length len; + if (t_isdigit(str[0]) || str[0] == '.') + { + len.fromString(str); + } + else + { + int idx = value_index(str, border_width_strings); + if (idx >= 0) + { + len.set_value(border_width_values[idx], css_units_px); + } + } + return len; +} + +void style::parse_two_lengths(const string& str, css_length len[2]) +{ + string_vector tokens; + split_string(str, tokens, " "); + if (tokens.size() == 1) + { + css_length length; + length.fromString(tokens[0]); + len[0] = len[1] = length; + } + else if (tokens.size() == 2) + { + len[0].fromString(tokens[0]); + len[1].fromString(tokens[1]); + } +} + +int style::parse_four_lengths(const string& str, css_length len[4]) +{ + string_vector tokens; + split_string(str, tokens, " "); + if (tokens.size() == 0 || tokens.size() > 4) + { + return 0; + } + for (size_t i = 0; i < tokens.size(); i++) + { + len[i].fromString(tokens[i]); + } + return (int)tokens.size(); +} + +void style::parse_background(const string& val, const string& baseurl, bool important, document_container* container) +{ + string_vector tokens; + split_string(val, tokens, ",", "", "("); + if (tokens.empty()) return; + + web_color color; + string_vector images; + int_vector repeats, origins, clips, attachments; + length_vector x_positions, y_positions; + size_vector sizes; + + for (const auto& token : tokens) + { + background bg; + if (!parse_one_background(token, container, bg)) + return; + + color = bg.m_color; + images.push_back(bg.m_image[0]); + repeats.push_back(bg.m_repeat[0]); + origins.push_back(bg.m_origin[0]); + clips.push_back(bg.m_clip[0]); + attachments.push_back(bg.m_attachment[0]); + x_positions.push_back(bg.m_position_x[0]); + y_positions.push_back(bg.m_position_y[0]); + sizes.push_back(bg.m_size[0]); + } + + add_parsed_property(_background_color_, property_value(color, important)); + add_parsed_property(_background_image_, property_value(images, important)); + add_parsed_property(_background_image_baseurl_, property_value(baseurl, important)); + add_parsed_property(_background_repeat_, property_value(repeats, important)); + add_parsed_property(_background_origin_, property_value(origins, important)); + add_parsed_property(_background_clip_, property_value(clips, important)); + add_parsed_property(_background_attachment_, property_value(attachments, important)); + add_parsed_property(_background_position_x_, property_value(x_positions, important)); + add_parsed_property(_background_position_y_, property_value(y_positions, important)); + add_parsed_property(_background_size_, property_value(sizes, important)); +} + +bool style::parse_one_background(const string& val, document_container* container, background& bg) +{ + bg.m_color = web_color::transparent; + bg.m_image = {""}; + bg.m_repeat = { background_repeat_repeat }; + bg.m_origin = { background_box_padding }; + bg.m_clip = { background_box_border }; + bg.m_attachment = { background_attachment_scroll }; + bg.m_position_x = { css_length(0, css_units_percentage) }; + bg.m_position_y = { css_length(0, css_units_percentage) }; + bg.m_size = { css_size(css_length::predef_value(background_size_auto), css_length::predef_value(background_size_auto)) }; + + if(val == "none") + { + return true; + } + + string_vector tokens; + split_string(val, tokens, " \t\n\r", "", "("); + + bool color_found = false; + bool image_found = false; + bool origin_found = false; + bool clip_found = false; + bool repeat_found = false; + bool attachment_found = false; + + string position; + for(const auto& token : tokens) + { + int idx; + if(token.substr(0, 3) == "url") + { + if (image_found) return false; + string url; + css::parse_css_url(token, url); + bg.m_image = { url }; + image_found = true; + } else if( (idx = value_index(token, background_repeat_strings)) >= 0 ) + { + if (repeat_found) return false; + bg.m_repeat = { idx }; + repeat_found = true; + } else if( (idx = value_index(token, background_attachment_strings)) >= 0 ) + { + if (attachment_found) return false; + bg.m_attachment = { idx }; + attachment_found = true; + } else if( (idx = value_index(token, background_box_strings)) >= 0 ) + { + if(!origin_found) + { + bg.m_origin = { idx }; + origin_found = true; + } else + { + if (clip_found) return false; + bg.m_clip = { idx }; + clip_found = true; + } + } else if( value_in_list(token, background_position_strings) || + token.find('/') != string::npos || + t_isdigit(token[0]) || + token[0] == '+' || + token[0] == '-' || + token[0] == '.' ) + { + position += " " + token; + } else if (web_color::is_color(token, container)) + { + if (color_found) return false; + bg.m_color = web_color::from_string(token, container); + color_found = true; + } + else + { + return false; + } + } + + if (position != "") + { + string_vector tokens; + split_string(position, tokens, "/"); + + if (tokens.size() > 2) return false; + + if (tokens.size() == 2 && !parse_one_background_size(tokens[1], bg.m_size[0])) + return false; + + if (tokens.size() > 0 && !parse_one_background_position(tokens[0], bg.m_position_x[0], bg.m_position_y[0])) + return false; + } + + return true; +} + +void style::parse_background_image(const string& val, const string& baseurl, bool important) +{ + string_vector tokens; + split_string(val, tokens, ",", "", "("); + if (tokens.empty()) return; + + string_vector images; + + for (const auto& token : tokens) + { + string url; + css::parse_css_url(token, url); + images.push_back(url); + } + + add_parsed_property(_background_image_, property_value(images, important)); + add_parsed_property(_background_image_baseurl_, property_value(baseurl, important)); +} + +void style::parse_keyword_comma_list(string_id name, const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + int_vector vec; + + for (auto& token : tokens) + { + trim(token); + int idx = value_index(token, m_valid_values[name]); + if (idx == -1) return; + vec.push_back(idx); + } + + add_parsed_property(name, property_value(vec, important)); +} + +void style::parse_background_position(const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + length_vector x_positions, y_positions; + + for (const auto& token : tokens) + { + css_length x, y; + if(!parse_one_background_position(token, x, y)) return; + x_positions.push_back(x); + y_positions.push_back(y); + } + + add_parsed_property(_background_position_x_, property_value(x_positions, important)); + add_parsed_property(_background_position_y_, property_value(y_positions, important)); +} + +bool style::parse_one_background_position(const string& val, css_length& x, css_length& y) +{ + string_vector pos; + split_string(val, pos, " \t"); + + if (pos.empty() || pos.size() > 2) + { + return false; + } + + if (pos.size() == 1) + { + if (value_in_list(pos[0], "left;right;center")) + { + x.fromString(pos[0], "left;right;center"); + y.set_value(50, css_units_percentage); + } + else if (value_in_list(pos[0], "top;bottom;center")) + { + y.fromString(pos[0], "top;bottom;center"); + x.set_value(50, css_units_percentage); + } + else + { + x.fromString(pos[0], "left;right;center"); + y.set_value(50, css_units_percentage); + } + } + else if (pos.size() == 2) + { + if (value_in_list(pos[0], "left;right")) + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + else if (value_in_list(pos[0], "top;bottom")) + { + x.fromString(pos[1], "left;right;center"); + y.fromString(pos[0], "top;bottom;center"); + } + else if (value_in_list(pos[1], "left;right")) + { + x.fromString(pos[1], "left;right;center"); + y.fromString(pos[0], "top;bottom;center"); + } + else if (value_in_list(pos[1], "top;bottom")) + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + else + { + x.fromString(pos[0], "left;right;center"); + y.fromString(pos[1], "top;bottom;center"); + } + } + + if (x.is_predefined()) + { + switch (x.predef()) + { + case 0: + x.set_value(0, css_units_percentage); + break; + case 1: + x.set_value(100, css_units_percentage); + break; + case 2: + x.set_value(50, css_units_percentage); + break; + } + } + if (y.is_predefined()) + { + switch (y.predef()) + { + case 0: + y.set_value(0, css_units_percentage); + break; + case 1: + y.set_value(100, css_units_percentage); + break; + case 2: + y.set_value(50, css_units_percentage); + break; + } + } + return true; +} + +void style::parse_background_size(const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, ","); + if (tokens.empty()) return; + + size_vector sizes; + + for (const auto& token : tokens) + { + css_size size; + if (!parse_one_background_size(token, size)) return; + sizes.push_back(size); + } + + add_parsed_property(_background_size_, property_value(sizes, important)); +} + +bool style::parse_one_background_size(const string& val, css_size& size) +{ + string_vector res; + split_string(val, res, " \t"); + if (res.empty()) + { + return false; + } + + size.width.fromString(res[0], background_size_strings); + if (res.size() > 1) + { + size.height.fromString(res[1], background_size_strings); + } + else + { + size.height.predef(background_size_auto); + } + return true; +} + +void style::parse_font(const string& val, bool important) +{ + if (val == "inherit") + { + add_parsed_property(_font_style_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_variant_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_weight_, property_value(important, prop_type_inherit)); + add_parsed_property(_font_size_, property_value(important, prop_type_inherit)); + add_parsed_property(_line_height_, property_value(important, prop_type_inherit)); + return; + } else + { + add_parsed_property(_font_style_, property_value(font_style_normal, important)); + add_parsed_property(_font_variant_, property_value(font_variant_normal, important)); + add_parsed_property(_font_weight_, property_value(font_weight_normal, important)); + add_parsed_property(_font_size_, property_value(font_size_medium, important)); + add_parsed_property(_line_height_, property_value(line_height_normal, important)); + } + + string_vector tokens; + split_string(val, tokens, " ", "", "\""); + + int idx; + bool is_family = false; + string font_family; + for(const auto& token : tokens) + { + if(is_family) + { + font_family += token; + continue; + } + + if((idx = value_index(token, font_style_strings)) >= 0) + { + if(idx == 0) + { + add_parsed_property(_font_style_, property_value(font_style_normal, important)); + add_parsed_property(_font_variant_, property_value(font_variant_normal, important)); + add_parsed_property(_font_weight_, property_value(font_weight_normal, important)); + } else + { + add_parsed_property(_font_style_, property_value(idx, important)); + } + } else if((idx = value_index(token, font_weight_strings)) >= 0) + { + add_parsed_property(_font_weight_, property_value(idx, important)); + } else if((idx = value_index(token, font_variant_strings)) >= 0) + { + add_parsed_property(_font_variant_, property_value(idx, important)); + } + else if(t_isdigit(token[0]) || token[0] == '.' || + value_in_list(token, font_size_strings) || token.find('/') != string::npos) + { + string_vector szlh; + split_string(token, szlh, "/"); + if(!szlh.empty()) + { + auto size = css_length::from_string(szlh[0], font_size_strings, -1); + add_parsed_property(_font_size_, property_value(size, important)); + + if (szlh.size() == 2) + { + auto height = css_length::from_string(szlh[1], "normal", -1); + add_parsed_property(_line_height_, property_value(height, important)); + } + } + } else + { + is_family = true; + font_family += token; + } + } + add_parsed_property(_font_family_, property_value(font_family, important)); +} + +void style::parse_flex(const string& val, bool important) +{ + css_length _auto = css_length::predef_value(flex_basis_auto); + + if (val == "initial") + { + // 0 1 auto + add_parsed_property(_flex_grow_, property_value(0.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else if (val == "auto") + { + // 1 1 auto + add_parsed_property(_flex_grow_, property_value(1.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else if (val == "none") + { + // 0 0 auto + add_parsed_property(_flex_grow_, property_value(0.f, important)); + add_parsed_property(_flex_shrink_, property_value(0.f, important)); + add_parsed_property(_flex_basis_, property_value(_auto, important)); + } + else + { + string_vector tokens; + split_string(val, tokens, " "); + if (tokens.size() == 3) + { + float grow = t_strtof(tokens[0]); + float shrink = t_strtof(tokens[1]); + auto basis = css_length::from_string(tokens[2], flex_basis_strings, -1); + if(!basis.is_predefined() && basis.units() == css_units_none && basis.val() == 0) + { + basis.set_value(basis.val(), css_units_px); + } + + add_parsed_property(_flex_grow_, property_value(grow, important)); + add_parsed_property(_flex_shrink_, property_value(shrink, important)); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + else if (tokens.size() == 2) + { + float grow = t_strtof(tokens[0]); + add_parsed_property(_flex_grow_, property_value(grow, important)); + + if (litehtml::is_number(tokens[1])) + { + float shrink = t_strtof(tokens[1]); + add_parsed_property(_flex_shrink_, property_value(shrink, important)); + add_parsed_property(_flex_basis_, property_value(css_length(0), important)); + } + else + { + auto basis = css_length::from_string(tokens[1], flex_basis_strings, -1); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + } + else if (tokens.size() == 1) + { + if (is_number(tokens[0])) + { + float grow = t_strtof(tokens[0]); + add_parsed_property(_flex_grow_, property_value(grow, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(css_length(0), important)); + } + else + { + auto basis = css_length::from_string(tokens[0], flex_basis_strings, -1); + add_parsed_property(_flex_grow_, property_value(1.f, important)); + add_parsed_property(_flex_shrink_, property_value(1.f, important)); + add_parsed_property(_flex_basis_, property_value(basis, important)); + } + } + } +} + +void style::parse_align_self(string_id name, const string& val, bool important) +{ + string_vector tokens; + split_string(val, tokens, " "); + if(tokens.size() == 1) + { + int idx = value_index(val, m_valid_values[name]); + if (idx >= 0) + { + add_parsed_property(name, property_value(idx, important)); + } + } else + { + int val1 = 0; + int val2 = -1; + for(auto &token : tokens) + { + if(token == "first") + { + val1 |= flex_align_items_first; + } else if(token == "last") + { + val1 |= flex_align_items_last; + } else if(token == "safe") + { + val1 |= flex_align_items_safe; + } else if(token == "unsafe") + { + val1 |= flex_align_items_unsafe; + } else + { + int idx = value_index(token, m_valid_values[name]); + if(idx >= 0) + { + val2 = idx; + } + } + } + if(val2 >= 0) + { + add_parsed_property(name, property_value(val1 | val2, important)); + } + } +} + +void style::add_parsed_property( string_id name, const property_value& propval ) +{ + auto prop = m_properties.find(name); + if (prop != m_properties.end()) + { + if (!prop->second.m_important || (propval.m_important && prop->second.m_important)) + { + prop->second = propval; + } + } + else + { + m_properties[name] = propval; + } +} + +void style::remove_property( string_id name, bool important ) +{ + auto prop = m_properties.find(name); + if(prop != m_properties.end()) + { + if( !prop->second.m_important || (important && prop->second.m_important) ) + { + m_properties.erase(prop); + } + } +} + +void style::combine(const style& src) +{ + for (const auto& property : src.m_properties) + { + add_parsed_property(property.first, property.second); + } +} + +const property_value& style::get_property(string_id name) const +{ + auto it = m_properties.find(name); + if (it != m_properties.end()) + { + return it->second; + } + static property_value dummy; + return dummy; +} + +void style::subst_vars_(string& str, const element* el) +{ + while (true) + { + auto start = str.find("var("); + if (start == string::npos) break; + if (start > 0 && isalnum(str[start - 1])) break; + auto end = str.find(')', start + 4); + if (end == string::npos) break; + auto name = str.substr(start + 4, end - start - 4); + trim(name); + string val = el->get_custom_property(_id(name), ""); + str.replace(start, end - start + 1, val); + } +} + +void style::subst_vars(const element* el) +{ + for (auto& prop : m_properties) + { + if (prop.second.m_type == prop_type_var) + { + subst_vars_(prop.second.m_string, el); + // re-adding the same property + // if it is a custom property it will be readded as a string (currently it is prop_type_var) + // if it is a standard css property it will be parsed and properly added as typed property + add_property(prop.first, prop.second.m_string, "", prop.second.m_important, el->get_document()->container()); + } + } +} + +} // namespace litehtml
\ No newline at end of file diff --git a/libs/litehtml/src/stylesheet.cpp b/libs/litehtml/src/stylesheet.cpp new file mode 100644 index 0000000000..8c4b784311 --- /dev/null +++ b/libs/litehtml/src/stylesheet.cpp @@ -0,0 +1,225 @@ +#include "html.h" +#include "stylesheet.h" +#include <algorithm> +#include "document.h" + + +void litehtml::css::parse_stylesheet(const char* str, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media) +{ + string text = str; + + // remove comments + string::size_type c_start = text.find("/*"); + while(c_start != string::npos) + { + string::size_type c_end = text.find("*/", c_start + 2); + if(c_end == string::npos) + { + text.erase(c_start); + break; + } + text.erase(c_start, c_end - c_start + 2); + c_start = text.find("/*"); + } + + string::size_type pos = text.find_first_not_of(" \n\r\t"); + while(pos != string::npos) + { + while(pos != string::npos && text[pos] == '@') + { + string::size_type sPos = pos; + pos = text.find_first_of("{;", pos); + if(pos != string::npos && text[pos] == '{') + { + pos = find_close_bracket(text, pos, '{', '}'); + } + if(pos != string::npos) + { + parse_atrule(text.substr(sPos, pos - sPos + 1), baseurl, doc, media); + } else + { + parse_atrule(text.substr(sPos), baseurl, doc, media); + } + + if(pos != string::npos) + { + pos = text.find_first_not_of(" \n\r\t", pos + 1); + } + } + + if(pos == string::npos) + { + break; + } + + string::size_type style_start = text.find('{', pos); + string::size_type style_end = text.find('}', pos); + if(style_start != string::npos && style_end != string::npos) + { + auto str_style = text.substr(style_start + 1, style_end - style_start - 1); + style::ptr style = std::make_shared<litehtml::style>(); + style->add(str_style, baseurl ? baseurl : "", doc->container()); + + parse_selectors(text.substr(pos, style_start - pos), style, media); + + if(media && doc) + { + doc->add_media_list(media); + } + + pos = style_end + 1; + } else + { + pos = string::npos; + } + + if(pos != string::npos) + { + pos = text.find_first_not_of(" \n\r\t", pos); + } + } +} + +void litehtml::css::parse_css_url( const string& str, string& url ) +{ + url = ""; + size_t pos1 = str.find('('); + size_t pos2 = str.find(')'); + if(pos1 != string::npos && pos2 != string::npos) + { + url = str.substr(pos1 + 1, pos2 - pos1 - 1); + if(url.length()) + { + if(url[0] == '\'' || url[0] == '"') + { + url.erase(0, 1); + } + } + if(url.length()) + { + if(url[url.length() - 1] == '\'' || url[url.length() - 1] == '"') + { + url.erase(url.length() - 1, 1); + } + } + } +} + +bool litehtml::css::parse_selectors( const string& txt, const style::ptr& styles, const media_query_list::ptr& media ) +{ + string selector = txt; + trim(selector); + string_vector tokens; + split_string(selector, tokens, ","); + + bool added_something = false; + + for(auto & token : tokens) + { + css_selector::ptr new_selector = std::make_shared<css_selector>(media); + new_selector->m_style = styles; + trim(token); + if(new_selector->parse(token)) + { + new_selector->calc_specificity(); + add_selector(new_selector); + added_something = true; + } + } + + return added_something; +} + +void litehtml::css::sort_selectors() +{ + std::sort(m_selectors.begin(), m_selectors.end(), + [](const css_selector::ptr& v1, const css_selector::ptr& v2) + { + return (*v1) < (*v2); + } + ); +} + +void litehtml::css::parse_atrule(const string& text, const char* baseurl, const std::shared_ptr<document>& doc, const media_query_list::ptr& media) +{ + if(text.substr(0, 7) == "@import") + { + int sPos = 7; + string iStr; + iStr = text.substr(sPos); + if(iStr[iStr.length() - 1] == ';') + { + iStr.erase(iStr.length() - 1); + } + trim(iStr); + string_vector tokens; + split_string(iStr, tokens, " ", "", "(\""); + if(!tokens.empty()) + { + string url; + parse_css_url(tokens.front(), url); + if(url.empty()) + { + url = tokens.front(); + } + tokens.erase(tokens.begin()); + if(doc) + { + document_container* doc_cont = doc->container(); + if(doc_cont) + { + string css_text; + string css_baseurl; + if(baseurl) + { + css_baseurl = baseurl; + } + doc_cont->import_css(css_text, url, css_baseurl); + if(!css_text.empty()) + { + media_query_list::ptr new_media = media; + if(!tokens.empty()) + { + string media_str; + for(auto iter = tokens.begin(); iter != tokens.end(); iter++) + { + if(iter != tokens.begin()) + { + media_str += " "; + } + media_str += (*iter); + } + new_media = media_query_list::create_from_string(media_str, doc); + if(!new_media) + { + new_media = media; + } + } + parse_stylesheet(css_text.c_str(), css_baseurl.c_str(), doc, new_media); + } + } + } + } + } else if(text.substr(0, 6) == "@media") + { + string::size_type b1 = text.find_first_of('{'); + string::size_type b2 = text.find_last_of('}'); + if(b1 != string::npos) + { + string media_type = text.substr(6, b1 - 6); + trim(media_type); + media_query_list::ptr new_media = media_query_list::create_from_string(media_type, doc); + + string media_style; + if(b2 != string::npos) + { + media_style = text.substr(b1 + 1, b2 - b1 - 1); + } else + { + media_style = text.substr(b1 + 1); + } + + parse_stylesheet(media_style.c_str(), baseurl, doc, new_media); + } + } +} diff --git a/libs/litehtml/src/table.cpp b/libs/litehtml/src/table.cpp new file mode 100644 index 0000000000..08c167b222 --- /dev/null +++ b/libs/litehtml/src/table.cpp @@ -0,0 +1,609 @@ +#include "html.h" +#include "table.h" +#include "element.h" +#include "render_item.h" + +void litehtml::table_grid::add_cell(const std::shared_ptr<render_item>& el) +{ + table_cell cell; + cell.el = el; + cell.colspan = atoi(el->src_el()->get_attr("colspan", "1")); + cell.rowspan = atoi(el->src_el()->get_attr("rowspan", "1")); + cell.borders = el->get_borders(); + + while( is_rowspanned( (int) m_cells.size() - 1, (int) m_cells.back().size() ) ) + { + m_cells.back().push_back(table_cell()); + } + + m_cells.back().push_back(cell); + for(int i = 1; i < cell.colspan; i++) + { + table_cell empty_cell; + m_cells.back().push_back(empty_cell); + } +} + + +void litehtml::table_grid::begin_row(const std::shared_ptr<render_item>& row) +{ + std::vector<table_cell> r; + m_cells.push_back(r); + + m_rows.push_back(table_row(0, row)); +} + + +bool litehtml::table_grid::is_rowspanned( int r, int c ) +{ + for(int row = r - 1; row >= 0; row--) + { + if(c < (int) m_cells[row].size()) + { + if(m_cells[row][c].rowspan > 1) + { + if(m_cells[row][c].rowspan >= r - row + 1) + { + return true; + } + } + } + } + return false; +} + +void litehtml::table_grid::finish() +{ + m_rows_count = (int) m_cells.size(); + m_cols_count = 0; + for(auto& cell : m_cells) + { + m_cols_count = std::max(m_cols_count, (int) cell.size()); + } + for(auto& cell : m_cells) + { + for(int j = (int) cell.size(); j < m_cols_count; j++) + { + table_cell empty_cell; + cell.push_back(empty_cell); + } + } + + m_columns.clear(); + for(int i = 0; i < m_cols_count; i++) + { + m_columns.push_back(table_column(0, 0)); + } + + for(int col = 0; col < m_cols_count; col++) + { + for(int row = 0; row < m_rows_count; row++) + { + if(cell(col, row)->el) + { + // find minimum left border width + if(m_columns[col].border_left) + { + m_columns[col].border_left = std::min(m_columns[col].border_left, cell(col, row)->borders.left); + } else + { + m_columns[col].border_left = cell(col, row)->borders.left; + } + // find minimum right border width + if(m_columns[col].border_right) + { + m_columns[col].border_right = std::min(m_columns[col].border_right, cell(col, row)->borders.right); + } else + { + m_columns[col].border_right = cell(col, row)->borders.right; + } + // find minimum top border width + if(m_rows[row].border_top) + { + m_rows[row].border_top = std::min(m_rows[row].border_top, cell(col, row)->borders.top); + } else + { + m_rows[row].border_top = cell(col, row)->borders.top; + } + // find minimum bottom border width + if(m_rows[row].border_bottom) + { + m_rows[row].border_bottom = std::min(m_rows[row].border_bottom, cell(col, row)->borders.bottom); + } else + { + m_rows[row].border_bottom = cell(col, row)->borders.bottom; + } + } + + if(cell(col, row)->el && cell(col, row)->colspan <= 1) + { + if (!cell(col, row)->el->src_el()->css().get_width().is_predefined() && m_columns[col].css_width.is_predefined()) + { + m_columns[col].css_width = cell(col, row)->el->src_el()->css().get_width(); + } + } + } + } + + for(int col = 0; col < m_cols_count; col++) + { + for(int row = 0; row < m_rows_count; row++) + { + if(cell(col, row)->el && cell(col, row)->colspan == 1) + { + cell(col, row)->el->src_el()->css_w().set_width(m_columns[col].css_width); + } + } + } +} + +litehtml::table_cell* litehtml::table_grid::cell( int t_col, int t_row ) +{ + if(t_col >= 0 && t_col < m_cols_count && t_row >= 0 && t_row < m_rows_count) + { + return &m_cells[t_row][t_col]; + } + return nullptr; +} + +void litehtml::table_grid::distribute_max_width( int width, int start, int end ) +{ + table_column_accessor_max_width selector; + distribute_width(width, start, end, &selector); +} + +void litehtml::table_grid::distribute_min_width( int width, int start, int end ) +{ + table_column_accessor_min_width selector; + distribute_width(width, start, end, &selector); +} + +void litehtml::table_grid::distribute_width( int width, int start, int end, table_column_accessor* acc ) +{ + if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count)) + { + return; + } + + int cols_width = 0; + for(int col = start; col <= end; col++) + { + cols_width += m_columns[col].max_width; + } + + int add = width / (end - start + 1); + int added_width = 0; + for(int col = start; col <= end; col++) + { + if(cols_width) + { + add = round_f( (float) width * ((float) m_columns[col].max_width / (float) cols_width) ); + } + added_width += add; + acc->get(m_columns[col]) += add; + } + if(added_width < width) + { + acc->get(m_columns[start]) += width - added_width; + } +} + +void litehtml::table_grid::distribute_width( int width, int start, int end ) +{ + if(!(start >= 0 && start < m_cols_count && end >= 0 && end < m_cols_count)) + { + return; + } + + std::vector<table_column*> distribute_columns; + + for(int step = 0; step < 3; step++) + { + distribute_columns.clear(); + + switch(step) + { + case 0: + { + // distribute between the columns with width == auto + for(int col = start; col <= end; col++) + { + if(m_columns[col].css_width.is_predefined()) + { + distribute_columns.push_back(&m_columns[col]); + } + } + } + break; + case 1: + { + // distribute between the columns with percents + for(int col = start; col <= end; col++) + { + if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage) + { + distribute_columns.push_back(&m_columns[col]); + } + } + } + break; + case 2: + { + //well distribute between all columns + for(int col = start; col <= end; col++) + { + distribute_columns.push_back(&m_columns[col]); + } + } + break; + } + + int added_width = 0; + + if(!distribute_columns.empty() || step == 2) + { + int cols_width = 0; + for(const auto& column : distribute_columns) + { + cols_width += column->max_width - column->min_width; + } + + if(cols_width) + { + int add = width / (int) distribute_columns.size(); + for(const auto& column : distribute_columns) + { + add = round_f( (float) width * ((float) (column->max_width - column->min_width) / (float) cols_width) ); + if(column->width + add >= column->min_width) + { + column->width += add; + added_width += add; + } else + { + added_width += (column->width - column->min_width) * (add / abs(add)); + column->width = column->min_width; + } + } + if(added_width < width && step) + { + distribute_columns.front()->width += width - added_width; + added_width = width; + } + } else + { + distribute_columns.back()->width += width; + added_width = width; + } + } + + if(added_width == width) + { + break; + } else + { + width -= added_width; + } + } +} + +int litehtml::table_grid::calc_table_width(int block_width, bool is_auto, int& min_table_width, int& max_table_width) +{ + //int table_width = 0; + + min_table_width = 0; // MIN + max_table_width = 0; // MAX + + int cur_width = 0; + int max_w = 0; + int min_w = 0; + + for(int col = 0; col < m_cols_count; col++) + { + min_table_width += m_columns[col].min_width; + max_table_width += m_columns[col].max_width; + + if(!m_columns[col].css_width.is_predefined()) + { + m_columns[col].width = m_columns[col].css_width.calc_percent(block_width); + m_columns[col].width = std::max(m_columns[col].width, m_columns[col].min_width); + } else + { + m_columns[col].width = m_columns[col].min_width; + max_w += m_columns[col].max_width; + min_w += m_columns[col].min_width; + } + + cur_width += m_columns[col].width; + } + + if(cur_width == block_width) + { + return cur_width; + } + + if(cur_width < block_width) + { + if(cur_width - min_w + max_w <= block_width) + { + cur_width = 0; + for(int col = 0; col < m_cols_count; col++) + { + if(m_columns[col].css_width.is_predefined()) + { + m_columns[col].width = m_columns[col].max_width; + } + cur_width += m_columns[col].width; + } + if(cur_width == block_width || is_auto) + { + return cur_width; + } + } + distribute_width(block_width - cur_width, 0, m_cols_count - 1); + cur_width = 0; + for(int col = 0; col < m_cols_count; col++) + { + cur_width += m_columns[col].width; + } + } else + { + int fixed_width = 0; + float percent = 0; + for(int col = 0; col < m_cols_count; col++) + { + if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage) + { + percent += m_columns[col].css_width.val(); + } else + { + fixed_width += m_columns[col].width; + } + } + auto scale = (float) (100.0 / percent); + cur_width = 0; + for(int col = 0; col < m_cols_count; col++) + { + if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage) + { + css_length w; + w.set_value(m_columns[col].css_width.val() * scale, css_units_percentage); + m_columns[col].width = w.calc_percent(block_width - fixed_width); + if(m_columns[col].width < m_columns[col].min_width) + { + m_columns[col].width = m_columns[col].min_width; + } + } + cur_width += m_columns[col].width; + } + // If the table is still too wide shrink columns with % widths + if(cur_width > block_width) + { + while(true) + { + bool shrunk = false; + for(int col = 0; col < m_cols_count; col++) + { + if(!m_columns[col].css_width.is_predefined() && m_columns[col].css_width.units() == css_units_percentage) + { + if(m_columns[col].width > m_columns[col].min_width) + { + m_columns[col].width--; + cur_width--; + shrunk = true; + if(cur_width == block_width) + { + break; + } + } + } + } + if(cur_width == block_width || !shrunk) + { + break; + } + } + } + } + return cur_width; +} + +void litehtml::table_grid::clear() +{ + m_rows_count = 0; + m_cols_count = 0; + m_cells.clear(); + m_columns.clear(); + m_rows.clear(); +} + +void litehtml::table_grid::calc_horizontal_positions( const margins& table_borders, border_collapse bc, int bdr_space_x) +{ + if(bc == border_collapse_separate) + { + int left = bdr_space_x; + for(int i = 0; i < m_cols_count; i++) + { + m_columns[i].left = left; + m_columns[i].right = m_columns[i].left + m_columns[i].width; + left = m_columns[i].right + bdr_space_x; + } + } else + { + int left = 0; + if(m_cols_count) + { + left -= std::min(table_borders.left, m_columns[0].border_left); + } + for(int i = 0; i < m_cols_count; i++) + { + if(i > 0) + { + left -= std::min(m_columns[i - 1].border_right, m_columns[i].border_left); + } + + m_columns[i].left = left; + m_columns[i].right = m_columns[i].left + m_columns[i].width; + left = m_columns[i].right; + } + } +} + +void litehtml::table_grid::calc_vertical_positions( const margins& table_borders, border_collapse bc, int bdr_space_y ) +{ + if(bc == border_collapse_separate) + { + int top = bdr_space_y; + for(int i = 0; i < m_rows_count; i++) + { + m_rows[i].top = top; + m_rows[i].bottom = m_rows[i].top + m_rows[i].height; + top = m_rows[i].bottom + bdr_space_y; + } + } else + { + int top = 0; + if(m_rows_count) + { + top -= std::min(table_borders.top, m_rows[0].border_top); + } + for(int i = 0; i < m_rows_count; i++) + { + if(i > 0) + { + top -= std::min(m_rows[i - 1].border_bottom, m_rows[i].border_top); + } + + m_rows[i].top = top; + m_rows[i].bottom = m_rows[i].top + m_rows[i].height; + top = m_rows[i].bottom; + } + } +} + +void litehtml::table_grid::calc_rows_height(int blockHeight, int /*borderSpacingY*/) +{ + int min_table_height = 0; + + // compute vertical size inferred by cells + for (auto& row : m_rows) + { + if (!row.css_height.is_predefined()) + { + if (row.css_height.units() != css_units_percentage) + { + if (row.height < (int)row.css_height.val()) + { + row.height = (int)row.css_height.val(); + } + } + } + row.min_height = row.height; + min_table_height += row.height; + } + + //min_table_height += borderSpacingY * ((int) m_rows.size() + 1); + + if (blockHeight > min_table_height) + { + int extra_height = blockHeight - min_table_height; + int auto_count = 0; // number of rows with height=auto + for (auto& row : m_rows) + { + if (!row.css_height.is_predefined() && row.css_height.units() == css_units_percentage) + { + row.height = row.css_height.calc_percent(blockHeight); + if (row.height < row.min_height) + { + row.height = row.min_height; + } + + extra_height -= row.height - row.min_height; + + if (extra_height <= 0) break; + } + else if (row.css_height.is_predefined()) + { + auto_count++; + } + } + if (extra_height > 0) + { + if (auto_count) + { + // distribute height to the rows with height=auto + int extra_row_height = (int)(extra_height / auto_count); + for (auto& row : m_rows) + { + if (row.css_height.is_predefined()) + { + row.height += extra_row_height; + } + } + } + else + { + // We don't have rows with height=auto, so distribute height to all rows + if (!m_rows.empty()) + { + int extra_row_height = (int)(extra_height / m_rows.size()); + for (auto& row : m_rows) + { + row.height += extra_row_height; + } + } + } + } + else if (extra_height < 0) + { + extra_height = -extra_height; + for (auto row = m_rows.rbegin(); row < m_rows.rend() && extra_height > 0; row++) + { + if (row->height > row->min_height) + { + if (row->height - extra_height >= row->min_height) + { + row->height -= extra_height; + extra_height = 0; + } + else + { + extra_height -= row->height - row->min_height; + row->height = row->min_height; + } + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////// + +int& litehtml::table_column_accessor_max_width::get( table_column& col ) +{ + return col.max_width; +} + +int& litehtml::table_column_accessor_min_width::get( table_column& col ) +{ + return col.min_width; +} + +int& litehtml::table_column_accessor_width::get( table_column& col ) +{ + return col.width; +} + +litehtml::table_row::table_row(int h, const std::shared_ptr<render_item>& row) +{ + min_height = 0; + height = h; + el_row = row; + border_bottom = 0; + border_top = 0; + top = 0; + bottom = 0; + if (row) + { + css_height = row->src_el()->css().get_height(); + } +} diff --git a/libs/litehtml/src/tstring_view.cpp b/libs/litehtml/src/tstring_view.cpp new file mode 100644 index 0000000000..f9afa4bbc9 --- /dev/null +++ b/libs/litehtml/src/tstring_view.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020-2021 Primate Labs Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "tstring_view.h" + +namespace litehtml { + + +std::basic_ostream<tstring_view::value_type>& operator<<( + std::basic_ostream<tstring_view::value_type>& os, + tstring_view str) +{ + if (os.good()) { + os.write(str.data(), str.size()); + } + + return os; +} + +} // namespace litehtml
\ No newline at end of file diff --git a/libs/litehtml/src/url.cpp b/libs/litehtml/src/url.cpp new file mode 100644 index 0000000000..13076e338b --- /dev/null +++ b/libs/litehtml/src/url.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2020-2021 Primate Labs Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "url.h" + +#include <iostream> +#include <sstream> +#include <algorithm> + +#include "codepoint.h" +#include "url_path.h" + +namespace litehtml { + +url::url(const string& str) +: str_(str) +{ + // TODO: Rewrite using tstring_view to avoid unnecessary allocations. + string tmp = str_; + + // Does the URL include a scheme? + size_t offset = tmp.find(':'); + if (offset != string::npos) { + bool valid_scheme = true; + for (size_t i = 0; i < offset; i++) { + if (!is_url_scheme_codepoint(tmp[i])) { + valid_scheme = false; + break; + } + } + if (valid_scheme) { + scheme_ = tmp.substr(0, offset); + tmp = tmp.substr(offset + 1); + } + } + + // Does the URL include an authority? An authority component is preceded + // by a double slash ("//") and is terminated by the next slash ("/"), + // question mark ("?"), number sign ("#"), or the end of the URL. + + if (tmp.size() >= 2 && tmp[0] == '/' && tmp[1] == '/') { + tmp = tmp.substr(2); + offset = tmp.size(); + offset = std::min(offset, tmp.find('/')); + offset = std::min(offset, tmp.find('?')); + offset = std::min(offset, tmp.find('#')); + authority_ = tmp.substr(0, offset); + tmp = tmp.substr(offset); + + // TODO: Parse the network location into host and port? + } + + // Does the URL include a fragment? + offset = tmp.find('#'); + if (offset != string::npos) { + fragment_ = tmp.substr(offset + 1); + tmp = tmp.substr(0, offset); + } + + // Does the URL include a query? + offset = tmp.find('?'); + if (offset != string::npos) { + query_ = tmp.substr(offset + 1); + tmp = tmp.substr(0, offset); + } + + // Whatever remains of the URL after removing the scheme, the network + // location, the query, and the fragment is the path. + path_ = tmp; +} + +url::url(const string& scheme, + const string& authority, + const string& path, + const string& query, + const string& fragment) +: scheme_(scheme) +, authority_(authority) +, path_(path) +, query_(query) +, fragment_(fragment) +{ + std::stringstream tss; + + if (!scheme_.empty()) { + tss << scheme_ << ":"; + } + if (!authority_.empty()) { + tss << "//" << authority_; + } + if (!path_.empty()) { + tss << path_; + } + if (!query_.empty()) { + tss << "?" << query_; + } + if (!fragment_.empty()) { + tss << "#" << fragment_; + } + str_ = tss.str(); +} + +url resolve(const url& b, const url& r) +{ + // The resolution algorithm roughly follows the resolution algorithm + // outlined in Section 5.2 (in particular Section 5.2.2) of RFC 3986. The + // major difference between the resolution algorithm and resolve() is that + // resolve() does not attempt to normalize the path components. + + if (r.has_scheme()) { + return r; + } else if (r.has_authority()) { + return url(b.scheme(), r.authority(), r.path(), r.query(), r.fragment()); + } else if (r.has_path()) { + + // The relative URL path is either an absolute path or a relative + // path. If it is an absolute path, build the URL using only the + // relative path. If it is a relative path, resolve the relative path + // against the base path and build the URL using the resolved path. + + if (is_url_path_absolute(r.path())) { + return url(b.scheme(), b.authority(), r.path(), r.query(), r.fragment()); + } else { + string path = url_path_resolve(b.path(), r.path()); + return url(b.scheme(), b.authority(), path, r.query(), r.fragment()); + } + + } else if (r.has_query()) { + return url(b.scheme(), b.authority(), b.path(), r.query(), r.fragment()); + } else { + // The resolved URL never includes the base URL fragment (i.e., it + // always includes the reference URL fragment). + return url(b.scheme(), b.authority(), b.path(), b.query(), r.fragment()); + } +} + +} // namespace litehtml diff --git a/libs/litehtml/src/url_path.cpp b/libs/litehtml/src/url_path.cpp new file mode 100644 index 0000000000..da8620251f --- /dev/null +++ b/libs/litehtml/src/url_path.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2020-2021 Primate Labs Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the names of the copyright holders nor the names of their +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "url_path.h" + +namespace litehtml { + +bool is_url_path_absolute(const string& path) +{ + return path.length() > 0 && path[0] == '/'; +} + +string url_path_directory_name(const string& path) +{ + size_t offset = path.find_last_of('/'); + if (offset == string::npos) { + return "."; + } else { + return path.substr(0, offset + 1); + } +} + +string url_path_base_name(const string& path) +{ + size_t offset = path.find_last_of('/'); + if (offset == string::npos) { + return path; + } else { + return path.substr(offset + 1); + } +} + +string url_path_append(const string& base, const string& path) +{ + string result(base); + + // Only append a separator if both base and path are not empty and if the + // last character of base is not already a separator. + if (!result.empty() && !path.empty() && result.back() != '/') { + result.append(1, '/'); + } + + result.append(path); + + return result; +} + +string url_path_resolve(const string& base, const string& path) +{ + + // If the possibly relative path is an absolute path then it is not + // relative and the base path is irrelevant. + if (is_url_path_absolute(path)) { + return path; + } + + return url_path_append(url_path_directory_name(base), path); +} + +} // namespace litehtml diff --git a/libs/litehtml/src/utf8_strings.cpp b/libs/litehtml/src/utf8_strings.cpp new file mode 100644 index 0000000000..787af86f42 --- /dev/null +++ b/libs/litehtml/src/utf8_strings.cpp @@ -0,0 +1,99 @@ +#include "html.h" +#include "utf8_strings.h" + + +litehtml::utf8_to_wchar::utf8_to_wchar(const char* val) +{ + m_utf8 = (const byte*) val; + if (!m_utf8) return; + + while (true) + { + ucode_t wch = get_char(); + if (!wch) break; + m_str += wch; + } +} + +litehtml::ucode_t litehtml::utf8_to_wchar::get_char() +{ + ucode_t b1 = getb(); + + if (!b1) + { + return 0; + } + + // Determine whether we are dealing + // with a one-, two-, three-, or four- + // byte sequence. + if ((b1 & 0x80) == 0) + { + // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx + return b1; + } + else if ((b1 & 0xe0) == 0xc0) + { + // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + ucode_t r = (b1 & 0x1f) << 6; + r |= get_next_utf8(getb()); + return r; + } + else if ((b1 & 0xf0) == 0xe0) + { + // 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + ucode_t r = (b1 & 0x0f) << 12; + r |= get_next_utf8(getb()) << 6; + r |= get_next_utf8(getb()); + return r; + } + else if ((b1 & 0xf8) == 0xf0) + { + // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + int b2 = get_next_utf8(getb()); + int b3 = get_next_utf8(getb()); + int b4 = get_next_utf8(getb()); + return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) | + ((b3 & 0x3f) << 6) | (b4 & 0x3f); + } + + //bad start for UTF-8 multi-byte sequence + return '?'; +} + +litehtml::wchar_to_utf8::wchar_to_utf8(const std::wstring& val) +{ + unsigned int code; + for (int i = 0; val[i]; i++) + { + code = val[i]; + if (code <= 0x7F) + { + m_str += (char)code; + } + else if (code <= 0x7FF) + { + m_str += (code >> 6) + 192; + m_str += (code & 63) + 128; + } + else if (0xd800 <= code && code <= 0xdfff) + { + //invalid block of utf8 + } + else if (code <= 0xFFFF) + { + m_str += (code >> 12) + 224; + m_str += ((code >> 6) & 63) + 128; + m_str += (code & 63) + 128; + } + else if (code <= 0x10FFFF) + { + m_str += (code >> 18) + 240; + m_str += ((code >> 12) & 63) + 128; + m_str += ((code >> 6) & 63) + 128; + m_str += (code & 63) + 128; + } + } +} diff --git a/libs/litehtml/src/web_color.cpp b/libs/litehtml/src/web_color.cpp new file mode 100644 index 0000000000..78b201fac0 --- /dev/null +++ b/libs/litehtml/src/web_color.cpp @@ -0,0 +1,274 @@ +#include "html.h" +#include "web_color.h" +#include <cstring> + +const litehtml::web_color litehtml::web_color::transparent = web_color(0, 0, 0, 0); +const litehtml::web_color litehtml::web_color::black = web_color(0, 0, 0, 255); +const litehtml::web_color litehtml::web_color::white = web_color(255, 255, 255, 255); + +litehtml::def_color litehtml::g_def_colors[] = +{ + {"transparent","rgba(0, 0, 0, 0)"}, + {"AliceBlue","#F0F8FF"}, + {"AntiqueWhite","#FAEBD7"}, + {"Aqua","#00FFFF"}, + {"Aquamarine","#7FFFD4"}, + {"Azure","#F0FFFF"}, + {"Beige","#F5F5DC"}, + {"Bisque","#FFE4C4"}, + {"Black","#000000"}, + {"BlanchedAlmond","#FFEBCD"}, + {"Blue","#0000FF"}, + {"BlueViolet","#8A2BE2"}, + {"Brown","#A52A2A"}, + {"BurlyWood","#DEB887"}, + {"CadetBlue","#5F9EA0"}, + {"Chartreuse","#7FFF00"}, + {"Chocolate","#D2691E"}, + {"Coral","#FF7F50"}, + {"CornflowerBlue","#6495ED"}, + {"Cornsilk","#FFF8DC"}, + {"Crimson","#DC143C"}, + {"Cyan","#00FFFF"}, + {"DarkBlue","#00008B"}, + {"DarkCyan","#008B8B"}, + {"DarkGoldenRod","#B8860B"}, + {"DarkGray","#A9A9A9"}, + {"DarkGrey","#A9A9A9"}, + {"DarkGreen","#006400"}, + {"DarkKhaki","#BDB76B"}, + {"DarkMagenta","#8B008B"}, + {"DarkOliveGreen","#556B2F"}, + {"Darkorange","#FF8C00"}, + {"DarkOrchid","#9932CC"}, + {"DarkRed","#8B0000"}, + {"DarkSalmon","#E9967A"}, + {"DarkSeaGreen","#8FBC8F"}, + {"DarkSlateBlue","#483D8B"}, + {"DarkSlateGray","#2F4F4F"}, + {"DarkSlateGrey","#2F4F4F"}, + {"DarkTurquoise","#00CED1"}, + {"DarkViolet","#9400D3"}, + {"DeepPink","#FF1493"}, + {"DeepSkyBlue","#00BFFF"}, + {"DimGray","#696969"}, + {"DimGrey","#696969"}, + {"DodgerBlue","#1E90FF"}, + {"FireBrick","#B22222"}, + {"FloralWhite","#FFFAF0"}, + {"ForestGreen","#228B22"}, + {"Fuchsia","#FF00FF"}, + {"Gainsboro","#DCDCDC"}, + {"GhostWhite","#F8F8FF"}, + {"Gold","#FFD700"}, + {"GoldenRod","#DAA520"}, + {"Gray","#808080"}, + {"Grey","#808080"}, + {"Green","#008000"}, + {"GreenYellow","#ADFF2F"}, + {"HoneyDew","#F0FFF0"}, + {"HotPink","#FF69B4"}, + {"Ivory","#FFFFF0"}, + {"Khaki","#F0E68C"}, + {"Lavender","#E6E6FA"}, + {"LavenderBlush","#FFF0F5"}, + {"LawnGreen","#7CFC00"}, + {"LemonChiffon","#FFFACD"}, + {"LightBlue","#ADD8E6"}, + {"LightCoral","#F08080"}, + {"LightCyan","#E0FFFF"}, + {"LightGoldenRodYellow","#FAFAD2"}, + {"LightGray","#D3D3D3"}, + {"LightGrey","#D3D3D3"}, + {"LightGreen","#90EE90"}, + {"LightPink","#FFB6C1"}, + {"LightSalmon","#FFA07A"}, + {"LightSeaGreen","#20B2AA"}, + {"LightSkyBlue","#87CEFA"}, + {"LightSlateGray","#778899"}, + {"LightSlateGrey","#778899"}, + {"LightSteelBlue","#B0C4DE"}, + {"LightYellow","#FFFFE0"}, + {"Lime","#00FF00"}, + {"LimeGreen","#32CD32"}, + {"Linen","#FAF0E6"}, + {"Magenta","#FF00FF"}, + {"Maroon","#800000"}, + {"MediumAquaMarine","#66CDAA"}, + {"MediumBlue","#0000CD"}, + {"MediumOrchid","#BA55D3"}, + {"MediumPurple","#9370D8"}, + {"MediumSeaGreen","#3CB371"}, + {"MediumSlateBlue","#7B68EE"}, + {"MediumSpringGreen","#00FA9A"}, + {"MediumTurquoise","#48D1CC"}, + {"MediumVioletRed","#C71585"}, + {"MidnightBlue","#191970"}, + {"MintCream","#F5FFFA"}, + {"MistyRose","#FFE4E1"}, + {"Moccasin","#FFE4B5"}, + {"NavajoWhite","#FFDEAD"}, + {"Navy","#000080"}, + {"OldLace","#FDF5E6"}, + {"Olive","#808000"}, + {"OliveDrab","#6B8E23"}, + {"Orange","#FFA500"}, + {"OrangeRed","#FF4500"}, + {"Orchid","#DA70D6"}, + {"PaleGoldenRod","#EEE8AA"}, + {"PaleGreen","#98FB98"}, + {"PaleTurquoise","#AFEEEE"}, + {"PaleVioletRed","#D87093"}, + {"PapayaWhip","#FFEFD5"}, + {"PeachPuff","#FFDAB9"}, + {"Peru","#CD853F"}, + {"Pink","#FFC0CB"}, + {"Plum","#DDA0DD"}, + {"PowderBlue","#B0E0E6"}, + {"Purple","#800080"}, + {"Red","#FF0000"}, + {"RosyBrown","#BC8F8F"}, + {"RoyalBlue","#4169E1"}, + {"SaddleBrown","#8B4513"}, + {"Salmon","#FA8072"}, + {"SandyBrown","#F4A460"}, + {"SeaGreen","#2E8B57"}, + {"SeaShell","#FFF5EE"}, + {"Sienna","#A0522D"}, + {"Silver","#C0C0C0"}, + {"SkyBlue","#87CEEB"}, + {"SlateBlue","#6A5ACD"}, + {"SlateGray","#708090"}, + {"SlateGrey","#708090"}, + {"Snow","#FFFAFA"}, + {"SpringGreen","#00FF7F"}, + {"SteelBlue","#4682B4"}, + {"Tan","#D2B48C"}, + {"Teal","#008080"}, + {"Thistle","#D8BFD8"}, + {"Tomato","#FF6347"}, + {"Turquoise","#40E0D0"}, + {"Violet","#EE82EE"}, + {"Wheat","#F5DEB3"}, + {"White","#FFFFFF"}, + {"WhiteSmoke","#F5F5F5"}, + {"Yellow","#FFFF00"}, + {"YellowGreen","#9ACD32"}, + {nullptr,nullptr} +}; + + +litehtml::web_color litehtml::web_color::from_string(const string& _str, document_container* callback) +{ + auto str = _str.c_str(); + if(!str[0]) + { + return web_color(0, 0, 0); + } + if(str[0] == '#') + { + string red; + string green; + string blue; + if(strlen(str + 1) == 3) + { + red += str[1]; + red += str[1]; + green += str[2]; + green += str[2]; + blue += str[3]; + blue += str[3]; + } else if(strlen(str + 1) == 6) + { + red += str[1]; + red += str[2]; + green += str[3]; + green += str[4]; + blue += str[5]; + blue += str[6]; + } + char* sss = nullptr; + web_color clr; + clr.red = (byte) strtol(red.c_str(), &sss, 16); + clr.green = (byte) strtol(green.c_str(), &sss, 16); + clr.blue = (byte) strtol(blue.c_str(), &sss, 16); + return clr; + } else if(!strncmp(str, "rgb", 3)) + { + string s = str; + + string::size_type pos = s.find_first_of('('); + if(pos != string::npos) + { + s.erase(s.begin(), s.begin() + pos + 1); + } + pos = s.find_last_of(')'); + if(pos != string::npos) + { + s.erase(s.begin() + pos, s.end()); + } + + std::vector<string> tokens; + split_string(s, tokens, ", \t"); + + web_color clr; + + if(tokens.size() >= 1) clr.red = (byte) atoi(tokens[0].c_str()); + if(tokens.size() >= 2) clr.green = (byte) atoi(tokens[1].c_str()); + if(tokens.size() >= 3) clr.blue = (byte) atoi(tokens[2].c_str()); + if(tokens.size() >= 4) clr.alpha = (byte) (t_strtod(tokens[3].c_str(), nullptr) * 255.0); + + return clr; + } else + { + string rgb = resolve_name(str, callback); + if(!rgb.empty()) + { + return from_string(rgb.c_str(), callback); + } + } + return web_color(0, 0, 0); +} + +litehtml::string litehtml::web_color::resolve_name(const string& name, document_container* callback) +{ + for(int i=0; g_def_colors[i].name; i++) + { + if(!t_strcasecmp(name.c_str(), g_def_colors[i].name)) + { + return g_def_colors[i].rgb; + } + } + if (callback) + { + string clr = callback->resolve_color(name); + return clr; + } + return ""; +} + +bool litehtml::web_color::is_color(const string& str, document_container* callback) +{ + if (!t_strncasecmp(str.c_str(), "rgb", 3) || str[0] == '#') + { + return true; + } + if (t_isalpha(str[0]) && resolve_name(str, callback) != "") + { + return true; + } + return false; +} + +litehtml::string litehtml::web_color::to_string() const +{ + char str[9]; + if(alpha) + { + t_snprintf(str, 9, "%02X%02X%02X%02X", red, green, blue, alpha); + } else + { + t_snprintf(str, 9, "%02X%02X%02X", red, green, blue); + } + return str; +} |