├── .gitattributes
├── templates
├── message.twig
├── partials
│ ├── footer.twig
│ ├── header.twig
│ ├── posts-section-partial.twig
│ ├── post-partial.twig
│ ├── image-svg-sprite.twig
│ ├── html-header.twig
│ ├── thumbnail.twig
│ ├── menu.twig
│ └── posts-pagination.twig
├── custom-templates
│ └── example.twig
├── front-page.twig
├── blog.twig
├── page.twig
├── singular.twig
└── base.twig
├── footer.php
├── common_config.json
├── scss
├── _apply.scss
├── base
│ ├── _fontface.scss
│ ├── _scaffolding.scss
│ ├── _base.scss
│ └── _normalize_tweaks.scss
├── abstracts
│ ├── variables
│ │ ├── _colors.scss
│ │ ├── _others.scss
│ │ └── _typography.scss
│ ├── _functions.scss
│ ├── _mixins.scss
│ └── _textcontent-mixins.scss
├── _dependencies.scss
├── components
│ └── example-component
│ │ └── _example-component.scss
├── _vendors.scss
└── style.scss
├── screenshot.png
├── functions
├── plugins
│ ├── plugin.php
│ ├── custom-fields.php
│ └── acf.php
├── frontend-functions.php
├── theme-setup
│ ├── register-menus.php
│ ├── register-sidebars.php
│ ├── register-post-types.php
│ ├── register-taxonomies.php
│ ├── theme-support.php
│ ├── register-thumbnail-sizes.php
│ └── register-scripts.php
├── alter-the-loop
│ └── alter-archive-post-type.php
├── common-variables.php
├── script-data
│ ├── localized-strings.php
│ └── script-data.php
├── timber
│ ├── timber-extend-post.php
│ ├── timber-setup.php
│ ├── timber-extend-site.php
│ └── extend-twig.php
├── admin-hooks.php
└── frontend-hooks.php
├── composer.json
├── template-example.php
├── front-page.php
├── js
├── modules
│ ├── example-module.js
│ └── _utils.js
└── main.js
├── home.php
├── 404.php
├── loco.xml
├── index.php
├── singular.php
├── .jshintrc
├── .gitignore
├── package.json
├── functions.php
├── .stylelintrc.json
├── phpcs.xml
├── composer.lock
├── README.md
├── gulpfile.js
└── style.css
/.gitattributes:
--------------------------------------------------------------------------------
1 | style.css binary
2 | *.min.js
3 |
--------------------------------------------------------------------------------
/templates/message.twig:
--------------------------------------------------------------------------------
1 | {% extends "base.twig" %}
--------------------------------------------------------------------------------
/templates/partials/footer.twig:
--------------------------------------------------------------------------------
1 | © {{ "now"|date("Y") }}
--------------------------------------------------------------------------------
/footer.php:
--------------------------------------------------------------------------------
1 | __( 'Menu in the header', 'theme_domain' ),
9 | ]
10 | );
11 |
--------------------------------------------------------------------------------
/scss/abstracts/variables/_colors.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable color-no-hex */
2 | $color-pomegranate: #ee2d29;
3 | $color-concrete: #f3f3f3;
4 |
5 | $color-accent: $color-pomegranate;
6 |
7 | $color-link: $color-accent;
8 | $color-bg: white;
9 |
--------------------------------------------------------------------------------
/functions/theme-setup/register-sidebars.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ __('Skip to content', 'theme_domain') }}
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/template-example.php:
--------------------------------------------------------------------------------
1 |
6 |
7 | {% block content_area_inner_content '' %}
8 |
9 |
10 |
11 | {% endblock %}
--------------------------------------------------------------------------------
/scss/components/example-component/_example-component.scss:
--------------------------------------------------------------------------------
1 | // @z-index space: 80-90
2 | @mixin c-example-component($base:&) {
3 |
4 | & {
5 | }
6 |
7 | @at-root {
8 | #{$base}_modifier {
9 | }
10 | #{$base}__element {
11 | }
12 | #{$base}__element_modifier {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/functions/alter-the-loop/alter-archive-post-type.php:
--------------------------------------------------------------------------------
1 | .php
5 | * and add a require statement in the functions.php to include them
6 | */
7 |
8 |
--------------------------------------------------------------------------------
/front-page.php:
--------------------------------------------------------------------------------
1 |
4 |
6 |
7 |
8 | {% for post in posts %}
9 | {% include 'partials/post-partial.twig' with {'post':post} %}
10 | {% endfor %}
11 |
12 |
13 |
14 |
15 | {% endif %}
--------------------------------------------------------------------------------
/scss/abstracts/_functions.scss:
--------------------------------------------------------------------------------
1 | // replace sass-rem function with a dummy function in local environments
2 | // this allows us to have pixels in browsers on local instead of rems for easier testing
3 | @function rem-calc($val) {
4 | @if $_is-env-dev == true {
5 | @return $val;
6 | } @else {
7 | @return rem($val);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/functions/common-variables.php:
--------------------------------------------------------------------------------
1 | __( 'Load more', 'theme_domain' ),
10 | ];
11 | return $localized_strings;
12 | }
13 |
--------------------------------------------------------------------------------
/templates/partials/post-partial.twig:
--------------------------------------------------------------------------------
1 | {% if post %}
2 |
3 |
4 | {% include 'partials/thumbnail.twig' with {'post': post, 'size':'third_high', 'classes': 'thumbnail-class'} %}
5 |
6 |
7 | {{ post.title }}
8 | {{ post.post_excerpt|e('wp_kses_post') }}
9 |
10 |
11 |
12 | {% endif %}
--------------------------------------------------------------------------------
/js/modules/example-module.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // import common_config from '../../common_config.json';
3 |
4 | /**
5 | * Example module
6 | */
7 | export const example_module = () => {
8 |
9 | // !Set vars
10 |
11 |
12 |
13 |
14 | // !Append HTML
15 |
16 |
17 |
18 |
19 | // !Events
20 |
21 |
22 |
23 |
24 | // !Functions
25 |
26 |
27 |
28 | };
29 |
--------------------------------------------------------------------------------
/scss/_vendors.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable plugin/at-rule-import-path */
2 |
3 | // CSS and Javascript dependencies
4 | // Thanks to sass-module-importer gulp plugin we can import css files from node_modules without renaming like this: "@import 'fullpage.js/dist/jquery.fullpage.min.css';"
5 | @import '~normalize.css/normalize.css';
6 |
7 | /* stylelint-enable plugin/at-rule-import-path */
8 |
--------------------------------------------------------------------------------
/home.php:
--------------------------------------------------------------------------------
1 | ', '' );
9 | Timber::render( 'message.twig', $context );
10 |
--------------------------------------------------------------------------------
/loco.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | .
7 |
8 |
9 | languages
10 |
11 |
12 | languages/theme_domain.pot
13 |
14 |
15 |
16 |
17 | node_modules
18 |
19 |
20 |
--------------------------------------------------------------------------------
/templates/partials/image-svg-sprite.twig:
--------------------------------------------------------------------------------
1 | {% if id %}
2 |
3 | {% set svg_classes = [ 'u-svg-' ~ id ~ '-size' ] %}
4 | {% if classes is iterable %}
5 | {% set svg_classes = svg_classes|merge(classes) %}
6 | {% endif %}
7 |
8 |
12 | {% endif %}
--------------------------------------------------------------------------------
/functions/script-data/script-data.php:
--------------------------------------------------------------------------------
1 | admin_url( 'admin-ajax.php' ),
10 | // 'svg_icon' => Timber::compile_string( "{% include 'partials/image-svg-sprite.twig' with {'id': 'icon_id', 'classes': ['c-icon'], 'theme_link': theme_link} %}", [ 'theme_link' => get_template_directory_uri() ] ),
11 | ];
12 | return $script_data;
13 | }
14 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {# #}
8 |
9 |
10 | {{ fn('wp_head') }}
11 |
--------------------------------------------------------------------------------
/functions/timber/timber-extend-post.php:
--------------------------------------------------------------------------------
1 |
12 |
13 | Timber not activated. Make sure you activate the plugin in ' . esc_url( admin_url( 'plugins.php' ) ) . '
14 |
15 |
16 | ';
17 | }
18 | );
19 |
20 | return;
21 | }
22 |
23 | Timber::$dirname = ['templates', 'img'];
24 |
--------------------------------------------------------------------------------
/functions/theme-setup/theme-support.php:
--------------------------------------------------------------------------------
1 | ID ) ) {
11 | Timber::render( 'single-password.twig', $context );
12 | } elseif ( get_post_type( $timber_post ) === 'page' ) {
13 | Timber::render( ['page.twig', 'singular.twig'], $context );
14 | } else {
15 | Timber::render( ['single-' . $timber_post->ID . '.twig', 'single-' . $timber_post->post_type . '.twig', 'single.twig', 'singular.twig'], $context );
16 | }
17 |
--------------------------------------------------------------------------------
/functions/admin-hooks.php:
--------------------------------------------------------------------------------
1 | remove_section( 'colors' );
14 | $wp_customize->remove_section( 'custom_css' );
15 | // $wp_customize->remove_section( 'static_front_page' );
16 | }
17 |
18 | add_action( 'customize_register', 'themeprefix_edit_customizer' );
19 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6,
3 | "bitwise" : true,
4 | "laxcomma" : true,
5 | "curly" : true,
6 | "debug" : true,
7 | "eqeqeq" : true,
8 | "immed" : true,
9 | "indent" : 2,
10 | "latedef" : "nofunc",
11 | "newcap" : true,
12 | "noarg" : true,
13 | "quotmark" : true,
14 | "undef" : true,
15 | "unused" : false,
16 | "strict" : true,
17 | "trailing" : true,
18 | "smarttabs": true,
19 | "expr" : true,
20 | "validthis": true,
21 |
22 | // Environments:
23 | "browser" : true,
24 | "node" : true,
25 |
26 | // Globals:
27 | "predef" : [
28 | "ga",
29 | "ajaxurl",
30 | "localized_strings",
31 | "script_data",
32 | "Modernizr"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/functions/theme-setup/register-thumbnail-sizes.php:
--------------------------------------------------------------------------------
1 | cover_width, $common_config->cover_height, true );
8 |
9 | // These standard sizes are only for end user usage in rich content area
10 | // Their height should be kept unlimited to prevent incorrect resize that changes image width
11 | update_option( 'thumbnail_size_w', 200 );
12 | update_option( 'thumbnail_crop', '0' );
13 | update_option( 'medium_size_w', 510 );
14 | update_option( 'large_size_w', 1050 );
15 |
16 | $content_sizes = ['thumbnail', 'medium', 'large'];
17 | foreach ( $content_sizes as $content_size ) {
18 | update_option( $content_size . '_size_h', 0 );
19 | }
20 |
--------------------------------------------------------------------------------
/scss/base/_normalize_tweaks.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-universal, selector-max-type */
2 | // Tweaks for Normalize 3.0
3 | h1, h2, h3, h4, h5, h6, p, dl, dd, ul, ol, li, figure {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | h1, h2, h3, h4, h5, h6 {
9 | font-weight: normal;
10 | font-size: 100%;
11 | }
12 |
13 | ul {
14 | list-style: none;
15 | }
16 |
17 | html {
18 | box-sizing: border-box;
19 | }
20 |
21 | *, *::before, *::after {
22 | box-sizing: inherit;
23 | }
24 |
25 | ol, ul {
26 | list-style-position: inside;
27 | }
28 |
29 | textarea {
30 | max-width: 100%;
31 | resize: vertical;
32 | }
33 |
34 | fieldset {
35 | border: none;
36 | margin: 0;
37 | padding: 0;
38 | }
39 |
40 | select {
41 | color: black;
42 | }
43 |
44 | iframe {
45 | border: none;
46 | }
47 |
--------------------------------------------------------------------------------
/scss/abstracts/variables/_others.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable meowtec/no-px */
2 |
3 | // Proportions
4 | $unit-x: rem-calc(10px);
5 | $unit-y: $unit-x;
6 |
7 | // Widths
8 |
9 | //Thumbnail sizes — same as wp registered sizes unless noted otherwise
10 | // $third-low-height:300px;
11 |
12 | // Visual effects
13 |
14 | // Transitions & animations
15 | // note that property is omitted
16 | // $transition-main:ease-out .4s;
17 |
18 | // Excluded selectors (only simple selectors)
19 | // use @include t-focused with arguments to set your own styling when element is focused
20 | $classes-exclude-from-focus: (
21 | 'c-selector-1'
22 | 'c-selector-2'
23 | );
24 |
25 |
26 | // Breakpoints
27 | // usage: @include mq($from: xlarge) {}
28 | $mq-breakpoints: (
29 | small: 380px,
30 | medium: 768px,
31 | large: 1024px,
32 | xlarge: 1280px,
33 | );
34 |
35 | /* stylelint-enable meowtec/no-px */
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore assets auto generated by gulp
2 | # do not ignore style.css file to allow for wp-cli style automatic installation
3 | /js/libs/
4 | /js/scripts.min.js
5 | /js/modernizr.js
6 | /js/modernizr.min.js
7 | /img/sprite.svg
8 | /scss/autogenerated/svg-sprite.css
9 |
10 | /functions/dev-functions.php
11 |
12 | # ignore all files starting with . or ~
13 | .*
14 | ~*
15 |
16 | # ignore dependency directories
17 | node_modules/
18 | vendor/
19 |
20 | # ignore OS generated files
21 | ehthumbs.db
22 | Thumbs.db
23 |
24 | # ignore Editor files
25 | *.sublime-project
26 | *.sublime-workspace
27 | *.komodoproject
28 | *-favs.json
29 | /.vscode
30 |
31 | # ignore log files
32 | *.log
33 |
34 | # ignore i18n files
35 | *.mo
36 |
37 | # -------------------------
38 | # BEGIN Whitelisted Files
39 | # -------------------------
40 |
41 | # track these files, if they exist
42 | !.gitignore
43 | !.editorconfig
44 | !.jshintrc
45 | !.sass-lint.yml
46 | !.stylelintrc.json
47 | !.gitattributes
48 |
--------------------------------------------------------------------------------
/templates/partials/thumbnail.twig:
--------------------------------------------------------------------------------
1 | {% if post %}
2 |
3 | {% if post.thumbnail %}
4 | {% set thumbnail = post.thumbnail %}
5 | {% endif %}
6 | {% if post.object_type == 'image' %}
7 | {% set thumbnail = post %}
8 | {% endif %}
9 |
10 | {% if thumbnail %}
11 |
12 | {% if classes %}
13 |
14 | {% set thumb_classes = [] %}
15 | {% if classes is iterable %}
16 | {% set thumb_classes = thumb_classes|merge(classes) %}
17 | {% else %}
18 | {% set thumb_classes = [classes] %}
19 | {% endif %}
20 |
21 | {% endif %}
22 |
23 | {% set thumb_attributes = {} %}
24 | {% if thumb_classes %}
25 | {% set thumb_attributes = {'class': thumb_classes|join(' ')} %}
26 | {% endif %}
27 | {% if attributes %}
28 | {% set thumb_attributes = thumb_attributes|merge(attributes) %}
29 | {% endif %}
30 |
31 | {{ fn('wp_get_attachment_image', thumbnail.id, size, false, thumb_attributes ) }}
32 |
33 | {% endif %}
34 | {% endif %}
35 |
--------------------------------------------------------------------------------
/scss/style.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme Name: Timber Boilerplate Theme
3 | Theme URI: https://github.com/certainlyakey/timber-boilerplate
4 | Description: This is a boilerplate theme using Timber
5 | Version: 1.0
6 | Author: Aleksandr Beliaev
7 | Text Domain: theme_domain
8 | Domain Path: /languages/
9 | */
10 |
11 | // !Dependencies
12 | @import 'dependencies';
13 | @import 'vendors';
14 |
15 | // !Site abstracts
16 | @import 'abstracts/functions';
17 | @import 'abstracts/variables/colors';
18 | @import 'abstracts/variables/typography';
19 | @import 'abstracts/variables/others';
20 | @import 'abstracts/mixins';
21 | // @import 'abstracts/animations';
22 | @import 'abstracts/textcontent-mixins';
23 |
24 | // !Base
25 | @import 'base/fontface';
26 | @import 'base/normalize_tweaks';
27 | @import 'base/base';
28 | @import 'base/scaffolding';
29 |
30 | // !Generated
31 | // @import 'autogenerated/svg-sprite';
32 |
33 | // !Components
34 | @import 'components/example-component/example-component';
35 |
36 | // Apply the components to corresponding component classes
37 | @import 'apply';
38 |
--------------------------------------------------------------------------------
/scss/abstracts/variables/_typography.scss:
--------------------------------------------------------------------------------
1 | $ff-body: 'Helvetica Neue', Helvetica, Arial, sans-serif;
2 |
3 |
4 | $font-size-base: rem-calc(16px);
5 |
6 | // A map containing the basic typography for all the site
7 | // The 2nd level of the map (body and heading) corresponds to the main typefaces.
8 | // The 3rd level of the map corresponds to font property combinations that frequently go together. Any arbitrary word goes as a group name. The properties are usually font-size and line-height but can be also any other. Please avoid including color and other non typography properties here, though.
9 | // Usage: @include u-set-typography($typeface, $style-name);
10 |
11 | /* stylelint-disable indentation */
12 | $font-styles: (
13 |
14 | 'body': ( // aka Helvetica Neue
15 |
16 | 'regular': (
17 | font-size: $font-size-base,
18 | line-height: 1.6
19 | ),
20 | ),
21 |
22 | // 'heading': ( // aka heading font
23 |
24 | // 'section-title': (
25 | // font-size:16px,
26 | // line-height:1
27 | // ),
28 | // )
29 |
30 | );
31 |
32 | /* stylelint-enable indentation */
33 |
--------------------------------------------------------------------------------
/templates/base.twig:
--------------------------------------------------------------------------------
1 | {% block head %}
2 |
3 | {% include 'partials/html-header.twig' %}
4 | {% block head_append '' %}
5 |
6 |
7 | {% endblock %}
8 |
9 |
10 | {% include 'sprite.svg' ignore missing %}
11 |
12 |
13 |
14 | {% block header %}
15 | {% include 'partials/header.twig' %}
16 | {% endblock %}
17 |
18 |
19 |
20 | {% block content_area_prepend '' %}
21 |
22 | {% block content_area_inner %}
23 | {{ __('Sorry, no content', 'theme_domain') }}
24 | {% endblock %}
25 |
26 | {% block content_area_append '' %}
27 |
28 |
29 |
30 |
31 | {# a block ready to be filled with some default content (but blank for now) #}
32 | {% block footer_before '' %}
33 |
34 | {% block footer %}
35 |
38 | {% endblock %}
39 |
40 | {% block footer_after '' %}
41 |
42 | {{ function('wp_footer') }}
43 |
44 |
45 |
--------------------------------------------------------------------------------
/functions/theme-setup/register-scripts.php:
--------------------------------------------------------------------------------
1 | \n';
30 | }
31 |
32 | return $tag;
33 | }
34 |
35 | add_filter( 'script_loader_tag', 'themeprefix_defer_scripts', 10, 3 );
36 |
--------------------------------------------------------------------------------
/functions/plugins/custom-fields.php:
--------------------------------------------------------------------------------
1 | $v ) {
9 | $classes[ $k ] = 'p-' . $v;
10 | }
11 | }
12 | return $classes;
13 | }
14 |
15 | add_filter( 'body_class', 'themeprefix_add_namespaced_body_classes' );
16 |
17 |
18 |
19 | function themeprefix_add_slug_to_body_class( $classes ) {
20 | global $post;
21 |
22 | if ( is_singular() ) {
23 | $classes[] = sanitize_html_class( $post->post_name );
24 | };
25 |
26 | return $classes;
27 | }
28 |
29 | add_filter( 'body_class', 'themeprefix_add_slug_to_body_class' );
30 |
31 |
32 |
33 | // Remove WP emoji code
34 | remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
35 | remove_action( 'wp_print_styles', 'print_emoji_styles' );
36 |
37 | remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
38 | remove_action( 'admin_print_styles', 'print_emoji_styles' );
39 |
40 |
41 |
42 | // Remove Gutenberg default styles
43 | function themeprefix_remove_wp_block_library_css() {
44 | wp_dequeue_style( 'wp-block-library' );
45 | wp_dequeue_style( 'wp-block-library-theme' );
46 | }
47 |
48 | add_action( 'wp_enqueue_scripts', 'themeprefix_remove_wp_block_library_css', 100 );
49 |
--------------------------------------------------------------------------------
/functions/timber/extend-twig.php:
--------------------------------------------------------------------------------
1 | addFilter( new Twig_SimpleFilter( 'merge_recursive', 'themeprefix_array_merge_recursive' ) );
9 | $twig->addFilter( new Twig_SimpleFilter( 'slugify', 'themeprefix_string_slugify' ) );
10 | return $twig;
11 | }
12 |
13 | add_filter( 'timber/twig', 'themeprefix_add_to_twig' );
14 |
15 |
16 |
17 | function themeprefix_array_merge_recursive( $arr1, $arr2 ) {
18 | if ( $arr1 instanceof Traversable ) {
19 | $arr1 = iterator_to_array( $arr1 );
20 | } elseif ( !is_array( $arr1 ) ) {
21 | throw new Twig_Error_Runtime( sprintf( 'The merge_recursive filter only works with arrays or "Traversable", got "%s" as first argument.', gettype( $arr1 ) ) );
22 | }
23 | if ( $arr2 instanceof Traversable ) {
24 | $arr2 = iterator_to_array( $arr2 );
25 | } elseif ( !is_array( $arr2 ) ) {
26 | throw new Twig_Error_Runtime( sprintf( 'The merge_recursive filter only works with arrays or "Traversable", got "%s" as second argument.', gettype( $arr2 ) ) );
27 | }
28 | return array_replace_recursive( $arr1, $arr2 );
29 | }
30 |
31 |
32 |
33 | function themeprefix_string_slugify( $str ) {
34 | if ( gettype( $str ) === 'string' ) {
35 | $result = strtolower( str_replace( ' ', '-', $str ) );
36 | } else {
37 | throw new Twig_Error_Runtime( sprintf( 'The slugify filter only works with strings, got "%s" as first argument.', gettype( $str ) ) );
38 | }
39 | return $result;
40 | }
41 |
--------------------------------------------------------------------------------
/functions/plugins/acf.php:
--------------------------------------------------------------------------------
1 | __( 'Site Settings', 'theme_domain' ),
14 | 'menu_slug' => 'site-settings',
15 | 'capability' => 'edit_posts',
16 | 'redirect' => false,
17 | ]
18 | );
19 |
20 | }
21 | }
22 |
23 | add_action( 'acf/init', 'themeprefix_add_options_pages' );
24 |
25 |
26 |
27 | function themeprefix_acf_global_settings_context( $context ) {
28 |
29 | // make ACF options page fields available in every Twig file
30 | $context['options'] = get_fields( 'option' );
31 |
32 | return $context;
33 | }
34 |
35 | add_filter( 'timber_context', 'themeprefix_acf_global_settings_context' );
36 |
37 |
38 |
39 | // Wraps field definitions in __() function when exporting to PHP via ACF admin UI
40 | function themeprefix_acf_localize_fields_when_exporting() {
41 | acf_update_setting( 'l10n_textdomain', 'theme_domain' );
42 | }
43 |
44 | add_action( 'acf/init', 'themeprefix_acf_localize_fields_when_exporting' );
45 |
46 |
47 |
48 | // Disable "Custom fields" menu in admin
49 | // You need to load environment to WP in order for this to work
50 | // Eg. by adding autoload.php from a site' vendor folder to wp-config.php
51 | add_filter(
52 | 'acf/settings/show_admin',
53 | function() {
54 | return getenv( 'ENV' ) === 'dev' ? true : false;
55 | }
56 | );
57 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "timber-theme",
3 | "version": "2.0.0",
4 | "dependencies": {
5 | "@babel/core": "^7.13.14",
6 | "@babel/preset-env": "^7.13.12",
7 | "autoprefixer": "^9.8.6",
8 | "babelify": "^10.0.0",
9 | "browserify": "^16.5.2",
10 | "common-sass-utilities": "1.0.2",
11 | "cssnano": "^4.0.0",
12 | "dotenv": "^8.0.0",
13 | "gulp": "^4.0.0",
14 | "gulp-concat": "^2.6.0",
15 | "gulp-gettext": "^0.3.0",
16 | "gulp-jshint": "^2.0.0",
17 | "gulp-modernizr": "^3.0.0",
18 | "gulp-notify": "^2.2.0",
19 | "gulp-postcss": "^7.0.0",
20 | "gulp-sass": "^4.0.0",
21 | "gulp-sass-variables": "^1.1.0",
22 | "gulp-sourcemaps": "^2.6.5",
23 | "gulp-stylelint": "^9.0.0",
24 | "gulp-svg-sprite": "^1.5.0",
25 | "gulp-uglify": "^3.0.0",
26 | "gulp-util": "^3.0.7",
27 | "jshint": "^2.12.0",
28 | "jshint-stylish": "^2.0.1",
29 | "node-sass-css-importer": "github:certainlyakey/node-sass-css-importer",
30 | "node-sass-package-importer": "^5.3.2",
31 | "normalize.css": "^8.0.1",
32 | "postcss": "^7.0.35",
33 | "sass-module-importer": "^1.4.0",
34 | "sass-mq": "^5.0.1",
35 | "sass-rem": "^2.0.0",
36 | "stylelint-at-rule-import-path": "github:certainlyakey/stylelint-at-rule-import-path",
37 | "stylelint-config-recommended-scss": "^3.0.0",
38 | "stylelint-no-px": "^0.12.1",
39 | "stylelint-scss": "^3.19.0",
40 | "vinyl-buffer": "^1.0.0",
41 | "vinyl-source-stream": "^2.0.0"
42 | },
43 | "devDependencies": {
44 | "browser-sync": "^2.26.14",
45 | "gulp-phpcs": "^3.1.0"
46 | },
47 | "browserslist": [
48 | "last 3 versions",
49 | "not ie < 11"
50 | ],
51 | "scripts": {
52 | "build_css": "gulp build_css",
53 | "build": "gulp build --env=prod",
54 | "watch": "gulp watch",
55 | "default": "gulp"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/js/modules/_utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Common utility functions
5 | */
6 | export const isIE = () => {
7 | var isIE = /*@cc_on!@*/false || !!document.documentMode;
8 | return isIE;
9 | };
10 |
11 |
12 | export const isEdge = () => {
13 | // Edge 20+
14 | var isEdge = !isIE() && !!window.StyleMedia;
15 | return isEdge;
16 | };
17 |
18 |
19 | export const isChrome = () => {
20 | var isChrome = !!window.chrome;
21 | return isChrome;
22 | };
23 |
24 |
25 | export const isSafari = () => {
26 | var isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
27 | return isSafari;
28 | };
29 |
30 |
31 | export const isiOSSafari = () => {
32 | var isiOS = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i);
33 | var isWebkit = !!navigator.userAgent.match(/WebKit/i);
34 | return isiOS && isWebkit;
35 | };
36 |
37 |
38 | export const addBrowserClasses = () => {
39 |
40 | // adds classes to IE and Edge
41 | if (isIE()) {
42 | document.documentElement.classList.add('js-browser-ie');
43 | }
44 | if (isEdge()) {
45 | document.documentElement.classList.add('js-browser-edge');
46 | }
47 |
48 |
49 |
50 | // adds class to Chrome
51 | if (isChrome()) {
52 | document.documentElement.classList.add('js-browser-chrome');
53 | }
54 |
55 |
56 |
57 | // adds class to Safari
58 | if (isSafari()) {
59 | document.documentElement.classList.add('js-browser-safari');
60 | }
61 |
62 |
63 |
64 | // adds class to iOS Safari
65 | if (isiOSSafari()) {
66 | document.documentElement.classList.add('js-browser-ios-safari');
67 | }
68 |
69 | };
70 |
71 |
72 | export const debounce = (func, ms) => {
73 | let timeout;
74 | return () => {
75 | clearTimeout(timeout);
76 | timeout = setTimeout(() => {
77 | timeout = null;
78 | func();
79 | }, ms);
80 | };
81 | };
82 |
--------------------------------------------------------------------------------
/scss/abstracts/_textcontent-mixins.scss:
--------------------------------------------------------------------------------
1 | // pure appearance (typographic/cosmetic) styles
2 | // please keep here only those mixins that are related to single post styling
3 |
4 | @mixin t-textcontent {
5 | /* stylelint-disable selector-max-type, selector-max-compound-selectors */
6 |
7 | // preventing text styles leaking into widgets pasted into content area via shortcodes
8 | & > {
9 | blockquote {
10 | font-style: italic;
11 | }
12 | // h2 {
13 | // @include t-heading-xxxl;
14 | // }
15 | // h3 {
16 | // @include t-heading-xxl;
17 | // }
18 | // h4 {
19 | // @include t-heading-xl;
20 | // }
21 | // h5 {
22 | // @include t-heading-l;
23 | // }
24 | // h6 {
25 | // @include t-heading-m;
26 | // }
27 | p, ul, ol {
28 | &:not(:only-child) {
29 | @include u-spacing-y($unit-y, 'margin');
30 | }
31 | }
32 | h2, h3, h4, h5, h6, p, ul, ol {
33 | &:first-child {
34 | margin-top: 0;
35 | }
36 | &:last-child {
37 | margin-bottom: 0;
38 | }
39 | }
40 | ul li {
41 | list-style-type: disc;
42 | }
43 | ul, ol {
44 | li li {
45 | padding-left: $unit-x * 2;
46 | }
47 | }
48 | }
49 | img {
50 | display:block;
51 | @include mq($until: large) {
52 | @include u-image-autowidth;
53 | }
54 | }
55 | iframe {
56 | width: 100%;
57 | }
58 |
59 | /* stylelint-enable selector-max-type, selector-max-compound-selectors */
60 | }
61 |
62 |
63 | // ~ heading level 2
64 | // @mixin t-heading-xxxl {
65 | // @include u-set-typography('body', 'big-heading');
66 | // }
67 |
68 |
69 | // ~ heading level 3
70 | // @mixin t-heading-xxl {
71 | // }
72 |
73 |
74 | // // ~ heading level 4
75 | // @mixin t-heading-xl {
76 | // }
77 |
78 |
79 | // // ~ heading level 5
80 | // @mixin t-heading-l {
81 | // }
82 |
83 |
84 | // // ~ heading level 6
85 | // @mixin t-heading-m {
86 | // }
87 |
--------------------------------------------------------------------------------
/templates/partials/menu.twig:
--------------------------------------------------------------------------------
1 | {#
2 | Item classes legend:
3 | __item — all items
4 | __subitem — all items on 2nd and deeper levels
5 | __level-x-item -- all items on specific level
6 | #}
7 |
8 | {% if menu %}
9 | {% spaceless %}
10 | {% set listclass = [] %}
11 | {% if is_submenu is defined and is_submenu == true %}
12 | {% set listclass = listclass|merge([ baseclass ~ '__submenu' ]) %}
13 | {% set first_subitem = menu|first %}
14 | {% set listclass = listclass|merge([ baseclass ~ '__menu_level-' ~ (first_subitem.level + 1) ]) %}
15 | {% else %}
16 | {% set listclass = listclass|merge([ baseclass ~ '__list', baseclass ~ '__menu_level-1' ]) %}
17 | {% endif %}
18 |
19 |
20 | {% for item in menu %}
21 | {# {% set itemclasses = item.classes %} #}
22 | {% set itemclasses = [] %}
23 | {% if is_submenu is defined and is_submenu == true %}
24 | {% set itemclasses = itemclasses|merge([ baseclass ~ '__item', baseclass ~ '__subitem', baseclass ~ '__item_level-' ~ (item.level + 1) ]) %}
25 | {% else %}
26 | {% set itemclasses = itemclasses|merge([ baseclass ~ '__item', baseclass ~ '__item_level-1' ]) %}
27 | {% endif %}
28 | {% if item.current %}
29 | {% set itemclasses = itemclasses|merge([ baseclass ~ '__item_current' ]) %}
30 | {% endif %}
31 | {% if item.current_item_parent %}
32 | {% set itemclasses = itemclasses|merge([ baseclass ~ '__item_current-parent' ]) %}
33 | {% endif %}
34 | {% if item.get_children %}
35 | {% set itemclasses = itemclasses|merge([ baseclass ~ '__item_has-submenu' ]) %}
36 | {% endif %}
37 | -
38 | {{item.title}}
39 | {% include 'partials/menu.twig' with {'menu':item.get_children, is_submenu:true } %}
40 |
41 | {% endfor %}
42 |
43 | {% endspaceless %}
44 | {% endif %}
--------------------------------------------------------------------------------
/functions.php:
--------------------------------------------------------------------------------
1 |
10 |
11 | {% if before_after and pagination.prev %}
12 | {# A workaround for Loco Translate to be able to scan strings that are located inside HTML attributes #}
13 | {% set prev_label = __('Go to previous page', 'theme_domain') %}
14 |
15 | {% endif %}
16 |
17 | {% if numbered %}
18 |
19 | {% for page in pagination.pages %}
20 |
21 | {% if page.link %}
22 | {# use page.class to assign Wordpress classes #}
23 | {% set page_label = __('Page', 'theme_domain') ~ ' ' ~ page.title %}
24 |
25 | {% endif %}
26 |
27 | {% if page.current %}
28 | {% set current_label = __('Current page', 'theme_domain') ~ ', ' ~ __('page', 'theme_domain') ~ ' ' ~ page.title %}
29 |
30 | {% endif %}
31 |
32 | {% if page.class == 'dots' %}
33 |
34 | {% endif %}
35 |
36 | {% endfor %}
37 |
38 | {% endif %}
39 |
40 | {% if before_after and pagination.next %}
41 | {% set next_label = __('Go to next page', 'theme_domain') %}
42 |
43 | {% endif %}
44 |
45 |
46 | {% endspaceless %}
47 |
48 | {% endif %}
--------------------------------------------------------------------------------
/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "stylelint-config-recommended-scss",
3 | "plugins": [
4 | "stylelint-scss",
5 | "stylelint-no-px",
6 | "stylelint-at-rule-import-path"
7 | ],
8 | "rules": {
9 | "block-no-empty": null,
10 | "comment-word-blacklist": [["/\\s?todo\\s/i", "/\\s?hack\\s/i"], {"severity": "warning", "message":"A todo or hack comment was found. Consider resolving the issue in future"}],
11 | "selector-class-pattern": ["^((c-|u-|s-|no-|has-|state-|is-|js-|size-)[a-z]+|js)", {"resolveNestedSelectors":true, "message":"Please use namespacing (prefixes) when naming classes. See https://gist.github.com/stephenway/a6145d9b4430e8c55a77 for the namespaces this project uses."}],
12 | "rule-empty-line-before": null,
13 | "string-no-newline": null,
14 | "color-no-hex": [true, {"severity": "warning", "message":"Consider creating a variable if this color repeats more than once"}],
15 | "no-duplicate-selectors": [true, {"severity": "warning"}],
16 | "declaration-property-unit-whitelist": {"line-height": ["em"]},
17 | "value-no-vendor-prefix": true,
18 | "property-no-vendor-prefix": true,
19 | "declaration-no-important": true,
20 | "declaration-block-single-line-max-declarations": 1,
21 | "selector-max-attribute": [0, {"severity": "warning", "message":"Avoid using attribute selectors, add classes to markup instead and utilise them. Use stylelint ignore rules if they are absolutely needed"}],
22 | "selector-max-class": 3,
23 | "selector-max-compound-selectors": 3,
24 | "selector-max-id": 0,
25 | "selector-max-specificity": "0,3,2",
26 | "selector-max-type": [0, {"severity": "warning", "message":"Try to avoid using type selectors as they make styling components more dependent on specific markup and might cause specificity conflicts. Add classes to markup instead and utilise them. Use stylelint ignore rules when needed", "ignoreTypes": ["a", "/--/"]}],
27 | "selector-max-universal": [0, {"severity": "warning"}],
28 | "no-descending-specificity": [true, {"severity": "warning"}],
29 | "selector-no-qualifying-type": true,
30 | "selector-no-vendor-prefix": [true, {"severity": "warning", "message":"Do not use vendor-prefixed selectors. Autoprefixer will take care of them"}],
31 | "at-rule-no-vendor-prefix": [true, {"severity": "warning", "message":"Do not use vendor-prefixed at-rules. Autoprefixer will take care of them"}],
32 | "media-feature-name-no-vendor-prefix": [true, {"severity": "warning", "message":"Do not use vendor-prefixed media features. Autoprefixer will take care of them"}],
33 | "at-rule-blacklist": ["extend", {"severity": "warning", "message":"Avoid using @extends as they degrade clarity of code and can cause hard-to-track bugs. Utilise mixins instead"}],
34 | "font-family-name-quotes":"always-where-recommended",
35 | "string-quotes":"single",
36 | "length-zero-no-unit":true,
37 | "selector-combinator-space-before": "always",
38 | "selector-combinator-space-after": "always",
39 | "selector-pseudo-element-colon-notation": "double",
40 | "indentation": 2,
41 | "max-empty-lines": [4, {"severity": "warning"}],
42 | "scss/at-mixin-pattern": ["^(c-|u-|t-|o-).+", {"severity": "error", "message":"Please use namespacing (prefixes) when naming mixins. See https://gist.github.com/stephenway/a6145d9b4430e8c55a77 for the namespaces this project uses."}],
43 | "scss/at-rule-no-unknown": null,
44 | "plugin/at-rule-import-path": true,
45 | "meowtec/no-px": [true, { "ignore": ["1px"], "ignoreFunctions" : ["rem-calc"], "message":"Use rem unit or rem-calc() function instead of px" }]
46 | },
47 | "ignoreFiles": "scss/autogenerated/*.scss"
48 | }
49 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 | vendor/*
21 | node_modules/*
22 |
23 |
26 |
27 | warning
28 |
29 |
30 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
52 |
53 |
54 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "a230f6a551103b04e9b78bfe8296ec3e",
8 | "packages": [
9 | {
10 | "name": "squizlabs/php_codesniffer",
11 | "version": "3.5.5",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
15 | "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
20 | "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-simplexml": "*",
25 | "ext-tokenizer": "*",
26 | "ext-xmlwriter": "*",
27 | "php": ">=5.4.0"
28 | },
29 | "require-dev": {
30 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
31 | },
32 | "bin": [
33 | "bin/phpcs",
34 | "bin/phpcbf"
35 | ],
36 | "type": "library",
37 | "extra": {
38 | "branch-alias": {
39 | "dev-master": "3.x-dev"
40 | }
41 | },
42 | "notification-url": "https://packagist.org/downloads/",
43 | "license": [
44 | "BSD-3-Clause"
45 | ],
46 | "authors": [
47 | {
48 | "name": "Greg Sherwood",
49 | "role": "lead"
50 | }
51 | ],
52 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
53 | "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
54 | "keywords": [
55 | "phpcs",
56 | "standards"
57 | ],
58 | "time": "2020-04-17T01:09:41+00:00"
59 | },
60 | {
61 | "name": "wp-coding-standards/wpcs",
62 | "version": "2.3.0",
63 | "source": {
64 | "type": "git",
65 | "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
66 | "reference": "7da1894633f168fe244afc6de00d141f27517b62"
67 | },
68 | "dist": {
69 | "type": "zip",
70 | "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
71 | "reference": "7da1894633f168fe244afc6de00d141f27517b62",
72 | "shasum": ""
73 | },
74 | "require": {
75 | "php": ">=5.4",
76 | "squizlabs/php_codesniffer": "^3.3.1"
77 | },
78 | "require-dev": {
79 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
80 | "phpcompatibility/php-compatibility": "^9.0",
81 | "phpcsstandards/phpcsdevtools": "^1.0",
82 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
83 | },
84 | "suggest": {
85 | "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
86 | },
87 | "type": "phpcodesniffer-standard",
88 | "notification-url": "https://packagist.org/downloads/",
89 | "license": [
90 | "MIT"
91 | ],
92 | "authors": [
93 | {
94 | "name": "Contributors",
95 | "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
96 | }
97 | ],
98 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
99 | "keywords": [
100 | "phpcs",
101 | "standards",
102 | "wordpress"
103 | ],
104 | "time": "2020-05-13T23:57:56+00:00"
105 | }
106 | ],
107 | "packages-dev": [],
108 | "aliases": [],
109 | "minimum-stability": "stable",
110 | "stability-flags": [],
111 | "prefer-stable": false,
112 | "prefer-lowest": false,
113 | "platform": [],
114 | "platform-dev": [],
115 | "plugin-api-version": "1.1.0"
116 | }
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Timber theme boilerplate
2 |
3 | ## Theme highlights
4 |
5 | - [Timber](https://timber.github.io/docs/) (Twig) based templates. Put logic in usual wordpress PHP templates, relate it to a Twig template by assigning to the `$context[]` variable, add corresponding templates in `/templates` folder;
6 | - [BEM](https://bem.info) methodology for markup/CSS. The project frontend consists of self-contained components. BEM naming convention is `component__element_modifier`. Avoid all the things that you would avoid in a typical BEM-like project. See below for more information;
7 | - namespaces for CSS classes aka prefixes. Read below on what prefixes can be used, and see here [why namespacing is cool](https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/);
8 | - stylelint linting. Comments starting from words "todo"/"hack" appear as warnings to bring attention to them;
9 | - `dotenv` for doing different things depending on local/stg/prod environment;
10 | - shared variables inside the theme (a variable added to `common_config.json` can be reused in JS/Gulp/SASS/PHP/Twig);
11 | - npm packages for theme usage;
12 | - Babel-enabled modular JS;
13 | - SVG spriting. Put new SVG files to be found in the sprite to `/img/svg-sprite-source` folder, invoke them with the `image-svg-sprite.twig` partial;
14 | - automated Modernizr build based on actually used features only;
15 | - custom fields registered in code for faster deployment to other environments.
16 |
17 | The theme is best served with [VVV site template](https://github.com/certainlyakey/vvv-project-boilerplate) but can be used standalone without any problems.
18 |
19 | ## CSS architecture
20 |
21 | CSS architecture of the project follows a set of rules to establish better maintainability, reusability, and organization of code. It borrows from several concepts including [BEM](https://bem.info)/[7-1 pattern](https://sass-guidelin.es/#architecture)/[ITCSS](https://speakerdeck.com/dafed/managing-css-projects-with-itcss)/[Harry Roberts'namespaces](http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#the-namespaces).
22 | Every class or mixin should be prefixed. Here's the types of classes/mixins that are used throughout the project:
23 |
24 | 1. Components (prefixed with `c-`) are potentially reusable mixins that represent independent, fully styled blocks within a page. Where to place: `components/_component-name.scss`.
25 | 1. The concept of components is fully compatible with the BEM methodology. They may contain `__elements` and `_modifiers`. Components may itself have a modifier, but a component cannot have a subcomponent — only 1 level of nesting elements inside a component is allowed;
26 | 2. They are applied to the class of the same name in `_main.scss` but also can be applied to other classes as well, without having to add the original class in the markup explicitly and allowing for easy extension (any component can be extended with another component — without drawbacks of `@extend`s). That's why the first argument in the component mixin should always be `$base_class` and its inner elements definitions should start with `#{$base_class}`. See the example component in the `components` folder;
27 | 3. Non reusable components used for layout features (such as header, footer, main and so on) are still components, so they should be prefixed and comply to the usual rules. It is not mandatory though to create them as mixins;
28 | 2. Theming mixins (`t-`) — these are only related to appearance. Usually are not used alone as well. Where to place: `abstracts/_mixins.scss`;
29 | 3. Utilities are “does one thing”-style mixins. Prefix: `u-`. Where to place: `abstracts/_mixins.scss`;
30 | 4. Scoped mixins (`s-`) - define a separate styling context inside which tag selectors may be used (usually we can only use classes). Only for styling user edited rich content areas (articles body etc.). Where to place: `abstracts/_mixins.scss`.
31 |
32 | The project also makes use of context dependent prefixes such as `js-`, `has-` and others.
33 |
34 | When styling a new piece of markup, it's important to see if there's already a component mixin that fits its design. If there is, maybe it would be more appropriate to add some new elements to that mixin and then apply it. An alternative approach is to create a new component that `@include`s another one and add up the difference in styling to the latter.
35 |
36 | When styling a group of repeated items (such as a section of teasers) it's preferable to separate the group's own styling and item's inner styling into two different components. This way we can always reapply the item's styling independently somewhere else.
37 |
38 | Don't use extends unless they're provided by an external tool (such as `svg-sprite`). [Here's some explanation why this project avoids them](http://csswizardry.com/2016/02/mixins-better-for-performance/).
39 |
40 | ## Installation
41 |
42 | The theme is dependent on ACF and Timber Library plugins. Make sure they're installed and activated before activating the theme.
43 | The theme can also make use of an `.env` file if it exists in the project. The path to the `.env` file is specified in `gulpfile.js`.
44 |
45 | 1. Replace all the instances of `themeprefix` in boilerplate `*.php` files with any prefix wanted;
46 | 2. replace all the instances of `theme_domain` in boilerplate `*.php`, `*.twig`, `style.scss`, `loco.xml` files with your theme's localisation domain;
47 | 3. rename the theme in `style.scss` and `package.json` files appropriately;
48 | 4. go to the `timber-theme` theme folder, run `npm install`;
49 | 5. create an `.env` file in the theme folder or adjust its location in `gulpfile.js`. Add `HOST=YOURLOCALSITE.TEST` there to enable Browsersync;
50 | 6. Add `ENV=dev` line to the `.env` file. This will generate files more adapted for local FE work (CSS source maps, non minified CSS/JS, pixels instead of rems). On staging/production it may contain anything except for `dev`;
51 | 7. run `gulp` to compile theme, `gulp watch` to compile and watch for changes.
52 |
53 | You may wish to add `style.css` in the root after first `gulp` execution to the theme's `.gitignore` file (though it's not mandatory).
54 |
55 | ## Development notes
56 |
57 | - If you create a native Wordpress custom page template — put the Twig file into the `templates/custom-templates` folder. It is a good idea to keep PHP files for custom page templates prefixed uniformly (for example with `template-` prefix).
58 | - The theme Javascript is separated into modules. Each module is merged into the main `scripts.min.js` file which is served on frontend upon gulp compilation. Each time you need to introduce a new script that is not related to others, you will want to create a new module.
59 | 1. duplicate any existing module in the `js/modules` folder (or the provided `example-module.js` file);
60 | 2. rename it appropriately;
61 | 3. init the module in `js/main.js` file.
62 | - Theme functions are organized into several includes, if adding something try to find an appropriate include for that or create a new one. Each file's purpose is described in its comment section.
63 | - When registering new custom fields you can follow the naming convention of `{posttypename}_{fieldname}` for post custom fields and post-type-wide fields (stored in the `option` table) and `{taxname}_{fieldname}` for term meta fields. This will allow you to use the fields in various smart ways.
64 | - You can use [Loco Translate](https://wordpress.org/plugins/loco-translate/) plugin for translation of the English theme strings into another languages (no setup needed, just install it on your local). The plugin will automatically discover all the English strings of the theme and will let you translate them right in the admin. After doing some translations make a commit. The translation file `/languages/.po` is compiled into the `.mo` file when you save your translation in Loco Translate admin interface and also by a `gulp watch` task.
65 | - You can use a `@z-index space: XX-XX` comment in the beginning of a SCSS file of a component to indicate the range of `z-index` values to be used here to other developers. This helps to prevent clashes between different components. Obviously, other components should have `z-index` values assigned in another range. For example, a component `c-a` will have `@z-index space: 20-30` comment while a component `c-b` will have `@z-index space: 30-40`.
66 | - You can lint PHP files by running `composer install` in the theme folder (install [composer](https://getcomposer.org/) globally first) and `vendor/bin/phpcs .`.
67 |
68 | ## Ideas for future development
69 |
70 | 1. add a stylelint check for browser incompatibilities with `ismay/stylelint-no-unsupported-browser-features`
71 | 2. replace JSHint with ESLint
72 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // DIR CONFIG
4 |
5 | const config = {
6 | dirs: {
7 | generated: './scss/autogenerated/',
8 | assets: './img/',
9 | scripts: './js/',
10 | styles: './scss/',
11 | },
12 | // Standalone JS libraries to copy on build
13 | js_libs_paths: [
14 | // './node_modules/slick-carousel/slick/slick.min.js'
15 | ]
16 | };
17 |
18 |
19 | // DEPENDENCIES
20 | // all require'd variables are to be prefixed with an underscore to ease debugging and cleaning up
21 |
22 | // const debug = require('gulp-debug');
23 | const _gulp = require('gulp');
24 |
25 | // Some gulp utility commands
26 | const _gutil = require('gulp-util');
27 |
28 | // File system read access
29 | const _fs = require('fs');
30 |
31 | // Allows to output different builds depending on current environment. .env is located in the root of the repo
32 | // ignored if .env not found
33 | const _dotenv = require('dotenv').config({ path: './../../../.env' });
34 |
35 | // Compiling Sass
36 | const _gulpsass = require('gulp-sass');
37 |
38 | // Postprocessing CSS
39 | const _postcss = require('gulp-postcss');
40 |
41 | // CSS minification
42 | const _cssnano = require('cssnano');
43 |
44 | // Joining CSS files
45 | const _concat = require('gulp-concat');
46 |
47 | // Build notifications
48 | const _notify = require('gulp-notify');
49 |
50 | // Uglifying JS
51 | const _uglify = require('gulp-uglify');
52 |
53 | // Creates svg sprites from source svg files
54 | const _svgsprite = require('gulp-svg-sprite');
55 |
56 | // Checks JS for mistakes. jshint-stylish should be installed too
57 | const _jshint = require('gulp-jshint');
58 |
59 | // Autoprefixes Sass
60 | const _autoprefixer = require('autoprefixer');
61 |
62 | // Generates Sass/JS sourcemaps for easier inbrowser debugging
63 | const _sourcemaps = require('gulp-sourcemaps');
64 |
65 | // These handle merging JS modules
66 | const _browserify = require('browserify');
67 | const _source = require('vinyl-source-stream');
68 | const _buffer = require('vinyl-buffer');
69 |
70 | // Automatically reload browsers while watching
71 | const _browsersync = require('browser-sync').create();
72 |
73 | // Allows to use ES2015 in JS. babel-preset-es2015 should be installed too
74 | const _babelify = require('babelify');
75 |
76 | // Adds browser feature test results to HTML and JS
77 | const _modernizr = require('gulp-modernizr');
78 |
79 | // Injects variables from config file to Sass
80 | const _sassvariables = require('gulp-sass-variables');
81 |
82 | // Allows to import Sass npm modules with a shorter notation
83 | const _packageimporter = require('node-sass-package-importer');
84 |
85 | // Allows to inline css @imports instead of just linking to them (node-sass has marked this option as deprecated). Place "!" before filename of a CSS file to have its contents injected
86 | const _cssimporter = require('node-sass-css-importer');
87 |
88 | // Lints Sass and CSS
89 | const _gulp_stylelint = require('gulp-stylelint');
90 |
91 | // Converts .po localisation files to .mo
92 | const _gettext = require('gulp-gettext');
93 |
94 | const _phpcs = require('gulp-phpcs');
95 |
96 | // Source for variables shared between gulp, JS, and Sass
97 | const _projectconfig = require('./common_config.json');
98 |
99 |
100 |
101 | // TASKS CONFIG
102 |
103 |
104 | // Environment variables
105 | // if defined as a gulp commandline argument (gulp --env=dev)
106 | let is_env_dev = true;
107 | if (typeof process.env.ENV !== 'undefined') {
108 | is_env_dev = (process.env.ENV === 'dev');
109 | }
110 | if (typeof _gutil.env.env !== 'undefined') {
111 | is_env_dev = (_gutil.env.env === 'dev');
112 | }
113 |
114 |
115 | // SVG sprite config
116 | const svgsprite_config = {
117 | mode : {
118 | symbol : {
119 | dest : '.',
120 | inline : true,
121 | prefix : '.u-svg-%s',
122 | dimensions : '-size',
123 | sprite : config.dirs.assets + 'sprite.svg',
124 | render : {
125 | css : {
126 | dest : config.dirs.generated + 'svg-sprite.css'
127 | }
128 | }
129 | }
130 | }
131 | };
132 |
133 |
134 | // Injecting config variables into Sass
135 | let config_sass_vars = {};
136 | for (var variable in _projectconfig) {
137 | config_sass_vars['$_' + variable] = _projectconfig[variable];
138 | }
139 | config_sass_vars['$_is-env-dev'] = is_env_dev;
140 |
141 |
142 |
143 | // TASKS
144 |
145 | // build_svg_sprite
146 | function build_svg_sprite() {
147 | return _gulp.src(config.dirs.assets + 'svg-sprite-source/*.svg')
148 | .pipe(_svgsprite(svgsprite_config)).on('error', function(message) {
149 | console.log(message);
150 | })
151 | .pipe(_gulp.dest('.'))
152 | .pipe(is_env_dev ? _notify('SVG sprite created successfully!') : _gutil.noop() );
153 | }
154 |
155 | // lint_css
156 | function lint_css() {
157 | return _gulp
158 | .src(config.dirs.styles + '**/*.scss')
159 | .pipe(_gulp_stylelint({
160 | reporters: [
161 | {formatter: 'string', console: true}
162 | ]
163 | }));
164 | }
165 |
166 | // build_css, before: build_svg_sprite
167 | function build_css() {
168 | let postcss_plugins = [
169 | _autoprefixer()
170 | ];
171 | if (!is_env_dev) {
172 | postcss_plugins.push(_cssnano());
173 | }
174 | return _gulp
175 | .src(config.dirs.styles + 'style.scss')
176 | .pipe( is_env_dev ? _sourcemaps.init() : _gutil.noop() )
177 | .pipe(_sassvariables(config_sass_vars))
178 | .pipe(_gulpsass({
179 | style: 'expanded',
180 | includePaths: [],
181 | importer: [_packageimporter(), _cssimporter()]
182 | }))
183 | .pipe(_concat('style.css'))
184 | .pipe(_postcss(postcss_plugins))
185 | .pipe( is_env_dev ? _sourcemaps.write() : _gutil.noop() )
186 | .pipe(_gulp.dest('./'))
187 | .pipe(_browsersync.stream())
188 | .pipe(is_env_dev ? _notify('CSS compiled and concatenated successfully!') : _gutil.noop() );
189 | }
190 |
191 | // lint_js
192 | function lint_js() {
193 | const files_to_lint = [
194 | __filename,
195 | config.dirs.scripts + 'modules/*.js'
196 | ];
197 |
198 | return _gulp.src(files_to_lint)
199 | .pipe(_jshint())
200 | .pipe(_jshint.reporter(require('jshint-stylish')));
201 | }
202 |
203 | // build_modernizr, before: build_css
204 | function build_modernizr() {
205 | var paths = [
206 | config.dirs.scripts + 'main.js',
207 | config.dirs.scripts + 'modules/*.js',
208 | 'style.css'
209 | ];
210 |
211 | return _gulp
212 | .src(paths)
213 | .pipe(_modernizr('modernizr.js', {
214 | options: ['setClasses'],
215 | classPrefix: 'js-supports-'
216 | }))
217 | .pipe(_uglify())
218 | .pipe(_gulp.dest(config.dirs.scripts))
219 | .on('error', _gutil.log);
220 | }
221 |
222 | // bundlejs
223 | function bundlejs() {
224 |
225 | return _browserify({
226 | entries: [config.dirs.scripts + 'main.js'],
227 | debug: is_env_dev ? true : false,
228 | transform: [
229 | _babelify.configure({
230 | presets: ['@babel/preset-env']
231 | })
232 | ]
233 | })
234 | .bundle()
235 | .on('error', _gutil.log)
236 | .pipe(_source('scripts.min.js'))
237 | .pipe(_buffer())
238 | // don't uglify if we're in local environment, do uglify if it's something other
239 | .pipe(is_env_dev ? _gutil.noop() : _uglify())
240 | .pipe(_gulp.dest(config.dirs.scripts));
241 | }
242 |
243 | // build_js, before: build_modernizr, bundlejs
244 | function build_js(done) {
245 | let paths_to_check = [
246 | config.dirs.scripts + 'modernizr.js',
247 | config.dirs.scripts + 'scripts.min.js'
248 | ];
249 | let paths = [];
250 | paths_to_check.forEach(path => {
251 | if (_fs.existsSync(path)) {
252 | paths.push(path);
253 | }
254 | });
255 |
256 | if (paths.length > 0) {
257 | return _gulp
258 | .src(paths)
259 | .pipe(_concat('scripts.min.js'))
260 | .pipe(_gulp.dest(config.dirs.scripts))
261 | .pipe(_browsersync.stream())
262 | .pipe(is_env_dev ? _notify('JS compiled and concatenated successfully!') : _gutil.noop());
263 | }
264 | done();
265 | }
266 |
267 |
268 | function build_po_to_mo() {
269 | return _gulp.src('languages/*.po')
270 | .pipe(_gettext())
271 | .pipe(_gulp.dest('languages'));
272 | }
273 |
274 |
275 | function lint_php() {
276 | return _gulp.src(['./**/*.php', '!vendor/**/*.*'])
277 | .pipe(_phpcs({
278 | bin: 'vendor/bin/phpcs',
279 | standard: './phpcs.xml',
280 | }))
281 | .pipe(_phpcs.reporter('log'));
282 | }
283 |
284 |
285 | // build_copy_jslibs
286 | function build_copy_jslibs(done) {
287 | let paths_to_copy = [];
288 | config.js_libs_paths.forEach(path => {
289 | if (_fs.existsSync(path)) {
290 | paths_to_copy.push(path);
291 | } else {
292 | console.log(`JS lib at ${path} doesn't exist, can't copy`);
293 | }
294 | });
295 | if (paths_to_copy.length > 0) {
296 | console.log('Copying these JS libs: ', paths_to_copy);
297 | return _gulp
298 | .src(paths_to_copy)
299 | .pipe(_gulp.dest(config.dirs.scripts + 'libs/'));
300 | }
301 | done();
302 | }
303 |
304 |
305 | // reload, before: default
306 | function reload(done) {
307 | _browsersync.reload();
308 | done();
309 | }
310 |
311 |
312 | // Main workflow/Local build
313 | const tasks_build = _gulp.series(
314 | _gulp.parallel(
315 | build_po_to_mo,
316 | build_copy_jslibs,
317 | _gulp.series(
318 | build_svg_sprite,
319 | build_css, // after build_svg_sprite: we need to have svg-sprite.css ready to include it into style.css
320 | build_modernizr // after build_css
321 | ),
322 | _gulp.series(
323 | bundlejs,
324 | build_js
325 | ),
326 | lint_php
327 | )
328 | );
329 |
330 |
331 | // Serve (aka watch): serve, before: default
332 | function serve(done) {
333 | let browsersyncSettings = {
334 | port: process.env.PORT ? process.env.PORT : 3001,
335 | open: false,
336 | notify: false
337 | };
338 | if (process.env.HOST) {
339 | browsersyncSettings = {
340 | ...browsersyncSettings,
341 | proxy: process.env.HOST
342 | };
343 | } else {
344 | browsersyncSettings = {
345 | ...browsersyncSettings,
346 | server: {
347 | baseDir: ['./']
348 | },
349 | };
350 | }
351 | _browsersync.init(browsersyncSettings);
352 |
353 | // Gulpfile.js:
354 | _gulp.watch(
355 | __filename,
356 | _gulp.series(
357 | lint_js
358 | )
359 | );
360 |
361 | // Scripts:
362 | _gulp.watch(
363 | [
364 | config.dirs.scripts + 'main.js',
365 | config.dirs.scripts + 'modules/*.js'
366 | ],
367 | _gulp.parallel(
368 | lint_js,
369 | _gulp.series(
370 | bundlejs,
371 | build_js,
372 | reload
373 | )
374 | )
375 | );
376 |
377 | // Templates:
378 | _gulp.watch(
379 | [
380 | './**/*.php',
381 | './templates/**/*.twig'
382 | ],
383 | _gulp.series(
384 | reload
385 | )
386 | );
387 |
388 | // PHP linting:
389 | _gulp.watch(
390 | ['./**/*.php'],
391 | _gulp.series(
392 | lint_php
393 | )
394 | );
395 |
396 | // Styles:
397 | _gulp.watch(
398 | config.dirs.styles + '**/*.scss',
399 | _gulp.parallel(
400 | lint_css,
401 | _gulp.series(
402 | build_svg_sprite,
403 | build_css
404 | )
405 | )
406 | );
407 |
408 | // SVG:
409 | _gulp.watch(
410 | config.dirs.assets + 'svg-sprite-source/*.svg',
411 | _gulp.series(
412 | build_svg_sprite,
413 | reload
414 | )
415 | );
416 |
417 | // Po files:
418 | _gulp.watch(
419 | 'languages/*.po',
420 | _gulp.series(
421 | build_po_to_mo,
422 | reload
423 | )
424 | );
425 |
426 | done();
427 | }
428 |
429 |
430 | exports.watch = _gulp.parallel(tasks_build, serve);
431 | exports.serve = _gulp.parallel(tasks_build, serve);
432 | exports.build_css = _gulp.series(build_svg_sprite, build_css);
433 | exports.default = tasks_build;
434 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Theme Name: Timber Boilerplate Theme
3 | Theme URI: https://github.com/certainlyakey/timber-boilerplate
4 | Description: This is a boilerplate theme using Timber
5 | Version: 1.0
6 | Author: Aleksandr Beliaev
7 | Text Domain: theme_domain
8 | Domain Path: /languages/
9 | */
10 | /* stylelint-disable plugin/at-rule-import-path */
11 | .u-screenreader-text {
12 | position: absolute;
13 | overflow: hidden;
14 | clip: rect(0 0 0 0);
15 | height: 1px;
16 | width: 1px;
17 | margin: -1px;
18 | padding: 0;
19 | border: none;
20 | white-space: nowrap; }
21 |
22 | html:not(.no-js) .js-hidden-if-js-on {
23 | display: none; }
24 |
25 | .u-inner-layer {
26 | position: relative;
27 | z-index: 1; }
28 |
29 | .u-nowrap {
30 | white-space: nowrap; }
31 |
32 | .js-hidden,
33 | .u-hidden {
34 | display: none; }
35 |
36 | /* stylelint-enable plugin/at-rule-import-path */
37 | /* stylelint-disable plugin/at-rule-import-path */
38 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
39 | /* Document
40 | ========================================================================== */
41 | /**
42 | * 1. Correct the line height in all browsers.
43 | * 2. Prevent adjustments of font size after orientation changes in iOS.
44 | */
45 | html {
46 | line-height: 1.15;
47 | /* 1 */
48 | -webkit-text-size-adjust: 100%;
49 | /* 2 */ }
50 |
51 | /* Sections
52 | ========================================================================== */
53 | /**
54 | * Remove the margin in all browsers.
55 | */
56 | body {
57 | margin: 0; }
58 |
59 | /**
60 | * Render the `main` element consistently in IE.
61 | */
62 | main {
63 | display: block; }
64 |
65 | /**
66 | * Correct the font size and margin on `h1` elements within `section` and
67 | * `article` contexts in Chrome, Firefox, and Safari.
68 | */
69 | h1 {
70 | font-size: 2em;
71 | margin: 0.67em 0; }
72 |
73 | /* Grouping content
74 | ========================================================================== */
75 | /**
76 | * 1. Add the correct box sizing in Firefox.
77 | * 2. Show the overflow in Edge and IE.
78 | */
79 | hr {
80 | -webkit-box-sizing: content-box;
81 | box-sizing: content-box;
82 | /* 1 */
83 | height: 0;
84 | /* 1 */
85 | overflow: visible;
86 | /* 2 */ }
87 |
88 | /**
89 | * 1. Correct the inheritance and scaling of font size in all browsers.
90 | * 2. Correct the odd `em` font sizing in all browsers.
91 | */
92 | pre {
93 | font-family: monospace, monospace;
94 | /* 1 */
95 | font-size: 1em;
96 | /* 2 */ }
97 |
98 | /* Text-level semantics
99 | ========================================================================== */
100 | /**
101 | * Remove the gray background on active links in IE 10.
102 | */
103 | a {
104 | background-color: transparent; }
105 |
106 | /**
107 | * 1. Remove the bottom border in Chrome 57-
108 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
109 | */
110 | abbr[title] {
111 | border-bottom: none;
112 | /* 1 */
113 | text-decoration: underline;
114 | /* 2 */
115 | -webkit-text-decoration: underline dotted;
116 | text-decoration: underline dotted;
117 | /* 2 */ }
118 |
119 | /**
120 | * Add the correct font weight in Chrome, Edge, and Safari.
121 | */
122 | b,
123 | strong {
124 | font-weight: bolder; }
125 |
126 | /**
127 | * 1. Correct the inheritance and scaling of font size in all browsers.
128 | * 2. Correct the odd `em` font sizing in all browsers.
129 | */
130 | code,
131 | kbd,
132 | samp {
133 | font-family: monospace, monospace;
134 | /* 1 */
135 | font-size: 1em;
136 | /* 2 */ }
137 |
138 | /**
139 | * Add the correct font size in all browsers.
140 | */
141 | small {
142 | font-size: 80%; }
143 |
144 | /**
145 | * Prevent `sub` and `sup` elements from affecting the line height in
146 | * all browsers.
147 | */
148 | sub,
149 | sup {
150 | font-size: 75%;
151 | line-height: 0;
152 | position: relative;
153 | vertical-align: baseline; }
154 |
155 | sub {
156 | bottom: -0.25em; }
157 |
158 | sup {
159 | top: -0.5em; }
160 |
161 | /* Embedded content
162 | ========================================================================== */
163 | /**
164 | * Remove the border on images inside links in IE 10.
165 | */
166 | img {
167 | border-style: none; }
168 |
169 | /* Forms
170 | ========================================================================== */
171 | /**
172 | * 1. Change the font styles in all browsers.
173 | * 2. Remove the margin in Firefox and Safari.
174 | */
175 | button,
176 | input,
177 | optgroup,
178 | select,
179 | textarea {
180 | font-family: inherit;
181 | /* 1 */
182 | font-size: 100%;
183 | /* 1 */
184 | line-height: 1.15;
185 | /* 1 */
186 | margin: 0;
187 | /* 2 */ }
188 |
189 | /**
190 | * Show the overflow in IE.
191 | * 1. Show the overflow in Edge.
192 | */
193 | button,
194 | input {
195 | /* 1 */
196 | overflow: visible; }
197 |
198 | /**
199 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
200 | * 1. Remove the inheritance of text transform in Firefox.
201 | */
202 | button,
203 | select {
204 | /* 1 */
205 | text-transform: none; }
206 |
207 | /**
208 | * Correct the inability to style clickable types in iOS and Safari.
209 | */
210 | button,
211 | [type="button"],
212 | [type="reset"],
213 | [type="submit"] {
214 | -webkit-appearance: button; }
215 |
216 | /**
217 | * Remove the inner border and padding in Firefox.
218 | */
219 | button::-moz-focus-inner,
220 | [type="button"]::-moz-focus-inner,
221 | [type="reset"]::-moz-focus-inner,
222 | [type="submit"]::-moz-focus-inner {
223 | border-style: none;
224 | padding: 0; }
225 |
226 | /**
227 | * Restore the focus styles unset by the previous rule.
228 | */
229 | button:-moz-focusring,
230 | [type="button"]:-moz-focusring,
231 | [type="reset"]:-moz-focusring,
232 | [type="submit"]:-moz-focusring {
233 | outline: 1px dotted ButtonText; }
234 |
235 | /**
236 | * Correct the padding in Firefox.
237 | */
238 | fieldset {
239 | padding: 0.35em 0.75em 0.625em; }
240 |
241 | /**
242 | * 1. Correct the text wrapping in Edge and IE.
243 | * 2. Correct the color inheritance from `fieldset` elements in IE.
244 | * 3. Remove the padding so developers are not caught out when they zero out
245 | * `fieldset` elements in all browsers.
246 | */
247 | legend {
248 | -webkit-box-sizing: border-box;
249 | box-sizing: border-box;
250 | /* 1 */
251 | color: inherit;
252 | /* 2 */
253 | display: table;
254 | /* 1 */
255 | max-width: 100%;
256 | /* 1 */
257 | padding: 0;
258 | /* 3 */
259 | white-space: normal;
260 | /* 1 */ }
261 |
262 | /**
263 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
264 | */
265 | progress {
266 | vertical-align: baseline; }
267 |
268 | /**
269 | * Remove the default vertical scrollbar in IE 10+.
270 | */
271 | textarea {
272 | overflow: auto; }
273 |
274 | /**
275 | * 1. Add the correct box sizing in IE 10.
276 | * 2. Remove the padding in IE 10.
277 | */
278 | [type="checkbox"],
279 | [type="radio"] {
280 | -webkit-box-sizing: border-box;
281 | box-sizing: border-box;
282 | /* 1 */
283 | padding: 0;
284 | /* 2 */ }
285 |
286 | /**
287 | * Correct the cursor style of increment and decrement buttons in Chrome.
288 | */
289 | [type="number"]::-webkit-inner-spin-button,
290 | [type="number"]::-webkit-outer-spin-button {
291 | height: auto; }
292 |
293 | /**
294 | * 1. Correct the odd appearance in Chrome and Safari.
295 | * 2. Correct the outline style in Safari.
296 | */
297 | [type="search"] {
298 | -webkit-appearance: textfield;
299 | /* 1 */
300 | outline-offset: -2px;
301 | /* 2 */ }
302 |
303 | /**
304 | * Remove the inner padding in Chrome and Safari on macOS.
305 | */
306 | [type="search"]::-webkit-search-decoration {
307 | -webkit-appearance: none; }
308 |
309 | /**
310 | * 1. Correct the inability to style clickable types in iOS and Safari.
311 | * 2. Change font properties to `inherit` in Safari.
312 | */
313 | ::-webkit-file-upload-button {
314 | -webkit-appearance: button;
315 | /* 1 */
316 | font: inherit;
317 | /* 2 */ }
318 |
319 | /* Interactive
320 | ========================================================================== */
321 | /*
322 | * Add the correct display in Edge, IE 10+, and Firefox.
323 | */
324 | details {
325 | display: block; }
326 |
327 | /*
328 | * Add the correct display in all browsers.
329 | */
330 | summary {
331 | display: list-item; }
332 |
333 | /* Misc
334 | ========================================================================== */
335 | /**
336 | * Add the correct display in IE 10+.
337 | */
338 | template {
339 | display: none; }
340 |
341 | /**
342 | * Add the correct display in IE 10.
343 | */
344 | [hidden] {
345 | display: none; }
346 |
347 | /* stylelint-enable plugin/at-rule-import-path */
348 | /* stylelint-disable color-no-hex */
349 | /* stylelint-disable indentation */
350 | /* stylelint-enable indentation */
351 | /* stylelint-disable meowtec/no-px */
352 | /* stylelint-enable meowtec/no-px */
353 | /* stylelint-disable selector-max-universal, selector-max-type */
354 | h1, h2, h3, h4, h5, h6, p, dl, dd, ul, ol, li, figure {
355 | margin: 0;
356 | padding: 0; }
357 |
358 | h1, h2, h3, h4, h5, h6 {
359 | font-weight: normal;
360 | font-size: 100%; }
361 |
362 | ul {
363 | list-style: none; }
364 |
365 | html {
366 | -webkit-box-sizing: border-box;
367 | box-sizing: border-box; }
368 |
369 | *, *::before, *::after {
370 | -webkit-box-sizing: inherit;
371 | box-sizing: inherit; }
372 |
373 | ol, ul {
374 | list-style-position: inside; }
375 |
376 | textarea {
377 | max-width: 100%;
378 | resize: vertical; }
379 |
380 | fieldset {
381 | border: none;
382 | margin: 0;
383 | padding: 0; }
384 |
385 | select {
386 | color: black; }
387 |
388 | iframe {
389 | border: none; }
390 |
391 | /* stylelint-disable declaration-no-important, selector-max-universal */
392 | body {
393 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
394 | font-size: 16px;
395 | line-height: 1.6;
396 | background-color: white; }
397 |
398 | a {
399 | color: #ee2d29;
400 | text-decoration: none; }
401 |
402 | .s-textcontent {
403 | /* stylelint-disable selector-max-type, selector-max-compound-selectors */
404 | /* stylelint-enable selector-max-type, selector-max-compound-selectors */ }
405 | .s-textcontent > blockquote {
406 | font-style: italic; }
407 | .s-textcontent > p:not(:only-child), .s-textcontent > ul:not(:only-child), .s-textcontent > ol:not(:only-child) {
408 | margin-top: 10px;
409 | margin-bottom: 10px; }
410 | .s-textcontent > h2:first-child, .s-textcontent > h3:first-child, .s-textcontent > h4:first-child, .s-textcontent > h5:first-child, .s-textcontent > h6:first-child, .s-textcontent > p:first-child, .s-textcontent > ul:first-child, .s-textcontent > ol:first-child {
411 | margin-top: 0; }
412 | .s-textcontent > h2:last-child, .s-textcontent > h3:last-child, .s-textcontent > h4:last-child, .s-textcontent > h5:last-child, .s-textcontent > h6:last-child, .s-textcontent > p:last-child, .s-textcontent > ul:last-child, .s-textcontent > ol:last-child {
413 | margin-bottom: 0; }
414 | .s-textcontent > ul li {
415 | list-style-type: disc; }
416 | .s-textcontent > ul li li, .s-textcontent > ol li li {
417 | padding-left: 20px; }
418 | .s-textcontent img {
419 | display: block; }
420 | @media (max-width: 63.99em) {
421 | .s-textcontent img {
422 | max-width: 100%;
423 | display: block;
424 | height: auto; } }
425 | .s-textcontent iframe {
426 | width: 100%; }
427 |
428 | .is-page-loading * {
429 | -webkit-transition: none !important;
430 | -o-transition: none !important;
431 | transition: none !important; }
432 |
433 | .u-link {
434 | color: #ee2d29;
435 | text-decoration: none; }
436 |
437 | .u-link-button {
438 | color: #ee2d29;
439 | text-decoration: none;
440 | border: none;
441 | background: none;
442 | -webkit-box-shadow: none;
443 | box-shadow: none;
444 | padding: 0; }
445 |
446 | .c-edit-link {
447 | position: fixed;
448 | top: 1em;
449 | left: 1em;
450 | opacity: 0; }
451 | .c-edit-link:hover {
452 | opacity: 1; }
453 |
454 | /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLnNjc3MiLCJfZGVwZW5kZW5jaWVzLnNjc3MiLCIuLi9ub2RlX21vZHVsZXMvY29tbW9uLXNhc3MtdXRpbGl0aWVzL3V0aWxpdGllcy9fY2xhc3Nlcy5zY3NzIiwiLi4vbm9kZV9tb2R1bGVzL2NvbW1vbi1zYXNzLXV0aWxpdGllcy91dGlsaXRpZXMvbWl4aW5zL191LXNjcmVlbnJlYWRlci10ZXh0LnNjc3MiLCJfdmVuZG9ycy5zY3NzIiwiLi4vfm5vcm1hbGl6ZS5jc3Mvbm9ybWFsaXplLmNzcyIsInN0eWxlLmNzcyIsImFic3RyYWN0cy92YXJpYWJsZXMvX2NvbG9ycy5zY3NzIiwiYWJzdHJhY3RzL3ZhcmlhYmxlcy9fdHlwb2dyYXBoeS5zY3NzIiwiYWJzdHJhY3RzL3ZhcmlhYmxlcy9fb3RoZXJzLnNjc3MiLCJiYXNlL19ub3JtYWxpemVfdHdlYWtzLnNjc3MiLCJiYXNlL19iYXNlLnNjc3MiLCJhYnN0cmFjdHMvX21peGlucy5zY3NzIiwiYWJzdHJhY3RzL190ZXh0Y29udGVudC1taXhpbnMuc2NzcyIsIi4uL25vZGVfbW9kdWxlcy9jb21tb24tc2Fzcy11dGlsaXRpZXMvdXRpbGl0aWVzL21peGlucy9fdS1zcGFjaW5nLnNjc3MiLCIuLi9ub2RlX21vZHVsZXMvc2Fzcy1tcS9fbXEuc2NzcyIsIi4uL25vZGVfbW9kdWxlcy9jb21tb24tc2Fzcy11dGlsaXRpZXMvdXRpbGl0aWVzL21peGlucy9fdS1pbWFnZS1hdXRvd2lkdGguc2NzcyIsIi4uL25vZGVfbW9kdWxlcy9jb21tb24tc2Fzcy11dGlsaXRpZXMvdXRpbGl0aWVzL21peGlucy9fdS1yZW1vdmUtYnV0dG9uLXN0eWxpbmcuc2NzcyIsImJhc2UvX3NjYWZmb2xkaW5nLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0E7Ozs7Ozs7O0VBUUU7QUNYRixrREFBa0Q7QUNBbEQ7RUNDRSxtQkFBa0I7RUFDbEIsaUJBQWdCO0VBQ2hCLG9CQUFtQjtFQUNuQixZQUFXO0VBQ1gsV0FBVTtFQUNWLGFBQVk7RUFDWixXQUFVO0VBQ1YsYUFBWTtFQUNaLG9CQUFtQixFRFBwQjs7QUFHQztFQUNFLGNBQVksRUFDYjs7QUFHSDtFQUNFLG1CQUFpQjtFQUNqQixXQUFTLEVBQ1Y7O0FBRUQ7RUFDRSxvQkFBa0IsRUFDbkI7O0FBRUQ7O0VBRUUsY0FBWSxFQUNiOztBRGZELGlEQUFpRDtBR1BqRCxrREFBa0Q7QUNBbEQsNEVBQTRFO0FBRTVFO2dGQUNnRjtBQUVoRjs7O0dBR0c7QUFFSDtFQUNFLGtCQUFpQjtFQUFFLE9BQU87RUFDMUIsK0JBQThCO0VBQUUsT0FBTyxFQUN4Qzs7QUFFRDtnRkFDZ0Y7QUFFaEY7O0dBRUc7QUFFSDtFQUNFLFVBQVMsRUFDVjs7QUFFRDs7R0FFRztBQUVIO0VBQ0UsZUFBYyxFQUNmOztBQUVEOzs7R0FHRztBQUVIO0VBQ0UsZUFBYztFQUNkLGlCQUFnQixFQUNqQjs7QUFFRDtnRkFDZ0Y7QUFFaEY7OztHQUdHO0FBRUg7RUFDRSxnQ0FBdUI7VUFBdkIsd0JBQXVCO0VBQUUsT0FBTztFQUNoQyxVQUFTO0VBQUUsT0FBTztFQUNsQixrQkFBaUI7RUFBRSxPQUFPLEVBQzNCOztBQUVEOzs7R0FHRztBQUVIO0VBQ0Usa0NBQWlDO0VBQUUsT0FBTztFQUMxQyxlQUFjO0VBQUUsT0FBTyxFQUN4Qjs7QUFFRDtnRkFDZ0Y7QUFFaEY7O0dBRUc7QUFFSDtFQUNFLDhCQUE2QixFQUM5Qjs7QUFFRDs7O0dBR0c7QUFFSDtFQUNFLG9CQUFtQjtFQUFFLE9BQU87RUFDNUIsMkJBQTBCO0VBQUUsT0FBTztFQUNuQywwQ0FBaUM7VUFBakMsa0NBQWlDO0VBQUUsT0FBTyxFQUMzQzs7QUFFRDs7R0FFRztBQUVIOztFQUVFLG9CQUFtQixFQUNwQjs7QUFFRDs7O0dBR0c7QUFFSDs7O0VBR0Usa0NBQWlDO0VBQUUsT0FBTztFQUMxQyxlQUFjO0VBQUUsT0FBTyxFQUN4Qjs7QUFFRDs7R0FFRztBQUVIO0VBQ0UsZUFBYyxFQUNmOztBQUVEOzs7R0FHRztBQUVIOztFQUVFLGVBQWM7RUFDZCxlQUFjO0VBQ2QsbUJBQWtCO0VBQ2xCLHlCQUF3QixFQUN6Qjs7QUFFRDtFQUNFLGdCQUFlLEVBQ2hCOztBQUVEO0VBQ0UsWUFBVyxFQUNaOztBQUVEO2dGQUNnRjtBQUVoRjs7R0FFRztBQUVIO0VBQ0UsbUJBQWtCLEVBQ25COztBQUVEO2dGQUNnRjtBQUVoRjs7O0dBR0c7QUFFSDs7Ozs7RUFLRSxxQkFBb0I7RUFBRSxPQUFPO0VBQzdCLGdCQUFlO0VBQUUsT0FBTztFQUN4QixrQkFBaUI7RUFBRSxPQUFPO0VBQzFCLFVBQVM7RUFBRSxPQUFPLEVBQ25COztBQUVEOzs7R0FHRztBQUVIOztFQUNRLE9BQU87RUFDYixrQkFBaUIsRUFDbEI7O0FBRUQ7OztHQUdHO0FBRUg7O0VBQ1MsT0FBTztFQUNkLHFCQUFvQixFQUNyQjs7QUFFRDs7R0FFRztBQUVIOzs7O0VBSUUsMkJBQTBCLEVBQzNCOztBQUVEOztHQUVHO0FBRUg7Ozs7RUFJRSxtQkFBa0I7RUFDbEIsV0FBVSxFQUNYOztBQUVEOztHQUVHO0FBRUg7Ozs7RUFJRSwrQkFBOEIsRUFDL0I7O0FBRUQ7O0dBRUc7QUFFSDtFQUNFLCtCQUE4QixFQUMvQjs7QUFFRDs7Ozs7R0FLRztBQUVIO0VBQ0UsK0JBQXNCO1VBQXRCLHVCQUFzQjtFQUFFLE9BQU87RUFDL0IsZUFBYztFQUFFLE9BQU87RUFDdkIsZUFBYztFQUFFLE9BQU87RUFDdkIsZ0JBQWU7RUFBRSxPQUFPO0VBQ3hCLFdBQVU7RUFBRSxPQUFPO0VBQ25CLG9CQUFtQjtFQUFFLE9BQU8sRUFDN0I7O0FBRUQ7O0dBRUc7QUFFSDtFQUNFLHlCQUF3QixFQUN6Qjs7QUFFRDs7R0FFRztBQUVIO0VBQ0UsZUFBYyxFQUNmOztBQUVEOzs7R0FHRztBQ09IOztFREhFLCtCQUFzQjtVQUF0Qix1QkFBc0I7RUFBRSxPQUFPO0VBQy9CLFdBQVU7RUFBRSxPQUFPLEVBQ3BCOztBQUVEOztHQUVHO0FDT0g7O0VESEUsYUFBWSxFQUNiOztBQUVEOzs7R0FHRztBQ0tIO0VERkUsOEJBQTZCO0VBQUUsT0FBTztFQUN0QyxxQkFBb0I7RUFBRSxPQUFPLEVBQzlCOztBQUVEOztHQUVHO0FDS0g7RURGRSx5QkFBd0IsRUFDekI7O0FBRUQ7OztHQUdHO0FBRUg7RUFDRSwyQkFBMEI7RUFBRSxPQUFPO0VBQ25DLGNBQWE7RUFBRSxPQUFPLEVBQ3ZCOztBQUVEO2dGQUNnRjtBQUVoRjs7R0FFRztBQUVIO0VBQ0UsZUFBYyxFQUNmOztBQUVEOztHQUVHO0FBRUg7RUFDRSxtQkFBa0IsRUFDbkI7O0FBRUQ7Z0ZBQ2dGO0FBRWhGOztHQUVHO0FBRUg7RUFDRSxjQUFhLEVBQ2Q7O0FBRUQ7O0dBRUc7QUNMSDtFRFFFLGNBQWEsRUFDZDs7QUR0VkQsaURBQWlEO0FHTmpELG9DQUFvQztBQ1VwQyxtQ0FBbUM7QUFxQm5DLGtDQUFrQztBQy9CbEMscUNBQXFDO0FBa0NyQyxvQ0FBb0M7QUNsQ3BDLGlFQUFpRTtBQUVqRTtFQUNFLFVBQVM7RUFDVCxXQUFVLEVBQ1g7O0FBRUQ7RUFDRSxvQkFBbUI7RUFDbkIsZ0JBQWUsRUFDaEI7O0FBRUQ7RUFDRSxpQkFBZ0IsRUFDakI7O0FBRUQ7RUFDRSwrQkFBc0I7VUFBdEIsdUJBQXNCLEVBQ3ZCOztBQUVEO0VBQ0UsNEJBQW1CO1VBQW5CLG9CQUFtQixFQUNwQjs7QUFFRDtFQUNFLDRCQUEyQixFQUM1Qjs7QUFFRDtFQUNFLGdCQUFlO0VBQ2YsaUJBQWdCLEVBQ2pCOztBQUVEO0VBQ0UsYUFBWTtFQUNaLFVBQVM7RUFDVCxXQUFVLEVBQ1g7O0FBRUQ7RUFDRSxhQUFZLEVBQ2I7O0FBRUQ7RUFDRSxhQUFZLEVBQ2I7O0FDN0NELHdFQUF3RTtBQUN4RTtFQ1NJLDRESlZvRDtFSWdDbEQsZ0JKN0J3QjtFSTZCeEIsaUJKZmdCO0VHZHBCLHdCSkljLEVJSGY7O0FBRUQ7RUNxQ0UsZUwxQ3lCO0VLMkN6QixzQkFBcUIsRURwQ3RCOztBQUVEO0VFTkUsMEVBQTBFO0VBc0QxRSx5RUFBeUUsRUY5QzFFO0VBRkQ7SUVETSxtQkFBa0IsRUFDbkI7RUZBTDtJR0pFLGlCTEhvQjtJS0lwQixvQkxKb0IsRUkwQmY7RUZuQlA7SUV1QlEsY0FBYSxFQUNkO0VGeEJQO0lFMEJRLGlCQUFnQixFQUNqQjtFRjNCUDtJRThCTSxzQkFBcUIsRUFDdEI7RUYvQkw7SUVrQ1EsbUJBQXlCLEVBQzFCO0VGbkNQO0lFdUNJLGVBQWEsRUFJZDtJRTRMSztNSnZPUjtRS1RFLGdCQUFjO1FBQ2QsZUFBYTtRQUNiLGFBQVcsRUhrRFYsRUFBQTtFRjNDSDtJRTZDSSxZQUFXLEVBQ1o7O0FGMUNIO0VBQ0Usb0NBQTJCO0VBQTNCLCtCQUEyQjtFQUEzQiw0QkFBMkIsRUFDNUI7O0FBRUQ7RUN5QkUsZUwxQ3lCO0VLMkN6QixzQkFBcUIsRUR4QnRCOztBQUVEO0VDcUJFLGVMMUN5QjtFSzJDekIsc0JBQXFCO0VLM0NyQixhQUFXO0VBQ1gsaUJBQWU7RUFDZix5QkFBZTtVQUFmLGlCQUFlO0VBQ2YsV0FBUyxFTnFCVjs7QU94QkQ7RUFDRSxnQkFBZTtFQUNmLFNBQVE7RUFDUixVQUFTO0VBQ1QsV0FBVSxFQUlYO0VBUkQ7SUFNSSxXQUFVLEVBQ1giLCJmaWxlIjoic3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiJF9hdmF0YXJfd2lkdGg6IDgwO1xuJF9hdmF0YXJfaGVpZ2h0OiA4MDtcbiRfaXMtZW52LWRldjogdHJ1ZTtcbi8qIVxuVGhlbWUgTmFtZTogICBUaW1iZXIgQm9pbGVycGxhdGUgVGhlbWVcblRoZW1lIFVSSTogICAgaHR0cHM6Ly9naXRodWIuY29tL2NlcnRhaW5seWFrZXkvdGltYmVyLWJvaWxlcnBsYXRlXG5EZXNjcmlwdGlvbjogIFRoaXMgaXMgYSBib2lsZXJwbGF0ZSB0aGVtZSB1c2luZyBUaW1iZXJcblZlcnNpb246ICAgICAgMS4wXG5BdXRob3I6ICAgICAgIEFsZWtzYW5kciBCZWxpYWV2XG5UZXh0IERvbWFpbjogIHRoZW1lX2RvbWFpblxuRG9tYWluIFBhdGg6ICAvbGFuZ3VhZ2VzL1xuKi9cblxuLy8gIURlcGVuZGVuY2llc1xuQGltcG9ydCAnZGVwZW5kZW5jaWVzJztcbkBpbXBvcnQgJ3ZlbmRvcnMnO1xuXG4vLyAhU2l0ZSBhYnN0cmFjdHNcbkBpbXBvcnQgJ2Fic3RyYWN0cy9mdW5jdGlvbnMnO1xuQGltcG9ydCAnYWJzdHJhY3RzL3ZhcmlhYmxlcy9jb2xvcnMnO1xuQGltcG9ydCAnYWJzdHJhY3RzL3ZhcmlhYmxlcy90eXBvZ3JhcGh5JztcbkBpbXBvcnQgJ2Fic3RyYWN0cy92YXJpYWJsZXMvb3RoZXJzJztcbkBpbXBvcnQgJ2Fic3RyYWN0cy9taXhpbnMnO1xuLy8gQGltcG9ydCAnYWJzdHJhY3RzL2FuaW1hdGlvbnMnO1xuQGltcG9ydCAnYWJzdHJhY3RzL3RleHRjb250ZW50LW1peGlucyc7XG5cbi8vICFCYXNlXG5AaW1wb3J0ICdiYXNlL2ZvbnRmYWNlJztcbkBpbXBvcnQgJ2Jhc2Uvbm9ybWFsaXplX3R3ZWFrcyc7XG5AaW1wb3J0ICdiYXNlL2Jhc2UnO1xuQGltcG9ydCAnYmFzZS9zY2FmZm9sZGluZyc7XG5cbi8vICFHZW5lcmF0ZWRcbi8vIEBpbXBvcnQgJ2F1dG9nZW5lcmF0ZWQvc3ZnLXNwcml0ZSc7XG5cbi8vICFDb21wb25lbnRzIFxuQGltcG9ydCAnY29tcG9uZW50cy9leGFtcGxlLWNvbXBvbmVudC9leGFtcGxlLWNvbXBvbmVudCc7XG5cbi8vIEFwcGx5IHRoZSBjb21wb25lbnRzIHRvIGNvcnJlc3BvbmRpbmcgY29tcG9uZW50IGNsYXNzZXNcbkBpbXBvcnQgJ2FwcGx5JztcbiIsIi8qIHN0eWxlbGludC1kaXNhYmxlIHBsdWdpbi9hdC1ydWxlLWltcG9ydC1wYXRoICovXG5cbi8vIFNBU1MgY29tcGlsZS10aW1lIGRlcGVuZGVuY2llc1xuQGltcG9ydCAnfnNhc3MtbXEvX21xLnNjc3MnO1xuQGltcG9ydCAnfmNvbW1vbi1zYXNzLXV0aWxpdGllcyc7XG5AaW1wb3J0ICd+c2Fzcy1yZW0nO1xuXG4vKiBzdHlsZWxpbnQtZW5hYmxlIHBsdWdpbi9hdC1ydWxlLWltcG9ydC1wYXRoICovXG4iLCIudS1zY3JlZW5yZWFkZXItdGV4dCB7XG4gIEBpbmNsdWRlIHUtc2NyZWVucmVhZGVyLXRleHQ7XG59XG5cbi5qcy1oaWRkZW4taWYtanMtb24ge1xuICAjeyRqcy1vbn0ge1xuICAgIGRpc3BsYXk6bm9uZTsgXG4gIH1cbn1cblxuLnUtaW5uZXItbGF5ZXIge1xuICBwb3NpdGlvbjpyZWxhdGl2ZTsgXG4gIHotaW5kZXg6MTsgXG59XG5cbi51LW5vd3JhcCB7XG4gIHdoaXRlLXNwYWNlOm5vd3JhcDtcbn1cblxuLmpzLWhpZGRlbixcbi51LWhpZGRlbiB7XG4gIGRpc3BsYXk6bm9uZTsgXG59XG4iLCJAbWl4aW4gdS1zY3JlZW5yZWFkZXItdGV4dCB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTsgXG4gIG92ZXJmbG93OiBoaWRkZW47IFxuICBjbGlwOiByZWN0KDAgMCAwIDApOyBcbiAgaGVpZ2h0OiAxcHg7IFxuICB3aWR0aDogMXB4OyBcbiAgbWFyZ2luOiAtMXB4OyBcbiAgcGFkZGluZzogMDsgXG4gIGJvcmRlcjogbm9uZTsgXG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG59IiwiLyogc3R5bGVsaW50LWRpc2FibGUgcGx1Z2luL2F0LXJ1bGUtaW1wb3J0LXBhdGggKi9cblxuLy8gQ1NTIGFuZCBKYXZhc2NyaXB0IGRlcGVuZGVuY2llc1xuLy8gVGhhbmtzIHRvIHNhc3MtbW9kdWxlLWltcG9ydGVyIGd1bHAgcGx1Z2luIHdlIGNhbiBpbXBvcnQgY3NzIGZpbGVzIGZyb20gbm9kZV9tb2R1bGVzIHdpdGhvdXQgcmVuYW1pbmcgbGlrZSB0aGlzOiBcIkBpbXBvcnQgJ2Z1bGxwYWdlLmpzL2Rpc3QvanF1ZXJ5LmZ1bGxwYWdlLm1pbi5jc3MnO1wiXG5AaW1wb3J0ICd+bm9ybWFsaXplLmNzcy9ub3JtYWxpemUuY3NzJztcblxuLyogc3R5bGVsaW50LWVuYWJsZSBwbHVnaW4vYXQtcnVsZS1pbXBvcnQtcGF0aCAqL1xuIiwiLyohIG5vcm1hbGl6ZS5jc3MgdjguMC4xIHwgTUlUIExpY2Vuc2UgfCBnaXRodWIuY29tL25lY29sYXMvbm9ybWFsaXplLmNzcyAqL1xuXG4vKiBEb2N1bWVudFxuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiAxLiBDb3JyZWN0IHRoZSBsaW5lIGhlaWdodCBpbiBhbGwgYnJvd3NlcnMuXG4gKiAyLiBQcmV2ZW50IGFkanVzdG1lbnRzIG9mIGZvbnQgc2l6ZSBhZnRlciBvcmllbnRhdGlvbiBjaGFuZ2VzIGluIGlPUy5cbiAqL1xuXG5odG1sIHtcbiAgbGluZS1oZWlnaHQ6IDEuMTU7IC8qIDEgKi9cbiAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAvKiAyICovXG59XG5cbi8qIFNlY3Rpb25zXG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4vKipcbiAqIFJlbW92ZSB0aGUgbWFyZ2luIGluIGFsbCBicm93c2Vycy5cbiAqL1xuXG5ib2R5IHtcbiAgbWFyZ2luOiAwO1xufVxuXG4vKipcbiAqIFJlbmRlciB0aGUgYG1haW5gIGVsZW1lbnQgY29uc2lzdGVudGx5IGluIElFLlxuICovXG5cbm1haW4ge1xuICBkaXNwbGF5OiBibG9jaztcbn1cblxuLyoqXG4gKiBDb3JyZWN0IHRoZSBmb250IHNpemUgYW5kIG1hcmdpbiBvbiBgaDFgIGVsZW1lbnRzIHdpdGhpbiBgc2VjdGlvbmAgYW5kXG4gKiBgYXJ0aWNsZWAgY29udGV4dHMgaW4gQ2hyb21lLCBGaXJlZm94LCBhbmQgU2FmYXJpLlxuICovXG5cbmgxIHtcbiAgZm9udC1zaXplOiAyZW07XG4gIG1hcmdpbjogMC42N2VtIDA7XG59XG5cbi8qIEdyb3VwaW5nIGNvbnRlbnRcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qKlxuICogMS4gQWRkIHRoZSBjb3JyZWN0IGJveCBzaXppbmcgaW4gRmlyZWZveC5cbiAqIDIuIFNob3cgdGhlIG92ZXJmbG93IGluIEVkZ2UgYW5kIElFLlxuICovXG5cbmhyIHtcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7IC8qIDEgKi9cbiAgaGVpZ2h0OiAwOyAvKiAxICovXG4gIG92ZXJmbG93OiB2aXNpYmxlOyAvKiAyICovXG59XG5cbi8qKlxuICogMS4gQ29ycmVjdCB0aGUgaW5oZXJpdGFuY2UgYW5kIHNjYWxpbmcgb2YgZm9udCBzaXplIGluIGFsbCBicm93c2Vycy5cbiAqIDIuIENvcnJlY3QgdGhlIG9kZCBgZW1gIGZvbnQgc2l6aW5nIGluIGFsbCBicm93c2Vycy5cbiAqL1xuXG5wcmUge1xuICBmb250LWZhbWlseTogbW9ub3NwYWNlLCBtb25vc3BhY2U7IC8qIDEgKi9cbiAgZm9udC1zaXplOiAxZW07IC8qIDIgKi9cbn1cblxuLyogVGV4dC1sZXZlbCBzZW1hbnRpY3NcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qKlxuICogUmVtb3ZlIHRoZSBncmF5IGJhY2tncm91bmQgb24gYWN0aXZlIGxpbmtzIGluIElFIDEwLlxuICovXG5cbmEge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbn1cblxuLyoqXG4gKiAxLiBSZW1vdmUgdGhlIGJvdHRvbSBib3JkZXIgaW4gQ2hyb21lIDU3LVxuICogMi4gQWRkIHRoZSBjb3JyZWN0IHRleHQgZGVjb3JhdGlvbiBpbiBDaHJvbWUsIEVkZ2UsIElFLCBPcGVyYSwgYW5kIFNhZmFyaS5cbiAqL1xuXG5hYmJyW3RpdGxlXSB7XG4gIGJvcmRlci1ib3R0b206IG5vbmU7IC8qIDEgKi9cbiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IC8qIDIgKi9cbiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmUgZG90dGVkOyAvKiAyICovXG59XG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGZvbnQgd2VpZ2h0IGluIENocm9tZSwgRWRnZSwgYW5kIFNhZmFyaS5cbiAqL1xuXG5iLFxuc3Ryb25nIHtcbiAgZm9udC13ZWlnaHQ6IGJvbGRlcjtcbn1cblxuLyoqXG4gKiAxLiBDb3JyZWN0IHRoZSBpbmhlcml0YW5jZSBhbmQgc2NhbGluZyBvZiBmb250IHNpemUgaW4gYWxsIGJyb3dzZXJzLlxuICogMi4gQ29ycmVjdCB0aGUgb2RkIGBlbWAgZm9udCBzaXppbmcgaW4gYWxsIGJyb3dzZXJzLlxuICovXG5cbmNvZGUsXG5rYmQsXG5zYW1wIHtcbiAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZSwgbW9ub3NwYWNlOyAvKiAxICovXG4gIGZvbnQtc2l6ZTogMWVtOyAvKiAyICovXG59XG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxuc21hbGwge1xuICBmb250LXNpemU6IDgwJTtcbn1cblxuLyoqXG4gKiBQcmV2ZW50IGBzdWJgIGFuZCBgc3VwYCBlbGVtZW50cyBmcm9tIGFmZmVjdGluZyB0aGUgbGluZSBoZWlnaHQgaW5cbiAqIGFsbCBicm93c2Vycy5cbiAqL1xuXG5zdWIsXG5zdXAge1xuICBmb250LXNpemU6IDc1JTtcbiAgbGluZS1oZWlnaHQ6IDA7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgdmVydGljYWwtYWxpZ246IGJhc2VsaW5lO1xufVxuXG5zdWIge1xuICBib3R0b206IC0wLjI1ZW07XG59XG5cbnN1cCB7XG4gIHRvcDogLTAuNWVtO1xufVxuXG4vKiBFbWJlZGRlZCBjb250ZW50XG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4vKipcbiAqIFJlbW92ZSB0aGUgYm9yZGVyIG9uIGltYWdlcyBpbnNpZGUgbGlua3MgaW4gSUUgMTAuXG4gKi9cblxuaW1nIHtcbiAgYm9yZGVyLXN0eWxlOiBub25lO1xufVxuXG4vKiBGb3Jtc1xuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiAxLiBDaGFuZ2UgdGhlIGZvbnQgc3R5bGVzIGluIGFsbCBicm93c2Vycy5cbiAqIDIuIFJlbW92ZSB0aGUgbWFyZ2luIGluIEZpcmVmb3ggYW5kIFNhZmFyaS5cbiAqL1xuXG5idXR0b24sXG5pbnB1dCxcbm9wdGdyb3VwLFxuc2VsZWN0LFxudGV4dGFyZWEge1xuICBmb250LWZhbWlseTogaW5oZXJpdDsgLyogMSAqL1xuICBmb250LXNpemU6IDEwMCU7IC8qIDEgKi9cbiAgbGluZS1oZWlnaHQ6IDEuMTU7IC8qIDEgKi9cbiAgbWFyZ2luOiAwOyAvKiAyICovXG59XG5cbi8qKlxuICogU2hvdyB0aGUgb3ZlcmZsb3cgaW4gSUUuXG4gKiAxLiBTaG93IHRoZSBvdmVyZmxvdyBpbiBFZGdlLlxuICovXG5cbmJ1dHRvbixcbmlucHV0IHsgLyogMSAqL1xuICBvdmVyZmxvdzogdmlzaWJsZTtcbn1cblxuLyoqXG4gKiBSZW1vdmUgdGhlIGluaGVyaXRhbmNlIG9mIHRleHQgdHJhbnNmb3JtIGluIEVkZ2UsIEZpcmVmb3gsIGFuZCBJRS5cbiAqIDEuIFJlbW92ZSB0aGUgaW5oZXJpdGFuY2Ugb2YgdGV4dCB0cmFuc2Zvcm0gaW4gRmlyZWZveC5cbiAqL1xuXG5idXR0b24sXG5zZWxlY3QgeyAvKiAxICovXG4gIHRleHQtdHJhbnNmb3JtOiBub25lO1xufVxuXG4vKipcbiAqIENvcnJlY3QgdGhlIGluYWJpbGl0eSB0byBzdHlsZSBjbGlja2FibGUgdHlwZXMgaW4gaU9TIGFuZCBTYWZhcmkuXG4gKi9cblxuYnV0dG9uLFxuW3R5cGU9XCJidXR0b25cIl0sXG5bdHlwZT1cInJlc2V0XCJdLFxuW3R5cGU9XCJzdWJtaXRcIl0ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IGJ1dHRvbjtcbn1cblxuLyoqXG4gKiBSZW1vdmUgdGhlIGlubmVyIGJvcmRlciBhbmQgcGFkZGluZyBpbiBGaXJlZm94LlxuICovXG5cbmJ1dHRvbjo6LW1vei1mb2N1cy1pbm5lcixcblt0eXBlPVwiYnV0dG9uXCJdOjotbW96LWZvY3VzLWlubmVyLFxuW3R5cGU9XCJyZXNldFwiXTo6LW1vei1mb2N1cy1pbm5lcixcblt0eXBlPVwic3VibWl0XCJdOjotbW96LWZvY3VzLWlubmVyIHtcbiAgYm9yZGVyLXN0eWxlOiBub25lO1xuICBwYWRkaW5nOiAwO1xufVxuXG4vKipcbiAqIFJlc3RvcmUgdGhlIGZvY3VzIHN0eWxlcyB1bnNldCBieSB0aGUgcHJldmlvdXMgcnVsZS5cbiAqL1xuXG5idXR0b246LW1vei1mb2N1c3JpbmcsXG5bdHlwZT1cImJ1dHRvblwiXTotbW96LWZvY3VzcmluZyxcblt0eXBlPVwicmVzZXRcIl06LW1vei1mb2N1c3JpbmcsXG5bdHlwZT1cInN1Ym1pdFwiXTotbW96LWZvY3VzcmluZyB7XG4gIG91dGxpbmU6IDFweCBkb3R0ZWQgQnV0dG9uVGV4dDtcbn1cblxuLyoqXG4gKiBDb3JyZWN0IHRoZSBwYWRkaW5nIGluIEZpcmVmb3guXG4gKi9cblxuZmllbGRzZXQge1xuICBwYWRkaW5nOiAwLjM1ZW0gMC43NWVtIDAuNjI1ZW07XG59XG5cbi8qKlxuICogMS4gQ29ycmVjdCB0aGUgdGV4dCB3cmFwcGluZyBpbiBFZGdlIGFuZCBJRS5cbiAqIDIuIENvcnJlY3QgdGhlIGNvbG9yIGluaGVyaXRhbmNlIGZyb20gYGZpZWxkc2V0YCBlbGVtZW50cyBpbiBJRS5cbiAqIDMuIFJlbW92ZSB0aGUgcGFkZGluZyBzbyBkZXZlbG9wZXJzIGFyZSBub3QgY2F1Z2h0IG91dCB3aGVuIHRoZXkgemVybyBvdXRcbiAqICAgIGBmaWVsZHNldGAgZWxlbWVudHMgaW4gYWxsIGJyb3dzZXJzLlxuICovXG5cbmxlZ2VuZCB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7IC8qIDEgKi9cbiAgY29sb3I6IGluaGVyaXQ7IC8qIDIgKi9cbiAgZGlzcGxheTogdGFibGU7IC8qIDEgKi9cbiAgbWF4LXdpZHRoOiAxMDAlOyAvKiAxICovXG4gIHBhZGRpbmc6IDA7IC8qIDMgKi9cbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDsgLyogMSAqL1xufVxuXG4vKipcbiAqIEFkZCB0aGUgY29ycmVjdCB2ZXJ0aWNhbCBhbGlnbm1lbnQgaW4gQ2hyb21lLCBGaXJlZm94LCBhbmQgT3BlcmEuXG4gKi9cblxucHJvZ3Jlc3Mge1xuICB2ZXJ0aWNhbC1hbGlnbjogYmFzZWxpbmU7XG59XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBkZWZhdWx0IHZlcnRpY2FsIHNjcm9sbGJhciBpbiBJRSAxMCsuXG4gKi9cblxudGV4dGFyZWEge1xuICBvdmVyZmxvdzogYXV0bztcbn1cblxuLyoqXG4gKiAxLiBBZGQgdGhlIGNvcnJlY3QgYm94IHNpemluZyBpbiBJRSAxMC5cbiAqIDIuIFJlbW92ZSB0aGUgcGFkZGluZyBpbiBJRSAxMC5cbiAqL1xuXG5bdHlwZT1cImNoZWNrYm94XCJdLFxuW3R5cGU9XCJyYWRpb1wiXSB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7IC8qIDEgKi9cbiAgcGFkZGluZzogMDsgLyogMiAqL1xufVxuXG4vKipcbiAqIENvcnJlY3QgdGhlIGN1cnNvciBzdHlsZSBvZiBpbmNyZW1lbnQgYW5kIGRlY3JlbWVudCBidXR0b25zIGluIENocm9tZS5cbiAqL1xuXG5bdHlwZT1cIm51bWJlclwiXTo6LXdlYmtpdC1pbm5lci1zcGluLWJ1dHRvbixcblt0eXBlPVwibnVtYmVyXCJdOjotd2Via2l0LW91dGVyLXNwaW4tYnV0dG9uIHtcbiAgaGVpZ2h0OiBhdXRvO1xufVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIG9kZCBhcHBlYXJhbmNlIGluIENocm9tZSBhbmQgU2FmYXJpLlxuICogMi4gQ29ycmVjdCB0aGUgb3V0bGluZSBzdHlsZSBpbiBTYWZhcmkuXG4gKi9cblxuW3R5cGU9XCJzZWFyY2hcIl0ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IHRleHRmaWVsZDsgLyogMSAqL1xuICBvdXRsaW5lLW9mZnNldDogLTJweDsgLyogMiAqL1xufVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgaW5uZXIgcGFkZGluZyBpbiBDaHJvbWUgYW5kIFNhZmFyaSBvbiBtYWNPUy5cbiAqL1xuXG5bdHlwZT1cInNlYXJjaFwiXTo6LXdlYmtpdC1zZWFyY2gtZGVjb3JhdGlvbiB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTtcbn1cblxuLyoqXG4gKiAxLiBDb3JyZWN0IHRoZSBpbmFiaWxpdHkgdG8gc3R5bGUgY2xpY2thYmxlIHR5cGVzIGluIGlPUyBhbmQgU2FmYXJpLlxuICogMi4gQ2hhbmdlIGZvbnQgcHJvcGVydGllcyB0byBgaW5oZXJpdGAgaW4gU2FmYXJpLlxuICovXG5cbjo6LXdlYmtpdC1maWxlLXVwbG9hZC1idXR0b24ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IGJ1dHRvbjsgLyogMSAqL1xuICBmb250OiBpbmhlcml0OyAvKiAyICovXG59XG5cbi8qIEludGVyYWN0aXZlXG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4vKlxuICogQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gRWRnZSwgSUUgMTArLCBhbmQgRmlyZWZveC5cbiAqL1xuXG5kZXRhaWxzIHtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi8qXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cblxuc3VtbWFyeSB7XG4gIGRpc3BsYXk6IGxpc3QtaXRlbTtcbn1cblxuLyogTWlzY1xuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRSAxMCsuXG4gKi9cblxudGVtcGxhdGUge1xuICBkaXNwbGF5OiBub25lO1xufVxuXG4vKipcbiAqIEFkZCB0aGUgY29ycmVjdCBkaXNwbGF5IGluIElFIDEwLlxuICovXG5cbltoaWRkZW5dIHtcbiAgZGlzcGxheTogbm9uZTtcbn1cbiIsIi8qIVxuVGhlbWUgTmFtZTogICBUaW1iZXIgQm9pbGVycGxhdGUgVGhlbWVcblRoZW1lIFVSSTogICAgaHR0cHM6Ly9naXRodWIuY29tL2NlcnRhaW5seWFrZXkvdGltYmVyLWJvaWxlcnBsYXRlXG5EZXNjcmlwdGlvbjogIFRoaXMgaXMgYSBib2lsZXJwbGF0ZSB0aGVtZSB1c2luZyBUaW1iZXJcblZlcnNpb246ICAgICAgMS4wXG5BdXRob3I6ICAgICAgIEFsZWtzYW5kciBCZWxpYWV2XG5UZXh0IERvbWFpbjogIHRoZW1lX2RvbWFpblxuRG9tYWluIFBhdGg6ICAvbGFuZ3VhZ2VzL1xuKi9cbi8qIHN0eWxlbGludC1kaXNhYmxlIHBsdWdpbi9hdC1ydWxlLWltcG9ydC1wYXRoICovXG4udS1zY3JlZW5yZWFkZXItdGV4dCB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgY2xpcDogcmVjdCgwIDAgMCAwKTtcbiAgaGVpZ2h0OiAxcHg7XG4gIHdpZHRoOiAxcHg7XG4gIG1hcmdpbjogLTFweDtcbiAgcGFkZGluZzogMDtcbiAgYm9yZGVyOiBub25lO1xuICB3aGl0ZS1zcGFjZTogbm93cmFwOyB9XG5cbmh0bWw6bm90KC5uby1qcykgLmpzLWhpZGRlbi1pZi1qcy1vbiB7XG4gIGRpc3BsYXk6IG5vbmU7IH1cblxuLnUtaW5uZXItbGF5ZXIge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHotaW5kZXg6IDE7IH1cblxuLnUtbm93cmFwIHtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDsgfVxuXG4uanMtaGlkZGVuLFxuLnUtaGlkZGVuIHtcbiAgZGlzcGxheTogbm9uZTsgfVxuXG4vKiBzdHlsZWxpbnQtZW5hYmxlIHBsdWdpbi9hdC1ydWxlLWltcG9ydC1wYXRoICovXG4vKiBzdHlsZWxpbnQtZGlzYWJsZSBwbHVnaW4vYXQtcnVsZS1pbXBvcnQtcGF0aCAqL1xuLyohIG5vcm1hbGl6ZS5jc3MgdjguMC4xIHwgTUlUIExpY2Vuc2UgfCBnaXRodWIuY29tL25lY29sYXMvbm9ybWFsaXplLmNzcyAqL1xuLyogRG9jdW1lbnRcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGxpbmUgaGVpZ2h0IGluIGFsbCBicm93c2Vycy5cbiAqIDIuIFByZXZlbnQgYWRqdXN0bWVudHMgb2YgZm9udCBzaXplIGFmdGVyIG9yaWVudGF0aW9uIGNoYW5nZXMgaW4gaU9TLlxuICovXG5odG1sIHtcbiAgbGluZS1oZWlnaHQ6IDEuMTU7XG4gIC8qIDEgKi9cbiAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlO1xuICAvKiAyICovIH1cblxuLyogU2VjdGlvbnNcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG4vKipcbiAqIFJlbW92ZSB0aGUgbWFyZ2luIGluIGFsbCBicm93c2Vycy5cbiAqL1xuYm9keSB7XG4gIG1hcmdpbjogMDsgfVxuXG4vKipcbiAqIFJlbmRlciB0aGUgYG1haW5gIGVsZW1lbnQgY29uc2lzdGVudGx5IGluIElFLlxuICovXG5tYWluIHtcbiAgZGlzcGxheTogYmxvY2s7IH1cblxuLyoqXG4gKiBDb3JyZWN0IHRoZSBmb250IHNpemUgYW5kIG1hcmdpbiBvbiBgaDFgIGVsZW1lbnRzIHdpdGhpbiBgc2VjdGlvbmAgYW5kXG4gKiBgYXJ0aWNsZWAgY29udGV4dHMgaW4gQ2hyb21lLCBGaXJlZm94LCBhbmQgU2FmYXJpLlxuICovXG5oMSB7XG4gIGZvbnQtc2l6ZTogMmVtO1xuICBtYXJnaW46IDAuNjdlbSAwOyB9XG5cbi8qIEdyb3VwaW5nIGNvbnRlbnRcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG4vKipcbiAqIDEuIEFkZCB0aGUgY29ycmVjdCBib3ggc2l6aW5nIGluIEZpcmVmb3guXG4gKiAyLiBTaG93IHRoZSBvdmVyZmxvdyBpbiBFZGdlIGFuZCBJRS5cbiAqL1xuaHIge1xuICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbiAgLyogMSAqL1xuICBoZWlnaHQ6IDA7XG4gIC8qIDEgKi9cbiAgb3ZlcmZsb3c6IHZpc2libGU7XG4gIC8qIDIgKi8gfVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluaGVyaXRhbmNlIGFuZCBzY2FsaW5nIG9mIGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuXG4gKiAyLiBDb3JyZWN0IHRoZSBvZGQgYGVtYCBmb250IHNpemluZyBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cbnByZSB7XG4gIGZvbnQtZmFtaWx5OiBtb25vc3BhY2UsIG1vbm9zcGFjZTtcbiAgLyogMSAqL1xuICBmb250LXNpemU6IDFlbTtcbiAgLyogMiAqLyB9XG5cbi8qIFRleHQtbGV2ZWwgc2VtYW50aWNzXG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuLyoqXG4gKiBSZW1vdmUgdGhlIGdyYXkgYmFja2dyb3VuZCBvbiBhY3RpdmUgbGlua3MgaW4gSUUgMTAuXG4gKi9cbmEge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDsgfVxuXG4vKipcbiAqIDEuIFJlbW92ZSB0aGUgYm90dG9tIGJvcmRlciBpbiBDaHJvbWUgNTctXG4gKiAyLiBBZGQgdGhlIGNvcnJlY3QgdGV4dCBkZWNvcmF0aW9uIGluIENocm9tZSwgRWRnZSwgSUUsIE9wZXJhLCBhbmQgU2FmYXJpLlxuICovXG5hYmJyW3RpdGxlXSB7XG4gIGJvcmRlci1ib3R0b206IG5vbmU7XG4gIC8qIDEgKi9cbiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG4gIC8qIDIgKi9cbiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmUgZG90dGVkO1xuICAvKiAyICovIH1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZm9udCB3ZWlnaHQgaW4gQ2hyb21lLCBFZGdlLCBhbmQgU2FmYXJpLlxuICovXG5iLFxuc3Ryb25nIHtcbiAgZm9udC13ZWlnaHQ6IGJvbGRlcjsgfVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluaGVyaXRhbmNlIGFuZCBzY2FsaW5nIG9mIGZvbnQgc2l6ZSBpbiBhbGwgYnJvd3NlcnMuXG4gKiAyLiBDb3JyZWN0IHRoZSBvZGQgYGVtYCBmb250IHNpemluZyBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cbmNvZGUsXG5rYmQsXG5zYW1wIHtcbiAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZSwgbW9ub3NwYWNlO1xuICAvKiAxICovXG4gIGZvbnQtc2l6ZTogMWVtO1xuICAvKiAyICovIH1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZm9udCBzaXplIGluIGFsbCBicm93c2Vycy5cbiAqL1xuc21hbGwge1xuICBmb250LXNpemU6IDgwJTsgfVxuXG4vKipcbiAqIFByZXZlbnQgYHN1YmAgYW5kIGBzdXBgIGVsZW1lbnRzIGZyb20gYWZmZWN0aW5nIHRoZSBsaW5lIGhlaWdodCBpblxuICogYWxsIGJyb3dzZXJzLlxuICovXG5zdWIsXG5zdXAge1xuICBmb250LXNpemU6IDc1JTtcbiAgbGluZS1oZWlnaHQ6IDA7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgdmVydGljYWwtYWxpZ246IGJhc2VsaW5lOyB9XG5cbnN1YiB7XG4gIGJvdHRvbTogLTAuMjVlbTsgfVxuXG5zdXAge1xuICB0b3A6IC0wLjVlbTsgfVxuXG4vKiBFbWJlZGRlZCBjb250ZW50XG4gICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuLyoqXG4gKiBSZW1vdmUgdGhlIGJvcmRlciBvbiBpbWFnZXMgaW5zaWRlIGxpbmtzIGluIElFIDEwLlxuICovXG5pbWcge1xuICBib3JkZXItc3R5bGU6IG5vbmU7IH1cblxuLyogRm9ybXNcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG4vKipcbiAqIDEuIENoYW5nZSB0aGUgZm9udCBzdHlsZXMgaW4gYWxsIGJyb3dzZXJzLlxuICogMi4gUmVtb3ZlIHRoZSBtYXJnaW4gaW4gRmlyZWZveCBhbmQgU2FmYXJpLlxuICovXG5idXR0b24sXG5pbnB1dCxcbm9wdGdyb3VwLFxuc2VsZWN0LFxudGV4dGFyZWEge1xuICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgLyogMSAqL1xuICBmb250LXNpemU6IDEwMCU7XG4gIC8qIDEgKi9cbiAgbGluZS1oZWlnaHQ6IDEuMTU7XG4gIC8qIDEgKi9cbiAgbWFyZ2luOiAwO1xuICAvKiAyICovIH1cblxuLyoqXG4gKiBTaG93IHRoZSBvdmVyZmxvdyBpbiBJRS5cbiAqIDEuIFNob3cgdGhlIG92ZXJmbG93IGluIEVkZ2UuXG4gKi9cbmJ1dHRvbixcbmlucHV0IHtcbiAgLyogMSAqL1xuICBvdmVyZmxvdzogdmlzaWJsZTsgfVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgaW5oZXJpdGFuY2Ugb2YgdGV4dCB0cmFuc2Zvcm0gaW4gRWRnZSwgRmlyZWZveCwgYW5kIElFLlxuICogMS4gUmVtb3ZlIHRoZSBpbmhlcml0YW5jZSBvZiB0ZXh0IHRyYW5zZm9ybSBpbiBGaXJlZm94LlxuICovXG5idXR0b24sXG5zZWxlY3Qge1xuICAvKiAxICovXG4gIHRleHQtdHJhbnNmb3JtOiBub25lOyB9XG5cbi8qKlxuICogQ29ycmVjdCB0aGUgaW5hYmlsaXR5IHRvIHN0eWxlIGNsaWNrYWJsZSB0eXBlcyBpbiBpT1MgYW5kIFNhZmFyaS5cbiAqL1xuYnV0dG9uLFxuW3R5cGU9XCJidXR0b25cIl0sXG5bdHlwZT1cInJlc2V0XCJdLFxuW3R5cGU9XCJzdWJtaXRcIl0ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IGJ1dHRvbjsgfVxuXG4vKipcbiAqIFJlbW92ZSB0aGUgaW5uZXIgYm9yZGVyIGFuZCBwYWRkaW5nIGluIEZpcmVmb3guXG4gKi9cbmJ1dHRvbjo6LW1vei1mb2N1cy1pbm5lcixcblt0eXBlPVwiYnV0dG9uXCJdOjotbW96LWZvY3VzLWlubmVyLFxuW3R5cGU9XCJyZXNldFwiXTo6LW1vei1mb2N1cy1pbm5lcixcblt0eXBlPVwic3VibWl0XCJdOjotbW96LWZvY3VzLWlubmVyIHtcbiAgYm9yZGVyLXN0eWxlOiBub25lO1xuICBwYWRkaW5nOiAwOyB9XG5cbi8qKlxuICogUmVzdG9yZSB0aGUgZm9jdXMgc3R5bGVzIHVuc2V0IGJ5IHRoZSBwcmV2aW91cyBydWxlLlxuICovXG5idXR0b246LW1vei1mb2N1c3JpbmcsXG5bdHlwZT1cImJ1dHRvblwiXTotbW96LWZvY3VzcmluZyxcblt0eXBlPVwicmVzZXRcIl06LW1vei1mb2N1c3JpbmcsXG5bdHlwZT1cInN1Ym1pdFwiXTotbW96LWZvY3VzcmluZyB7XG4gIG91dGxpbmU6IDFweCBkb3R0ZWQgQnV0dG9uVGV4dDsgfVxuXG4vKipcbiAqIENvcnJlY3QgdGhlIHBhZGRpbmcgaW4gRmlyZWZveC5cbiAqL1xuZmllbGRzZXQge1xuICBwYWRkaW5nOiAwLjM1ZW0gMC43NWVtIDAuNjI1ZW07IH1cblxuLyoqXG4gKiAxLiBDb3JyZWN0IHRoZSB0ZXh0IHdyYXBwaW5nIGluIEVkZ2UgYW5kIElFLlxuICogMi4gQ29ycmVjdCB0aGUgY29sb3IgaW5oZXJpdGFuY2UgZnJvbSBgZmllbGRzZXRgIGVsZW1lbnRzIGluIElFLlxuICogMy4gUmVtb3ZlIHRoZSBwYWRkaW5nIHNvIGRldmVsb3BlcnMgYXJlIG5vdCBjYXVnaHQgb3V0IHdoZW4gdGhleSB6ZXJvIG91dFxuICogICAgYGZpZWxkc2V0YCBlbGVtZW50cyBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cbmxlZ2VuZCB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIC8qIDEgKi9cbiAgY29sb3I6IGluaGVyaXQ7XG4gIC8qIDIgKi9cbiAgZGlzcGxheTogdGFibGU7XG4gIC8qIDEgKi9cbiAgbWF4LXdpZHRoOiAxMDAlO1xuICAvKiAxICovXG4gIHBhZGRpbmc6IDA7XG4gIC8qIDMgKi9cbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbiAgLyogMSAqLyB9XG5cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IHZlcnRpY2FsIGFsaWdubWVudCBpbiBDaHJvbWUsIEZpcmVmb3gsIGFuZCBPcGVyYS5cbiAqL1xucHJvZ3Jlc3Mge1xuICB2ZXJ0aWNhbC1hbGlnbjogYmFzZWxpbmU7IH1cblxuLyoqXG4gKiBSZW1vdmUgdGhlIGRlZmF1bHQgdmVydGljYWwgc2Nyb2xsYmFyIGluIElFIDEwKy5cbiAqL1xudGV4dGFyZWEge1xuICBvdmVyZmxvdzogYXV0bzsgfVxuXG4vKipcbiAqIDEuIEFkZCB0aGUgY29ycmVjdCBib3ggc2l6aW5nIGluIElFIDEwLlxuICogMi4gUmVtb3ZlIHRoZSBwYWRkaW5nIGluIElFIDEwLlxuICovXG5bdHlwZT1cImNoZWNrYm94XCJdLFxuW3R5cGU9XCJyYWRpb1wiXSB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIC8qIDEgKi9cbiAgcGFkZGluZzogMDtcbiAgLyogMiAqLyB9XG5cbi8qKlxuICogQ29ycmVjdCB0aGUgY3Vyc29yIHN0eWxlIG9mIGluY3JlbWVudCBhbmQgZGVjcmVtZW50IGJ1dHRvbnMgaW4gQ2hyb21lLlxuICovXG5bdHlwZT1cIm51bWJlclwiXTo6LXdlYmtpdC1pbm5lci1zcGluLWJ1dHRvbixcblt0eXBlPVwibnVtYmVyXCJdOjotd2Via2l0LW91dGVyLXNwaW4tYnV0dG9uIHtcbiAgaGVpZ2h0OiBhdXRvOyB9XG5cbi8qKlxuICogMS4gQ29ycmVjdCB0aGUgb2RkIGFwcGVhcmFuY2UgaW4gQ2hyb21lIGFuZCBTYWZhcmkuXG4gKiAyLiBDb3JyZWN0IHRoZSBvdXRsaW5lIHN0eWxlIGluIFNhZmFyaS5cbiAqL1xuW3R5cGU9XCJzZWFyY2hcIl0ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IHRleHRmaWVsZDtcbiAgLyogMSAqL1xuICBvdXRsaW5lLW9mZnNldDogLTJweDtcbiAgLyogMiAqLyB9XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBpbm5lciBwYWRkaW5nIGluIENocm9tZSBhbmQgU2FmYXJpIG9uIG1hY09TLlxuICovXG5bdHlwZT1cInNlYXJjaFwiXTo6LXdlYmtpdC1zZWFyY2gtZGVjb3JhdGlvbiB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTsgfVxuXG4vKipcbiAqIDEuIENvcnJlY3QgdGhlIGluYWJpbGl0eSB0byBzdHlsZSBjbGlja2FibGUgdHlwZXMgaW4gaU9TIGFuZCBTYWZhcmkuXG4gKiAyLiBDaGFuZ2UgZm9udCBwcm9wZXJ0aWVzIHRvIGBpbmhlcml0YCBpbiBTYWZhcmkuXG4gKi9cbjo6LXdlYmtpdC1maWxlLXVwbG9hZC1idXR0b24ge1xuICAtd2Via2l0LWFwcGVhcmFuY2U6IGJ1dHRvbjtcbiAgLyogMSAqL1xuICBmb250OiBpbmhlcml0O1xuICAvKiAyICovIH1cblxuLyogSW50ZXJhY3RpdmVcbiAgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG4vKlxuICogQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gRWRnZSwgSUUgMTArLCBhbmQgRmlyZWZveC5cbiAqL1xuZGV0YWlscyB7XG4gIGRpc3BsYXk6IGJsb2NrOyB9XG5cbi8qXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBhbGwgYnJvd3NlcnMuXG4gKi9cbnN1bW1hcnkge1xuICBkaXNwbGF5OiBsaXN0LWl0ZW07IH1cblxuLyogTWlzY1xuICAgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cbi8qKlxuICogQWRkIHRoZSBjb3JyZWN0IGRpc3BsYXkgaW4gSUUgMTArLlxuICovXG50ZW1wbGF0ZSB7XG4gIGRpc3BsYXk6IG5vbmU7IH1cblxuLyoqXG4gKiBBZGQgdGhlIGNvcnJlY3QgZGlzcGxheSBpbiBJRSAxMC5cbiAqL1xuW2hpZGRlbl0ge1xuICBkaXNwbGF5OiBub25lOyB9XG5cbi8qIHN0eWxlbGludC1lbmFibGUgcGx1Z2luL2F0LXJ1bGUtaW1wb3J0LXBhdGggKi9cbi8qIHN0eWxlbGludC1kaXNhYmxlIGNvbG9yLW5vLWhleCAqL1xuLyogc3R5bGVsaW50LWRpc2FibGUgaW5kZW50YXRpb24gKi9cbi8qIHN0eWxlbGludC1lbmFibGUgaW5kZW50YXRpb24gKi9cbi8qIHN0eWxlbGludC1kaXNhYmxlIG1lb3d0ZWMvbm8tcHggKi9cbi8qIHN0eWxlbGludC1lbmFibGUgbWVvd3RlYy9uby1weCAqL1xuLyogc3R5bGVsaW50LWRpc2FibGUgc2VsZWN0b3ItbWF4LXVuaXZlcnNhbCwgc2VsZWN0b3ItbWF4LXR5cGUgKi9cbmgxLCBoMiwgaDMsIGg0LCBoNSwgaDYsIHAsIGRsLCBkZCwgdWwsIG9sLCBsaSwgZmlndXJlIHtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwOyB9XG5cbmgxLCBoMiwgaDMsIGg0LCBoNSwgaDYge1xuICBmb250LXdlaWdodDogbm9ybWFsO1xuICBmb250LXNpemU6IDEwMCU7IH1cblxudWwge1xuICBsaXN0LXN0eWxlOiBub25lOyB9XG5cbmh0bWwge1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94OyB9XG5cbiosICo6OmJlZm9yZSwgKjo6YWZ0ZXIge1xuICBib3gtc2l6aW5nOiBpbmhlcml0OyB9XG5cbm9sLCB1bCB7XG4gIGxpc3Qtc3R5bGUtcG9zaXRpb246IGluc2lkZTsgfVxuXG50ZXh0YXJlYSB7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgcmVzaXplOiB2ZXJ0aWNhbDsgfVxuXG5maWVsZHNldCB7XG4gIGJvcmRlcjogbm9uZTtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwOyB9XG5cbnNlbGVjdCB7XG4gIGNvbG9yOiBibGFjazsgfVxuXG5pZnJhbWUge1xuICBib3JkZXI6IG5vbmU7IH1cblxuLyogc3R5bGVsaW50LWRpc2FibGUgZGVjbGFyYXRpb24tbm8taW1wb3J0YW50LCBzZWxlY3Rvci1tYXgtdW5pdmVyc2FsICovXG5ib2R5IHtcbiAgZm9udC1mYW1pbHk6IFwiSGVsdmV0aWNhIE5ldWVcIiwgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZjtcbiAgZm9udC1zaXplOiAxNnB4O1xuICBsaW5lLWhlaWdodDogMS42O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsgfVxuXG5hIHtcbiAgY29sb3I6ICNlZTJkMjk7XG4gIHRleHQtZGVjb3JhdGlvbjogbm9uZTsgfVxuXG4ucy10ZXh0Y29udGVudCB7XG4gIC8qIHN0eWxlbGludC1kaXNhYmxlIHNlbGVjdG9yLW1heC10eXBlLCBzZWxlY3Rvci1tYXgtY29tcG91bmQtc2VsZWN0b3JzICovXG4gIC8qIHN0eWxlbGludC1lbmFibGUgc2VsZWN0b3ItbWF4LXR5cGUsIHNlbGVjdG9yLW1heC1jb21wb3VuZC1zZWxlY3RvcnMgKi8gfVxuICAucy10ZXh0Y29udGVudCA+IGJsb2NrcXVvdGUge1xuICAgIGZvbnQtc3R5bGU6IGl0YWxpYzsgfVxuICAucy10ZXh0Y29udGVudCA+IHA6bm90KDpvbmx5LWNoaWxkKSwgLnMtdGV4dGNvbnRlbnQgPiB1bDpub3QoOm9ubHktY2hpbGQpLCAucy10ZXh0Y29udGVudCA+IG9sOm5vdCg6b25seS1jaGlsZCkge1xuICAgIG1hcmdpbi10b3A6IDEwcHg7XG4gICAgbWFyZ2luLWJvdHRvbTogMTBweDsgfVxuICAucy10ZXh0Y29udGVudCA+IGgyOmZpcnN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGgzOmZpcnN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGg0OmZpcnN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGg1OmZpcnN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGg2OmZpcnN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IHA6Zmlyc3QtY2hpbGQsIC5zLXRleHRjb250ZW50ID4gdWw6Zmlyc3QtY2hpbGQsIC5zLXRleHRjb250ZW50ID4gb2w6Zmlyc3QtY2hpbGQge1xuICAgIG1hcmdpbi10b3A6IDA7IH1cbiAgLnMtdGV4dGNvbnRlbnQgPiBoMjpsYXN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGgzOmxhc3QtY2hpbGQsIC5zLXRleHRjb250ZW50ID4gaDQ6bGFzdC1jaGlsZCwgLnMtdGV4dGNvbnRlbnQgPiBoNTpsYXN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IGg2Omxhc3QtY2hpbGQsIC5zLXRleHRjb250ZW50ID4gcDpsYXN0LWNoaWxkLCAucy10ZXh0Y29udGVudCA+IHVsOmxhc3QtY2hpbGQsIC5zLXRleHRjb250ZW50ID4gb2w6bGFzdC1jaGlsZCB7XG4gICAgbWFyZ2luLWJvdHRvbTogMDsgfVxuICAucy10ZXh0Y29udGVudCA+IHVsIGxpIHtcbiAgICBsaXN0LXN0eWxlLXR5cGU6IGRpc2M7IH1cbiAgLnMtdGV4dGNvbnRlbnQgPiB1bCBsaSBsaSwgLnMtdGV4dGNvbnRlbnQgPiBvbCBsaSBsaSB7XG4gICAgcGFkZGluZy1sZWZ0OiAyMHB4OyB9XG4gIC5zLXRleHRjb250ZW50IGltZyB7XG4gICAgZGlzcGxheTogYmxvY2s7IH1cbiAgICBAbWVkaWEgKG1heC13aWR0aDogNjMuOTllbSkge1xuICAgICAgLnMtdGV4dGNvbnRlbnQgaW1nIHtcbiAgICAgICAgbWF4LXdpZHRoOiAxMDAlO1xuICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgaGVpZ2h0OiBhdXRvOyB9IH1cbiAgLnMtdGV4dGNvbnRlbnQgaWZyYW1lIHtcbiAgICB3aWR0aDogMTAwJTsgfVxuXG4uaXMtcGFnZS1sb2FkaW5nICoge1xuICB0cmFuc2l0aW9uOiBub25lICFpbXBvcnRhbnQ7IH1cblxuLnUtbGluayB7XG4gIGNvbG9yOiAjZWUyZDI5O1xuICB0ZXh0LWRlY29yYXRpb246IG5vbmU7IH1cblxuLnUtbGluay1idXR0b24ge1xuICBjb2xvcjogI2VlMmQyOTtcbiAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICBib3JkZXI6IG5vbmU7XG4gIGJhY2tncm91bmQ6IG5vbmU7XG4gIGJveC1zaGFkb3c6IG5vbmU7XG4gIHBhZGRpbmc6IDA7IH1cblxuLmMtZWRpdC1saW5rIHtcbiAgcG9zaXRpb246IGZpeGVkO1xuICB0b3A6IDFlbTtcbiAgbGVmdDogMWVtO1xuICBvcGFjaXR5OiAwOyB9XG4gIC5jLWVkaXQtbGluazpob3ZlciB7XG4gICAgb3BhY2l0eTogMTsgfVxuIiwiLyogc3R5bGVsaW50LWRpc2FibGUgY29sb3Itbm8taGV4ICovXG4kY29sb3ItcG9tZWdyYW5hdGU6ICNlZTJkMjk7XG4kY29sb3ItY29uY3JldGU6ICNmM2YzZjM7XG5cbiRjb2xvci1hY2NlbnQ6ICRjb2xvci1wb21lZ3JhbmF0ZTtcblxuJGNvbG9yLWxpbms6ICRjb2xvci1hY2NlbnQ7XG4kY29sb3ItYmc6IHdoaXRlO1xuIiwiJGZmLWJvZHk6ICdIZWx2ZXRpY2EgTmV1ZScsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7XG5cblxuJGZvbnQtc2l6ZS1iYXNlOiByZW0tY2FsYygxNnB4KTtcblxuLy8gQSBtYXAgY29udGFpbmluZyB0aGUgYmFzaWMgdHlwb2dyYXBoeSBmb3IgYWxsIHRoZSBzaXRlXG4vLyBUaGUgMm5kIGxldmVsIG9mIHRoZSBtYXAgKGJvZHkgYW5kIGhlYWRpbmcpIGNvcnJlc3BvbmRzIHRvIHRoZSBtYWluIHR5cGVmYWNlcy5cbi8vIFRoZSAzcmQgbGV2ZWwgb2YgdGhlIG1hcCBjb3JyZXNwb25kcyB0byBmb250IHByb3BlcnR5IGNvbWJpbmF0aW9ucyB0aGF0IGZyZXF1ZW50bHkgZ28gdG9nZXRoZXIuIEFueSBhcmJpdHJhcnkgd29yZCBnb2VzIGFzIGEgZ3JvdXAgbmFtZS4gVGhlIHByb3BlcnRpZXMgYXJlIHVzdWFsbHkgZm9udC1zaXplIGFuZCBsaW5lLWhlaWdodCBidXQgY2FuIGJlIGFsc28gYW55IG90aGVyLiBQbGVhc2UgYXZvaWQgaW5jbHVkaW5nIGNvbG9yIGFuZCBvdGhlciBub24gdHlwb2dyYXBoeSBwcm9wZXJ0aWVzIGhlcmUsIHRob3VnaC5cbi8vIFVzYWdlOiBAaW5jbHVkZSB1LXNldC10eXBvZ3JhcGh5KCR0eXBlZmFjZSwgJHN0eWxlLW5hbWUpO1xuXG4vKiBzdHlsZWxpbnQtZGlzYWJsZSBpbmRlbnRhdGlvbiAqL1xuJGZvbnQtc3R5bGVzOiAoXG4gIFxuICAnYm9keSc6ICggLy8gYWthIEhlbHZldGljYSBOZXVlXG5cbiAgICAncmVndWxhcic6IChcbiAgICAgIGZvbnQtc2l6ZTogJGZvbnQtc2l6ZS1iYXNlLFxuICAgICAgbGluZS1oZWlnaHQ6IDEuNlxuICAgICksXG4gICksXG5cbiAgLy8gJ2hlYWRpbmcnOiAoIC8vIGFrYSBoZWFkaW5nIGZvbnRcblxuICAvLyAgICdzZWN0aW9uLXRpdGxlJzogKFxuICAvLyAgICAgZm9udC1zaXplOjE2cHgsXG4gIC8vICAgICBsaW5lLWhlaWdodDoxXG4gIC8vICAgKSxcbiAgLy8gKVxuXG4pO1xuXG4vKiBzdHlsZWxpbnQtZW5hYmxlIGluZGVudGF0aW9uICovXG4iLCIvKiBzdHlsZWxpbnQtZGlzYWJsZSBtZW93dGVjL25vLXB4ICovXG5cbi8vIFByb3BvcnRpb25zXG4kdW5pdC14OiByZW0tY2FsYygxMHB4KTtcbiR1bml0LXk6ICR1bml0LXg7XG5cbi8vIFdpZHRoc1xuXG4vL1RodW1ibmFpbCBzaXplcyDigJQgc2FtZSBhcyB3cCByZWdpc3RlcmVkIHNpemVzIHVubGVzcyBub3RlZCBvdGhlcndpc2Vcbi8vICR0aGlyZC1sb3ctaGVpZ2h0OjMwMHB4O1xuXG4vLyBWaXN1YWwgZWZmZWN0c1xuXG4vLyBUcmFuc2l0aW9ucyAmIGFuaW1hdGlvbnNcbi8vIG5vdGUgdGhhdCBwcm9wZXJ0eSBpcyBvbWl0dGVkIFxuLy8gJHRyYW5zaXRpb24tbWFpbjplYXNlLW91dCAuNHM7XG5cbi8vIEV4Y2x1ZGVkIHNlbGVjdG9ycyAob25seSBzaW1wbGUgc2VsZWN0b3JzKVxuLy8gdXNlIEBpbmNsdWRlIHQtZm9jdXNlZCB3aXRoIGFyZ3VtZW50cyB0byBzZXQgeW91ciBvd24gc3R5bGluZyB3aGVuIGVsZW1lbnQgaXMgZm9jdXNlZFxuJGNsYXNzZXMtZXhjbHVkZS1mcm9tLWZvY3VzOiAoXG4gICdjLXNlbGVjdG9yLTEnXG4gICdjLXNlbGVjdG9yLTInXG4pO1xuXG5cbi8vIEJyZWFrcG9pbnRzXG4vLyB1c2FnZTogQGluY2x1ZGUgbXEoJGZyb206IHhsYXJnZSkge31cbiRtcS1icmVha3BvaW50czogKFxuICBzbWFsbDogIDM4MHB4LFxuICBtZWRpdW06IDc2OHB4LFxuICBsYXJnZTogIDEwMjRweCxcbiAgeGxhcmdlOiAxMjgwcHgsXG4pO1xuXG4vKiBzdHlsZWxpbnQtZW5hYmxlIG1lb3d0ZWMvbm8tcHggKi9cbiIsIi8qIHN0eWxlbGludC1kaXNhYmxlIHNlbGVjdG9yLW1heC11bml2ZXJzYWwsIHNlbGVjdG9yLW1heC10eXBlICovXG4vLyBUd2Vha3MgZm9yIE5vcm1hbGl6ZSAzLjBcbmgxLCBoMiwgaDMsIGg0LCBoNSwgaDYsIHAsIGRsLCBkZCwgdWwsIG9sLCBsaSwgZmlndXJlIHtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwOyBcbn1cblxuaDEsIGgyLCBoMywgaDQsIGg1LCBoNiB7ICBcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDsgXG4gIGZvbnQtc2l6ZTogMTAwJTsgXG59XG5cbnVsIHtcbiAgbGlzdC1zdHlsZTogbm9uZTtcbn1cblxuaHRtbCB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG59XG5cbiosICo6OmJlZm9yZSwgKjo6YWZ0ZXIge1xuICBib3gtc2l6aW5nOiBpbmhlcml0O1xufVxuXG5vbCwgdWwge1xuICBsaXN0LXN0eWxlLXBvc2l0aW9uOiBpbnNpZGU7IFxufVxuXG50ZXh0YXJlYSB7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgcmVzaXplOiB2ZXJ0aWNhbDtcbn1cblxuZmllbGRzZXQge1xuICBib3JkZXI6IG5vbmU7IFxuICBtYXJnaW46IDA7IFxuICBwYWRkaW5nOiAwOyBcbn1cblxuc2VsZWN0IHtcbiAgY29sb3I6IGJsYWNrOyBcbn1cblxuaWZyYW1lIHtcbiAgYm9yZGVyOiBub25lOyBcbn1cbiIsIi8qIHN0eWxlbGludC1kaXNhYmxlIGRlY2xhcmF0aW9uLW5vLWltcG9ydGFudCwgc2VsZWN0b3ItbWF4LXVuaXZlcnNhbCAqL1xuYm9keSB7XG4gIEBpbmNsdWRlIHUtc2V0LXR5cG9ncmFwaHk7XG4gIGJhY2tncm91bmQtY29sb3I6ICRjb2xvci1iZzsgXG59XG5cbmEge1xuICBAaW5jbHVkZSB0LWxpbmstYmFzZTtcbn1cblxuLnMtdGV4dGNvbnRlbnQge1xuICBAaW5jbHVkZSB0LXRleHRjb250ZW50O1xufVxuXG4uaXMtcGFnZS1sb2FkaW5nICoge1xuICB0cmFuc2l0aW9uOiBub25lICFpbXBvcnRhbnQ7XG59XG5cbi51LWxpbmsge1xuICBAaW5jbHVkZSB0LWxpbmstYmFzZTtcbn1cblxuLnUtbGluay1idXR0b24ge1xuICBAaW5jbHVkZSB0LWxpbmstYmFzZTtcbiAgQGluY2x1ZGUgdS1yZW1vdmUtYnV0dG9uLXN0eWxpbmc7XG59XG4iLCIvLyBQcm9qZWN0IG1peGluc1xuXG4vLyAhVXRpbGl0aWVzXG4vLyBUaGVzZSBkbyBvbmUgc2luZ2xlIHRoaW5nXG5AbWl4aW4gdS1zZXQtdHlwb2dyYXBoeSgkdHlwZWZhY2UtbmFtZTogJ2JvZHknLCAkc3R5bGUtbmFtZTogJ3JlZ3VsYXInKSB7XG4gIFxuICAkdGhpcy10eXBlZmFjZTogbWFwLWdldCgkZm9udC1zdHlsZXMsICR0eXBlZmFjZS1uYW1lKTtcbiAgJHRoaXMtc3R5bGU6IG1hcC1nZXQoJHRoaXMtdHlwZWZhY2UsICRzdHlsZS1uYW1lKTtcbiAgXG4gIEBpZiAkdHlwZWZhY2UtbmFtZSA9PSAnYm9keScge1xuICAgIGZvbnQtZmFtaWx5OiAkZmYtYm9keTsgXG4gIH1cbiAgQGlmICR0eXBlZmFjZS1uYW1lID09ICdoZWFkaW5nJyB7XG4gICAgZm9udC1mYW1pbHk6ICRmZi1oZWFkaW5nOyBcbiAgICBmb250LXdlaWdodDogODAwOyBcbiAgfVxuXG4gIEBlYWNoICRwcm9wZXJ0eSwgJHZhbHVlIGluICR0aGlzLXN0eWxlIHtcbiAgICBAaWYgbWFwLWhhcy1rZXkoJG1xLWJyZWFrcG9pbnRzLCAkcHJvcGVydHkpIGFuZCB0eXBlLW9mKCR2YWx1ZSkgPT0gJ21hcCcge1xuICAgICAgQGluY2x1ZGUgbXEoJGZyb206ICRwcm9wZXJ0eSkge1xuICAgICAgICBAZWFjaCAkc3VicHJvcGVydHksICRzdWJ2YWx1ZSBpbiAkdmFsdWUge1xuICAgICAgICAgIEBpZiAkc3VicHJvcGVydHkgPT0gJ2ZvbnQtc2l6ZScge1xuICAgICAgICAgICAgJHN1YnZhbHVlOiByZW0tY2FsYygkc3VidmFsdWUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgICN7JHN1YnByb3BlcnR5fTogJHN1YnZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBAZWxzZSB7XG4gICAgICBAaWYgJHByb3BlcnR5ID09ICdmb250LXNpemUnIHtcbiAgICAgICAgJHZhbHVlOiByZW0tY2FsYygkdmFsdWUpO1xuICAgICAgfVxuICAgICAgI3skcHJvcGVydHl9OiAkdmFsdWU7XG4gICAgfVxuICB9XG59XG5cblxuXG4vLyAhVGhlbWluZyBtaXhpbnNcbi8vIHB1cmUgYXBwZWFyYW5jZSAodHlwb2dyYXBoaWMvY29zbWV0aWMpIHN0eWxlc1xuXG5AbWl4aW4gdC1saW5rLWJhc2Uge1xuICBjb2xvcjogJGNvbG9yLWxpbms7IFxuICB0ZXh0LWRlY29yYXRpb246IG5vbmU7IFxufVxuXG5cbkBtaXhpbiB0LWZvY3VzZWQge1xufVxuIiwiLy8gcHVyZSBhcHBlYXJhbmNlICh0eXBvZ3JhcGhpYy9jb3NtZXRpYykgc3R5bGVzXG4vLyBwbGVhc2Uga2VlcCBoZXJlIG9ubHkgdGhvc2UgbWl4aW5zIHRoYXQgYXJlIHJlbGF0ZWQgdG8gc2luZ2xlIHBvc3Qgc3R5bGluZyBcblxuQG1peGluIHQtdGV4dGNvbnRlbnQge1xuICAvKiBzdHlsZWxpbnQtZGlzYWJsZSBzZWxlY3Rvci1tYXgtdHlwZSwgc2VsZWN0b3ItbWF4LWNvbXBvdW5kLXNlbGVjdG9ycyAqL1xuXG4gIC8vIHByZXZlbnRpbmcgdGV4dCBzdHlsZXMgbGVha2luZyBpbnRvIHdpZGdldHMgcGFzdGVkIGludG8gY29udGVudCBhcmVhIHZpYSBzaG9ydGNvZGVzXG4gICYgPiB7XG4gICAgYmxvY2txdW90ZSB7XG4gICAgICBmb250LXN0eWxlOiBpdGFsaWM7IFxuICAgIH1cbiAgICAvLyBoMiB7XG4gICAgLy8gICBAaW5jbHVkZSB0LWhlYWRpbmcteHh4bDtcbiAgICAvLyB9XG4gICAgLy8gaDMge1xuICAgIC8vICAgQGluY2x1ZGUgdC1oZWFkaW5nLXh4bDtcbiAgICAvLyB9XG4gICAgLy8gaDQge1xuICAgIC8vICAgQGluY2x1ZGUgdC1oZWFkaW5nLXhsO1xuICAgIC8vIH1cbiAgICAvLyBoNSB7XG4gICAgLy8gICBAaW5jbHVkZSB0LWhlYWRpbmctbDtcbiAgICAvLyB9XG4gICAgLy8gaDYge1xuICAgIC8vICAgQGluY2x1ZGUgdC1oZWFkaW5nLW07XG4gICAgLy8gfVxuICAgIHAsIHVsLCBvbCB7XG4gICAgICAmOm5vdCg6b25seS1jaGlsZCkge1xuICAgICAgICBAaW5jbHVkZSB1LXNwYWNpbmcteSgkdW5pdC15LCAnbWFyZ2luJyk7XG4gICAgICB9XG4gICAgfVxuICAgIGgyLCBoMywgaDQsIGg1LCBoNiwgcCwgdWwsIG9sIHtcbiAgICAgICY6Zmlyc3QtY2hpbGQge1xuICAgICAgICBtYXJnaW4tdG9wOiAwOyBcbiAgICAgIH1cbiAgICAgICY6bGFzdC1jaGlsZCB7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDA7IFxuICAgICAgfVxuICAgIH1cbiAgICB1bCBsaSB7XG4gICAgICBsaXN0LXN0eWxlLXR5cGU6IGRpc2M7IFxuICAgIH1cbiAgICB1bCwgb2wge1xuICAgICAgbGkgbGkge1xuICAgICAgICBwYWRkaW5nLWxlZnQ6ICR1bml0LXggKiAyOyBcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgaW1nIHtcbiAgICBkaXNwbGF5OmJsb2NrOyBcbiAgICBAaW5jbHVkZSBtcSgkdW50aWw6IGxhcmdlKSB7XG4gICAgICBAaW5jbHVkZSB1LWltYWdlLWF1dG93aWR0aDtcbiAgICB9XG4gIH1cbiAgaWZyYW1lIHtcbiAgICB3aWR0aDogMTAwJTsgXG4gIH1cblxuICAvKiBzdHlsZWxpbnQtZW5hYmxlIHNlbGVjdG9yLW1heC10eXBlLCBzZWxlY3Rvci1tYXgtY29tcG91bmQtc2VsZWN0b3JzICovXG59XG5cblxuLy8gfiBoZWFkaW5nIGxldmVsIDJcbi8vIEBtaXhpbiB0LWhlYWRpbmcteHh4bCB7XG4vLyAgIEBpbmNsdWRlIHUtc2V0LXR5cG9ncmFwaHkoJ2JvZHknLCAnYmlnLWhlYWRpbmcnKTtcbi8vIH1cblxuXG4vLyB+IGhlYWRpbmcgbGV2ZWwgM1xuLy8gQG1peGluIHQtaGVhZGluZy14eGwge1xuLy8gfVxuXG5cbi8vIC8vIH4gaGVhZGluZyBsZXZlbCA0XG4vLyBAbWl4aW4gdC1oZWFkaW5nLXhsIHtcbi8vIH1cblxuXG4vLyAvLyB+IGhlYWRpbmcgbGV2ZWwgNVxuLy8gQG1peGluIHQtaGVhZGluZy1sIHtcbi8vIH1cblxuXG4vLyAvLyB+IGhlYWRpbmcgbGV2ZWwgNlxuLy8gQG1peGluIHQtaGVhZGluZy1tIHtcbi8vIH1cbiIsIkBtaXhpbiB1LXNwYWNpbmcteCgkc3BhY2luZywgJHNwYWNpbmctdHlwZToncGFkZGluZycpIHtcbiAgI3skc3BhY2luZy10eXBlfS1sZWZ0OiRzcGFjaW5nOyBcbiAgI3skc3BhY2luZy10eXBlfS1yaWdodDokc3BhY2luZzsgXG59XG5cbkBtaXhpbiB1LXNwYWNpbmcteSgkc3BhY2luZywgJHNwYWNpbmctdHlwZToncGFkZGluZycpIHtcbiAgI3skc3BhY2luZy10eXBlfS10b3A6JHNwYWNpbmc7IFxuICAjeyRzcGFjaW5nLXR5cGV9LWJvdHRvbTokc3BhY2luZzsgXG59IiwiQGNoYXJzZXQgXCJVVEYtOFwiOyAvLyBGaXhlcyBhbiBpc3N1ZSB3aGVyZSBSdWJ5IGxvY2FsZSBpcyBub3Qgc2V0IHByb3Blcmx5XG4gICAgICAgICAgICAgICAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3Nhc3MtbXEvc2Fzcy1tcS9wdWxsLzEwXG5cbi8vLyBCYXNlIGZvbnQgc2l6ZSBvbiB0aGUgYDxib2R5PmAgZWxlbWVudFxuLy8vXG4vLy8gRG8gbm90IG92ZXJyaWRlIHRoaXMgdmFsdWUsIG9yIHRoaW5ncyB3aWxsIGJyZWFrXG4vLy9cbi8vLyBAbGluayBodHRwczovL2dpdGh1Yi5jb20vc2Fzcy1tcS9zYXNzLW1xL2lzc3Vlcy8xMjJcbi8vLyBAZGVwcmVjYXRlZCBUaGlzIHNldHRpbmcgd2lsbCBiZSByZW1vdmVkIGluIHNhc3MtbXEgdjYuMC4wXG4vLy8gQGFjY2VzcyBwcml2YXRlXG4vLy8gQHR5cGUgTnVtYmVyICh1bml0KVxuJG1xLWJhc2UtZm9udC1zaXplOiAxNnB4ICFkZWZhdWx0O1xuXG4vLy8gUmVzcG9uc2l2ZSBtb2RlXG4vLy9cbi8vLyBTZXQgdG8gYGZhbHNlYCB0byBlbmFibGUgc3VwcG9ydCBmb3IgYnJvd3NlcnMgdGhhdCBkbyBub3Qgc3VwcG9ydCBAbWVkaWEgcXVlcmllcyxcbi8vLyAoSUUgPD0gOCwgRmlyZWZveCA8PSAzLCBPcGVyYSA8PSA5KVxuLy8vXG4vLy8gWW91IGNvdWxkIGNyZWF0ZSBhIHN0eWxlc2hlZXQgc2VydmVkIGV4Y2x1c2l2ZWx5IHRvIG9sZGVyIGJyb3dzZXJzLFxuLy8vIHdoZXJlIEBtZWRpYSBxdWVyaWVzIGFyZSByYXN0ZXJpemVkXG4vLy9cbi8vLyBAZXhhbXBsZSBzY3NzXG4vLy8gIC8vIG9sZC1pZS5zY3NzXG4vLy8gICRtcS1yZXNwb25zaXZlOiBmYWxzZTtcbi8vLyAgQGltcG9ydCAnbWFpbic7IC8vIEBtZWRpYSBxdWVyaWVzIGluIHRoaXMgZmlsZSB3aWxsIGJlIHJhc3Rlcml6ZWQgdXAgdG8gJG1xLXN0YXRpYy1icmVha3BvaW50XG4vLy8gICAgICAgICAgICAgICAgICAgLy8gbGFyZ2VyIGJyZWFrcG9pbnRzIHdpbGwgYmUgaWdub3JlZFxuLy8vXG4vLy8gQHR5cGUgQm9vbGVhblxuLy8vIEBsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXNzLW1xL3Nhc3MtbXEjcmVzcG9uc2l2ZS1tb2RlLW9mZiBEaXNhYmxlZCByZXNwb25zaXZlIG1vZGUgZG9jdW1lbnRhdGlvblxuJG1xLXJlc3BvbnNpdmU6IHRydWUgIWRlZmF1bHQ7XG5cbi8vLyBCcmVha3BvaW50IGxpc3Rcbi8vL1xuLy8vIE5hbWUgeW91ciBicmVha3BvaW50cyBpbiBhIHdheSB0aGF0IGNyZWF0ZXMgYSB1YmlxdWl0b3VzIGxhbmd1YWdlXG4vLy8gYWNyb3NzIHRlYW0gbWVtYmVycy4gSXQgd2lsbCBpbXByb3ZlIGNvbW11bmljYXRpb24gYmV0d2VlblxuLy8vIHN0YWtlaG9sZGVycywgZGVzaWduZXJzLCBkZXZlbG9wZXJzLCBhbmQgdGVzdGVycy5cbi8vL1xuLy8vIEB0eXBlIE1hcFxuLy8vIEBsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXNzLW1xL3Nhc3MtbXEjc2VlaW5nLXRoZS1jdXJyZW50bHktYWN0aXZlLWJyZWFrcG9pbnQgRnVsbCBkb2N1bWVudGF0aW9uIGFuZCBleGFtcGxlc1xuJG1xLWJyZWFrcG9pbnRzOiAoXG4gICAgbW9iaWxlOiAgMzIwcHgsXG4gICAgdGFibGV0OiAgNzQwcHgsXG4gICAgZGVza3RvcDogOTgwcHgsXG4gICAgd2lkZTogICAgMTMwMHB4XG4pICFkZWZhdWx0O1xuXG4vLy8gU3RhdGljIGJyZWFrcG9pbnQgKGZvciBmaXhlZC13aWR0aCBsYXlvdXRzKVxuLy8vXG4vLy8gRGVmaW5lIHRoZSBicmVha3BvaW50IGZyb20gJG1xLWJyZWFrcG9pbnRzIHRoYXQgc2hvdWxkXG4vLy8gYmUgdXNlZCBhcyB0aGUgdGFyZ2V0IHdpZHRoIGZvciB0aGUgZml4ZWQtd2lkdGggbGF5b3V0XG4vLy8gKGkuZS4gd2hlbiAkbXEtcmVzcG9uc2l2ZSBpcyBzZXQgdG8gJ2ZhbHNlJykgaW4gYSBvbGQtaWUuc2Nzc1xuLy8vXG4vLy8gQGV4YW1wbGUgc2Nzc1xuLy8vICAvLyB0YWJsZXQtb25seS5zY3NzXG4vLy8gIC8vXG4vLy8gIC8vIElnbm9yZSBhbGwgc3R5bGVzIGFib3ZlIHRhYmxldCBicmVha3BvaW50LFxuLy8vICAvLyBhbmQgZml4IHRoZSBzdHlsZXMgKHN1Y2ggYXMgdGhlIGxheW91dCkgYXQgdGFibGV0IHdpZHRoXG4vLy8gICRtcS1yZXNwb25zaXZlOiBmYWxzZTtcbi8vLyAgJG1xLXN0YXRpYy1icmVha3BvaW50OiB0YWJsZXQ7XG4vLy8gIEBpbXBvcnQgJ21haW4nOyAvLyBAbWVkaWEgcXVlcmllcyBpbiB0aGlzIGZpbGUgd2lsbCBiZSByYXN0ZXJpemVkIHVwIHRvIHRhYmxldFxuLy8vICAgICAgICAgICAgICAgICAgIC8vIGxhcmdlciBicmVha3BvaW50cyB3aWxsIGJlIGlnbm9yZWRcbi8vL1xuLy8vIEB0eXBlIFN0cmluZ1xuLy8vIEBsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXNzLW1xL3Nhc3MtbXEjYWRkaW5nLWN1c3RvbS1icmVha3BvaW50cyBGdWxsIGRvY3VtZW50YXRpb24gYW5kIGV4YW1wbGVzXG4kbXEtc3RhdGljLWJyZWFrcG9pbnQ6IGRlc2t0b3AgIWRlZmF1bHQ7XG5cbi8vLyBTaG93IGJyZWFrcG9pbnRzIGluIHRoZSB0b3AgcmlnaHQgY29ybmVyXG4vLy9cbi8vLyBJZiB5b3Ugd2FudCB0byBkaXNwbGF5IHRoZSBjdXJyZW50bHkgYWN0aXZlIGJyZWFrcG9pbnQgaW4gdGhlIHRvcFxuLy8vIHJpZ2h0IGNvcm5lciBvZiB5b3VyIHNpdGUgZHVyaW5nIGRldmVsb3BtZW50LCBhZGQgdGhlIGJyZWFrcG9pbnRzXG4vLy8gdG8gdGhpcyBsaXN0LCBvcmRlcmVkIGJ5IHdpZHRoLiBGb3IgZXhhbXBsZTogKG1vYmlsZSwgdGFibGV0LCBkZXNrdG9wKS5cbi8vL1xuLy8vIEBleGFtcGxlIHNjc3Ncbi8vLyAgICRtcS1zaG93LWJyZWFrcG9pbnRzOiAobW9iaWxlLCB0YWJsZXQsIGRlc2t0b3ApO1xuLy8vICAgQGltcG9ydCAncGF0aC90by9tcSc7XG4vLy9cbi8vLyBAdHlwZSBtYXBcbiRtcS1zaG93LWJyZWFrcG9pbnRzOiAoKSAhZGVmYXVsdDtcblxuLy8vIEN1c3RvbWl6ZSB0aGUgbWVkaWEgdHlwZSAoZm9yIGV4YW1wbGU6IGBAbWVkaWEgc2NyZWVuYCBvciBgQG1lZGlhIHByaW50YClcbi8vLyBCeSBkZWZhdWx0IHNhc3MtbXEgdXNlcyBhbiBcImFsbFwiIG1lZGlhIHR5cGUgKGBAbWVkaWEgYWxsIGFuZCDigKZgKVxuLy8vXG4vLy8gQHR5cGUgU3RyaW5nXG4vLy8gQGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3Nhc3MtbXEvc2Fzcy1tcSNjaGFuZ2luZy1tZWRpYS10eXBlIEZ1bGwgZG9jdW1lbnRhdGlvbiBhbmQgZXhhbXBsZXNcbiRtcS1tZWRpYS10eXBlOiBhbGwgIWRlZmF1bHQ7XG5cbi8vLyBDb252ZXJ0IHBpeGVscyB0byBlbXNcbi8vL1xuLy8vIEBwYXJhbSB7TnVtYmVyfSAkcHggLSB2YWx1ZSB0byBjb252ZXJ0XG4vLy8gQGlnbm9yZSBAcGFyYW0ge051bWJlcn0gJGJhc2UtZm9udC1zaXplIFskbXEtYmFzZS1mb250LXNpemVdIC0gYDxib2R5PmAgZm9udCBzaXplIChkZXByZWNhdGVkKVxuLy8vXG4vLy8gQGV4YW1wbGUgc2Nzc1xuLy8vICAkZm9udC1zaXplLWluLWVtczogbXEtcHgyZW0oMTZweCk7XG4vLy8gIHAgeyBmb250LXNpemU6IG1xLXB4MmVtKDE2cHgpOyB9XG4vLy9cbi8vLyBAcmVxdWlyZXMgJG1xLWJhc2UtZm9udC1zaXplXG4vLy8gQHJldHVybnMge051bWJlcn1cbkBmdW5jdGlvbiBtcS1weDJlbSgkcHgsICRiYXNlLWZvbnQtc2l6ZTogJG1xLWJhc2UtZm9udC1zaXplKSB7XG4gICAgQGlmICgkbXEtYmFzZS1mb250LXNpemUgIT0gMTZweCkge1xuICAgICAgICBAd2FybiBcIk92ZXJyaWRpbmcgJG1xLWJhc2UtZm9udC1zaXplIHdpbGwgYnJlYWsgdGhpbmdzLCBzZWUgaHR0cHM6Ly9naXRodWIuY29tL3Nhc3MtbXEvc2Fzcy1tcS9pc3N1ZXMvMTIyLlwiO1xuICAgIH1cbiAgICBAaWYgKCRiYXNlLWZvbnQtc2l6ZSAhPSAxNnB4KSB7XG4gICAgICAgIEB3YXJuIFwiVGhlICRiYXNlLWZvbnQtc2l6ZSBhcmd1bWVudCB3aWxsIGJlIHJlbW92ZWQgaW4gc2Fzcy1tcSB2Ni4wLjAsIGFzIG92ZXJyaWRpbmcgaXQgYnJlYWtzIHRoaW5ncywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXNzLW1xL3Nhc3MtbXEvaXNzdWVzLzEyMi5cIjtcbiAgICB9XG4gICAgQGlmIHVuaXRsZXNzKCRweCkge1xuICAgICAgICBAd2FybiBcIkFzc3VtaW5nICN7JHB4fSB0byBiZSBpbiBwaXhlbHMsIGF0dGVtcHRpbmcgdG8gY29udmVydCBpdCBpbnRvIHBpeGVscy5cIjtcbiAgICAgICAgQHJldHVybiBtcS1weDJlbSgkcHggKiAxcHgsICRiYXNlLWZvbnQtc2l6ZSk7XG4gICAgfSBAZWxzZSBpZiB1bml0KCRweCkgPT0gZW0ge1xuICAgICAgICBAcmV0dXJuICRweDtcbiAgICB9XG4gICAgQHJldHVybiAoJHB4IC8gJGJhc2UtZm9udC1zaXplKSAqIDFlbTtcbn1cblxuLy8vIEdldCBhIGJyZWFrcG9pbnQncyB3aWR0aFxuLy8vXG4vLy8gQHBhcmFtIHtTdHJpbmd9ICRuYW1lIC0gTmFtZSBvZiB0aGUgYnJlYWtwb2ludC4gT25lIG9mICRtcS1icmVha3BvaW50c1xuLy8vXG4vLy8gQGV4YW1wbGUgc2Nzc1xuLy8vICAkdGFibGV0LXdpZHRoOiBtcS1nZXQtYnJlYWtwb2ludC13aWR0aCh0YWJsZXQpO1xuLy8vICBAbWVkaWEgKG1pbi13aWR0aDogbXEtZ2V0LWJyZWFrcG9pbnQtd2lkdGgoZGVza3RvcCkpIHt9XG4vLy9cbi8vLyBAcmVxdWlyZXMge1ZhcmlhYmxlfSAkbXEtYnJlYWtwb2ludHNcbi8vL1xuLy8vIEByZXR1cm5zIHtOdW1iZXJ9IFZhbHVlIGluIHBpeGVsc1xuQGZ1bmN0aW9uIG1xLWdldC1icmVha3BvaW50LXdpZHRoKCRuYW1lLCAkYnJlYWtwb2ludHM6ICRtcS1icmVha3BvaW50cykge1xuICAgIEBpZiBtYXAtaGFzLWtleSgkYnJlYWtwb2ludHMsICRuYW1lKSB7XG4gICAgICAgIEByZXR1cm4gbWFwLWdldCgkYnJlYWtwb2ludHMsICRuYW1lKTtcbiAgICB9IEBlbHNlIHtcbiAgICAgICAgQHdhcm4gXCJCcmVha3BvaW50ICN7JG5hbWV9IHdhc24ndCBmb3VuZCBpbiAkYnJlYWtwb2ludHMuXCI7XG4gICAgfVxufVxuXG4vLy8gTWVkaWEgUXVlcnkgbWl4aW5cbi8vL1xuLy8vIEBwYXJhbSB7U3RyaW5nIHwgQm9vbGVhbn0gJGZyb20gW2ZhbHNlXSAtIE9uZSBvZiAkbXEtYnJlYWtwb2ludHNcbi8vLyBAcGFyYW0ge1N0cmluZyB8IEJvb2xlYW59ICR1bnRpbCBbZmFsc2VdIC0gT25lIG9mICRtcS1icmVha3BvaW50c1xuLy8vIEBwYXJhbSB7U3RyaW5nIHwgQm9vbGVhbn0gJGFuZCBbZmFsc2VdIC0gQWRkaXRpb25hbCBtZWRpYSBxdWVyeSBwYXJhbWV0ZXJzXG4vLy8gQHBhcmFtIHtTdHJpbmd9ICRtZWRpYS10eXBlIFskbXEtbWVkaWEtdHlwZV0gLSBNZWRpYSB0eXBlOiBzY3JlZW4sIHByaW504oCmXG4vLy9cbi8vLyBAaWdub3JlIFVuZG9jdW1lbnRlZCBBUEksIGZvciBhZHZhbmNlZCB1c2Ugb25seTpcbi8vLyBAaWdub3JlIEBwYXJhbSB7TWFwfSAkYnJlYWtwb2ludHMgWyRtcS1icmVha3BvaW50c11cbi8vLyBAaWdub3JlIEBwYXJhbSB7U3RyaW5nfSAkc3RhdGljLWJyZWFrcG9pbnQgWyRtcS1zdGF0aWMtYnJlYWtwb2ludF1cbi8vL1xuLy8vIEBjb250ZW50IHN0eWxpbmcgcnVsZXMsIHdyYXBwZWQgaW50byBhIEBtZWRpYSBxdWVyeSB3aGVuICRyZXNwb25zaXZlIGlzIHRydWVcbi8vL1xuLy8vIEByZXF1aXJlcyB7VmFyaWFibGV9ICRtcS1tZWRpYS10eXBlXG4vLy8gQHJlcXVpcmVzIHtWYXJpYWJsZX0gJG1xLWJyZWFrcG9pbnRzXG4vLy8gQHJlcXVpcmVzIHtWYXJpYWJsZX0gJG1xLXN0YXRpYy1icmVha3BvaW50XG4vLy8gQHJlcXVpcmVzIHtmdW5jdGlvbn0gbXEtcHgyZW1cbi8vLyBAcmVxdWlyZXMge2Z1bmN0aW9ufSBtcS1nZXQtYnJlYWtwb2ludC13aWR0aFxuLy8vXG4vLy8gQGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3Nhc3MtbXEvc2Fzcy1tcSNyZXNwb25zaXZlLW1vZGUtb24tZGVmYXVsdCBGdWxsIGRvY3VtZW50YXRpb24gYW5kIGV4YW1wbGVzXG4vLy9cbi8vLyBAZXhhbXBsZSBzY3NzXG4vLy8gIC5lbGVtZW50IHtcbi8vLyAgICBAaW5jbHVkZSBtcSgkZnJvbTogbW9iaWxlKSB7XG4vLy8gICAgICBjb2xvcjogcmVkO1xuLy8vICAgIH1cbi8vLyAgICBAaW5jbHVkZSBtcSgkdW50aWw6IHRhYmxldCkge1xuLy8vICAgICAgY29sb3I6IGJsdWU7XG4vLy8gICAgfVxuLy8vICAgIEBpbmNsdWRlIG1xKG1vYmlsZSwgdGFibGV0KSB7XG4vLy8gICAgICBjb2xvcjogZ3JlZW47XG4vLy8gICAgfVxuLy8vICAgIEBpbmNsdWRlIG1xKCRmcm9tOiB0YWJsZXQsICRhbmQ6ICcob3JpZW50YXRpb246IGxhbmRzY2FwZSknKSB7XG4vLy8gICAgICBjb2xvcjogdGVhbDtcbi8vLyAgICB9XG4vLy8gICAgQGluY2x1ZGUgbXEoOTUwcHgpIHtcbi8vLyAgICAgIGNvbG9yOiBob3RwaW5rO1xuLy8vICAgIH1cbi8vLyAgICBAaW5jbHVkZSBtcSh0YWJsZXQsICRtZWRpYS10eXBlOiBzY3JlZW4pIHtcbi8vLyAgICAgIGNvbG9yOiBob3RwaW5rO1xuLy8vICAgIH1cbi8vLyAgICAvLyBBZHZhbmNlZCB1c2U6XG4vLy8gICAgJG15LWJyZWFrcG9pbnRzOiAoTDogOTAwcHgsIFhMOiAxMjAwcHgpO1xuLy8vICAgIEBpbmNsdWRlIG1xKEwsICRicmVha3BvaW50czogJG15LWJyZWFrcG9pbnRzLCAkc3RhdGljLWJyZWFrcG9pbnQ6IEwpIHtcbi8vLyAgICAgIGNvbG9yOiBob3RwaW5rO1xuLy8vICAgIH1cbi8vLyAgfVxuQG1peGluIG1xKFxuICAgICRmcm9tOiBmYWxzZSxcbiAgICAkdW50aWw6IGZhbHNlLFxuICAgICRhbmQ6IGZhbHNlLFxuICAgICRtZWRpYS10eXBlOiAkbXEtbWVkaWEtdHlwZSxcbiAgICAkYnJlYWtwb2ludHM6ICRtcS1icmVha3BvaW50cyxcbiAgICAkcmVzcG9uc2l2ZTogJG1xLXJlc3BvbnNpdmUsXG4gICAgJHN0YXRpYy1icmVha3BvaW50OiAkbXEtc3RhdGljLWJyZWFrcG9pbnRcbikge1xuICAgICRtaW4td2lkdGg6IDA7XG4gICAgJG1heC13aWR0aDogMDtcbiAgICAkbWVkaWEtcXVlcnk6ICcnO1xuXG4gICAgLy8gRnJvbTogdGhpcyBicmVha3BvaW50IChpbmNsdXNpdmUpXG4gICAgQGlmICRmcm9tIHtcbiAgICAgICAgQGlmIHR5cGUtb2YoJGZyb20pID09IG51bWJlciB7XG4gICAgICAgICAgICAkbWluLXdpZHRoOiBtcS1weDJlbSgkZnJvbSk7XG4gICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgJG1pbi13aWR0aDogbXEtcHgyZW0obXEtZ2V0LWJyZWFrcG9pbnQtd2lkdGgoJGZyb20sICRicmVha3BvaW50cykpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVW50aWw6IHRoYXQgYnJlYWtwb2ludCAoZXhjbHVzaXZlKVxuICAgIEBpZiAkdW50aWwge1xuICAgICAgICBAaWYgdHlwZS1vZigkdW50aWwpID09IG51bWJlciB7XG4gICAgICAgICAgICAkbWF4LXdpZHRoOiBtcS1weDJlbSgkdW50aWwpO1xuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICRtYXgtd2lkdGg6IG1xLXB4MmVtKG1xLWdldC1icmVha3BvaW50LXdpZHRoKCR1bnRpbCwgJGJyZWFrcG9pbnRzKSkgLSAuMDFlbTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlc3BvbnNpdmUgc3VwcG9ydCBpcyBkaXNhYmxlZCwgcmFzdGVyaXplIHRoZSBvdXRwdXQgb3V0c2lkZSBAbWVkaWEgYmxvY2tzXG4gICAgLy8gVGhlIGJyb3dzZXIgd2lsbCByZWx5IG9uIHRoZSBjYXNjYWRlIGl0c2VsZi5cbiAgICBAaWYgJHJlc3BvbnNpdmUgPT0gZmFsc2Uge1xuICAgICAgICAkc3RhdGljLWJyZWFrcG9pbnQtd2lkdGg6IG1xLWdldC1icmVha3BvaW50LXdpZHRoKCRzdGF0aWMtYnJlYWtwb2ludCwgJGJyZWFrcG9pbnRzKTtcbiAgICAgICAgJHRhcmdldC13aWR0aDogbXEtcHgyZW0oJHN0YXRpYy1icmVha3BvaW50LXdpZHRoKTtcblxuICAgICAgICAvLyBPdXRwdXQgb25seSBydWxlcyB0aGF0IHN0YXJ0IGF0IG9yIHNwYW4gb3VyIHRhcmdldCB3aWR0aFxuICAgICAgICBAaWYgKFxuICAgICAgICAgICAgJGFuZCA9PSBmYWxzZVxuICAgICAgICAgICAgYW5kICRtaW4td2lkdGggPD0gJHRhcmdldC13aWR0aFxuICAgICAgICAgICAgYW5kIChcbiAgICAgICAgICAgICAgICAkdW50aWwgPT0gZmFsc2Ugb3IgJG1heC13aWR0aCA+PSAkdGFyZ2V0LXdpZHRoXG4gICAgICAgICAgICApXG4gICAgICAgICAgICBhbmQgJG1lZGlhLXR5cGUgIT0gJ3ByaW50J1xuICAgICAgICApIHtcbiAgICAgICAgICAgIEBjb250ZW50O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVzcG9uc2l2ZSBzdXBwb3J0IGlzIGVuYWJsZWQsIG91dHB1dCBydWxlcyBpbnNpZGUgQG1lZGlhIHF1ZXJpZXNcbiAgICBAZWxzZSB7XG4gICAgICAgIEBpZiAkbWluLXdpZHRoICE9IDAgeyAkbWVkaWEtcXVlcnk6ICcjeyRtZWRpYS1xdWVyeX0gYW5kIChtaW4td2lkdGg6ICN7JG1pbi13aWR0aH0pJzsgfVxuICAgICAgICBAaWYgJG1heC13aWR0aCAhPSAwIHsgJG1lZGlhLXF1ZXJ5OiAnI3skbWVkaWEtcXVlcnl9IGFuZCAobWF4LXdpZHRoOiAjeyRtYXgtd2lkdGh9KSc7IH1cbiAgICAgICAgQGlmICRhbmQgICAgICAgICAgICB7ICRtZWRpYS1xdWVyeTogJyN7JG1lZGlhLXF1ZXJ5fSBhbmQgI3skYW5kfSc7IH1cblxuICAgICAgICAvLyBSZW1vdmUgdW5uZWNlc3NhcnkgbWVkaWEgcXVlcnkgcHJlZml4ICdhbGwgYW5kICdcbiAgICAgICAgQGlmICgkbWVkaWEtdHlwZSA9PSAnYWxsJyBhbmQgJG1lZGlhLXF1ZXJ5ICE9ICcnKSB7XG4gICAgICAgICAgICAkbWVkaWEtdHlwZTogJyc7XG4gICAgICAgICAgICAkbWVkaWEtcXVlcnk6IHN0ci1zbGljZSh1bnF1b3RlKCRtZWRpYS1xdWVyeSksIDYpO1xuICAgICAgICB9XG5cbiAgICAgICAgQG1lZGlhICN7JG1lZGlhLXR5cGUgKyAkbWVkaWEtcXVlcnl9IHtcbiAgICAgICAgICAgIEBjb250ZW50O1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vLy8gUXVpY2sgc29ydFxuLy8vXG4vLy8gQGF1dGhvciBTYW0gUmljaGFyZHNcbi8vLyBAYWNjZXNzIHByaXZhdGVcbi8vLyBAcGFyYW0ge0xpc3R9ICRsaXN0IC0gTGlzdCB0byBzb3J0XG4vLy8gQHJldHVybnMge0xpc3R9IFNvcnRlZCBMaXN0XG5AZnVuY3Rpb24gX21xLXF1aWNrLXNvcnQoJGxpc3QpIHtcbiAgICAkbGVzczogICgpO1xuICAgICRlcXVhbDogKCk7XG4gICAgJGxhcmdlOiAoKTtcblxuICAgIEBpZiBsZW5ndGgoJGxpc3QpID4gMSB7XG4gICAgICAgICRzZWVkOiBudGgoJGxpc3QsIGNlaWwobGVuZ3RoKCRsaXN0KSAvIDIpKTtcblxuICAgICAgICBAZWFjaCAkaXRlbSBpbiAkbGlzdCB7XG4gICAgICAgICAgICBAaWYgKCRpdGVtID09ICRzZWVkKSB7XG4gICAgICAgICAgICAgICAgJGVxdWFsOiBhcHBlbmQoJGVxdWFsLCAkaXRlbSk7XG4gICAgICAgICAgICB9IEBlbHNlIGlmICgkaXRlbSA8ICRzZWVkKSB7XG4gICAgICAgICAgICAgICAgJGxlc3M6IGFwcGVuZCgkbGVzcywgJGl0ZW0pO1xuICAgICAgICAgICAgfSBAZWxzZSBpZiAoJGl0ZW0gPiAkc2VlZCkge1xuICAgICAgICAgICAgICAgICRsYXJnZTogYXBwZW5kKCRsYXJnZSwgJGl0ZW0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgQHJldHVybiBqb2luKGpvaW4oX21xLXF1aWNrLXNvcnQoJGxlc3MpLCAkZXF1YWwpLCBfbXEtcXVpY2stc29ydCgkbGFyZ2UpKTtcbiAgICB9XG5cbiAgICBAcmV0dXJuICRsaXN0O1xufVxuXG4vLy8gU29ydCBhIG1hcCBieSB2YWx1ZXMgKHdvcmtzIHdpdGggbnVtYmVycyBvbmx5KVxuLy8vXG4vLy8gQGFjY2VzcyBwcml2YXRlXG4vLy8gQHBhcmFtIHtNYXB9ICRtYXAgLSBNYXAgdG8gc29ydFxuLy8vIEByZXR1cm5zIHtNYXB9IE1hcCBzb3J0ZWQgYnkgdmFsdWVcbkBmdW5jdGlvbiBfbXEtbWFwLXNvcnQtYnktdmFsdWUoJG1hcCkge1xuICAgICRtYXAtc29ydGVkOiAoKTtcbiAgICAkbWFwLWtleXM6IG1hcC1rZXlzKCRtYXApO1xuICAgICRtYXAtdmFsdWVzOiBtYXAtdmFsdWVzKCRtYXApO1xuICAgICRtYXAtdmFsdWVzLXNvcnRlZDogX21xLXF1aWNrLXNvcnQoJG1hcC12YWx1ZXMpO1xuXG4gICAgLy8gUmVvcmRlciBrZXkvdmFsdWUgcGFpcnMgYmFzZWQgb24ga2V5IHZhbHVlc1xuICAgIEBlYWNoICR2YWx1ZSBpbiAkbWFwLXZhbHVlcy1zb3J0ZWQge1xuICAgICAgICAkaW5kZXg6IGluZGV4KCRtYXAtdmFsdWVzLCAkdmFsdWUpO1xuICAgICAgICAka2V5OiBudGgoJG1hcC1rZXlzLCAkaW5kZXgpO1xuICAgICAgICAkbWFwLXNvcnRlZDogbWFwLW1lcmdlKCRtYXAtc29ydGVkLCAoJGtleTogJHZhbHVlKSk7XG5cbiAgICAgICAgLy8gVW5zZXQgdGhlIHZhbHVlIGluICRtYXAtdmFsdWVzIHRvIHByZXZlbnQgdGhlIGxvb3BcbiAgICAgICAgLy8gZnJvbSBmaW5kaW5nIHRoZSBzYW1lIGluZGV4IHR3aWNlXG4gICAgICAgICRtYXAtdmFsdWVzOiBzZXQtbnRoKCRtYXAtdmFsdWVzLCAkaW5kZXgsIDApO1xuICAgIH1cblxuICAgIEByZXR1cm4gJG1hcC1zb3J0ZWQ7XG59XG5cbi8vLyBBZGQgYSBicmVha3BvaW50XG4vLy9cbi8vLyBAcGFyYW0ge1N0cmluZ30gJG5hbWUgLSBOYW1lIG9mIHRoZSBicmVha3BvaW50XG4vLy8gQHBhcmFtIHtOdW1iZXJ9ICR3aWR0aCAtIFdpZHRoIG9mIHRoZSBicmVha3BvaW50XG4vLy9cbi8vLyBAcmVxdWlyZXMge1ZhcmlhYmxlfSAkbXEtYnJlYWtwb2ludHNcbi8vL1xuLy8vIEBleGFtcGxlIHNjc3Ncbi8vLyAgQGluY2x1ZGUgbXEtYWRkLWJyZWFrcG9pbnQodHZzY3JlZW4sIDE5MjBweCk7XG4vLy8gIEBpbmNsdWRlIG1xKHR2c2NyZWVuKSB7fVxuQG1peGluIG1xLWFkZC1icmVha3BvaW50KCRuYW1lLCAkd2lkdGgpIHtcbiAgICAkbmV3LWJyZWFrcG9pbnQ6ICgkbmFtZTogJHdpZHRoKTtcbiAgICAkbXEtYnJlYWtwb2ludHM6IG1hcC1tZXJnZSgkbXEtYnJlYWtwb2ludHMsICRuZXctYnJlYWtwb2ludCkgIWdsb2JhbDtcbiAgICAkbXEtYnJlYWtwb2ludHM6IF9tcS1tYXAtc29ydC1ieS12YWx1ZSgkbXEtYnJlYWtwb2ludHMpICFnbG9iYWw7XG59XG5cbi8vLyBTaG93IHRoZSBhY3RpdmUgYnJlYWtwb2ludCBpbiB0aGUgdG9wIHJpZ2h0IGNvcm5lciBvZiB0aGUgdmlld3BvcnRcbi8vLyBAbGluayBodHRwczovL2dpdGh1Yi5jb20vc2Fzcy1tcS9zYXNzLW1xI3NlZWluZy10aGUtY3VycmVudGx5LWFjdGl2ZS1icmVha3BvaW50XG4vLy9cbi8vLyBAcGFyYW0ge0xpc3R9ICRzaG93LWJyZWFrcG9pbnRzIFskbXEtc2hvdy1icmVha3BvaW50c10gLSBMaXN0IG9mIGJyZWFrcG9pbnRzIHRvIHNob3cgaW4gdGhlIHRvcCByaWdodCBjb3JuZXJcbi8vLyBAcGFyYW0ge01hcH0gJGJyZWFrcG9pbnRzIFskbXEtYnJlYWtwb2ludHNdIC0gQnJlYWtwb2ludCBuYW1lcyBhbmQgc2l6ZXNcbi8vL1xuLy8vIEByZXF1aXJlcyB7VmFyaWFibGV9ICRtcS1icmVha3BvaW50c1xuLy8vIEByZXF1aXJlcyB7VmFyaWFibGV9ICRtcS1zaG93LWJyZWFrcG9pbnRzXG4vLy9cbi8vLyBAZXhhbXBsZSBzY3NzXG4vLy8gIC8vIFNob3cgYnJlYWtwb2ludHMgdXNpbmcgZ2xvYmFsIHNldHRpbmdzXG4vLy8gIEBpbmNsdWRlIG1xLXNob3ctYnJlYWtwb2ludHM7XG4vLy9cbi8vLyAgLy8gU2hvdyBicmVha3BvaW50cyB1c2luZyBjdXN0b20gc2V0dGluZ3Ncbi8vLyAgQGluY2x1ZGUgbXEtc2hvdy1icmVha3BvaW50cygoTCwgWEwpLCAoUzogMzAwcHgsIEw6IDgwMHB4LCBYTDogMTIwMHB4KSk7XG5AbWl4aW4gbXEtc2hvdy1icmVha3BvaW50cygkc2hvdy1icmVha3BvaW50czogJG1xLXNob3ctYnJlYWtwb2ludHMsICRicmVha3BvaW50czogJG1xLWJyZWFrcG9pbnRzKSB7XG4gICAgYm9keTpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRkNGOEUzO1xuICAgICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI0ZCRUVENTtcbiAgICAgICAgYm9yZGVyLWxlZnQ6IDFweCBzb2xpZCAjRkJFRUQ1O1xuICAgICAgICBjb2xvcjogI0MwOTg1MztcbiAgICAgICAgZm9udDogc21hbGwtY2FwdGlvbjtcbiAgICAgICAgcGFkZGluZzogM3B4IDZweDtcbiAgICAgICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gICAgICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAgICAgcmlnaHQ6IDA7XG4gICAgICAgIHRvcDogMDtcbiAgICAgICAgei1pbmRleDogMTAwO1xuXG4gICAgICAgIC8vIExvb3AgdGhyb3VnaCB0aGUgYnJlYWtwb2ludHMgdGhhdCBzaG91bGQgYmUgc2hvd25cbiAgICAgICAgQGVhY2ggJHNob3ctYnJlYWtwb2ludCBpbiAkc2hvdy1icmVha3BvaW50cyB7XG4gICAgICAgICAgICAkd2lkdGg6IG1xLWdldC1icmVha3BvaW50LXdpZHRoKCRzaG93LWJyZWFrcG9pbnQsICRicmVha3BvaW50cyk7XG4gICAgICAgICAgICBAaW5jbHVkZSBtcSgkc2hvdy1icmVha3BvaW50LCAkYnJlYWtwb2ludHM6ICRicmVha3BvaW50cykge1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IFwiI3skc2hvdy1icmVha3BvaW50fSDiiaUgI3skd2lkdGh9ICgje21xLXB4MmVtKCR3aWR0aCl9KVwiO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5AaWYgbGVuZ3RoKCRtcS1zaG93LWJyZWFrcG9pbnRzKSA+IDAge1xuICAgIEBpbmNsdWRlIG1xLXNob3ctYnJlYWtwb2ludHM7XG59XG4iLCJAbWl4aW4gdS1pbWFnZS1hdXRvd2lkdGgge1xuICBtYXgtd2lkdGg6MTAwJTsgXG4gIGRpc3BsYXk6YmxvY2s7IFxuICBoZWlnaHQ6YXV0bzsgXG59IiwiQG1peGluIHUtcmVtb3ZlLWJ1dHRvbi1zdHlsaW5nIHtcbiAgYm9yZGVyOm5vbmU7IFxuICBiYWNrZ3JvdW5kOm5vbmU7IFxuICBib3gtc2hhZG93Om5vbmU7IFxuICBwYWRkaW5nOjA7IFxufSIsIi8vICFEZXYgcmVsYXRlZCBzdHlsZXNcbi5jLWVkaXQtbGluayB7XG4gIHBvc2l0aW9uOiBmaXhlZDsgXG4gIHRvcDogMWVtOyBcbiAgbGVmdDogMWVtOyBcbiAgb3BhY2l0eTogMDsgXG4gICY6aG92ZXIge1xuICAgIG9wYWNpdHk6IDE7IFxuICB9XG59XG4iXX0= */
455 |
--------------------------------------------------------------------------------