Easy Table of Contents - Version 2.0-rc11

Version Description

Download this release

Release Info

Developer shazahm1@hotmail.com
Plugin Icon 128x128 Easy Table of Contents
Version 2.0-rc11
Comparing to
See all releases

Code changes from version 1.7.1 to 2.0-rc11

README.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: shazahm1@hotmail.com
3
  Donate link: http://connections-pro.com/
4
  Tags: table of contents, toc
5
- Requires at least: 4.4
6
  Tested up to: 5.3
7
- Requires PHP: 5.3
8
  Stable tag: 1.7.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -17,6 +17,9 @@ A user friendly, featured focused plugin which allows you to insert a table of c
17
 
18
  = Features =
19
  * Automatically generate a table of contents for your posts, pages and custom post types by parsing its contents for headers.
 
 
 
20
  * Optionally enable for pages and/or posts. Custom post types are supported, as long as their content is output with the `the_content()` template tag.
21
  * Optionally auto insert the table of contents into the page, selectable by enabled post type.
22
  * Provides many easy to understand options to configure when and where to insert the table of contents.
@@ -43,13 +46,9 @@ Here are links to documentation pages for several of the premium templates for t
43
 
44
  = Roadmap =
45
  * Fragment caching for improved performance.
46
- * Support for `<!--nextpage-->`.
47
- * Customizer support.
48
-
49
- = Requirements =
50
-
51
- * **WordPress version:** >= 3.2
52
- * **PHP version:** >= 5.2.4
53
 
54
  = Credit =
55
 
@@ -90,8 +89,44 @@ Easy Table Contents is a fork of the excellent [Table of Contents Plus](https://
90
 
91
  == Changelog ==
92
 
93
- = 1.7.1 02/18/2020 =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  * BUG: Sanitize the excluded heading string before saving post meta.
 
 
95
 
96
  = 1.7 05/09/2018 =
97
  * NEW: Introduce the `ez_toc_shortcode` filter.
@@ -272,3 +307,6 @@ Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
272
 
273
  = 1.7 =
274
  Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
 
 
 
2
  Contributors: shazahm1@hotmail.com
3
  Donate link: http://connections-pro.com/
4
  Tags: table of contents, toc
5
+ Requires at least: 5.2
6
  Tested up to: 5.3
7
+ Requires PHP: 5.6.20
8
  Stable tag: 1.7.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
17
 
18
  = Features =
19
  * Automatically generate a table of contents for your posts, pages and custom post types by parsing its contents for headers.
20
+ * Supports the `<!--nextpage-->` tag.
21
+ * Supports the Rank Math plugin.
22
+ * Supports the Classic Editor, Gutenberg, Elementor, WPBakery Page Builder and Visual Composer page editors.
23
  * Optionally enable for pages and/or posts. Custom post types are supported, as long as their content is output with the `the_content()` template tag.
24
  * Optionally auto insert the table of contents into the page, selectable by enabled post type.
25
  * Provides many easy to understand options to configure when and where to insert the table of contents.
46
 
47
  = Roadmap =
48
  * Fragment caching for improved performance.
49
+ * Improve SEO by adding options to add nofollow to TOC link and wrap TOC nav in noindex tag.
50
+ * Improve accessibility.
51
+ * Add Bullet and Arrow options for list counter style.
 
 
 
 
52
 
53
  = Credit =
54
 
89
 
90
  == Changelog ==
91
 
92
+ = 2.0 02/01/2020 =
93
+ * NEW: Major rewrite of all code and processing logic to make it faster and more reliable.
94
+ * NEW: Support for the <!--nextpage--> tag.
95
+ * NEW: Introduce helper functions for devs.
96
+ * NEW: Support WPML.
97
+ * NEW: Support Polylang.
98
+ * NEW: Add filter to support the Rank Math plugin.
99
+ * NEW: Introduce the `ez_toc_maybe_apply_the_content_filter` filter.
100
+ * TWEAK: Improve translation compatibility.
101
+ * TWEAK: Rework widget logic to allow multi-line TOC items, improve active item highlighting while removing the use of the jQuery Waypoints library.
102
+ * TWEAK Add additional classes to TOC list items.
103
+ * TWEAK: Add WOFF2 format for icon format and change font references in CSS.
104
+ * TWEAK: Add font-display: swap for toggle icon.
105
+ * TWEAK: Update JS Cookie to 2.2.1.
106
+ * TWEAK: Update jQuery Smooth Scroll to 2.2.0.
107
+ * TWEAK: Allow forward slash and angle brackets in headings and alternate headings.
108
+ * TWEAK: Allow forward slash in excluded headings.
109
+ * TWEAK: Remove new line/returns when matching excluded headings.
110
+ * TWEAK: Simple transient cache to ensure a post is only processed once per request for a TOC.
111
+ * TWEAK: Improve sanitization of alternate headings field value.
112
+ * TWEAK: Deal with non-breaking-spaces in alternate headings.
113
+ * TWEAK: Add the ability to exclude by selector content eligible to be included in the TOC.
114
+ * TWEAK: Change the shortcode priority to a higher value.
115
+ * TWEAK: Add filter to remove shortcodes from the content prior to the `the_content` filter being run to exclude shortcode content from being eligible as TOC items.
116
+ * TWEAK: Add compatibility filters to remove shortcodes for Connections and Striking theme to remove them from eligible TOC item content.
117
+ * TWEAK: Do not execute if root current filter is the `wp_head` or `get_the_excerpt` filters.
118
+ * TWEAK: Add filter to exclude content by selector.
119
+ * TWEAK: Move in-page anchor to after the heading instead of wrapping the heading to prevent conflicts with theme styling.
120
+ * TWEAK: Utilize the `ez_toc_exclude_by_selector` filter the exclude the JetPack share buttons from eligible headings.
121
+ * TWEAK: Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
122
+ * TWEAK: Add compatibility filter for the Visual Composer plugin.
123
+ * I18N: Add wpml-config.xml file.
124
+ * BUG: Correct option misspelling.
125
+ * BUG: Do not need to run values for alternate and exclude headings thru `wp_unslash()` because `update_post_meta()` already does.
126
+ * BUG: Do not need to run `stripslashes()` when escaping the alternate heading value.
127
  * BUG: Sanitize the excluded heading string before saving post meta.
128
+ * DEV: Change PHP keywords to comply with PSR2.
129
+ * DEV:Bump minimum PHP version to 5.6.20 which matches WP core.
130
 
131
  = 1.7 05/09/2018 =
132
  * NEW: Introduce the `ez_toc_shortcode` filter.
307
 
308
  = 1.7 =
309
  Requires WordPress >= 4.4 and PHP >= 5.3. PHP version >= 7.1 recommended.
310
+
311
+ = 2.0-rc4 =
312
+ Requires WordPress >= 5.0 and PHP version >= 5.6.20 (>= 7.1 is recommended).
assets/css/screen.css CHANGED
@@ -12,10 +12,9 @@
12
  width: auto;
13
  }
14
 
15
- .ez-toc-widget-container {
16
- /*padding: 0 10px;*/
17
  position: relative;
18
- white-space: nowrap;
19
  }
20
 
21
  #ez-toc-container.ez-toc-light-blue {
@@ -34,8 +33,17 @@
34
  background: none transparent;
35
  }
36
 
37
- .ez-toc-widget-container ul.ez-toc-list {
38
- padding: 0 10px;
 
 
 
 
 
 
 
 
 
39
  }
40
 
41
  #ez-toc-container ul ul,
@@ -52,11 +60,10 @@
52
  #ez-toc-container ul,
53
  #ez-toc-container li,
54
  #ez-toc-container ul li,
55
- .ez-toc-widget-container,
56
- .ez-toc-widget-container li {
57
  background: none;
58
- list-style-type: none;
59
- list-style: none;
60
  line-height: 1.6;
61
  margin: 0;
62
  overflow: hidden;
12
  width: auto;
13
  }
14
 
15
+ div.ez-toc-widget-container {
16
+ padding: 0;
17
  position: relative;
 
18
  }
19
 
20
  #ez-toc-container.ez-toc-light-blue {
33
  background: none transparent;
34
  }
35
 
36
+ div.ez-toc-widget-container ul {
37
+ display: block;
38
+ }
39
+
40
+ div.ez-toc-widget-container li {
41
+ border: none;
42
+ padding: 0;
43
+ }
44
+
45
+ div.ez-toc-widget-container ul.ez-toc-list {
46
+ padding: 10px;
47
  }
48
 
49
  #ez-toc-container ul ul,
60
  #ez-toc-container ul,
61
  #ez-toc-container li,
62
  #ez-toc-container ul li,
63
+ div.ez-toc-widget-container,
64
+ div.ez-toc-widget-container li {
65
  background: none;
66
+ list-style: none none;
 
67
  line-height: 1.6;
68
  margin: 0;
69
  overflow: hidden;
assets/css/screen.min.css CHANGED
@@ -1 +1 @@
1
- #ez-toc-container{background:#F9F9F9;border:1px solid #AAA;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}.ez-toc-widget-container{position:relative;white-space:nowrap}#ez-toc-container.ez-toc-light-blue{background:#EDF6FF}#ez-toc-container.ez-toc-white{background:#FFF}#ez-toc-container.ez-toc-black{background:#000}#ez-toc-container.ez-toc-transparent{background:none}.ez-toc-widget-container ul.ez-toc-list{padding:0 10px}#ez-toc-container ul ul,.ez-toc div.ez-toc-widget-container ul ul{margin-left:1.5em}#ez-toc-container li,#ez-toc-container ul{padding:0}#ez-toc-container li,#ez-toc-container ul,#ez-toc-container ul li,.ez-toc-widget-container,.ez-toc-widget-container li{background:0 0;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}.btn.active,.ez-toc-btn,.ez-toc-btn-default.active,.ez-toc-btn-default:active,.ez-toc-btn:active{background-image:none}#ez-toc-container p.ez-toc-title{text-align:left;line-height:1.45;margin:0;padding:0}.ez-toc-title-container{display:table;width:100%}.ez-toc-title,.ez-toc-title-toggle{display:table-cell;text-align:left;vertical-align:middle}#ez-toc-container.ez-toc-black p.ez-toc-title{color:#FFF}#ez-toc-container div.ez-toc-title-container+ul.ez-toc-list{margin-top:1em}.ez-toc-wrap-left{float:left;margin-right:10px}.ez-toc-wrap-right{float:right;margin-left:10px}#ez-toc-container a{color:#444;text-decoration:none;text-shadow:none}#ez-toc-container a:visited{color:#9f9f9f}#ez-toc-container a:hover{text-decoration:underline}#ez-toc-container.ez-toc-black a,#ez-toc-container.ez-toc-black a:visited{color:#FFF}#ez-toc-container a.ez-toc-toggle{color:#444}#ez-toc-container.counter-flat ul,#ez-toc-container.counter-hierarchy ul,.ez-toc-widget-container.counter-flat ul,.ez-toc-widget-container.counter-hierarchy ul{counter-reset:item}#ez-toc-container.counter-numeric li,.ez-toc-widget-container.counter-numeric li{list-style-type:decimal;list-style-position:inside}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before,.ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before{content:counters(item,".") ". ";counter-increment:item}#ez-toc-container.counter-roman li a::before,.ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before{content:counters(item,".",upper-roman) ". ";counter-increment:item}.ez-toc-widget-container ul.ez-toc-list li::before{content:' ';position:absolute;left:0;right:0;height:30px;line-height:30px;z-index:-1}.ez-toc-widget-container ul.ez-toc-list li.active::before{background-color:#EDEDED}.ez-toc-widget-container li.active>a{font-weight:900}.ez-toc-btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.ez-toc-btn:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.ez-toc-btn:focus,.ez-toc-btn:hover{color:#333;text-decoration:none}.ez-toc-btn.active,.ez-toc-btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-btn-default{color:#333;background-color:#fff;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.ez-toc-btn-default.active,.ez-toc-btn-default:active,.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{color:#333;background-color:#ebebeb;border-color:#adadad}.ez-toc-btn-sm,.ez-toc-btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.ez-toc-glyphicon,[class*=ez-toc-icon-]{font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ez-toc-btn-xs{padding:1px 5px}.ez-toc-btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.ez-toc-btn-default.active,.ez-toc-btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.ez-toc-pull-right{float:right!important;margin-left:10px}.ez-toc-glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings'}.ez-toc-glyphicon:empty{width:1em}.ez-toc-toggle i.ez-toc-glyphicon{font-size:16px;margin-left:2px}[class*=ez-toc-icon-]{font-family:ez-toc-icomoon!important;speak:none;font-variant:normal;text-transform:none}.ez-toc-icon-toggle:before{content:"\e87a"}
1
+ #ez-toc-container{background:#F9F9F9;border:1px solid #AAA;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);display:table;margin-bottom:1em;padding:10px;position:relative;width:auto}div.ez-toc-widget-container{padding:0;position:relative;}#ez-toc-container.ez-toc-light-blue{background:#EDF6FF}#ez-toc-container.ez-toc-white{background:#FFF}#ez-toc-container.ez-toc-black{background:#000}#ez-toc-container.ez-toc-transparent{background:none}div.ez-toc-widget-container ul{display:block}div.ez-toc-widget-container li{border:none;padding:0}div.ez-toc-widget-container ul.ez-toc-list{padding:10px}#ez-toc-container ul ul,.ez-toc div.ez-toc-widget-container ul ul{margin-left:1.5em}#ez-toc-container li,#ez-toc-container ul{padding:0}#ez-toc-container li,#ez-toc-container ul,#ez-toc-container ul li,div.ez-toc-widget-container,div.ez-toc-widget-container li{background:0 0;list-style:none;line-height:1.6;margin:0;overflow:hidden;z-index:1}.btn.active,.ez-toc-btn,.ez-toc-btn-default.active,.ez-toc-btn-default:active,.ez-toc-btn:active{background-image:none}#ez-toc-container p.ez-toc-title{text-align:left;line-height:1.45;margin:0;padding:0}.ez-toc-title-container{display:table;width:100%}.ez-toc-title,.ez-toc-title-toggle{display:table-cell;text-align:left;vertical-align:middle}#ez-toc-container.ez-toc-black p.ez-toc-title{color:#FFF}#ez-toc-container div.ez-toc-title-container+ul.ez-toc-list{margin-top:1em}.ez-toc-wrap-left{float:left;margin-right:10px}.ez-toc-wrap-right{float:right;margin-left:10px}#ez-toc-container a{color:#444;text-decoration:none;text-shadow:none}#ez-toc-container a:visited{color:#9f9f9f}#ez-toc-container a:hover{text-decoration:underline}#ez-toc-container.ez-toc-black a,#ez-toc-container.ez-toc-black a:visited{color:#FFF}#ez-toc-container a.ez-toc-toggle{color:#444}#ez-toc-container.counter-flat ul,#ez-toc-container.counter-hierarchy ul,.ez-toc-widget-container.counter-flat ul,.ez-toc-widget-container.counter-hierarchy ul{counter-reset:item}#ez-toc-container.counter-numeric li,.ez-toc-widget-container.counter-numeric li{list-style-type:decimal;list-style-position:inside}#ez-toc-container.counter-decimal ul.ez-toc-list li a::before,.ez-toc-widget-container.counter-decimal ul.ez-toc-list li a::before{content:counters(item,".") ". ";counter-increment:item}#ez-toc-container.counter-roman li a::before,.ez-toc-widget-container.counter-roman ul.ez-toc-list li a::before{content:counters(item,".",upper-roman) ". ";counter-increment:item}.ez-toc-widget-container ul.ez-toc-list li::before{content:' ';position:absolute;left:0;right:0;height:30px;line-height:30px;z-index:-1}.ez-toc-widget-container ul.ez-toc-list li.active::before{background-color:#EDEDED}.ez-toc-widget-container li.active>a{font-weight:900}.ez-toc-btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.ez-toc-btn:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.ez-toc-btn:focus,.ez-toc-btn:hover{color:#333;text-decoration:none}.ez-toc-btn.active,.ez-toc-btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-btn-default{color:#333;background-color:#fff;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.ez-toc-btn-default.active,.ez-toc-btn-default:active,.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{color:#333;background-color:#ebebeb;border-color:#adadad}.ez-toc-btn-sm,.ez-toc-btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.ez-toc-glyphicon,[class*=ez-toc-icon-]{font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ez-toc-btn-xs{padding:1px 5px}.ez-toc-btn-default:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.ez-toc-btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.ez-toc-btn-default:focus,.ez-toc-btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.ez-toc-btn-default.active,.ez-toc-btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.ez-toc-pull-right{float:right!important;margin-left:10px}.ez-toc-glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings'}.ez-toc-glyphicon:empty{width:1em}.ez-toc-toggle i.ez-toc-glyphicon{font-size:16px;margin-left:2px}[class*=ez-toc-icon-]{font-family:ez-toc-icomoon!important;speak:none;font-variant:normal;text-transform:none}.ez-toc-icon-toggle:before{content:"\e87a"}
assets/js/front.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery( document ).ready( function( $ ) {
2
 
3
  if ( typeof ezTOC != 'undefined' ) {
4
 
@@ -99,8 +99,11 @@ jQuery( document ).ready( function( $ ) {
99
  if ( target ) {
100
  $.smoothScroll( {
101
  scrollTarget: target,
102
- offset: offset
 
 
103
  } );
 
104
  }
105
  }
106
  } );
@@ -167,54 +170,127 @@ jQuery( document ).ready( function( $ ) {
167
  } );
168
  }
169
 
170
- // ======================================
171
- // Waypoints helper functions
172
- // ======================================
173
-
174
- // Get link by section or article id
175
- function getRelatedNavigation( element ) {
176
- return $( '.ez-toc-widget-container .ez-toc-list a[href="#' + $( element ).attr( 'id' ) + '"]' );
177
- }
178
-
179
- function getScrollOffset( element ) {
180
-
181
- var scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
182
- var offset = $( element ).height() + scrollOffset;
183
-
184
- var adminbar = $( '#wpadminbar' );
185
-
186
- if ( 0 === adminbar.length ) {
187
-
188
- offset = offset-30;
189
- }
190
-
191
- return parseInt( offset );
192
- }
193
-
194
- // ======================================
195
- // Waypoints
196
- // ======================================
197
-
198
- $('span.ez-toc-section')
199
- .waypoint( function( direction ) {
200
- // Highlight element when related content is 10% percent from the bottom - remove if below.
201
- var item = getRelatedNavigation( this.element ).toggleClass( 'active', direction === 'down' );
202
- item.toggleClass( 'active', direction === 'down' ).parent().toggleClass( 'active', direction === 'down' );
203
- }, {
204
- offset: '90%' //
205
- });
206
- $('span.ez-toc-section')
207
- .waypoint( function( direction ) {
208
- // Highlight element when bottom of related content is 30px from the top - remove if less.
209
- var item = getRelatedNavigation( this.element ).toggleClass( 'active', direction === 'up' );
210
- item.toggleClass( 'active', direction === 'up' ).parent().toggleClass( 'active', direction === 'up' );
211
- }, {
212
- offset: getScrollOffset( this.element )
213
- });
214
-
215
-
216
- var div_height = $('.ez-toc-widget-container ul.ez-toc-list li').css('line-height');
217
 
218
- $('<style>.ez-toc-widget-container ul.ez-toc-list li::before{line-height:' + div_height + ';height:' + div_height + '}</style>').appendTo('head');
219
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  } );
1
+ jQuery( function( $ ) {
2
 
3
  if ( typeof ezTOC != 'undefined' ) {
4
 
99
  if ( target ) {
100
  $.smoothScroll( {
101
  scrollTarget: target,
102
+ offset: offset,
103
+ beforeScroll: deactivateSetActiveEzTocListElement,
104
+ afterScroll: function() { setActiveEzTocListElement(); activateSetActiveEzTocListElement(); }
105
  } );
106
+
107
  }
108
  }
109
  } );
170
  } );
171
  }
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
+ // ======================================
175
+ // Set active heading in ez-toc-widget list
176
+ // ======================================
177
+
178
+ var headings = $( 'span.ez-toc-section' ).toArray();
179
+ var headingToListElementLinkMap = getHeadingToListElementLinkMap( headings );
180
+ var listElementLinks = $.map( headingToListElementLinkMap, function ( value, key ) {
181
+ return value
182
+ } );
183
+ var scrollOffset = getScrollOffset();
184
+
185
+ activateSetActiveEzTocListElement();
186
+
187
+ function setActiveEzTocListElement() {
188
+ var activeHeading = getActiveHeading( scrollOffset, headings );
189
+ if ( activeHeading ) {
190
+ var activeListElementLink = headingToListElementLinkMap[ activeHeading.id ];
191
+ removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks );
192
+ setStyleForActiveListElementElement( activeListElementLink );
193
+ }
194
+ };
195
+
196
+ function activateSetActiveEzTocListElement() {
197
+ if ( headings.length > 0 && $('.ez-toc-widget-container').length) {
198
+ $( window ).on( 'load resize scroll', setActiveEzTocListElement );
199
+ }
200
+ }
201
+
202
+ function deactivateSetActiveEzTocListElement() {
203
+ $( window ).off( 'load resize scroll', setActiveEzTocListElement );
204
+ }
205
+
206
+ function getEzTocListElementLinkByHeading( heading ) {
207
+ return $( '.ez-toc-widget-container .ez-toc-list a[href="#' + $( heading ).attr( 'id' ) + '"]' );
208
+ }
209
+
210
+ function getHeadingToListElementLinkMap( headings ) {
211
+ return headings.reduce( function ( map, heading ) {
212
+ map[ heading.id ] = getEzTocListElementLinkByHeading( heading );
213
+ return map;
214
+ }, {} );
215
+ }
216
+
217
+ function getScrollOffset() {
218
+ var scrollOffset = 5; // so if smooth offset is off, the correct title is set as active
219
+ if ( typeof ezTOC.smooth_scroll != 'undefined' && parseInt( ezTOC.smooth_scroll ) === 1 ) {
220
+ scrollOffset = ( typeof ezTOC.scroll_offset != 'undefined' ) ? parseInt( ezTOC.scroll_offset ) : 30;
221
+ }
222
+
223
+ var adminbar = $( '#wpadminbar' );
224
+
225
+ if ( adminbar.length ) {
226
+ scrollOffset += adminbar.height();
227
+ }
228
+ return scrollOffset;
229
+ }
230
+
231
+ function getActiveHeading( topOffset, headings ) {
232
+ var scrollTop = $( window ).scrollTop();
233
+ var relevantOffset = scrollTop + topOffset + 1;
234
+ var activeHeading = headings[ 0 ];
235
+ var closestHeadingAboveOffset = relevantOffset - $( activeHeading ).offset().top;
236
+ headings.forEach( function ( section ) {
237
+ var topOffset = relevantOffset - $( section ).offset().top;
238
+ if ( topOffset > 0 && topOffset < closestHeadingAboveOffset ) {
239
+ closestHeadingAboveOffset = topOffset;
240
+ activeHeading = section;
241
+ }
242
+ } );
243
+ return activeHeading;
244
+ }
245
+
246
+ function removeStyleFromNonActiveListElement( activeListElementLink, listElementLinks ) {
247
+ listElementLinks.forEach( function ( listElementLink ) {
248
+ if ( activeListElementLink !== listElementLink && listElementLink.parent().hasClass( 'active' ) ) {
249
+ listElementLink.parent().removeClass( 'active' );
250
+ }
251
+ } );
252
+ }
253
+
254
+ function correctActiveListElementBackgroundColorHeight( activeListElement ) {
255
+ var listElementHeight = getListElementHeightWithoutUlChildren( activeListElement );
256
+ addListElementBackgroundColorHeightStyleToHead( listElementHeight );
257
+ }
258
+
259
+ function getListElementHeightWithoutUlChildren( listElement ) {
260
+ var $listElement = $( listElement );
261
+ var content = $listElement.html();
262
+ // Adding list item with class '.active' to get the real height.
263
+ // When adding a class to an existing element and using jQuery(..).height() directly afterwards,
264
+ // the height is the 'old' height. The height might change due to text-wraps when setting the text-weight bold for example
265
+ // When adding a new item, the height is calculated correctly.
266
+ // But only when it might be visible (so display:none; is not possible...)
267
+ // But because it get's directly removed afterwards it never will be rendered by the browser
268
+ // (at least in my tests in FF, Chrome, IE11 and Edge)
269
+ $listElement.parent().append( '<li id="ez-toc-height-test" class="active">' + content + '</li>' );
270
+ var height = jQuery( '#ez-toc-height-test' ).height();
271
+ jQuery( '#ez-toc-height-test' ).remove();
272
+ return height - $listElement.children( 'ul' ).first().height();
273
+ }
274
+
275
+ function addListElementBackgroundColorHeightStyleToHead( listElementHeight ) {
276
+ // Remove existing
277
+ $( '#ez-toc-active-height' ).remove();
278
+ // jQuery(..).css(..) doesn't work, because ::before is a pseudo element and not part of the DOM
279
+ // Workaround is to add it to head
280
+ $( '<style id="ez-toc-active-height">' +
281
+ '.ez-toc-widget-container ul.ez-toc-list li.active::before {' +
282
+ // 'line-heigh:' + listElementHeight + 'px; ' +
283
+ 'height:' + listElementHeight + 'px;' +
284
+ '} </style>' )
285
+ .appendTo( 'head' );
286
+ }
287
+
288
+ function setStyleForActiveListElementElement( activeListElementLink ) {
289
+ var activeListElement = activeListElementLink.parent();
290
+ if ( !activeListElement.hasClass( 'active' ) ) {
291
+ activeListElement.addClass( 'active' );
292
+ }
293
+ correctActiveListElementBackgroundColorHeight( activeListElement );
294
+ }
295
+ }
296
  } );
assets/js/front.min.js CHANGED
@@ -1,6 +1 @@
1
- jQuery(document).ready(function(a){if("undefined"!=typeof ezTOC){var f=function(b){return a('.ez-toc-widget-container .ez-toc-list a[href="#'+a(b).attr("id")+'"]')};if(0!==a(".ez-toc-widget-container.ez-toc-affix").length){var c=30;"undefined"!=typeof ezTOC.scroll_offset&&(c=ezTOC.scroll_offset);a(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:parseInt(c)})}a.fn.shrinkTOCWidth=function(){a(this).css({width:"auto",display:"table"});/MSIE 7\./.test(navigator.userAgent)&&a(this).css("width",
2
- "")};if(1==ezTOC.smooth_scroll){var d=hostname=pathname=qs=hash=null;a("body a").click(function(b){hostname=a(this).prop("hostname");pathname=a(this).prop("pathname");qs=a(this).prop("search");hash=a(this).prop("hash");0<pathname.length&&"/"!=pathname.charAt(0)&&(pathname="/"+pathname);window.location.hostname==hostname&&window.location.pathname==pathname&&window.location.search==qs&&""!==hash&&(b=hash.replace(/([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g,"\\$1"),0<a(b).length?d=hash:(anchor=hash,anchor=
3
- anchor.replace("#",""),d='a[name="'+anchor+'"]',0==a(d).length&&(d="")),"undefined"!=typeof ezTOC.scroll_offset?b=-1*ezTOC.scroll_offset:(b=a("#wpadminbar"),b=0<b.length?b.is(":visible")?-30:0:0),d&&a.smoothScroll({scrollTarget:d,offset:b}))})}if("undefined"!=typeof ezTOC.visibility_hide_by_default){c=a("a.ez-toc-toggle");var e=ezTOC.visibility_hide_by_default;Cookies?1==Cookies.get("ezTOC_hidetoc")?c.data("visible",!1):c.data("visible",!0):c.data("visible",!0);e&&c.data("visible",!1);c.data("visible")||
4
- a("ul.ez-toc-list").hide();c.click(function(b){b.preventDefault();a(this).data("visible")?(a(this).data("visible",!1),Cookies&&(e?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),a("ul.ez-toc-list").hide("fast")):(a(this).data("visible",!0),Cookies&&(e?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),a("ul.ez-toc-list").show("fast"))})}a("span.ez-toc-section").waypoint(function(a){f(this.element).toggleClass("active",
5
- "down"===a).toggleClass("active","down"===a).parent().toggleClass("active","down"===a)},{offset:"90%"});a("span.ez-toc-section").waypoint(function(a){f(this.element).toggleClass("active","up"===a).toggleClass("active","up"===a).parent().toggleClass("active","up"===a)},{offset:function(b){var c="undefined"!=typeof ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30;b=a(b).height()+c;0===a("#wpadminbar").length&&(b-=30);return parseInt(b)}(this.element)});c=a(".ez-toc-widget-container ul.ez-toc-list li").css("line-height");
6
- a("<style>.ez-toc-widget-container ul.ez-toc-list li::before{line-height:"+c+";height:"+c+"}</style>").appendTo("head")}});
1
+ jQuery(function(l){if("undefined"!=typeof ezTOC){if(0!==l(".ez-toc-widget-container.ez-toc-affix").length){var e=30;void 0!==ezTOC.scroll_offset&&(e=ezTOC.scroll_offset),l(ezTOC.affixSelector).stick_in_parent({inner_scrolling:!1,offset_top:parseInt(e)})}if(l.fn.shrinkTOCWidth=function(){l(this).css({width:"auto",display:"table"}),/MSIE 7\./.test(navigator.userAgent)&&l(this).css("width","")},1==ezTOC.smooth_scroll){var a=hostname=pathname=qs=hash=null;l("body a").click(function(e){if(hostname=l(this).prop("hostname"),pathname=l(this).prop("pathname"),qs=l(this).prop("search"),hash=l(this).prop("hash"),0<pathname.length&&"/"!=pathname.charAt(0)&&(pathname="/"+pathname),window.location.hostname==hostname&&window.location.pathname==pathname&&window.location.search==qs&&""!==hash){var t=hash.replace(/([ !"$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g,"\\$1");if(0<l(t).length?a=hash:(anchor=hash,anchor=anchor.replace("#",""),a='a[name="'+anchor+'"]',0==l(a).length&&(a="")),void 0!==ezTOC.scroll_offset)var i=-1*ezTOC.scroll_offset;else{var o=l("#wpadminbar");i=0<o.length&&o.is(":visible")?-30:0}a&&l.smoothScroll({scrollTarget:a,offset:i,beforeScroll:h,afterScroll:function(){s(),n()}})}})}if(void 0!==ezTOC.visibility_hide_by_default){var t=l("a.ez-toc-toggle"),i=ezTOC.visibility_hide_by_default;Cookies&&1==Cookies.get("ezTOC_hidetoc")?t.data("visible",!1):t.data("visible",!0),i&&t.data("visible",!1),t.data("visible")||l("ul.ez-toc-list").hide(),t.click(function(e){e.preventDefault(),l(this).data("visible")?(l(this).data("visible",!1),Cookies&&(i?Cookies.set("ezTOC_hidetoc",null,{path:"/"}):Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"})),l("ul.ez-toc-list").hide("fast")):(l(this).data("visible",!0),Cookies&&(i?Cookies.set("ezTOC_hidetoc","1",{expires:30,path:"/"}):Cookies.set("ezTOC_hidetoc",null,{path:"/"})),l("ul.ez-toc-list").show("fast"))})}var r=l("span.ez-toc-section").toArray(),c=r.reduce(function(e,t){return e[t.id]=l('.ez-toc-widget-container .ez-toc-list a[href="#'+l(t).attr("id")+'"]'),e},{}),f=l.map(c,function(e,t){return e}),d=function(){var e=5;void 0!==ezTOC.smooth_scroll&&1===parseInt(ezTOC.smooth_scroll)&&(e=void 0!==ezTOC.scroll_offset?parseInt(ezTOC.scroll_offset):30);var t=l("#wpadminbar");t.length&&(e+=t.height());return e}();function s(){var e,t,i,o,a,s,n=(e=d,t=r,i=l(window).scrollTop()+e+1,o=t[0],a=i-l(o).offset().top,t.forEach(function(e){var t=i-l(e).offset().top;0<t&&t<a&&(a=t,o=e)}),o);if(n){var h=c[n.id];s=h,f.forEach(function(e){s!==e&&e.parent().hasClass("active")&&e.parent().removeClass("active")}),function(e){var t=e.parent();t.hasClass("active")||t.addClass("active");i=t,o=function(e){var t=l(e),i=t.html();t.parent().append('<li id="ez-toc-height-test" class="active">'+i+"</li>");var o=jQuery("#ez-toc-height-test").height();return jQuery("#ez-toc-height-test").remove(),o-t.children("ul").first().height()}(i),l("#ez-toc-active-height").remove(),l('<style id="ez-toc-active-height">.ez-toc-widget-container ul.ez-toc-list li.active::before {height:'+o+"px;} </style>").appendTo("head");var i,o}(h)}}function n(){0<r.length&&l(".ez-toc-widget-container").length&&l(window).on("load resize scroll",s)}function h(){l(window).off("load resize scroll",s)}n()}});
 
 
 
 
 
easy-table-of-contents.php CHANGED
@@ -3,13 +3,13 @@
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: http://connections-pro.com/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
- * Version: 1.7.1
7
  * Author: Steven A. Zahm
8
  * Author URI: http://connections-pro.com/
9
  * Text Domain: easy-table-of-contents
10
  * Domain Path: /languages
11
  *
12
- * Copyright 2018 Steven A. Zahm ( email : helpdesk@connections-pro.com )
13
  *
14
  * Easy Table of Contents is free software; you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License, version 2, as
@@ -26,9 +26,11 @@
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Steven A. Zahm
29
- * @version 1.7.1
30
  */
31
 
 
 
32
  // Exit if accessed directly
33
  if ( ! defined( 'ABSPATH' ) ) exit;
34
 
@@ -45,7 +47,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
45
  * @since 1.0
46
  * @var string
47
  */
48
- const VERSION = '1.7.1';
49
 
50
  /**
51
  * Stores the instance of this class.
@@ -59,15 +61,10 @@ if ( ! class_exists( 'ezTOC' ) ) {
59
  private static $instance;
60
 
61
  /**
62
- * Keeps a track of used anchors for collision detecting.
63
- *
64
- * @access private
65
- * @since 1.0
66
- * @static
67
- *
68
  * @var array
69
  */
70
- private static $collision_collector = array();
71
 
72
  /**
73
  * A dummy constructor to prevent the class from being loaded more than once.
@@ -132,7 +129,12 @@ if ( ! class_exists( 'ezTOC' ) ) {
132
  require_once( EZ_TOC_PATH . 'includes/class.admin.php' );
133
  }
134
 
 
135
  require_once( EZ_TOC_PATH . 'includes/class.widget-toc.php' );
 
 
 
 
136
  }
137
 
138
  /**
@@ -198,11 +200,13 @@ if ( ! class_exists( 'ezTOC' ) ) {
198
  } else {
199
 
200
  // Load the default language files
201
- load_plugin_textdomain( $domain, FALSE, $languagesDirectory );
202
  }
203
  }
204
 
205
  /**
 
 
206
  * Register and enqueue CSS and javascript files for frontend.
207
  *
208
  * @access private
@@ -212,18 +216,17 @@ if ( ! class_exists( 'ezTOC' ) ) {
212
  public static function enqueueScripts() {
213
 
214
  // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
215
- $min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
216
 
217
  $js_vars = array();
218
 
219
  wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
220
  wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
221
 
222
- wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.0.3', TRUE );
223
- wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '1.5.5', TRUE );
224
  wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
225
- wp_register_script( 'jquery-waypoints', EZ_TOC_URL . "vendor/waypoints/jquery.waypoints$min.js", array( 'jquery' ), '1.9.2', TRUE );
226
- wp_register_script( 'ez-toc-js', EZ_TOC_URL . "assets/js/front$min.js", array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit', 'jquery-waypoints' ), ezTOC::VERSION, TRUE );
227
 
228
  if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
229
 
@@ -233,7 +236,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
233
 
234
  if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
235
 
236
- $js_vars['smooth_scroll'] = TRUE;
237
  }
238
 
239
  //wp_enqueue_script( 'ez-toc-js' );
@@ -242,7 +245,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
242
 
243
  $width = ezTOC_Option::get( 'width' ) != 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
244
 
245
- $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? TRUE : FALSE;
246
 
247
  $js_vars['width'] = esc_js( $width );
248
  }
@@ -307,7 +310,7 @@ if ( ! class_exists( 'ezTOC' ) ) {
307
  $css .= '}';
308
  }
309
 
310
- if ( 'custom' == ezTOC_Option::get( 'theme' ) ) {
311
 
312
  $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
313
  //$css .= 'div#ez-toc-container p.ez-toc-title a,div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
@@ -323,505 +326,6 @@ if ( ! class_exists( 'ezTOC' ) ) {
323
  }
324
  }
325
 
326
- /**
327
- * Returns a URL to be used as the destination anchor target.
328
- *
329
- * @access private
330
- * @since 1.0
331
- * @static
332
- *
333
- * @param string $title
334
- *
335
- * @return bool|string
336
- */
337
- private static function url_anchor_target( $title ) {
338
-
339
- $return = FALSE;
340
-
341
- if ( $title ) {
342
-
343
- // WP entity encodes the post content.
344
- $return = html_entity_decode( $title, ENT_QUOTES, get_option( 'blog_charset' ) );
345
-
346
- $return = trim( strip_tags( $return ) );
347
-
348
- // Convert accented characters to ASCII.
349
- $return = remove_accents( $return );
350
-
351
- // replace newlines with spaces (eg when headings are split over multiple lines)
352
- $return = str_replace( array( "\r", "\n", "\n\r", "\r\n" ), ' ', $return );
353
-
354
- // Remove `&amp;` and `&nbsp;` NOTE: in order to strip "hidden" `&nbsp;`,
355
- // title needs to be converted to HTML entities.
356
- // @link https://stackoverflow.com/a/21801444/5351316
357
- $return = htmlentities2( $return );
358
- $return = str_replace( array( '&amp;', '&nbsp;' ), ' ', $return );
359
- $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
360
-
361
- // remove non alphanumeric chars
362
- $return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
363
-
364
- // convert spaces to _
365
- $return = preg_replace( '/\s+/', '_', $return );
366
-
367
- // remove trailing - and _
368
- $return = rtrim( $return, '-_' );
369
-
370
- // lowercase everything?
371
- if ( ezTOC_Option::get( 'lowercase' ) ) {
372
-
373
- $return = strtolower( $return );
374
- }
375
-
376
- // if blank, then prepend with the fragment prefix
377
- // blank anchors normally appear on sites that don't use the latin charset
378
- if ( ! $return ) {
379
-
380
- $return = ( ezTOC_Option::get( 'fragment_prefix' ) ) ? ezTOC_Option::get( 'fragment_prefix' ) : '_';
381
- }
382
-
383
- // hyphenate?
384
- if ( ezTOC_Option::get( 'hyphenate' ) ) {
385
-
386
- $return = str_replace( '_', '-', $return );
387
- $return = str_replace( '--', '-', $return );
388
- }
389
- }
390
-
391
- if ( array_key_exists( $return, self::$collision_collector ) ) {
392
-
393
- self::$collision_collector[ $return ]++;
394
- $return .= '-' . self::$collision_collector[ $return ];
395
-
396
- } else {
397
-
398
- self::$collision_collector[ $return ] = 1;
399
- }
400
-
401
- return apply_filters( 'ez_toc_url_anchor_target', $return, $title );
402
- }
403
-
404
- /**
405
- * Generates a nested unordered list for the table of contents.
406
- *
407
- * @access private
408
- * @since 1.0
409
- * @static
410
- *
411
- * @param array $matches
412
- * @param array $headings Array of headers to be considered for a TOC item.
413
- *
414
- * @return string
415
- */
416
- private static function build_hierarchy( &$matches, $headings ) {
417
-
418
- $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
419
- $html = '';
420
- $numbered_items = array();
421
- $numbered_items_min = NULL;
422
-
423
- // reset the internal collision collection
424
- self::$collision_collector = array();
425
-
426
- // find the minimum heading to establish our baseline
427
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
428
- if ( $current_depth > $matches[ $i ][2] ) {
429
- $current_depth = (int) $matches[ $i ][2];
430
- }
431
- }
432
-
433
- $numbered_items[ $current_depth ] = 0;
434
- $numbered_items_min = $current_depth;
435
-
436
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
437
-
438
- if ( $current_depth == (int) $matches[ $i ][2] ) {
439
-
440
- $html .= '<li>';
441
- }
442
-
443
- // start lists
444
- if ( $current_depth != (int) $matches[ $i ][2] ) {
445
-
446
- for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
447
-
448
- $numbered_items[ $current_depth + 1 ] = 0;
449
- $html .= '<ul><li>';
450
- }
451
- }
452
-
453
- // list item
454
- if ( in_array( $matches[ $i ][2], $headings ) ) {
455
-
456
- //$title = apply_filters( 'ez_toc_title', strip_tags( wp_kses_post( $matches[ $i ][0] ) ) );
457
- $title = strip_tags( apply_filters( 'ez_toc_title', $matches[ $i ][0] ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
458
-
459
- //$html .= '<a href="#' . self::url_anchor_target( $title ) . '">';
460
- $html .= sprintf(
461
- '<a href="%1$s" title="%2$s">',
462
- esc_url( '#' . self::url_anchor_target( $matches[ $i ][0] ) ),
463
- esc_attr( strip_tags( $title ) )
464
- );
465
-
466
- //if ( 'decimal' == ezTOC_Option::get( 'counter' ) ) {
467
- //
468
- // // attach leading numbers when lower in hierarchy
469
- // $html .= '<span class="ez-toc-number ez-toc-depth_' . ( $current_depth - $numbered_items_min + 1 ) . '">';
470
- //
471
- // for ( $j = $numbered_items_min; $j < $current_depth; $j ++ ) {
472
- //
473
- // $number = ( $numbered_items[ $j ] ) ? $numbered_items[ $j ] : 0;
474
- // $html .= $number . '.';
475
- // }
476
- //
477
- // $html .= ( $numbered_items[ $current_depth ] + 1 ) . '</span> ';
478
- // $numbered_items[ $current_depth ] ++;
479
- //}
480
-
481
- $html .= $title . '</a>';
482
- }
483
-
484
- // end lists
485
- if ( $i != count( $matches ) - 1 ) {
486
-
487
- if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
488
-
489
- for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
490
-
491
- $html .= '</li></ul>';
492
- $numbered_items[ $current_depth ] = 0;
493
- }
494
- }
495
-
496
- if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
497
-
498
- $html .= '</li>';
499
- }
500
-
501
- } else {
502
-
503
- // this is the last item, make sure we close off all tags
504
- for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth -- ) {
505
-
506
- $html .= '</li>';
507
-
508
- if ( $current_depth != $numbered_items_min ) {
509
- $html .= '</ul>';
510
- }
511
- }
512
- }
513
- }
514
-
515
- return $html;
516
- }
517
-
518
- /**
519
- * Returns a string with all items from the $find array replaced with their matching
520
- * items in the $replace array. This does a one to one replacement (rather than globally).
521
- *
522
- * This function is multibyte safe.
523
- *
524
- * $find and $replace are arrays, $string is the haystack. All variables are passed by reference.
525
- *
526
- * @access private
527
- * @since 1.0
528
- * @static
529
- *
530
- * @param bool $find
531
- * @param bool $replace
532
- * @param string $string
533
- *
534
- * @return mixed|string
535
- */
536
- private static function mb_find_replace( &$find = FALSE, &$replace = FALSE, &$string = '' ) {
537
-
538
- if ( is_array( $find ) && is_array( $replace ) && $string ) {
539
-
540
- // check if multibyte strings are supported
541
- if ( function_exists( 'mb_strpos' ) ) {
542
-
543
- for ( $i = 0; $i < count( $find ); $i ++ ) {
544
-
545
- $string = mb_substr(
546
- $string,
547
- 0,
548
- mb_strpos( $string, $find[ $i ] )
549
- ) . // everything before $find
550
- $replace[ $i ] . // its replacement
551
- mb_substr(
552
- $string,
553
- mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
554
- ) // everything after $find
555
- ;
556
- }
557
-
558
- } else {
559
-
560
- for ( $i = 0; $i < count( $find ); $i ++ ) {
561
-
562
- $string = substr_replace(
563
- $string,
564
- $replace[ $i ],
565
- strpos( $string, $find[ $i ] ),
566
- strlen( $find[ $i ] )
567
- );
568
- }
569
- }
570
- }
571
-
572
- return $string;
573
- }
574
-
575
- /**
576
- * This function extracts headings from the html formatted $content. It will pull out
577
- * only the required headings as specified in the options. For all qualifying headings,
578
- * this function populates the $find and $replace arrays (both passed by reference)
579
- * with what to search and replace with.
580
- *
581
- * Returns a HTML formatted string of list items for each qualifying heading. This
582
- * is everything between and NOT including <ul> and </ul>
583
- *
584
- * @access private
585
- * @since 1.0
586
- * @static
587
- *
588
- * @param array $find
589
- * @param array $replace
590
- * @param WP_Post $post
591
- *
592
- * @return bool|string
593
- */
594
- public static function extract_headings( &$find, &$replace, $post ) {
595
-
596
- $matches = array();
597
- $anchor = '';
598
- $items = '';
599
-
600
- $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', TRUE );
601
- $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', TRUE );
602
- $altText = get_post_meta( $post->ID, '_ez-toc-alttext', TRUE );
603
-
604
- if ( ! is_array( $headings ) ) {
605
-
606
- $headings = array();
607
- }
608
-
609
- if ( empty( $headings ) ) {
610
-
611
- $headings = ezTOC_Option::get( 'heading_levels', array() );
612
- }
613
-
614
- if ( empty( $exclude ) ) {
615
-
616
- $exclude = ezTOC_Option::get( 'exclude' );
617
- }
618
-
619
- // reset the internal collision collection as the_content may have been triggered elsewhere
620
- // eg by themes or other plugins that need to read in content such as metadata fields in
621
- // the head html tag, or to provide descriptions to twitter/facebook
622
- self::$collision_collector = array();
623
-
624
- $content = apply_filters( 'ez_toc_extract_headings_content', $post->post_content );
625
-
626
- if ( is_array( $find ) && is_array( $replace ) && $content ) {
627
-
628
- // get all headings
629
- // the html spec allows for a maximum of 6 heading depths
630
- if ( preg_match_all( '/(<h([1-6]{1})[^>]*>).*<\/h\2>/msuU', $content, $matches, PREG_SET_ORDER ) ) {
631
-
632
- // remove undesired headings (if any) as defined by heading_levels
633
- if ( count( $headings ) != 6 ) {
634
-
635
- $new_matches = array();
636
-
637
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
638
-
639
- if ( in_array( $matches[ $i ][2], $headings ) ) {
640
-
641
- $new_matches[] = $matches[ $i ];
642
- }
643
- }
644
- $matches = $new_matches;
645
- }
646
-
647
- // remove specific headings if provided via the 'exclude' property
648
- if ( $exclude ) {
649
-
650
- $excluded_headings = explode( '|', $exclude );
651
- $excluded_count = count( $excluded_headings );
652
-
653
- if ( $excluded_count > 0 ) {
654
-
655
- for ( $j = 0; $j < $excluded_count; $j++ ) {
656
-
657
- $excluded_headings[ $j ] = preg_quote( $excluded_headings[ $j ] );
658
-
659
- // escape some regular expression characters
660
- // others: http://www.php.net/manual/en/regexp.reference.meta.php
661
- $excluded_headings[ $j ] = str_replace(
662
- array( '\*' ),
663
- array( '.*' ),
664
- trim( $excluded_headings[ $j ] )
665
- );
666
- }
667
-
668
- $new_matches = array();
669
-
670
- for ( $i = 0; $i < count( $matches ); $i++ ) {
671
-
672
- $found = FALSE;
673
-
674
- for ( $j = 0; $j < $excluded_count; $j++ ) {
675
-
676
- // Since WP manipulates the post content it is required that the excluded header and
677
- // the actual header be manipulated similarly so a match can be made.
678
- $pattern = html_entity_decode(
679
- wptexturize( $excluded_headings[ $j ] ),
680
- ENT_NOQUOTES,
681
- get_option( 'blog_charset' )
682
- );
683
-
684
- $against = html_entity_decode(
685
- wptexturize( strip_tags( $matches[ $i ][0] ) ),
686
- ENT_NOQUOTES,
687
- get_option( 'blog_charset' )
688
- );
689
-
690
- if ( @preg_match( '/^' . $pattern . '$/imU', $against ) ) {
691
-
692
- $found = TRUE;
693
- break;
694
- }
695
- }
696
-
697
- if ( ! $found ) {
698
-
699
- $new_matches[] = $matches[ $i ];
700
- }
701
- }
702
-
703
- if ( count( $matches ) != count( $new_matches ) ) {
704
-
705
- $matches = $new_matches;
706
- }
707
- }
708
- }
709
-
710
- // remove empty headings
711
- $new_matches = array();
712
-
713
- for ( $i = 0; $i < count( $matches ); $i ++ ) {
714
-
715
- if ( trim( strip_tags( $matches[ $i ][0] ) ) != FALSE ) {
716
-
717
- $new_matches[] = $matches[ $i ];
718
- }
719
- }
720
-
721
- if ( count( $matches ) != count( $new_matches ) ) {
722
-
723
- $matches = $new_matches;
724
- }
725
-
726
- $toc = $matches;
727
-
728
- // Replace headers with toc alt text.
729
- if ( $altText ) {
730
-
731
- $alt_headings = array();
732
- $split_headings = preg_split( '/\r\n|[\r\n]/', $altText );
733
- $split_headings_count = count( $split_headings );
734
-
735
- if ( $split_headings ) {
736
-
737
- for ( $k = 0; $k < $split_headings_count; $k++ ) {
738
-
739
- $explode_headings = explode( '|', $split_headings[ $k ] );
740
-
741
- if ( 0 < strlen( $explode_headings[0] ) && 0 < strlen( $explode_headings[1] ) ) {
742
-
743
- $alt_headings[ $explode_headings[0] ] = $explode_headings[1];
744
- }
745
- }
746
-
747
- }
748
-
749
- if ( 0 < count( $alt_headings ) ) {
750
-
751
- for ( $i = 0; $i < count( $toc ); $i++ ) {
752
-
753
- foreach ( $alt_headings as $original_heading => $alt_heading ) {
754
-
755
- $original_heading = preg_quote( $original_heading );
756
-
757
- // escape some regular expression characters
758
- // others: http://www.php.net/manual/en/regexp.reference.meta.php
759
- $original_heading = str_replace(
760
- array( '\*' ),
761
- array( '.*' ),
762
- trim( $original_heading )
763
- );
764
-
765
- if ( @preg_match( '/^' . $original_heading . '$/imU', strip_tags( $toc[ $i ][0] ) ) ) {
766
-
767
- //$matches[ $i ][0] = str_replace( $original_heading, $alt_heading, $matches[ $i ][0] );
768
- $toc[ $i ][0] = $alt_heading;
769
- }
770
- }
771
- }
772
- }
773
- }
774
-
775
- // check minimum number of headings
776
- if ( count( $matches ) >= ezTOC_Option::get( 'start' ) ) {
777
-
778
- for ( $i = 0; $i < count( $matches ); $i++ ) {
779
-
780
- // get anchor and add to find and replace arrays
781
- $anchor = isset( $toc[ $i ][0] ) ? self::url_anchor_target( $toc[ $i ][0] ) : self::url_anchor_target( $matches[ $i ][0] );
782
- $find[] = $matches[ $i ][0];
783
- $replace[] = str_replace(
784
- array(
785
- $matches[ $i ][1], // start of heading
786
- '</h' . $matches[ $i ][2] . '>' // end of heading
787
- ),
788
- array(
789
- $matches[ $i ][1] . '<span class="ez-toc-section" id="' . $anchor . '">',
790
- '</span></h' . $matches[ $i ][2] . '>'
791
- ),
792
- $matches[ $i ][0]
793
- );
794
-
795
- // assemble flat list
796
- if ( ! ezTOC_Option::get( 'show_hierarchy' ) ) {
797
-
798
- $items .= '<li><a href="' . esc_url( '#' . $anchor ) . '">';
799
- //$title = apply_filters( 'ez_toc_title', strip_tags( wp_kses_post( $toc[ $i ][0] ) ) );
800
- $title = strip_tags( apply_filters( 'ez_toc_title', $matches[ $i ][0] ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
801
-
802
- //if ( 'decimal' == ezTOC_Option::get( 'counter' ) ) {
803
- //
804
- // $items .= count( $replace ) . ' ';
805
- //}
806
-
807
- $items .= $title . '</a></li>';
808
- }
809
- }
810
-
811
- // build a hierarchical toc?
812
- // we could have tested for $items but that var can be quite large in some cases
813
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
814
-
815
- $items = self::build_hierarchy( $toc, $headings );
816
- }
817
-
818
- }
819
- }
820
- }
821
-
822
- return $items;
823
- }
824
-
825
  /**
826
  * Array search deep.
827
  *
@@ -840,38 +344,47 @@ if ( ! class_exists( 'ezTOC' ) ) {
840
  foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
841
 
842
  if ( $search === ${${"mode"}} ) {
843
- return TRUE;
844
  }
845
  }
846
 
847
- return FALSE;
848
  }
849
 
850
  /**
851
  * Returns true if the table of contents is eligible to be printed, false otherwise.
852
  *
 
 
853
  * @access public
854
  * @since 1.0
855
  * @static
856
  *
 
 
857
  * @return bool
858
  */
859
- public static function is_eligible() {
860
 
861
- global $wp_query;
862
 
863
- $post = $wp_query->post;
 
 
 
 
 
864
 
865
- if ( empty( $post ) ) {
866
- return FALSE;
867
  }
868
 
869
- if ( has_shortcode( $post->post_content, 'toc' ) || has_shortcode( $post->post_content, 'ez-toc' ) ) {
870
- return TRUE;
 
871
  }
872
 
873
  if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
874
- return FALSE;
875
  }
876
 
877
  $type = get_post_type( $post->ID );
@@ -883,204 +396,70 @@ if ( ! class_exists( 'ezTOC' ) ) {
883
 
884
  if ( ezTOC_Option::get( 'restrict_path' ) ) {
885
 
886
- //if ( strpos( $_SERVER['REQUEST_URI'], ezTOC_Option::get( 'restrict_path' ) ) === 0 ) {
887
- //
888
- // return TRUE;
889
- //
890
- //} else {
891
- //
892
- // return FALSE;
893
- //}
894
-
895
  /**
896
  * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
897
  */
898
- if ( FALSE !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
899
 
900
- return FALSE;
901
 
902
  } else {
903
 
904
- return TRUE;
905
  }
906
 
907
  } else {
908
 
909
- if ( $insert && 1 == get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) ) {
910
 
911
- return FALSE;
912
 
913
- } elseif ( $insert && 0 == get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) ) {
914
 
915
- return TRUE;
916
 
917
- } elseif ( $enabled && 1 == get_post_meta( $post->ID, '_ez-toc-insert', TRUE ) ) {
918
 
919
- return TRUE;
920
  }
921
 
922
- return FALSE;
923
- //return TRUE;
924
  }
925
 
926
  } else {
927
 
928
- return FALSE;
929
  }
930
  }
931
 
932
  /**
933
- * Build the table of contents.
934
  *
935
- * @access private
936
- * @since 1.3
937
- * @static
938
  *
939
- * @param WP_Post $post The page/post content.
940
  *
941
- * @return array
942
  */
943
- public static function build( $post ) {
944
-
945
- $css_classes = '';
946
-
947
- $html = '';
948
- $find = array();
949
- $replace = array();
950
- $items = self::extract_headings( $find, $replace, $post );
951
-
952
- if ( $items ) {
953
-
954
- // wrapping css classes
955
- switch ( ezTOC_Option::get( 'wrapping' ) ) {
956
-
957
- case 'left':
958
- $css_classes .= ' ez-toc-wrap-left';
959
- break;
960
-
961
- case 'right':
962
- $css_classes .= ' ez-toc-wrap-right';
963
- break;
964
-
965
- case 'none':
966
- default:
967
- // do nothing
968
- }
969
-
970
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
971
-
972
- $css_classes .= ' counter-hierarchy';
973
-
974
- } else {
975
-
976
- $css_classes .= ' counter-flat';
977
- }
978
-
979
- switch ( ezTOC_Option::get( 'counter' ) ) {
980
-
981
- case 'numeric':
982
- $css_classes .= ' counter-numeric';
983
- break;
984
-
985
- case 'roman':
986
- $css_classes .= ' counter-roman';
987
- break;
988
 
989
- case 'decimal':
990
- $css_classes .= ' counter-decimal';
991
- break;
992
- }
993
-
994
- // colour themes
995
- switch ( ezTOC_Option::get( 'theme' ) ) {
996
-
997
- case 'light-blue':
998
- $css_classes .= ' ez-toc-light-blue';
999
- break;
1000
-
1001
- case 'white':
1002
- $css_classes .= ' ez-toc-white';
1003
- break;
1004
-
1005
- case 'black':
1006
- $css_classes .= ' ez-toc-black';
1007
- break;
1008
-
1009
- case 'transparent':
1010
- $css_classes .= ' ez-toc-transparent';
1011
- break;
1012
-
1013
- case 'grey':
1014
- $css_classes .= ' ez-toc-grey';
1015
- break;
1016
-
1017
- default:
1018
- // do nothing
1019
- }
1020
-
1021
- if ( ezTOC_Option::get( 'css_container_class' ) ) {
1022
 
1023
- $css_classes .= ' ' . ezTOC_Option::get( 'css_container_class' );
1024
- }
1025
-
1026
- $css_classes = trim( $css_classes );
1027
-
1028
- // an empty class="" is invalid markup!
1029
- if ( ! $css_classes ) {
1030
-
1031
- $css_classes = ' ';
1032
- }
1033
 
1034
- // add container, toc title and list items
1035
- $html .= '<div id="ez-toc-container" class="' . $css_classes . '">' . PHP_EOL;
1036
-
1037
- if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1038
-
1039
- $toc_title = ezTOC_Option::get( 'heading_text' );
1040
-
1041
- if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== FALSE ) {
1042
-
1043
- $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1044
- }
1045
 
1046
- if ( strpos( $toc_title, '%PAGE_NAME%' ) !== FALSE ) {
1047
-
1048
- $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1049
- }
1050
-
1051
- $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1052
-
1053
- $html .= '<p class="ez-toc-title">' . esc_html( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ) ). '</p>' . PHP_EOL;
1054
-
1055
- $html .= '<span class="ez-toc-title-toggle">';
1056
-
1057
- if ( ezTOC_Option::get( 'visibility' ) ) {
1058
 
1059
- $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
1060
- }
1061
 
1062
- $html .= '</span>';
1063
 
1064
- $html .= '</div>' . PHP_EOL;
1065
  }
1066
-
1067
- ob_start();
1068
- do_action( 'ez_toc_before' );
1069
- $html .= ob_get_clean();
1070
-
1071
- $html .= '<nav><ul class="ez-toc-list">' . $items . '</ul></nav>';
1072
-
1073
- ob_start();
1074
- do_action( 'ez_toc_after' );
1075
- $html .= ob_get_clean();
1076
-
1077
- $html .= '</div>' . PHP_EOL;
1078
-
1079
- // Enqueue the script.
1080
- wp_enqueue_script( 'ez-toc-js' );
1081
  }
1082
 
1083
- return array( 'find' => $find, 'replace' => $replace, 'content' => $html );
1084
  }
1085
 
1086
  /**
@@ -1090,27 +469,67 @@ if ( ! class_exists( 'ezTOC' ) ) {
1090
  *
1091
  * @access private
1092
  * @since 1.3
1093
- * @static
1094
  *
1095
  * @param array|string $atts Shortcode attributes array or empty string.
1096
  * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
1097
  * @param string $tag Shortcode name.
1098
  *
1099
- * @return mixed
1100
  */
1101
  public static function shortcode( $atts, $content, $tag ) {
1102
 
1103
- static $run = TRUE;
1104
- $out = '';
1105
 
1106
  if ( $run ) {
1107
 
1108
- $args = self::build( get_post( get_the_ID() ) );
1109
- $out = $args['content'];
1110
- $run = FALSE;
 
 
 
 
1111
  }
1112
 
1113
- return $out;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1114
  }
1115
 
1116
  /**
@@ -1129,69 +548,60 @@ if ( ! class_exists( 'ezTOC' ) ) {
1129
  */
1130
  public static function the_content( $content ) {
1131
 
1132
- // bail if feed, search or archive
1133
- if ( is_feed() || is_search() || is_archive() ) {
1134
  return $content;
1135
  }
1136
 
1137
  // bail if post not eligible and widget is not active
1138
- $is_eligible = self::is_eligible();
1139
 
1140
  if ( ! $is_eligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
1141
 
1142
  return $content;
1143
  }
1144
 
1145
- /*
1146
- * get_post() does not return post_content filtered via `the_content` filter, which is good otherwise this
1147
- * might cause an infinite loop.
1148
- *
1149
- * Since the ezTOC `the_content` filter is added at priority 100, it should run last in most situations
1150
- * and already be filtered by other plugins/themes which ezTOC should take into account when building the
1151
- * TOC. So, take the post content past via `the_content` filter callback and replace the post_content with
1152
- * it before building the TOC.
1153
- */
1154
- $post = get_post( get_the_ID() );
1155
- $post->post_content = $content;
1156
 
1157
- // build toc
1158
- $args = self::build( $post );
1159
- $find = $args['find'];
1160
- $replace = $args['replace'];
1161
- $html = $args['content'];
1162
 
1163
  // bail if no headings found
1164
- if ( empty( $find ) ) {
1165
 
1166
  return $content;
1167
  }
1168
 
 
 
 
 
1169
  // if shortcode used or post not eligible, return content with anchored headings
1170
  if ( strpos( $content, 'ez-toc-container' ) || ! $is_eligible ) {
1171
 
1172
- return self::mb_find_replace( $find, $replace, $content );
1173
  }
1174
 
1175
  // else also add toc to content
1176
  switch ( ezTOC_Option::get( 'position' ) ) {
1177
 
1178
  case 'top':
1179
- $content = $html . self::mb_find_replace( $find, $replace, $content );
1180
  break;
1181
 
1182
  case 'bottom':
1183
- $content = self::mb_find_replace( $find, $replace, $content ) . $html;
1184
  break;
1185
 
1186
  case 'after':
1187
  $replace[0] = $replace[0] . $html;
1188
- $content = self::mb_find_replace( $find, $replace, $content );
1189
  break;
1190
 
1191
  case 'before':
1192
  default:
1193
  $replace[0] = $html . $replace[0];
1194
- $content = self::mb_find_replace( $find, $replace, $content );
1195
  }
1196
 
1197
  return $content;
@@ -1219,50 +629,3 @@ if ( ! class_exists( 'ezTOC' ) ) {
1219
  // Start Easy Table of Contents.
1220
  add_action( 'plugins_loaded', 'ezTOC' );
1221
  }
1222
-
1223
-
1224
- /**
1225
- * Returns a HTML formatted string of the table of contents without the surrounding UL or OL
1226
- * tags to enable the theme editor to supply their own ID and/or classes to the outer list.
1227
- *
1228
- * There are three optional parameters you can feed this function with:
1229
- *
1230
- * - $content is the entire content with headings. If blank, will default to the current $post
1231
- *
1232
- * - $link is the URL to prefix the anchor with. If provided a string, will use it as the prefix.
1233
- * If set to true then will try to obtain the permalink from the $post object.
1234
- *
1235
- * - $apply_eligibility bool, defaults to false. When set to true, will apply the check to
1236
- * see if bit of content has the prerequisites needed for a TOC, eg minimum number of headings
1237
- * enabled post type, etc.
1238
- */
1239
- //function toc_get_index( $content = '', $prefix_url = '', $apply_eligibility = FALSE ) {
1240
- //
1241
- // global $wp_query, $tic;
1242
- //
1243
- // $return = '';
1244
- // $find = $replace = array();
1245
- // $proceed = TRUE;
1246
- //
1247
- // if ( ! $content ) {
1248
- // $post = get_post( $wp_query->post->ID );
1249
- // $content = wptexturize( $post->post_content );
1250
- // }
1251
- //
1252
- // if ( $apply_eligibility ) {
1253
- // if ( ! $tic->is_eligible() ) {
1254
- // $proceed = FALSE;
1255
- // }
1256
- // } else {
1257
- // $tic->set_option( array( 'start' => 0 ) );
1258
- // }
1259
- //
1260
- // if ( $proceed ) {
1261
- // $return = $tic->extract_headings( $find, $replace, $content );
1262
- // if ( $prefix_url ) {
1263
- // $return = str_replace( 'href="#', 'href="' . $prefix_url . '#', $return );
1264
- // }
1265
- // }
1266
- //
1267
- // return $return;
1268
- //}
3
  * Plugin Name: Easy Table of Contents
4
  * Plugin URI: http://connections-pro.com/
5
  * Description: Adds a user friendly and fully automatic way to create and display a table of contents generated from the page content.
6
+ * Version: 2.0-rc11
7
  * Author: Steven A. Zahm
8
  * Author URI: http://connections-pro.com/
9
  * Text Domain: easy-table-of-contents
10
  * Domain Path: /languages
11
  *
12
+ * Copyright 2020 Steven A. Zahm ( email : helpdesk@connections-pro.com )
13
  *
14
  * Easy Table of Contents is free software; you can redistribute it and/or modify
15
  * it under the terms of the GNU General Public License, version 2, as
26
  * @package Easy Table of Contents
27
  * @category Plugin
28
  * @author Steven A. Zahm
29
+ * @version 2.0-rc11
30
  */
31
 
32
+ use function Easy_Plugins\Table_Of_Contents\String\mb_find_replace;
33
+
34
  // Exit if accessed directly
35
  if ( ! defined( 'ABSPATH' ) ) exit;
36
 
47
  * @since 1.0
48
  * @var string
49
  */
50
+ const VERSION = '2.0-rc11';
51
 
52
  /**
53
  * Stores the instance of this class.
61
  private static $instance;
62
 
63
  /**
64
+ * @since 2.0
 
 
 
 
 
65
  * @var array
66
  */
67
+ private static $store = array();
68
 
69
  /**
70
  * A dummy constructor to prevent the class from being loaded more than once.
129
  require_once( EZ_TOC_PATH . 'includes/class.admin.php' );
130
  }
131
 
132
+ require_once( EZ_TOC_PATH . 'includes/class.post.php' );
133
  require_once( EZ_TOC_PATH . 'includes/class.widget-toc.php' );
134
+ require_once( EZ_TOC_PATH . 'includes/inc.functions.php' );
135
+ require_once( EZ_TOC_PATH . 'includes/inc.string-functions.php' );
136
+
137
+ require_once( EZ_TOC_PATH . 'includes/inc.plugin-compatibility.php' );
138
  }
139
 
140
  /**
200
  } else {
201
 
202
  // Load the default language files
203
+ load_plugin_textdomain( $domain, false, $languagesDirectory );
204
  }
205
  }
206
 
207
  /**
208
+ * Call back for the `wp_enqueue_scripts` action.
209
+ *
210
  * Register and enqueue CSS and javascript files for frontend.
211
  *
212
  * @access private
216
  public static function enqueueScripts() {
217
 
218
  // If SCRIPT_DEBUG is set and TRUE load the non-minified JS files, otherwise, load the minified files.
219
+ $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
220
 
221
  $js_vars = array();
222
 
223
  wp_register_style( 'ez-icomoon', EZ_TOC_URL . "vendor/icomoon/style$min.css", array(), ezTOC::VERSION );
224
  wp_register_style( 'ez-toc', EZ_TOC_URL . "assets/css/screen$min.css", array( 'ez-icomoon' ), ezTOC::VERSION );
225
 
226
+ wp_register_script( 'js-cookie', EZ_TOC_URL . "vendor/js-cookie/js.cookie$min.js", array(), '2.2.1', TRUE );
227
+ wp_register_script( 'jquery-smooth-scroll', EZ_TOC_URL . "vendor/smooth-scroll/jquery.smooth-scroll$min.js", array( 'jquery' ), '2.2.0', TRUE );
228
  wp_register_script( 'jquery-sticky-kit', EZ_TOC_URL . "vendor/sticky-kit/jquery.sticky-kit$min.js", array( 'jquery' ), '1.9.2', TRUE );
229
+ wp_register_script( 'ez-toc-js', EZ_TOC_URL . "assets/js/front$min.js", array( 'jquery-smooth-scroll', 'js-cookie', 'jquery-sticky-kit'), ezTOC::VERSION, TRUE );
 
230
 
231
  if ( ! ezTOC_Option::get( 'exclude_css' ) ) {
232
 
236
 
237
  if ( ezTOC_Option::get( 'smooth_scroll' ) ) {
238
 
239
+ $js_vars['smooth_scroll'] = true;
240
  }
241
 
242
  //wp_enqueue_script( 'ez-toc-js' );
245
 
246
  $width = ezTOC_Option::get( 'width' ) != 'custom' ? ezTOC_Option::get( 'width' ) : ezTOC_Option::get( 'width_custom' ) . ezTOC_Option::get( 'width_custom_units' );
247
 
248
+ $js_vars['visibility_hide_by_default'] = ezTOC_Option::get( 'visibility_hide_by_default' ) ? true : false;
249
 
250
  $js_vars['width'] = esc_js( $width );
251
  }
310
  $css .= '}';
311
  }
312
 
313
+ if ( 'custom' == ezTOC_Option::get( 'theme' ) ) {
314
 
315
  $css .= 'div#ez-toc-container p.ez-toc-title {color: ' . ezTOC_Option::get( 'custom_title_colour' ) . ';}';
316
  //$css .= 'div#ez-toc-container p.ez-toc-title a,div#ez-toc-container ul.ez-toc-list a {color: ' . ezTOC_Option::get( 'custom_link_colour' ) . ';}';
326
  }
327
  }
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  /**
330
  * Array search deep.
331
  *
344
  foreach ( new RecursiveIteratorIterator( new RecursiveArrayIterator( $array ) ) as $key => $value ) {
345
 
346
  if ( $search === ${${"mode"}} ) {
347
+ return true;
348
  }
349
  }
350
 
351
+ return false;
352
  }
353
 
354
  /**
355
  * Returns true if the table of contents is eligible to be printed, false otherwise.
356
  *
357
+ * NOTE: Must bve use only within the loop.
358
+ *
359
  * @access public
360
  * @since 1.0
361
  * @static
362
  *
363
+ * @param WP_Post $post
364
+ *
365
  * @return bool
366
  */
367
+ public static function is_eligible( $post ) {
368
 
369
+ global $wp_current_filter;
370
 
371
+ if ( empty( $post ) || ! $post instanceof WP_Post ) {
372
+ return false;
373
+ }
374
+
375
+ // Do not execute if root filter is one of those in the array.
376
+ if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'wp_head' ), true ) ) {
377
 
378
+ return false;
 
379
  }
380
 
381
+ if ( has_shortcode( $post->post_content, apply_filters( 'ez_toc_shortcode', 'toc' ) ) ||
382
+ has_shortcode( $post->post_content, 'ez-toc' ) ) {
383
+ return true;
384
  }
385
 
386
  if ( is_front_page() && ! ezTOC_Option::get( 'include_homepage' ) ) {
387
+ return false;
388
  }
389
 
390
  $type = get_post_type( $post->ID );
396
 
397
  if ( ezTOC_Option::get( 'restrict_path' ) ) {
398
 
 
 
 
 
 
 
 
 
 
399
  /**
400
  * @link https://wordpress.org/support/topic/restrict-path-logic-does-not-work-correctly?
401
  */
402
+ if ( false !== strpos( ezTOC_Option::get( 'restrict_path' ), $_SERVER['REQUEST_URI'] ) ) {
403
 
404
+ return false;
405
 
406
  } else {
407
 
408
+ return true;
409
  }
410
 
411
  } else {
412
 
413
+ if ( $insert && 1 == get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
414
 
415
+ return false;
416
 
417
+ } elseif ( $insert && 0 == get_post_meta( $post->ID, '_ez-toc-disabled', true ) ) {
418
 
419
+ return true;
420
 
421
+ } elseif ( $enabled && 1 == get_post_meta( $post->ID, '_ez-toc-insert', true ) ) {
422
 
423
+ return true;
424
  }
425
 
426
+ return false;
 
427
  }
428
 
429
  } else {
430
 
431
+ return false;
432
  }
433
  }
434
 
435
  /**
436
+ * Get TOC from store and if not in store process post and add it to the store.
437
  *
438
+ * @since 2.0
 
 
439
  *
440
+ * @param int $id
441
  *
442
+ * @return ezTOC_Post|null
443
  */
444
+ public static function get( $id ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
 
446
+ $post = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
+ if ( isset( self::$store[ $id ] ) && self::$store[ $id ] instanceof ezTOC_Post ) {
 
 
 
 
 
 
 
 
 
449
 
450
+ $post = self::$store[ $id ];
 
 
 
 
 
 
 
 
 
 
451
 
452
+ } else {
 
 
 
 
 
 
 
 
 
 
 
453
 
454
+ $post = ezTOC_Post::get( get_the_ID() );
 
455
 
456
+ if ( $post instanceof ezTOC_Post ) {
457
 
458
+ self::$store[ $id ] = $post;
459
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460
  }
461
 
462
+ return $post;
463
  }
464
 
465
  /**
469
  *
470
  * @access private
471
  * @since 1.3
 
472
  *
473
  * @param array|string $atts Shortcode attributes array or empty string.
474
  * @param string $content The enclosed content (if the shortcode is used in its enclosing form)
475
  * @param string $tag Shortcode name.
476
  *
477
+ * @return string
478
  */
479
  public static function shortcode( $atts, $content, $tag ) {
480
 
481
+ static $run = true;
482
+ $html = '';
483
 
484
  if ( $run ) {
485
 
486
+ if ( is_null( $post = self::get( get_the_ID() ) ) ) {
487
+
488
+ return $content;
489
+ }
490
+
491
+ $html = $post->getTOC();
492
+ $run = false;
493
  }
494
 
495
+ return $html;
496
+ }
497
+
498
+ /**
499
+ * Whether or not apply `the_content` filter.
500
+ *
501
+ * @since 2.0
502
+ *
503
+ * @return bool
504
+ */
505
+ private static function maybeApplyTheContentFilter() {
506
+
507
+ $apply = true;
508
+
509
+ global $wp_current_filter;
510
+
511
+ // Do not execute if root current filter is one of those in the array.
512
+ if ( in_array( $wp_current_filter[0], array( 'get_the_excerpt', 'init', 'wp_head' ), true ) ) {
513
+
514
+ $apply = false;
515
+ }
516
+
517
+ // bail if feed, search or archive
518
+ if ( is_feed() || is_search() || is_archive() ) {
519
+
520
+ $apply = false;
521
+ }
522
+
523
+ /**
524
+ * Whether or not to apply `the_content` filter callback.
525
+ *
526
+ * @see ezTOC::the_content()
527
+ *
528
+ * @since 2.0
529
+ *
530
+ * @param bool $apply
531
+ */
532
+ return apply_filters( 'ez_toc_maybe_apply_the_content_filter', $apply );
533
  }
534
 
535
  /**
548
  */
549
  public static function the_content( $content ) {
550
 
551
+ if ( ! self::maybeApplyTheContentFilter() ) {
552
+
553
  return $content;
554
  }
555
 
556
  // bail if post not eligible and widget is not active
557
+ $is_eligible = self::is_eligible( get_post() );
558
 
559
  if ( ! $is_eligible && ! is_active_widget( false, false, 'ezw_tco' ) ) {
560
 
561
  return $content;
562
  }
563
 
564
+ if ( is_null( $post = self::get( get_the_ID() ) ) ) {
 
 
 
 
 
 
 
 
 
 
565
 
566
+ return $content;
567
+ }
 
 
 
568
 
569
  // bail if no headings found
570
+ if ( ! $post->hasTOCItems() ) {
571
 
572
  return $content;
573
  }
574
 
575
+ $find = $post->getHeadings();
576
+ $replace = $post->getHeadingsWithAnchors();
577
+ $html = $post->getTOC();
578
+
579
  // if shortcode used or post not eligible, return content with anchored headings
580
  if ( strpos( $content, 'ez-toc-container' ) || ! $is_eligible ) {
581
 
582
+ return mb_find_replace( $find, $replace, $content );
583
  }
584
 
585
  // else also add toc to content
586
  switch ( ezTOC_Option::get( 'position' ) ) {
587
 
588
  case 'top':
589
+ $content = $html . mb_find_replace( $find, $replace, $content );
590
  break;
591
 
592
  case 'bottom':
593
+ $content = mb_find_replace( $find, $replace, $content ) . $html;
594
  break;
595
 
596
  case 'after':
597
  $replace[0] = $replace[0] . $html;
598
+ $content = mb_find_replace( $find, $replace, $content );
599
  break;
600
 
601
  case 'before':
602
  default:
603
  $replace[0] = $html . $replace[0];
604
+ $content = mb_find_replace( $find, $replace, $content );
605
  }
606
 
607
  return $content;
629
  // Start Easy Table of Contents.
630
  add_action( 'plugins_loaded', 'ezTOC' );
631
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/class.admin.php CHANGED
@@ -72,7 +72,7 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
72
  */
73
  public function registerScripts() {
74
 
75
- wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, TRUE );
76
  wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
77
  }
78
 
@@ -160,11 +160,11 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
160
  // Add an nonce field so we can check for it on save.
161
  wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
162
 
163
- $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', TRUE ) == 1 ? TRUE : FALSE;
164
- $insert = get_post_meta( $post->ID, '_ez-toc-insert', TRUE ) == 1 ? TRUE : FALSE;
165
- $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', TRUE );
166
- $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', TRUE );
167
- $altText = get_post_meta( $post->ID, '_ez-toc-alttext', TRUE );
168
 
169
  if ( ! is_array( $headings ) ) {
170
 
@@ -345,21 +345,21 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
345
  // Checkboxes are present if checked, absent if not.
346
  if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
347
 
348
- update_post_meta( $post_id, '_ez-toc-disabled', TRUE );
349
 
350
  } else {
351
 
352
- update_post_meta( $post_id, '_ez-toc-disabled', FALSE );
353
 
354
  }
355
 
356
  if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
357
 
358
- update_post_meta( $post_id, '_ez-toc-insert', TRUE );
359
 
360
  } else {
361
 
362
- update_post_meta( $post_id, '_ez-toc-insert', FALSE );
363
  }
364
 
365
  if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
@@ -384,14 +384,21 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
384
 
385
  if ( is_string( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
386
 
387
- $alttext = wp_unslash( trim( $_REQUEST['ez-toc-settings']['alttext'] ) );
388
 
389
  } else {
390
 
391
  $alttext = '';
392
  }
393
 
394
- update_post_meta( $post_id, '_ez-toc-alttext', wp_kses_data( $alttext ) );
 
 
 
 
 
 
 
395
 
396
  } else {
397
 
@@ -402,7 +409,7 @@ if ( ! class_exists( 'ezTOC_Admin' ) ) {
402
 
403
  if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
404
 
405
- $exclude = wp_unslash( trim( $_REQUEST['ez-toc-settings']['exclude'] ) );
406
 
407
  } else {
408
 
72
  */
73
  public function registerScripts() {
74
 
75
+ wp_register_script( 'cn_toc_admin_script', EZ_TOC_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker' ), ezTOC::VERSION, true );
76
  wp_register_style( 'cn_toc_admin_style', EZ_TOC_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), ezTOC::VERSION );
77
  }
78
 
160
  // Add an nonce field so we can check for it on save.
161
  wp_nonce_field( 'ez_toc_save', '_ez_toc_nonce' );
162
 
163
+ $suppress = get_post_meta( $post->ID, '_ez-toc-disabled', true ) == 1 ? true : false;
164
+ $insert = get_post_meta( $post->ID, '_ez-toc-insert', true ) == 1 ? true : false;
165
+ $headings = get_post_meta( $post->ID, '_ez-toc-heading-levels', true );
166
+ $exclude = get_post_meta( $post->ID, '_ez-toc-exclude', true );
167
+ $altText = get_post_meta( $post->ID, '_ez-toc-alttext', true );
168
 
169
  if ( ! is_array( $headings ) ) {
170
 
345
  // Checkboxes are present if checked, absent if not.
346
  if ( isset( $_REQUEST['ez-toc-settings']['disabled-toc'] ) ) {
347
 
348
+ update_post_meta( $post_id, '_ez-toc-disabled', true );
349
 
350
  } else {
351
 
352
+ update_post_meta( $post_id, '_ez-toc-disabled', false );
353
 
354
  }
355
 
356
  if ( isset( $_REQUEST['ez-toc-settings']['insert-toc'] ) ) {
357
 
358
+ update_post_meta( $post_id, '_ez-toc-insert', true );
359
 
360
  } else {
361
 
362
+ update_post_meta( $post_id, '_ez-toc-insert', false );
363
  }
364
 
365
  if ( isset( $_REQUEST['ez-toc-settings']['heading-levels'] ) && ! empty( $_REQUEST['ez-toc-settings']['heading-levels'] ) ) {
384
 
385
  if ( is_string( $_REQUEST['ez-toc-settings']['alttext'] ) ) {
386
 
387
+ $alttext = trim( $_REQUEST['ez-toc-settings']['alttext'] );
388
 
389
  } else {
390
 
391
  $alttext = '';
392
  }
393
 
394
+ /*
395
+ * This is basically `esc_html()` but does not encode quotes.
396
+ * This is to allow angle brackets and such which `wp_kses_post` would strip as "evil" scripts.
397
+ */
398
+ $alttext = wp_check_invalid_utf8( $alttext );
399
+ $alttext = _wp_specialchars( $alttext, ENT_NOQUOTES );
400
+
401
+ update_post_meta( $post_id, '_ez-toc-alttext', wp_kses_post( $alttext ) );
402
 
403
  } else {
404
 
409
 
410
  if ( is_string( $_REQUEST['ez-toc-settings']['exclude'] ) ) {
411
 
412
+ $exclude = trim( $_REQUEST['ez-toc-settings']['exclude'] );
413
 
414
  } else {
415
 
includes/class.options.php CHANGED
@@ -21,7 +21,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
21
  */
22
  public static function register() {
23
 
24
- if ( FALSE === get_option( 'ez-toc-settings' ) ) {
25
 
26
  add_option( 'ez-toc-settings', self::getDefaults() );
27
  }
@@ -47,20 +47,20 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
47
  'ez_toc_settings_' . $section,
48
  array(
49
  'section' => $section,
50
- 'id' => isset( $option['id'] ) ? $option['id'] : NULL,
51
  'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
52
- 'name' => isset( $option['name'] ) ? $option['name'] : NULL,
53
- 'size' => isset( $option['size'] ) ? $option['size'] : NULL,
54
  'options' => isset( $option['options'] ) ? $option['options'] : '',
55
  'default' => isset( $option['default'] ) ? $option['default'] : '',
56
- 'min' => isset( $option['min'] ) ? $option['min'] : NULL,
57
- 'max' => isset( $option['max'] ) ? $option['max'] : NULL,
58
- 'step' => isset( $option['step'] ) ? $option['step'] : NULL,
59
- 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : NULL,
60
- 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : NULL,
61
- 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : TRUE,
62
- 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : FALSE,
63
- 'faux' => isset( $option['faux'] ) ? $option['faux'] : FALSE,
64
  )
65
  );
66
  }
@@ -102,7 +102,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
102
  foreach ( $input as $key => $value ) {
103
 
104
  // Get the setting type (checkbox, select, etc)
105
- $type = isset( $registered[ $sectionID ][ $key ]['type'] ) ? $registered[ $sectionID ][ $key ]['type'] : FALSE;
106
 
107
  if ( $type ) {
108
 
@@ -202,7 +202,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
202
  'name' => __( 'Display Header Label', 'easy-table-of-contents' ),
203
  'desc' => __( 'Show header text above the table of contents.', 'easy-table-of-contents' ),
204
  'type' => 'checkbox',
205
- 'default' => TRUE,
206
  ),
207
  'heading_text' => array(
208
  'id' => 'heading_text',
@@ -216,7 +216,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
216
  'name' => __( 'Toggle View', 'easy-table-of-contents' ),
217
  'desc' => __( 'Allow the user to toggle the visibility of the table of contents.', 'easy-table-of-contents' ),
218
  'type' => 'checkbox',
219
- 'default' => TRUE,
220
  ),
221
  //'visibility_show' => array(
222
  // 'id' => 'visibility_show',
@@ -237,14 +237,14 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
237
  'name' => __( 'Initial View', 'easy-table-of-contents' ),
238
  'desc' => __( 'Initially hide the table of contents.', 'easy-table-of-contents' ),
239
  'type' => 'checkbox',
240
- 'default' => FALSE,
241
  ),
242
  'show_hierarchy' => array(
243
  'id' => 'show_hierarchy',
244
  'name' => __( 'Show as Hierarchy', 'easy-table-of-contents' ),
245
  'desc' => '',
246
  'type' => 'checkbox',
247
- 'default' => TRUE,
248
  ),
249
  'counter' => array(
250
  'id' => 'counter',
@@ -264,7 +264,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
264
  'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
265
  'desc' => '',
266
  'type' => 'checkbox',
267
- 'default' => TRUE,
268
  ),
269
  )
270
  ),
@@ -436,35 +436,35 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
436
  'name' => __( 'Lowercase', 'easy-table-of-contents' ),
437
  'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
438
  'type' => 'checkbox',
439
- 'default' => FALSE,
440
  ),
441
  'hyphenate' => array(
442
  'id' => 'hyphenate',
443
  'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
444
  'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
445
  'type' => 'checkbox',
446
- 'default' => FALSE,
447
  ),
448
  'include_homepage' => array(
449
  'id' => 'include_homepage',
450
  'name' => __( 'Homepage', 'easy-table-of-contents' ),
451
  'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
452
  'type' => 'checkbox',
453
- 'default' => FALSE,
454
  ),
455
  'exclude_css' => array(
456
  'id' => 'exclude_css',
457
  'name' => __( 'CSS', 'easy-table-of-contents' ),
458
  'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
459
  'type' => 'checkbox',
460
- 'default' => FALSE,
461
  ),
462
  //'bullet_spacing' => array(
463
  // 'id' => 'bullet_spacing',
464
  // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
465
  // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
466
  // 'type' => 'checkbox',
467
- // 'default' => FALSE,
468
  //),
469
  'heading_levels' => array(
470
  'id' => 'heading_levels',
@@ -564,19 +564,19 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
564
  'fragment_prefix' => 'i',
565
  'position' => 'before',
566
  'start' => 4,
567
- 'show_heading_text' => TRUE,
568
  'heading_text' => 'Table of Contents',
569
  'enabled_post_types' => array( 'page' ),
570
  'auto_insert_post_types' => array(),
571
- 'show_hierarchy' => TRUE,
572
  'counter' => 'decimal',
573
- 'smooth_scroll' => TRUE,
574
  'smooth_scroll_offset' => 30,
575
- 'moile_smooth_scroll_offset' => 0,
576
- 'visibility' => TRUE,
577
  //'visibility_show' => 'show',
578
  //'visibility_hide' => 'hide',
579
- 'visibility_hide_by_default' => FALSE,
580
  'width' => 'auto',
581
  'width_custom' => 275,
582
  'width_custom_units' => 'px',
@@ -593,16 +593,16 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
593
  'custom_link_colour' => '#428bca',
594
  'custom_link_hover_colour' => '#2a6496',
595
  'custom_link_visited_colour' => '#428bca',
596
- 'lowercase' => FALSE,
597
- 'hyphenate' => FALSE,
598
- //'bullet_spacing' => FALSE,
599
- 'include_homepage' => FALSE,
600
- 'exclude_css' => FALSE,
601
  'exclude' => '',
602
  'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
603
  'restrict_path' => '',
604
  'css_container_class' => '',
605
- //'show_toc_in_widget_only' => FALSE,
606
  //'show_toc_in_widget_only_post_types' => array(),
607
  'widget_affix_selector' => '',
608
  );
@@ -636,11 +636,11 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
636
  * @static
637
  *
638
  * @param string $key
639
- * @param bool|FALSE $default
640
  *
641
  * @return mixed
642
  */
643
- public static function get( $key, $default = FALSE ) {
644
 
645
  $options = self::getOptions();
646
 
@@ -658,11 +658,11 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
658
  * @static
659
  *
660
  * @param string $key
661
- * @param bool|FALSE $value
662
  *
663
  * @return bool
664
  */
665
- public static function set( $key, $value = FALSE ) {
666
 
667
  if ( empty( $value ) ) {
668
 
@@ -807,25 +807,25 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
807
  * @param array $args Arguments passed by the setting
808
  * @param null $value
809
  */
810
- public static function text( $args, $value = NULL ) {
811
 
812
  if ( is_null( $value ) ) {
813
 
814
  $value = self::get( $args['id'], $args['default'] );
815
  }
816
 
817
- if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
818
 
819
- $args['readonly'] = TRUE;
820
  $value = isset( $args['default'] ) ? $args['default'] : '';
821
  $name = '';
822
 
823
  } else {
824
 
825
- $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
826
  }
827
 
828
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === TRUE ? ' readonly="readonly"' : '';
829
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
830
 
831
  $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
@@ -850,7 +850,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
850
  * @param array $args Arguments passed by the setting
851
  * @param null $value
852
  */
853
- public static function textarea( $args, $value = NULL ) {
854
 
855
  $html = '';
856
 
@@ -859,18 +859,18 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
859
  $value = self::get( $args['id'], $args['default'] );
860
  }
861
 
862
- if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
863
 
864
- $args['readonly'] = TRUE;
865
  $value = isset( $args['default'] ) ? $args['default'] : '';
866
  $name = '';
867
 
868
  } else {
869
 
870
- $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
871
  }
872
 
873
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === TRUE ? ' readonly="readonly"' : '';
874
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
875
 
876
  if ( 0 < strlen( $args['desc'] ) ) {
@@ -878,7 +878,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
878
  $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
879
  }
880
 
881
- $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( stripslashes( $value ) ) . '</textarea>';
882
 
883
  echo $html;
884
  }
@@ -898,18 +898,18 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
898
 
899
  $value = self::get( $args['id'], $args['default'] );
900
 
901
- if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
902
 
903
- $args['readonly'] = TRUE;
904
  $value = isset( $args['default'] ) ? $args['default'] : '';
905
  $name = '';
906
 
907
  } else {
908
 
909
- $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
910
  }
911
 
912
- $readonly = isset( $args['readonly'] ) && $args['readonly'] === TRUE ? ' readonly="readonly"' : '';
913
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
914
 
915
  $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
@@ -934,23 +934,23 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
934
  * @param array $args Arguments passed by the setting
935
  * @param null $value
936
  */
937
- public static function checkbox( $args, $value = NULL ) {
938
 
939
  if ( is_null( $value ) ) {
940
 
941
  $value = self::get( $args['id'], $args['default'] );
942
  }
943
 
944
- if ( isset( $args['faux'] ) && TRUE === $args['faux'] ) {
945
 
946
  $name = '';
947
 
948
  } else {
949
 
950
- $name = 'name="ez-toc-settings[' . $args['id'] . ']"';
951
  }
952
 
953
- $checked = $value ? checked( 1, $value, FALSE ) : '';
954
 
955
  $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
956
 
@@ -974,7 +974,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
974
  * @param array $args Arguments passed by the setting
975
  * @param null $value
976
  */
977
- public static function checkboxgroup( $args, $value = NULL ) {
978
 
979
  if ( is_null( $value ) ) {
980
 
@@ -991,10 +991,10 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
991
 
992
  } else {
993
 
994
- $enabled = NULL;
995
  }
996
 
997
- echo '<input name="ez-toc-settings[' . $args['id'] . '][' . $key . ']" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="checkbox" value="' . $key . '" ' . checked( $option, $enabled, FALSE ) . '/>&nbsp;';
998
  echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
999
 
1000
  endforeach;
@@ -1023,7 +1023,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
1023
 
1024
  foreach ( $args['options'] as $key => $option ) {
1025
 
1026
- echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, FALSE ) . '/>&nbsp;';
1027
  echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1028
  }
1029
 
@@ -1063,7 +1063,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
1063
  $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1064
 
1065
  foreach ( $args['options'] as $option => $name ) {
1066
- $selected = selected( $option, $value, FALSE );
1067
  $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1068
  }
1069
 
@@ -1112,7 +1112,7 @@ if ( ! class_exists( 'ezTOC_Option' ) ) {
1112
 
1113
  foreach ( $group['options'] as $option => $name ) {
1114
 
1115
- $selected = selected( $option, $value, FALSE );
1116
  $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1117
  }
1118
 
21
  */
22
  public static function register() {
23
 
24
+ if ( false === get_option( 'ez-toc-settings' ) ) {
25
 
26
  add_option( 'ez-toc-settings', self::getDefaults() );
27
  }
47
  'ez_toc_settings_' . $section,
48
  array(
49
  'section' => $section,
50
+ 'id' => isset( $option['id'] ) ? $option['id'] : null,
51
  'desc' => ! empty( $option['desc'] ) ? $option['desc'] : '',
52
+ 'name' => isset( $option['name'] ) ? $option['name'] : null,
53
+ 'size' => isset( $option['size'] ) ? $option['size'] : null,
54
  'options' => isset( $option['options'] ) ? $option['options'] : '',
55
  'default' => isset( $option['default'] ) ? $option['default'] : '',
56
+ 'min' => isset( $option['min'] ) ? $option['min'] : null,
57
+ 'max' => isset( $option['max'] ) ? $option['max'] : null,
58
+ 'step' => isset( $option['step'] ) ? $option['step'] : null,
59
+ 'chosen' => isset( $option['chosen'] ) ? $option['chosen'] : null,
60
+ 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : null,
61
+ 'allow_blank' => isset( $option['allow_blank'] ) ? $option['allow_blank'] : true,
62
+ 'readonly' => isset( $option['readonly'] ) ? $option['readonly'] : false,
63
+ 'faux' => isset( $option['faux'] ) ? $option['faux'] : false,
64
  )
65
  );
66
  }
102
  foreach ( $input as $key => $value ) {
103
 
104
  // Get the setting type (checkbox, select, etc)
105
+ $type = isset( $registered[ $sectionID ][ $key ]['type'] ) ? $registered[ $sectionID ][ $key ]['type'] : false;
106
 
107
  if ( $type ) {
108
 
202
  'name' => __( 'Display Header Label', 'easy-table-of-contents' ),
203
  'desc' => __( 'Show header text above the table of contents.', 'easy-table-of-contents' ),
204
  'type' => 'checkbox',
205
+ 'default' => true,
206
  ),
207
  'heading_text' => array(
208
  'id' => 'heading_text',
216
  'name' => __( 'Toggle View', 'easy-table-of-contents' ),
217
  'desc' => __( 'Allow the user to toggle the visibility of the table of contents.', 'easy-table-of-contents' ),
218
  'type' => 'checkbox',
219
+ 'default' => true,
220
  ),
221
  //'visibility_show' => array(
222
  // 'id' => 'visibility_show',
237
  'name' => __( 'Initial View', 'easy-table-of-contents' ),
238
  'desc' => __( 'Initially hide the table of contents.', 'easy-table-of-contents' ),
239
  'type' => 'checkbox',
240
+ 'default' => false,
241
  ),
242
  'show_hierarchy' => array(
243
  'id' => 'show_hierarchy',
244
  'name' => __( 'Show as Hierarchy', 'easy-table-of-contents' ),
245
  'desc' => '',
246
  'type' => 'checkbox',
247
+ 'default' => true,
248
  ),
249
  'counter' => array(
250
  'id' => 'counter',
264
  'name' => __( 'Smooth Scroll', 'easy-table-of-contents' ),
265
  'desc' => '',
266
  'type' => 'checkbox',
267
+ 'default' => true,
268
  ),
269
  )
270
  ),
436
  'name' => __( 'Lowercase', 'easy-table-of-contents' ),
437
  'desc' => __( 'Ensure anchors are in lowercase.', 'easy-table-of-contents' ),
438
  'type' => 'checkbox',
439
+ 'default' => false,
440
  ),
441
  'hyphenate' => array(
442
  'id' => 'hyphenate',
443
  'name' => __( 'Hyphenate', 'easy-table-of-contents' ),
444
  'desc' => __( 'Use - rather than _ in anchors.', 'easy-table-of-contents' ),
445
  'type' => 'checkbox',
446
+ 'default' => false,
447
  ),
448
  'include_homepage' => array(
449
  'id' => 'include_homepage',
450
  'name' => __( 'Homepage', 'easy-table-of-contents' ),
451
  'desc' => __( 'Show the table of contents for qualifying items on the homepage.', 'easy-table-of-contents' ),
452
  'type' => 'checkbox',
453
+ 'default' => false,
454
  ),
455
  'exclude_css' => array(
456
  'id' => 'exclude_css',
457
  'name' => __( 'CSS', 'easy-table-of-contents' ),
458
  'desc' => __( "Prevent the loading the core CSS styles. When selected, the appearance options from above will be ignored.", 'easy-table-of-contents' ),
459
  'type' => 'checkbox',
460
+ 'default' => false,
461
  ),
462
  //'bullet_spacing' => array(
463
  // 'id' => 'bullet_spacing',
464
  // 'name' => __( 'Theme Bullets', 'easy-table-of-contents' ),
465
  // 'desc' => __( 'If your theme includes background images for unordered list elements, enable this option to support them.', 'easy-table-of-contents' ),
466
  // 'type' => 'checkbox',
467
+ // 'default' => false,
468
  //),
469
  'heading_levels' => array(
470
  'id' => 'heading_levels',
564
  'fragment_prefix' => 'i',
565
  'position' => 'before',
566
  'start' => 4,
567
+ 'show_heading_text' => true,
568
  'heading_text' => 'Table of Contents',
569
  'enabled_post_types' => array( 'page' ),
570
  'auto_insert_post_types' => array(),
571
+ 'show_hierarchy' => true,
572
  'counter' => 'decimal',
573
+ 'smooth_scroll' => true,
574
  'smooth_scroll_offset' => 30,
575
+ 'mobile_smooth_scroll_offset' => 0,
576
+ 'visibility' => true,
577
  //'visibility_show' => 'show',
578
  //'visibility_hide' => 'hide',
579
+ 'visibility_hide_by_default' => false,
580
  'width' => 'auto',
581
  'width_custom' => 275,
582
  'width_custom_units' => 'px',
593
  'custom_link_colour' => '#428bca',
594
  'custom_link_hover_colour' => '#2a6496',
595
  'custom_link_visited_colour' => '#428bca',
596
+ 'lowercase' => false,
597
+ 'hyphenate' => false,
598
+ //'bullet_spacing' => false,
599
+ 'include_homepage' => false,
600
+ 'exclude_css' => false,
601
  'exclude' => '',
602
  'heading_levels' => array( '1', '2', '3', '4', '5', '6' ),
603
  'restrict_path' => '',
604
  'css_container_class' => '',
605
+ //'show_toc_in_widget_only' => false,
606
  //'show_toc_in_widget_only_post_types' => array(),
607
  'widget_affix_selector' => '',
608
  );
636
  * @static
637
  *
638
  * @param string $key
639
+ * @param bool|false $default
640
  *
641
  * @return mixed
642
  */
643
+ public static function get( $key, $default = false ) {
644
 
645
  $options = self::getOptions();
646
 
658
  * @static
659
  *
660
  * @param string $key
661
+ * @param bool|false $value
662
  *
663
  * @return bool
664
  */
665
+ public static function set( $key, $value = false ) {
666
 
667
  if ( empty( $value ) ) {
668
 
807
  * @param array $args Arguments passed by the setting
808
  * @param null $value
809
  */
810
+ public static function text( $args, $value = null ) {
811
 
812
  if ( is_null( $value ) ) {
813
 
814
  $value = self::get( $args['id'], $args['default'] );
815
  }
816
 
817
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
818
 
819
+ $args['readonly'] = true;
820
  $value = isset( $args['default'] ) ? $args['default'] : '';
821
  $name = '';
822
 
823
  } else {
824
 
825
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
826
  }
827
 
828
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
829
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
830
 
831
  $html = '<input type="text" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
850
  * @param array $args Arguments passed by the setting
851
  * @param null $value
852
  */
853
+ public static function textarea( $args, $value = null ) {
854
 
855
  $html = '';
856
 
859
  $value = self::get( $args['id'], $args['default'] );
860
  }
861
 
862
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
863
 
864
+ $args['readonly'] = true;
865
  $value = isset( $args['default'] ) ? $args['default'] : '';
866
  $name = '';
867
 
868
  } else {
869
 
870
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
871
  }
872
 
873
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
874
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
875
 
876
  if ( 0 < strlen( $args['desc'] ) ) {
878
  $html .= '<label for="ez-toc-settings[' . $args['id'] . ']"> ' . $args['desc'] . '</label>';
879
  }
880
 
881
+ $html .= '<textarea rows="10" cols="50" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . $readonly . '/>' . esc_textarea( $value ) . '</textarea>';
882
 
883
  echo $html;
884
  }
898
 
899
  $value = self::get( $args['id'], $args['default'] );
900
 
901
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
902
 
903
+ $args['readonly'] = true;
904
  $value = isset( $args['default'] ) ? $args['default'] : '';
905
  $name = '';
906
 
907
  } else {
908
 
909
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
910
  }
911
 
912
+ $readonly = isset( $args['readonly'] ) && $args['readonly'] === true ? ' readonly="readonly"' : '';
913
  $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
914
 
915
  $html = '<input type="number" class="' . $size . '-text" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="' . esc_attr( stripslashes( $value ) ) . '"' . $readonly . '/>';
934
  * @param array $args Arguments passed by the setting
935
  * @param null $value
936
  */
937
+ public static function checkbox( $args, $value = null ) {
938
 
939
  if ( is_null( $value ) ) {
940
 
941
  $value = self::get( $args['id'], $args['default'] );
942
  }
943
 
944
+ if ( isset( $args['faux'] ) && true === $args['faux'] ) {
945
 
946
  $name = '';
947
 
948
  } else {
949
 
950
+ $name = ' name="ez-toc-settings[' . $args['id'] . ']"';
951
  }
952
 
953
+ $checked = $value ? checked( 1, $value, false ) : '';
954
 
955
  $html = '<input type="checkbox" id="ez-toc-settings[' . $args['id'] . ']"' . $name . ' value="1" ' . $checked . '/>';
956
 
974
  * @param array $args Arguments passed by the setting
975
  * @param null $value
976
  */
977
+ public static function checkboxgroup( $args, $value = null ) {
978
 
979
  if ( is_null( $value ) ) {
980
 
991
 
992
  } else {
993
 
994
+ $enabled = null;
995
  }
996
 
997
+ echo '<input name="ez-toc-settings[' . $args['id'] . '][' . $key . ']" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="checkbox" value="' . $key . '" ' . checked( $option, $enabled, false ) . '/>&nbsp;';
998
  echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
999
 
1000
  endforeach;
1023
 
1024
  foreach ( $args['options'] as $key => $option ) {
1025
 
1026
+ echo '<input name="ez-toc-settings[' . $args['id'] . ']"" id="ez-toc-settings[' . $args['id'] . '][' . $key . ']" type="radio" value="' . $key . '" ' . checked( $key, $value, false ) . '/>&nbsp;';
1027
  echo '<label for="ez-toc-settings[' . $args['id'] . '][' . $key . ']">' . $option . '</label><br/>';
1028
  }
1029
 
1063
  $html = '<select id="ez-toc-settings[' . $args['id'] . ']" name="ez-toc-settings[' . $args['id'] . ']" ' . $chosen . 'data-placeholder="' . $placeholder . '" />';
1064
 
1065
  foreach ( $args['options'] as $option => $name ) {
1066
+ $selected = selected( $option, $value, false );
1067
  $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1068
  }
1069
 
1112
 
1113
  foreach ( $group['options'] as $option => $name ) {
1114
 
1115
+ $selected = selected( $option, $value, false );
1116
  $html .= '<option value="' . $option . '" ' . $selected . '>' . $name . '</option>';
1117
  }
1118
 
includes/class.post.php ADDED
@@ -0,0 +1,1289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class ezTOC_Post {
4
+
5
+ /**
6
+ * @since 2.0
7
+ * @var int
8
+ */
9
+ private $queriedObjectID;
10
+
11
+ /**
12
+ * @since 2.0
13
+ * @var WP_Post
14
+ */
15
+ private $post;
16
+
17
+ /**
18
+ * @since 2.0
19
+ * @var false|string
20
+ */
21
+ private $permalink;
22
+
23
+ /**
24
+ * The post content broken into pages by user inserting `<!--nextpage-->` into the post content.
25
+ * @see ezTOC_Post::extractPages()
26
+ * @since 2.0
27
+ * @var array
28
+ */
29
+ private $pages = array();
30
+
31
+ /**
32
+ * The user defined heading levels to be included in the TOC.
33
+ * @see ezTOC_Post::getHeadingLevels()
34
+ * @since 2.0
35
+ * @var array
36
+ */
37
+ private $headingLevels = array();
38
+
39
+ /**
40
+ * Array of nodes that are excluded by class/id selector.
41
+ * @since 2.0
42
+ * @var string[]
43
+ */
44
+ private $excludedNodes = array();
45
+
46
+ /**
47
+ * Keeps a track of used anchors for collision detecting.
48
+ * @see ezTOC_Post::generateHeadingIDFromTitle()
49
+ * @since 2.0
50
+ * @var array
51
+ */
52
+ private $collision_collector = array();
53
+
54
+ /**
55
+ * @var bool
56
+ */
57
+ private $hasTOCItems = false;
58
+
59
+ /**
60
+ * ezTOC_Post constructor.
61
+ *
62
+ * @since 2.0
63
+ *
64
+ * @param WP_Post $post
65
+ * @param bool $apply_content_filter Whether or not to apply the `the_content` filter on the post content.
66
+ */
67
+ public function __construct( WP_Post $post, $apply_content_filter = true ) {
68
+
69
+ $this->post = $post;
70
+ $this->permalink = get_permalink( $post );
71
+ $this->queriedObjectID = get_queried_object_id();
72
+
73
+ if ( $apply_content_filter ) {
74
+
75
+ $this->applyContentFilter()->process();
76
+
77
+ } else {
78
+
79
+ $this->process();
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @access public
85
+ * @since 2.0
86
+ *
87
+ * @param $id
88
+ *
89
+ * @return ezTOC_Post|null
90
+ */
91
+ public static function get( $id ) {
92
+
93
+ $post = get_post( $id );
94
+
95
+ if ( ! $post instanceof WP_Post ) {
96
+
97
+ return null;
98
+ }
99
+
100
+ return new static( $post );
101
+ }
102
+
103
+ /**
104
+ * Process post content for headings.
105
+ *
106
+ * This must be run after object init or after @see ezTOC_Post::applyContentFilter().
107
+ *
108
+ * @since 2.0
109
+ *
110
+ * @return static
111
+ */
112
+ private function process() {
113
+
114
+ $this->processPages();
115
+
116
+ return $this;
117
+ }
118
+
119
+ /**
120
+ * Apply `the_content` filter to the post content.
121
+ *
122
+ * @since 2.0
123
+ *
124
+ * @return static
125
+ */
126
+ private function applyContentFilter() {
127
+
128
+ add_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ), 10, 2 );
129
+
130
+ /*
131
+ * Ensure the ezTOC content filter is not applied when running `the_content` filter.
132
+ */
133
+ remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
134
+
135
+ $this->post->post_content = apply_filters( 'the_content', strip_shortcodes( $this->post->post_content ) );
136
+
137
+ add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
138
+
139
+ remove_filter( 'strip_shortcodes_tagnames', array( __CLASS__, 'stripShortcodes' ) );
140
+
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * Callback for the `strip_shortcodes_tagnames` filter.
146
+ *
147
+ * Strip the shortcodes so their content is no processed for headings.
148
+ *
149
+ * @see ezTOC_Post::applyContentFilter()
150
+ *
151
+ * @since 2.0
152
+ *
153
+ * @param array $tags_to_remove Array of shortcode tags to remove.
154
+ * @param string $content Content shortcodes are being removed from.
155
+ *
156
+ * @return array
157
+ */
158
+ public static function stripShortcodes( $tags_to_remove, $content ) {
159
+
160
+ //error_log( var_export( $tags_to_remove, true ) );
161
+
162
+ /*
163
+ * Ensure the ezTOC shortcodes are not processed when applying `the_content` filter
164
+ * otherwise an infinite loop may occur.
165
+ */
166
+ $tags_to_remove = apply_filters(
167
+ 'ez_toc_strip_shortcodes_tagnames',
168
+ array(
169
+ 'ez-toc',
170
+ apply_filters( 'ez_toc_shortcode', 'toc' ),
171
+ ),
172
+ $content
173
+ );
174
+
175
+ //error_log( var_export( $tags_to_remove, true ) );
176
+
177
+ return $tags_to_remove;
178
+ }
179
+
180
+ /**
181
+ * This is a work around for theme's and plugins
182
+ * which break the WordPress global $wp_query var by unsetting it
183
+ * or overwriting it which breaks the method call
184
+ * that `get_query_var()` uses to return the query variable.
185
+ *
186
+ * @access protected
187
+ * @since 2.0
188
+ *
189
+ * @return int
190
+ */
191
+ protected function getCurrentPage() {
192
+
193
+ global $wp_query;
194
+
195
+ // Check to see if the global `$wp_query` var is an instance of WP_Query and that the get() method is callable.
196
+ // If it is then when can simply use the get_query_var() function.
197
+ if ( $wp_query instanceof WP_Query && is_callable( array( $wp_query, 'get' ) ) ) {
198
+
199
+ $page = get_query_var( 'page', 1 );
200
+
201
+ return 1 > $page ? 1 : $page;
202
+
203
+ // If a theme or plugin broke the global `$wp_query` var, check to see if the $var was parsed and saved in $GLOBALS['wp_query']->query_vars.
204
+ } elseif ( isset( $GLOBALS['wp_query']->query_vars[ 'page' ] ) ) {
205
+
206
+ return $GLOBALS['wp_query']->query_vars[ 'page' ];
207
+
208
+ // We should not reach this, but if we do, lets check the original parsed query vars in $GLOBALS['wp_the_query']->query_vars.
209
+ } elseif ( isset( $GLOBALS['wp_the_query']->query_vars[ 'page' ] ) ) {
210
+
211
+ return $GLOBALS['wp_the_query']->query_vars[ 'page' ];
212
+
213
+ // Ok, if all else fails, check the $_REQUEST super global.
214
+ } elseif ( isset( $_REQUEST[ 'page' ] ) ) {
215
+
216
+ return $_REQUEST[ 'page' ];
217
+ }
218
+
219
+ // Finally, return the $default if it was supplied.
220
+ return 1;
221
+ }
222
+
223
+ /**
224
+ * Get the number of page the post has.
225
+ *
226
+ * @access protected
227
+ * @since 2.0
228
+ *
229
+ * @return int
230
+ */
231
+ protected function getNumberOfPages() {
232
+
233
+ return count( $this->pages );
234
+ }
235
+
236
+ /**
237
+ * Whether or not the post has multiple pages.
238
+ *
239
+ * @access protected
240
+ * @since 2.0
241
+ *
242
+ * @return bool
243
+ */
244
+ protected function isMultipage() {
245
+
246
+ return 1 < $this->getNumberOfPages();
247
+ }
248
+
249
+ /**
250
+ * Parse the post content and headings.
251
+ *
252
+ * @access private
253
+ * @since 2.0
254
+ */
255
+ private function processPages() {
256
+
257
+ //if ( ! class_exists( 'TagFilter' ) ) {
258
+ //
259
+ // require_once( EZ_TOC_PATH . 'includes/vendor/ultimate-web-scraper/tag_filter.php' );
260
+ //}
261
+
262
+ $split = preg_split( '/<!--nextpage-->/msuU', $this->post->post_content );
263
+ $pages = array();
264
+
265
+ if ( is_array( $split ) ) {
266
+
267
+ $page = 1;
268
+
269
+ //$tagFilterOptions = TagFilter::GetHTMLOptions();
270
+
271
+ //// Set custom TagFilter options.
272
+ //$tagFilterOptions['charset'] = get_option( 'blog_charset' );
273
+ ////$tagFilterOptions['output_mode'] = 'xml';
274
+
275
+ foreach ( $split as $content ) {
276
+
277
+ //$html = TagFilter::Explode( $content, $tagFilterOptions );
278
+ //
279
+ ///**
280
+ // * @since 2.0
281
+ // *
282
+ // * @param $selectors array Array of classes/id selector to exclude from TOC.
283
+ // * @param $content string Post content.
284
+ // */
285
+ //$selectors = apply_filters( 'ez_toc_exclude_by_selector', array(), $content );
286
+ //
287
+ //$nodes = $html->Find( implode( ',', $selectors ) );
288
+ //
289
+ //foreach ( $nodes['ids'] as $id ) {
290
+ //
291
+ // $html->Remove( $id );
292
+ //}
293
+ //
294
+ //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
295
+ //
296
+ ///**
297
+ // * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
298
+ // * Normalize `$eligibleContent` to match WP.
299
+ // *
300
+ // * @see wpautop()
301
+ // */
302
+ ////$eligibleContent = str_replace( array( '<br>', '<br/>' ), array( '<br />' ), $eligibleContent );
303
+ //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
304
+
305
+ $this->extractExcludedNodes( $page, $content );
306
+
307
+ $pages[ $page ] = array(
308
+ 'headings' => $this->extractHeadings( $content ),
309
+ 'content' => $content,
310
+ );
311
+
312
+ $page++;
313
+ }
314
+
315
+ }
316
+
317
+ $this->pages = $pages;
318
+ }
319
+
320
+ /**
321
+ * Get the post's parse content and headings.
322
+ *
323
+ * @access public
324
+ * @since 2.0
325
+ *
326
+ * @return array
327
+ */
328
+ public function getPages() {
329
+
330
+ return $this->pages;
331
+ }
332
+
333
+ /**
334
+ * Extract nodes that heading are to be excluded.
335
+ *
336
+ * @since 2.0
337
+ *
338
+ * @param int $page
339
+ * @param string $content
340
+ */
341
+ private function extractExcludedNodes( $page, $content ) {
342
+
343
+ if ( ! class_exists( 'TagFilter' ) ) {
344
+
345
+ require_once( EZ_TOC_PATH . 'includes/vendor/ultimate-web-scraper/tag_filter.php' );
346
+ }
347
+
348
+ $tagFilterOptions = TagFilter::GetHTMLOptions();
349
+
350
+ // Set custom TagFilter options.
351
+ $tagFilterOptions['charset'] = get_option( 'blog_charset' );
352
+ //$tagFilterOptions['output_mode'] = 'xml';
353
+
354
+ $html = TagFilter::Explode( $content, $tagFilterOptions );
355
+
356
+ /**
357
+ * @since 2.0
358
+ *
359
+ * @param $selectors array Array of classes/id selector to exclude from TOC.
360
+ * @param $content string Post content.
361
+ */
362
+ $selectors = apply_filters( 'ez_toc_exclude_by_selector', array(), $content );
363
+
364
+ $nodes = $html->Find( implode( ',', $selectors ) );
365
+
366
+ foreach ( $nodes['ids'] as $id ) {
367
+
368
+ //$this->excludedNodes[ $page ][ $id ] = $html->Implode( $id, $tagFilterOptions );
369
+ array_push( $this->excludedNodes, $html->Implode( $id, $tagFilterOptions ) );
370
+ }
371
+
372
+ //$eligibleContent = $html->Implode( 0, $tagFilterOptions );
373
+
374
+ /**
375
+ * TagFilter::Implode() writes br tags as `<br>` while WP normalizes to `<br />`.
376
+ * Normalize `$eligibleContent` to match WP.
377
+ *
378
+ * @see wpautop()
379
+ */
380
+ //$eligibleContent = \Easy_Plugins\Table_Of_Contents\String\force_balance_tags( $eligibleContent );
381
+ }
382
+
383
+ /**
384
+ * Extract the posts content for headings.
385
+ *
386
+ * @access private
387
+ * @since 2.0
388
+ *
389
+ * @param string $content
390
+ *
391
+ * @return array
392
+ */
393
+ private function extractHeadings( $content ) {
394
+
395
+ $matches = array();
396
+
397
+ // reset the internal collision collection as the_content may have been triggered elsewhere
398
+ // eg by themes or other plugins that need to read in content such as metadata fields in
399
+ // the head html tag, or to provide descriptions to twitter/facebook
400
+ /** @todo does this need to be used??? */
401
+ //self::$collision_collector = array();
402
+
403
+ $content = apply_filters( 'ez_toc_extract_headings_content', wptexturize( $content ) );
404
+
405
+ // get all headings
406
+ // the html spec allows for a maximum of 6 heading depths
407
+ if ( preg_match_all( '/(<h([1-6]{1})[^>]*>)(.*)<\/h\2>/msuU', $content, $matches, PREG_SET_ORDER ) ) {
408
+
409
+ $minimum = absint( ezTOC_Option::get( 'start' ) );
410
+
411
+ $this->removeHeadingsFromExcludedNodes( $matches );
412
+ $this->removeHeadings( $matches );
413
+ $this->excludeHeadings( $matches );
414
+ $this->removeEmptyHeadings( $matches );
415
+
416
+ if ( count( $matches ) >= $minimum ) {
417
+
418
+ $this->alternateHeadings( $matches );
419
+ $this->headingIDs( $matches );
420
+ $this->hasTOCItems = true;
421
+
422
+ } else {
423
+
424
+ return array();
425
+ }
426
+
427
+ }
428
+
429
+ return $matches;
430
+ }
431
+
432
+ /**
433
+ * Whether or not the string is in one of the excluded nodes.
434
+ *
435
+ * @since 2.0
436
+ *
437
+ * @param string $string
438
+ *
439
+ * @return bool
440
+ */
441
+ private function inExcludedNode( $string ) {
442
+
443
+ foreach ( $this->excludedNodes as $node ) {
444
+
445
+ if ( false !== strpos( $node, $string ) ) {
446
+
447
+ return true;
448
+ }
449
+ }
450
+
451
+ return false;
452
+ }
453
+
454
+ /**
455
+ * Remove headings that are in excluded nodes.
456
+ *
457
+ * @since 2.0
458
+ *
459
+ * @param array $matches
460
+ *
461
+ * @return array
462
+ */
463
+ private function removeHeadingsFromExcludedNodes( &$matches ) {
464
+
465
+ foreach ( $matches as $i => $match ) {
466
+
467
+ if ( $this->inExcludedNode( $match[3] ) ) {
468
+
469
+ unset( $matches[ $i ] );
470
+ }
471
+ }
472
+
473
+ return $matches;
474
+ }
475
+
476
+ /**
477
+ * Get the heading levels to be included in the TOC.
478
+ *
479
+ * @access private
480
+ * @since 2.0
481
+ *
482
+ * @return array
483
+ */
484
+ private function getHeadingLevels() {
485
+
486
+ $levels = get_post_meta( $this->post->ID, '_ez-toc-heading-levels', true );
487
+
488
+ if ( ! is_array( $levels ) ) {
489
+
490
+ $levels = array();
491
+ }
492
+
493
+ if ( empty( $levels ) ) {
494
+
495
+ $levels = ezTOC_Option::get( 'heading_levels', array() );
496
+ }
497
+
498
+ $this->headingLevels = $levels;
499
+
500
+ return $this->headingLevels;
501
+ }
502
+
503
+ /**
504
+ * Remove the heading levels as defined by user settings from the TOC heading matches.
505
+ *
506
+ * @see ezTOC_Post::extractHeadings()
507
+ *
508
+ * @access private
509
+ * @since 2.0
510
+ *
511
+ * @param array $matches The heading from the post content extracted with preg_match_all().
512
+ *
513
+ * @return array
514
+ */
515
+ private function removeHeadings( &$matches ) {
516
+
517
+ $levels = $this->getHeadingLevels();
518
+
519
+ if ( count( $levels ) != 6 ) {
520
+
521
+ $new_matches = array();
522
+ $count = count( $matches );
523
+
524
+ for ( $i = 0; $i < $count; $i++ ) {
525
+
526
+ if ( in_array( $matches[ $i ][2], $levels ) ) {
527
+
528
+ $new_matches[] = $matches[ $i ];
529
+ }
530
+ }
531
+
532
+ $matches = $new_matches;
533
+ }
534
+
535
+ return $matches;
536
+ }
537
+
538
+ /**
539
+ * Exclude the heading, by title, as defined by the user settings from the TOC matches.
540
+ *
541
+ * @see ezTOC_Post::extractHeadings()
542
+ *
543
+ * @access private
544
+ * @since 2.0
545
+ *
546
+ * @param array $matches The headings from the post content extracted with preg_match_all().
547
+ *
548
+ * @return array
549
+ */
550
+ private function excludeHeadings( &$matches ) {
551
+
552
+ $exclude = get_post_meta( $this->post->ID, '_ez-toc-exclude', true );
553
+
554
+ if ( empty( $exclude ) ) {
555
+
556
+ $exclude = ezTOC_Option::get( 'exclude' );
557
+ }
558
+
559
+ if ( $exclude ) {
560
+
561
+ $excluded_headings = explode( '|', $exclude );
562
+ $excluded_count = count( $excluded_headings );
563
+
564
+ if ( $excluded_count > 0 ) {
565
+
566
+ for ( $j = 0; $j < $excluded_count; $j++ ) {
567
+
568
+ $excluded_headings[ $j ] = preg_quote( $excluded_headings[ $j ] );
569
+
570
+ // escape some regular expression characters
571
+ // others: http://www.php.net/manual/en/regexp.reference.meta.php
572
+ $excluded_headings[ $j ] = str_replace(
573
+ array( '\*', '/', '%' ),
574
+ array( '.*', '\/', '\%' ),
575
+ trim( $excluded_headings[ $j ] )
576
+ );
577
+ }
578
+
579
+ $new_matches = array();
580
+ $count = count( $matches );
581
+
582
+ for ( $i = 0; $i < $count; $i++ ) {
583
+
584
+ $found = false;
585
+
586
+ for ( $j = 0; $j < $excluded_count; $j++ ) {
587
+
588
+ // Since WP manipulates the post content it is required that the excluded header and
589
+ // the actual header be manipulated similarly so a match can be made.
590
+ $pattern = html_entity_decode(
591
+ wptexturize( $excluded_headings[ $j ] ),
592
+ ENT_NOQUOTES,
593
+ get_option( 'blog_charset' )
594
+ );
595
+
596
+ $against = html_entity_decode(
597
+ wptexturize( strip_tags( str_replace( array( "\r", "\n" ), ' ', $matches[ $i ][0] ) ) ),
598
+ ENT_NOQUOTES,
599
+ get_option( 'blog_charset' )
600
+ );
601
+
602
+ if ( @preg_match( '/^' . $pattern . '$/imU', $against ) ) {
603
+
604
+ $found = true;
605
+ break;
606
+ }
607
+ }
608
+
609
+ if ( ! $found ) {
610
+
611
+ $new_matches[] = $matches[ $i ];
612
+ }
613
+ }
614
+
615
+ if ( count( $matches ) != count( $new_matches ) ) {
616
+
617
+ $matches = $new_matches;
618
+ }
619
+ }
620
+ }
621
+
622
+ return $matches;
623
+ }
624
+
625
+ /**
626
+ * Return the alternate headings added by the user, saved in the post meta.
627
+ *
628
+ * The result is an associative array where the `key` is the original post heading
629
+ * and the `value` is the alternate heading.
630
+ *
631
+ * @access private
632
+ * @since 2.0
633
+ *
634
+ * @return array
635
+ */
636
+ private function getAlternateHeadings() {
637
+
638
+ $alternates = array();
639
+ $value = get_post_meta( $this->post->ID, '_ez-toc-alttext', true );
640
+
641
+ if ( $value ) {
642
+
643
+ $headings = preg_split( '/\r\n|[\r\n]/', $value );
644
+ $count = count( $headings );
645
+
646
+ if ( $headings ) {
647
+
648
+ for ( $k = 0; $k < $count; $k++ ) {
649
+
650
+ $heading = explode( '|', $headings[ $k ] );
651
+
652
+ if ( 0 < strlen( $heading[0] ) && 0 < strlen( $heading[1] ) ) {
653
+
654
+ $alternates[ $heading[0] ] = $heading[1];
655
+ }
656
+ }
657
+
658
+ }
659
+
660
+ }
661
+
662
+ return $alternates;
663
+ }
664
+
665
+ /**
666
+ * Add the alternate headings to the array.
667
+ *
668
+ * @see ezTOC_Post::extractHeadings()
669
+ *
670
+ * @access private
671
+ * @since 2.0
672
+ *
673
+ * @param array $matches The heading from the post content extracted with preg_match_all().
674
+ *
675
+ * @return array
676
+ */
677
+ private function alternateHeadings( &$matches ) {
678
+
679
+ $alt_headings = $this->getAlternateHeadings();
680
+ $count = count( $matches );
681
+
682
+ if ( 0 < count( $alt_headings ) ) {
683
+
684
+ for ( $i = 0; $i < $count; $i++ ) {
685
+
686
+ foreach ( $alt_headings as $original_heading => $alt_heading ) {
687
+
688
+ // Cleanup and texturize so alt heading can match heading in post content.
689
+ $original_heading = wptexturize( trim( $original_heading ) );
690
+
691
+ // Deal with special characters such as non-breakable space.
692
+ $original_heading = str_replace(
693
+ array( "\xc2\xa0" ),
694
+ array( ' ' ),
695
+ $original_heading
696
+ );
697
+
698
+ // Escape for regular expression.
699
+ $original_heading = preg_quote( $original_heading );
700
+
701
+ // Escape for regular expression some other characters: http://www.php.net/manual/en/regexp.reference.meta.php
702
+ $original_heading = str_replace(
703
+ array( '\*', '/', '%' ),
704
+ array( '.*', '\/', '\%' ),
705
+ $original_heading
706
+ );
707
+
708
+ // Cleanup subject so alt heading can match heading in post content.
709
+ $subject = strip_tags( $matches[ $i ][0] );
710
+
711
+ // Deal with special characters such as non-breakable space.
712
+ $subject = str_replace(
713
+ array( "\xc2\xa0" ),
714
+ array( ' ' ),
715
+ $subject
716
+ );
717
+
718
+ if ( @preg_match( '/^' . $original_heading . '$/imU', $subject ) ) {
719
+
720
+ $matches[ $i ]['alternate'] = $alt_heading;
721
+ }
722
+ }
723
+ }
724
+ }
725
+
726
+ return $matches;
727
+ }
728
+
729
+ /**
730
+ * Add the heading `id` to the array.
731
+ *
732
+ * @see ezTOC_Post::extractHeadings()
733
+ *
734
+ * @access private
735
+ * @since 2.0
736
+ *
737
+ * @param array $matches The heading from the post content extracted with preg_match_all().
738
+ *
739
+ * @return mixed
740
+ */
741
+ private function headingIDs( &$matches ) {
742
+
743
+ $count = count( $matches );
744
+
745
+ for ( $i = 0; $i < $count; $i++ ) {
746
+
747
+ $matches[ $i ]['id'] = $this->generateHeadingIDFromTitle( $matches[ $i ][0] );
748
+ }
749
+
750
+ return $matches;
751
+ }
752
+
753
+ /**
754
+ * Create unique heading ID from heading string.
755
+ *
756
+ * @access private
757
+ * @since 2.0
758
+ *
759
+ * @param string $heading
760
+ *
761
+ * @return bool|string
762
+ */
763
+ private function generateHeadingIDFromTitle( $heading ) {
764
+
765
+ $return = false;
766
+
767
+ if ( $heading ) {
768
+
769
+ // WP entity encodes the post content.
770
+ $return = html_entity_decode( $heading, ENT_QUOTES, get_option( 'blog_charset' ) );
771
+
772
+ $return = trim( strip_tags( $return ) );
773
+
774
+ // Convert accented characters to ASCII.
775
+ $return = remove_accents( $return );
776
+
777
+ // replace newlines with spaces (eg when headings are split over multiple lines)
778
+ $return = str_replace( array( "\r", "\n", "\n\r", "\r\n" ), ' ', $return );
779
+
780
+ // Remove `&amp;` and `&nbsp;` NOTE: in order to strip "hidden" `&nbsp;`,
781
+ // title needs to be converted to HTML entities.
782
+ // @link https://stackoverflow.com/a/21801444/5351316
783
+ $return = htmlentities2( $return );
784
+ $return = str_replace( array( '&amp;', '&nbsp;' ), ' ', $return );
785
+ $return = html_entity_decode( $return, ENT_QUOTES, get_option( 'blog_charset' ) );
786
+
787
+ // remove non alphanumeric chars
788
+ $return = preg_replace( '/[^a-zA-Z0-9 \-_]*/', '', $return );
789
+
790
+ // convert spaces to _
791
+ $return = preg_replace( '/\s+/', '_', $return );
792
+
793
+ // remove trailing - and _
794
+ $return = rtrim( $return, '-_' );
795
+
796
+ // lowercase everything?
797
+ if ( ezTOC_Option::get( 'lowercase' ) ) {
798
+
799
+ $return = strtolower( $return );
800
+ }
801
+
802
+ // if blank, then prepend with the fragment prefix
803
+ // blank anchors normally appear on sites that don't use the latin charset
804
+ if ( ! $return ) {
805
+
806
+ $return = ( ezTOC_Option::get( 'fragment_prefix' ) ) ? ezTOC_Option::get( 'fragment_prefix' ) : '_';
807
+ }
808
+
809
+ // hyphenate?
810
+ if ( ezTOC_Option::get( 'hyphenate' ) ) {
811
+
812
+ $return = str_replace( '_', '-', $return );
813
+ $return = str_replace( '--', '-', $return );
814
+ }
815
+ }
816
+
817
+ if ( array_key_exists( $return, $this->collision_collector ) ) {
818
+
819
+ $this->collision_collector[ $return ]++;
820
+ $return .= '-' . $this->collision_collector[ $return ];
821
+
822
+ } else {
823
+
824
+ $this->collision_collector[ $return ] = 1;
825
+ }
826
+
827
+ return apply_filters( 'ez_toc_url_anchor_target', $return, $heading );
828
+ }
829
+
830
+ /**
831
+ * Remove any empty headings from the TOC.
832
+ *
833
+ * @access private
834
+ * @since 2.0
835
+ *
836
+ * @param array $matches The heading from the post content extracted with preg_match_all().
837
+ *
838
+ * @return array
839
+ */
840
+ private function removeEmptyHeadings( &$matches ) {
841
+
842
+ $new_matches = array();
843
+ $count = count( $matches );
844
+
845
+ for ( $i = 0; $i < $count; $i ++ ) {
846
+
847
+ if ( trim( strip_tags( $matches[ $i ][0] ) ) != false ) {
848
+
849
+ $new_matches[] = $matches[ $i ];
850
+ }
851
+ }
852
+
853
+ if ( count( $matches ) != count( $new_matches ) ) {
854
+
855
+ $matches = $new_matches;
856
+ }
857
+
858
+ return $matches;
859
+ }
860
+
861
+ /**
862
+ * Whether or not the post has TOC items.
863
+ *
864
+ * @see ezTOC_Post::extractHeadings()
865
+ *
866
+ * @access public
867
+ * @since 2.0
868
+ *
869
+ * @return bool
870
+ */
871
+ public function hasTOCItems() {
872
+
873
+ return $this->hasTOCItems;
874
+ }
875
+
876
+ /**
877
+ * Get the headings of the current page of the post.
878
+ *
879
+ * @access public
880
+ * @since 2.0
881
+ *
882
+ * @param int|null $page
883
+ *
884
+ * @return array
885
+ */
886
+ public function getHeadings( $page = null ) {
887
+
888
+ $headings = array();
889
+
890
+ if ( is_null( $page ) ) {
891
+
892
+ $page = $this->getCurrentPage();
893
+ }
894
+
895
+ if ( isset( $this->pages[ $page ] ) ) {
896
+
897
+ $headings = wp_list_pluck( $this->pages[ $page ]['headings'], 0 );
898
+ }
899
+
900
+ return $headings;
901
+ }
902
+
903
+ /**
904
+ * Get the heading with in page anchors of the current page of the post.
905
+ *
906
+ * @access public
907
+ * @since 2.0
908
+ *
909
+ * @param int|null $page
910
+ *
911
+ * @return array
912
+ */
913
+ public function getHeadingsWithAnchors( $page = null ) {
914
+
915
+ $headings = array();
916
+
917
+ if ( is_null( $page ) ) {
918
+
919
+ $page = $this->getCurrentPage();
920
+ }
921
+
922
+ if ( isset( $this->pages[ $page ] ) ) {
923
+
924
+ $matches = $this->pages[ $page ]['headings'];
925
+ $count = count( $matches );
926
+
927
+ for ( $i = 0; $i < $count; $i++ ) {
928
+
929
+ $anchor = $matches[ $i ]['id'];
930
+ $headings[] = str_replace(
931
+ array(
932
+ $matches[ $i ][1], // start of heading
933
+ '</h' . $matches[ $i ][2] . '>' // end of heading
934
+ ),
935
+ array(
936
+ $matches[ $i ][1],
937
+ '<span class="ez-toc-section" id="' . $anchor . '"></span></h' . $matches[ $i ][2] . '>'
938
+ ),
939
+ $matches[ $i ][0]
940
+ );
941
+ }
942
+ }
943
+
944
+ return $headings;
945
+ }
946
+
947
+ /**
948
+ * Get the post TOC list.
949
+ *
950
+ * @access public
951
+ * @since 2.0
952
+ *
953
+ * @return string
954
+ */
955
+ public function getTOCList() {
956
+
957
+ $html = '';
958
+
959
+ if ( $this->hasTOCItems ) {
960
+
961
+ foreach ( $this->pages as $page => $attribute ) {
962
+
963
+ $html .= $this->createTOC( $page, $attribute['headings'] );
964
+ }
965
+
966
+ $html = '<ul class="ez-toc-list ez-toc-list-level-1">' . $html . '</ul>';
967
+ }
968
+
969
+ return $html;
970
+ }
971
+
972
+ /**
973
+ * Get the post TOC content block.
974
+ *
975
+ * @access public
976
+ * @since 2.0
977
+ *
978
+ * @return string
979
+ */
980
+ public function getTOC() {
981
+
982
+ $css_classes = '';
983
+ $html = '';
984
+
985
+ if ( $this->hasTOCItems() ) {
986
+
987
+ // wrapping css classes
988
+ switch ( ezTOC_Option::get( 'wrapping' ) ) {
989
+
990
+ case 'left':
991
+ $css_classes .= ' ez-toc-wrap-left';
992
+ break;
993
+
994
+ case 'right':
995
+ $css_classes .= ' ez-toc-wrap-right';
996
+ break;
997
+
998
+ case 'none':
999
+ default:
1000
+ // do nothing
1001
+ }
1002
+
1003
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
1004
+
1005
+ $css_classes .= ' counter-hierarchy';
1006
+
1007
+ } else {
1008
+
1009
+ $css_classes .= ' counter-flat';
1010
+ }
1011
+
1012
+ switch ( ezTOC_Option::get( 'counter' ) ) {
1013
+
1014
+ case 'numeric':
1015
+ $css_classes .= ' counter-numeric';
1016
+ break;
1017
+
1018
+ case 'roman':
1019
+ $css_classes .= ' counter-roman';
1020
+ break;
1021
+
1022
+ case 'decimal':
1023
+ $css_classes .= ' counter-decimal';
1024
+ break;
1025
+ }
1026
+
1027
+ // colour themes
1028
+ switch ( ezTOC_Option::get( 'theme' ) ) {
1029
+
1030
+ case 'light-blue':
1031
+ $css_classes .= ' ez-toc-light-blue';
1032
+ break;
1033
+
1034
+ case 'white':
1035
+ $css_classes .= ' ez-toc-white';
1036
+ break;
1037
+
1038
+ case 'black':
1039
+ $css_classes .= ' ez-toc-black';
1040
+ break;
1041
+
1042
+ case 'transparent':
1043
+ $css_classes .= ' ez-toc-transparent';
1044
+ break;
1045
+
1046
+ case 'grey':
1047
+ $css_classes .= ' ez-toc-grey';
1048
+ break;
1049
+
1050
+ default:
1051
+ // do nothing
1052
+ }
1053
+
1054
+ if ( ezTOC_Option::get( 'css_container_class' ) ) {
1055
+
1056
+ $css_classes .= ' ' . ezTOC_Option::get( 'css_container_class' );
1057
+ }
1058
+
1059
+ $css_classes = trim( $css_classes );
1060
+
1061
+ // an empty class="" is invalid markup!
1062
+ if ( ! $css_classes ) {
1063
+
1064
+ $css_classes = ' ';
1065
+ }
1066
+
1067
+ // add container, toc title and list items
1068
+ $html .= '<div id="ez-toc-container" class="' . $css_classes . '">' . PHP_EOL;
1069
+
1070
+ if ( ezTOC_Option::get( 'show_heading_text' ) ) {
1071
+
1072
+ $toc_title = ezTOC_Option::get( 'heading_text' );
1073
+
1074
+ if ( strpos( $toc_title, '%PAGE_TITLE%' ) !== false ) {
1075
+
1076
+ $toc_title = str_replace( '%PAGE_TITLE%', get_the_title(), $toc_title );
1077
+ }
1078
+
1079
+ if ( strpos( $toc_title, '%PAGE_NAME%' ) !== false ) {
1080
+
1081
+ $toc_title = str_replace( '%PAGE_NAME%', get_the_title(), $toc_title );
1082
+ }
1083
+
1084
+ $html .= '<div class="ez-toc-title-container">' . PHP_EOL;
1085
+
1086
+ $html .= '<p class="ez-toc-title">' . esc_html__( htmlentities( $toc_title, ENT_COMPAT, 'UTF-8' ), 'easy-table-of-contents' ). '</p>' . PHP_EOL;
1087
+
1088
+ $html .= '<span class="ez-toc-title-toggle">';
1089
+
1090
+ if ( ezTOC_Option::get( 'visibility' ) ) {
1091
+
1092
+ $html .= '<a class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle"><i class="ez-toc-glyphicon ez-toc-icon-toggle"></i></a>';
1093
+ }
1094
+
1095
+ $html .= '</span>';
1096
+
1097
+ $html .= '</div>' . PHP_EOL;
1098
+ }
1099
+
1100
+ ob_start();
1101
+ do_action( 'ez_toc_before' );
1102
+ $html .= ob_get_clean();
1103
+
1104
+ $html .= '<nav>' . $this->getTOCList() . '</nav>';
1105
+
1106
+ ob_start();
1107
+ do_action( 'ez_toc_after' );
1108
+ $html .= ob_get_clean();
1109
+
1110
+ $html .= '</div>' . PHP_EOL;
1111
+
1112
+ // Enqueue the script.
1113
+ wp_enqueue_script( 'ez-toc-js' );
1114
+ }
1115
+
1116
+ return $html;
1117
+ }
1118
+
1119
+ /**
1120
+ * Displays the post's TOC.
1121
+ *
1122
+ * @access public
1123
+ * @since 2.0
1124
+ */
1125
+ public function toc() {
1126
+
1127
+ echo $this->getTOC();
1128
+ }
1129
+
1130
+ /**
1131
+ * Generate the TOC list items for a given page within a post.
1132
+ *
1133
+ * @access private
1134
+ * @since 2.0
1135
+ *
1136
+ * @param int $page The page of the post to create the TOC items for.
1137
+ * @param array $matches The heading from the post content extracted with preg_match_all().
1138
+ *
1139
+ * @return string The HTML list of TOC items.
1140
+ */
1141
+ private function createTOC( $page, $matches ) {
1142
+
1143
+ // Whether or not the TOC should be built flat or hierarchical.
1144
+ $hierarchical = ezTOC_Option::get( 'show_hierarchy' );
1145
+ $html = '';
1146
+
1147
+ if ( $hierarchical ) {
1148
+
1149
+ $current_depth = 100; // headings can't be larger than h6 but 100 as a default to be sure
1150
+ $numbered_items = array();
1151
+ $numbered_items_min = null;
1152
+
1153
+ // reset the internal collision collection
1154
+ /** @todo does this need to be used??? */
1155
+ //self::$collision_collector = array();
1156
+
1157
+ // find the minimum heading to establish our baseline
1158
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
1159
+ if ( $current_depth > $matches[ $i ][2] ) {
1160
+ $current_depth = (int) $matches[ $i ][2];
1161
+ }
1162
+ }
1163
+
1164
+ $numbered_items[ $current_depth ] = 0;
1165
+ $numbered_items_min = $current_depth;
1166
+
1167
+ for ( $i = 0; $i < count( $matches ); $i ++ ) {
1168
+
1169
+ $level = $matches[ $i ][2];
1170
+ $count = $i + 1;
1171
+
1172
+ if ( $current_depth == (int) $matches[ $i ][2] ) {
1173
+
1174
+ $html .= '<li class="ez-toc-page-' . $page . ' ez-toc-heading-level-' . $current_depth . '">';
1175
+ }
1176
+
1177
+ // start lists
1178
+ if ( $current_depth != (int) $matches[ $i ][2] ) {
1179
+
1180
+ for ( $current_depth; $current_depth < (int) $matches[ $i ][2]; $current_depth++ ) {
1181
+
1182
+ $numbered_items[ $current_depth + 1 ] = 0;
1183
+ $html .= '<ul class="ez-toc-list-level-' . $level . '"><li class="ez-toc-heading-level-' . $level . '">';
1184
+ }
1185
+ }
1186
+
1187
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1188
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1189
+
1190
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1191
+
1192
+ // end lists
1193
+ if ( $i != count( $matches ) - 1 ) {
1194
+
1195
+ if ( $current_depth > (int) $matches[ $i + 1 ][2] ) {
1196
+
1197
+ for ( $current_depth; $current_depth > (int) $matches[ $i + 1 ][2]; $current_depth-- ) {
1198
+
1199
+ $html .= '</li></ul>';
1200
+ $numbered_items[ $current_depth ] = 0;
1201
+ }
1202
+ }
1203
+
1204
+ if ( $current_depth == (int) @$matches[ $i + 1 ][2] ) {
1205
+
1206
+ $html .= '</li>';
1207
+ }
1208
+
1209
+ } else {
1210
+
1211
+ // this is the last item, make sure we close off all tags
1212
+ for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1213
+
1214
+ $html .= '</li>';
1215
+
1216
+ if ( $current_depth != $numbered_items_min ) {
1217
+ $html .= '</ul>';
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+
1223
+ } else {
1224
+
1225
+ for ( $i = 0; $i < count( $matches ); $i++ ) {
1226
+
1227
+ $count = $i + 1;
1228
+
1229
+ $title = isset( $matches[ $i ]['alternate'] ) ? $matches[ $i ]['alternate'] : $matches[ $i ][0];
1230
+ $title = strip_tags( apply_filters( 'ez_toc_title', $title ), apply_filters( 'ez_toc_title_allowable_tags', '' ) );
1231
+
1232
+ $html .= '<li class="ez-toc-page-' . $page . '">';
1233
+
1234
+ $html .= $this->createTOCItemAnchor( $page, $matches[ $i ]['id'], $title, $count );
1235
+
1236
+ $html .= '</li>';
1237
+ }
1238
+ }
1239
+
1240
+ return $html;
1241
+ }
1242
+
1243
+ /**
1244
+ * @access private
1245
+ * @since 2.0
1246
+ *
1247
+ * @param int $page
1248
+ * @param string $id
1249
+ * @param string $title
1250
+ * @param int $count
1251
+ *
1252
+ * @return string
1253
+ */
1254
+ private function createTOCItemAnchor( $page, $id, $title, $count ) {
1255
+
1256
+ return sprintf(
1257
+ '<a class="ez-toc-link ez-toc-heading-' . $count . '" href="%1$s" title="%2$s">' . $title . '</a>',
1258
+ esc_url( $this->createTOCItemURL( $id, $page ) ),
1259
+ esc_attr( strip_tags( $title ) )
1260
+ );
1261
+ }
1262
+
1263
+ /**
1264
+ * @access private
1265
+ * @since 2.0
1266
+ *
1267
+ * @param string $id
1268
+ * @param int $page
1269
+ *
1270
+ * @return string
1271
+ */
1272
+ private function createTOCItemURL( $id, $page ) {
1273
+
1274
+ $current_post = $this->post->ID === $this->queriedObjectID;
1275
+ $current_page = $this->getCurrentPage();
1276
+
1277
+ if ( $page === $current_page && $current_post ) {
1278
+
1279
+ return '#' . $id;
1280
+
1281
+ } elseif ( 1 === $page ) {
1282
+
1283
+ return $this->permalink . '#' . $id;
1284
+
1285
+ }
1286
+
1287
+ return $this->permalink . $page . '/#' . $id;
1288
+ }
1289
+ }
includes/class.widget-toc.php CHANGED
@@ -138,74 +138,76 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
138
 
139
  if ( is_404() || is_archive() || is_search() || ( ! is_front_page() && is_home() ) ) return;
140
 
141
- global $wp_query;
142
 
143
- $css_classes = '';
144
-
145
- $find = $replace = array();
146
- $post = get_post( $wp_query->post->ID );
147
 
148
  /*
149
  * Ensure the ezTOC content filter is not applied when running `the_content` filter.
150
  */
151
- remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
152
- $post->post_content = apply_filters( 'the_content', $post->post_content );
153
- add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
154
-
155
- /**
156
- * @var string $before_widget
157
- * @var string $after_widget
158
- * @var string $before_title
159
- * @var string $after_title
160
- */
161
- extract( $args );
162
 
163
- $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
164
- $items = ezTOC::extract_headings( $find, $replace, $post );
165
 
166
- if ( FALSE !== strpos( $title, '%PAGE_TITLE%' ) || FALSE !== strpos( $title, '%PAGE_NAME%' ) ) {
167
 
168
- $title = str_replace( '%PAGE_TITLE%', get_the_title(), $title );
169
- }
 
 
 
 
 
 
 
 
170
 
171
- if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
172
 
173
- $css_classes = ' counter-hierarchy';
 
174
 
175
- } else {
176
 
177
- $css_classes .= ' counter-flat';
178
- }
179
 
180
- switch ( ezTOC_Option::get( 'counter' ) ) {
181
 
182
- case 'numeric':
183
- $css_classes .= ' counter-numeric';
184
- break;
185
 
186
- case 'roman':
187
- $css_classes .= ' counter-roman';
188
- break;
189
 
190
- case 'decimal':
191
- $css_classes .= ' counter-decimal';
192
- break;
193
- }
194
 
195
- if ( $instance['affix'] ) {
 
 
196
 
197
- $css_classes .= ' ez-toc-affix';
198
- }
 
 
199
 
200
- $css_classes = trim( $css_classes );
201
 
202
- // an empty class="" is invalid markup!
203
- if ( ! $css_classes ) {
204
 
205
- $css_classes = ' ';
206
- }
207
 
208
- if ( $items ) {
 
 
 
 
209
 
210
  echo $before_widget;
211
 
@@ -255,7 +257,7 @@ if ( ! class_exists( 'ezTOC_Widget' ) ) {
255
  <?php
256
  }
257
 
258
- echo '<nav><ul class="ez-toc-list">'. PHP_EOL . $items . '</ul></nav>' . PHP_EOL;
259
 
260
  do_action( 'ez_toc_after_widget' );
261
 
138
 
139
  if ( is_404() || is_archive() || is_search() || ( ! is_front_page() && is_home() ) ) return;
140
 
141
+ //global $wp_query;
142
 
143
+ //$find = $replace = array();
144
+ //$post = get_post( $wp_query->post->ID );
145
+ //$post = ezTOC_Post::get( get_the_ID() );//->applyContentFilter()->process();
146
+ $post = ezTOC::get( get_the_ID() );
147
 
148
  /*
149
  * Ensure the ezTOC content filter is not applied when running `the_content` filter.
150
  */
151
+ //remove_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
152
+ //$post->post_content = apply_filters( 'the_content', $post->post_content );
153
+ //add_filter( 'the_content', array( 'ezTOC', 'the_content' ), 100 );
 
 
 
 
 
 
 
 
154
 
155
+ if ( $post->hasTOCItems() ) {
 
156
 
157
+ $css_classes = '';
158
 
159
+ /**
160
+ * @var string $before_widget
161
+ * @var string $after_widget
162
+ * @var string $before_title
163
+ * @var string $after_title
164
+ */
165
+ extract( $args );
166
+
167
+ $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
168
+ //$items = ezTOC::extract_headings( $find, $replace, $post );
169
 
170
+ if ( false !== strpos( $title, '%PAGE_TITLE%' ) || false !== strpos( $title, '%PAGE_NAME%' ) ) {
171
 
172
+ $title = str_replace( '%PAGE_TITLE%', get_the_title(), $title );
173
+ }
174
 
175
+ if ( ezTOC_Option::get( 'show_hierarchy' ) ) {
176
 
177
+ $css_classes = ' counter-hierarchy';
 
178
 
179
+ } else {
180
 
181
+ $css_classes .= ' counter-flat';
182
+ }
 
183
 
184
+ switch ( ezTOC_Option::get( 'counter' ) ) {
 
 
185
 
186
+ case 'numeric':
187
+ $css_classes .= ' counter-numeric';
188
+ break;
 
189
 
190
+ case 'roman':
191
+ $css_classes .= ' counter-roman';
192
+ break;
193
 
194
+ case 'decimal':
195
+ $css_classes .= ' counter-decimal';
196
+ break;
197
+ }
198
 
199
+ if ( $instance['affix'] ) {
200
 
201
+ $css_classes .= ' ez-toc-affix';
202
+ }
203
 
204
+ $css_classes = trim( $css_classes );
 
205
 
206
+ // an empty class="" is invalid markup!
207
+ if ( ! $css_classes ) {
208
+
209
+ $css_classes = ' ';
210
+ }
211
 
212
  echo $before_widget;
213
 
257
  <?php
258
  }
259
 
260
+ echo '<nav>'. PHP_EOL . $post->getTOCList() . '</nav>' . PHP_EOL;
261
 
262
  do_action( 'ez_toc_after_widget' );
263
 
includes/inc.functions.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if ( ! defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Get the current post's TOC list or supplied post's TOC list.
8
+ *
9
+ * @access public
10
+ * @since 2.0
11
+ *
12
+ * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
13
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
14
+ *
15
+ * @return string
16
+ */
17
+ function get_ez_toc_list( $post = null, $apply_content_filter = true ) {
18
+
19
+ if ( ! $post instanceof WP_Post ) {
20
+
21
+ $post = get_post( $post );
22
+ }
23
+
24
+ if ( $apply_content_filter ) {
25
+
26
+ $ezPost = new ezTOC_Post( $post );
27
+
28
+ } else {
29
+
30
+ $ezPost = new ezTOC_Post( $post, false );
31
+ }
32
+
33
+ return $ezPost->getTOCList();
34
+ }
35
+
36
+ /**
37
+ * Display the current post's TOC list or supplied post's TOC list.
38
+ *
39
+ * @access public
40
+ * @since 2.0
41
+ *
42
+ * @param null|WP_Post $post An instance of WP_Post
43
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
44
+ */
45
+ function ez_toc_list( $post = null, $apply_content_filter = true ) {
46
+
47
+ echo get_ez_toc_list( $post, $apply_content_filter );
48
+ }
49
+
50
+ /**
51
+ * Get the current post's TOC content block or supplied post's TOC content block.
52
+ *
53
+ * @access public
54
+ * @since 2.0
55
+ *
56
+ * @param int|null|WP_Post $post An instance of WP_Post or post ID. Defaults to current post.
57
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
58
+ *
59
+ * @return string
60
+ */
61
+ function get_ez_toc_block( $post = null, $apply_content_filter = true ) {
62
+
63
+ if ( ! $post instanceof WP_Post ) {
64
+
65
+ $post = get_post( $post );
66
+ }
67
+
68
+ if ( $apply_content_filter ) {
69
+
70
+ $ezPost = new ezTOC_Post( $post );
71
+
72
+ } else {
73
+
74
+ $ezPost = new ezTOC_Post( $post, false );
75
+ }
76
+
77
+ return $ezPost->getTOC();
78
+ }
79
+
80
+ /**
81
+ * Display the current post's TOC content or supplied post's TOC content.
82
+ *
83
+ * @access public
84
+ * @since 2.0
85
+ *
86
+ * @param null|WP_Post $post An instance of WP_Post
87
+ * @param bool $apply_content_filter Whether or not to apply `the_content` filter when processing post for headings.
88
+ */
89
+ function ez_toc_block( $post = null, $apply_content_filter = true ) {
90
+
91
+ echo get_ez_toc_block( $post, $apply_content_filter );
92
+ }
includes/inc.plugin-compatibility.php ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Filter to add plugins to the TOC list.
4
+ *
5
+ * @link https://rankmath.com/kb/filters-hooks-api-developer/#add-toc-plugin
6
+ *
7
+ * @since 2.0
8
+ *
9
+ * @param array TOC plugins.
10
+ */
11
+ add_filter(
12
+ 'rank_math/researches/toc_plugins',
13
+ function( $toc_plugins ) {
14
+
15
+ $toc_plugins[ EZ_TOC_BASE_NAME ] = 'Easy Table of Contents';
16
+
17
+ return $toc_plugins;
18
+ }
19
+ );
20
+
21
+ /**
22
+ * Filter to remove Connections Business Directory related shortcodes from being processed as eligible TOC items.
23
+ *
24
+ * @since 2.0
25
+ */
26
+ add_filter(
27
+ 'ez_toc_strip_shortcodes_tagnames',
28
+ function( $tags_to_remove ) {
29
+
30
+ $shortcodes = array (
31
+ 'connections_form',
32
+ 'cn_multi_category_search',
33
+ 'cn_widget',
34
+ 'cn_carousel',
35
+ 'connections_categories',
36
+ 'connections_link_view',
37
+ 'connections_link_edit',
38
+ 'connections_login',
39
+ 'siteshot',
40
+ 'connections',
41
+ 'upcoming_list',
42
+ 'cn-mapblock',
43
+ 'connections_vcard',
44
+ 'connections_qtip',
45
+ 'cn_thumb',
46
+ 'cn_thumbr',
47
+ );
48
+
49
+ $tags_to_remove = array_merge( $tags_to_remove, $shortcodes );
50
+
51
+ return $tags_to_remove;
52
+ }
53
+ );
54
+
55
+
56
+ /**
57
+ * Filter to remove Striking theme related shortcodes from being processed as eligible TOC items.
58
+ *
59
+ * @since 2.0
60
+ */
61
+ add_filter(
62
+ 'ez_toc_strip_shortcodes_tagnames',
63
+ function( $tags_to_remove ) {
64
+
65
+ $shortcodes = array (
66
+ 'iconbox',
67
+ 'toggle',
68
+ );
69
+
70
+ $tags_to_remove = array_merge( $tags_to_remove, $shortcodes );
71
+
72
+ return $tags_to_remove;
73
+ }
74
+ );
75
+
76
+ /**
77
+ * Remove the JetPack share buttons node from the post content before extracting headings.
78
+ *
79
+ * @since 2.0
80
+ */
81
+ add_filter(
82
+ 'ez_toc_exclude_by_selector',
83
+ function( $selectors ) {
84
+
85
+ $selectors['jetpack-sharedaddy'] = '.sharedaddy';
86
+
87
+ return $selectors;
88
+ }
89
+ );
90
+
91
+ /**
92
+ * Remove the Elegant Themes Bloom plugin node from the post content before extracting headings.
93
+ *
94
+ * @since 2.0
95
+ */
96
+ add_filter(
97
+ 'ez_toc_exclude_by_selector',
98
+ function( $selectors ) {
99
+
100
+ $selectors['elegant-themes-bloom'] = '.et_bloom_below_post';
101
+
102
+ return $selectors;
103
+ }
104
+ );
105
+
106
+ /**
107
+ * Do not allow `the_content` TOC callback to run when editing a page in Visual Composer.
108
+ *
109
+ * @link https://wordpress.org/support/topic/correct-method-to-determine-if-using-frontend-editor/#post-12404679
110
+ *
111
+ * @since 2.0
112
+ */
113
+ add_filter(
114
+ 'ez_toc_maybe_apply_the_content_filter',
115
+ function( $apply ) {
116
+
117
+ if ( function_exists( 'vchelper' ) ) {
118
+
119
+ //$sourceId = intval( vchelper( "Request" )->input( 'vcv-source-id' ) );
120
+ //
121
+ //if ( $sourceId === get_the_ID() ) {
122
+ //
123
+ // $apply = false;
124
+ //}
125
+
126
+ if ( vchelper( 'Frontend' )->isPageEditable() ) {
127
+
128
+ $apply = false;
129
+ }
130
+ }
131
+
132
+ return $apply;
133
+ }
134
+ );
135
+
136
+ /**
137
+ * Do not allow `the_content` TOC callback to run when editing a page in WPBakery Page Builder.
138
+ *
139
+ * @link https://wordpress.org/support/topic/correct-method-to-determine-if-using-frontend-editor/#post-12404679
140
+ *
141
+ * @since 2.0
142
+ */
143
+ add_filter(
144
+ 'ez_toc_maybe_apply_the_content_filter',
145
+ function( $apply ) {
146
+
147
+ if ( function_exists( 'vc_is_page_editable' ) ) {
148
+
149
+ if ( vc_is_page_editable() ) {
150
+
151
+ $apply = false;
152
+ }
153
+ }
154
+
155
+ return $apply;
156
+ }
157
+ );
158
+
159
+ /**
160
+ * Filter to remove WPBakery Page Builder related shortcodes from being processed as eligible TOC items.
161
+ *
162
+ * @since 2.0
163
+ */
164
+ add_filter(
165
+ 'ez_toc_strip_shortcodes_tagnames',
166
+ function( $tags_to_remove ) {
167
+
168
+ $shortcodes = array (
169
+ 'vc_tta_section',
170
+ );
171
+
172
+ $tags_to_remove = array_merge( $tags_to_remove, $shortcodes );
173
+
174
+ return $tags_to_remove;
175
+ }
176
+ );
177
+
178
+ /**
179
+ * Exclude the TOC shortcodes from being processed in the admin in the Divi Theme by Elegant Themes.
180
+ *
181
+ * @since 2.0
182
+ */
183
+ add_action(
184
+ 'et_pb_admin_excluded_shortcodes',
185
+ function( $shortcodes ) {
186
+
187
+ $shortcodes[] = 'ez-toc';
188
+ $shortcodes[] = apply_filters( 'ez_toc_shortcode', 'toc' );
189
+
190
+ return $shortcodes;
191
+ }
192
+ );
includes/inc.string-functions.php ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Easy_Plugins\Table_Of_Contents\String;
4
+
5
+ /**
6
+ * Pulled from WordPress formatting functions.
7
+ *
8
+ * Edited to add space before self closing tags.
9
+ *
10
+ * @since 2.0
11
+ *
12
+ * @param string $text
13
+ *
14
+ * @return string|string[]
15
+ */
16
+ function force_balance_tags( $text ) {
17
+ $tagstack = array();
18
+ $stacksize = 0;
19
+ $tagqueue = '';
20
+ $newtext = '';
21
+ // Known single-entity/self-closing tags
22
+ $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
23
+ // Tags that can be immediately nested within themselves
24
+ $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
25
+
26
+ // WP bug fix for comments - in case you REALLY meant to type '< !--'
27
+ $text = str_replace( '< !--', '< !--', $text );
28
+ // WP bug fix for LOVE <3 (and other situations with '<' before a number)
29
+ $text = preg_replace( '#<([0-9]{1})#', '&lt;$1', $text );
30
+
31
+ /**
32
+ * Matches supported tags.
33
+ *
34
+ * To get the pattern as a string without the comments paste into a PHP
35
+ * REPL like `php -a`.
36
+ *
37
+ * @see https://html.spec.whatwg.org/#elements-2
38
+ * @see https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name
39
+ *
40
+ * @example
41
+ * ~# php -a
42
+ * php > $s = [paste copied contents of expression below including parentheses];
43
+ * php > echo $s;
44
+ */
45
+ $tag_pattern = (
46
+ '#<' . // Start with an opening bracket.
47
+ '(/?)' . // Group 1 - If it's a closing tag it'll have a leading slash.
48
+ '(' . // Group 2 - Tag name.
49
+ // Custom element tags have more lenient rules than HTML tag names.
50
+ '(?:[a-z](?:[a-z0-9._]*)-(?:[a-z0-9._-]+)+)' .
51
+ '|' .
52
+ // Traditional tag rules approximate HTML tag names.
53
+ '(?:[\w:]+)' .
54
+ ')' .
55
+ '(?:' .
56
+ // We either immediately close the tag with its '>' and have nothing here.
57
+ '\s*' .
58
+ '(/?)' . // Group 3 - "attributes" for empty tag.
59
+ '|' .
60
+ // Or we must start with space characters to separate the tag name from the attributes (or whitespace).
61
+ '(\s+)' . // Group 4 - Pre-attribute whitespace.
62
+ '([^>]*)' . // Group 5 - Attributes.
63
+ ')' .
64
+ '>#' // End with a closing bracket.
65
+ );
66
+
67
+ while ( preg_match( $tag_pattern, $text, $regex ) ) {
68
+ $full_match = $regex[0];
69
+ $has_leading_slash = ! empty( $regex[1] );
70
+ $tag_name = $regex[2];
71
+ $tag = strtolower( $tag_name );
72
+ $is_single_tag = in_array( $tag, $single_tags, true );
73
+ $pre_attribute_ws = isset( $regex[4] ) ? $regex[4] : '';
74
+ $attributes = trim( isset( $regex[5] ) ? $regex[5] : $regex[3] );
75
+ $has_self_closer = '/' === substr( $attributes, -1 );
76
+
77
+ $newtext .= $tagqueue;
78
+
79
+ $i = strpos( $text, $full_match );
80
+ $l = strlen( $full_match );
81
+
82
+ // Clear the shifter.
83
+ $tagqueue = '';
84
+ if ( $has_leading_slash ) { // End Tag.
85
+ // If too many closing tags.
86
+ if ( $stacksize <= 0 ) {
87
+ $tag = '';
88
+ // Or close to be safe $tag = '/' . $tag.
89
+
90
+ // If stacktop value = tag close value, then pop.
91
+ } elseif ( $tagstack[ $stacksize - 1 ] === $tag ) { // Found closing tag.
92
+ $tag = '</' . $tag . '>'; // Close Tag.
93
+ array_pop( $tagstack );
94
+ $stacksize--;
95
+ } else { // Closing tag not at top, search for it.
96
+ for ( $j = $stacksize - 1; $j >= 0; $j-- ) {
97
+ if ( $tagstack[ $j ] === $tag ) {
98
+ // Add tag to tagqueue.
99
+ for ( $k = $stacksize - 1; $k >= $j; $k-- ) {
100
+ $tagqueue .= '</' . array_pop( $tagstack ) . '>';
101
+ $stacksize--;
102
+ }
103
+ break;
104
+ }
105
+ }
106
+ $tag = '';
107
+ }
108
+ } else { // Begin Tag.
109
+ if ( $has_self_closer ) { // If it presents itself as a self-closing tag...
110
+ // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
111
+ // immediately close it with a closing tag (the tag will encapsulate no text as a result)
112
+ if ( ! $is_single_tag ) {
113
+ $attributes = trim( substr( $attributes, 0, -1 ) ) . "></$tag";
114
+ }
115
+ } elseif ( $is_single_tag ) { // ElseIf it's a known single-entity tag but it doesn't close itself, do so
116
+ $pre_attribute_ws = ' ';
117
+ $attributes .= 0 < strlen( $attributes ) ? ' /' : '/'; // EDIT: If there are attributes, add space before closing tag to match how WP insert br, hr and img tags.
118
+ } else { // It's not a single-entity tag.
119
+ // If the top of the stack is the same as the tag we want to push, close previous tag.
120
+ if ( $stacksize > 0 && ! in_array( $tag, $nestable_tags, true ) && $tagstack[ $stacksize - 1 ] === $tag ) {
121
+ $tagqueue = '</' . array_pop( $tagstack ) . '>';
122
+ $stacksize--;
123
+ }
124
+ $stacksize = array_push( $tagstack, $tag );
125
+ }
126
+
127
+ // Attributes.
128
+ if ( $has_self_closer && $is_single_tag ) {
129
+ // We need some space - avoid <br/> and prefer <br />.
130
+ $pre_attribute_ws = ' ';
131
+ }
132
+
133
+ $tag = '<' . $tag . $pre_attribute_ws . $attributes . '>';
134
+ // If already queuing a close tag, then put this tag on too.
135
+ if ( ! empty( $tagqueue ) ) {
136
+ $tagqueue .= $tag;
137
+ $tag = '';
138
+ }
139
+ }
140
+ $newtext .= substr( $text, 0, $i ) . $tag;
141
+ $text = substr( $text, $i + $l );
142
+ }
143
+
144
+ // Clear Tag Queue.
145
+ $newtext .= $tagqueue;
146
+
147
+ // Add remaining text.
148
+ $newtext .= $text;
149
+
150
+ while ( $x = array_pop( $tagstack ) ) {
151
+ $newtext .= '</' . $x . '>'; // Add remaining tags to close.
152
+ }
153
+
154
+ // WP fix for the bug with HTML comments.
155
+ $newtext = str_replace( '< !--', '<!--', $newtext );
156
+ $newtext = str_replace( '< !--', '< !--', $newtext );
157
+
158
+ return $newtext;
159
+ }
160
+
161
+ /**
162
+ * Multibyte substr_replace(). The mbstring library does not come with a multibyte equivalent of substr_replace().
163
+ * This function behaves exactly like substr_replace() even when the arguments are arrays.
164
+ *
165
+ * @link https://gist.github.com/stemar/8287074
166
+ *
167
+ * @since 2.0
168
+ *
169
+ * @param $string
170
+ * @param $replacement
171
+ * @param $start
172
+ * @param null $length
173
+ *
174
+ * @return array|string
175
+ */
176
+ function mb_substr_replace( $string, $replacement, $start, $length = null ) {
177
+
178
+ if ( is_array( $string ) ) {
179
+
180
+ $num = count( $string );
181
+
182
+ // $replacement
183
+ $replacement = is_array( $replacement ) ? array_slice( $replacement, 0, $num ) : array_pad( array( $replacement ), $num, $replacement );
184
+
185
+ // $start
186
+ if ( is_array( $start ) ) {
187
+ $start = array_slice( $start, 0, $num );
188
+ foreach ( $start as $key => $value ) {
189
+ $start[ $key ] = is_int( $value ) ? $value : 0;
190
+ }
191
+ } else {
192
+ $start = array_pad( array( $start ), $num, $start );
193
+ }
194
+
195
+ // $length
196
+ if ( ! isset( $length ) ) {
197
+ $length = array_fill( 0, $num, 0 );
198
+ } elseif ( is_array( $length ) ) {
199
+ $length = array_slice( $length, 0, $num );
200
+ foreach ( $length as $key => $value ) {
201
+ $length[ $key ] = isset( $value ) ? ( is_int( $value ) ? $value : $num ) : 0;
202
+ }
203
+ } else {
204
+ $length = array_pad( array( $length ), $num, $length );
205
+ }
206
+
207
+ // Recursive call
208
+ return array_map( __FUNCTION__, $string, $replacement, $start, $length );
209
+ }
210
+
211
+ preg_match_all( '/./us', (string) $string, $smatches );
212
+ preg_match_all( '/./us', (string) $replacement, $rmatches );
213
+
214
+ if ( $length === null ) {
215
+
216
+ $length = mb_strlen( $string );
217
+ }
218
+
219
+ array_splice( $smatches[0], $start, $length, $rmatches[0] );
220
+
221
+ return join( $smatches[0] );
222
+ }
223
+
224
+ /**
225
+ * Returns a string with all items from the $find array replaced with their matching
226
+ * items in the $replace array. This does a one to one replacement (rather than globally).
227
+ *
228
+ * This function is multibyte safe.
229
+ *
230
+ * $find and $replace are arrays, $string is the haystack. All variables are passed by reference.
231
+ *
232
+ * @since 1.0
233
+ *
234
+ * @param bool $find
235
+ * @param bool $replace
236
+ * @param string $string
237
+ *
238
+ * @return mixed|string
239
+ */
240
+ function mb_find_replace( &$find = false, &$replace = false, &$string = '' ) {
241
+
242
+ if ( is_array( $find ) && is_array( $replace ) && $string ) {
243
+
244
+ // check if multibyte strings are supported
245
+ if ( function_exists( 'mb_strpos' ) ) {
246
+
247
+ //for ( $i = 0; $i < count( $find ); $i ++ ) {
248
+ //
249
+ // $string = mb_substr(
250
+ // $string,
251
+ // 0,
252
+ // mb_strpos( $string, $find[ $i ] )
253
+ // ) . // everything before $find
254
+ // $replace[ $i ] . // its replacement
255
+ // mb_substr(
256
+ // $string,
257
+ // mb_strpos( $string, $find[ $i ] ) + mb_strlen( $find[ $i ] )
258
+ // ) // everything after $find
259
+ // ;
260
+ //}
261
+
262
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
263
+
264
+ $start = mb_strpos( $string, $find[ $i ] );
265
+ $length = mb_strlen( $find[ $i ] );
266
+
267
+ /*
268
+ * `mb_strpos()` can return `false`. Only process `mb_substr_replace()` if position in string is found.
269
+ */
270
+ if ( is_int( $start ) ) {
271
+
272
+ $string = mb_substr_replace( $string, $replace[ $i ], $start, $length );
273
+ }
274
+
275
+ }
276
+
277
+ } else {
278
+
279
+ for ( $i = 0; $i < count( $find ); $i ++ ) {
280
+
281
+ $start = strpos( $string, $find[ $i ] );
282
+ $length = strlen( $find[ $i ] );
283
+
284
+ /*
285
+ * `strpos()` can return `false`. Only process `substr_replace()` if position in string is found.
286
+ */
287
+ if ( is_int( $start ) ) {
288
+
289
+ $string = substr_replace( $string, $replace[ $i ], $start, $length );
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ return $string;
296
+ }
includes/vendor/ultimate-web-scraper/cacert.pem ADDED
@@ -0,0 +1,3314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##
2
+ ## Bundle of CA Root Certificates
3
+ ##
4
+ ## Certificate data from Mozilla as of: Wed Jun 20 03:12:06 2018 GMT
5
+ ##
6
+ ## This is a bundle of X.509 certificates of public Certificate Authorities
7
+ ## (CA). These were automatically extracted from Mozilla's root certificates
8
+ ## file (certdata.txt). This file can be found in the mozilla source tree:
9
+ ## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
10
+ ##
11
+ ## It contains the certificates in PEM format and therefore
12
+ ## can be directly used with curl / libcurl / php_curl, or with
13
+ ## an Apache+mod_ssl webserver for SSL client authentication.
14
+ ## Just configure this file as the SSLCACertificateFile.
15
+ ##
16
+ ## Conversion done with mk-ca-bundle.pl version 1.27.
17
+ ## SHA256: c80f571d9f4ebca4a91e0ad3a546f263153d71afffc845c6f8f52ce9d1a2e8ec
18
+ ##
19
+
20
+
21
+ GlobalSign Root CA
22
+ ==================
23
+ -----BEGIN CERTIFICATE-----
24
+ MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
25
+ GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
26
+ b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
27
+ BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
28
+ VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
29
+ DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
30
+ THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
31
+ Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
32
+ c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
33
+ gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
34
+ HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
35
+ AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
36
+ Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
37
+ j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
38
+ hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
39
+ X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
40
+ -----END CERTIFICATE-----
41
+
42
+ GlobalSign Root CA - R2
43
+ =======================
44
+ -----BEGIN CERTIFICATE-----
45
+ MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
46
+ YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
47
+ bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
48
+ aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
49
+ bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
50
+ ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
51
+ s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
52
+ S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
53
+ TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
54
+ ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
55
+ FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
56
+ YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
57
+ BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
58
+ 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
59
+ 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
60
+ 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
61
+ TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
62
+ -----END CERTIFICATE-----
63
+
64
+ Verisign Class 3 Public Primary Certification Authority - G3
65
+ ============================================================
66
+ -----BEGIN CERTIFICATE-----
67
+ MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
68
+ UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
69
+ cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
70
+ IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
71
+ dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
72
+ CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
73
+ dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
74
+ cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
75
+ Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
76
+ ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
77
+ EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
78
+ cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
79
+ EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
80
+ 055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
81
+ ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
82
+ j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
83
+ /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
84
+ xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
85
+ t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
86
+ -----END CERTIFICATE-----
87
+
88
+ Entrust.net Premium 2048 Secure Server CA
89
+ =========================================
90
+ -----BEGIN CERTIFICATE-----
91
+ MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
92
+ ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
93
+ bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
94
+ BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
95
+ NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
96
+ d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
97
+ MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
98
+ ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
99
+ MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
100
+ Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
101
+ hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
102
+ nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
103
+ VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
104
+ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
105
+ KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
106
+ T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
107
+ zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
108
+ J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
109
+ nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
110
+ -----END CERTIFICATE-----
111
+
112
+ Baltimore CyberTrust Root
113
+ =========================
114
+ -----BEGIN CERTIFICATE-----
115
+ MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
116
+ ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
117
+ ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
118
+ SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
119
+ dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
120
+ uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
121
+ UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
122
+ G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
123
+ XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
124
+ l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
125
+ VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
126
+ BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
127
+ cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
128
+ hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
129
+ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
130
+ RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
131
+ -----END CERTIFICATE-----
132
+
133
+ AddTrust External Root
134
+ ======================
135
+ -----BEGIN CERTIFICATE-----
136
+ MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
137
+ QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
138
+ VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
139
+ NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
140
+ cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
141
+ Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
142
+ +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
143
+ Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
144
+ aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
145
+ 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
146
+ 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
147
+ BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
148
+ VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
149
+ VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
150
+ IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
151
+ j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
152
+ 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
153
+ e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
154
+ G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
155
+ -----END CERTIFICATE-----
156
+
157
+ Entrust Root Certification Authority
158
+ ====================================
159
+ -----BEGIN CERTIFICATE-----
160
+ MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
161
+ BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
162
+ b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
163
+ A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
164
+ MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
165
+ MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
166
+ Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
167
+ dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
168
+ ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
169
+ A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
170
+ Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
171
+ j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
172
+ rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
173
+ DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
174
+ MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
175
+ hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
176
+ A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
177
+ Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
178
+ v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
179
+ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
180
+ tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
181
+ -----END CERTIFICATE-----
182
+
183
+ GeoTrust Global CA
184
+ ==================
185
+ -----BEGIN CERTIFICATE-----
186
+ MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
187
+ Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
188
+ MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
189
+ LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
190
+ CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
191
+ BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
192
+ 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
193
+ T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
194
+ vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
195
+ AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
196
+ DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
197
+ zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
198
+ d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
199
+ mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
200
+ XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
201
+ Mw==
202
+ -----END CERTIFICATE-----
203
+
204
+ GeoTrust Universal CA
205
+ =====================
206
+ -----BEGIN CERTIFICATE-----
207
+ MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
208
+ R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
209
+ MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
210
+ Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
211
+ ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
212
+ JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
213
+ RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
214
+ 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
215
+ 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
216
+ qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
217
+ Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
218
+ Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
219
+ KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
220
+ ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
221
+ XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
222
+ hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
223
+ aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
224
+ qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
225
+ oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
226
+ xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
227
+ KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
228
+ DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
229
+ xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
230
+ p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
231
+ P/rmMuGNG2+k5o7Y+SlIis5z/iw=
232
+ -----END CERTIFICATE-----
233
+
234
+ GeoTrust Universal CA 2
235
+ =======================
236
+ -----BEGIN CERTIFICATE-----
237
+ MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
238
+ R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
239
+ MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
240
+ SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
241
+ A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
242
+ DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
243
+ j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
244
+ JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
245
+ QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
246
+ WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
247
+ 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
248
+ ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
249
+ SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
250
+ 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
251
+ +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
252
+ BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
253
+ dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
254
+ 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
255
+ mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
256
+ A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
257
+ Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
258
+ pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
259
+ FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
260
+ gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
261
+ X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
262
+ -----END CERTIFICATE-----
263
+
264
+ Visa eCommerce Root
265
+ ===================
266
+ -----BEGIN CERTIFICATE-----
267
+ MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
268
+ EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
269
+ QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
270
+ WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
271
+ VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
272
+ bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
273
+ F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
274
+ RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
275
+ TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
276
+ /k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
277
+ GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
278
+ MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
279
+ CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
280
+ YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
281
+ zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
282
+ YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
283
+ 398znM/jra6O1I7mT1GvFpLgXPYHDw==
284
+ -----END CERTIFICATE-----
285
+
286
+ Comodo AAA Services root
287
+ ========================
288
+ -----BEGIN CERTIFICATE-----
289
+ MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
290
+ R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
291
+ TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
292
+ MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
293
+ c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
294
+ BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
295
+ ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
296
+ C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
297
+ i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
298
+ Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
299
+ Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
300
+ Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
301
+ BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
302
+ cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
303
+ LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
304
+ 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
305
+ Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
306
+ 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
307
+ 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
308
+ -----END CERTIFICATE-----
309
+
310
+ QuoVadis Root CA
311
+ ================
312
+ -----BEGIN CERTIFICATE-----
313
+ MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
314
+ ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
315
+ eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
316
+ MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
317
+ cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
318
+ EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
319
+ AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
320
+ J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
321
+ F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
322
+ YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
323
+ AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
324
+ PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
325
+ ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
326
+ MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
327
+ YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
328
+ ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
329
+ Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
330
+ Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
331
+ BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
332
+ FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
333
+ aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
334
+ tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
335
+ fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
336
+ LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
337
+ gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
338
+ 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
339
+ 5nrQNiOKSnQ2+Q==
340
+ -----END CERTIFICATE-----
341
+
342
+ QuoVadis Root CA 2
343
+ ==================
344
+ -----BEGIN CERTIFICATE-----
345
+ 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
371
+ -----END CERTIFICATE-----
372
+
373
+ QuoVadis Root CA 3
374
+ ==================
375
+ -----BEGIN CERTIFICATE-----
376
+ MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
377
+ EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
378
+ OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
379
+ aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
380
+ DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
381
+ DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
382
+ KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
383
+ DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
384
+ BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
385
+ p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
386
+ nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
387
+ MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
388
+ Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
389
+ uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
390
+ BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
391
+ YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
392
+ aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
393
+ BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
394
+ VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
395
+ ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
396
+ AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
397
+ qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
398
+ hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
399
+ POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
400
+ Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
401
+ 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
402
+ bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
403
+ g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
404
+ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
405
+ qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
406
+ -----END CERTIFICATE-----
407
+
408
+ Security Communication Root CA
409
+ ==============================
410
+ -----BEGIN CERTIFICATE-----
411
+ MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
412
+ U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
413
+ HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
414
+ U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
415
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
416
+ 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
417
+ DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
418
+ 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
419
+ DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
420
+ JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
421
+ DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
422
+ 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
423
+ mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
424
+ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
425
+ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
426
+ FL39vmwLAw==
427
+ -----END CERTIFICATE-----
428
+
429
+ Sonera Class 2 Root CA
430
+ ======================
431
+ -----BEGIN CERTIFICATE-----
432
+ MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
433
+ U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
434
+ NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
435
+ IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
436
+ /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
437
+ dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
438
+ f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
439
+ tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
440
+ nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
441
+ XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
442
+ 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
443
+ cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
444
+ Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
445
+ EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
446
+ llpwrN9M
447
+ -----END CERTIFICATE-----
448
+
449
+ XRamp Global CA Root
450
+ ====================
451
+ -----BEGIN CERTIFICATE-----
452
+ MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
453
+ BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
454
+ dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
455
+ dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
456
+ HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
457
+ U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
458
+ dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
459
+ IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
460
+ foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
461
+ zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
462
+ AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
463
+ xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
464
+ EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
465
+ oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
466
+ AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
467
+ /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
468
+ qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
469
+ nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
470
+ 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
471
+ -----END CERTIFICATE-----
472
+
473
+ Go Daddy Class 2 CA
474
+ ===================
475
+ -----BEGIN CERTIFICATE-----
476
+ MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
477
+ VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
478
+ ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
479
+ A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
480
+ RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
481
+ ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
482
+ 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
483
+ qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
484
+ YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
485
+ vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
486
+ BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
487
+ atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
488
+ MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
489
+ A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
490
+ PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
491
+ I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
492
+ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
493
+ Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
494
+ vZ8=
495
+ -----END CERTIFICATE-----
496
+
497
+ Starfield Class 2 CA
498
+ ====================
499
+ -----BEGIN CERTIFICATE-----
500
+ MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
501
+ U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
502
+ Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
503
+ MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
504
+ A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
505
+ SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
506
+ bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
507
+ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
508
+ epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
509
+ F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
510
+ MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
511
+ hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
512
+ bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
513
+ QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
514
+ afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
515
+ PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
516
+ xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
517
+ KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
518
+ QBFGmh95DmK/D5fs4C8fF5Q=
519
+ -----END CERTIFICATE-----
520
+
521
+ Taiwan GRCA
522
+ ===========
523
+ -----BEGIN CERTIFICATE-----
524
+ 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
549
+ -----END CERTIFICATE-----
550
+
551
+ DigiCert Assured ID Root CA
552
+ ===========================
553
+ -----BEGIN CERTIFICATE-----
554
+ MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
555
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
556
+ IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
557
+ MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
558
+ ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
559
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
560
+ 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
561
+ UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
562
+ /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
563
+ oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
564
+ GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
565
+ 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
566
+ hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
567
+ EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
568
+ SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
569
+ 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
570
+ +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
571
+ -----END CERTIFICATE-----
572
+
573
+ DigiCert Global Root CA
574
+ =======================
575
+ -----BEGIN CERTIFICATE-----
576
+ MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
577
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
578
+ HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
579
+ MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
580
+ dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
581
+ hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
582
+ TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
583
+ BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
584
+ 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
585
+ 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
586
+ o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
587
+ 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
588
+ BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
589
+ EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
590
+ tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
591
+ UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
592
+ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
593
+ -----END CERTIFICATE-----
594
+
595
+ DigiCert High Assurance EV Root CA
596
+ ==================================
597
+ -----BEGIN CERTIFICATE-----
598
+ MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
599
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
600
+ KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
601
+ MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
602
+ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
603
+ Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
604
+ Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
605
+ OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
606
+ MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
607
+ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
608
+ h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
609
+ Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
610
+ JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
611
+ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
612
+ myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
613
+ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
614
+ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
615
+ -----END CERTIFICATE-----
616
+
617
+ Certplus Class 2 Primary CA
618
+ ===========================
619
+ -----BEGIN CERTIFICATE-----
620
+ MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
621
+ BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
622
+ OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
623
+ dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
624
+ ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
625
+ 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
626
+ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
627
+ YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
628
+ e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
629
+ CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
630
+ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
631
+ L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
632
+ P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
633
+ TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
634
+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
635
+ //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
636
+ l7+ijrRU
637
+ -----END CERTIFICATE-----
638
+
639
+ DST Root CA X3
640
+ ==============
641
+ -----BEGIN CERTIFICATE-----
642
+ MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
643
+ ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
644
+ DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
645
+ cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
646
+ ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
647
+ rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
648
+ UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
649
+ xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
650
+ utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
651
+ AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
652
+ MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
653
+ dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
654
+ GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
655
+ RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
656
+ fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
657
+ -----END CERTIFICATE-----
658
+
659
+ SwissSign Gold CA - G2
660
+ ======================
661
+ -----BEGIN CERTIFICATE-----
662
+ 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
688
+ -----END CERTIFICATE-----
689
+
690
+ SwissSign Silver CA - G2
691
+ ========================
692
+ -----BEGIN CERTIFICATE-----
693
+ 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
719
+ -----END CERTIFICATE-----
720
+
721
+ GeoTrust Primary Certification Authority
722
+ ========================================
723
+ -----BEGIN CERTIFICATE-----
724
+ MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
725
+ EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
726
+ ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
727
+ CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
728
+ cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
729
+ CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
730
+ b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
731
+ nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
732
+ RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
733
+ tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
734
+ AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
735
+ hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
736
+ Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
737
+ NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
738
+ Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
739
+ 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
740
+ -----END CERTIFICATE-----
741
+
742
+ thawte Primary Root CA
743
+ ======================
744
+ -----BEGIN CERTIFICATE-----
745
+ MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
746
+ BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
747
+ aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
748
+ cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
749
+ MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
750
+ SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
751
+ KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
752
+ FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
753
+ oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
754
+ 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
755
+ q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
756
+ aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
757
+ afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
758
+ VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
759
+ AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
760
+ uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
761
+ xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
762
+ jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
763
+ z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
764
+ -----END CERTIFICATE-----
765
+
766
+ VeriSign Class 3 Public Primary Certification Authority - G5
767
+ ============================================================
768
+ -----BEGIN CERTIFICATE-----
769
+ MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
770
+ BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
771
+ ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
772
+ IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
773
+ ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
774
+ yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
775
+ biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
776
+ dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
777
+ YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
778
+ ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
779
+ j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
780
+ Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
781
+ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
782
+ fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
783
+ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
784
+ Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
785
+ aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
786
+ SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
787
+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
788
+ KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
789
+ Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
790
+ ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
791
+ -----END CERTIFICATE-----
792
+
793
+ SecureTrust CA
794
+ ==============
795
+ -----BEGIN CERTIFICATE-----
796
+ MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
797
+ EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
798
+ dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
799
+ BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
800
+ ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
801
+ OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
802
+ DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
803
+ GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
804
+ 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
805
+ ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
806
+ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
807
+ aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
808
+ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
809
+ SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
810
+ mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
811
+ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
812
+ 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
813
+ -----END CERTIFICATE-----
814
+
815
+ Secure Global CA
816
+ ================
817
+ -----BEGIN CERTIFICATE-----
818
+ MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
819
+ EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
820
+ bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
821
+ MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
822
+ Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
823
+ YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
824
+ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
825
+ 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
826
+ HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
827
+ 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
828
+ EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
829
+ oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
830
+ MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
831
+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
832
+ CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
833
+ 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
834
+ f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
835
+ -----END CERTIFICATE-----
836
+
837
+ COMODO Certification Authority
838
+ ==============================
839
+ -----BEGIN CERTIFICATE-----
840
+ MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
841
+ BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
842
+ A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
843
+ dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
844
+ MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
845
+ T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
846
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
847
+ +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
848
+ xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
849
+ 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
850
+ 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
851
+ rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
852
+ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
853
+ b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
854
+ AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
855
+ OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
856
+ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
857
+ IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
858
+ +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
859
+ -----END CERTIFICATE-----
860
+
861
+ Network Solutions Certificate Authority
862
+ =======================================
863
+ -----BEGIN CERTIFICATE-----
864
+ MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
865
+ EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
866
+ IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
867
+ MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
868
+ MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
869
+ CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
870
+ jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
871
+ aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
872
+ crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
873
+ /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
874
+ AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
875
+ BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
876
+ bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
877
+ A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
878
+ 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
879
+ GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
880
+ wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
881
+ ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
882
+ -----END CERTIFICATE-----
883
+
884
+ COMODO ECC Certification Authority
885
+ ==================================
886
+ -----BEGIN CERTIFICATE-----
887
+ MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
888
+ R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
889
+ ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
890
+ dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
891
+ GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
892
+ Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
893
+ b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
894
+ 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
895
+ wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
896
+ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
897
+ FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
898
+ U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
899
+ -----END CERTIFICATE-----
900
+
901
+ OISTE WISeKey Global Root GA CA
902
+ ===============================
903
+ -----BEGIN CERTIFICATE-----
904
+ MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
905
+ BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
906
+ A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
907
+ bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
908
+ VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
909
+ IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
910
+ IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
911
+ Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
912
+ Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
913
+ d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
914
+ /yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
915
+ LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
916
+ AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
917
+ KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
918
+ MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
919
+ +vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
920
+ hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
921
+ okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
922
+ -----END CERTIFICATE-----
923
+
924
+ Certigna
925
+ ========
926
+ -----BEGIN CERTIFICATE-----
927
+ MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
928
+ EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
929
+ MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
930
+ Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
931
+ XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
932
+ GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
933
+ ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
934
+ DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
935
+ Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
936
+ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
937
+ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
938
+ SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
939
+ hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
940
+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
941
+ PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
942
+ 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
943
+ WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
944
+ -----END CERTIFICATE-----
945
+
946
+ Deutsche Telekom Root CA 2
947
+ ==========================
948
+ -----BEGIN CERTIFICATE-----
949
+ MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
950
+ RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
951
+ A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
952
+ MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
953
+ A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
954
+ b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
955
+ bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
956
+ KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
957
+ AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
958
+ Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
959
+ jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
960
+ HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
961
+ E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
962
+ zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
963
+ rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
964
+ dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
965
+ Cm26OWMohpLzGITY+9HPBVZkVw==
966
+ -----END CERTIFICATE-----
967
+
968
+ Cybertrust Global Root
969
+ ======================
970
+ -----BEGIN CERTIFICATE-----
971
+ MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
972
+ ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
973
+ MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
974
+ ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
975
+ +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
976
+ 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
977
+ AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
978
+ 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
979
+ 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
980
+ BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
981
+ MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
982
+ A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
983
+ lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
984
+ 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
985
+ hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
986
+ X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
987
+ WL1WMRJOEcgh4LMRkWXbtKaIOM5V
988
+ -----END CERTIFICATE-----
989
+
990
+ ePKI Root Certification Authority
991
+ =================================
992
+ -----BEGIN CERTIFICATE-----
993
+ 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
1019
+ -----END CERTIFICATE-----
1020
+
1021
+ certSIGN ROOT CA
1022
+ ================
1023
+ -----BEGIN CERTIFICATE-----
1024
+ MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
1025
+ VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
1026
+ Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
1027
+ CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
1028
+ JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
1029
+ rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
1030
+ ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
1031
+ 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
1032
+ AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
1033
+ Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
1034
+ AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
1035
+ SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
1036
+ x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
1037
+ vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
1038
+ TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
1039
+ -----END CERTIFICATE-----
1040
+
1041
+ GeoTrust Primary Certification Authority - G3
1042
+ =============================================
1043
+ -----BEGIN CERTIFICATE-----
1044
+ MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
1045
+ BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
1046
+ IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
1047
+ eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
1048
+ NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
1049
+ YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
1050
+ LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
1051
+ hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
1052
+ K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
1053
+ c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
1054
+ IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
1055
+ dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
1056
+ MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
1057
+ 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
1058
+ cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
1059
+ Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
1060
+ AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
1061
+ t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
1062
+ -----END CERTIFICATE-----
1063
+
1064
+ thawte Primary Root CA - G2
1065
+ ===========================
1066
+ -----BEGIN CERTIFICATE-----
1067
+ MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
1068
+ VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
1069
+ IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
1070
+ Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
1071
+ MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
1072
+ b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
1073
+ IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
1074
+ LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
1075
+ 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
1076
+ mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
1077
+ G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
1078
+ rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
1079
+ -----END CERTIFICATE-----
1080
+
1081
+ thawte Primary Root CA - G3
1082
+ ===========================
1083
+ -----BEGIN CERTIFICATE-----
1084
+ MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
1085
+ BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
1086
+ aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
1087
+ cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
1088
+ ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
1089
+ d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
1090
+ VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
1091
+ A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
1092
+ MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
1093
+ P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
1094
+ +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
1095
+ 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
1096
+ vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
1097
+ BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
1098
+ KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
1099
+ A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
1100
+ t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
1101
+ 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
1102
+ er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
1103
+ -----END CERTIFICATE-----
1104
+
1105
+ GeoTrust Primary Certification Authority - G2
1106
+ =============================================
1107
+ -----BEGIN CERTIFICATE-----
1108
+ MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
1109
+ VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
1110
+ Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
1111
+ ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
1112
+ OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
1113
+ MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
1114
+ b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
1115
+ BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
1116
+ KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
1117
+ VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
1118
+ EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
1119
+ ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
1120
+ npaqBA+K
1121
+ -----END CERTIFICATE-----
1122
+
1123
+ VeriSign Universal Root Certification Authority
1124
+ ===============================================
1125
+ -----BEGIN CERTIFICATE-----
1126
+ MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
1127
+ BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
1128
+ ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
1129
+ IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
1130
+ IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
1131
+ UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
1132
+ cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
1133
+ IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
1134
+ aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
1135
+ 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
1136
+ MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
1137
+ 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
1138
+ AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
1139
+ tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
1140
+ CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
1141
+ a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
1142
+ DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
1143
+ Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
1144
+ Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
1145
+ P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
1146
+ wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
1147
+ mJO37M2CYfE45k+XmCpajQ==
1148
+ -----END CERTIFICATE-----
1149
+
1150
+ VeriSign Class 3 Public Primary Certification Authority - G4
1151
+ ============================================================
1152
+ -----BEGIN CERTIFICATE-----
1153
+ MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
1154
+ VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
1155
+ b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
1156
+ ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
1157
+ YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
1158
+ MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
1159
+ cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
1160
+ b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
1161
+ IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
1162
+ Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
1163
+ rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
1164
+ /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
1165
+ HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
1166
+ Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
1167
+ A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
1168
+ AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
1169
+ -----END CERTIFICATE-----
1170
+
1171
+ NetLock Arany (Class Gold) Főtanúsítvány
1172
+ ========================================
1173
+ -----BEGIN CERTIFICATE-----
1174
+ MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
1175
+ A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
1176
+ dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
1177
+ cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
1178
+ MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
1179
+ ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
1180
+ biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
1181
+ c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
1182
+ 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
1183
+ /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
1184
+ H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
1185
+ fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
1186
+ neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
1187
+ BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
1188
+ qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
1189
+ YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
1190
+ bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
1191
+ NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
1192
+ dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
1193
+ -----END CERTIFICATE-----
1194
+
1195
+ Staat der Nederlanden Root CA - G2
1196
+ ==================================
1197
+ -----BEGIN CERTIFICATE-----
1198
+ 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
1224
+ 66+KAQ==
1225
+ -----END CERTIFICATE-----
1226
+
1227
+ Hongkong Post Root CA 1
1228
+ =======================
1229
+ -----BEGIN CERTIFICATE-----
1230
+ MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
1231
+ DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
1232
+ NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
1233
+ IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
1234
+ AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
1235
+ ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
1236
+ auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
1237
+ qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
1238
+ V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
1239
+ HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
1240
+ h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
1241
+ l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
1242
+ IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
1243
+ T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
1244
+ c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
1245
+ -----END CERTIFICATE-----
1246
+
1247
+ SecureSign RootCA11
1248
+ ===================
1249
+ -----BEGIN CERTIFICATE-----
1250
+ MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
1251
+ SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
1252
+ b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
1253
+ KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
1254
+ cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
1255
+ TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
1256
+ wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
1257
+ g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
1258
+ O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
1259
+ bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
1260
+ t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
1261
+ OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
1262
+ bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
1263
+ Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
1264
+ y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
1265
+ lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
1266
+ -----END CERTIFICATE-----
1267
+
1268
+ Microsec e-Szigno Root CA 2009
1269
+ ==============================
1270
+ -----BEGIN CERTIFICATE-----
1271
+ MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
1272
+ MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
1273
+ c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
1274
+ dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
1275
+ BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
1276
+ U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
1277
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
1278
+ fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
1279
+ 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
1280
+ pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
1281
+ 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
1282
+ AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
1283
+ QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
1284
+ FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
1285
+ lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
1286
+ I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
1287
+ tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
1288
+ yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
1289
+ LXpUq3DDfSJlgnCW
1290
+ -----END CERTIFICATE-----
1291
+
1292
+ GlobalSign Root CA - R3
1293
+ =======================
1294
+ -----BEGIN CERTIFICATE-----
1295
+ MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
1296
+ YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
1297
+ bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
1298
+ aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
1299
+ bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
1300
+ iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
1301
+ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
1302
+ rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
1303
+ OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
1304
+ xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
1305
+ FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
1306
+ lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
1307
+ EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
1308
+ bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
1309
+ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
1310
+ kpeDMdmztcpHWD9f
1311
+ -----END CERTIFICATE-----
1312
+
1313
+ Autoridad de Certificacion Firmaprofesional CIF A62634068
1314
+ =========================================================
1315
+ -----BEGIN CERTIFICATE-----
1316
+ MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
1317
+ BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
1318
+ MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
1319
+ QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
1320
+ NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
1321
+ Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
1322
+ B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
1323
+ 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
1324
+ ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
1325
+ plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
1326
+ MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
1327
+ LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
1328
+ bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
1329
+ vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
1330
+ EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
1331
+ DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
1332
+ cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
1333
+ bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
1334
+ ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
1335
+ 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
1336
+ R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
1337
+ T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
1338
+ Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
1339
+ osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
1340
+ crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
1341
+ saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
1342
+ KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
1343
+ 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
1344
+ -----END CERTIFICATE-----
1345
+
1346
+ Izenpe.com
1347
+ ==========
1348
+ -----BEGIN CERTIFICATE-----
1349
+ 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
1376
+ -----END CERTIFICATE-----
1377
+
1378
+ Chambers of Commerce Root - 2008
1379
+ ================================
1380
+ -----BEGIN CERTIFICATE-----
1381
+ MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
1382
+ MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
1383
+ bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
1384
+ QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
1385
+ Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
1386
+ ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
1387
+ EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
1388
+ cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
1389
+ AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
1390
+ XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
1391
+ h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
1392
+ ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
1393
+ NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
1394
+ D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
1395
+ lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
1396
+ 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
1397
+ ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
1398
+ EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
1399
+ G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
1400
+ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
1401
+ bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
1402
+ bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
1403
+ CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
1404
+ AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
1405
+ wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
1406
+ 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
1407
+ RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
1408
+ M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
1409
+ YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
1410
+ 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
1411
+ zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
1412
+ nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
1413
+ OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
1414
+ -----END CERTIFICATE-----
1415
+
1416
+ Global Chambersign Root - 2008
1417
+ ==============================
1418
+ -----BEGIN CERTIFICATE-----
1419
+ MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
1420
+ MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
1421
+ bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
1422
+ QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
1423
+ NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
1424
+ Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
1425
+ QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
1426
+ aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
1427
+ VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
1428
+ XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
1429
+ ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
1430
+ /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
1431
+ TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
1432
+ H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
1433
+ Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
1434
+ HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
1435
+ wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
1436
+ AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
1437
+ BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
1438
+ BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
1439
+ aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
1440
+ aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
1441
+ 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
1442
+ dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
1443
+ /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
1444
+ ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
1445
+ dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
1446
+ 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
1447
+ foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
1448
+ qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
1449
+ P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
1450
+ c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
1451
+ 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
1452
+ -----END CERTIFICATE-----
1453
+
1454
+ Go Daddy Root Certificate Authority - G2
1455
+ ========================================
1456
+ -----BEGIN CERTIFICATE-----
1457
+ MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
1458
+ B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
1459
+ MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
1460
+ MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
1461
+ b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
1462
+ A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
1463
+ hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
1464
+ 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
1465
+ +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
1466
+ fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
1467
+ NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
1468
+ MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
1469
+ BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
1470
+ vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
1471
+ 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
1472
+ N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
1473
+ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
1474
+ -----END CERTIFICATE-----
1475
+
1476
+ Starfield Root Certificate Authority - G2
1477
+ =========================================
1478
+ -----BEGIN CERTIFICATE-----
1479
+ MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
1480
+ B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
1481
+ b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
1482
+ eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
1483
+ DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
1484
+ VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
1485
+ dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
1486
+ W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
1487
+ bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
1488
+ N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
1489
+ ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
1490
+ JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
1491
+ AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
1492
+ TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
1493
+ 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
1494
+ F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
1495
+ pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
1496
+ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
1497
+ -----END CERTIFICATE-----
1498
+
1499
+ Starfield Services Root Certificate Authority - G2
1500
+ ==================================================
1501
+ -----BEGIN CERTIFICATE-----
1502
+ MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
1503
+ B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
1504
+ b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
1505
+ IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
1506
+ BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
1507
+ dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
1508
+ Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
1509
+ AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
1510
+ h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
1511
+ hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
1512
+ LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
1513
+ rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
1514
+ AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
1515
+ SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
1516
+ E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
1517
+ xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
1518
+ iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
1519
+ YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
1520
+ -----END CERTIFICATE-----
1521
+
1522
+ AffirmTrust Commercial
1523
+ ======================
1524
+ -----BEGIN CERTIFICATE-----
1525
+ MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
1526
+ BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
1527
+ MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
1528
+ bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
1529
+ AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
1530
+ DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
1531
+ C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
1532
+ BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
1533
+ MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
1534
+ HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
1535
+ AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
1536
+ hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
1537
+ qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
1538
+ 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
1539
+ sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
1540
+ -----END CERTIFICATE-----
1541
+
1542
+ AffirmTrust Networking
1543
+ ======================
1544
+ -----BEGIN CERTIFICATE-----
1545
+ MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
1546
+ BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
1547
+ MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
1548
+ bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
1549
+ AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
1550
+ Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
1551
+ dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
1552
+ /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
1553
+ h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
1554
+ HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
1555
+ AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
1556
+ UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
1557
+ 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
1558
+ WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
1559
+ /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
1560
+ -----END CERTIFICATE-----
1561
+
1562
+ AffirmTrust Premium
1563
+ ===================
1564
+ -----BEGIN CERTIFICATE-----
1565
+ MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
1566
+ BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
1567
+ OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
1568
+ dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
1569
+ MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
1570
+ BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
1571
+ 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
1572
+ +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
1573
+ GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
1574
+ p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
1575
+ S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
1576
+ 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
1577
+ /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
1578
+ +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
1579
+ /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
1580
+ MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
1581
+ Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
1582
+ 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
1583
+ L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
1584
+ +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
1585
+ BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
1586
+ IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
1587
+ g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
1588
+ zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
1589
+ -----END CERTIFICATE-----
1590
+
1591
+ AffirmTrust Premium ECC
1592
+ =======================
1593
+ -----BEGIN CERTIFICATE-----
1594
+ MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
1595
+ BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
1596
+ MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
1597
+ cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
1598
+ IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
1599
+ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
1600
+ BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
1601
+ BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
1602
+ 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
1603
+ eQ==
1604
+ -----END CERTIFICATE-----
1605
+
1606
+ Certum Trusted Network CA
1607
+ =========================
1608
+ -----BEGIN CERTIFICATE-----
1609
+ MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
1610
+ ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
1611
+ biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
1612
+ MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
1613
+ ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
1614
+ MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
1615
+ AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
1616
+ l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
1617
+ J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
1618
+ fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
1619
+ cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
1620
+ Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
1621
+ DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
1622
+ jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
1623
+ mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
1624
+ Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
1625
+ 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
1626
+ -----END CERTIFICATE-----
1627
+
1628
+ TWCA Root Certification Authority
1629
+ =================================
1630
+ -----BEGIN CERTIFICATE-----
1631
+ MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
1632
+ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
1633
+ dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
1634
+ EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
1635
+ IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
1636
+ AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
1637
+ QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
1638
+ oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
1639
+ 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
1640
+ y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
1641
+ BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
1642
+ 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
1643
+ mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
1644
+ QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
1645
+ T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
1646
+ Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
1647
+ -----END CERTIFICATE-----
1648
+
1649
+ Security Communication RootCA2
1650
+ ==============================
1651
+ -----BEGIN CERTIFICATE-----
1652
+ MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
1653
+ U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
1654
+ dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
1655
+ SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
1656
+ aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
1657
+ ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
1658
+ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
1659
+ 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
1660
+ spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
1661
+ EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
1662
+ QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
1663
+ CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
1664
+ u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
1665
+ 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
1666
+ tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
1667
+ mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
1668
+ -----END CERTIFICATE-----
1669
+
1670
+ EC-ACC
1671
+ ======
1672
+ -----BEGIN CERTIFICATE-----
1673
+ MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
1674
+ BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
1675
+ ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
1676
+ VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
1677
+ CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
1678
+ BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
1679
+ MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
1680
+ SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
1681
+ Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
1682
+ cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
1683
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
1684
+ w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
1685
+ ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
1686
+ HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
1687
+ E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
1688
+ 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
1689
+ BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
1690
+ VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
1691
+ Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
1692
+ dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
1693
+ lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
1694
+ Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
1695
+ l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
1696
+ E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
1697
+ 5EI=
1698
+ -----END CERTIFICATE-----
1699
+
1700
+ Hellenic Academic and Research Institutions RootCA 2011
1701
+ =======================================================
1702
+ -----BEGIN CERTIFICATE-----
1703
+ MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
1704
+ O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
1705
+ aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
1706
+ IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
1707
+ AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
1708
+ IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
1709
+ IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
1710
+ AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
1711
+ 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
1712
+ 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
1713
+ 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
1714
+ 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
1715
+ MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
1716
+ MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
1717
+ b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
1718
+ XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
1719
+ TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
1720
+ /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
1721
+ 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
1722
+ -----END CERTIFICATE-----
1723
+
1724
+ Actalis Authentication Root CA
1725
+ ==============================
1726
+ -----BEGIN CERTIFICATE-----
1727
+ MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
1728
+ BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
1729
+ AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
1730
+ MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
1731
+ IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
1732
+ IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
1733
+ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
1734
+ by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
1735
+ zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
1736
+ YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
1737
+ oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
1738
+ EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
1739
+ hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
1740
+ EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
1741
+ jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
1742
+ iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
1743
+ ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
1744
+ WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
1745
+ JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
1746
+ K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
1747
+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
1748
+ 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
1749
+ 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
1750
+ lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
1751
+ OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
1752
+ vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
1753
+ -----END CERTIFICATE-----
1754
+
1755
+ Trustis FPS Root CA
1756
+ ===================
1757
+ -----BEGIN CERTIFICATE-----
1758
+ MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
1759
+ EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
1760
+ IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
1761
+ BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
1762
+ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
1763
+ RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
1764
+ H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
1765
+ cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
1766
+ o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
1767
+ AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
1768
+ BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
1769
+ GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
1770
+ yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
1771
+ 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
1772
+ l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
1773
+ iB6XzCGcKQENZetX2fNXlrtIzYE=
1774
+ -----END CERTIFICATE-----
1775
+
1776
+ Buypass Class 2 Root CA
1777
+ =======================
1778
+ -----BEGIN CERTIFICATE-----
1779
+ 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
1803
+ rJgWVqA=
1804
+ -----END CERTIFICATE-----
1805
+
1806
+ Buypass Class 3 Root CA
1807
+ =======================
1808
+ -----BEGIN CERTIFICATE-----
1809
+ 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
1833
+ Cp/HuZc=
1834
+ -----END CERTIFICATE-----
1835
+
1836
+ T-TeleSec GlobalRoot Class 3
1837
+ ============================
1838
+ -----BEGIN CERTIFICATE-----
1839
+ MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
1840
+ IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
1841
+ cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
1842
+ MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
1843
+ dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
1844
+ ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
1845
+ DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
1846
+ 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
1847
+ NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
1848
+ iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
1849
+ 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
1850
+ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
1851
+ AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
1852
+ fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
1853
+ ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
1854
+ P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
1855
+ e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
1856
+ -----END CERTIFICATE-----
1857
+
1858
+ EE Certification Centre Root CA
1859
+ ===============================
1860
+ -----BEGIN CERTIFICATE-----
1861
+ MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
1862
+ EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
1863
+ dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
1864
+ MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
1865
+ UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
1866
+ ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
1867
+ DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
1868
+ TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
1869
+ rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
1870
+ 93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
1871
+ P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
1872
+ AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
1873
+ MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
1874
+ BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
1875
+ xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
1876
+ lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
1877
+ uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
1878
+ 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
1879
+ dcGWxZ0=
1880
+ -----END CERTIFICATE-----
1881
+
1882
+ D-TRUST Root Class 3 CA 2 2009
1883
+ ==============================
1884
+ -----BEGIN CERTIFICATE-----
1885
+ MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
1886
+ DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
1887
+ Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
1888
+ LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
1889
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
1890
+ ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
1891
+ BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
1892
+ KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
1893
+ p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
1894
+ AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
1895
+ 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
1896
+ eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
1897
+ MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
1898
+ PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
1899
+ OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
1900
+ 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
1901
+ o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
1902
+ dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
1903
+ X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
1904
+ -----END CERTIFICATE-----
1905
+
1906
+ D-TRUST Root Class 3 CA 2 EV 2009
1907
+ =================================
1908
+ -----BEGIN CERTIFICATE-----
1909
+ MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
1910
+ DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
1911
+ OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
1912
+ DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
1913
+ OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
1914
+ egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
1915
+ zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
1916
+ 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
1917
+ sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
1918
+ 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
1919
+ cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
1920
+ ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
1921
+ MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
1922
+ b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
1923
+ c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
1924
+ PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
1925
+ nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
1926
+ ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
1927
+ NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
1928
+ w9y4AyHqnxbxLFS1
1929
+ -----END CERTIFICATE-----
1930
+
1931
+ CA Disig Root R2
1932
+ ================
1933
+ -----BEGIN CERTIFICATE-----
1934
+ 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
1958
+ 7+ZtsH8tZ/3zbBt1RqPlShfppNcL
1959
+ -----END CERTIFICATE-----
1960
+
1961
+ ACCVRAIZ1
1962
+ =========
1963
+ -----BEGIN CERTIFICATE-----
1964
+ MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
1965
+ SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
1966
+ MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
1967
+ UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
1968
+ DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
1969
+ jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
1970
+ RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
1971
+ aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
1972
+ 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
1973
+ WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
1974
+ 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
1975
+ 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
1976
+ 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
1977
+ Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
1978
+ Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
1979
+ Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
1980
+ VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
1981
+ Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
1982
+ QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
1983
+ AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
1984
+ YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
1985
+ AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
1986
+ IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
1987
+ aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
1988
+ dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
1989
+ MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
1990
+ hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
1991
+ R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
1992
+ YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
1993
+ nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
1994
+ TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
1995
+ sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
1996
+ I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
1997
+ Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
1998
+ 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
1999
+ EfbRD0tVNEYqi4Y7
2000
+ -----END CERTIFICATE-----
2001
+
2002
+ TWCA Global Root CA
2003
+ ===================
2004
+ -----BEGIN CERTIFICATE-----
2005
+ MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
2006
+ CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
2007
+ QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
2008
+ EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
2009
+ Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
2010
+ nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
2011
+ r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
2012
+ Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
2013
+ tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
2014
+ KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
2015
+ sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
2016
+ yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
2017
+ kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
2018
+ zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
2019
+ AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
2020
+ cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
2021
+ LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
2022
+ 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
2023
+ /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
2024
+ lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
2025
+ A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
2026
+ i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
2027
+ EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
2028
+ zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
2029
+ -----END CERTIFICATE-----
2030
+
2031
+ TeliaSonera Root CA v1
2032
+ ======================
2033
+ -----BEGIN CERTIFICATE-----
2034
+ MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
2035
+ CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
2036
+ MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
2037
+ VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
2038
+ 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
2039
+ 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
2040
+ B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
2041
+ Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
2042
+ oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
2043
+ F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
2044
+ oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
2045
+ gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
2046
+ TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
2047
+ AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
2048
+ DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
2049
+ zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
2050
+ 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
2051
+ pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
2052
+ G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
2053
+ c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
2054
+ JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
2055
+ qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
2056
+ Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
2057
+ WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
2058
+ -----END CERTIFICATE-----
2059
+
2060
+ E-Tugra Certification Authority
2061
+ ===============================
2062
+ -----BEGIN CERTIFICATE-----
2063
+ MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
2064
+ DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
2065
+ ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
2066
+ ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
2067
+ NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
2068
+ QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
2069
+ cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
2070
+ DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
2071
+ MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
2072
+ hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
2073
+ CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
2074
+ ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
2075
+ BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
2076
+ E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
2077
+ rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
2078
+ jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
2079
+ rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
2080
+ dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
2081
+ /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
2082
+ MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
2083
+ kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
2084
+ XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
2085
+ VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
2086
+ a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
2087
+ dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
2088
+ KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
2089
+ Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
2090
+ 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
2091
+ C7TbO6Orb1wdtn7os4I07QZcJA==
2092
+ -----END CERTIFICATE-----
2093
+
2094
+ T-TeleSec GlobalRoot Class 2
2095
+ ============================
2096
+ -----BEGIN CERTIFICATE-----
2097
+ MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
2098
+ IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
2099
+ cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
2100
+ MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
2101
+ dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
2102
+ ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
2103
+ DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
2104
+ SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
2105
+ vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
2106
+ 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
2107
+ WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
2108
+ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
2109
+ YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
2110
+ r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
2111
+ vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
2112
+ 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
2113
+ 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
2114
+ -----END CERTIFICATE-----
2115
+
2116
+ Atos TrustedRoot 2011
2117
+ =====================
2118
+ -----BEGIN CERTIFICATE-----
2119
+ MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
2120
+ cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
2121
+ MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
2122
+ A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
2123
+ hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
2124
+ 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
2125
+ DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
2126
+ HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
2127
+ z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
2128
+ l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
2129
+ bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
2130
+ CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
2131
+ k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
2132
+ TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
2133
+ 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
2134
+ 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
2135
+ -----END CERTIFICATE-----
2136
+
2137
+ QuoVadis Root CA 1 G3
2138
+ =====================
2139
+ -----BEGIN CERTIFICATE-----
2140
+ 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
2164
+ hMJKzRwuJIczYOXD
2165
+ -----END CERTIFICATE-----
2166
+
2167
+ QuoVadis Root CA 2 G3
2168
+ =====================
2169
+ -----BEGIN CERTIFICATE-----
2170
+ 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
2194
+ O3jtZsSOeWmD3n+M
2195
+ -----END CERTIFICATE-----
2196
+
2197
+ QuoVadis Root CA 3 G3
2198
+ =====================
2199
+ -----BEGIN CERTIFICATE-----
2200
+ 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
2224
+ PpxxVJkES/1Y+Zj0
2225
+ -----END CERTIFICATE-----
2226
+
2227
+ DigiCert Assured ID Root G2
2228
+ ===========================
2229
+ -----BEGIN CERTIFICATE-----
2230
+ MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
2231
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
2232
+ IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
2233
+ MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
2234
+ ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
2235
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
2236
+ 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
2237
+ bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
2238
+ VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
2239
+ YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
2240
+ lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
2241
+ w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
2242
+ 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
2243
+ d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
2244
+ hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
2245
+ jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
2246
+ IhNzbM8m9Yop5w==
2247
+ -----END CERTIFICATE-----
2248
+
2249
+ DigiCert Assured ID Root G3
2250
+ ===========================
2251
+ -----BEGIN CERTIFICATE-----
2252
+ MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
2253
+ UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
2254
+ VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
2255
+ MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
2256
+ d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
2257
+ BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
2258
+ RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
2259
+ KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
2260
+ UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
2261
+ YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
2262
+ 1vUhZscv6pZjamVFkpUBtA==
2263
+ -----END CERTIFICATE-----
2264
+
2265
+ DigiCert Global Root G2
2266
+ =======================
2267
+ -----BEGIN CERTIFICATE-----
2268
+ MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
2269
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
2270
+ HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
2271
+ MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
2272
+ dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
2273
+ hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
2274
+ kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
2275
+ 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
2276
+ BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
2277
+ UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
2278
+ o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
2279
+ 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
2280
+ F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
2281
+ WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
2282
+ QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
2283
+ iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
2284
+ MrY=
2285
+ -----END CERTIFICATE-----
2286
+
2287
+ DigiCert Global Root G3
2288
+ =======================
2289
+ -----BEGIN CERTIFICATE-----
2290
+ MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
2291
+ UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
2292
+ VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
2293
+ MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
2294
+ aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
2295
+ AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
2296
+ YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
2297
+ BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
2298
+ Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
2299
+ 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
2300
+ VOKa5Vt8sycX
2301
+ -----END CERTIFICATE-----
2302
+
2303
+ DigiCert Trusted Root G4
2304
+ ========================
2305
+ -----BEGIN CERTIFICATE-----
2306
+ MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
2307
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
2308
+ HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
2309
+ MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
2310
+ d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
2311
+ CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
2312
+ pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
2313
+ k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
2314
+ vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
2315
+ QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
2316
+ MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
2317
+ mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
2318
+ f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
2319
+ dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
2320
+ oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
2321
+ DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
2322
+ ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
2323
+ ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
2324
+ yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
2325
+ 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
2326
+ ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
2327
+ 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
2328
+ /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
2329
+ 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
2330
+ G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
2331
+ 82Z+
2332
+ -----END CERTIFICATE-----
2333
+
2334
+ COMODO RSA Certification Authority
2335
+ ==================================
2336
+ -----BEGIN CERTIFICATE-----
2337
+ MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
2338
+ BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
2339
+ A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
2340
+ biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
2341
+ R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
2342
+ ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
2343
+ dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
2344
+ dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
2345
+ FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
2346
+ 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
2347
+ x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
2348
+ 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
2349
+ OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
2350
+ sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
2351
+ GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
2352
+ WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
2353
+ FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
2354
+ DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
2355
+ rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
2356
+ nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
2357
+ tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
2358
+ sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
2359
+ pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
2360
+ zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
2361
+ ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
2362
+ 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
2363
+ LaZRfyHBNVOFBkpdn627G190
2364
+ -----END CERTIFICATE-----
2365
+
2366
+ USERTrust RSA Certification Authority
2367
+ =====================================
2368
+ -----BEGIN CERTIFICATE-----
2369
+ MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
2370
+ BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
2371
+ ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
2372
+ dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
2373
+ BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
2374
+ ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
2375
+ dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
2376
+ 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
2377
+ Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
2378
+ RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
2379
+ +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
2380
+ /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
2381
+ Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
2382
+ lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
2383
+ yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
2384
+ eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
2385
+ BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
2386
+ MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
2387
+ FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
2388
+ 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
2389
+ Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
2390
+ 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
2391
+ FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
2392
+ yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
2393
+ J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
2394
+ sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
2395
+ Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
2396
+ -----END CERTIFICATE-----
2397
+
2398
+ USERTrust ECC Certification Authority
2399
+ =====================================
2400
+ -----BEGIN CERTIFICATE-----
2401
+ MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
2402
+ VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
2403
+ aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
2404
+ biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
2405
+ VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
2406
+ aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
2407
+ biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
2408
+ 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
2409
+ nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
2410
+ HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
2411
+ HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
2412
+ 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
2413
+ -----END CERTIFICATE-----
2414
+
2415
+ GlobalSign ECC Root CA - R4
2416
+ ===========================
2417
+ -----BEGIN CERTIFICATE-----
2418
+ MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
2419
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
2420
+ EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
2421
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
2422
+ EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
2423
+ OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
2424
+ AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
2425
+ MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
2426
+ JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
2427
+ -----END CERTIFICATE-----
2428
+
2429
+ GlobalSign ECC Root CA - R5
2430
+ ===========================
2431
+ -----BEGIN CERTIFICATE-----
2432
+ MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
2433
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
2434
+ EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
2435
+ R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
2436
+ EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
2437
+ SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
2438
+ h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
2439
+ BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
2440
+ uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
2441
+ yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
2442
+ -----END CERTIFICATE-----
2443
+
2444
+ Staat der Nederlanden Root CA - G3
2445
+ ==================================
2446
+ -----BEGIN CERTIFICATE-----
2447
+ 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
2472
+ -----END CERTIFICATE-----
2473
+
2474
+ Staat der Nederlanden EV Root CA
2475
+ ================================
2476
+ -----BEGIN CERTIFICATE-----
2477
+ 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
2501
+ eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
2502
+ -----END CERTIFICATE-----
2503
+
2504
+ IdenTrust Commercial Root CA 1
2505
+ ==============================
2506
+ -----BEGIN CERTIFICATE-----
2507
+ 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
2531
+ cGzM7vRX+Bi6hG6H
2532
+ -----END CERTIFICATE-----
2533
+
2534
+ IdenTrust Public Sector Root CA 1
2535
+ =================================
2536
+ -----BEGIN CERTIFICATE-----
2537
+ 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
2561
+ 3Wl9af0AVqW3rLatt8o+Ae+c
2562
+ -----END CERTIFICATE-----
2563
+
2564
+ Entrust Root Certification Authority - G2
2565
+ =========================================
2566
+ -----BEGIN CERTIFICATE-----
2567
+ MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
2568
+ BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
2569
+ bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
2570
+ b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
2571
+ HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
2572
+ DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
2573
+ OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
2574
+ eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
2575
+ MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
2576
+ /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
2577
+ HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
2578
+ s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
2579
+ TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
2580
+ AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
2581
+ 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
2582
+ iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
2583
+ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
2584
+ nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
2585
+ vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
2586
+ e4pIb4tF9g==
2587
+ -----END CERTIFICATE-----
2588
+
2589
+ Entrust Root Certification Authority - EC1
2590
+ ==========================================
2591
+ -----BEGIN CERTIFICATE-----
2592
+ MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
2593
+ FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
2594
+ YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
2595
+ ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
2596
+ IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
2597
+ FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
2598
+ LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
2599
+ dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
2600
+ IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
2601
+ AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
2602
+ 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
2603
+ FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
2604
+ vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
2605
+ kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
2606
+ -----END CERTIFICATE-----
2607
+
2608
+ CFCA EV ROOT
2609
+ ============
2610
+ -----BEGIN CERTIFICATE-----
2611
+ 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
2636
+ -----END CERTIFICATE-----
2637
+
2638
+ Certinomis - Root CA
2639
+ ====================
2640
+ -----BEGIN CERTIFICATE-----
2641
+ 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
2666
+ hkIGuUE=
2667
+ -----END CERTIFICATE-----
2668
+
2669
+ OISTE WISeKey Global Root GB CA
2670
+ ===============================
2671
+ -----BEGIN CERTIFICATE-----
2672
+ MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
2673
+ EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
2674
+ ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
2675
+ MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
2676
+ VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
2677
+ b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
2678
+ scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
2679
+ rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
2680
+ 9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
2681
+ Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
2682
+ GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
2683
+ /zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
2684
+ hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
2685
+ dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
2686
+ VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
2687
+ HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
2688
+ Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
2689
+ -----END CERTIFICATE-----
2690
+
2691
+ SZAFIR ROOT CA2
2692
+ ===============
2693
+ -----BEGIN CERTIFICATE-----
2694
+ MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
2695
+ A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
2696
+ BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
2697
+ BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
2698
+ VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
2699
+ qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
2700
+ DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
2701
+ 2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
2702
+ ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
2703
+ ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
2704
+ AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
2705
+ AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
2706
+ O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
2707
+ oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
2708
+ 4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
2709
+ +/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
2710
+ -----END CERTIFICATE-----
2711
+
2712
+ Certum Trusted Network CA 2
2713
+ ===========================
2714
+ -----BEGIN CERTIFICATE-----
2715
+ MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
2716
+ BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
2717
+ bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
2718
+ ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
2719
+ TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
2720
+ cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
2721
+ IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
2722
+ 7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
2723
+ CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
2724
+ Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
2725
+ uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
2726
+ GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
2727
+ 9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
2728
+ Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
2729
+ hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
2730
+ BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
2731
+ AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
2732
+ hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
2733
+ Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
2734
+ L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
2735
+ clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
2736
+ pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
2737
+ w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
2738
+ J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
2739
+ ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
2740
+ is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
2741
+ zAYspsbiDrW5viSP
2742
+ -----END CERTIFICATE-----
2743
+
2744
+ Hellenic Academic and Research Institutions RootCA 2015
2745
+ =======================================================
2746
+ -----BEGIN CERTIFICATE-----
2747
+ MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
2748
+ BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
2749
+ aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
2750
+ YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
2751
+ MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
2752
+ QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
2753
+ BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
2754
+ MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
2755
+ bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
2756
+ iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
2757
+ 6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
2758
+ FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
2759
+ i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
2760
+ GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
2761
+ fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
2762
+ iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
2763
+ Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
2764
+ AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
2765
+ hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
2766
+ D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
2767
+ d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
2768
+ d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
2769
+ 82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
2770
+ davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
2771
+ Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
2772
+ J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
2773
+ JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
2774
+ p/UsQu0yrbYhnr68
2775
+ -----END CERTIFICATE-----
2776
+
2777
+ Hellenic Academic and Research Institutions ECC RootCA 2015
2778
+ ===========================================================
2779
+ -----BEGIN CERTIFICATE-----
2780
+ MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
2781
+ aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
2782
+ cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
2783
+ aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
2784
+ MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
2785
+ IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
2786
+ VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
2787
+ Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
2788
+ dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
2789
+ Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
2790
+ BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
2791
+ GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
2792
+ dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
2793
+ -----END CERTIFICATE-----
2794
+
2795
+ Certplus Root CA G1
2796
+ ===================
2797
+ -----BEGIN CERTIFICATE-----
2798
+ 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
2822
+ qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
2823
+ -----END CERTIFICATE-----
2824
+
2825
+ Certplus Root CA G2
2826
+ ===================
2827
+ -----BEGIN CERTIFICATE-----
2828
+ MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT
2829
+ AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x
2830
+ NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0
2831
+ cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA
2832
+ BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN
2833
+ Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD
2834
+ AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud
2835
+ IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV
2836
+ HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl
2837
+ vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==
2838
+ -----END CERTIFICATE-----
2839
+
2840
+ OpenTrust Root CA G1
2841
+ ====================
2842
+ -----BEGIN CERTIFICATE-----
2843
+ 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
2867
+ OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx
2868
+ -----END CERTIFICATE-----
2869
+
2870
+ OpenTrust Root CA G2
2871
+ ====================
2872
+ -----BEGIN CERTIFICATE-----
2873
+ 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
2897
+ u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK
2898
+ -----END CERTIFICATE-----
2899
+
2900
+ OpenTrust Root CA G3
2901
+ ====================
2902
+ -----BEGIN CERTIFICATE-----
2903
+ MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT
2904
+ AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X
2905
+ DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w
2906
+ ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA
2907
+ IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B
2908
+ ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB
2909
+ /wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf
2910
+ BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM
2911
+ BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta
2912
+ 3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB
2913
+ -----END CERTIFICATE-----
2914
+
2915
+ ISRG Root X1
2916
+ ============
2917
+ -----BEGIN CERTIFICATE-----
2918
+ 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
2942
+ m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
2943
+ -----END CERTIFICATE-----
2944
+
2945
+ AC RAIZ FNMT-RCM
2946
+ ================
2947
+ -----BEGIN CERTIFICATE-----
2948
+ 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
2973
+ -----END CERTIFICATE-----
2974
+
2975
+ Amazon Root CA 1
2976
+ ================
2977
+ -----BEGIN CERTIFICATE-----
2978
+ MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
2979
+ VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
2980
+ MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
2981
+ bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
2982
+ ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
2983
+ FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
2984
+ gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
2985
+ dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
2986
+ VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
2987
+ /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
2988
+ DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
2989
+ CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
2990
+ 8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
2991
+ 2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
2992
+ xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
2993
+ -----END CERTIFICATE-----
2994
+
2995
+ Amazon Root CA 2
2996
+ ================
2997
+ -----BEGIN CERTIFICATE-----
2998
+ MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
2999
+ VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
3000
+ MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
3001
+ bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
3002
+ ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
3003
+ kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
3004
+ N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
3005
+ AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
3006
+ fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
3007
+ kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
3008
+ btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
3009
+ Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
3010
+ c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
3011
+ 3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
3012
+ DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
3013
+ A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
3014
+ +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
3015
+ YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
3016
+ xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
3017
+ gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
3018
+ aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
3019
+ Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
3020
+ KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
3021
+ JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
3022
+ -----END CERTIFICATE-----
3023
+
3024
+ Amazon Root CA 3
3025
+ ================
3026
+ -----BEGIN CERTIFICATE-----
3027
+ MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
3028
+ EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
3029
+ NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
3030
+ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
3031
+ f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
3032
+ Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
3033
+ rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
3034
+ eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
3035
+ -----END CERTIFICATE-----
3036
+
3037
+ Amazon Root CA 4
3038
+ ================
3039
+ -----BEGIN CERTIFICATE-----
3040
+ MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
3041
+ EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
3042
+ NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
3043
+ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
3044
+ /sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
3045
+ 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
3046
+ HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
3047
+ MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
3048
+ AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
3049
+ -----END CERTIFICATE-----
3050
+
3051
+ LuxTrust Global Root 2
3052
+ ======================
3053
+ -----BEGIN CERTIFICATE-----
3054
+ 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
3080
+ -----END CERTIFICATE-----
3081
+
3082
+ TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
3083
+ =============================================
3084
+ -----BEGIN CERTIFICATE-----
3085
+ MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
3086
+ D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
3087
+ IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
3088
+ TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
3089
+ ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
3090
+ VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
3091
+ c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
3092
+ bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
3093
+ IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
3094
+ MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
3095
+ 6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
3096
+ wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
3097
+ 3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
3098
+ WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
3099
+ ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
3100
+ KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
3101
+ AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
3102
+ lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
3103
+ e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
3104
+ q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
3105
+ -----END CERTIFICATE-----
3106
+
3107
+ GDCA TrustAUTH R5 ROOT
3108
+ ======================
3109
+ -----BEGIN CERTIFICATE-----
3110
+ MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
3111
+ BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
3112
+ DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
3113
+ YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
3114
+ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
3115
+ AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
3116
+ AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
3117
+ OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
3118
+ pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
3119
+ 9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
3120
+ xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
3121
+ R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
3122
+ D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
3123
+ oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
3124
+ 9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
3125
+ MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
3126
+ p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
3127
+ H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
3128
+ 6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
3129
+ +PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
3130
+ HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
3131
+ F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
3132
+ 8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
3133
+ /EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
3134
+ aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
3135
+ -----END CERTIFICATE-----
3136
+
3137
+ TrustCor RootCert CA-1
3138
+ ======================
3139
+ -----BEGIN CERTIFICATE-----
3140
+ MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP
3141
+ MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
3142
+ U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
3143
+ dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx
3144
+ MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu
3145
+ YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe
3146
+ VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy
3147
+ dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq
3148
+ jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4
3149
+ pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0
3150
+ JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h
3151
+ gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw
3152
+ /Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j
3153
+ BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
3154
+ AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5
3155
+ mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
3156
+ ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C
3157
+ qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P
3158
+ 3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk=
3159
+ -----END CERTIFICATE-----
3160
+
3161
+ TrustCor RootCert CA-2
3162
+ ======================
3163
+ -----BEGIN CERTIFICATE-----
3164
+ MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w
3165
+ DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT
3166
+ eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0
3167
+ eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy
3168
+ MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h
3169
+ bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
3170
+ cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0
3171
+ IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb
3172
+ ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk
3173
+ RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1
3174
+ oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb
3175
+ XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1
3176
+ /p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q
3177
+ jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP
3178
+ eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg
3179
+ rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
3180
+ 8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU
3181
+ 2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD
3182
+ VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h
3183
+ Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp
3184
+ kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv
3185
+ 2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3
3186
+ S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw
3187
+ PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv
3188
+ DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU
3189
+ RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE
3190
+ xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX
3191
+ RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ
3192
+ -----END CERTIFICATE-----
3193
+
3194
+ TrustCor ECA-1
3195
+ ==============
3196
+ -----BEGIN CERTIFICATE-----
3197
+ MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP
3198
+ MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig
3199
+ U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp
3200
+ dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw
3201
+ N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5
3202
+ MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y
3203
+ IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG
3204
+ SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR
3205
+ MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23
3206
+ xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc
3207
+ p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+
3208
+ fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj
3209
+ YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL
3210
+ f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
3211
+ AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u
3212
+ /ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
3213
+ hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs
3214
+ J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC
3215
+ jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g==
3216
+ -----END CERTIFICATE-----
3217
+
3218
+ SSL.com Root Certification Authority RSA
3219
+ ========================================
3220
+ -----BEGIN CERTIFICATE-----
3221
+ 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
3247
+ WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
3248
+ -----END CERTIFICATE-----
3249
+
3250
+ SSL.com Root Certification Authority ECC
3251
+ ========================================
3252
+ -----BEGIN CERTIFICATE-----
3253
+ MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
3254
+ BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
3255
+ BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
3256
+ MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
3257
+ BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
3258
+ bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
3259
+ BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
3260
+ 8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
3261
+ hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
3262
+ jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
3263
+ e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
3264
+ 5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
3265
+ -----END CERTIFICATE-----
3266
+
3267
+ SSL.com EV Root Certification Authority RSA R2
3268
+ ==============================================
3269
+ -----BEGIN CERTIFICATE-----
3270
+ MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
3271
+ DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
3272
+ MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
3273
+ MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
3274
+ DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
3275
+ VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
3276
+ BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
3277
+ hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
3278
+ cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
3279
+ Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
3280
+ B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
3281
+ CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
3282
+ 9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
3283
+ RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
3284
+ JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
3285
+ +qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
3286
+ HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
3287
+ qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
3288
+ ++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
3289
+ Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
3290
+ guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
3291
+ OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
3292
+ CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
3293
+ lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
3294
+ rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
3295
+ hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
3296
+ 9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
3297
+ -----END CERTIFICATE-----
3298
+
3299
+ SSL.com EV Root Certification Authority ECC
3300
+ ===========================================
3301
+ -----BEGIN CERTIFICATE-----
3302
+ MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
3303
+ BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
3304
+ BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
3305
+ MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
3306
+ EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
3307
+ LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
3308
+ BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
3309
+ 3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
3310
+ BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
3311
+ 5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
3312
+ N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
3313
+ m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
3314
+ -----END CERTIFICATE-----
includes/vendor/ultimate-web-scraper/crc32_stream.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CRC32 stream class.
3
+ // (C) 2016 CubicleSoft. All Rights Reserved.
4
+ //
5
+ // Direct port from the CubicleSoft C++ implementation.
6
+
7
+ class CRC32Stream
8
+ {
9
+ private $open, $crctable, $datareflect, $crcreflect, $firstcrc, $currcrc, $finalxor;
10
+ private static $revlookup = array(0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255);
11
+
12
+ // PKZip, gzip, AUTODIN II, Ethernet, and FDDI.
13
+ public static $default = array("poly" => 0x04C11DB7, "start" => 0xFFFFFFFF, "xor" => 0xFFFFFFFF, "refdata" => 1, "refcrc" => 1);
14
+
15
+ public function __construct()
16
+ {
17
+ $this->open = false;
18
+ }
19
+
20
+ public function Init($options = false)
21
+ {
22
+ if ($options === false) $options = self::$default;
23
+
24
+ $this->crctable = array();
25
+ $poly = $this->LIM32($options["poly"]);
26
+ for ($x = 0; $x < 256; $x++)
27
+ {
28
+ $c = $this->SHL32($x, 24);
29
+ for ($y = 0; $y < 8; $y++) $c = $this->SHL32($c, 1) ^ ($c & 0x80000000 ? $poly : 0);
30
+ $this->crctable[$x] = $c;
31
+ }
32
+
33
+ $this->datareflect = $options["refdata"];
34
+ $this->crcreflect = $options["refcrc"];
35
+ $this->firstcrc = $options["start"];
36
+ $this->currcrc = $options["start"];
37
+ $this->finalxor = $options["xor"];
38
+ $this->open = true;
39
+ }
40
+
41
+ public function AddData($data)
42
+ {
43
+ if (!$this->open) return false;
44
+
45
+ $y = strlen($data);
46
+ for ($x < 0; $x < $y; $x++)
47
+ {
48
+ if ($this->datareflect) $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ self::$revlookup[ord($data{$x})]];
49
+ else $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ ord($data{$x})];
50
+ }
51
+
52
+ return true;
53
+ }
54
+
55
+ public function Finalize()
56
+ {
57
+ if (!$this->open) return false;
58
+
59
+ if ($this->crcreflect)
60
+ {
61
+ $tempcrc = $this->currcrc;
62
+ $this->currcrc = self::$revlookup[$this->SHR32($tempcrc, 24)] | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 16) & 0xFF], 8) | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 8) & 0xFF], 16) | $this->SHL32(self::$revlookup[$this->LIM32($tempcrc & 0xFF)], 24);
63
+ }
64
+ $result = $this->currcrc ^ $this->finalxor;
65
+
66
+ $this->currcrc = $this->firstcrc;
67
+
68
+ return $result;
69
+ }
70
+
71
+ // These functions are a hacky, but effective way of enforcing unsigned 32-bit integers onto a generic signed int.
72
+ // Allow bitwise operations to work across platforms. Minimum integer size must be 32-bit.
73
+ private function SHR32($num, $bits)
74
+ {
75
+ $num = (int)$num;
76
+ if ($bits < 0) $bits = 0;
77
+
78
+ if ($num < 0 && $bits)
79
+ {
80
+ $num = ($num >> 1) & 0x7FFFFFFF;
81
+ $bits--;
82
+ }
83
+
84
+ return $this->LIM32($num >> $bits);
85
+ }
86
+
87
+ private function SHL32($num, $bits)
88
+ {
89
+ if ($bits < 0) $bits = 0;
90
+
91
+ return $this->LIM32((int)$num << $bits);
92
+ }
93
+
94
+ private function LIM32($num)
95
+ {
96
+ return (int)((int)$num & 0xFFFFFFFF);
97
+ }
98
+ }
99
+ ?>
includes/vendor/ultimate-web-scraper/deflate_stream.php ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Deflate stream class. Default is RFC1951 (raw deflate). Supports RFC1950 (ZLIB) and RFC1952 (gzip).
3
+ // (C) 2016 CubicleSoft. All Rights Reserved.
4
+
5
+ class DeflateStream
6
+ {
7
+ private $open, $fp, $filter, $compress, $indata, $outdata, $options;
8
+ private static $supported;
9
+
10
+ public function __construct()
11
+ {
12
+ $this->open = false;
13
+ }
14
+
15
+ public function __destruct()
16
+ {
17
+ $this->Finalize();
18
+ }
19
+
20
+ public static function IsSupported()
21
+ {
22
+ if (!is_bool(self::$supported))
23
+ {
24
+ self::$supported = function_exists("stream_filter_append") && function_exists("stream_filter_remove") && function_exists("gzcompress");
25
+ if (self::$supported)
26
+ {
27
+ $data = self::Compress("test");
28
+ if ($data === false || $data === "") self::$supported = false;
29
+ else
30
+ {
31
+ $data = self::Uncompress($data);
32
+ if ($data === false || $data !== "test") self::$supported = false;
33
+ }
34
+ }
35
+ }
36
+
37
+ return self::$supported;
38
+ }
39
+
40
+ public static function Compress($data, $compresslevel = -1, $options = array())
41
+ {
42
+ $ds = new DeflateStream;
43
+ if (!$ds->Init("wb", $compresslevel, $options)) return false;
44
+ if (!$ds->Write($data)) return false;
45
+ if (!$ds->Finalize()) return false;
46
+ $data = $ds->Read();
47
+
48
+ return $data;
49
+ }
50
+
51
+ public static function Uncompress($data, $options = array("type" => "auto"))
52
+ {
53
+ $ds = new DeflateStream;
54
+ if (!$ds->Init("rb", -1, $options)) return false;
55
+ if (!$ds->Write($data)) return false;
56
+ if (!$ds->Finalize()) return false;
57
+ $data = $ds->Read();
58
+
59
+ return $data;
60
+ }
61
+
62
+ public function Init($mode, $compresslevel = -1, $options = array())
63
+ {
64
+ if ($mode !== "rb" && $mode !== "wb") return false;
65
+ if ($this->open) $this->Finalize();
66
+
67
+ $this->fp = fopen("php://memory", "w+b");
68
+ if ($this->fp === false) return false;
69
+ $this->compress = ($mode == "wb");
70
+ if (!isset($options["type"])) $options["type"] = "rfc1951";
71
+
72
+ if ($options["type"] == "rfc1950") $options["type"] = "zlib";
73
+ else if ($options["type"] == "rfc1952") $options["type"] = "gzip";
74
+
75
+ if ($options["type"] != "zlib" && $options["type"] != "gzip" && ($this->compress || $options["type"] != "auto")) $options["type"] = "raw";
76
+ $this->options = $options;
77
+
78
+ // Add the deflate filter.
79
+ if ($this->compress) $this->filter = stream_filter_append($this->fp, "zlib.deflate", STREAM_FILTER_WRITE, $compresslevel);
80
+ else $this->filter = stream_filter_append($this->fp, "zlib.inflate", STREAM_FILTER_READ);
81
+
82
+ $this->open = true;
83
+ $this->indata = "";
84
+ $this->outdata = "";
85
+
86
+ if ($this->compress)
87
+ {
88
+ if ($this->options["type"] == "zlib")
89
+ {
90
+ $this->outdata .= "\x78\x9C";
91
+ $this->options["a"] = 1;
92
+ $this->options["b"] = 0;
93
+ }
94
+ else if ($this->options["type"] == "gzip")
95
+ {
96
+ if (!class_exists("CRC32Stream", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/crc32_stream.php";
97
+
98
+ $this->options["crc32"] = new CRC32Stream();
99
+ $this->options["crc32"]->Init();
100
+ $this->options["bytes"] = 0;
101
+
102
+ $this->outdata .= "\x1F\x8B\x08";
103
+ $flags = 0;
104
+ if (isset($this->options["filename"])) $flags |= 0x08;
105
+ if (isset($this->options["comment"])) $flags |= 0x10;
106
+ $this->outdata .= chr($flags);
107
+ $this->outdata .= "\x00\x00\x00\x00";
108
+ $this->outdata .= "\x00";
109
+ $this->outdata .= "\x03";
110
+
111
+ if (isset($this->options["filename"])) $this->outdata .= str_replace("\x00", " ", $this->options["filename"]) . "\x00";
112
+ if (isset($this->options["comment"])) $this->outdata .= str_replace("\x00", " ", $this->options["comment"]) . "\x00";
113
+ }
114
+ }
115
+ else
116
+ {
117
+ $this->options["header"] = false;
118
+ }
119
+
120
+ return true;
121
+ }
122
+
123
+ public function Read()
124
+ {
125
+ $result = $this->outdata;
126
+ $this->outdata = "";
127
+
128
+ return $result;
129
+ }
130
+
131
+ public function Write($data)
132
+ {
133
+ if (!$this->open) return false;
134
+
135
+ if ($this->compress)
136
+ {
137
+ if ($this->options["type"] == "zlib")
138
+ {
139
+ // Adler-32.
140
+ $y = strlen($data);
141
+ for ($x = 0; $x < $y; $x++)
142
+ {
143
+ $this->options["a"] = ($this->options["a"] + ord($data{$x})) % 65521;
144
+ $this->options["b"] = ($this->options["b"] + $this->options["a"]) % 65521;
145
+ }
146
+ }
147
+ else if ($this->options["type"] == "gzip")
148
+ {
149
+ $this->options["crc32"]->AddData($data);
150
+ $this->options["bytes"] = $this->ADD32($this->options["bytes"], strlen($data));
151
+ }
152
+
153
+ $this->indata .= $data;
154
+ while (strlen($this->indata) >= 65536)
155
+ {
156
+ fwrite($this->fp, substr($this->indata, 0, 65536));
157
+ $this->indata = substr($this->indata, 65536);
158
+
159
+ $this->ProcessOutput();
160
+ }
161
+ }
162
+ else
163
+ {
164
+ $this->indata .= $data;
165
+ $this->ProcessInput();
166
+ }
167
+
168
+ return true;
169
+ }
170
+
171
+ // Finalizes the stream.
172
+ public function Finalize()
173
+ {
174
+ if (!$this->open) return false;
175
+
176
+ if (!$this->compress) $this->ProcessInput(true);
177
+
178
+ if (strlen($this->indata) > 0)
179
+ {
180
+ fwrite($this->fp, $this->indata);
181
+ $this->indata = "";
182
+ }
183
+
184
+ // Removing the filter pushes the last buffer into the stream.
185
+ stream_filter_remove($this->filter);
186
+ $this->filter = false;
187
+
188
+ $this->ProcessOutput();
189
+
190
+ fclose($this->fp);
191
+
192
+ if ($this->compress)
193
+ {
194
+ if ($this->options["type"] == "zlib") $this->outdata .= pack("N", $this->SHL32($this->options["b"], 16) | $this->options["a"]);
195
+ else if ($this->options["type"] == "gzip") $this->outdata .= pack("V", $this->options["crc32"]->Finalize()) . pack("V", $this->options["bytes"]);
196
+ }
197
+
198
+ $this->open = false;
199
+
200
+ return true;
201
+ }
202
+
203
+ private function ProcessOutput()
204
+ {
205
+ rewind($this->fp);
206
+
207
+ // Hack! Because ftell() on a stream with a filter is still broken even under the latest PHP a mere 4 years later.
208
+ // See: https://bugs.php.net/bug.php?id=49874
209
+ ob_start();
210
+ fpassthru($this->fp);
211
+ $this->outdata .= ob_get_contents();
212
+ ob_end_clean();
213
+
214
+ rewind($this->fp);
215
+ ftruncate($this->fp, 0);
216
+ }
217
+
218
+ private function ProcessInput($final = false)
219
+ {
220
+ // Automatically determine the type of data based on the header signature.
221
+ if ($this->options["type"] == "auto")
222
+ {
223
+ if (strlen($this->indata) >= 3)
224
+ {
225
+ $zlibtest = unpack("n", substr($this->indata, 0, 2));
226
+
227
+ if (substr($this->indata, 0, 3) === "\x1F\x8B\x08") $this->options["type"] = "gzip";
228
+ else if ((ord($this->indata{0}) & 0x0F) == 8 && ((ord($this->indata{0}) & 0xF0) >> 4) < 8 && $zlibtest[1] % 31 == 0) $this->options["type"] = "zlib";
229
+ else $this->options["type"] = "raw";
230
+ }
231
+ else if ($final) $this->options["type"] = "raw";
232
+ }
233
+
234
+ if ($this->options["type"] == "gzip")
235
+ {
236
+ if (!$this->options["header"])
237
+ {
238
+ if (strlen($this->indata) >= 10)
239
+ {
240
+ $idcm = substr($this->indata, 0, 3);
241
+ $flg = ord($this->indata{3});
242
+
243
+ if ($idcm !== "\x1F\x8B\x08") $this->options["type"] = "ignore";
244
+ else
245
+ {
246
+ // Calculate the number of bytes to skip. If flags are set, the size can be dynamic.
247
+ $size = 10;
248
+ $y = strlen($this->indata);
249
+
250
+ // FLG.FEXTRA
251
+ if ($size && ($flg & 0x04))
252
+ {
253
+ if ($size + 2 >= $y) $size = 0;
254
+ else
255
+ {
256
+ $xlen = unpack("v", substr($this->indata, $size, 2));
257
+ $size = ($size + 2 + $xlen <= $y ? $size + 2 + $xlen : 0);
258
+ }
259
+ }
260
+
261
+ // FLG.FNAME
262
+ if ($size && ($flg & 0x08))
263
+ {
264
+ $pos = strpos($this->indata, "\x00", $size);
265
+ $size = ($pos !== false ? $pos + 1 : 0);
266
+ }
267
+
268
+ // FLG.FCOMMENT
269
+ if ($size && ($flg & 0x10))
270
+ {
271
+ $pos = strpos($this->indata, "\x00", $size);
272
+ $size = ($pos !== false ? $pos + 1 : 0);
273
+ }
274
+
275
+ // FLG.FHCRC
276
+ if ($size && ($flg & 0x02)) $size = ($size + 2 <= $y ? $size + 2 : 0);
277
+
278
+ if ($size)
279
+ {
280
+ $this->indata = substr($this->indata, $size);
281
+ $this->options["header"] = true;
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ if ($this->options["header"] && strlen($this->indata) > 8)
288
+ {
289
+ fwrite($this->fp, substr($this->indata, 0, -8));
290
+ $this->indata = substr($this->indata, -8);
291
+
292
+ $this->ProcessOutput();
293
+ }
294
+
295
+ if ($final) $this->indata = "";
296
+ }
297
+ else if ($this->options["type"] == "zlib")
298
+ {
299
+ if (!$this->options["header"])
300
+ {
301
+ if (strlen($this->indata) >= 2)
302
+ {
303
+ $cmf = ord($this->indata{0});
304
+ $flg = ord($this->indata{1});
305
+ $cm = $cmf & 0x0F;
306
+ $cinfo = ($cmf & 0xF0) >> 4;
307
+
308
+ // Compression method 'deflate' ($cm = 8), window size - 8 ($cinfo < 8), no preset dictionaries ($flg bit 5), checksum validates.
309
+ if ($cm != 8 || $cinfo > 7 || ($flg & 0x20) || (($cmf << 8 | $flg) % 31) != 0) $this->options["type"] = "ignore";
310
+ else
311
+ {
312
+ $this->indata = substr($this->indata, 2);
313
+ $this->options["header"] = true;
314
+ }
315
+ }
316
+ }
317
+
318
+ if ($this->options["header"] && strlen($this->indata) > 4)
319
+ {
320
+ fwrite($this->fp, substr($this->indata, 0, -4));
321
+ $this->indata = substr($this->indata, -4);
322
+
323
+ $this->ProcessOutput();
324
+ }
325
+
326
+ if ($final) $this->indata = "";
327
+ }
328
+
329
+ if ($this->options["type"] == "raw")
330
+ {
331
+ fwrite($this->fp, $this->indata);
332
+ $this->indata = "";
333
+
334
+ $this->ProcessOutput();
335
+ }
336
+
337
+ // Only set when an unrecoverable header error has occurred for gzip or zlib.
338
+ if ($this->options["type"] == "ignore") $this->indata = "";
339
+ }
340
+
341
+ private function SHL32($num, $bits)
342
+ {
343
+ if ($bits < 0) $bits = 0;
344
+
345
+ return $this->LIM32((int)$num << $bits);
346
+ }
347
+
348
+ private function LIM32($num)
349
+ {
350
+ return (int)((int)$num & 0xFFFFFFFF);
351
+ }
352
+
353
+ private function ADD32($num, $num2)
354
+ {
355
+ $num = (int)$num;
356
+ $num2 = (int)$num2;
357
+ $add = ((($num >> 30) & 0x03) + (($num2 >> 30) & 0x03));
358
+ $num = ((int)($num & 0x3FFFFFFF) + (int)($num2 & 0x3FFFFFFF));
359
+ if ($num & 0x40000000) $add++;
360
+ $num = (int)(($num & 0x3FFFFFFF) | (($add & 0x03) << 30));
361
+
362
+ return $num;
363
+ }
364
+ }
365
+ ?>
includes/vendor/ultimate-web-scraper/emulate_curl.php ADDED
@@ -0,0 +1,1423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP HTTP cURL emulation functions.
3
+ // (C) 2016 CubicleSoft. All Rights Reserved.
4
+
5
+ // cURL HTTP emulation support requires:
6
+ // The CubicleSoft PHP HTTP functions.
7
+ // The CubicleSoft Web Browser state emulation class.
8
+ if (!function_exists("curl_init"))
9
+ {
10
+ if (!class_exists("HTTP", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/http.php";
11
+
12
+ global $curl_error__map, $curl_init__map, $curl_multi_init__map;
13
+
14
+ // Constants based on PHP 5.4.0 and libcurl 7.25.0.
15
+ $curl_error__map = array(
16
+ 0 => "CURLE_OK",
17
+ 1 => "CURLE_UNSUPPORTED_PROTOCOL",
18
+ 2 => "CURLE_FAILED_INIT",
19
+ 3 => "CURLE_URL_MALFORMAT",
20
+ 4 => "CURLE_NOT_BUILT_IN",
21
+ 5 => "CURLE_COULDNT_RESOLVE_PROXY",
22
+ 6 => "CURLE_COULDNT_RESOLVE_HOST",
23
+ 7 => "CURLE_COULDNT_CONNECT",
24
+ 8 => "CURLE_FTP_WEIRD_SERVER_REPLY",
25
+ 9 => "CURLE_REMOTE_ACCESS_DENIED",
26
+ 10 => "CURLE_FTP_ACCEPT_FAILED",
27
+ 11 => "CURLE_FTP_WEIRD_PASS_REPLY",
28
+ 12 => "CURLE_FTP_ACCEPT_TIMEOUT",
29
+ 13 => "CURLE_FTP_WEIRD_PASV_REPLY",
30
+ 14 => "CURLE_FTP_WEIRD_227_FORMAT",
31
+ 15 => "CURLE_FTP_CANT_GET_HOST",
32
+ 17 => "CURLE_FTP_COULDNT_SET_TYPE",
33
+ 18 => "CURLE_PARTIAL_FILE",
34
+ 19 => "CURLE_FTP_COULDNT_RETR_FILE",
35
+ 21 => "CURLE_QUOTE_ERROR",
36
+ 22 => "CURLE_HTTP_RETURNED_ERROR",
37
+ 23 => "CURLE_WRITE_ERROR",
38
+ 25 => "CURLE_UPLOAD_FAILED",
39
+ 26 => "CURLE_READ_ERROR",
40
+ 27 => "CURLE_OUT_OF_MEMORY",
41
+ 28 => "CURLE_OPERATION_TIMEDOUT",
42
+ 30 => "CURLE_FTP_PORT_FAILED",
43
+ 31 => "CURLE_FTP_COULDNT_USE_REST",
44
+ 33 => "CURLE_RANGE_ERROR",
45
+ 34 => "CURLE_HTTP_POST_ERROR",
46
+ 35 => "CURLE_SSL_CONNECT_ERROR",
47
+ 36 => "CURLE_BAD_DOWNLOAD_RESUME",
48
+ 37 => "CURLE_FILE_COULDNT_READ_FILE",
49
+ 38 => "CURLE_LDAP_CANNOT_BIND",
50
+ 39 => "CURLE_LDAP_SEARCH_FAILED",
51
+ 41 => "CURLE_FUNCTION_NOT_FOUND",
52
+ 42 => "CURLE_ABORTED_BY_CALLBACK",
53
+ 43 => "CURLE_BAD_FUNCTION_ARGUMENT",
54
+ 45 => "CURLE_INTERFACE_FAILED",
55
+ 47 => "CURLE_TOO_MANY_REDIRECTS",
56
+ 48 => "CURLE_UNKNOWN_OPTION",
57
+ 49 => "CURLE_TELNET_OPTION_SYNTAX",
58
+ 51 => "CURLE_PEER_FAILED_VERIFICATION",
59
+ 52 => "CURLE_GOT_NOTHING",
60
+ 53 => "CURLE_SSL_ENGINE_NOTFOUND",
61
+ 54 => "CURLE_SSL_ENGINE_SETFAILED",
62
+ 55 => "CURLE_SEND_ERROR",
63
+ 56 => "CURLE_RECV_ERROR",
64
+ 58 => "CURLE_SSL_CERTPROBLEM",
65
+ 59 => "CURLE_SSL_CIPHER",
66
+ 60 => "CURLE_SSL_CACERT",
67
+ 61 => "CURLE_BAD_CONTENT_ENCODING",
68
+ 62 => "CURLE_LDAP_INVALID_URL",
69
+ 63 => "CURLE_FILESIZE_EXCEEDED",
70
+ 64 => "CURLE_USE_SSL_FAILED",
71
+ 65 => "CURLE_SEND_FAIL_REWIND",
72
+ 66 => "CURLE_SSL_ENGINE_INITFAILED",
73
+ 67 => "CURLE_LOGIN_DENIED",
74
+ 68 => "CURLE_TFTP_NOTFOUND",
75
+ 69 => "CURLE_TFTP_PERM",
76
+ 70 => "CURLE_REMOTE_DISK_FULL",
77
+ 71 => "CURLE_TFTP_ILLEGAL",
78
+ 72 => "CURLE_TFTP_UNKNOWNID",
79
+ 73 => "CURLE_REMOTE_FILE_EXISTS",
80
+ 74 => "CURLE_TFTP_NOSUCHUSER",
81
+ 75 => "CURLE_CONV_FAILED",
82
+ 76 => "CURLE_CONV_REQD",
83
+ 77 => "CURLE_SSL_CACERT_BADFILE",
84
+ 78 => "CURLE_REMOTE_FILE_NOT_FOUND",
85
+ 79 => "CURLE_SSH",
86
+ 80 => "CURLE_SSL_SHUTDOWN_FAILED",
87
+ 81 => "CURLE_AGAIN",
88
+ 82 => "CURLE_SSL_CRL_BADFILE",
89
+ 83 => "CURLE_SSL_ISSUER_ERROR",
90
+ 84 => "CURLE_FTP_PRET_FAILED",
91
+ 85 => "CURLE_RTSP_CSEQ_ERROR",
92
+ 86 => "CURLE_RTSP_SESSION_ERROR",
93
+ 87 => "CURLE_FTP_BAD_FILE_LIST",
94
+ 88 => "CURLE_CHUNK_FAILED",
95
+ );
96
+
97
+ // Define constants in the same order as the official PHP cURL extension with the same integer values.
98
+ // Additional defines exist in some locations because they will likely be defined in a future version of PHP.
99
+ // DO NOT rely on these constants existing in the official PHP extension!
100
+
101
+ // Constants for curl_setopt().
102
+ define("CURLOPT_IPRESOLVE", 113);
103
+ define("CURL_IPRESOLVE_WHATEVER", 0);
104
+ define("CURL_IPRESOLVE_V4", 1);
105
+ define("CURL_IPRESOLVE_V6", 2);
106
+ define("CURLOPT_DNS_USE_GLOBAL_CACHE", 91); // DEPRECATED, do not use!
107
+ define("CURLOPT_DNS_CACHE_TIMEOUT", 92);
108
+ define("CURLOPT_PORT", 3);
109
+ define("CURLOPT_FILE", 10001);
110
+ define("CURLOPT_READDATA", 10009);
111
+ define("CURLOPT_INFILE", 10009);
112
+ define("CURLOPT_INFILESIZE", 14);
113
+ define("CURLOPT_URL", 10002);
114
+ define("CURLOPT_PROXY", 10004);
115
+ define("CURLOPT_VERBOSE", 41);
116
+ define("CURLOPT_HEADER", 42);
117
+ define("CURLOPT_HTTPHEADER", 10023);
118
+ define("CURLOPT_NOPROGRESS", 43);
119
+ define("CURLOPT_PROGRESSFUNCTION", 20056);
120
+ define("CURLOPT_NOBODY", 44);
121
+ define("CURLOPT_FAILONERROR", 45);
122
+ define("CURLOPT_UPLOAD", 46);
123
+ define("CURLOPT_POST", 47);
124
+ define("CURLOPT_FTPLISTONLY", 48);
125
+ define("CURLOPT_FTPAPPEND", 50);
126
+ define("CURLOPT_NETRC", 51);
127
+ define("CURLOPT_FOLLOWLOCATION", 52);
128
+ define("CURLOPT_PUT", 54);
129
+ define("CURLOPT_USERPWD", 10005);
130
+ define("CURLOPT_PROXYUSERPWD", 10006);
131
+ define("CURLOPT_RANGE", 10007);
132
+ define("CURLOPT_TIMEOUT", 13);
133
+ define("CURLOPT_TIMEOUT_MS", 155);
134
+ define("CURLOPT_POSTFIELDS", 10015);
135
+ define("CURLOPT_REFERER", 10016);
136
+ define("CURLOPT_USERAGENT", 10018);
137
+ define("CURLOPT_FTPPORT", 10017);
138
+ define("CURLOPT_FTP_USE_EPSV", 85);
139
+ define("CURLOPT_LOW_SPEED_LIMIT", 19);
140
+ define("CURLOPT_LOW_SPEED_TIME", 20);
141
+ define("CURLOPT_RESUME_FROM", 21);
142
+ define("CURLOPT_COOKIE", 10022);
143
+ define("CURLOPT_COOKIESESSION", 96);
144
+ define("CURLOPT_AUTOREFERER", 58);
145
+ define("CURLOPT_SSLCERT", 10025);
146
+ define("CURLOPT_SSLCERTPASSWD", 10026);
147
+ define("CURLOPT_WRITEHEADER", 10029);
148
+ define("CURLOPT_SSL_VERIFYHOST", 81);
149
+ define("CURLOPT_COOKIEFILE", 10031);
150
+ define("CURLOPT_SSLVERSION", 32);
151
+ define("CURLOPT_TIMECONDITION", 33);
152
+ define("CURLOPT_TIMEVALUE", 34);
153
+ define("CURLOPT_CUSTOMREQUEST", 10036);
154
+ define("CURLOPT_STDERR", 10037);
155
+ define("CURLOPT_TRANSFERTEXT", 53);
156
+ define("CURLOPT_RETURNTRANSFER", 19913);
157
+ define("CURLOPT_QUOTE", 10028);
158
+ define("CURLOPT_POSTQUOTE", 10039);
159
+ define("CURLOPT_INTERFACE", 10062);
160
+ define("CURLOPT_KRB4LEVEL", 10063);
161
+ define("CURLOPT_HTTPPROXYTUNNEL", 61);
162
+ define("CURLOPT_FILETIME", 69);
163
+ define("CURLOPT_WRITEFUNCTION", 20011);
164
+ define("CURLOPT_READFUNCTION", 20012);
165
+ define("CURLOPT_HEADERFUNCTION", 20079);
166
+ define("CURLOPT_MAXREDIRS", 68);
167
+ define("CURLOPT_MAXCONNECTS", 71);
168
+ define("CURLOPT_CLOSEPOLICY", 72);
169
+ define("CURLOPT_FRESH_CONNECT", 74);
170
+ define("CURLOPT_FORBID_REUSE", 75);
171
+ define("CURLOPT_RANDOM_FILE", 10076);
172
+ define("CURLOPT_EGDSOCKET", 10077);
173
+ define("CURLOPT_CONNECTTIMEOUT", 78);
174
+ define("CURLOPT_CONNECTTIMEOUT_MS", 156);
175
+ define("CURLOPT_SSL_VERIFYPEER", 64);
176
+ define("CURLOPT_CAINFO", 10065);
177
+ define("CURLOPT_CAPATH", 10097);
178
+ define("CURLOPT_COOKIEJAR", 10082);
179
+ define("CURLOPT_SSL_CIPHER_LIST", 10083);
180
+ define("CURLOPT_BINARYTRANSFER", 19914);
181
+ define("CURLOPT_NOSIGNAL", 99);
182
+ define("CURLOPT_PROXYTYPE", 101);
183
+ define("CURLOPT_BUFFERSIZE", 98);
184
+ define("CURLOPT_HTTPGET", 80);
185
+ define("CURLOPT_HTTP_VERSION", 84);
186
+ define("CURLOPT_SSLKEY", 10087);
187
+ define("CURLOPT_SSLKEYTYPE", 10088);
188
+ define("CURLOPT_SSLKEYPASSWD", 10026);
189
+ define("CURLOPT_SSLENGINE", 10089);
190
+ define("CURLOPT_SSLENGINE_DEFAULT", 90);
191
+ define("CURLOPT_SSLCERTTYPE", 10086);
192
+ define("CURLOPT_CRLF", 27);
193
+ define("CURLOPT_ENCODING", 10102);
194
+ define("CURLOPT_PROXYPORT", 59);
195
+ define("CURLOPT_UNRESTRICTED_AUTH", 105);
196
+ define("CURLOPT_FTP_USE_EPRT", 106);
197
+ define("CURLOPT_TCP_NODELAY", 121);
198
+ define("CURLOPT_HTTP200ALIASES", 10104);
199
+ define("CURL_TIMECOND_NONE", 0);
200
+ define("CURL_TIMECOND_IFMODSINCE", 1);
201
+ define("CURL_TIMECOND_IFUNMODSINCE", 2);
202
+ define("CURL_TIMECOND_LASTMOD", 3);
203
+ define("CURLOPT_MAX_RECV_SPEED_LARGE", 30146);
204
+ define("CURLOPT_MAX_SEND_SPEED_LARGE", 30145);
205
+ define("CURLOPT_HTTPAUTH", 107);
206
+ define("CURLAUTH_NONE", 0);
207
+ define("CURLAUTH_BASIC", 1);
208
+ define("CURLAUTH_DIGEST", 2);
209
+ define("CURLAUTH_GSSNEGOTIATE", 4);
210
+ define("CURLAUTH_NTLM", 8);
211
+ define("CURLAUTH_DIGEST_IE", 16);
212
+ define("CURLAUTH_NTLM_WB", 32);
213
+ define("CURLAUTH_ANY", -17);
214
+ define("CURLAUTH_ANYSAFE", -18);
215
+ define("CURLOPT_PROXYAUTH", 111);
216
+ define("CURLOPT_FTP_CREATE_MISSING_DIRS", 110);
217
+ define("CURLOPT_PRIVATE", 10103);
218
+
219
+ // Constants effecting the way CURLOPT_CLOSEPOLICY works.
220
+ define("CURLCLOSEPOLICY_LEAST_RECENTLY_USED", 2);
221
+ define("CURLCLOSEPOLICY_LEAST_TRAFFIC", 3);
222
+ define("CURLCLOSEPOLICY_SLOWEST", 4);
223
+ define("CURLCLOSEPOLICY_CALLBACK", 5);
224
+ define("CURLCLOSEPOLICY_OLDEST", 1);
225
+
226
+ // Info constants.
227
+ define("CURLINFO_EFFECTIVE_URL", 0x100000 + 1);
228
+ define("CURLINFO_HTTP_CODE", 0x200000 + 2);
229
+ define("CURLINFO_RESPONSE_CODE", 0x200000 + 2);
230
+ define("CURLINFO_HEADER_SIZE", 0x200000 + 11);
231
+ define("CURLINFO_REQUEST_SIZE", 0x200000 + 12);
232
+ define("CURLINFO_TOTAL_TIME", 0x300000 + 3);
233
+ define("CURLINFO_NAMELOOKUP_TIME", 0x300000 + 4);
234
+ define("CURLINFO_CONNECT_TIME", 0x300000 + 5);
235
+ define("CURLINFO_PRETRANSFER_TIME", 0x300000 + 6);
236
+ define("CURLINFO_SIZE_UPLOAD", 0x300000 + 7);
237
+ define("CURLINFO_SIZE_DOWNLOAD", 0x300000 + 8);
238
+ define("CURLINFO_SPEED_DOWNLOAD", 0x300000 + 9);
239
+ define("CURLINFO_SPEED_UPLOAD", 0x300000 + 10);
240
+ define("CURLINFO_FILETIME", 0x200000 + 14);
241
+ define("CURLINFO_SSL_VERIFYRESULT", 0x200000 + 14);
242
+ define("CURLINFO_CONTENT_LENGTH_DOWNLOAD", 0x300000 + 15);
243
+ define("CURLINFO_CONTENT_LENGTH_UPLOAD", 0x300000 + 16);
244
+ define("CURLINFO_STARTTRANSFER_TIME", 0x300000 + 17);
245
+ define("CURLINFO_CONTENT_TYPE", 0x100000 + 18);
246
+ define("CURLINFO_REDIRECT_TIME", 0x300000 + 19);
247
+ define("CURLINFO_REDIRECT_COUNT", 0x200000 + 20);
248
+ define("CURLINFO_HEADER_OUT", 2);
249
+ define("CURLINFO_PRIVATE", 0x100000 + 21);
250
+ define("CURLINFO_CERTINFO", 0x400000 + 34);
251
+ define("CURLINFO_REDIRECT_URL", 0x100000 + 31);
252
+
253
+ // cURL compile-time constants (curl_version).
254
+ define("CURL_VERSION_IPV6", 1);
255
+ define("CURL_VERSION_KERBEROS4", 2);
256
+ define("CURL_VERSION_SSL", 4);
257
+ define("CURL_VERSION_LIBZ", 8);
258
+ define("CURL_VERSION_NTLM", 16);
259
+ define("CURL_VERSION_GSSNEGOTIATE", 32);
260
+ define("CURL_VERSION_DEBUG", 64);
261
+ define("CURL_VERSION_ASYNCHDNS", 128);
262
+ define("CURL_VERSION_SPNEGO", 256);
263
+ define("CURL_VERSION_LARGEFILE", 512);
264
+ define("CURL_VERSION_IDN", 1024);
265
+ define("CURL_VERSION_SSPI", 2048);
266
+ define("CURL_VERSION_CONV", 4096);
267
+ define("CURL_VERSION_CURLDEBUG", 8192);
268
+ define("CURL_VERSION_TLSAUTH_SRP", 16384);
269
+ define("CURL_VERSION_NTLM_WB", 32768);
270
+
271
+ // Version constants.
272
+ define("CURLVERSION_NOW", 3);
273
+
274
+ // Error constants.
275
+ foreach ($curl_error__map as $num => $name)
276
+ {
277
+ if (!defined($name)) define($name, $num);
278
+ }
279
+
280
+ // Dear PHP devs: Comment your code. Thanks.
281
+ define("CURLPROXY_HTTP", 0);
282
+ define("CURLPROXY_HTTP_1_0", 1);
283
+ define("CURLPROXY_SOCKS4", 4);
284
+ define("CURLPROXY_SOCKS5", 5);
285
+ define("CURLPROXY_SOCKS4A", 6);
286
+ define("CURLPROXY_SOCKS5_HOSTNAME", 7);
287
+
288
+ define("CURL_NETRC_OPTIONAL", 1);
289
+ define("CURL_NETRC_IGNORED", 0);
290
+ define("CURL_NETRC_REQUIRED", 2);
291
+
292
+ define("CURL_HTTP_VERSION_NONE", 0);
293
+ define("CURL_HTTP_VERSION_1_0", 1);
294
+ define("CURL_HTTP_VERSION_1_1", 2);
295
+
296
+ define("CURLM_CALL_MULTI_PERFORM", -1);
297
+ define("CURLM_OK", 0);
298
+ define("CURLM_BAD_HANDLE", 1);
299
+ define("CURLM_BAD_EASY_HANDLE", 2);
300
+ define("CURLM_OUT_OF_MEMORY", 3);
301
+ define("CURLM_INTERNAL_ERROR", 4);
302
+ define("CURLM_BAD_SOCKET", 5);
303
+ define("CURLM_UNKNOWN_OPTION", 6);
304
+
305
+ define("CURLMSG_DONE", 1);
306
+
307
+ define("CURLOPT_FTPSSLAUTH", 129);
308
+ define("CURLFTPAUTH_DEFAULT", 0);
309
+ define("CURLFTPAUTH_SSL", 1);
310
+ define("CURLFTPAUTH_TLS", 2);
311
+ define("CURLOPT_FTP_SSL", 119);
312
+ define("CURLFTPSSL_NONE", 0);
313
+ define("CURLFTPSSL_TRY", 1);
314
+ define("CURLFTPSSL_CONTROL", 2);
315
+ define("CURLFTPSSL_ALL", 3);
316
+ define("CURLUSESSL_NONE", 0);
317
+ define("CURLUSESSL_TRY", 1);
318
+ define("CURLUSESSL_CONTROL", 2);
319
+ define("CURLUSESSL_ALL", 3);
320
+
321
+ define("CURLOPT_CERTINFO", 172);
322
+ define("CURLOPT_POSTREDIR", 161);
323
+
324
+ define("CURLSSH_AUTH_ANY", -1);
325
+ define("CURLSSH_AUTH_NONE", 0);
326
+ define("CURLSSH_AUTH_PUBLICKEY", 1);
327
+ define("CURLSSH_AUTH_PASSWORD", 2);
328
+ define("CURLSSH_AUTH_HOST", 4);
329
+ define("CURLSSH_AUTH_KEYBOARD", 8);
330
+ define("CURLSSH_AUTH_DEFAULT", -1);
331
+ define("CURLOPT_SSH_AUTH_TYPES", 151);
332
+ define("CURLOPT_KEYPASSWD", 10026);
333
+ define("CURLOPT_SSH_PUBLIC_KEYFILE", 10152);
334
+ define("CURLOPT_SSH_PRIVATE_KEYFILE", 10153);
335
+ define("CURLOPT_SSH_HOST_PUBLIC_KEY_MD5", 10162);
336
+
337
+ define("CURLOPT_REDIR_PROTOCOLS", 182);
338
+ define("CURLOPT_PROTOCOLS", 181);
339
+ define("CURLPROTO_HTTP", 1);
340
+ define("CURLPROTO_HTTPS", 2);
341
+ define("CURLPROTO_FTP", 4);
342
+ define("CURLPROTO_FTPS", 8);
343
+ define("CURLPROTO_SCP", 16);
344
+ define("CURLPROTO_SFTP", 32);
345
+ define("CURLPROTO_TELNET", 64);
346
+ define("CURLPROTO_LDAP", 128);
347
+ define("CURLPROTO_LDAPS", 256);
348
+ define("CURLPROTO_DICT", 512);
349
+ define("CURLPROTO_FILE", 1024);
350
+ define("CURLPROTO_TFTP", 2048);
351
+ define("CURLPROTO_ALL", -1);
352
+
353
+ define("CURLOPT_FTP_FILEMETHOD", 138);
354
+ define("CURLOPT_FTP_SKIP_PASV_IP", 137);
355
+
356
+ define("CURLFTPMETHOD_DEFAULT", 0);
357
+ define("CURLFTPMETHOD_MULTICWD", 1);
358
+ define("CURLFTPMETHOD_NOCWD", 2);
359
+ define("CURLFTPMETHOD_SINGLECWD", 3);
360
+
361
+ // Emulation internal use ONLY. DO NOT USE!
362
+ define("CURLOPT_DEBUGFUNCTION", 20094);
363
+ define("CURLOPT_DEBUGDATA", 10095);
364
+
365
+ // Internal functions used by the public emulation routines.
366
+ $curl_init__map = array();
367
+ function get_curl_init_key($ch)
368
+ {
369
+ ob_start();
370
+ echo $ch;
371
+ ob_end_clean();
372
+
373
+ return ob_get_contents();
374
+ }
375
+
376
+ function get_check_curl_init_key($ch)
377
+ {
378
+ global $curl_init__map;
379
+
380
+ $key = get_curl_init_key($ch);
381
+ if (!isset($curl_init__map[$key])) throw new Exception(HTTP::HTTPTranslate("cURL Emulator: Unable to find key mapping for resource."));
382
+
383
+ return $key;
384
+ }
385
+
386
+ // Public emulation functions.
387
+ function curl_version($age = CURLVERSION_NOW)
388
+ {
389
+ $curlversion = "7.25.0";
390
+ $curlvernum = explode(".", $curlversion);
391
+
392
+ $result = array(
393
+ "version_number" => (($curlvernum[0] << 16) | ($curlvernum[1] << 8) | $curlvernum[2]),
394
+ "age" => $age,
395
+ "features" => CURL_VERSION_IPV6 | (defined("OPENSSL_VERSION_TEXT") ? CURL_VERSION_SSL : 0) | CURL_VERSION_DEBUG | CURL_VERSION_CURLDEBUG | CURL_VERSION_LARGEFILE | CURL_VERSION_IDN | CURL_VERSION_CONV,
396
+ "ssl_version_number" => 0,
397
+ "version" => $curlversion,
398
+ "host" => "i386-pc-win32",
399
+ "ssl_version" => (defined("OPENSSL_VERSION_TEXT") ? implode("/", array_slice(explode(" ", OPENSSL_VERSION_TEXT), 0, 2)) : ""),
400
+ "libz_version" => "",
401
+ "protocols" => array("http", "https")
402
+ );
403
+
404
+ return $result;
405
+ }
406
+
407
+ function curl_init($url = false)
408
+ {
409
+ global $curl_init__map;
410
+
411
+ // Evil hack to create a "resource" so that is_resource() works.
412
+ // get_resource_type() will reveal its true identity but only an idiot would ever call that function.
413
+ $ch = fopen(__FILE__, "rb");
414
+ $key = get_curl_init_key($ch);
415
+ $options = array(
416
+ CURLOPT_NOPROGRESS => true,
417
+ CURLOPT_VERBOSE => false,
418
+ CURLOPT_DNS_USE_GLOBAL_CACHE => true,
419
+ CURLOPT_DNS_CACHE_TIMEOUT => 120,
420
+ CURLOPT_MAXREDIRS => 20,
421
+ CURLOPT_URL => $url
422
+ );
423
+
424
+ if (!class_exists("WebBrowser", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/web_browser.php";
425
+
426
+ $curl_init__map[$key] = array("self" => $ch, "method" => "GET", "options" => $options, "browser" => new WebBrowser(), "errorno" => CURLE_OK, "errorinfo" => "");
427
+
428
+ return $ch;
429
+ }
430
+
431
+ function curl_errno($ch)
432
+ {
433
+ global $curl_init__map;
434
+
435
+ $key = get_check_curl_init_key($ch);
436
+
437
+ return $curl_init__map[$key]["errorno"];
438
+ }
439
+
440
+ function curl_error($ch)
441
+ {
442
+ global $curl_init__map;
443
+
444
+ $key = get_check_curl_init_key($ch);
445
+
446
+ return ($curl_init__map[$key]["errorinfo"] == "" ? "" : $curl_error__map[$curl_init__map[$key]["errorno"]] . " - " . $curl_init__map[$key]["errorinfo"]);
447
+ }
448
+
449
+ function curl_copy_handle($ch)
450
+ {
451
+ global $curl_init__map;
452
+
453
+ $key = get_check_curl_init_key($ch);
454
+
455
+ $ch = fopen(__FILE__, "rb");
456
+ $key2 = get_curl_init_key($resource);
457
+ $curl_init__map[$key2] = $curl_init__map[$key];
458
+
459
+ return $ch;
460
+ }
461
+
462
+ function curl_close($ch)
463
+ {
464
+ global $curl_init__map;
465
+
466
+ $key = get_check_curl_init_key($ch);
467
+ unset($curl_init__map[$key]);
468
+ fclose($ch);
469
+ }
470
+
471
+ function curl_setopt($ch, $option, $value)
472
+ {
473
+ global $curl_init__map;
474
+
475
+ $key = get_check_curl_init_key($ch);
476
+
477
+ if ($option != CURLINFO_HEADER_OUT)
478
+ {
479
+ if ($value === null) unset($curl_init__map[$key]["options"][$option]);
480
+ else
481
+ {
482
+ if ($option == CURLOPT_HTTPGET && $value) $curl_init__map[$key]["method"] = "GET";
483
+ else if ($option == CURLOPT_NOBODY && $value) $curl_init__map[$key]["method"] = "HEAD";
484
+ else if ($option == CURLOPT_POST && $value) $curl_init__map[$key]["method"] = "POST";
485
+ else if ($option == CURLOPT_PUT && $value) $curl_init__map[$key]["method"] = "PUT";
486
+ else if ($option == CURLOPT_CUSTOMREQUEST) $curl_init__map[$key]["method"] = $value;
487
+
488
+ $curl_init__map[$key]["options"][$option] = $value;
489
+ }
490
+ }
491
+ else if ((bool)$value)
492
+ {
493
+ $curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"] = true;
494
+ }
495
+ else
496
+ {
497
+ unset($curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"]);
498
+ }
499
+
500
+ $curl_init__map[$key]["errorno"] = CURLE_OK;
501
+ $curl_init__map[$key]["errorinfo"] = "";
502
+
503
+ return true;
504
+ }
505
+
506
+ function curl_setopt_array($ch, $options)
507
+ {
508
+ foreach ($options as $option => $value)
509
+ {
510
+ if (!curl_setopt($ch, $option, $value)) return false;
511
+ }
512
+
513
+ return true;
514
+ }
515
+
516
+ function curl_exec($ch)
517
+ {
518
+ global $curl_init__map;
519
+
520
+ $key = get_check_curl_init_key($ch);
521
+
522
+ // Set allowed protocols.
523
+ $allowedprotocols = array("http" => true, "https" => true);
524
+ if (isset($curl_init__map[$key]["options"][CURLOPT_PROTOCOLS]))
525
+ {
526
+ $allowedprotocols["http"] = (bool)($curl_init__map[$key]["options"][CURLOPT_PROTOCOLS] & CURLPROTO_HTTP);
527
+ $allowedprotocols["https"] = (bool)($curl_init__map[$key]["options"][CURLOPT_PROTOCOLS] & CURLPROTO_HTTPS);
528
+ }
529
+ $curl_init__map[$key]["browser"]->SetState(array("allowedprotocols" => $allowedprotocols));
530
+
531
+ // Set allowed redirect protocols.
532
+ $allowedprotocols = array("http" => true, "https" => true);
533
+ if (isset($curl_init__map[$key]["options"][CURLOPT_REDIR_PROTOCOLS]))
534
+ {
535
+ $allowedprotocols["http"] = (bool)($curl_init__map[$key]["options"][CURLOPT_REDIR_PROTOCOLS] & CURLPROTO_HTTP);
536
+ $allowedprotocols["https"] = (bool)($curl_init__map[$key]["options"][CURLOPT_REDIR_PROTOCOLS] & CURLPROTO_HTTPS);
537
+ }
538
+ $curl_init__map[$key]["browser"]->SetState(array("allowedredirprotocols" => $allowedprotocols));
539
+
540
+ // Load cookies. Violates the PHP/cURL definition a lot. Whatever.
541
+ if (isset($curl_init__map[$key]["options"][CURLOPT_COOKIEFILE]) && is_string($curl_init__map[$key]["options"][CURLOPT_COOKIEFILE]) && $curl_init__map[$key]["options"][CURLOPT_COOKIEFILE] != "")
542
+ {
543
+ $data = @unserialize(@file_get_contents($curl_init__map[$key]["options"][CURLOPT_COOKIEFILE]));
544
+ if ($data !== false && is_array($data))
545
+ {
546
+ // Load the WebBrowser() object with the cookies.
547
+ $curl_init__map[$key]["browser"]->SetState(array("cookies" => $data));
548
+ }
549
+ $curl_init__map[$key]["options"][CURLOPT_COOKIEFILE] = "";
550
+ }
551
+ if (isset($curl_init__map[$key]["options"][CURLOPT_COOKIESESSION]) && $curl_init__map[$key]["options"][CURLOPT_COOKIESESSION]) $curl_init__map[$key]["browser"]->DeleteSessionCookies();
552
+
553
+ // Set the autoreferer setting.
554
+ $curl_init__map[$key]["browser"]->SetState(array("autoreferer" => (isset($curl_init__map[$key]["options"][CURLOPT_AUTOREFERER]) && $curl_init__map[$key]["options"][CURLOPT_AUTOREFERER])));
555
+
556
+ // Set the Referer.
557
+ if (isset($curl_init__map[$key]["options"][CURLOPT_REFERER]) && is_string($curl_init__map[$key]["options"][CURLOPT_REFERER]))
558
+ {
559
+ $curl_init__map[$key]["browser"]->SetState(array("referer" => $curl_init__map[$key]["options"][CURLOPT_REFERER]));
560
+ }
561
+
562
+ // Set the followlocation and maxfollow settings.
563
+ $curl_init__map[$key]["browser"]->SetState(array("followlocation" => (isset($curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION]) && $curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION])));
564
+ $curl_init__map[$key]["browser"]->SetState(array("maxfollow" => (isset($curl_init__map[$key]["options"][CURLOPT_MAXREDIRS]) ? $curl_init__map[$key]["options"][CURLOPT_MAXREDIRS] : 20)));
565
+
566
+ // Set up the options array.
567
+ $options = array();
568
+
569
+ // Set connect and total timeout options.
570
+ if (isset($curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT]) || isset($curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT_MS]))
571
+ {
572
+ $timeout = (isset($curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT]) ? $curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT] : 0) + ((isset($curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT_MS]) ? $curl_init__map[$key]["options"][CURLOPT_CONNECTTIMEOUT_MS] : 0) / 1000);
573
+ if ($timeout > 0)
574
+ {
575
+ $options["connecttimeout"] = $timeout;
576
+ $options["proxyconnecttimeout"] = $timeout;
577
+ }
578
+ }
579
+ if (isset($curl_init__map[$key]["options"][CURLOPT_TIMEOUT]) || isset($curl_init__map[$key]["options"][CURLOPT_TIMEOUT_MS]))
580
+ {
581
+ $timeout = (isset($curl_init__map[$key]["options"][CURLOPT_TIMEOUT]) ? $curl_init__map[$key]["options"][CURLOPT_TIMEOUT] : 0) + ((isset($curl_init__map[$key]["options"][CURLOPT_TIMEOUT_MS]) ? $curl_init__map[$key]["options"][CURLOPT_TIMEOUT_MS] : 0) / 1000);
582
+ if ($timeout > 0)
583
+ {
584
+ $options["connecttimeout"] = $timeout;
585
+ $options["proxyconnecttimeout"] = $timeout;
586
+ }
587
+ }
588
+
589
+ // Set proxy options.
590
+ if (isset($curl_init__map[$key]["options"][CURLOPT_PROXY]))
591
+ {
592
+ if (isset($curl_init__map[$key]["options"][CURLOPT_PROXYTYPE]) && $curl_init__map[$key]["options"][CURLOPT_PROXYTYPE] != CURLPROXY_HTTP)
593
+ {
594
+ $curl_init__map[$key]["errorno"] = CURLE_UNSUPPORTED_PROTOCOL;
595
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_PROXYTYPE option is unsupported.");
596
+
597
+ return false;
598
+ }
599
+
600
+ $proxyurl = $curl_init__map[$key]["options"][CURLOPT_PROXY];
601
+ $proxyport = (int)(isset($curl_init__map[$key]["options"][CURLOPT_PROXYPORT]) ? $curl_init__map[$key]["options"][CURLOPT_PROXYPORT] : false);
602
+ if ($proxyport < 1 || $proxyport > 65535) $proxyport = false;
603
+ if (strpos($proxyurl, "://") === false) $proxyurl = ($proxyport == 443 ? "https://" : "http://") . $proxyurl;
604
+
605
+ $proxyurl = HTTP::ExtractURL($proxyurl);
606
+ if ($proxyport !== false) $proxyurl["port"] = $proxyport;
607
+ if (isset($curl_init__map[$key]["options"][CURLOPT_PROXYUSERPWD]))
608
+ {
609
+ $userpass = explode(":", $curl_init__map[$key]["options"][CURLOPT_PROXYUSERPWD]);
610
+ if (count($userpass) == 2)
611
+ {
612
+ $proxyurl["loginusername"] = urldecode($userpass[0]);
613
+ $proxyurl["loginpassword"] = urldecode($userpass[1]);
614
+ }
615
+ }
616
+ $options["proxyurl"] = HTTP::CondenseURL($proxyurl);
617
+
618
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HTTPPROXYTUNNEL])) $options["proxyconnect"] = $curl_init__map[$key]["options"][CURLOPT_HTTPPROXYTUNNEL];
619
+ }
620
+
621
+ // Set SSL options.
622
+ $options["sslopts"] = array();
623
+ $options["sslopts"]["verify_peer"] = (isset($curl_init__map[$key]["options"][CURLOPT_SSL_VERIFYPEER]) ? $curl_init__map[$key]["options"][CURLOPT_SSL_VERIFYPEER] : true);
624
+ if (isset($curl_init__map[$key]["options"][CURLOPT_CAINFO])) $options["sslopts"]["cafile"] = $curl_init__map[$key]["options"][CURLOPT_CAINFO];
625
+ if (isset($curl_init__map[$key]["options"][CURLOPT_CAPATH])) $options["sslopts"]["capath"] = $curl_init__map[$key]["options"][CURLOPT_CAPATH];
626
+ if (!isset($options["sslopts"]["cafile"]) && !isset($options["sslopts"]["capath"])) $options["sslopts"]["auto_cainfo"] = true;
627
+ if (isset($curl_init__map[$key]["options"][CURLOPT_SSLCERT]) && isset($curl_init__map[$key]["options"][CURLOPT_SSLKEY]))
628
+ {
629
+ if ($curl_init__map[$key]["options"][CURLOPT_SSLCERT] !== $curl_init__map[$key]["options"][CURLOPT_SSLKEY])
630
+ {
631
+ $curl_init__map[$key]["errorno"] = CURLE_SSL_CONNECT_ERROR;
632
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_SSLCERT and CURLOPT_SSLKEY must be identical.");
633
+
634
+ return false;
635
+ }
636
+ $certpass = (isset($curl_init__map[$key]["options"][CURLOPT_SSLCERTPASSWD]) ? $curl_init__map[$key]["options"][CURLOPT_SSLCERTPASSWD] : false);
637
+ $keypass = (isset($curl_init__map[$key]["options"][CURLOPT_SSLKEYPASSWD]) ? $curl_init__map[$key]["options"][CURLOPT_SSLKEYPASSWD] : false);
638
+ if ($certpass !== $keypass)
639
+ {
640
+ $curl_init__map[$key]["errorno"] = CURLE_SSL_CONNECT_ERROR;
641
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_SSLCERTPASSWD and CURLOPT_SSLKEYPASSWD must be identical.");
642
+
643
+ return false;
644
+ }
645
+ $certtype = strtoupper(isset($curl_init__map[$key]["options"][CURLOPT_SSLCERTTYPE]) ? $curl_init__map[$key]["options"][CURLOPT_SSLCERTTYPE] : "PEM");
646
+ $keytype = strtoupper(isset($curl_init__map[$key]["options"][CURLOPT_SSLKEYTYPE]) ? $curl_init__map[$key]["options"][CURLOPT_SSLKEYTYPE] : "PEM");
647
+ if ($certpass !== $keypass || $cert !== "PEM")
648
+ {
649
+ $curl_init__map[$key]["errorno"] = CURLE_SSL_CONNECT_ERROR;
650
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_SSLCERTTYPE and CURLOPT_SSLKEYTYPE must be PEM format.");
651
+
652
+ return false;
653
+ }
654
+
655
+ $options["sslopts"]["local_cert"] = $curl_init__map[$key]["options"][CURLOPT_SSLCERT];
656
+ if ($certpass !== false) $options["sslopts"]["passphrase"] = $certpass;
657
+ }
658
+ if (isset($curl_init__map[$key]["options"][CURLOPT_SSL_CIPHER_LIST])) $options["sslopts"]["ciphers"] = $curl_init__map[$key]["options"][CURLOPT_SSL_CIPHER_LIST];
659
+ $options["sslopts"]["auto_cn_match"] = true;
660
+ $options["sslopts"]["auto_sni"] = true;
661
+ $options["sslopts"]["capture_peer_cert"] = (isset($curl_init__map[$key]["options"][CURLOPT_CERTINFO]) ? $curl_init__map[$key]["options"][CURLOPT_CERTINFO] : false);
662
+
663
+ // Set the method.
664
+ if (isset($curl_init__map[$key]["options"][CURLOPT_UPLOAD]) && (bool)$curl_init__map[$key]["options"][CURLOPT_UPLOAD]) $options["method"] = "PUT";
665
+ else $options["method"] = $curl_init__map[$key]["method"];
666
+
667
+ // Set the HTTP version.
668
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HTTP_VERSION]))
669
+ {
670
+ if ($curl_init__map[$key]["options"][CURLOPT_HTTP_VERSION] == CURL_HTTP_VERSION_1_0) $options["httpver"] = "1.0";
671
+ else if ($curl_init__map[$key]["options"][CURLOPT_HTTP_VERSION] == CURL_HTTP_VERSION_1_1) $options["httpver"] = "1.1";
672
+ }
673
+
674
+ // Set rate limits.
675
+ if (isset($curl_init__map[$key]["options"][CURLOPT_MAX_RECV_SPEED_LARGE])) $options["recvratelimit"] = $curl_init__map[$key]["options"][CURLOPT_MAX_RECV_SPEED_LARGE];
676
+ if (isset($curl_init__map[$key]["options"][CURLOPT_MAX_SEND_SPEED_LARGE])) $options["sendratelimit"] = $curl_init__map[$key]["options"][CURLOPT_MAX_SEND_SPEED_LARGE];
677
+
678
+ // Set headers.
679
+ $options["headers"] = array();
680
+ $options["headers"]["Accept"] = "*/*";
681
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HTTPHEADER]) && is_array($curl_init__map[$key]["options"][CURLOPT_HTTPHEADER]))
682
+ {
683
+ foreach ($curl_init__map[$key]["options"][CURLOPT_HTTPHEADER] as $header)
684
+ {
685
+ $pos = strpos($header, ":");
686
+ if ($pos !== false)
687
+ {
688
+ $val = ltrim(substr($header, $pos + 1));
689
+ if ($val == "") unset($options["headers"][HTTP::HeaderNameCleanup(substr($header, 0, $pos))]);
690
+ else $options["headers"][HTTP::HeaderNameCleanup(substr($header, 0, $pos))] = $val;
691
+ }
692
+ }
693
+ }
694
+ if (isset($curl_init__map[$key]["options"][CURLOPT_USERAGENT])) $options["headers"]["User-Agent"] = $curl_init__map[$key]["options"][CURLOPT_USERAGENT];
695
+ if (isset($curl_init__map[$key]["options"][CURLOPT_COOKIE])) $options["headers"]["Cookie"] = $curl_init__map[$key]["options"][CURLOPT_COOKIE];
696
+ if (isset($curl_init__map[$key]["options"][CURLOPT_RANGE])) $options["headers"]["Range"] = "bytes=" . $curl_init__map[$key]["options"][CURLOPT_RANGE];
697
+ if (isset($curl_init__map[$key]["options"][CURLOPT_RESUME_FROM])) $options["headers"]["Range"] = "bytes=" . $curl_init__map[$key]["options"][CURLOPT_RESUME_FROM] . "-";
698
+ if (isset($curl_init__map[$key]["options"][CURLOPT_TIMECONDITION]) && isset($curl_init__map[$key]["options"][CURLOPT_TIMEVALUE]))
699
+ {
700
+ if ($curl_init__map[$key]["options"][CURLOPT_TIMECONDITION] == CURL_TIMECOND_IFMODSINCE) $options["headers"]["If-Modified-Since"] = gmdate("D, d M Y H:i:s", $curl_init__map[$key]["options"][CURLOPT_TIMEVALUE]) . " GMT";
701
+ else if ($curl_init__map[$key]["options"][CURLOPT_TIMECONDITION] == CURL_TIMECOND_IFUNMODSINCE) $options["headers"]["If-Unmodified-Since"] = gmdate("D, d M Y H:i:s", $curl_init__map[$key]["options"][CURLOPT_TIMEVALUE]) . " GMT";
702
+ }
703
+
704
+ // Set POST variables and files.
705
+ if (isset($curl_init__map[$key]["options"][CURLOPT_POSTFIELDS]))
706
+ {
707
+ $postvars = $curl_init__map[$key]["options"][CURLOPT_POSTFIELDS];
708
+ if (is_string($postvars))
709
+ {
710
+ $postvars2 = array();
711
+ $postvars = explode("&", $postvars);
712
+ foreach ($postvars as $postvar)
713
+ {
714
+ $pos = strpos($postvar, "=");
715
+ if ($pos === false)
716
+ {
717
+ $name = urldecode($postvar);
718
+ $val = "";
719
+ }
720
+ else
721
+ {
722
+ $name = urldecode(substr($postvar, 0, $pos));
723
+ $val = urldecode(substr($postvar, $pos + 1));
724
+ }
725
+
726
+ if (!isset($postvars2[$name])) $postvars2[$name] = array();
727
+ $postvars2[$name][] = $val;
728
+ }
729
+ $postvars = $postvars2;
730
+ unset($postvars2);
731
+ }
732
+
733
+ foreach ($postvars as $name => $vals)
734
+ {
735
+ if (is_string($vals) || is_numeric($vals)) $vals = array($vals);
736
+ foreach ($vals as $num => $val)
737
+ {
738
+ // Move files to their own array.
739
+ if (substr($val, 0, 1) == "@")
740
+ {
741
+ $pos = strrpos($val, ";type=");
742
+ if ($pos === false) $mimetype = "";
743
+ else
744
+ {
745
+ $mimetype = substr($val, $pos + 6);
746
+ $val = substr($val, 0, $pos);
747
+ }
748
+
749
+ $val = substr($val, 1);
750
+ if (file_exists($val))
751
+ {
752
+ if (!isset($options["files"])) $options["files"] = array();
753
+ $options["files"][] = array(
754
+ "name" => $name,
755
+ "filename" => HTTP::FilenameSafe(HTTP::ExtractFilename($val)),
756
+ "type" => $mimetype,
757
+ "datafile" => $val
758
+ );
759
+
760
+ unset($vals[$num]);
761
+ }
762
+ }
763
+ }
764
+
765
+ if (!count($vals)) unset($postvars[$name]);
766
+ else $postvars[$name] = $vals;
767
+ }
768
+
769
+ $options["postvars"] = $postvars;
770
+ $options["method"] = "POST";
771
+ }
772
+
773
+ // Process the URL.
774
+ if (!isset($curl_init__map[$key]["options"][CURLOPT_URL]) || !is_string($curl_init__map[$key]["options"][CURLOPT_URL]) || $curl_init__map[$key]["options"][CURLOPT_URL] == "")
775
+ {
776
+ $curl_init__map[$key]["errorno"] = CURLE_URL_MALFORMAT;
777
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("No CURLOPT_URL option specified.");
778
+
779
+ return false;
780
+ }
781
+ $url = HTTP::ExtractURL($curl_init__map[$key]["options"][CURLOPT_URL]);
782
+ if ($url["scheme"] == "")
783
+ {
784
+ $curl_init__map[$key]["errorno"] = CURLE_URL_MALFORMAT;
785
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_URL does not have a scheme.");
786
+
787
+ return false;
788
+ }
789
+ if ($url["host"] == "")
790
+ {
791
+ $curl_init__map[$key]["errorno"] = CURLE_URL_MALFORMAT;
792
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("CURLOPT_URL does not specify a valid host.");
793
+
794
+ return false;
795
+ }
796
+ if (isset($curl_init__map[$key]["options"][CURLOPT_PORT]) && (int)$curl_init__map[$key]["options"][CURLOPT_PORT] > 0 && (int)$curl_init__map[$key]["options"][CURLOPT_PORT] < 65536)
797
+ {
798
+ $url["port"] = (int)$curl_init__map[$key]["options"][CURLOPT_PORT];
799
+ }
800
+ if (isset($curl_init__map[$key]["options"][CURLOPT_USERPWD]))
801
+ {
802
+ $userpass = explode(":", $curl_init__map[$key]["options"][CURLOPT_USERPWD]);
803
+ if (count($userpass) == 2)
804
+ {
805
+ $url["loginusername"] = urldecode($userpass[0]);
806
+ $url["loginpassword"] = urldecode($userpass[1]);
807
+ }
808
+ }
809
+ else if (isset($curl_init__map[$key]["options"][CURLOPT_NETRC]) && $curl_init__map[$key]["options"][CURLOPT_NETRC])
810
+ {
811
+ $data = @file_get_contents("~/.netrc");
812
+ if ($data !== false)
813
+ {
814
+ $lines = explode("\n", $data);
815
+ unset($data);
816
+ $host = false;
817
+ $user = false;
818
+ $password = false;
819
+ foreach ($lines as $line)
820
+ {
821
+ $line = trim($line);
822
+ if (substr($line, 0, 8) == "machine ") $host = trim(substr($line, 8));
823
+ if (substr($line, 0, 6) == "login ") $user = trim(substr($line, 6));
824
+ if (substr($line, 0, 9) == "password ") $password = trim(substr($line, 9));
825
+
826
+ if ($host !== false && $user !== false && $password !== false)
827
+ {
828
+ if ($host === $url["host"] || (isset($options["headers"]["Host"]) && $host === $options["headers"]["Host"]))
829
+ {
830
+ $url["loginusername"] = $user;
831
+ $url["loginpassword"] = $password;
832
+ }
833
+
834
+ $host = false;
835
+ $user = false;
836
+ $password = false;
837
+ }
838
+ }
839
+ unset($lines);
840
+ }
841
+ }
842
+
843
+ // Condense URL.
844
+ $url = HTTP::CondenseURL($url);
845
+
846
+ // Set up internal callbacks.
847
+ $options["read_headers_callback"] = "internal_curl_read_headers_callback";
848
+ $options["read_headers_callback_opts"] = $key;
849
+
850
+ if (!isset($curl_init__map[$key]["options"][CURLOPT_NOBODY]) || !$curl_init__map[$key]["options"][CURLOPT_NOBODY])
851
+ {
852
+ $options["read_body_callback"] = "internal_curl_read_body_callback";
853
+ $options["read_body_callback_opts"] = $key;
854
+ }
855
+
856
+ if ($options["method"] != "GET" && $options["method"] != "POST")
857
+ {
858
+ $options["write_body_callback"] = "internal_curl_write_body_callback";
859
+ $options["write_body_callback_opts"] = $key;
860
+ }
861
+
862
+ $options["debug_callback"] = "internal_curl_debug_callback";
863
+ $options["debug_callback_opts"] = $key;
864
+
865
+ // Remove weird callback results.
866
+ unset($curl_init__map[$key]["rawproxyheaders"]);
867
+ unset($curl_init__map[$key]["rawheaders"]);
868
+ unset($curl_init__map[$key]["returnresponse"]);
869
+ unset($curl_init__map[$key]["returnheader"]);
870
+ unset($curl_init__map[$key]["returnbody"]);
871
+ unset($curl_init__map[$key]["filetime"]);
872
+ $curl_init__map[$key]["outputbody"] = false;
873
+
874
+ // Process the request.
875
+ $options["profile"] = "";
876
+ $result = $curl_init__map[$key]["browser"]->Process($url, $options);
877
+ $curl_init__map[$key]["lastresult"] = $result;
878
+
879
+ // Deal with cookies.
880
+ if (!isset($curl_init__map[$key]["options"][CURLOPT_COOKIEFILE]) || !is_string($curl_init__map[$key]["options"][CURLOPT_COOKIEFILE]))
881
+ {
882
+ // Delete all cookies for another run later.
883
+ $curl_init__map[$key]["browser"]->SetState(array("cookies" => array()));
884
+ }
885
+ else if (isset($curl_init__map[$key]["options"][CURLOPT_COOKIEJAR]))
886
+ {
887
+ // Write out cookies here. Another violation of how cURL does things. Another - whatever.
888
+ $state = $curl_init__map[$key]["browser"]->GetState();
889
+ file_put_contents($curl_init__map[$key]["options"][CURLOPT_COOKIEJAR], serialize($state["cookies"]));
890
+ }
891
+
892
+ // Process the response.
893
+ if (!$result["success"])
894
+ {
895
+ if ($result["errorcode"] == "allowed_protocols")
896
+ {
897
+ $curl_init__map[$key]["errorno"] = CURLE_UNSUPPORTED_PROTOCOL;
898
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The cURL emulation layer does not support the protocol or was redirected to an unsupported protocol by the host. %s", $result["error"]);
899
+ }
900
+ else if ($result["errorcode"] == "allowed_redir_protocols")
901
+ {
902
+ $curl_init__map[$key]["errorno"] = CURLE_UNSUPPORTED_PROTOCOL;
903
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The cURL emulation layer was redirected to an unsupported protocol by the host. %s", $result["error"]);
904
+ }
905
+ else if ($result["errorcode"] == "retrievewebpage")
906
+ {
907
+ if ($result["info"]["errorcode"] == "timeout_exceeded")
908
+ {
909
+ $curl_init__map[$key]["errorno"] = CURLE_OPERATION_TIMEDOUT;
910
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The operation timed out. %s", $result["error"]);
911
+ }
912
+ else if ($result["info"]["errorcode"] == "get_response_line")
913
+ {
914
+ $curl_init__map[$key]["errorno"] = CURLE_READ_ERROR;
915
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Unable to get the response line. %s", $result["error"]);
916
+ }
917
+ else if ($result["info"]["errorcode"] == "read_header_callback")
918
+ {
919
+ $curl_init__map[$key]["errorno"] = CURLE_READ_ERROR;
920
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A read error occurred in the read header callback. %s", $result["error"]);
921
+ }
922
+ else if ($result["info"]["errorcode"] == "read_body_callback")
923
+ {
924
+ $curl_init__map[$key]["errorno"] = CURLE_READ_ERROR;
925
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A read error occurred in the read body callback. %s", $result["error"]);
926
+ }
927
+ else if ($result["info"]["errorcode"] == "function_check")
928
+ {
929
+ $curl_init__map[$key]["errorno"] = CURLE_FUNCTION_NOT_FOUND;
930
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A required function was not found. %s", $result["error"]);
931
+ }
932
+ else if ($result["info"]["errorcode"] == "protocol_check")
933
+ {
934
+ $curl_init__map[$key]["errorno"] = CURLE_UNSUPPORTED_PROTOCOL;
935
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The cURL emulation layer does not support the protocol or was redirected to an unsupported protocol by the host. %s", $result["error"]);
936
+ }
937
+ else if ($result["info"]["errorcode"] == "transport_not_installed")
938
+ {
939
+ $curl_init__map[$key]["errorno"] = CURLE_NOT_BUILT_IN;
940
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The cURL emulation layer attempted to use a required transport to connect to a host but failed. %s", $result["error"]);
941
+ }
942
+ else if ($result["info"]["errorcode"] == "proxy_transport_not_installed")
943
+ {
944
+ $curl_init__map[$key]["errorno"] = CURLE_NOT_BUILT_IN;
945
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("The cURL emulation layer attempted to use a required transport to connect to a proxy but failed. %s", $result["error"]);
946
+ }
947
+ else if ($result["info"]["errorcode"] == "proxy_connect")
948
+ {
949
+ $curl_init__map[$key]["errorno"] = CURLE_COULDNT_CONNECT;
950
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Unable to connect to the proxy. %s", $result["error"]);
951
+ }
952
+ else if ($result["info"]["errorcode"] == "proxy_connect_tunnel")
953
+ {
954
+ $curl_init__map[$key]["errorno"] = CURLE_COULDNT_CONNECT;
955
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Unable to open a tunnel through the connected proxy. %s", $result["error"]);
956
+ }
957
+ else if ($result["info"]["errorcode"] == "connect_failed")
958
+ {
959
+ $curl_init__map[$key]["errorno"] = CURLE_COULDNT_CONNECT;
960
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Unable to connect to the host. %s", $result["error"]);
961
+ }
962
+ else if ($result["info"]["errorcode"] == "write_body_callback")
963
+ {
964
+ $curl_init__map[$key]["errorno"] = CURLE_WRITE_ERROR;
965
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A write error occurred in the write body callback. %s", $result["error"]);
966
+ }
967
+ else if ($result["info"]["errorcode"] == "file_open")
968
+ {
969
+ $curl_init__map[$key]["errorno"] = CURLE_FILE_COULDNT_READ_FILE;
970
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Unable to open file for upload. %s", $result["error"]);
971
+ }
972
+ else if ($result["info"]["errorcode"] == "file_read")
973
+ {
974
+ $curl_init__map[$key]["errorno"] = CURLE_READ_ERROR;
975
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A read error occurred while uploading a file. %s", $result["error"]);
976
+ }
977
+ else
978
+ {
979
+ $curl_init__map[$key]["errorno"] = CURLE_HTTP_RETURNED_ERROR;
980
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("An error occurred. %s", $result["error"]);
981
+ }
982
+ }
983
+
984
+ return false;
985
+ }
986
+
987
+ if (isset($curl_init__map[$key]["returnresponse"]) && $curl_init__map[$key]["returnresponse"]["code"] >= 400 && isset($curl_init__map[$key]["options"][CURLOPT_FAILONERROR]) && $curl_init__map[$key]["options"][CURLOPT_FAILONERROR])
988
+ {
989
+ $curl_init__map[$key]["errorno"] = CURLE_HTTP_RETURNED_ERROR;
990
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("A HTTP error occurred. %s", $curl_init__map[$key]["returnresponse"]["line"]);
991
+
992
+ return false;
993
+ }
994
+
995
+ if (isset($curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION]) && $curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION] && isset($result["headers"]["Location"]))
996
+ {
997
+ $curl_init__map[$key]["errorno"] = CURLE_TOO_MANY_REDIRECTS;
998
+ $curl_init__map[$key]["errorinfo"] = HTTP::HTTPTranslate("Too many redirects took place.");
999
+
1000
+ return false;
1001
+ }
1002
+
1003
+ if (isset($curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER]) && $curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER])
1004
+ {
1005
+ return (isset($curl_init__map[$key]["returnheader"]) ? $curl_init__map[$key]["returnheader"] . "\r\n" : "") . (isset($curl_init__map[$key]["returnbody"]) ? $curl_init__map[$key]["returnbody"] : "");
1006
+ }
1007
+
1008
+ return true;
1009
+ }
1010
+
1011
+ // Internal functions used by curl_exec().
1012
+ function internal_curl_debug_callback($type, $data, $key)
1013
+ {
1014
+ global $curl_init__map;
1015
+
1016
+ ob_start();
1017
+
1018
+ if ($type == "proxypeercert")
1019
+ {
1020
+ if (isset($curl_init__map[$key]["options"][CURLOPT_CERTINFO]) && $curl_init__map[$key]["options"][CURLOPT_CERTINFO])
1021
+ {
1022
+ echo HTTP::HTTPTranslate("Proxy SSL Certificate:\n");
1023
+ var_dump($data);
1024
+ echo "\n";
1025
+ }
1026
+ }
1027
+ else if ($type == "peercert")
1028
+ {
1029
+ if (isset($curl_init__map[$key]["options"][CURLOPT_CERTINFO]) && $curl_init__map[$key]["options"][CURLOPT_CERTINFO])
1030
+ {
1031
+ echo HTTP::HTTPTranslate("Peer SSL Certificate:\n");
1032
+ var_dump($data);
1033
+ echo "\n";
1034
+ }
1035
+ }
1036
+ else if ($type == "rawproxyheaders")
1037
+ {
1038
+ if (isset($curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"]) && $curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"])
1039
+ {
1040
+ $curl_init__map[$key]["rawproxyheaders"] = $data;
1041
+
1042
+ echo HTTP::HTTPTranslate("Raw Proxy Headers:\n");
1043
+ echo $data;
1044
+ }
1045
+ }
1046
+ else if ($type == "rawheaders")
1047
+ {
1048
+ if (isset($curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"]) && $curl_init__map[$key]["options"]["__CURLINFO_HEADER_OUT"])
1049
+ {
1050
+ $curl_init__map[$key]["rawheaders"] = $data;
1051
+
1052
+ echo HTTP::HTTPTranslate("Raw Headers:\n");
1053
+ echo $data;
1054
+ }
1055
+ }
1056
+ else if ($type == "rawsend")
1057
+ {
1058
+ echo HTTP::HTTPTranslate("Sent:\n");
1059
+ echo $data;
1060
+ }
1061
+ else if ($type == "rawrecv")
1062
+ {
1063
+ echo HTTP::HTTPTranslate("Received:\n");
1064
+ echo $data;
1065
+ echo "\n";
1066
+ }
1067
+
1068
+ $output = ob_get_contents();
1069
+ ob_end_clean();
1070
+
1071
+ if ($output !== "" && isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1072
+ {
1073
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], $output);
1074
+ else if (defined("STDERR")) fwrite(STDERR, $output);
1075
+ else echo $output;
1076
+ }
1077
+ }
1078
+
1079
+ function internal_curl_write_body_callback(&$body, &$bodysize, $key)
1080
+ {
1081
+ global $curl_init__map;
1082
+
1083
+ if (!$bodysize)
1084
+ {
1085
+ if (!isset($curl_init__map[$key]["options"][CURLOPT_INFILESIZE])) return false;
1086
+ $bodysize = $curl_init__map[$key]["options"][CURLOPT_INFILESIZE];
1087
+ }
1088
+ else if (isset($curl_init__map[$key]["options"][CURLOPT_READFUNCTION]))
1089
+ {
1090
+ $bodysize2 = ($bodysize > 32768 ? 32768 : $bodysize);
1091
+ $bodysize3 = $bodysize2;
1092
+ $body = $curl_init__map[$key]["options"][CURLOPT_READFUNCTION]($curl_init__map[$key]["self"], $curl_init__map[$key]["options"][CURLOPT_INFILE], $bodysize2);
1093
+ if ($bodysize3 < strlen($body))
1094
+ {
1095
+ if (isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1096
+ {
1097
+ $output = HTTP::HTTPTranslate("An error occurred in the read function callback while reading the data to send/upload to the host.");
1098
+
1099
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], $output);
1100
+ else if (defined("STDERR")) fwrite(STDERR, $output);
1101
+ else echo $output;
1102
+ }
1103
+
1104
+ return false;
1105
+ }
1106
+ }
1107
+ else
1108
+ {
1109
+ if (!isset($curl_init__map[$key]["options"][CURLOPT_INFILE]) || !is_resource($curl_init__map[$key]["options"][CURLOPT_INFILE])) return false;
1110
+ if ($bodysize > 32768) $body = fread($curl_init__map[$key]["options"][CURLOPT_INFILE], 32768);
1111
+ else $body = fread($curl_init__map[$key]["options"][CURLOPT_INFILE], $bodysize);
1112
+ if ($body === false)
1113
+ {
1114
+ if (isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1115
+ {
1116
+ $output = HTTP::HTTPTranslate("An error occurred while reading the data to send/upload to the host.");
1117
+
1118
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], $output);
1119
+ else if (defined("STDERR")) fwrite(STDERR, $output);
1120
+ else echo $output;
1121
+ }
1122
+
1123
+ return false;
1124
+ }
1125
+ }
1126
+
1127
+ return true;
1128
+ }
1129
+
1130
+ function internal_curl_read_headers_callback(&$response, &$headers, $key)
1131
+ {
1132
+ global $curl_init__map;
1133
+
1134
+ if (isset($curl_init__map[$key]["returnresponse"])) $data = "";
1135
+ else
1136
+ {
1137
+ $data = $response["line"] . "\r\n";
1138
+
1139
+ $curl_init__map[$key]["returnresponse"] = $response;
1140
+ }
1141
+
1142
+ if ($response["code"] >= 400 && isset($curl_init__map[$key]["options"][CURLOPT_FAILONERROR]) && $curl_init__map[$key]["options"][CURLOPT_FAILONERROR]) return true;
1143
+
1144
+ foreach ($headers as $name => $vals)
1145
+ {
1146
+ foreach ($vals as $val) $data .= $name . ": " . $val . "\r\n";
1147
+ }
1148
+
1149
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HEADER]) && $curl_init__map[$key]["options"][CURLOPT_HEADER])
1150
+ {
1151
+ if (isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1152
+ {
1153
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], HTTP::HTTPTranslate("Header:\n") . $data);
1154
+ else if (defined("STDERR")) fwrite(STDERR, HTTP::HTTPTranslate("Header:\n") . $data);
1155
+ else echo HTTP::HTTPTranslate("Header:\n") . $data;
1156
+ }
1157
+ }
1158
+
1159
+ if (!isset($headers["Location"]) || !isset($curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION]) || !$curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION])
1160
+ {
1161
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HEADER]) && $curl_init__map[$key]["options"][CURLOPT_HEADER])
1162
+ {
1163
+ if (isset($curl_init__map[$key]["options"][CURLOPT_WRITEHEADER]) && is_resource($curl_init__map[$key]["options"][CURLOPT_WRITEHEADER]))
1164
+ {
1165
+ fwrite($curl_init__map[$key]["options"][CURLOPT_WRITEHEADER], $data);
1166
+ }
1167
+ else if (isset($curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER]) && $curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER])
1168
+ {
1169
+ if (!isset($curl_init__map[$key]["returnheader"])) $curl_init__map[$key]["returnheader"] = $data;
1170
+ else $curl_init__map[$key]["returnheader"] .= $data;
1171
+ }
1172
+ else if (!$curl_init__map[$key]["outputbody"])
1173
+ {
1174
+ if (isset($curl_init__map[$key]["options"][CURLOPT_FILE]) && is_resource($curl_init__map[$key]["options"][CURLOPT_FILE])) fwrite($curl_init__map[$key]["options"][CURLOPT_FILE], $data);
1175
+ else echo $data;
1176
+ }
1177
+ }
1178
+
1179
+ if (isset($curl_init__map[$key]["options"][CURLOPT_HEADERFUNCTION]) && $curl_init__map[$key]["options"][CURLOPT_HEADERFUNCTION])
1180
+ {
1181
+ $curl_init__map[$key]["options"][CURLOPT_HEADERFUNCTION]($curl_init__map[$key]["self"], $data);
1182
+ }
1183
+ }
1184
+
1185
+ return true;
1186
+ }
1187
+
1188
+ function internal_curl_read_body_callback(&$response, $data, $key)
1189
+ {
1190
+ global $curl_init__map;
1191
+
1192
+ if ($response["code"] >= 400 && isset($curl_init__map[$key]["options"][CURLOPT_FAILONERROR]) && $curl_init__map[$key]["options"][CURLOPT_FAILONERROR]) return true;
1193
+
1194
+ if (!isset($headers["Location"]) || !isset($curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION]) || !$curl_init__map[$key]["options"][CURLOPT_FOLLOWLOCATION])
1195
+ {
1196
+ if (!isset($curl_init__map[$key]["returnbody"])) $curl_init__map[$key]["returnbody"] = "";
1197
+
1198
+ if (isset($curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER]) && $curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER]) $curl_init__map[$key]["returnbody"] .= $data;
1199
+ else
1200
+ {
1201
+ if (isset($curl_init__map[$key]["options"][CURLOPT_FILE]) && is_resource($curl_init__map[$key]["options"][CURLOPT_FILE])) fwrite($curl_init__map[$key]["options"][CURLOPT_FILE], $data);
1202
+ else echo $data;
1203
+
1204
+ $curl_init__map[$key]["outputbody"] = true;
1205
+ }
1206
+
1207
+ if (isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1208
+ {
1209
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], HTTP::HTTPTranslate("Body:\n") . $data);
1210
+ else if (defined("STDERR")) fwrite(STDERR, HTTP::HTTPTranslate("Body:\n") . $data);
1211
+ else echo HTTP::HTTPTranslate("Body:\n") . $data;
1212
+ }
1213
+
1214
+ if (isset($curl_init__map[$key]["options"][CURLOPT_WRITEFUNCTION]) && $curl_init__map[$key]["options"][CURLOPT_WRITEFUNCTION])
1215
+ {
1216
+ $datasize = strlen($data);
1217
+ $size = $curl_init__map[$key]["options"][CURLOPT_WRITEFUNCTION]($curl_init__map[$key]["self"], $data);
1218
+ if ($size != $datasize)
1219
+ {
1220
+ if (isset($curl_init__map[$key]["options"][CURLOPT_VERBOSE]) && $curl_init__map[$key]["options"][CURLOPT_VERBOSE])
1221
+ {
1222
+ $output = HTTP::HTTPTranslate("An error occurred in the write function callback while writing the data received from the host.");
1223
+
1224
+ if (isset($curl_init__map[$key]["options"][CURLOPT_STDERR]) && is_resource($curl_init__map[$key]["options"][CURLOPT_STDERR])) fwrite($curl_init__map[$key]["options"][CURLOPT_STDERR], $output);
1225
+ else if (defined("STDERR")) fwrite(STDERR, $output);
1226
+ else echo $output;
1227
+ }
1228
+
1229
+ return false;
1230
+ }
1231
+ }
1232
+ }
1233
+
1234
+ return true;
1235
+ }
1236
+
1237
+ function curl_getinfo($ch, $opt = 0)
1238
+ {
1239
+ global $curl_init__map;
1240
+
1241
+ $key = get_check_curl_init_key($ch);
1242
+
1243
+ if (!isset($curl_init__map[$key]["lastresult"])) return false;
1244
+
1245
+ $result = array(
1246
+ "url" => $curl_init__map[$key]["lastresult"]["url"],
1247
+ "content_type" => (isset($curl_init__map[$key]["lastresult"]["headers"]) && isset($curl_init__map[$key]["lastresult"]["headers"]["Content-Type"]) ? $curl_init__map[$key]["lastresult"]["headers"]["Content-Type"][0] : null),
1248
+ "http_code" => (isset($curl_init__map[$key]["lastresult"]["response"]) && isset($curl_init__map[$key]["lastresult"]["response"]["code"]) ? (int)$curl_init__map[$key]["lastresult"]["response"]["code"] : null),
1249
+ "header_size" => (isset($curl_init__map[$key]["lastresult"]["rawrecvheadersize"]) ? $curl_init__map[$key]["lastresult"]["rawrecvheadersize"] : 0),
1250
+ "request_size" => (isset($curl_init__map[$key]["lastresult"]["totalrawsendsize"]) ? $curl_init__map[$key]["lastresult"]["totalrawsendsize"] : 0),
1251
+ "filetime" => (isset($curl_init__map[$key]["options"][CURLOPT_FILETIME]) && $curl_init__map[$key]["options"][CURLOPT_FILETIME] && isset($curl_init__map[$key]["lastresult"]["headers"]) && isset($curl_init__map[$key]["lastresult"]["headers"]["Last-Modified"]) ? HTTP::GetDateTimestamp($curl_init__map[$key]["lastresult"]["headers"]["Last-Modified"][0]) : -1),
1252
+ "ssl_verify_result" => 0,
1253
+ "redirect_count" => (isset($curl_init__map[$key]["lastresult"]["numredirects"]) ? $curl_init__map[$key]["lastresult"]["numredirects"] : 0),
1254
+ "total_time" => (isset($curl_init__map[$key]["lastresult"]["startts"]) && isset($curl_init__map[$key]["lastresult"]["endts"]) ? $curl_init__map[$key]["lastresult"]["endts"] - $curl_init__map[$key]["lastresult"]["startts"] : 0),
1255
+ "namelookup_time" => (isset($curl_init__map[$key]["lastresult"]["startts"]) && isset($curl_init__map[$key]["lastresult"]["connected"]) ? ($curl_init__map[$key]["lastresult"]["connected"] - $curl_init__map[$key]["lastresult"]["startts"]) / 2 : 0),
1256
+ "connect_time" => (isset($curl_init__map[$key]["lastresult"]["startts"]) && isset($curl_init__map[$key]["lastresult"]["connected"]) ? ($curl_init__map[$key]["lastresult"]["connected"] - $curl_init__map[$key]["lastresult"]["startts"]) / 2 : 0),
1257
+ "pretransfer_time" => (isset($curl_init__map[$key]["lastresult"]["connected"]) && isset($curl_init__map[$key]["lastresult"]["sendstart"]) ? $curl_init__map[$key]["lastresult"]["sendstart"] - $curl_init__map[$key]["lastresult"]["connected"] : 0),
1258
+ "size_upload" => (isset($curl_init__map[$key]["lastresult"]["rawsendsize"]) && isset($curl_init__map[$key]["lastresult"]["rawsendheadersize"]) ? $curl_init__map[$key]["lastresult"]["rawsendsize"] - $curl_init__map[$key]["lastresult"]["rawsendheadersize"] : 0),
1259
+ "size_download" => (isset($curl_init__map[$key]["lastresult"]["rawrecvsize"]) && isset($curl_init__map[$key]["lastresult"]["rawrecvheadersize"]) ? $curl_init__map[$key]["lastresult"]["rawrecvsize"] - $curl_init__map[$key]["lastresult"]["rawrecvheadersize"] : 0)
1260
+ );
1261
+
1262
+ $result["speed_download"] = (isset($curl_init__map[$key]["lastresult"]["recvstart"]) && isset($curl_init__map[$key]["lastresult"]["endts"]) && $curl_init__map[$key]["lastresult"]["endts"] - $curl_init__map[$key]["lastresult"]["recvstart"] > 0 ? $result["size_download"] / ($curl_init__map[$key]["lastresult"]["endts"] - $curl_init__map[$key]["lastresult"]["recvstart"]) : 0);
1263
+ $result["speed_upload"] = (isset($curl_init__map[$key]["lastresult"]["sendstart"]) && isset($curl_init__map[$key]["lastresult"]["recvstart"]) && $curl_init__map[$key]["lastresult"]["recvstart"] - $curl_init__map[$key]["lastresult"]["sendstart"] > 0 ? $result["size_upload"] / ($curl_init__map[$key]["lastresult"]["recvstart"] - $curl_init__map[$key]["lastresult"]["sendstart"]) : 0);
1264
+ $result["download_content_length"] = (isset($curl_init__map[$key]["lastresult"]["headers"]) && isset($curl_init__map[$key]["lastresult"]["headers"]["Content-Length"]) ? $curl_init__map[$key]["lastresult"]["headers"]["Content-Length"][0] : -1);
1265
+ $result["upload_content_length"] = $result["size_upload"];
1266
+ $result["starttransfer_time"] = (isset($curl_init__map[$key]["lastresult"]["startts"]) && isset($curl_init__map[$key]["lastresult"]["sendstart"]) ? $curl_init__map[$key]["lastresult"]["sendstart"] - $curl_init__map[$key]["lastresult"]["startts"] : 0);
1267
+ $result["redirect_time"] = (isset($curl_init__map[$key]["lastresult"]["firstreqts"]) && isset($curl_init__map[$key]["lastresult"]["redirectts"]) ? $curl_init__map[$key]["lastresult"]["redirectts"] - $curl_init__map[$key]["lastresult"]["firstreqts"] : 0);
1268
+ if (isset($curl_init__map[$key]["rawheaders"])) $result["request_header"] = $curl_init__map[$key]["rawheaders"];
1269
+
1270
+ if ($opt == 0) return $result;
1271
+
1272
+ $tempmap = array(
1273
+ CURLINFO_EFFECTIVE_URL => "url",
1274
+ CURLINFO_HTTP_CODE => "http_code",
1275
+ CURLINFO_FILETIME => "filetime",
1276
+ CURLINFO_TOTAL_TIME => "total_time",
1277
+ CURLINFO_NAMELOOKUP_TIME => "namelookup_time",
1278
+ CURLINFO_CONNECT_TIME => "connect_time",
1279
+ CURLINFO_PRETRANSFER_TIME => "pretransfer_time",
1280
+ CURLINFO_STARTTRANSFER_TIME => "starttransfer_time",
1281
+ CURLINFO_REDIRECT_TIME => "redirect_time",
1282
+ CURLINFO_SIZE_UPLOAD => "size_upload",
1283
+ CURLINFO_SIZE_DOWNLOAD => "size_download",
1284
+ CURLINFO_SPEED_DOWNLOAD => "speed_download",
1285
+ CURLINFO_SPEED_UPLOAD => "speed_upload",
1286
+ CURLINFO_HEADER_SIZE => "header_size",
1287
+ CURLINFO_HEADER_OUT => "request_header",
1288
+ CURLINFO_REQUEST_SIZE => "request_size",
1289
+ CURLINFO_SSL_VERIFYRESULT => "ssl_verify_result",
1290
+ CURLINFO_CONTENT_LENGTH_DOWNLOAD => "download_content_length",
1291
+ CURLINFO_CONTENT_LENGTH_UPLOAD => "upload_content_length",
1292
+ CURLINFO_CONTENT_TYPE => "content_type",
1293
+ );
1294
+ if (!isset($tempmap[$opt]) || !isset($result[$tempmap[$opt]])) return false;
1295
+
1296
+ return $result[$tempmap[$opt]];
1297
+ }
1298
+
1299
+ // These functions really just cheat and do requests in serial. Laziness at its finest!
1300
+ $curl_multi_init__map = array();
1301
+ function get_curl_multi_init_key($mh)
1302
+ {
1303
+ ob_start();
1304
+ echo $mh;
1305
+ ob_end_clean();
1306
+
1307
+ return ob_get_contents();
1308
+ }
1309
+
1310
+ function get_check_curl_multi_init_key($ch)
1311
+ {
1312
+ global $curl_init__map;
1313
+
1314
+ $key = get_curl_multi_init_key($ch);
1315
+ if (!isset($curl_multi_init__map[$key])) throw new Exception(HTTP::HTTPTranslate("cURL Emulator: Unable to find key mapping for resource."));
1316
+
1317
+ return $key;
1318
+ }
1319
+
1320
+ function curl_multi_init()
1321
+ {
1322
+ global $curl_multi_init__map;
1323
+
1324
+ // Another evil hack to create a "resource" so that is_resource() works.
1325
+ $mh = fopen(__FILE__, "rb");
1326
+ $key = get_curl_multi_init_key($mh);
1327
+ $curl_multi_init__map[$key] = array("self" => $mh, "handles" => array(), "messages" => array());
1328
+
1329
+ return $mh;
1330
+ }
1331
+
1332
+ function curl_multi_add_handle($mh, $ch)
1333
+ {
1334
+ global $curl_multi_init__map;
1335
+
1336
+ $key = get_check_curl_multi_init_key($mh);
1337
+ $key2 = get_check_curl_init_key($ch);
1338
+
1339
+ $curl_multi_init__map[$key]["handles"][$key2] = $ch;
1340
+
1341
+ return 0;
1342
+ }
1343
+
1344
+ function curl_multi_remove_handle($mh, $ch)
1345
+ {
1346
+ global $curl_multi_init__map;
1347
+
1348
+ $key = get_check_curl_multi_init_key($mh);
1349
+ $key2 = get_check_curl_init_key($ch);
1350
+
1351
+ unset($curl_multi_init__map[$key]["handles"][$key2]);
1352
+
1353
+ return 0;
1354
+ }
1355
+
1356
+ function curl_multi_close($mh)
1357
+ {
1358
+ global $curl_multi_init__map;
1359
+
1360
+ $key = get_check_curl_multi_init_key($mh);
1361
+
1362
+ unset($curl_multi_init__map[$key]);
1363
+ }
1364
+
1365
+ function curl_multi_getcontent($ch)
1366
+ {
1367
+ global $curl_init__map;
1368
+
1369
+ $key = get_check_curl_init_key($ch);
1370
+
1371
+ if (isset($curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER]) && $curl_init__map[$key]["options"][CURLOPT_RETURNTRANSFER])
1372
+ {
1373
+ return (isset($curl_init__map[$key]["returnheader"]) ? $curl_init__map[$key]["returnheader"] . "\r\n" : "") . (isset($curl_init__map[$key]["returnbody"]) ? $curl_init__map[$key]["returnbody"] : "");
1374
+ }
1375
+ }
1376
+
1377
+ function curl_multi_exec($mh, &$still_running)
1378
+ {
1379
+ global $curl_multi_init__map;
1380
+
1381
+ $key = get_check_curl_multi_init_key($mh);
1382
+
1383
+ foreach ($curl_multi_init__map[$key]["handles"] as $key2 => $ch)
1384
+ {
1385
+ curl_exec($ch);
1386
+ $curl_multi_init__map[$key]["messages"][] = array(
1387
+ "msg" => CURLMSG_DONE,
1388
+ "result" => curl_errno($ch),
1389
+ "handle" => $ch
1390
+ );
1391
+ unset($curl_multi_init__map[$key]["handles"][$key2]);
1392
+ }
1393
+
1394
+ $still_running = 0;
1395
+
1396
+ return CURLM_OK;
1397
+ }
1398
+
1399
+ function curl_multi_select($mh, $timeout = 1.0)
1400
+ {
1401
+ global $curl_multi_init__map;
1402
+
1403
+ $key = get_check_curl_multi_init_key($mh);
1404
+
1405
+ if (!count($curl_multi_init__map[$key]["handles"])) return -1;
1406
+
1407
+ return count($curl_multi_init__map[$key]["handles"]);
1408
+ }
1409
+
1410
+ function curl_multi_info_read($mh, &$msgs_in_queue = NULL)
1411
+ {
1412
+ global $curl_multi_init__map;
1413
+
1414
+ $key = get_check_curl_multi_init_key($mh);
1415
+
1416
+ $msgs_in_queue = count($curl_multi_init__map[$key]["messages"]);
1417
+ if (!$msgs_in_queue) return false;
1418
+ $msgs_in_queue--;
1419
+
1420
+ return array_shift($curl_multi_init__map[$key]["messages"]);
1421
+ }
1422
+ }
1423
+ ?>
includes/vendor/ultimate-web-scraper/http.php ADDED
@@ -0,0 +1,1810 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP HTTP class.
3
+ // (C) 2018 CubicleSoft. All Rights Reserved.
4
+
5
+ class HTTP
6
+ {
7
+ // RFC 3986 delimeter splitting implementation.
8
+ public static function ExtractURL($url)
9
+ {
10
+ $result = array(
11
+ "scheme" => "",
12
+ "authority" => "",
13
+ "login" => "",
14
+ "loginusername" => "",
15
+ "loginpassword" => "",
16
+ "host" => "",
17
+ "port" => "",
18
+ "path" => "",
19
+ "query" => "",
20
+ "queryvars" => array(),
21
+ "fragment" => ""
22
+ );
23
+
24
+ $url = str_replace("&amp;", "&", $url);
25
+
26
+ $pos = strpos($url, "#");
27
+ if ($pos !== false)
28
+ {
29
+ $result["fragment"] = substr($url, $pos + 1);
30
+ $url = substr($url, 0, $pos);
31
+ }
32
+
33
+ $pos = strpos($url, "?");
34
+ if ($pos !== false)
35
+ {
36
+ $result["query"] = str_replace(" ", "+", substr($url, $pos + 1));
37
+ $url = substr($url, 0, $pos);
38
+ $vars = explode("&", $result["query"]);
39
+ foreach ($vars as $var)
40
+ {
41
+ $pos = strpos($var, "=");
42
+ if ($pos === false)
43
+ {
44
+ $name = $var;
45
+ $value = "";
46
+ }
47
+ else
48
+ {
49
+ $name = substr($var, 0, $pos);
50
+ $value = urldecode(substr($var, $pos + 1));
51
+ }
52
+ $name = urldecode($name);
53
+ if (!isset($result["queryvars"][$name])) $result["queryvars"][$name] = array();
54
+ $result["queryvars"][$name][] = $value;
55
+ }
56
+ }
57
+
58
+ $url = str_replace("\\", "/", $url);
59
+
60
+ $pos = strpos($url, ":");
61
+ $pos2 = strpos($url, "/");
62
+ if ($pos !== false && ($pos2 === false || $pos < $pos2))
63
+ {
64
+ $result["scheme"] = strtolower(substr($url, 0, $pos));
65
+ $url = substr($url, $pos + 1);
66
+ }
67
+
68
+ if (substr($url, 0, 2) != "//") $result["path"] = $url;
69
+ else
70
+ {
71
+ $url = substr($url, 2);
72
+ $pos = strpos($url, "/");
73
+ if ($pos !== false)
74
+ {
75
+ $result["path"] = substr($url, $pos);
76
+ $url = substr($url, 0, $pos);
77
+ }
78
+ $result["authority"] = $url;
79
+
80
+ $pos = strpos($url, "@");
81
+ if ($pos !== false)
82
+ {
83
+ $result["login"] = substr($url, 0, $pos);
84
+ $url = substr($url, $pos + 1);
85
+ $pos = strpos($result["login"], ":");
86
+ if ($pos === false) $result["loginusername"] = urldecode($result["login"]);
87
+ else
88
+ {
89
+ $result["loginusername"] = urldecode(substr($result["login"], 0, $pos));
90
+ $result["loginpassword"] = urldecode(substr($result["login"], $pos + 1));
91
+ }
92
+ }
93
+
94
+ $pos = strpos($url, "]");
95
+ if (substr($url, 0, 1) == "[" && $pos !== false)
96
+ {
97
+ // IPv6 literal address.
98
+ $result["host"] = substr($url, 0, $pos + 1);
99
+ $url = substr($url, $pos + 1);
100
+
101
+ $pos = strpos($url, ":");
102
+ if ($pos !== false)
103
+ {
104
+ $result["port"] = substr($url, $pos + 1);
105
+ $url = substr($url, 0, $pos);
106
+ }
107
+ }
108
+ else
109
+ {
110
+ // Normal host[:port].
111
+ $pos = strpos($url, ":");
112
+ if ($pos !== false)
113
+ {
114
+ $result["port"] = substr($url, $pos + 1);
115
+ $url = substr($url, 0, $pos);
116
+ }
117
+
118
+ $result["host"] = $url;
119
+ }
120
+ }
121
+
122
+ return $result;
123
+ }
124
+
125
+ // Takes a ExtractURL() array and condenses it into a string.
126
+ public static function CondenseURL($data)
127
+ {
128
+ $result = "";
129
+ if (isset($data["host"]) && $data["host"] != "")
130
+ {
131
+ if (isset($data["scheme"]) && $data["scheme"] != "") $result = $data["scheme"] . "://";
132
+ if (isset($data["loginusername"]) && $data["loginusername"] != "" && isset($data["loginpassword"])) $result .= rawurlencode($data["loginusername"]) . ($data["loginpassword"] != "" ? ":" . rawurlencode($data["loginpassword"]) : "") . "@";
133
+ else if (isset($data["login"]) && $data["login"] != "") $result .= $data["login"] . "@";
134
+
135
+ $result .= $data["host"];
136
+ if (isset($data["port"]) && $data["port"] != "") $result .= ":" . $data["port"];
137
+
138
+ if (isset($data["path"]))
139
+ {
140
+ $data["path"] = str_replace("\\", "/", $data["path"]);
141
+ if (substr($data["path"], 0, 1) != "/") $data["path"] = "/" . $data["path"];
142
+ $result .= $data["path"];
143
+ }
144
+ }
145
+ else if (isset($data["authority"]) && $data["authority"] != "")
146
+ {
147
+ if (isset($data["scheme"]) && $data["scheme"] != "") $result = $data["scheme"] . "://";
148
+
149
+ $result .= $data["authority"];
150
+
151
+ if (isset($data["path"]))
152
+ {
153
+ $data["path"] = str_replace("\\", "/", $data["path"]);
154
+ if (substr($data["path"], 0, 1) != "/") $data["path"] = "/" . $data["path"];
155
+ $result .= $data["path"];
156
+ }
157
+ }
158
+ else if (isset($data["path"]))
159
+ {
160
+ if (isset($data["scheme"]) && $data["scheme"] != "") $result = $data["scheme"] . ":";
161
+
162
+ $result .= $data["path"];
163
+ }
164
+
165
+ if (isset($data["query"]))
166
+ {
167
+ if ($data["query"] != "") $result .= "?" . $data["query"];
168
+ }
169
+ else if (isset($data["queryvars"]))
170
+ {
171
+ $data["query"] = array();
172
+ foreach ($data["queryvars"] as $key => $vals)
173
+ {
174
+ if (is_string($vals)) $vals = array($vals);
175
+ foreach ($vals as $val) $data["query"][] = urlencode($key) . "=" . urlencode($val);
176
+ }
177
+ $data["query"] = implode("&", $data["query"]);
178
+
179
+ if ($data["query"] != "") $result .= "?" . $data["query"];
180
+ }
181
+
182
+ if (isset($data["fragment"]) && $data["fragment"] != "") $result .= "#" . $data["fragment"];
183
+
184
+ return $result;
185
+ }
186
+
187
+ public static function ConvertRelativeToAbsoluteURL($baseurl, $relativeurl)
188
+ {
189
+ $relative = (is_array($relativeurl) ? $relativeurl : self::ExtractURL($relativeurl));
190
+ $base = (is_array($baseurl) ? $baseurl : self::ExtractURL($baseurl));
191
+
192
+ if ($relative["host"] != "" || ($relative["scheme"] != "" && $relative["scheme"] != $base["scheme"]))
193
+ {
194
+ if ($relative["scheme"] == "") $relative["scheme"] = $base["scheme"];
195
+
196
+ return self::CondenseURL($relative);
197
+ }
198
+
199
+ $result = array(
200
+ "scheme" => $base["scheme"],
201
+ "loginusername" => $base["loginusername"],
202
+ "loginpassword" => $base["loginpassword"],
203
+ "host" => $base["host"],
204
+ "port" => $base["port"],
205
+ "path" => "",
206
+ "query" => $relative["query"],
207
+ "fragment" => $relative["fragment"]
208
+ );
209
+
210
+ if ($relative["path"] == "") $result["path"] = $base["path"];
211
+ else if (substr($relative["path"], 0, 1) == "/") $result["path"] = $relative["path"];
212
+ else
213
+ {
214
+ $abspath = explode("/", $base["path"]);
215
+ array_pop($abspath);
216
+ $relpath = explode("/", $relative["path"]);
217
+ foreach ($relpath as $piece)
218
+ {
219
+ if ($piece == ".")
220
+ {
221
+ }
222
+ else if ($piece == "..") array_pop($abspath);
223
+ else $abspath[] = $piece;
224
+ }
225
+
226
+ $abspath = implode("/", $abspath);
227
+ if (substr($abspath, 0, 1) != "/") $abspath = "/" . $abspath;
228
+
229
+ $result["path"] = $abspath;
230
+ }
231
+
232
+ return self::CondenseURL($result);
233
+ }
234
+
235
+ public static function GetUserAgent($type)
236
+ {
237
+ $type = strtolower($type);
238
+
239
+ if ($type == "ie") $type = "ie11";
240
+
241
+ if ($type == "ie6") return "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";
242
+ else if ($type == "ie7") return "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)";
243
+ else if ($type == "ie8") return "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1)";
244
+ else if ($type == "ie9") return "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
245
+ else if ($type == "ie10") return "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)";
246
+ else if ($type == "ie11") return "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";
247
+ else if ($type == "firefox") return "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0";
248
+ else if ($type == "opera") return "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.16";
249
+ else if ($type == "safari") return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2";
250
+ else if ($type == "chrome") return "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36";
251
+
252
+ return "";
253
+ }
254
+
255
+ public static function GetSSLCiphers($type = "intermediate")
256
+ {
257
+ $type = strtolower($type);
258
+
259
+ // Cipher list last updated May 3, 2017.
260
+ if ($type == "modern") return "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256";
261
+ else if ($type == "old") return "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP";
262
+
263
+ return "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";
264
+ }
265
+
266
+ public static function GetSafeSSLOpts($cafile = true, $cipherstype = "intermediate")
267
+ {
268
+ // Result array last updated May 3, 2017.
269
+ $result = array(
270
+ "ciphers" => self::GetSSLCiphers($cipherstype),
271
+ "disable_compression" => true,
272
+ "allow_self_signed" => false,
273
+ "verify_peer" => true,
274
+ "verify_depth" => 5
275
+ );
276
+
277
+ if ($cafile === true) $result["auto_cainfo"] = true;
278
+ else if ($cafile !== false) $result["cafile"] = $cafile;
279
+
280
+ return $result;
281
+ }
282
+
283
+ // Reasonably parses RFC1123, RFC850, and asctime() dates.
284
+ public static function GetDateTimestamp($httpdate)
285
+ {
286
+ $timestamp_map = array(
287
+ "jan" => 1, "feb" => 2, "mar" => 3, "apr" => 4, "may" => 5, "jun" => 6,
288
+ "jul" => 7, "aug" => 8, "sep" => 9, "oct" => 10, "nov" => 11, "dec" => 12
289
+ );
290
+
291
+ $year = false;
292
+ $month = false;
293
+ $day = false;
294
+ $hour = false;
295
+ $min = false;
296
+ $sec = false;
297
+
298
+ $items = explode(" ", preg_replace('/\s+/', " ", str_replace("-", " ", strtolower($httpdate))));
299
+ foreach ($items as $item)
300
+ {
301
+ if ($item != "")
302
+ {
303
+ if (strpos($item, ":") !== false)
304
+ {
305
+ $item = explode(":", $item);
306
+ $hour = (int)(count($item) > 0 ? array_shift($item) : 0);
307
+ $min = (int)(count($item) > 0 ? array_shift($item) : 0);
308
+ $sec = (int)(count($item) > 0 ? array_shift($item) : 0);
309
+
310
+ if ($hour > 23) $hour = 23;
311
+ if ($min > 59) $min = 59;
312
+ if ($sec > 59) $sec = 59;
313
+ }
314
+ else if (is_numeric($item))
315
+ {
316
+ if (strlen($item) >= 4) $year = (int)$item;
317
+ else if ($day === false) $day = (int)$item;
318
+ else $year = substr(date("Y"), 0, 2) . substr($item, -2);
319
+ }
320
+ else
321
+ {
322
+ $item = substr($item, 0, 3);
323
+ if (isset($timestamp_map[$item])) $month = $timestamp_map[$item];
324
+ }
325
+ }
326
+ }
327
+
328
+ if ($year === false || $month === false || $day === false || $hour === false || $min === false || $sec === false) return false;
329
+
330
+ return gmmktime($hour, $min, $sec, $month, $day, $year);
331
+ }
332
+
333
+ public static function HTTPTranslate()
334
+ {
335
+ $args = func_get_args();
336
+ if (!count($args)) return "";
337
+
338
+ return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args);
339
+ }
340
+
341
+ public static function HeaderNameCleanup($name)
342
+ {
343
+ return preg_replace('/\s+/', "-", ucwords(strtolower(trim(preg_replace('/[^A-Za-z0-9 ]/', " ", $name)))));
344
+ }
345
+
346
+ private static function HeaderValueCleanup($value)
347
+ {
348
+ return str_replace(array("\r", "\n"), array("", ""), $value);
349
+ }
350
+
351
+ public static function NormalizeHeaders($headers)
352
+ {
353
+ $result = array();
354
+ foreach ($headers as $name => $val)
355
+ {
356
+ $val = self::HeaderValueCleanup($val);
357
+ if ($val != "") $result[self::HeaderNameCleanup($name)] = $val;
358
+ }
359
+
360
+ return $result;
361
+ }
362
+
363
+ public static function MergeRawHeaders(&$headers, $rawheaders)
364
+ {
365
+ foreach ($rawheaders as $name => $val)
366
+ {
367
+ $val = self::HeaderValueCleanup($val);
368
+ if ($val != "")
369
+ {
370
+ $name2 = self::HeaderNameCleanup($name);
371
+ if (isset($headers[$name2])) unset($headers[$name2]);
372
+
373
+ $headers[$name] = $val;
374
+ }
375
+ }
376
+ }
377
+
378
+ public static function ExtractHeader($data)
379
+ {
380
+ $result = array();
381
+ $data = trim($data);
382
+ while ($data != "")
383
+ {
384
+ // Extract name/value pair.
385
+ $pos = strpos($data, "=");
386
+ $pos2 = strpos($data, ";");
387
+ if (($pos !== false && $pos2 === false) || ($pos !== false && $pos2 !== false && $pos < $pos2))
388
+ {
389
+ $name = trim(substr($data, 0, $pos));
390
+ $data = trim(substr($data, $pos + 1));
391
+ if (ord($data[0]) == ord("\""))
392
+ {
393
+ $pos = strpos($data, "\"", 1);
394
+ if ($pos !== false)
395
+ {
396
+ $value = substr($data, 1, $pos - 1);
397
+ $data = trim(substr($data, $pos + 1));
398
+ $pos = strpos($data, ";");
399
+ if ($pos !== false) $data = substr($data, $pos + 1);
400
+ else $data = "";
401
+ }
402
+ else
403
+ {
404
+ $value = $data;
405
+ $data = "";
406
+ }
407
+ }
408
+ else
409
+ {
410
+ $pos = strpos($data, ";");
411
+ if ($pos !== false)
412
+ {
413
+ $value = trim(substr($data, 0, $pos));
414
+ $data = substr($data, $pos + 1);
415
+ }
416
+ else
417
+ {
418
+ $value = $data;
419
+ $data = "";
420
+ }
421
+ }
422
+ }
423
+ else if ($pos2 !== false)
424
+ {
425
+ $name = "";
426
+ $value = trim(substr($data, 0, $pos2));
427
+ $data = substr($data, $pos2 + 1);
428
+ }
429
+ else
430
+ {
431
+ $name = "";
432
+ $value = $data;
433
+ $data = "";
434
+ }
435
+
436
+ if ($name != "" || $value != "") $result[strtolower($name)] = $value;
437
+
438
+ $data = trim($data);
439
+ }
440
+
441
+ return $result;
442
+ }
443
+
444
+ private static function ProcessSSLOptions(&$options, $key, $host)
445
+ {
446
+ if (isset($options[$key]["auto_cainfo"]))
447
+ {
448
+ unset($options[$key]["auto_cainfo"]);
449
+
450
+ $cainfo = ini_get("curl.cainfo");
451
+ if ($cainfo !== false && strlen($cainfo) > 0) $options[$key]["cafile"] = $cainfo;
452
+ else if (file_exists(str_replace("\\", "/", dirname(__FILE__)) . "/cacert.pem")) $options[$key]["cafile"] = str_replace("\\", "/", dirname(__FILE__)) . "/cacert.pem";
453
+ }
454
+
455
+ if (isset($options[$key]["auto_cn_match"]))
456
+ {
457
+ unset($options[$key]["auto_cn_match"]);
458
+
459
+ if (!isset($options["headers"]["Host"])) $options[$key]["CN_match"] = $host;
460
+ else
461
+ {
462
+ $info = self::ExtractURL("https://" . $options["headers"]["Host"]);
463
+ $options[$key]["CN_match"] = $info["host"];
464
+ }
465
+ }
466
+
467
+ if (isset($options[$key]["auto_sni"]))
468
+ {
469
+ unset($options[$key]["auto_sni"]);
470
+
471
+ $options[$key]["SNI_enabled"] = true;
472
+ if (!isset($options["headers"]["Host"])) $options[$key]["SNI_server_name"] = $host;
473
+ else
474
+ {
475
+ $info = self::ExtractURL("https://" . $options["headers"]["Host"]);
476
+ $options[$key]["SNI_server_name"] = $info["host"];
477
+ }
478
+ }
479
+ }
480
+
481
+ // Swiped from str_basics.php so this file can be standalone.
482
+ public static function ExtractFilename($dirfile)
483
+ {
484
+ $dirfile = str_replace("\\", "/", $dirfile);
485
+ $pos = strrpos($dirfile, "/");
486
+ if ($pos !== false) $dirfile = substr($dirfile, $pos + 1);
487
+
488
+ return $dirfile;
489
+ }
490
+
491
+ public static function FilenameSafe($filename)
492
+ {
493
+ return preg_replace('/[_]+/', "_", preg_replace('/[^A-Za-z0-9_.\-]/', "_", $filename));
494
+ }
495
+
496
+ public static function GetTimeLeft($start, $limit)
497
+ {
498
+ if ($limit === false) return false;
499
+
500
+ $difftime = microtime(true) - $start;
501
+ if ($difftime >= $limit) return 0;
502
+
503
+ return $limit - $difftime;
504
+ }
505
+
506
+ private static function ProcessRateLimit($size, $start, $limit, $async)
507
+ {
508
+ $difftime = microtime(true) - $start;
509
+ if ($difftime > 0.0)
510
+ {
511
+ if ($size / $difftime > $limit)
512
+ {
513
+ // Sleeping for some amount of time will equalize the rate.
514
+ // So, solve this for $x: $size / ($x + $difftime) = $limit
515
+ $amount = ($size - ($limit * $difftime)) / $limit;
516
+ $amount += 0.001;
517
+
518
+ if ($async) return microtime(true) + $amount;
519
+ else usleep($amount * 1000000);
520
+ }
521
+ }
522
+
523
+ return -1.0;
524
+ }
525
+
526
+ private static function GetDecodedBody(&$autodecode_ds, $body)
527
+ {
528
+ if ($autodecode_ds !== false)
529
+ {
530
+ $autodecode_ds->Write($body);
531
+ $body = $autodecode_ds->Read();
532
+ }
533
+
534
+ return $body;
535
+ }
536
+
537
+ private static function StreamTimedOut($fp)
538
+ {
539
+ if (!function_exists("stream_get_meta_data")) return false;
540
+
541
+ $info = stream_get_meta_data($fp);
542
+
543
+ return $info["timed_out"];
544
+ }
545
+
546
+ public static function InitResponseState($fp, $debug, $options, $startts, $timeout, $result, $close, $nextread, $client = true)
547
+ {
548
+ $state = array(
549
+ "fp" => $fp,
550
+ "type" => "response",
551
+ "async" => (isset($options["async"]) ? $options["async"] : false),
552
+ "debug" => $debug,
553
+ "startts" => $startts,
554
+ "timeout" => $timeout,
555
+ "waituntil" => -1.0,
556
+ "rawdata" => "",
557
+ "data" => "",
558
+ "rawsize" => 0,
559
+ "rawrecvheadersize" => 0,
560
+ "numheaders" => 0,
561
+ "autodecode" => (!isset($options["auto_decode"]) || $options["auto_decode"]),
562
+
563
+ "state" => ($client ? "response_line" : "request_line"),
564
+
565
+ "options" => $options,
566
+ "result" => $result,
567
+ "close" => $close,
568
+ "nextread" => $nextread,
569
+ "client" => $client
570
+ );
571
+
572
+ $state["result"]["recvstart"] = microtime(true);
573
+ $state["result"]["response"] = false;
574
+ $state["result"]["headers"] = false;
575
+ $state["result"]["body"] = false;
576
+
577
+ return $state;
578
+ }
579
+
580
+ // Handles partially read input. Also deals with the hacky workaround to the second bugfix in ProcessState__WriteData().
581
+ private static function ProcessState__InternalRead(&$state, $size, $endchar = false)
582
+ {
583
+ $y = strlen($state["nextread"]);
584
+
585
+ do
586
+ {
587
+ if ($size <= $y)
588
+ {
589
+ if ($endchar === false) $pos = $size;
590
+ else
591
+ {
592
+ $pos = strpos($state["nextread"], $endchar);
593
+ if ($pos === false || $pos > $size) $pos = $size;
594
+ else $pos++;
595
+ }
596
+
597
+ $data = substr($state["nextread"], 0, $pos);
598
+ $state["nextread"] = (string)substr($state["nextread"], $pos);
599
+
600
+ return $data;
601
+ }
602
+
603
+ if ($endchar !== false)
604
+ {
605
+ $pos = strpos($state["nextread"], $endchar);
606
+ if ($pos !== false)
607
+ {
608
+ $data = substr($state["nextread"], 0, $pos + 1);
609
+ $state["nextread"] = (string)substr($state["nextread"], $pos + 1);
610
+
611
+ return $data;
612
+ }
613
+ }
614
+
615
+ if ($state["debug"]) $data2 = fread($state["fp"], $size);
616
+ else $data2 = @fread($state["fp"], $size);
617
+
618
+ if ($data2 === false || $data2 === "")
619
+ {
620
+ if ($state["nextread"] === "") return $data2;
621
+
622
+ if ($state["async"] && $endchar !== false && $data2 === "") return "";
623
+
624
+ $data = $state["nextread"];
625
+ $state["nextread"] = "";
626
+
627
+ return $data;
628
+ }
629
+
630
+ $state["nextread"] .= $data2;
631
+
632
+ $y = strlen($state["nextread"]);
633
+ } while (!$state["async"] || ($size <= $y) || ($endchar !== false && strpos($state["nextread"], $endchar) !== false));
634
+
635
+ if ($endchar !== false) return "";
636
+
637
+ $data = $state["nextread"];
638
+ $state["nextread"] = "";
639
+
640
+ return $data;
641
+ }
642
+
643
+ // Reads one line.
644
+ private static function ProcessState__ReadLine(&$state)
645
+ {
646
+ while (strpos($state["data"], "\n") === false)
647
+ {
648
+ $data2 = self::ProcessState__InternalRead($state, 116000, "\n");
649
+
650
+ if ($data2 === false || $data2 === "")
651
+ {
652
+ if (feof($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Remote peer disconnected."), "errorcode" => "peer_disconnected");
653
+ else if ($state["async"]) return array("success" => false, "error" => self::HTTPTranslate("Non-blocking read returned no data."), "errorcode" => "no_data");
654
+ else if ($data2 === false) return array("success" => false, "error" => self::HTTPTranslate("Underlying stream encountered a read error."), "errorcode" => "stream_read_error");
655
+ }
656
+ $pos = strpos($data2, "\n");
657
+ if ($pos === false)
658
+ {
659
+ if (feof($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Remote peer disconnected."), "errorcode" => "peer_disconnected");
660
+ if (self::StreamTimedOut($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded");
661
+
662
+ $pos = strlen($data2);
663
+ }
664
+ if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded");
665
+ if (isset($state["options"]["readlinelimit"]) && strlen($state["data"]) + $pos > $state["options"]["readlinelimit"]) return array("success" => false, "error" => self::HTTPTranslate("Read line exceeded limit."), "errorcode" => "read_line_limit_exceeded");
666
+
667
+ $state["rawsize"] += strlen($data2);
668
+ $state["data"] .= $data2;
669
+
670
+ if (isset($state["options"]["recvlimit"]) && $state["options"]["recvlimit"] < $state["rawsize"]) return array("success" => false, "error" => self::HTTPTranslate("Received data exceeded limit."), "errorcode" => "receive_limit_exceeded");
671
+ if (isset($state["options"]["recvratelimit"])) $state["waituntil"] = self::ProcessRateLimit($state["rawsize"], $state["recvstart"], $state["options"]["recvratelimit"], $state["async"]);
672
+
673
+ if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("rawrecv", $data2, &$state["options"]["debug_callback_opts"]));
674
+ else if ($state["debug"]) $state["rawdata"] .= $data2;
675
+ }
676
+
677
+ return array("success" => true);
678
+ }
679
+
680
+ // Reads data in.
681
+ private static function ProcessState__ReadBodyData(&$state)
682
+ {
683
+ while ($state["sizeleft"] === false || $state["sizeleft"] > 0)
684
+ {
685
+ $data2 = self::ProcessState__InternalRead($state, ($state["sizeleft"] === false || $state["sizeleft"] > 65536 ? 65536 : $state["sizeleft"]));
686
+
687
+ if ($data2 === false) return array("success" => false, "error" => self::HTTPTranslate("Underlying stream encountered a read error."), "errorcode" => "stream_read_error");
688
+ if ($data2 === "")
689
+ {
690
+ if (feof($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Remote peer disconnected."), "errorcode" => "peer_disconnected");
691
+ if (self::StreamTimedOut($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Underlying stream timed out."), "errorcode" => "stream_timeout_exceeded");
692
+
693
+ if ($state["async"]) return array("success" => false, "error" => self::HTTPTranslate("Non-blocking read returned no data."), "errorcode" => "no_data");
694
+ }
695
+ if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded");
696
+
697
+ $tempsize = strlen($data2);
698
+ $state["rawsize"] += $tempsize;
699
+ if ($state["sizeleft"] !== false) $state["sizeleft"] -= $tempsize;
700
+
701
+ if ($state["result"]["response"]["code"] == 100 || !isset($state["options"]["read_body_callback"]) || !is_callable($state["options"]["read_body_callback"])) $state["result"]["body"] .= self::GetDecodedBody($state["autodecode_ds"], $data2);
702
+ else if (!call_user_func_array($state["options"]["read_body_callback"], array($state["result"][($state["client"] ? "response" : "request")], self::GetDecodedBody($state["autodecode_ds"], $data2), &$state["options"]["read_body_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback");
703
+
704
+ if (isset($state["options"]["recvlimit"]) && $state["options"]["recvlimit"] < $state["rawsize"]) return array("success" => false, "error" => self::HTTPTranslate("Received data exceeded limit."), "errorcode" => "receive_limit_exceeded");
705
+
706
+ if (isset($state["options"]["recvratelimit"]))
707
+ {
708
+ $state["waituntil"] = self::ProcessRateLimit($state["rawsize"], $state["recvstart"], $state["options"]["recvratelimit"], $state["async"]);
709
+ if (microtime(true) < $state["waituntil"]) return array("success" => false, "error" => self::HTTPTranslate("Rate limit for non-blocking connection has not been reached."), "errorcode" => "no_data");
710
+ }
711
+
712
+ if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("rawrecv", $data2, &$state["options"]["debug_callback_opts"]));
713
+ else if ($state["debug"]) $state["rawdata"] .= $data2;
714
+ }
715
+
716
+ return array("success" => true);
717
+ }
718
+
719
+ // Writes data out.
720
+ private static function ProcessState__WriteData(&$state, $prefix)
721
+ {
722
+ if ($state[$prefix . "data"] !== "")
723
+ {
724
+ // Serious bug in PHP core for non-blocking SSL sockets: https://bugs.php.net/bug.php?id=72333
725
+ if ($state["secure"] && $state["async"])
726
+ {
727
+ // This is a huge hack that has a pretty good chance of blocking on the socket.
728
+ // Peeling off up to just 4KB at a time helps to minimize that possibility. It's better than guaranteed failure of the socket though.
729
+ @stream_set_blocking($state["fp"], 1);
730
+ if ($state["debug"]) $result = fwrite($state["fp"], (strlen($state[$prefix . "data"]) > 4096 ? substr($state[$prefix . "data"], 0, 4096) : $state[$prefix . "data"]));
731
+ else $result = @fwrite($state["fp"], (strlen($state[$prefix . "data"]) > 4096 ? substr($state[$prefix . "data"], 0, 4096) : $state[$prefix . "data"]));
732
+ @stream_set_blocking($state["fp"], 0);
733
+ }
734
+ else
735
+ {
736
+ if ($state["debug"]) $result = fwrite($state["fp"], $state[$prefix . "data"]);
737
+ else $result = @fwrite($state["fp"], $state[$prefix . "data"]);
738
+ }
739
+
740
+ if ($result === false || feof($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("A fwrite() failure occurred. Most likely cause: Connection failure."), "errorcode" => "fwrite_failed");
741
+
742
+ // Serious bug in PHP core for all socket types: https://bugs.php.net/bug.php?id=73535
743
+ if ($result === 0)
744
+ {
745
+ // Temporarily switch to non-blocking sockets and test a one byte read (doesn't matter if data is available or not).
746
+ // This is a bigger hack than the first hack above.
747
+ if (!$state["async"]) @stream_set_blocking($state["fp"], 0);
748
+
749
+ if ($state["debug"]) $data2 = fread($state["fp"], 1);
750
+ else $data2 = @fread($state["fp"], 1);
751
+
752
+ if ($data2 === false) return array("success" => false, "error" => self::HTTPTranslate("Underlying stream encountered a read error."), "errorcode" => "stream_read_error");
753
+ if ($data2 === "" && feof($state["fp"])) return array("success" => false, "error" => self::HTTPTranslate("Remote peer disconnected."), "errorcode" => "peer_disconnected");
754
+
755
+ if ($data2 !== "") $state["nextread"] .= $data2;
756
+
757
+ if (!$state["async"]) @stream_set_blocking($state["fp"], 1);
758
+ }
759
+
760
+ if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded");
761
+
762
+ $data2 = (string)substr($state[$prefix . "data"], 0, $result);
763
+ $state[$prefix . "data"] = (string)substr($state[$prefix . "data"], $result);
764
+
765
+ $state["result"]["rawsend" . $prefix . "size"] += $result;
766
+
767
+ if (isset($state["options"]["sendratelimit"]))
768
+ {
769
+ $state["waituntil"] = self::ProcessRateLimit($state["result"]["rawsendsize"], $state["result"]["connected"], $state["options"]["sendratelimit"], $state["async"]);
770
+ if (microtime(true) < $state["waituntil"]) return array("success" => false, "error" => self::HTTPTranslate("Rate limit for non-blocking connection has not been reached."), "errorcode" => "no_data");
771
+ }
772
+
773
+ if (isset($state["options"]["debug_callback"]) && is_callable($state["options"]["debug_callback"])) call_user_func_array($state["options"]["debug_callback"], array("rawsend", $data2, &$state["options"]["debug_callback_opts"]));
774
+ else if ($state["debug"]) $state["result"]["rawsend"] .= $data2;
775
+
776
+ if ($state["async"] && strlen($state[$prefix . "data"])) return array("success" => false, "error" => self::HTTPTranslate("Non-blocking write did not send all data."), "errorcode" => "no_data");
777
+ }
778
+
779
+ return array("success" => true);
780
+ }
781
+
782
+ public static function ForceClose(&$state)
783
+ {
784
+ if ($state["fp"] !== false)
785
+ {
786
+ @fclose($state["fp"]);
787
+ $state["fp"] = false;
788
+ }
789
+
790
+ if (isset($state["currentfile"]) && $state["currentfile"] !== false)
791
+ {
792
+ if ($state["currentfile"]["fp"] !== false) @fclose($state["currentfile"]["fp"]);
793
+ $state["currentfile"] = false;
794
+ }
795
+ }
796
+
797
+ private static function CleanupErrorState(&$state, $result)
798
+ {
799
+ if (!$result["success"] && $result["errorcode"] !== "no_data")
800
+ {
801
+ self::ForceClose($state);
802
+
803
+ $state["error"] = $result;
804
+ }
805
+
806
+ return $result;
807
+ }
808
+
809
+ public static function WantRead(&$state)
810
+ {
811
+ return ($state["type"] === "response" || $state["state"] === "proxy_connect_response" || $state["state"] === "receive_switch" || $state["state"] === "connecting_enable_crypto" || $state["state"] === "proxy_connect_enable_crypto");
812
+ }
813
+
814
+ public static function WantWrite(&$state)
815
+ {
816
+ return (!self::WantRead($state) || $state["state"] === "connecting_enable_crypto" || $state["state"] === "proxy_connect_enable_crypto");
817
+ }
818
+
819
+ public static function ProcessState(&$state)
820
+ {
821
+ if (isset($state["error"])) return $state["error"];
822
+
823
+ if ($state["timeout"] !== false && self::GetTimeLeft($state["startts"], $state["timeout"]) == 0) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded"));
824
+ if (microtime(true) < $state["waituntil"]) return array("success" => false, "error" => self::HTTPTranslate("Rate limit for non-blocking connection has not been reached."), "errorcode" => "no_data");
825
+
826
+ if ($state["type"] === "request")
827
+ {
828
+ while ($state["state"] !== "done")
829
+ {
830
+ switch ($state["state"])
831
+ {
832
+ case "connecting":
833
+ {
834
+ if (function_exists("stream_select") && $state["async"])
835
+ {
836
+ $readfp = NULL;
837
+ $writefp = array($state["fp"]);
838
+ $exceptfp = array($state["fp"]);
839
+ if ($state["debug"]) $result = stream_select($readfp, $writefp, $exceptfp, 0);
840
+ else $result = @stream_select($readfp, $writefp, $exceptfp, 0);
841
+ if ($result === false || count($exceptfp)) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A stream_select() failure occurred. Most likely cause: Connection failure."), "errorcode" => "stream_select_failed"));
842
+
843
+ if (!count($writefp)) return array("success" => false, "error" => self::HTTPTranslate("Connection not established yet."), "errorcode" => "no_data");
844
+ }
845
+
846
+ // Deal with failed connections that hang applications.
847
+ if (isset($state["options"]["streamtimeout"]) && $state["options"]["streamtimeout"] !== false && function_exists("stream_set_timeout")) @stream_set_timeout($state["fp"], $state["options"]["streamtimeout"]);
848
+
849
+ // Switch to the next state.
850
+ if ($state["async"] && function_exists("stream_socket_client") && (($state["useproxy"] && $state["proxysecure"]) || (!$state["useproxy"] && $state["secure"]))) $state["state"] = "connecting_enable_crypto";
851
+ else $state["state"] = "connection_ready";
852
+
853
+ break;
854
+ }
855
+ case "connecting_enable_crypto":
856
+ {
857
+ // This is only used by clients that connect asynchronously via SSL.
858
+ if ($state["debug"]) $result = stream_socket_enable_crypto($state["fp"], true, STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
859
+ else $result = @stream_socket_enable_crypto($state["fp"], true, STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
860
+
861
+ if ($result === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A stream_socket_enable_crypto() failure occurred. Most likely cause: Connection failure or incompatible crypto setup."), "errorcode" => "stream_socket_enable_crypto_failed"));
862
+ else if ($result === true) $state["state"] = "connection_ready";
863
+
864
+ break;
865
+ }
866
+ case "connection_ready":
867
+ {
868
+ // Handle peer certificate retrieval.
869
+ if (function_exists("stream_context_get_options"))
870
+ {
871
+ $contextopts = stream_context_get_options($state["fp"]);
872
+ if ($state["useproxy"])
873
+ {
874
+ if ($state["proxysecure"] && isset($state["options"]["proxysslopts"]) && is_array($state["options"]["proxysslopts"]))
875
+ {
876
+ if (isset($state["options"]["peer_cert_callback"]) && is_callable($state["options"]["peer_cert_callback"]))
877
+ {
878
+ if (isset($contextopts["ssl"]["peer_certificate"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("proxypeercert", $contextopts["ssl"]["peer_certificate"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
879
+ if (isset($contextopts["ssl"]["peer_certificate_chain"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("proxypeercertchain", $contextopts["ssl"]["peer_certificate_chain"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
880
+ }
881
+ }
882
+ }
883
+ else
884
+ {
885
+ if ($state["secure"] && isset($state["options"]["sslopts"]) && is_array($state["options"]["sslopts"]))
886
+ {
887
+ if (isset($state["options"]["peer_cert_callback"]) && is_callable($state["options"]["peer_cert_callback"]))
888
+ {
889
+ if (isset($contextopts["ssl"]["peer_certificate"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("peercert", $contextopts["ssl"]["peer_certificate"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
890
+ if (isset($contextopts["ssl"]["peer_certificate_chain"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("peercertchain", $contextopts["ssl"]["peer_certificate_chain"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
891
+ }
892
+ }
893
+ }
894
+ }
895
+
896
+ $state["result"]["connected"] = microtime(true);
897
+
898
+ // Switch to the correct state.
899
+ if ($state["proxyconnect"])
900
+ {
901
+ $state["result"]["rawsendproxysize"] = 0;
902
+ $state["result"]["rawsendproxyheadersize"] = strlen($state["proxydata"]);
903
+
904
+ $state["state"] = "proxy_connect_send";
905
+ }
906
+ else
907
+ {
908
+ $state["result"]["sendstart"] = microtime(true);
909
+
910
+ $state["state"] = "send_data";
911
+ }
912
+
913
+ break;
914
+ }
915
+ case "proxy_connect_send":
916
+ {
917
+ // Send the HTTP CONNECT request to the proxy.
918
+ $result = self::ProcessState__WriteData($state, "proxy");
919
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
920
+
921
+ // Prepare the state for handling the response from the proxy server.
922
+ $options2 = array();
923
+ if (isset($state["options"]["async"])) $options2["async"] = $state["options"]["async"];
924
+ if (isset($state["options"]["recvratelimit"])) $options2["recvratelimit"] = $state["options"]["recvratelimit"];
925
+ if (isset($state["options"]["debug_callback"]))
926
+ {
927
+ $options2["debug_callback"] = $state["options"]["debug_callback"];
928
+ $options2["debug_callback_opts"] = $state["options"]["debug_callback_opts"];
929
+ }
930
+ $state["proxyresponse"] = self::InitResponseState($state["fp"], $state["debug"], $options2, $state["startts"], $state["timeout"], $state["result"], false, $state["nextread"]);
931
+
932
+ $state["state"] = "proxy_connect_response";
933
+
934
+ break;
935
+ }
936
+ case "proxy_connect_response":
937
+ {
938
+ // Recursively call this function to handle the proxy response.
939
+ $result = self::ProcessState($state["proxyresponse"]);
940
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
941
+
942
+ $state["result"]["rawrecvsize"] += $result["rawrecvsize"];
943
+ $state["result"]["rawrecvheadersize"] += $result["rawrecvheadersize"];
944
+
945
+ if (substr($result["response"]["code"], 0, 1) != "2") return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Expected a 200 response from the CONNECT request. Received: %s.", $result["response"]["line"]), "info" => $result, "errorcode" => "proxy_connect_tunnel_failed"));
946
+
947
+ // Proxy connect tunnel established. Proceed normally.
948
+ $state["result"]["sendstart"] = microtime(true);
949
+
950
+ if ($state["secure"]) $state["state"] = "proxy_connect_enable_crypto";
951
+ else $state["state"] = "send_data";
952
+
953
+ break;
954
+ }
955
+ case "proxy_connect_enable_crypto":
956
+ {
957
+ if ($state["debug"]) $result = stream_socket_enable_crypto($state["fp"], true, STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
958
+ else $result = @stream_socket_enable_crypto($state["fp"], true, STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
959
+
960
+ if ($result === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A stream_socket_enable_crypto() failure occurred. Most likely cause: Tunnel connection failure or incompatible crypto setup."), "errorcode" => "stream_socket_enable_crypto_failed"));
961
+ else if ($result === true)
962
+ {
963
+ // Handle peer certificate retrieval.
964
+ if (function_exists("stream_context_get_options"))
965
+ {
966
+ $contextopts = stream_context_get_options($state["fp"]);
967
+
968
+ if (isset($state["options"]["sslopts"]) && is_array($state["options"]["sslopts"]))
969
+ {
970
+ if (isset($state["options"]["peer_cert_callback"]) && is_callable($state["options"]["peer_cert_callback"]))
971
+ {
972
+ if (isset($contextopts["ssl"]["peer_certificate"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("peercert", $contextopts["ssl"]["peer_certificate"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
973
+ if (isset($contextopts["ssl"]["peer_certificate_chain"]) && !call_user_func_array($state["options"]["peer_cert_callback"], array("peercertchain", $contextopts["ssl"]["peer_certificate_chain"], &$state["options"]["peer_cert_callback_opts"]))) return array("success" => false, "error" => self::HTTPTranslate("Peer certificate callback returned with a failure condition."), "errorcode" => "peer_cert_callback");
974
+ }
975
+ }
976
+ }
977
+
978
+ // Secure connection established.
979
+ $state["state"] = "send_data";
980
+ }
981
+
982
+ break;
983
+ }
984
+ case "send_data":
985
+ {
986
+ // Send the queued data.
987
+ $result = self::ProcessState__WriteData($state, "");
988
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
989
+
990
+ // Queue up more data.
991
+ if (isset($state["options"]["write_body_callback"]) && is_callable($state["options"]["write_body_callback"]))
992
+ {
993
+ if ($state["bodysize"] === false || $state["bodysize"] > 0)
994
+ {
995
+ $bodysize2 = $state["bodysize"];
996
+ $result = call_user_func_array($state["options"]["write_body_callback"], array(&$state["data"], &$bodysize2, &$state["options"]["write_body_callback_opts"]));
997
+ if (!$result || ($state["bodysize"] !== false && strlen($state["data"]) > $state["bodysize"])) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("HTTP write body callback function failed."), "errorcode" => "write_body_callback"));
998
+
999
+ if ($state["bodysize"] === false)
1000
+ {
1001
+ if ($state["data"] !== "" && $state["chunked"]) $state["data"] = dechex(strlen($state["data"])) . "\r\n" . $state["data"] . "\r\n";
1002
+
1003
+ // When $bodysize2 is set to true, it is the last chunk.
1004
+ if ($bodysize2 === true)
1005
+ {
1006
+ if ($state["chunked"])
1007
+ {
1008
+ $state["data"] .= "0\r\n";
1009
+
1010
+ // Allow the body callback function to append additional headers to the content to send.
1011
+ // It is up to the callback function to correctly format the extra headers.
1012
+ $result = call_user_func_array($state["options"]["write_body_callback"], array(&$state["data"], &$bodysize2, &$state["options"]["write_body_callback_opts"]));
1013
+ if (!$result) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("HTTP write body callback function failed."), "errorcode" => "write_body_callback"));
1014
+
1015
+ $state["data"] .= "\r\n";
1016
+ }
1017
+
1018
+ $state["bodysize"] = 0;
1019
+ }
1020
+ }
1021
+ else
1022
+ {
1023
+ $state["bodysize"] -= strlen($state["data"]);
1024
+ }
1025
+ }
1026
+ }
1027
+ else if (isset($state["options"]["files"]) && $state["bodysize"] > 0)
1028
+ {
1029
+ // Select the next file to upload.
1030
+ if ($state["currentfile"] === false && count($state["options"]["files"]))
1031
+ {
1032
+ $state["currentfile"] = array_shift($state["options"]["files"]);
1033
+
1034
+ $name = self::HeaderValueCleanup($state["currentfile"]["name"]);
1035
+ $name = str_replace("\"", "", $name);
1036
+ $filename = self::FilenameSafe(self::ExtractFilename($state["currentfile"]["filename"]));
1037
+ $type = self::HeaderValueCleanup($state["currentfile"]["type"]);
1038
+
1039
+ $state["data"] = "--" . $state["mime"] . "\r\n";
1040
+ $state["data"] .= "Content-Disposition: form-data; name=\"" . $name . "\"; filename=\"" . $filename . "\"\r\n";
1041
+ $state["data"] .= "Content-Type: " . $type . "\r\n";
1042
+ $state["data"] .= "\r\n";
1043
+
1044
+ if (!isset($state["currentfile"]["datafile"]))
1045
+ {
1046
+ $state["data"] .= $state["currentfile"]["data"];
1047
+ $state["data"] .= "\r\n";
1048
+
1049
+ $state["currentfile"] = false;
1050
+ }
1051
+ else
1052
+ {
1053
+ $state["currentfile"]["fp"] = @fopen($state["currentfile"]["datafile"], "rb");
1054
+ if ($state["currentfile"]["fp"] === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("The file '%s' does not exist.", $state["currentfile"]["datafile"]), "errorcode" => "file_does_not_exist"));
1055
+ }
1056
+ }
1057
+
1058
+ // Process the next chunk of file information.
1059
+ if ($state["currentfile"] !== false && isset($state["currentfile"]["fp"]))
1060
+ {
1061
+ // Read/Write up to 65K at a time.
1062
+ if ($state["currentfile"]["filesize"] >= 65536)
1063
+ {
1064
+ $data2 = fread($state["currentfile"]["fp"], 65536);
1065
+ if ($data2 === false || strlen($data2) !== 65536) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A read error was encountered with the file '%s'.", $state["currentfile"]["datafile"]), "errorcode" => "file_read"));
1066
+
1067
+ $state["data"] .= $data2;
1068
+
1069
+ $state["currentfile"]["filesize"] -= 65536;
1070
+ }
1071
+ else
1072
+ {
1073
+ // Read in the rest.
1074
+ if ($state["currentfile"]["filesize"] > 0)
1075
+ {
1076
+ $data2 = fread($state["currentfile"]["fp"], $state["currentfile"]["filesize"]);
1077
+ if ($data2 === false || strlen($data2) != $state["currentfile"]["filesize"]) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A read error was encountered with the file '%s'.", $state["currentfile"]["datafile"]), "errorcode" => "file_read"));
1078
+
1079
+ $state["data"] .= $data2;
1080
+ }
1081
+
1082
+ $state["data"] .= "\r\n";
1083
+
1084
+ fclose($state["currentfile"]["fp"]);
1085
+
1086
+ $state["currentfile"] = false;
1087
+ }
1088
+ }
1089
+
1090
+ // If there is no more data, write out the closing MIME line.
1091
+ if ($state["data"] === "") $state["data"] = "--" . $state["mime"] . "--\r\n";
1092
+
1093
+ $state["bodysize"] -= strlen($state["data"]);
1094
+ }
1095
+ else if ($state["bodysize"] === false || $state["bodysize"] > 0)
1096
+ {
1097
+ return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A weird internal HTTP error that should never, ever happen...just happened."), "errorcode" => "impossible"));
1098
+ }
1099
+
1100
+ // All done sending data.
1101
+ if ($state["data"] === "")
1102
+ {
1103
+ if ($state["client"]) $state["state"] = "receive_switch";
1104
+ else
1105
+ {
1106
+ $state["result"]["endts"] = microtime(true);
1107
+
1108
+ if ($state["close"]) fclose($state["fp"]);
1109
+ else $state["result"]["fp"] = $state["fp"];
1110
+
1111
+ return $state["result"];
1112
+ }
1113
+ }
1114
+
1115
+ break;
1116
+ }
1117
+ case "receive_switch":
1118
+ {
1119
+ if (function_exists("stream_select") && $state["async"])
1120
+ {
1121
+ $readfp = array($state["fp"]);
1122
+ $writefp = NULL;
1123
+ $exceptfp = NULL;
1124
+ if ($state["debug"]) $result = stream_select($readfp, $writefp, $exceptfp, 0);
1125
+ else $result = @stream_select($readfp, $writefp, $exceptfp, 0);
1126
+ if ($result === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("A stream_select() failure occurred. Most likely cause: Connection failure."), "errorcode" => "stream_select_failed"));
1127
+
1128
+ if (!count($readfp)) return array("success" => false, "error" => self::HTTPTranslate("Connection not fully established yet."), "errorcode" => "no_data");
1129
+ }
1130
+
1131
+ $state["state"] = "done";
1132
+
1133
+ break;
1134
+ }
1135
+ }
1136
+ }
1137
+
1138
+ // The request has been sent. Change the state to a response state.
1139
+ $state = self::InitResponseState($state["fp"], $state["debug"], $state["options"], $state["startts"], $state["timeout"], $state["result"], $state["close"], $state["nextread"]);
1140
+
1141
+ // Run one cycle.
1142
+ return self::ProcessState($state);
1143
+ }
1144
+ else if ($state["type"] === "response")
1145
+ {
1146
+ while ($state["state"] !== "done")
1147
+ {
1148
+ switch ($state["state"])
1149
+ {
1150
+ case "response_line":
1151
+ {
1152
+ $result = self::ProcessState__ReadLine($state);
1153
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
1154
+
1155
+ // Parse the response line.
1156
+ $pos = strpos($state["data"], "\n");
1157
+ if ($pos === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Unable to retrieve response line."), "errorcode" => "get_response_line"));
1158
+ $line = trim(substr($state["data"], 0, $pos));
1159
+ $state["data"] = substr($state["data"], $pos + 1);
1160
+ $state["rawrecvheadersize"] += $pos + 1;
1161
+ $response = explode(" ", $line, 3);
1162
+
1163
+ $state["result"]["response"] = array(
1164
+ "line" => $line,
1165
+ "httpver" => strtoupper($response[0]),
1166
+ "code" => $response[1],
1167
+ "meaning" => (isset($response[2]) ? $response[2] : "")
1168
+ );
1169
+
1170
+ $state["state"] = "headers";
1171
+ $state["result"]["headers"] = array();
1172
+ $state["lastheader"] = "";
1173
+
1174
+ break;
1175
+ }
1176
+ case "request_line":
1177
+ {
1178
+ // Server mode only.
1179
+ $result = self::ProcessState__ReadLine($state);
1180
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
1181
+
1182
+ // Parse the request line.
1183
+ $pos = strpos($state["data"], "\n");
1184
+ if ($pos === false) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Unable to retrieve request line."), "errorcode" => "get_request_line"));
1185
+ $line = trim(substr($state["data"], 0, $pos));
1186
+ $state["data"] = substr($state["data"], $pos + 1);
1187
+ $state["rawrecvheadersize"] += $pos + 1;
1188
+
1189
+ $request = $line;
1190
+ $pos = strpos($request, " ");
1191
+ if ($pos === false) $pos = strlen($request);
1192
+ $method = (string)substr($request, 0, $pos);
1193
+ $request = trim(substr($request, $pos));
1194
+
1195
+ $pos = strrpos($request, " ");
1196
+ if ($pos === false) $pos = strlen($request);
1197
+ $path = trim(substr($request, 0, $pos));
1198
+ if ($path === "") $path = "/";
1199
+ $version = (string)substr($request, $pos + 1);
1200
+
1201
+ $state["result"]["request"] = array(
1202
+ "line" => $line,
1203
+ "method" => strtoupper($method),
1204
+ "path" => $path,
1205
+ "httpver" => strtoupper($version),
1206
+ );
1207
+
1208
+ // Fake the response line to bypass some client-only code.
1209
+ $state["result"]["response"] = array(
1210
+ "line" => "200",
1211
+ "httpver" => "",
1212
+ "code" => 200,
1213
+ "meaning" => ""
1214
+ );
1215
+
1216
+ $state["state"] = "headers";
1217
+ $state["result"]["headers"] = array();
1218
+ $state["lastheader"] = "";
1219
+
1220
+ break;
1221
+ }
1222
+ case "headers":
1223
+ case "body_chunked_headers":
1224
+ {
1225
+ $result = self::ProcessState__ReadLine($state);
1226
+ if (!$result["success"] && ($state["state"] === "headers" || ($result["errorcode"] !== "stream_read_error" && $result["errorcode"] !== "peer_disconnected"))) return self::CleanupErrorState($state, $result);
1227
+
1228
+ $pos = strpos($state["data"], "\n");
1229
+ if ($pos === false) $pos = strlen($state["data"]);
1230
+ $header = rtrim(substr($state["data"], 0, $pos));
1231
+ $state["data"] = substr($state["data"], $pos + 1);
1232
+ $state["rawrecvheadersize"] += $pos + 1;
1233
+ if ($header != "")
1234
+ {
1235
+ if ($state["lastheader"] != "" && (substr($header, 0, 1) == " " || substr($header, 0, 1) == "\t")) $state["result"]["headers"][$state["lastheader"]][count($state["result"]["headers"][$state["lastheader"]]) - 1] .= $header;
1236
+ else
1237
+ {
1238
+ $pos = strpos($header, ":");
1239
+ if ($pos === false) $pos = strlen($header);
1240
+ $state["lastheader"] = self::HeaderNameCleanup(substr($header, 0, $pos));
1241
+ if (!isset($state["result"]["headers"][$state["lastheader"]])) $state["result"]["headers"][$state["lastheader"]] = array();
1242
+ $state["result"]["headers"][$state["lastheader"]][] = ltrim(substr($header, $pos + 1));
1243
+ }
1244
+
1245
+ $state["numheaders"]++;
1246
+ if (isset($state["options"]["maxheaders"]) && $state["numheaders"] > $state["options"]["maxheaders"]) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("The number of headers exceeded the limit."), "errorcode" => "headers_limit_exceeded"));
1247
+ }
1248
+ else
1249
+ {
1250
+ if ($state["result"]["response"]["code"] != 100 && isset($state["options"]["read_headers_callback"]) && is_callable($state["options"]["read_headers_callback"]))
1251
+ {
1252
+ if (!call_user_func_array($state["options"]["read_headers_callback"], array(&$state["result"][($state["client"] ? "response" : "request")], &$state["result"]["headers"], &$state["options"]["read_headers_callback_opts"]))) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Read headers callback returned with a failure condition."), "errorcode" => "read_header_callback"));
1253
+ }
1254
+
1255
+ // Additional headers (optional) are the last bit of data in a chunked response.
1256
+ if ($state["state"] === "body_chunked_headers") $state["state"] = "body_finalize";
1257
+ else
1258
+ {
1259
+ $state["result"]["body"] = "";
1260
+
1261
+ // Handle 100 Continue below OR WebSocket among other things by letting the caller handle reading the body.
1262
+ if ($state["result"]["response"]["code"] == 100 || $state["result"]["response"]["code"] == 101) $state["state"] = "done";
1263
+ else
1264
+ {
1265
+ // Determine if decoding the content is possible and necessary.
1266
+ if ($state["autodecode"] && !isset($state["result"]["headers"]["Content-Encoding"]) || (strtolower($state["result"]["headers"]["Content-Encoding"][0]) != "gzip" && strtolower($state["result"]["headers"]["Content-Encoding"][0]) != "deflate")) $state["autodecode"] = false;
1267
+ if (!$state["autodecode"]) $state["autodecode_ds"] = false;
1268
+ else
1269
+ {
1270
+ if (!class_exists("DeflateStream", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/deflate_stream.php";
1271
+
1272
+ // Since servers and browsers do everything wrong, ignore the encoding claim and attempt to auto-detect the encoding.
1273
+ $state["autodecode_ds"] = new DeflateStream();
1274
+ $state["autodecode_ds"]->Init("rb", -1, array("type" => "auto"));
1275
+ }
1276
+
1277
+ // Use the appropriate state for handling the next bit of input.
1278
+ if (isset($state["result"]["headers"]["Transfer-Encoding"]) && strtolower($state["result"]["headers"]["Transfer-Encoding"][0]) == "chunked")
1279
+ {
1280
+ $state["state"] = "body_chunked_size";
1281
+ }
1282
+ else
1283
+ {
1284
+ $state["sizeleft"] = (isset($state["result"]["headers"]["Content-Length"]) ? (double)preg_replace('/[^0-9]/', "", $state["result"]["headers"]["Content-Length"][0]) : false);
1285
+ $state["state"] = ($state["sizeleft"] !== false || $state["client"] ? "body_content" : "done");
1286
+ }
1287
+
1288
+ // Let servers have a chance to alter limits before processing the input body.
1289
+ if (!$state["client"] && $state["state"] !== "done") return array("success" => false, "error" => self::HTTPTranslate("Intermission for adjustments to limits."), "errorcode" => "no_data");
1290
+ }
1291
+ }
1292
+ }
1293
+
1294
+ break;
1295
+ }
1296
+ case "body_chunked_size":
1297
+ {
1298
+ $result = self::ProcessState__ReadLine($state);
1299
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
1300
+
1301
+ $pos = strpos($state["data"], "\n");
1302
+ if ($pos === false) $pos = strlen($state["data"]);
1303
+ $line = trim(substr($state["data"], 0, $pos));
1304
+ $state["data"] = substr($state["data"], $pos + 1);
1305
+ $pos = strpos($line, ";");
1306
+ if ($pos === false) $pos = strlen($line);
1307
+ $size = hexdec(substr($line, 0, $pos));
1308
+ if ($size < 0) $size = 0;
1309
+
1310
+ // Retrieve content.
1311
+ $size2 = $size;
1312
+ $size3 = min(strlen($state["data"]), $size);
1313
+ if ($size3 > 0)
1314
+ {
1315
+ $data2 = substr($state["data"], 0, $size3);
1316
+ $state["data"] = substr($state["data"], $size3);
1317
+ $size2 -= $size3;
1318
+
1319
+ if ($state["result"]["response"]["code"] == 100 || !isset($state["options"]["read_body_callback"]) || !is_callable($state["options"]["read_body_callback"])) $state["result"]["body"] .= self::GetDecodedBody($state["autodecode_ds"], $data2);
1320
+ else if (!call_user_func_array($state["options"]["read_body_callback"], array($state["result"][($state["client"] ? "response" : "request")], self::GetDecodedBody($state["autodecode_ds"], $data2), &$state["options"]["read_body_callback_opts"]))) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"));
1321
+ }
1322
+
1323
+ $state["chunksize"] = $size;
1324
+ $state["sizeleft"] = $size2;
1325
+ $state["state"] = "body_chunked_data";
1326
+
1327
+ break;
1328
+ }
1329
+ case "body_chunked_data":
1330
+ {
1331
+ $result = self::ProcessState__ReadBodyData($state);
1332
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
1333
+
1334
+ if ($state["chunksize"] > 0) $state["state"] = "body_chunked_skipline";
1335
+ else
1336
+ {
1337
+ $state["lastheader"] = "";
1338
+ $state["state"] = "body_chunked_headers";
1339
+ }
1340
+
1341
+ break;
1342
+ }
1343
+ case "body_chunked_skipline":
1344
+ {
1345
+ $result = self::ProcessState__ReadLine($state);
1346
+ if (!$result["success"]) return self::CleanupErrorState($state, $result);
1347
+
1348
+ // Ignore one newline.
1349
+ $pos = strpos($state["data"], "\n");
1350
+ if ($pos === false) $pos = strlen($state["data"]);
1351
+ $state["data"] = substr($state["data"], $pos + 1);
1352
+
1353
+ $state["state"] = "body_chunked_size";
1354
+
1355
+ break;
1356
+ }
1357
+ case "body_content":
1358
+ {
1359
+ $result = self::ProcessState__ReadBodyData($state);
1360
+ if (!$result["success"] && (($state["sizeleft"] !== false && $state["sizeleft"] > 0) || ($state["sizeleft"] === false && $result["errorcode"] !== "stream_read_error" && $result["errorcode"] !== "peer_disconnected" && $result["errorcode"] !== "stream_timeout_exceeded"))) return self::CleanupErrorState($state, $result);
1361
+
1362
+ $state["state"] = "body_finalize";
1363
+
1364
+ break;
1365
+ }
1366
+ case "body_finalize":
1367
+ {
1368
+ if ($state["autodecode_ds"] !== false)
1369
+ {
1370
+ $state["autodecode_ds"]->Finalize();
1371
+ $data2 = $state["autodecode_ds"]->Read();
1372
+
1373
+ if ($state["result"]["response"]["code"] == 100 || !isset($state["options"]["read_body_callback"]) || !is_callable($state["options"]["read_body_callback"])) $state["result"]["body"] .= $data2;
1374
+ else if (!call_user_func_array($state["options"]["read_body_callback"], array($state["result"][($state["client"] ? "response" : "request")], $data2, &$state["options"]["read_body_callback_opts"]))) return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Read body callback returned with a failure condition."), "errorcode" => "read_body_callback"));
1375
+ }
1376
+
1377
+ $state["state"] = "done";
1378
+
1379
+ break;
1380
+ }
1381
+ }
1382
+
1383
+ // Handle HTTP 100 Continue status codes.
1384
+ if ($state["state"] === "done" && $state["result"]["response"]["code"] == 100)
1385
+ {
1386
+ $state["autodecode"] = (!isset($state["options"]["auto_decode"]) || $state["options"]["auto_decode"]);
1387
+ $state["state"] = "response";
1388
+ $state["result"]["response"] = false;
1389
+ $state["result"]["headers"] = false;
1390
+ $state["result"]["body"] = false;
1391
+ }
1392
+ }
1393
+
1394
+ if ($state["debug"]) $state["result"]["rawrecv"] .= $state["rawdata"];
1395
+ $state["result"]["rawrecvsize"] += $state["rawsize"];
1396
+ $state["result"]["rawrecvheadersize"] += $state["rawrecvheadersize"];
1397
+ $state["result"]["endts"] = microtime(true);
1398
+
1399
+ if ($state["close"] || ($state["client"] && isset($state["result"]["headers"]["Connection"]) && strtolower($state["result"]["headers"]["Connection"][0]) === "close")) fclose($state["fp"]);
1400
+ else $state["result"]["fp"] = $state["fp"];
1401
+
1402
+ return $state["result"];
1403
+ }
1404
+ else
1405
+ {
1406
+ return self::CleanupErrorState($state, array("success" => false, "error" => self::HTTPTranslate("Invalid 'type' in state tracker."), "errorcode" => "invalid_type"));
1407
+ }
1408
+ }
1409
+
1410
+ public static function RawFileSize($fileorname)
1411
+ {
1412
+ if (is_resource($fileorname)) $fp = $fileorname;
1413
+ else
1414
+ {
1415
+ $fp = @fopen($fileorname, "rb");
1416
+ if ($fp === false) return 0;
1417
+ }
1418
+
1419
+ if (PHP_INT_SIZE < 8)
1420
+ {
1421
+ $pos = 0;
1422
+ $size = 1073741824;
1423
+ fseek($fp, 0, SEEK_SET);
1424
+ while ($size > 1)
1425
+ {
1426
+ if (fseek($fp, $size, SEEK_CUR) === -1) break;
1427
+
1428
+ if (fgetc($fp) === false)
1429
+ {
1430
+ fseek($fp, -$size, SEEK_CUR);
1431
+ $size = (int)($size / 2);
1432
+ }
1433
+ else
1434
+ {
1435
+ fseek($fp, -1, SEEK_CUR);
1436
+ $pos += $size;
1437
+ }
1438
+ }
1439
+
1440
+ if ($size > 1)
1441
+ {
1442
+ // Unfortunately, fseek() failed for some reason. Going to have to do this the old-fashioned way.
1443
+ do
1444
+ {
1445
+ $data = fread($fp, 10485760);
1446
+ if ($data === false) $data = "";
1447
+ $pos += strlen($data);
1448
+ } while ($data !== "");
1449
+ }
1450
+ else
1451
+ {
1452
+ while (fgetc($fp) !== false) $pos++;
1453
+ }
1454
+ }
1455
+ else
1456
+ {
1457
+ fseek($fp, 0, SEEK_END);
1458
+ $pos = ftell($fp);
1459
+ }
1460
+
1461
+ if (!is_resource($fileorname)) fclose($fp);
1462
+
1463
+ return $pos;
1464
+ }
1465
+
1466
+ public static function RetrieveWebpage($url, $options = array())
1467
+ {
1468
+ $startts = microtime(true);
1469
+ $timeout = (isset($options["timeout"]) ? $options["timeout"] : false);
1470
+
1471
+ if (!function_exists("stream_socket_client") && !function_exists("fsockopen")) return array("success" => false, "error" => self::HTTPTranslate("The functions 'stream_socket_client' and 'fsockopen' do not exist."), "errorcode" => "function_check");
1472
+
1473
+ // Process the URL.
1474
+ $url = trim($url);
1475
+ $url = self::ExtractURL($url);
1476
+
1477
+ if ($url["scheme"] != "http" && $url["scheme"] != "https") return array("success" => false, "error" => self::HTTPTranslate("RetrieveWebpage() only supports the 'http' and 'https' protocols."), "errorcode" => "protocol_check");
1478
+
1479
+ $secure = ($url["scheme"] == "https");
1480
+ $async = (isset($options["async"]) ? $options["async"] : false);
1481
+ $protocol = ($secure && !$async ? (isset($options["protocol"]) ? strtolower($options["protocol"]) : "ssl") : "tcp");
1482
+ if (function_exists("stream_get_transports") && !in_array($protocol, stream_get_transports())) return array("success" => false, "error" => self::HTTPTranslate("The desired transport protocol '%s' is not installed.", $protocol), "errorcode" => "transport_not_installed");
1483
+ $host = str_replace(" ", "-", self::HeaderValueCleanup($url["host"]));
1484
+ if ($host == "") return array("success" => false, "error" => self::HTTPTranslate("Invalid URL."));
1485
+ $port = ((int)$url["port"] ? (int)$url["port"] : ($secure ? 443 : 80));
1486
+ $defaultport = ((!$secure && $port == 80) || ($secure && $port == 443));
1487
+ $path = ($url["path"] == "" ? "/" : $url["path"]);
1488
+ $query = $url["query"];
1489
+ $username = $url["loginusername"];
1490
+ $password = $url["loginpassword"];
1491
+
1492
+ // Cleanup input headers.
1493
+ if (!isset($options["headers"])) $options["headers"] = array();
1494
+ $options["headers"] = self::NormalizeHeaders($options["headers"]);
1495
+ if (isset($options["rawheaders"])) self::MergeRawHeaders($options["headers"], $options["rawheaders"]);
1496
+
1497
+ // Process the proxy URL (if specified).
1498
+ $useproxy = (isset($options["proxyurl"]) && trim($options["proxyurl"]) != "");
1499
+ $proxysecure = false;
1500
+ $proxyconnect = false;
1501
+ $proxydata = "";
1502
+ if ($useproxy)
1503
+ {
1504
+ $proxyurl = trim($options["proxyurl"]);
1505
+ $proxyurl = self::ExtractURL($proxyurl);
1506
+
1507
+ $proxysecure = ($proxyurl["scheme"] == "https");
1508
+ if ($proxysecure && $secure) return array("success" => false, "error" => self::HTTPTranslate("The PHP SSL sockets implementation does not support tunneled SSL/TLS connections over SSL/TLS."), "errorcode" => "multi_ssl_tunneling_not_supported");
1509
+ $proxyprotocol = ($proxysecure && !$async ? (isset($options["proxyprotocol"]) ? strtolower($options["proxyprotocol"]) : "ssl") : "tcp");
1510
+ if (function_exists("stream_get_transports") && !in_array($proxyprotocol, stream_get_transports())) return array("success" => false, "error" => self::HTTPTranslate("The desired transport proxy protocol '%s' is not installed.", $proxyprotocol), "errorcode" => "proxy_transport_not_installed");
1511
+ $proxyhost = str_replace(" ", "-", self::HeaderValueCleanup($proxyurl["host"]));
1512
+ if ($proxyhost === "") return array("success" => false, "error" => self::HTTPTranslate("The specified proxy URL is not a URL. Prefix 'proxyurl' with http:// or https://"), "errorcode" => "invalid_proxy_url");
1513
+ $proxyport = ((int)$proxyurl["port"] ? (int)$proxyurl["port"] : ($proxysecure ? 443 : 80));
1514
+ $proxypath = ($proxyurl["path"] == "" ? "/" : $proxyurl["path"]);
1515
+ $proxyusername = $proxyurl["loginusername"];
1516
+ $proxypassword = $proxyurl["loginpassword"];
1517
+
1518
+ // Open a tunnel instead of letting the proxy modify the request (HTTP CONNECT).
1519
+ $proxyconnect = (isset($options["proxyconnect"]) && $options["proxyconnect"] ? $options["proxyconnect"] : false);
1520
+ if ($proxyconnect)
1521
+ {
1522
+ $proxydata = "CONNECT " . $host . ":" . $port . " HTTP/1.1\r\n";
1523
+ if (isset($options["headers"]["User-Agent"])) $proxydata .= "User-Agent: " . $options["headers"]["User-Agent"] . "\r\n";
1524
+ $proxydata .= "Host: " . $host . ($defaultport ? "" : ":" . $port) . "\r\n";
1525
+ $proxydata .= "Proxy-Connection: keep-alive\r\n";
1526
+ if ($proxyusername != "") $proxydata .= "Proxy-Authorization: BASIC " . base64_encode($proxyusername . ":" . $proxypassword) . "\r\n";
1527
+ if (!isset($options["proxyheaders"])) $options["proxyheaders"] = array();
1528
+ $options["proxyheaders"] = self::NormalizeHeaders($options["proxyheaders"]);
1529
+ if (isset($options["rawproxyheaders"])) self::MergeRawHeaders($options["proxyheaders"], $options["rawproxyheaders"]);
1530
+
1531
+ unset($options["proxyheaders"]["Accept-Encoding"]);
1532
+ foreach ($options["proxyheaders"] as $name => $val)
1533
+ {
1534
+ if ($name != "Content-Type" && $name != "Content-Length" && $name != "Proxy-Connection" && $name != "Host") $proxydata .= $name . ": " . $val . "\r\n";
1535
+ }
1536
+
1537
+ $proxydata .= "\r\n";
1538
+ if (isset($options["debug_callback"]) && is_callable($options["debug_callback"])) call_user_func_array($options["debug_callback"], array("rawproxyheaders", $proxydata, &$options["debug_callback_opts"]));
1539
+ }
1540
+ }
1541
+
1542
+ // Process the method.
1543
+ if (!isset($options["method"]))
1544
+ {
1545
+ if ((isset($options["write_body_callback"]) && is_callable($options["write_body_callback"])) || isset($options["body"])) $options["method"] = "PUT";
1546
+ else if (isset($options["postvars"]) || (isset($options["files"]) && count($options["files"]))) $options["method"] = "POST";
1547
+ else $options["method"] = "GET";
1548
+ }
1549
+ $options["method"] = preg_replace('/[^A-Z]/', "", strtoupper($options["method"]));
1550
+
1551
+ // Process the HTTP version.
1552
+ if (!isset($options["httpver"])) $options["httpver"] = "1.1";
1553
+ $options["httpver"] = preg_replace('/[^0-9.]/', "", $options["httpver"]);
1554
+
1555
+ // Process the request.
1556
+ $data = $options["method"] . " ";
1557
+ $data .= ($useproxy && !$proxyconnect ? $url["scheme"] . "://" . $host . ":" . $port : "") . $path . ($query != "" ? "?" . $query : "");
1558
+ $data .= " HTTP/" . $options["httpver"] . "\r\n";
1559
+
1560
+ // Process the headers.
1561
+ if ($useproxy && !$proxyconnect && $proxyusername != "") $data .= "Proxy-Authorization: BASIC " . base64_encode($proxyusername . ":" . $proxypassword) . "\r\n";
1562
+ if ($username != "") $data .= "Authorization: BASIC " . base64_encode($username . ":" . $password) . "\r\n";
1563
+ $ver = explode(".", $options["httpver"]);
1564
+ if ((int)$ver[0] > 1 || ((int)$ver[0] == 1 && (int)$ver[1] >= 1))
1565
+ {
1566
+ if (!isset($options["headers"]["Host"])) $options["headers"]["Host"] = $host . ($defaultport ? "" : ":" . $port);
1567
+ $data .= "Host: " . $options["headers"]["Host"] . "\r\n";
1568
+ }
1569
+
1570
+ if (!isset($options["headers"]["Connection"])) $options["headers"]["Connection"] = "close";
1571
+ $data .= "Connection: " . $options["headers"]["Connection"] . "\r\n";
1572
+
1573
+ foreach ($options["headers"] as $name => $val)
1574
+ {
1575
+ if ($name != "Content-Type" && $name != "Content-Length" && $name != "Connection" && $name != "Host") $data .= $name . ": " . $val . "\r\n";
1576
+ }
1577
+
1578
+ if (isset($options["files"]) && !count($options["files"])) unset($options["files"]);
1579
+
1580
+ // Process the body.
1581
+ $mime = "";
1582
+ $body = "";
1583
+ $bodysize = 0;
1584
+ if (isset($options["write_body_callback"]) && is_callable($options["write_body_callback"]))
1585
+ {
1586
+ if (isset($options["headers"]["Content-Type"])) $data .= "Content-Type: " . $options["headers"]["Content-Type"] . "\r\n";
1587
+
1588
+ call_user_func_array($options["write_body_callback"], array(&$body, &$bodysize, &$options["write_body_callback_opts"]));
1589
+ }
1590
+ else if (isset($options["body"]))
1591
+ {
1592
+ if (isset($options["headers"]["Content-Type"])) $data .= "Content-Type: " . $options["headers"]["Content-Type"] . "\r\n";
1593
+
1594
+ $body = $options["body"];
1595
+ $bodysize = strlen($body);
1596
+ unset($options["body"]);
1597
+ }
1598
+ else if ((isset($options["files"]) && count($options["files"])) || (isset($options["headers"]["Content-Type"]) && stripos($options["headers"]["Content-Type"], "multipart/form-data") !== false))
1599
+ {
1600
+ $mime = "--------" . substr(sha1(uniqid(mt_rand(), true)), 0, 25);
1601
+ $data .= "Content-Type: multipart/form-data; boundary=" . $mime . "\r\n";
1602
+ if (isset($options["postvars"]))
1603
+ {
1604
+ foreach ($options["postvars"] as $name => $val)
1605
+ {
1606
+ $name = self::HeaderValueCleanup($name);
1607
+ $name = str_replace("\"", "", $name);
1608
+
1609
+ if (!is_array($val))
1610
+ {
1611
+ if (is_string($val) || is_numeric($val)) $val = array($val);
1612
+ else return array("success" => false, "error" => "A supplied 'postvars' value is an invalid type. Expected string, numeric, or array.", "errorcode" => "invalid_postvars_value", "info" => array("name" => $name, "val" => $val));
1613
+ }
1614
+
1615
+ foreach ($val as $val2)
1616
+ {
1617
+ $body .= "--" . $mime . "\r\n";
1618
+ $body .= "Content-Disposition: form-data; name=\"" . $name . "\"\r\n";
1619
+ $body .= "\r\n";
1620
+ $body .= $val2 . "\r\n";
1621
+ }
1622
+ }
1623
+
1624
+ unset($options["postvars"]);
1625
+ }
1626
+
1627
+ $bodysize = strlen($body);
1628
+
1629
+ // Only count the amount of data to send.
1630
+ if (!isset($options["files"])) $options["files"] = array();
1631
+ foreach ($options["files"] as $num => $info)
1632
+ {
1633
+ $name = self::HeaderValueCleanup($info["name"]);
1634
+ $name = str_replace("\"", "", $name);
1635
+ $filename = self::FilenameSafe(self::ExtractFilename($info["filename"]));
1636
+ $type = self::HeaderValueCleanup($info["type"]);
1637
+
1638
+ $body2 = "--" . $mime . "\r\n";
1639
+ $body2 .= "Content-Disposition: form-data; name=\"" . $name . "\"; filename=\"" . $filename . "\"\r\n";
1640
+ $body2 .= "Content-Type: " . $type . "\r\n";
1641
+ $body2 .= "\r\n";
1642
+
1643
+ $info["filesize"] = (isset($info["datafile"]) ? self::RawFileSize($info["datafile"]) : strlen($info["data"]));
1644
+ $bodysize += strlen($body2) + $info["filesize"] + 2;
1645
+
1646
+ $options["files"][$num] = $info;
1647
+ }
1648
+
1649
+ $body2 = "--" . $mime . "--\r\n";
1650
+ $bodysize += strlen($body2);
1651
+ }
1652
+ else
1653
+ {
1654
+ if (isset($options["postvars"]))
1655
+ {
1656
+ foreach ($options["postvars"] as $name => $val)
1657
+ {
1658
+ $name = self::HeaderValueCleanup($name);
1659
+
1660
+ if (!is_array($val))
1661
+ {
1662
+ if (is_string($val) || is_numeric($val)) $val = array($val);
1663
+ else return array("success" => false, "error" => "A supplied 'postvars' value is an invalid type. Expected string, numeric, or array.", "errorcode" => "invalid_postvars_value", "info" => array("name" => $name, "val" => $val));
1664
+ }
1665
+
1666
+ foreach ($val as $val2) $body .= ($body != "" ? "&" : "") . urlencode($name) . "=" . urlencode($val2);
1667
+ }
1668
+
1669
+ unset($options["postvars"]);
1670
+ }
1671
+
1672
+ if ($body != "") $data .= "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
1673
+
1674
+ $bodysize = strlen($body);
1675
+ }
1676
+ if (($bodysize === false && strlen($body) > 0) || ($bodysize !== false && $bodysize < strlen($body))) $bodysize = strlen($body);
1677
+
1678
+ // Finalize the headers.
1679
+ if ($bodysize === false) $data .= "Transfer-Encoding: chunked\r\n";
1680
+ else if ($bodysize > 0 || $body != "" || $options["method"] == "POST") $data .= "Content-Length: " . $bodysize . "\r\n";
1681
+ $data .= "\r\n";
1682
+ if (isset($options["debug_callback"]) && is_callable($options["debug_callback"])) call_user_func_array($options["debug_callback"], array("rawheaders", $data, &$options["debug_callback_opts"]));
1683
+ $rawheadersize = strlen($data);
1684
+
1685
+ // Finalize the initial data to be sent.
1686
+ $data .= $body;
1687
+ if ($bodysize !== false) $bodysize -= strlen($body);
1688
+ $body = "";
1689
+ $result = array("success" => true, "rawsendsize" => 0, "rawsendheadersize" => $rawheadersize, "rawrecvsize" => 0, "rawrecvheadersize" => 0, "startts" => $startts);
1690
+ $debug = (isset($options["debug"]) && $options["debug"]);
1691
+ if ($debug)
1692
+ {
1693
+ $result["rawsend"] = "";
1694
+ $result["rawrecv"] = "";
1695
+ }
1696
+
1697
+ if ($timeout !== false && self::GetTimeLeft($startts, $timeout) == 0) return array("success" => false, "error" => self::HTTPTranslate("HTTP timeout exceeded."), "errorcode" => "timeout_exceeded");
1698
+
1699
+ // Connect to the target server.
1700
+ $errornum = 0;
1701
+ $errorstr = "";
1702
+ if (isset($options["fp"]) && is_resource($options["fp"]))
1703
+ {
1704
+ $fp = $options["fp"];
1705
+ unset($options["fp"]);
1706
+
1707
+ $useproxy = false;
1708
+ $proxyconnect = false;
1709
+ $proxydata = "";
1710
+ }
1711
+ else if ($useproxy)
1712
+ {
1713
+ if (!isset($options["proxyconnecttimeout"])) $options["proxyconnecttimeout"] = 10;
1714
+ $timeleft = self::GetTimeLeft($startts, $timeout);
1715
+ if ($timeleft !== false) $options["proxyconnecttimeout"] = min($options["proxyconnecttimeout"], $timeleft);
1716
+ if (!function_exists("stream_socket_client"))
1717
+ {
1718
+ if ($debug) $fp = fsockopen($proxyprotocol . "://" . $proxyhost, $proxyport, $errornum, $errorstr, $options["proxyconnecttimeout"]);
1719
+ else $fp = @fsockopen($proxyprotocol . "://" . $proxyhost, $proxyport, $errornum, $errorstr, $options["proxyconnecttimeout"]);
1720
+ }
1721
+ else
1722
+ {
1723
+ $context = @stream_context_create();
1724
+ if (isset($options["source_ip"])) $context["socket"] = array("bindto" => $options["source_ip"] . ":0");
1725
+ if ($proxysecure)
1726
+ {
1727
+ if (!isset($options["proxysslopts"]) || !is_array($options["proxysslopts"])) $options["proxysslopts"] = self::GetSafeSSLOpts();
1728
+ self::ProcessSSLOptions($options, "proxysslopts", $host);
1729
+ foreach ($options["proxysslopts"] as $key => $val) @stream_context_set_option($context, "ssl", $key, $val);
1730
+ }
1731
+ else if ($secure)
1732
+ {
1733
+ if (!isset($options["sslopts"]) || !is_array($options["sslopts"])) $options["sslopts"] = self::GetSafeSSLOpts();
1734
+ self::ProcessSSLOptions($options, "sslopts", $host);
1735
+ foreach ($options["sslopts"] as $key => $val) @stream_context_set_option($context, "ssl", $key, $val);
1736
+ }
1737
+
1738
+ if ($debug) $fp = stream_socket_client($proxyprotocol . "://" . $proxyhost . ":" . $proxyport, $errornum, $errorstr, $options["proxyconnecttimeout"], ($async ? STREAM_CLIENT_ASYNC_CONNECT : STREAM_CLIENT_CONNECT), $context);
1739
+ else $fp = @stream_socket_client($proxyprotocol . "://" . $proxyhost . ":" . $proxyport, $errornum, $errorstr, $options["proxyconnecttimeout"], ($async ? STREAM_CLIENT_ASYNC_CONNECT : STREAM_CLIENT_CONNECT), $context);
1740
+ }
1741
+
1742
+ if ($fp === false) return array("success" => false, "error" => self::HTTPTranslate("Unable to establish a connection to '%s'.", ($proxysecure ? $proxyprotocol . "://" : "") . $proxyhost . ":" . $proxyport), "info" => $errorstr . " (" . $errornum . ")", "errorcode" => "proxy_connect");
1743
+ }
1744
+ else
1745
+ {
1746
+ if (!isset($options["connecttimeout"])) $options["connecttimeout"] = 10;
1747
+ $timeleft = self::GetTimeLeft($startts, $timeout);
1748
+ if ($timeleft !== false) $options["connecttimeout"] = min($options["connecttimeout"], $timeleft);
1749
+ if (!function_exists("stream_socket_client"))
1750
+ {
1751
+ if ($debug) $fp = fsockopen($protocol . "://" . $host, $port, $errornum, $errorstr, $options["connecttimeout"]);
1752
+ else $fp = @fsockopen($protocol . "://" . $host, $port, $errornum, $errorstr, $options["connecttimeout"]);
1753
+ }
1754
+ else
1755
+ {
1756
+ $context = @stream_context_create();
1757
+ if (isset($options["source_ip"])) $context["socket"] = array("bindto" => $options["source_ip"] . ":0");
1758
+ if ($secure)
1759
+ {
1760
+ if (!isset($options["sslopts"]) || !is_array($options["sslopts"])) $options["sslopts"] = self::GetSafeSSLOpts();
1761
+ self::ProcessSSLOptions($options, "sslopts", $host);
1762
+ foreach ($options["sslopts"] as $key => $val) @stream_context_set_option($context, "ssl", $key, $val);
1763
+ }
1764
+
1765
+ if ($debug) $fp = stream_socket_client($protocol . "://" . $host . ":" . $port, $errornum, $errorstr, $options["connecttimeout"], ($async ? STREAM_CLIENT_ASYNC_CONNECT : STREAM_CLIENT_CONNECT), $context);
1766
+ else $fp = @stream_socket_client($protocol . "://" . $host . ":" . $port, $errornum, $errorstr, $options["connecttimeout"], ($async ? STREAM_CLIENT_ASYNC_CONNECT : STREAM_CLIENT_CONNECT), $context);
1767
+ }
1768
+
1769
+ if ($fp === false) return array("success" => false, "error" => self::HTTPTranslate("Unable to establish a connection to '%s'.", ($secure ? $protocol . "://" : "") . $host . ":" . $port), "info" => $errorstr . " (" . $errornum . ")", "errorcode" => "connect_failed");
1770
+ }
1771
+
1772
+ if (function_exists("stream_set_blocking")) @stream_set_blocking($fp, ($async ? 0 : 1));
1773
+
1774
+ // Initialize the connection request state array.
1775
+ $state = array(
1776
+ "fp" => $fp,
1777
+ "type" => "request",
1778
+ "async" => $async,
1779
+ "debug" => $debug,
1780
+ "startts" => $startts,
1781
+ "timeout" => $timeout,
1782
+ "waituntil" => -1.0,
1783
+ "mime" => $mime,
1784
+ "data" => $data,
1785
+ "bodysize" => $bodysize,
1786
+ "chunked" => ($bodysize === false),
1787
+ "secure" => $secure,
1788
+ "useproxy" => $useproxy,
1789
+ "proxysecure" => $proxysecure,
1790
+ "proxyconnect" => $proxyconnect,
1791
+ "proxydata" => $proxydata,
1792
+ "currentfile" => false,
1793
+
1794
+ "state" => "connecting",
1795
+
1796
+ "options" => $options,
1797
+ "result" => $result,
1798
+ "close" => ($options["headers"]["Connection"] === "close"),
1799
+ "nextread" => "",
1800
+ "client" => true
1801
+ );
1802
+
1803
+ // Return the state for async calls. Caller must call ProcessState().
1804
+ if ($state["async"]) return array("success" => true, "state" => $state);
1805
+
1806
+ // Run through all of the valid states and return the result.
1807
+ return self::ProcessState($state);
1808
+ }
1809
+ }
1810
+ ?>
includes/vendor/ultimate-web-scraper/multi_async_helper.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP multiple asynchronous helper class.
3
+ // (C) 2015 CubicleSoft. All Rights Reserved.
4
+
5
+ class MultiAsyncHelper
6
+ {
7
+ private $objs, $queuedobjs, $limit;
8
+
9
+ public function __construct()
10
+ {
11
+ $this->objs = array();
12
+ $this->queuedobjs = array();
13
+ $this->limit = false;
14
+ }
15
+
16
+ public function SetConcurrencyLimit($limit)
17
+ {
18
+ $this->limit = $limit;
19
+ }
20
+
21
+ public function Set($key, $obj, $callback)
22
+ {
23
+ if (is_callable($callback))
24
+ {
25
+ $this->queuedobjs[$key] = array(
26
+ "obj" => $obj,
27
+ "callback" => $callback
28
+ );
29
+
30
+ unset($this->objs[$key]);
31
+ }
32
+ }
33
+
34
+ public function NumObjects()
35
+ {
36
+ return count($this->queuedobjs) + count($this->objs);
37
+ }
38
+
39
+ public function GetObject($key)
40
+ {
41
+ if (isset($this->queuedobjs[$key])) $result = $this->queuedobjs[$key]["obj"];
42
+ else if (isset($this->objs[$key])) $result = $this->objs[$key]["obj"];
43
+ else $result = false;
44
+
45
+ return $result;
46
+ }
47
+
48
+ // To be able to change a callback on the fly.
49
+ public function SetCallback($key, $callback)
50
+ {
51
+ if (is_callable($callback))
52
+ {
53
+ if (isset($this->queuedobjs[$key])) $this->queuedobjs[$key]["callback"] = $callback;
54
+ else if (isset($this->objs[$key])) $this->objs[$key]["callback"] = $callback;
55
+ }
56
+ }
57
+
58
+ private function InternalDetach($key, $cleanup)
59
+ {
60
+ if (isset($this->queuedobjs[$key]))
61
+ {
62
+ call_user_func_array($this->queuedobjs[$key]["callback"], array("cleanup", &$cleanup, $key, &$this->queuedobjs[$key]["obj"]));
63
+ $result = $this->queuedobjs[$key]["obj"];
64
+ unset($this->queuedobjs[$key]);
65
+ }
66
+ else if (isset($this->objs[$key]))
67
+ {
68
+ call_user_func_array($this->objs[$key]["callback"], array("cleanup", &$cleanup, $key, &$this->objs[$key]["obj"]));
69
+ $result = $this->objs[$key]["obj"];
70
+ unset($this->objs[$key]);
71
+ }
72
+ else
73
+ {
74
+ $result = false;
75
+ }
76
+
77
+ return $result;
78
+ }
79
+
80
+ public function Detach($key)
81
+ {
82
+ return $this->InternalDetach($key, false);
83
+ }
84
+
85
+ public function Remove($key)
86
+ {
87
+ return $this->InternalDetach($key, true);
88
+ }
89
+
90
+ // A few default functions for direct file/socket handles.
91
+ public static function ReadOnly($mode, &$data, $key, $fp)
92
+ {
93
+ switch ($mode)
94
+ {
95
+ case "init":
96
+ case "update":
97
+ {
98
+ // Move to/Keep in the live queue.
99
+ if (is_resource($fp)) $data = true;
100
+
101
+ break;
102
+ }
103
+ case "read":
104
+ case "write":
105
+ case "writefps":
106
+ {
107
+ break;
108
+ }
109
+ case "readfps":
110
+ {
111
+ $data[$key] = $fp;
112
+
113
+ break;
114
+ }
115
+ case "cleanup":
116
+ {
117
+ if ($data === true) @fclose($fp);
118
+
119
+ break;
120
+ }
121
+ }
122
+ }
123
+
124
+ public static function WriteOnly($mode, &$data, $key, $fp)
125
+ {
126
+ switch ($mode)
127
+ {
128
+ case "init":
129
+ case "update":
130
+ {
131
+ // Move to/Keep in the live queue.
132
+ if (is_resource($fp)) $data = true;
133
+
134
+ break;
135
+ }
136
+ case "read":
137
+ case "readfps":
138
+ case "write":
139
+ {
140
+ break;
141
+ }
142
+ case "writefps":
143
+ {
144
+ $data[$key] = $fp;
145
+
146
+ break;
147
+ }
148
+ case "cleanup":
149
+ {
150
+ if ($data === true) @fclose($fp);
151
+
152
+ break;
153
+ }
154
+ }
155
+ }
156
+
157
+ public static function ReadAndWrite($mode, &$data, $key, $fp)
158
+ {
159
+ switch ($mode)
160
+ {
161
+ case "init":
162
+ case "update":
163
+ {
164
+ // Move to/Keep in the live queue.
165
+ if (is_resource($fp)) $data = true;
166
+
167
+ break;
168
+ }
169
+ case "read":
170
+ case "write":
171
+ {
172
+ break;
173
+ }
174
+ case "readfps":
175
+ case "writefps":
176
+ {
177
+ $data[$key] = $fp;
178
+
179
+ break;
180
+ }
181
+ case "cleanup":
182
+ {
183
+ if ($data === true) @fclose($fp);
184
+
185
+ break;
186
+ }
187
+ }
188
+ }
189
+
190
+ public function Wait($timeout = false)
191
+ {
192
+ // Move queued objects to live.
193
+ $result2 = array("success" => true, "read" => array(), "write" => array(), "removed" => array(), "new" => array());
194
+ while (count($this->queuedobjs) && ($this->limit === false || count($this->objs) < $this->limit))
195
+ {
196
+ $info = reset($this->queuedobjs);
197
+ $key = key($this->queuedobjs);
198
+ unset($this->queuedobjs[$key]);
199
+
200
+ $result2["new"][$key] = $key;
201
+
202
+ $keep = false;
203
+ call_user_func_array($info["callback"], array("init", &$keep, $key, &$info["obj"]));
204
+
205
+ $this->objs[$key] = $info;
206
+
207
+ if (!$keep) $result2["removed"][$key] = $this->Remove($key);
208
+ }
209
+
210
+ // Walk the objects looking for read and write handles.
211
+ $readfps = array();
212
+ $writefps = array();
213
+ $exceptfps = NULL;
214
+ foreach ($this->objs as $key => &$info)
215
+ {
216
+ $keep = false;
217
+ call_user_func_array($info["callback"], array("update", &$keep, $key, &$info["obj"]));
218
+
219
+ if (!$keep) $result2["removed"][$key] = $this->Remove($key);
220
+ else
221
+ {
222
+ call_user_func_array($info["callback"], array("readfps", &$readfps, $key, &$info["obj"]));
223
+ call_user_func_array($info["callback"], array("writefps", &$writefps, $key, &$info["obj"]));
224
+ }
225
+ }
226
+ if (!count($readfps)) $readfps = NULL;
227
+ if (!count($writefps)) $writefps = NULL;
228
+
229
+ // Wait for something to happen.
230
+ if (isset($readfps) || isset($writefps))
231
+ {
232
+ if ($timeout === false) $timeout = NULL;
233
+ $readfps2 = $readfps;
234
+ $writefps2 = $writefps;
235
+ $result = @stream_select($readfps, $writefps, $exceptfps, $timeout);
236
+ if ($result === false) return array("success" => false, "error" => self::MAHTranslate("Wait() failed due to stream_select() failure. Most likely cause: Connection failure."), "errorcode" => "stream_select_failed");
237
+ else if ($result > 0)
238
+ {
239
+ if (isset($readfps))
240
+ {
241
+ $readfps3 = array();
242
+ foreach ($readfps as $key => $fp)
243
+ {
244
+ if (!isset($readfps2[$key]) || $readfps2[$key] !== $fp)
245
+ {
246
+ foreach ($readfps2 as $key2 => $fp2)
247
+ {
248
+ if ($fp === $fp2) $key = $key2;
249
+ }
250
+ }
251
+
252
+ if (isset($this->objs[$key]))
253
+ {
254
+ call_user_func_array($this->objs[$key]["callback"], array("read", &$fp, $key, &$this->objs[$key]["obj"]));
255
+
256
+ $readfps3[$key] = $fp;
257
+ }
258
+ }
259
+
260
+ $result2["read"] = $readfps3;
261
+ }
262
+
263
+ if (isset($writefps))
264
+ {
265
+ $writefps3 = array();
266
+ foreach ($writefps as $key => $fp)
267
+ {
268
+ if (!isset($writefps2[$key]) || $writefps2[$key] !== $fp)
269
+ {
270
+ foreach ($writefps2 as $key2 => $fp2)
271
+ {
272
+ if ($fp === $fp2) $key = $key2;
273
+ }
274
+ }
275
+
276
+ if (isset($this->objs[$key]))
277
+ {
278
+ call_user_func_array($this->objs[$key]["callback"], array("write", &$fp, $key, &$this->objs[$key]["obj"]));
279
+
280
+ $readfps3[$key] = $fp;
281
+ }
282
+ }
283
+
284
+ $result2["write"] = $writefps3;
285
+ }
286
+ }
287
+ }
288
+
289
+ $result2["numleft"] = count($this->queuedobjs) + count($this->objs);
290
+
291
+ return $result2;
292
+ }
293
+
294
+ public static function MAHTranslate()
295
+ {
296
+ $args = func_get_args();
297
+ if (!count($args)) return "";
298
+
299
+ return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args);
300
+ }
301
+ }
302
+ ?>
includes/vendor/ultimate-web-scraper/simple_html_dom.php ADDED
@@ -0,0 +1,975 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*******************************************************************************
3
+ Version: 1.11 ($Rev: 175 $)
4
+ Website: http://sourceforge.net/projects/simplehtmldom/
5
+ Author: S.C. Chen <me578022@gmail.com>
6
+ Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
7
+ Contributions by:
8
+ Yousuke Kumakura (Attribute filters)
9
+ Vadim Voituk (Negative indexes supports of "find" method)
10
+ Antcs (Constructor with automatically load contents either text or file/url)
11
+ Licensed under The MIT License
12
+ Redistributions of files must retain the above copyright notice.
13
+ *******************************************************************************/
14
+
15
+ define('HDOM_TYPE_ELEMENT', 1);
16
+ define('HDOM_TYPE_COMMENT', 2);
17
+ define('HDOM_TYPE_TEXT', 3);
18
+ define('HDOM_TYPE_ENDTAG', 4);
19
+ define('HDOM_TYPE_ROOT', 5);
20
+ define('HDOM_TYPE_UNKNOWN', 6);
21
+ define('HDOM_QUOTE_DOUBLE', 0);
22
+ define('HDOM_QUOTE_SINGLE', 1);
23
+ define('HDOM_QUOTE_NO', 3);
24
+ define('HDOM_INFO_BEGIN', 0);
25
+ define('HDOM_INFO_END', 1);
26
+ define('HDOM_INFO_QUOTE', 2);
27
+ define('HDOM_INFO_SPACE', 3);
28
+ define('HDOM_INFO_TEXT', 4);
29
+ define('HDOM_INFO_INNER', 5);
30
+ define('HDOM_INFO_OUTER', 6);
31
+ define('HDOM_INFO_ENDSPACE',7);
32
+
33
+ // helper functions
34
+ // -----------------------------------------------------------------------------
35
+ // get html dom form file
36
+ function file_get_html() {
37
+ $dom = new simple_html_dom;
38
+ $args = func_get_args();
39
+ $dom->load(call_user_func_array('file_get_contents', $args), true);
40
+ return $dom;
41
+ }
42
+
43
+ // get html dom form string
44
+ function str_get_html($str, $lowercase=true) {
45
+ $dom = new simple_html_dom;
46
+ $dom->load($str, $lowercase);
47
+ return $dom;
48
+ }
49
+
50
+ // dump html dom tree
51
+ function dump_html_tree($node, $show_attr=true, $deep=0) {
52
+ $lead = str_repeat(' ', $deep);
53
+ echo $lead.$node->tag;
54
+ if ($show_attr && count($node->attr)>0) {
55
+ echo '(';
56
+ foreach($node->attr as $k=>$v)
57
+ echo "[$k]=>\"".$node->$k.'", ';
58
+ echo ')';
59
+ }
60
+ echo "\n";
61
+
62
+ foreach($node->nodes as $c)
63
+ dump_html_tree($c, $show_attr, $deep+1);
64
+ }
65
+
66
+ // get dom form file (deprecated)
67
+ function file_get_dom() {
68
+ $dom = new simple_html_dom;
69
+ $args = func_get_args();
70
+ $dom->load(call_user_func_array('file_get_contents', $args), true);
71
+ return $dom;
72
+ }
73
+
74
+ // get dom form string (deprecated)
75
+ function str_get_dom($str, $lowercase=true) {
76
+ $dom = new simple_html_dom;
77
+ $dom->load($str, $lowercase);
78
+ return $dom;
79
+ }
80
+
81
+ // simple html dom node
82
+ // -----------------------------------------------------------------------------
83
+ class simple_html_dom_node {
84
+ public $nodetype = HDOM_TYPE_TEXT;
85
+ public $tag = 'text';
86
+ public $attr = array();
87
+ public $children = array();
88
+ public $nodes = array();
89
+ public $parent = null;
90
+ public $_ = array();
91
+ private $dom = null;
92
+
93
+ function __construct($dom) {
94
+ $this->dom = $dom;
95
+ $dom->nodes[] = $this;
96
+ }
97
+
98
+ function __destruct() {
99
+ $this->clear();
100
+ }
101
+
102
+ function __toString() {
103
+ return $this->outertext();
104
+ }
105
+
106
+ // clean up memory due to php5 circular references memory leak...
107
+ function clear() {
108
+ $this->dom = null;
109
+ $this->nodes = null;
110
+ $this->parent = null;
111
+ $this->children = null;
112
+ }
113
+
114
+ // dump node's tree
115
+ function dump($show_attr=true) {
116
+ dump_html_tree($this, $show_attr);
117
+ }
118
+
119
+ // returns the parent of node
120
+ function parent() {
121
+ return $this->parent;
122
+ }
123
+
124
+ // returns children of node
125
+ function children($idx=-1) {
126
+ if ($idx===-1) return $this->children;
127
+ if (isset($this->children[$idx])) return $this->children[$idx];
128
+ return null;
129
+ }
130
+
131
+ // returns the first child of node
132
+ function first_child() {
133
+ if (count($this->children)>0) return $this->children[0];
134
+ return null;
135
+ }
136
+
137
+ // returns the last child of node
138
+ function last_child() {
139
+ if (($count=count($this->children))>0) return $this->children[$count-1];
140
+ return null;
141
+ }
142
+
143
+ // returns the next sibling of node
144
+ function next_sibling() {
145
+ if ($this->parent===null) return null;
146
+ $idx = 0;
147
+ $count = count($this->parent->children);
148
+ while ($idx<$count && $this!==$this->parent->children[$idx])
149
+ ++$idx;
150
+ if (++$idx>=$count) return null;
151
+ return $this->parent->children[$idx];
152
+ }
153
+
154
+ // returns the previous sibling of node
155
+ function prev_sibling() {
156
+ if ($this->parent===null) return null;
157
+ $idx = 0;
158
+ $count = count($this->parent->children);
159
+ while ($idx<$count && $this!==$this->parent->children[$idx])
160
+ ++$idx;
161
+ if (--$idx<0) return null;
162
+ return $this->parent->children[$idx];
163
+ }
164
+
165
+ // get dom node's inner html
166
+ function innertext() {
167
+ if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
168
+ if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
169
+
170
+ $ret = '';
171
+ foreach($this->nodes as $n)
172
+ $ret .= $n->outertext();
173
+ return $ret;
174
+ }
175
+
176
+ // get dom node's outer text (with tag)
177
+ function outertext() {
178
+ if ($this->tag==='root') return $this->innertext();
179
+
180
+ // trigger callback
181
+ if ($this->dom->callback!==null)
182
+ call_user_func_array($this->dom->callback, array($this));
183
+
184
+ if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER];
185
+ if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
186
+
187
+ // render begin tag
188
+ $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
189
+
190
+ // render inner text
191
+ if (isset($this->_[HDOM_INFO_INNER]))
192
+ $ret .= $this->_[HDOM_INFO_INNER];
193
+ else {
194
+ foreach($this->nodes as $n)
195
+ $ret .= $n->outertext();
196
+ }
197
+
198
+ // render end tag
199
+ if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0)
200
+ $ret .= '</'.$this->tag.'>';
201
+ return $ret;
202
+ }
203
+
204
+ // get dom node's plain text
205
+ function text() {
206
+ if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
207
+ switch ($this->nodetype) {
208
+ case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
209
+ case HDOM_TYPE_COMMENT: return '';
210
+ case HDOM_TYPE_UNKNOWN: return '';
211
+ }
212
+ if (strcasecmp($this->tag, 'script')===0) return '';
213
+ if (strcasecmp($this->tag, 'style')===0) return '';
214
+
215
+ $ret = '';
216
+ foreach($this->nodes as $n)
217
+ $ret .= $n->text();
218
+ return $ret;
219
+ }
220
+
221
+ function xmltext() {
222
+ $ret = $this->innertext();
223
+ $ret = str_ireplace('<![CDATA[', '', $ret);
224
+ $ret = str_replace(']]>', '', $ret);
225
+ return $ret;
226
+ }
227
+
228
+ // build node's text with tag
229
+ function makeup() {
230
+ // text, comment, unknown
231
+ if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
232
+
233
+ $ret = '<'.$this->tag;
234
+ $i = -1;
235
+
236
+ foreach($this->attr as $key=>$val) {
237
+ ++$i;
238
+
239
+ // skip removed attribute
240
+ if ($val===null || $val===false)
241
+ continue;
242
+
243
+ $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
244
+ //no value attr: nowrap, checked selected...
245
+ if ($val===true)
246
+ $ret .= $key;
247
+ else {
248
+ switch($this->_[HDOM_INFO_QUOTE][$i]) {
249
+ case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
250
+ case HDOM_QUOTE_SINGLE: $quote = '\''; break;
251
+ default: $quote = '';
252
+ }
253
+ $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote;
254
+ }
255
+ }
256
+ $ret = $this->dom->restore_noise($ret);
257
+ return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
258
+ }
259
+
260
+ // find elements by css selector
261
+ function find($selector, $idx=null) {
262
+ $selectors = $this->parse_selector($selector);
263
+ if (($count=count($selectors))===0) return array();
264
+ $found_keys = array();
265
+
266
+ // find each selector
267
+ for ($c=0; $c<$count; ++$c) {
268
+ if (($levle=count($selectors[0]))===0) return array();
269
+ if (!isset($this->_[HDOM_INFO_BEGIN])) return array();
270
+
271
+ $head = array($this->_[HDOM_INFO_BEGIN]=>1);
272
+
273
+ // handle descendant selectors, no recursive!
274
+ for ($l=0; $l<$levle; ++$l) {
275
+ $ret = array();
276
+ foreach($head as $k=>$v) {
277
+ $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k];
278
+ $n->seek($selectors[$c][$l], $ret);
279
+ }
280
+ $head = $ret;
281
+ }
282
+
283
+ foreach($head as $k=>$v) {
284
+ if (!isset($found_keys[$k]))
285
+ $found_keys[$k] = 1;
286
+ }
287
+ }
288
+
289
+ // sort keys
290
+ ksort($found_keys);
291
+
292
+ $found = array();
293
+ foreach($found_keys as $k=>$v)
294
+ $found[] = $this->dom->nodes[$k];
295
+
296
+ // return nth-element or array
297
+ if (is_null($idx)) return $found;
298
+ else if ($idx<0) $idx = count($found) + $idx;
299
+ return (isset($found[$idx])) ? $found[$idx] : null;
300
+ }
301
+
302
+ // seek for given conditions
303
+ protected function seek($selector, &$ret) {
304
+ list($tag, $key, $val, $exp, $no_key) = $selector;
305
+
306
+ // xpath index
307
+ if ($tag && $key && is_numeric($key)) {
308
+ $count = 0;
309
+ foreach ($this->children as $c) {
310
+ if ($tag==='*' || $tag===$c->tag) {
311
+ if (++$count==$key) {
312
+ $ret[$c->_[HDOM_INFO_BEGIN]] = 1;
313
+ return;
314
+ }
315
+ }
316
+ }
317
+ return;
318
+ }
319
+
320
+ $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
321
+ if ($end==0) {
322
+ $parent = $this->parent;
323
+ while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) {
324
+ $end -= 1;
325
+ $parent = $parent->parent;
326
+ }
327
+ $end += $parent->_[HDOM_INFO_END];
328
+ }
329
+
330
+ for($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) {
331
+ $node = $this->dom->nodes[$i];
332
+ $pass = true;
333
+
334
+ if ($tag==='*' && !$key) {
335
+ if (in_array($node, $this->children, true))
336
+ $ret[$i] = 1;
337
+ continue;
338
+ }
339
+
340
+ // compare tag
341
+ if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;}
342
+ // compare key
343
+ if ($pass && $key) {
344
+ if ($no_key) {
345
+ if (isset($node->attr[$key])) $pass=false;
346
+ }
347
+ else if (!isset($node->attr[$key])) $pass=false;
348
+ }
349
+ // compare value
350
+ if ($pass && $key && $val && $val!=='*') {
351
+ $check = $this->match($exp, $val, $node->attr[$key]);
352
+ // handle multiple class
353
+ if (!$check && strcasecmp($key, 'class')===0) {
354
+ foreach(explode(' ',$node->attr[$key]) as $k) {
355
+ $check = $this->match($exp, $val, $k);
356
+ if ($check) break;
357
+ }
358
+ }
359
+ if (!$check) $pass = false;
360
+ }
361
+ if ($pass) $ret[$i] = 1;
362
+ unset($node);
363
+ }
364
+ }
365
+
366
+ protected function match($exp, $pattern, $value) {
367
+ switch ($exp) {
368
+ case '=':
369
+ return ($value===$pattern);
370
+ case '!=':
371
+ return ($value!==$pattern);
372
+ case '^=':
373
+ return preg_match("/^".preg_quote($pattern,'/')."/", $value);
374
+ case '$=':
375
+ return preg_match("/".preg_quote($pattern,'/')."$/", $value);
376
+ case '*=':
377
+ if ($pattern[0]=='/')
378
+ return preg_match($pattern, $value);
379
+ return preg_match("/".$pattern."/i", $value);
380
+ }
381
+ return false;
382
+ }
383
+
384
+ protected function parse_selector($selector_string) {
385
+ // pattern of CSS selectors, modified from mootools
386
+ $pattern = "/([\w\-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
387
+ preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
388
+ $selectors = array();
389
+ $result = array();
390
+ //print_r($matches);
391
+
392
+ foreach ($matches as $m) {
393
+ $m[0] = trim($m[0]);
394
+ if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue;
395
+ // for borwser grnreated xpath
396
+ if ($m[1]==='tbody') continue;
397
+
398
+ list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false);
399
+ if(!empty($m[2])) {$key='id'; $val=$m[2];}
400
+ if(!empty($m[3])) {$key='class'; $val=$m[3];}
401
+ if(!empty($m[4])) {$key=$m[4];}
402
+ if(!empty($m[5])) {$exp=$m[5];}
403
+ if(!empty($m[6])) {$val=$m[6];}
404
+
405
+ // convert to lowercase
406
+ if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);}
407
+ //elements that do NOT have the specified attribute
408
+ if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;}
409
+
410
+ $result[] = array($tag, $key, $val, $exp, $no_key);
411
+ if (trim($m[7])===',') {
412
+ $selectors[] = $result;
413
+ $result = array();
414
+ }
415
+ }
416
+ if (count($result)>0)
417
+ $selectors[] = $result;
418
+ return $selectors;
419
+ }
420
+
421
+ function __get($name) {
422
+ if (isset($this->attr[$name])) return $this->attr[$name];
423
+ switch($name) {
424
+ case 'outertext': return $this->outertext();
425
+ case 'innertext': return $this->innertext();
426
+ case 'plaintext': return $this->text();
427
+ case 'xmltext': return $this->xmltext();
428
+ default: return array_key_exists($name, $this->attr);
429
+ }
430
+ }
431
+
432
+ function __set($name, $value) {
433
+ switch($name) {
434
+ case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
435
+ case 'innertext':
436
+ if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value;
437
+ return $this->_[HDOM_INFO_INNER] = $value;
438
+ }
439
+ if (!isset($this->attr[$name])) {
440
+ $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
441
+ $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
442
+ }
443
+ $this->attr[$name] = $value;
444
+ }
445
+
446
+ function __isset($name) {
447
+ switch($name) {
448
+ case 'outertext': return true;
449
+ case 'innertext': return true;
450
+ case 'plaintext': return true;
451
+ }
452
+ //no value attr: nowrap, checked selected...
453
+ return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
454
+ }
455
+
456
+ function __unset($name) {
457
+ if (isset($this->attr[$name]))
458
+ unset($this->attr[$name]);
459
+ }
460
+
461
+ // camel naming conventions
462
+ function getAllAttributes() {return $this->attr;}
463
+ function getAttribute($name) {return $this->__get($name);}
464
+ function setAttribute($name, $value) {$this->__set($name, $value);}
465
+ function hasAttribute($name) {return $this->__isset($name);}
466
+ function removeAttribute($name) {$this->__set($name, null);}
467
+ function getElementById($id) {return $this->find("#$id", 0);}
468
+ function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
469
+ function getElementByTagName($name) {return $this->find($name, 0);}
470
+ function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);}
471
+ function parentNode() {return $this->parent();}
472
+ function childNodes($idx=-1) {return $this->children($idx);}
473
+ function firstChild() {return $this->first_child();}
474
+ function lastChild() {return $this->last_child();}
475
+ function nextSibling() {return $this->next_sibling();}
476
+ function previousSibling() {return $this->prev_sibling();}
477
+ }
478
+
479
+ // simple html dom parser
480
+ // -----------------------------------------------------------------------------
481
+ class simple_html_dom {
482
+ public $root = null;
483
+ public $nodes = array();
484
+ public $callback = null;
485
+ public $lowercase = false;
486
+ protected $pos;
487
+ protected $doc;
488
+ protected $char;
489
+ protected $size;
490
+ protected $cursor;
491
+ protected $parent;
492
+ protected $noise = array();
493
+ protected $token_blank = " \t\r\n";
494
+ protected $token_equal = ' =/>';
495
+ protected $token_slash = " />\r\n\t";
496
+ protected $token_attr = ' >';
497
+ // use isset instead of in_array, performance boost about 30%...
498
+ protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1);
499
+ protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1);
500
+ protected $optional_closing_tags = array(
501
+ 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1),
502
+ 'th'=>array('th'=>1),
503
+ 'td'=>array('td'=>1),
504
+ 'li'=>array('li'=>1),
505
+ 'dt'=>array('dt'=>1, 'dd'=>1),
506
+ 'dd'=>array('dd'=>1, 'dt'=>1),
507
+ 'dl'=>array('dd'=>1, 'dt'=>1),
508
+ 'p'=>array('p'=>1),
509
+ 'nobr'=>array('nobr'=>1),
510
+ );
511
+
512
+ function __construct($str=null) {
513
+ if ($str) {
514
+ if (preg_match("/^http:\/\//i",$str) || is_file($str))
515
+ $this->load_file($str);
516
+ else
517
+ $this->load($str);
518
+ }
519
+ }
520
+
521
+ function __destruct() {
522
+ $this->clear();
523
+ }
524
+
525
+ // load html from string
526
+ function load($str, $lowercase=true) {
527
+ // prepare
528
+ $this->prepare($str, $lowercase);
529
+ // strip out comments
530
+ $this->remove_noise("'<!--(.*?)-->'is");
531
+ // strip out cdata
532
+ $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
533
+ // strip out <style> tags
534
+ $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
535
+ $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
536
+ // strip out <script> tags
537
+ $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
538
+ $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
539
+ // strip out preformatted tags
540
+ $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
541
+ // strip out server side scripts
542
+ $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
543
+ // strip smarty scripts
544
+ $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
545
+
546
+ // parsing
547
+ while ($this->parse());
548
+ // end
549
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
550
+ }
551
+
552
+ // load html from file
553
+ function load_file() {
554
+ $args = func_get_args();
555
+ $this->load(call_user_func_array('file_get_contents', $args), true);
556
+ }
557
+
558
+ // set callback function
559
+ function set_callback($function_name) {
560
+ $this->callback = $function_name;
561
+ }
562
+
563
+ // remove callback function
564
+ function remove_callback() {
565
+ $this->callback = null;
566
+ }
567
+
568
+ // save dom as string
569
+ function save($filepath='') {
570
+ $ret = $this->root->innertext();
571
+ if ($filepath!=='') file_put_contents($filepath, $ret);
572
+ return $ret;
573
+ }
574
+
575
+ // find dom node by css selector
576
+ function find($selector, $idx=null) {
577
+ return $this->root->find($selector, $idx);
578
+ }
579
+
580
+ // clean up memory due to php5 circular references memory leak...
581
+ function clear() {
582
+ foreach($this->nodes as $n) {$n->clear(); $n = null;}
583
+ if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
584
+ if (isset($this->root)) {$this->root->clear(); unset($this->root);}
585
+ unset($this->doc);
586
+ unset($this->noise);
587
+ }
588
+
589
+ function dump($show_attr=true) {
590
+ $this->root->dump($show_attr);
591
+ }
592
+
593
+ // prepare HTML data and init everything
594
+ protected function prepare($str, $lowercase=true) {
595
+ $this->clear();
596
+ $this->doc = $str;
597
+ $this->pos = 0;
598
+ $this->cursor = 1;
599
+ $this->noise = array();
600
+ $this->nodes = array();
601
+ $this->lowercase = $lowercase;
602
+ $this->root = new simple_html_dom_node($this);
603
+ $this->root->tag = 'root';
604
+ $this->root->_[HDOM_INFO_BEGIN] = -1;
605
+ $this->root->nodetype = HDOM_TYPE_ROOT;
606
+ $this->parent = $this->root;
607
+ // set the length of content
608
+ $this->size = strlen($str);
609
+ if ($this->size>0) $this->char = $this->doc[0];
610
+ }
611
+
612
+ // parse html content
613
+ protected function parse() {
614
+ if (($s = $this->copy_until_char('<'))==='')
615
+ return $this->read_tag();
616
+
617
+ // text
618
+ $node = new simple_html_dom_node($this);
619
+ ++$this->cursor;
620
+ $node->_[HDOM_INFO_TEXT] = $s;
621
+ $this->link_nodes($node, false);
622
+ return true;
623
+ }
624
+
625
+ // read tag info
626
+ protected function read_tag() {
627
+ if ($this->char!=='<') {
628
+ $this->root->_[HDOM_INFO_END] = $this->cursor;
629
+ return false;
630
+ }
631
+ $begin_tag_pos = $this->pos;
632
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
633
+
634
+ // end tag
635
+ if ($this->char==='/') {
636
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
637
+ $this->skip($this->token_blank_t);
638
+ $tag = $this->copy_until_char('>');
639
+
640
+ // skip attributes in end tag
641
+ if (($pos = strpos($tag, ' '))!==false)
642
+ $tag = substr($tag, 0, $pos);
643
+
644
+ $parent_lower = strtolower($this->parent->tag);
645
+ $tag_lower = strtolower($tag);
646
+
647
+ if ($parent_lower!==$tag_lower) {
648
+ if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) {
649
+ $this->parent->_[HDOM_INFO_END] = 0;
650
+ $org_parent = $this->parent;
651
+
652
+ while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
653
+ $this->parent = $this->parent->parent;
654
+
655
+ if (strtolower($this->parent->tag)!==$tag_lower) {
656
+ $this->parent = $org_parent; // restore origonal parent
657
+ if ($this->parent->parent) $this->parent = $this->parent->parent;
658
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
659
+ return $this->as_text_node($tag);
660
+ }
661
+ }
662
+ else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) {
663
+ $this->parent->_[HDOM_INFO_END] = 0;
664
+ $org_parent = $this->parent;
665
+
666
+ while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
667
+ $this->parent = $this->parent->parent;
668
+
669
+ if (strtolower($this->parent->tag)!==$tag_lower) {
670
+ $this->parent = $org_parent; // restore origonal parent
671
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
672
+ return $this->as_text_node($tag);
673
+ }
674
+ }
675
+ else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower) {
676
+ $this->parent->_[HDOM_INFO_END] = 0;
677
+ $this->parent = $this->parent->parent;
678
+ }
679
+ else
680
+ return $this->as_text_node($tag);
681
+ }
682
+
683
+ $this->parent->_[HDOM_INFO_END] = $this->cursor;
684
+ if ($this->parent->parent) $this->parent = $this->parent->parent;
685
+
686
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
687
+ return true;
688
+ }
689
+
690
+ $node = new simple_html_dom_node($this);
691
+ $node->_[HDOM_INFO_BEGIN] = $this->cursor;
692
+ ++$this->cursor;
693
+ $tag = $this->copy_until($this->token_slash);
694
+
695
+ // doctype, cdata & comments...
696
+ if (isset($tag[0]) && $tag[0]==='!') {
697
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
698
+
699
+ if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') {
700
+ $node->nodetype = HDOM_TYPE_COMMENT;
701
+ $node->tag = 'comment';
702
+ } else {
703
+ $node->nodetype = HDOM_TYPE_UNKNOWN;
704
+ $node->tag = 'unknown';
705
+ }
706
+
707
+ if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
708
+ $this->link_nodes($node, true);
709
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
710
+ return true;
711
+ }
712
+
713
+ // text
714
+ if ($pos=strpos($tag, '<')!==false) {
715
+ $tag = '<' . substr($tag, 0, -1);
716
+ $node->_[HDOM_INFO_TEXT] = $tag;
717
+ $this->link_nodes($node, false);
718
+ $this->char = $this->doc[--$this->pos]; // prev
719
+ return true;
720
+ }
721
+
722
+ if (!preg_match("/^[\w\-:]+$/", $tag)) {
723
+ $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
724
+ if ($this->char==='<') {
725
+ $this->link_nodes($node, false);
726
+ return true;
727
+ }
728
+
729
+ if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
730
+ $this->link_nodes($node, false);
731
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
732
+ return true;
733
+ }
734
+
735
+ // begin tag
736
+ $node->nodetype = HDOM_TYPE_ELEMENT;
737
+ $tag_lower = strtolower($tag);
738
+ $node->tag = ($this->lowercase) ? $tag_lower : $tag;
739
+
740
+ // handle optional closing tags
741
+ if (isset($this->optional_closing_tags[$tag_lower]) ) {
742
+ while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
743
+ $this->parent->_[HDOM_INFO_END] = 0;
744
+ $this->parent = $this->parent->parent;
745
+ }
746
+ $node->parent = $this->parent;
747
+ }
748
+
749
+ $guard = 0; // prevent infinity loop
750
+ $space = array($this->copy_skip($this->token_blank), '', '');
751
+
752
+ // attributes
753
+ do {
754
+ if ($this->char!==null && $space[0]==='') break;
755
+ $name = $this->copy_until($this->token_equal);
756
+ if($guard===$this->pos) {
757
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
758
+ continue;
759
+ }
760
+ $guard = $this->pos;
761
+
762
+ // handle endless '<'
763
+ if($this->pos>=$this->size-1 && $this->char!=='>') {
764
+ $node->nodetype = HDOM_TYPE_TEXT;
765
+ $node->_[HDOM_INFO_END] = 0;
766
+ $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name;
767
+ $node->tag = 'text';
768
+ $this->link_nodes($node, false);
769
+ return true;
770
+ }
771
+
772
+ // handle mismatch '<'
773
+ if($this->doc[$this->pos-1]=='<') {
774
+ $node->nodetype = HDOM_TYPE_TEXT;
775
+ $node->tag = 'text';
776
+ $node->attr = array();
777
+ $node->_[HDOM_INFO_END] = 0;
778
+ $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1);
779
+ $this->pos -= 2;
780
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
781
+ $this->link_nodes($node, false);
782
+ return true;
783
+ }
784
+
785
+ if ($name!=='/' && $name!=='') {
786
+ $space[1] = $this->copy_skip($this->token_blank);
787
+ $name = $this->restore_noise($name);
788
+ if ($this->lowercase) $name = strtolower($name);
789
+ if ($this->char==='=') {
790
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
791
+ $this->parse_attr($node, $name, $space);
792
+ }
793
+ else {
794
+ //no value attr: nowrap, checked selected...
795
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
796
+ $node->attr[$name] = true;
797
+ if ($this->char!='>') $this->char = $this->doc[--$this->pos]; // prev
798
+ }
799
+ $node->_[HDOM_INFO_SPACE][] = $space;
800
+ $space = array($this->copy_skip($this->token_blank), '', '');
801
+ }
802
+ else
803
+ break;
804
+ } while($this->char!=='>' && $this->char!=='/');
805
+
806
+ $this->link_nodes($node, true);
807
+ $node->_[HDOM_INFO_ENDSPACE] = $space[0];
808
+
809
+ // check self closing
810
+ if ($this->copy_until_char_escape('>')==='/') {
811
+ $node->_[HDOM_INFO_ENDSPACE] .= '/';
812
+ $node->_[HDOM_INFO_END] = 0;
813
+ }
814
+ else {
815
+ // reset parent
816
+ if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node;
817
+ }
818
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
819
+ return true;
820
+ }
821
+
822
+ // parse attributes
823
+ protected function parse_attr($node, $name, &$space) {
824
+ $space[2] = $this->copy_skip($this->token_blank);
825
+ switch($this->char) {
826
+ case '"':
827
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
828
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
829
+ $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"'));
830
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
831
+ break;
832
+ case '\'':
833
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE;
834
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
835
+ $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\''));
836
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
837
+ break;
838
+ default:
839
+ $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
840
+ $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr));
841
+ }
842
+ }
843
+
844
+ // link node's parent
845
+ protected function link_nodes(&$node, $is_child) {
846
+ $node->parent = $this->parent;
847
+ $this->parent->nodes[] = $node;
848
+ if ($is_child)
849
+ $this->parent->children[] = $node;
850
+ }
851
+
852
+ // as a text node
853
+ protected function as_text_node($tag) {
854
+ $node = new simple_html_dom_node($this);
855
+ ++$this->cursor;
856
+ $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
857
+ $this->link_nodes($node, false);
858
+ $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
859
+ return true;
860
+ }
861
+
862
+ protected function skip($chars) {
863
+ $this->pos += strspn($this->doc, $chars, $this->pos);
864
+ $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
865
+ }
866
+
867
+ protected function copy_skip($chars) {
868
+ $pos = $this->pos;
869
+ $len = strspn($this->doc, $chars, $pos);
870
+ $this->pos += $len;
871
+ $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
872
+ if ($len===0) return '';
873
+ return substr($this->doc, $pos, $len);
874
+ }
875
+
876
+ protected function copy_until($chars) {
877
+ $pos = $this->pos;
878
+ $len = strcspn($this->doc, $chars, $pos);
879
+ $this->pos += $len;
880
+ $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
881
+ return substr($this->doc, $pos, $len);
882
+ }
883
+
884
+ protected function copy_until_char($char) {
885
+ if ($this->char===null) return '';
886
+
887
+ if (($pos = strpos($this->doc, $char, $this->pos))===false) {
888
+ $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
889
+ $this->char = null;
890
+ $this->pos = $this->size;
891
+ return $ret;
892
+ }
893
+
894
+ if ($pos===$this->pos) return '';
895
+ $pos_old = $this->pos;
896
+ $this->char = $this->doc[$pos];
897
+ $this->pos = $pos;
898
+ return substr($this->doc, $pos_old, $pos-$pos_old);
899
+ }
900
+
901
+ protected function copy_until_char_escape($char) {
902
+ if ($this->char===null) return '';
903
+
904
+ $start = $this->pos;
905
+ while(1) {
906
+ if (($pos = strpos($this->doc, $char, $start))===false) {
907
+ $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
908
+ $this->char = null;
909
+ $this->pos = $this->size;
910
+ return $ret;
911
+ }
912
+
913
+ if ($pos===$this->pos) return '';
914
+
915
+ if ($this->doc[$pos-1]==='\\') {
916
+ $start = $pos+1;
917
+ continue;
918
+ }
919
+
920
+ $pos_old = $this->pos;
921
+ $this->char = $this->doc[$pos];
922
+ $this->pos = $pos;
923
+ return substr($this->doc, $pos_old, $pos-$pos_old);
924
+ }
925
+ }
926
+
927
+ // remove noise from html content
928
+ protected function remove_noise($pattern, $remove_tag=false) {
929
+ $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
930
+
931
+ for ($i=$count-1; $i>-1; --$i) {
932
+ $key = '___noise___'.sprintf('% 3d', count($this->noise)+100);
933
+ $idx = ($remove_tag) ? 0 : 1;
934
+ $this->noise[$key] = $matches[$i][$idx][0];
935
+ $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
936
+ }
937
+
938
+ // reset the length of content
939
+ $this->size = strlen($this->doc);
940
+ if ($this->size>0) $this->char = $this->doc[0];
941
+ }
942
+
943
+ // restore noise to html content
944
+ function restore_noise($text) {
945
+ while(($pos=strpos($text, '___noise___'))!==false) {
946
+ $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13];
947
+ if (isset($this->noise[$key]))
948
+ $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+14);
949
+ }
950
+ return $text;
951
+ }
952
+
953
+ function __toString() {
954
+ return $this->root->innertext();
955
+ }
956
+
957
+ function __get($name) {
958
+ switch($name) {
959
+ case 'outertext': return $this->root->innertext();
960
+ case 'innertext': return $this->root->innertext();
961
+ case 'plaintext': return $this->root->text();
962
+ }
963
+ }
964
+
965
+ // camel naming conventions
966
+ function childNodes($idx=-1) {return $this->root->childNodes($idx);}
967
+ function firstChild() {return $this->root->first_child();}
968
+ function lastChild() {return $this->root->last_child();}
969
+ function getElementById($id) {return $this->find("#$id", 0);}
970
+ function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
971
+ function getElementByTagName($name) {return $this->find($name, 0);}
972
+ function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
973
+ function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);}
974
+ }
975
+ ?>
includes/vendor/ultimate-web-scraper/tag_filter.php ADDED
@@ -0,0 +1,3260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP Tag Filter class. Can repair broken HTML.
3
+ // (C) 2018 CubicleSoft. All Rights Reserved.
4
+
5
+ class TagFilterStream
6
+ {
7
+ protected $lastcontent, $lastresult, $final, $options, $stack;
8
+
9
+ public function __construct($options = array())
10
+ {
11
+ $this->Init($options);
12
+ }
13
+
14
+ public function Init($options = array())
15
+ {
16
+ if (!isset($options["keep_attr_newlines"])) $options["keep_attr_newlines"] = false;
17
+ if (!isset($options["keep_comments"])) $options["keep_comments"] = false;
18
+ if (!isset($options["allow_namespaces"])) $options["allow_namespaces"] = true;
19
+ if (!isset($options["process_attrs"])) $options["process_attrs"] = array();
20
+ if (!isset($options["charset"])) $options["charset"] = "UTF-8";
21
+ $options["charset"] = strtoupper($options["charset"]);
22
+ if (!isset($options["charset_tags"])) $options["charset_tags"] = true;
23
+ if (!isset($options["charset_attrs"])) $options["charset_attrs"] = true;
24
+ if (!isset($options["tag_name_map"])) $options["tag_name_map"] = array();
25
+ if (!isset($options["untouched_tag_attr_keys"])) $options["untouched_tag_attr_keys"] = array();
26
+ if (!isset($options["void_tags"])) $options["void_tags"] = array();
27
+ if (!isset($options["alt_tag_content_rules"])) $options["alt_tag_content_rules"] = array();
28
+ if (!isset($options["pre_close_tags"])) $options["pre_close_tags"] = array();
29
+ if (!isset($options["output_mode"])) $options["output_mode"] = "html";
30
+ if (!isset($options["lowercase_tags"])) $options["lowercase_tags"] = true;
31
+ if (!isset($options["lowercase_attrs"])) $options["lowercase_attrs"] = true;
32
+ $options["tag_num"] = 0;
33
+
34
+ $this->lastcontent = "";
35
+ $this->lastresult = "";
36
+ $this->final = false;
37
+ $this->options = $options;
38
+ $this->stack = array();
39
+ }
40
+
41
+ public function Process($content)
42
+ {
43
+ if ($this->lastcontent !== "") $content = $this->lastcontent . $content;
44
+
45
+ $result = $this->lastresult;
46
+ $this->lastresult = "";
47
+ $tag = false;
48
+ $a = ord("A");
49
+ $a2 = ord("a");
50
+ $f = ord("F");
51
+ $f2 = ord("f");
52
+ $z = ord("Z");
53
+ $z2 = ord("z");
54
+ $hyphen = ord("-");
55
+ $underscore = ord("_");
56
+ $period = ord(".");
57
+ $colon = ord(":");
58
+ $zero = ord("0");
59
+ $nine = ord("9");
60
+ $cx = 0;
61
+ $cy = strlen($content);
62
+ while ($cx < $cy)
63
+ {
64
+ if ($tag)
65
+ {
66
+ $firstcx = $cx;
67
+
68
+ // First character is '<'. Extract all non-alpha chars.
69
+ $prefix = "";
70
+ $startpos = $cx + 1;
71
+ for ($x = $startpos; $x < $cy; $x++)
72
+ {
73
+ $val = ord($content{$x});
74
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
75
+ {
76
+ if ($x > $cx + 1) $prefix = ltrim(substr($content, $cx + 1, $x - $cx - 1));
77
+ $startpos = $x;
78
+
79
+ break;
80
+ }
81
+ }
82
+
83
+ if ($prefix === "") $open = true;
84
+ else
85
+ {
86
+ if ($prefix{0} === "!")
87
+ {
88
+ // !DOCTYPE vs. comment.
89
+ if (substr($prefix, 0, 3) !== "!--")
90
+ {
91
+ $prefix = "!";
92
+ $open = true;
93
+ }
94
+ else
95
+ {
96
+ // Comment.
97
+ $pos = strpos($content, "!--", $cx);
98
+ $pos2 = strpos($content, "-->", $pos + 3);
99
+ if ($pos2 === false)
100
+ {
101
+ if (!$this->final)
102
+ {
103
+ $cx = $firstcx;
104
+
105
+ break;
106
+ }
107
+
108
+ $pos2 = $cy;
109
+ }
110
+
111
+ if ($this->options["keep_comments"])
112
+ {
113
+ $content2 = substr($content, $pos + 3, $pos2 - $pos - 3);
114
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
115
+ $content2 = "<!-- " . trim(htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"])) . " -->";
116
+
117
+ // Let a callback handle any necessary changes.
118
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
119
+
120
+ $result .= $content2;
121
+ }
122
+ $cx = $pos2 + 3;
123
+
124
+ $tag = false;
125
+
126
+ continue;
127
+ }
128
+ }
129
+ else if ($prefix{0} === "/")
130
+ {
131
+ // Close tag.
132
+ $prefix = "/";
133
+ $open = false;
134
+ }
135
+ else if ($prefix{0} === "<")
136
+ {
137
+ // Stray less than. Encode and reset.
138
+ $content2 = "&lt;";
139
+
140
+ // Let a callback handle any necessary changes.
141
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
142
+
143
+ $result .= $content2;
144
+ $cx++;
145
+
146
+ continue;
147
+ }
148
+ else
149
+ {
150
+ // Unknown. Encode it.
151
+ $data = substr($content, $cx, strpos($content, $prefix, $cx) + strlen($prefix) - $cx);
152
+ $content2 = $data;
153
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($content2)) $content2 = self::MakeValidUTF8($content2);
154
+ $content2 = htmlspecialchars($content2, ENT_COMPAT | ENT_HTML5, $this->options["charset"]);
155
+
156
+ // Let a callback handle any necessary changes.
157
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
158
+
159
+ $result .= $content2;
160
+ $cx += strlen($data);
161
+
162
+ $tag = false;
163
+
164
+ continue;
165
+ }
166
+ }
167
+
168
+ // Read the tag name.
169
+ $tagname = "";
170
+ $parse = false;
171
+ $cx = $startpos;
172
+ for (; $cx < $cy; $cx++)
173
+ {
174
+ $val = ord($content{$cx});
175
+ if ($val > 127) $parse = true;
176
+ else if (!(($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($cx > $startpos && (($val >= $zero && $val <= $nine) || $val == $hyphen || $val == $underscore || $val == $period)) || ($this->options["allow_namespaces"] && $val == $colon))) break;
177
+ }
178
+ $tagname = substr($content, $startpos, $cx - $startpos);
179
+ if ($parse)
180
+ {
181
+ if ($this->options["charset_tags"] && $this->options["charset"] === "UTF-8") $tagname = (self::IsValidUTF8($tagname) ? $tagname : self::MakeValidUTF8($tagname));
182
+ else $tagname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $tagname);
183
+ }
184
+ $tagname = rtrim($tagname, "._-:");
185
+ if (!$this->options["charset_tags"]) $tagname = preg_replace('/[^A-Za-z0-9:]/', "", $tagname);
186
+ $outtagname = ($this->options["lowercase_tags"] ? strtolower($tagname) : $tagname);
187
+ $tagname = strtolower($tagname);
188
+
189
+ // Close open tags in the stack that match the set of tags to look for to close.
190
+ if ($open && isset($this->options["pre_close_tags"][$tagname]))
191
+ {
192
+ // Find matches.
193
+ $info2 = $this->options["pre_close_tags"][$tagname];
194
+ $limit = (isset($info2["_limit"]) ? $info2["_limit"] : array());
195
+ if (is_string($limit)) $limit = array($limit => true);
196
+
197
+ // Unwind the stack.
198
+ do
199
+ {
200
+ $found = false;
201
+ foreach ($this->stack as $info)
202
+ {
203
+ if (isset($info2[$info["tag_name"]]))
204
+ {
205
+ $found = true;
206
+
207
+ break;
208
+ }
209
+
210
+ if (isset($limit[$info["tag_name"]])) break;
211
+ }
212
+
213
+ if ($found)
214
+ {
215
+ do
216
+ {
217
+ // Let a callback handle any necessary changes.
218
+ $attrs = array();
219
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
220
+ else $funcresult = array();
221
+
222
+ if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
223
+
224
+ $info = array_shift($this->stack);
225
+
226
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
227
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
228
+ } while (!isset($info2[$info["tag_name"]]));
229
+ }
230
+ } while ($found);
231
+ }
232
+
233
+ // Process attributes/properties until a closing condition is encountered.
234
+ $state = "name";
235
+ $voidtag = false;
236
+ $attrs = array();
237
+ do
238
+ {
239
+ if ($state === "name")
240
+ {
241
+ // Find attribute key/property.
242
+ for ($x = $cx; $x < $cy; $x++)
243
+ {
244
+ if ($content{$x} === ">" || $content{$x} === "<")
245
+ {
246
+ $cx = $x;
247
+
248
+ $state = "exit";
249
+
250
+ break;
251
+ }
252
+ else if ($content{$x} === "/")
253
+ {
254
+ $pos = strpos($content, ">", $x + 1);
255
+ if ($pos !== false && trim(substr($content, $x + 1, $pos - $x - 1)) === "")
256
+ {
257
+ $cx = $pos;
258
+ $voidtag = true;
259
+
260
+ $state = "exit";
261
+
262
+ break;
263
+ }
264
+ }
265
+ else if ($content{$x} === "\"" || $content{$x} === "'" || $content{$x} === "`")
266
+ {
267
+ $pos = strpos($content, $content{$x}, $x + 1);
268
+ if ($pos === false) $content .= $content{$x};
269
+ else if (isset($this->options["untouched_tag_attr_keys"][$tagname]))
270
+ {
271
+ $keyname = substr($content, $x, $pos - $x + 1);
272
+ $cx = $pos + 1;
273
+
274
+ $state = "equals";
275
+ }
276
+ else
277
+ {
278
+ $keyname = substr($content, $x + 1, $pos - $x - 1);
279
+ if ($this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
280
+ if (preg_match('/<\s*\/\s*' . $tagname . '(\s*|\s+.+?)>/is', strtolower($keyname)) || (count($this->stack) && preg_match('/<\s*\/\s*' . $this->stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', strtolower($keyname))))
281
+ {
282
+ // Found a matching close tag within the key name. Bail out.
283
+ $state = "exit";
284
+
285
+ break;
286
+ }
287
+ else
288
+ {
289
+ $keyname = preg_replace('/[^' . ($this->options["lowercase_attrs"] ? "" : "A-Z") . 'a-z' . ($this->options["allow_namespaces"] ? ":" : "") . ']/', "", $keyname);
290
+ if ($this->options["allow_namespaces"]) $keyname = rtrim($keyname, ":");
291
+ $cx = $pos + 1;
292
+
293
+ $state = "equals";
294
+ }
295
+ }
296
+
297
+ break;
298
+ }
299
+ else
300
+ {
301
+ $val = ord($content{$x});
302
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2))
303
+ {
304
+ $cx = $x;
305
+ $parse = false;
306
+
307
+ for (; $cx < $cy; $cx++)
308
+ {
309
+ if ($content{$cx} === " " || $content{$cx} === "=" || $content{$cx} === "\"" || $content{$cx} === "'" || $content{$cx} === "`" || $content{$cx} === ">" || $content{$cx} === "<" || $content{$cx} === "/" || $content{$cx} === "\0" || $content{$cx} === "\r" || $content{$cx} === "\n" || $content{$cx} === "\t") break;
310
+ else if (ord($content{$cx}) > 127) $parse = true;
311
+ }
312
+
313
+ $keyname = substr($content, $x, $cx - $x);
314
+ if ($parse && $this->options["charset_attrs"] && $this->options["charset"] === "UTF-8")
315
+ {
316
+ $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._\-\x80-\xFF]/' : '/[^A-Za-z0-9._\-\x80-\xFF]/'), "", $keyname);
317
+ if (!self::IsValidUTF8($keyname)) $keyname = self::MakeValidUTF8($keyname);
318
+ }
319
+ else
320
+ {
321
+ $keyname = preg_replace(($this->options["allow_namespaces"] ? '/[^A-Za-z0-9:._-]/' : '/[^A-Za-z0-9._-]/'), "", $keyname);
322
+ }
323
+ $keyname = rtrim($keyname, "._-:");
324
+ if (!isset($this->options["untouched_tag_attr_keys"][$tagname]) && $this->options["lowercase_attrs"]) $keyname = strtolower($keyname);
325
+
326
+ $state = "equals";
327
+
328
+ break;
329
+ }
330
+ }
331
+ }
332
+
333
+ if ($state === "name")
334
+ {
335
+ $cx = $cy;
336
+
337
+ $state = "exit";
338
+ }
339
+ }
340
+ else if ($state === "equals")
341
+ {
342
+ // Find the equals sign OR the start of the next attribute/property.
343
+ for ($x = $cx; $x < $cy; $x++)
344
+ {
345
+ if ($content{$x} === ">" || $content{$x} === "<")
346
+ {
347
+ $cx = $x;
348
+
349
+ $attrs[$keyname] = true;
350
+
351
+ $state = "exit";
352
+
353
+ break;
354
+ }
355
+ else if ($content{$x} === "=")
356
+ {
357
+ $cx = $x + 1;
358
+
359
+ $state = "value";
360
+
361
+ break;
362
+ }
363
+ else if ($content{$x} === "\"" || $content{$x} === "'")
364
+ {
365
+ $cx = $x;
366
+
367
+ $attrs[$keyname] = true;
368
+
369
+ $state = "name";
370
+
371
+ break;
372
+ }
373
+ else
374
+ {
375
+ $val = ord($content{$x});
376
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || ($val >= $zero && $val <= $nine))
377
+ {
378
+ $cx = $x;
379
+
380
+ $attrs[$keyname] = true;
381
+
382
+ $state = "name";
383
+
384
+ break;
385
+ }
386
+ }
387
+ }
388
+
389
+ if ($state === "equals")
390
+ {
391
+ $cx = $cy;
392
+
393
+ $attrs[$keyname] = true;
394
+
395
+ $state = "exit";
396
+ }
397
+ }
398
+ else if ($state === "value")
399
+ {
400
+ for ($x = $cx; $x < $cy; $x++)
401
+ {
402
+ if ($content{$x} === ">" || $content{$x} === "<")
403
+ {
404
+ $cx = $x;
405
+
406
+ $attrs[$keyname] = true;
407
+
408
+ $state = "exit";
409
+
410
+ break;
411
+ }
412
+ else if ($content{$x} === "\"" || $content{$x} === "'" || $content{$x} === "`")
413
+ {
414
+ $pos = strpos($content, $content{$x}, $x + 1);
415
+ if ($pos === false) $content .= $content{$x};
416
+ else
417
+ {
418
+ $value = substr($content, $x + 1, $pos - $x - 1);
419
+ $cx = $pos + 1;
420
+
421
+ $state = "name";
422
+ }
423
+
424
+ break;
425
+ }
426
+ else if ($content{$x} !== "\0" && $content{$x} !== "\r" && $content{$x} !== "\n" && $content{$x} !== "\t" && $content{$x} !== " ")
427
+ {
428
+ $cx = $x;
429
+
430
+ for (; $cx < $cy; $cx++)
431
+ {
432
+ if ($content{$cx} === "\0" || $content{$cx} === "\r" || $content{$cx} === "\n" || $content{$cx} === "\t" || $content{$cx} === " " || $content{$cx} === "<" || $content{$cx} === ">")
433
+ {
434
+ break;
435
+ }
436
+ }
437
+
438
+ $value = substr($content, $x, $cx - $x);
439
+
440
+ $state = "name";
441
+
442
+ break;
443
+ }
444
+ }
445
+
446
+ if ($state === "value")
447
+ {
448
+ $cx = $cy;
449
+
450
+ $attrs[$keyname] = true;
451
+
452
+ $state = "exit";
453
+ }
454
+
455
+ if ($state === "name")
456
+ {
457
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($value)) $value = self::MakeValidUTF8($value);
458
+ $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, $this->options["charset"]);
459
+
460
+ // Decode remaining entities.
461
+ $value2 = "";
462
+ $vx = 0;
463
+ $vy = strlen($value);
464
+ while ($vx < $vy)
465
+ {
466
+ $pos = strpos($value, "&#", $vx);
467
+ $pos2 = strpos($value, "\\", $vx);
468
+ if ($pos === false) $pos = $vy;
469
+ if ($pos2 === false) $pos2 = $vy;
470
+ if ($pos < $pos2)
471
+ {
472
+ // &#32 or &#x20 (optional trailing semi-colon)
473
+ $value2 .= substr($value, $vx, $pos - $vx);
474
+ $vx = $pos + 2;
475
+ if ($vx < $vy)
476
+ {
477
+ if ($value{$vx} == "x" || $value{$vx} == "X")
478
+ {
479
+ $vx++;
480
+ if ($vx < $vy)
481
+ {
482
+ for ($x = $vx; $x < $vy; $x++)
483
+ {
484
+ $val = ord($value{$x});
485
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
486
+ }
487
+
488
+ $num = hexdec(substr($value, $vx, $x - $vx));
489
+ $vx = $x;
490
+ if ($vx < $vy && $value{$vx} == ";") $vx++;
491
+
492
+ $value2 .= self::UTF8Chr($num);
493
+ }
494
+ }
495
+ else
496
+ {
497
+ for ($x = $vx; $x < $vy; $x++)
498
+ {
499
+ $val = ord($value{$x});
500
+ if (!($val >= $zero && $val <= $nine)) break;
501
+ }
502
+
503
+ $num = (int)substr($value, $vx, $x - $vx);
504
+ $vx = $x;
505
+ if ($vx < $vy && $value{$vx} == ";") $vx++;
506
+
507
+ $value2 .= self::UTF8Chr($num);
508
+ }
509
+ }
510
+ }
511
+ else if ($pos2 < $pos)
512
+ {
513
+ // Unicode (e.g. \0020)
514
+ $value2 .= substr($value, $vx, $pos2 - $vx);
515
+ $vx = $pos2 + 1;
516
+ if ($vx >= $vy) $value2 .= "\\";
517
+ else
518
+ {
519
+ for ($x = $vx; $x < $vy; $x++)
520
+ {
521
+ $val = ord($value{$x});
522
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
523
+ }
524
+
525
+ if ($x > $vx)
526
+ {
527
+ $num = hexdec(substr($value, $vx, $x - $vx));
528
+ $vx = $x;
529
+
530
+ $value2 .= self::UTF8Chr($num);
531
+ }
532
+ else
533
+ {
534
+ $value2 .= "\\";
535
+ }
536
+ }
537
+ }
538
+ else
539
+ {
540
+ $value2 .= substr($value, $vx);
541
+ $vx = $vy;
542
+ }
543
+ }
544
+ $value = $value2;
545
+
546
+ if (!$this->options["keep_attr_newlines"]) $value = str_replace(array("\r\n", "\r", "\n"), " ", $value);
547
+
548
+ if (isset($this->options["process_attrs"][$keyname]))
549
+ {
550
+ $type = $this->options["process_attrs"][$keyname];
551
+ if ($type === "classes")
552
+ {
553
+ $classes = explode(" ", $value);
554
+ $value = array();
555
+ foreach ($classes as $class)
556
+ {
557
+ if ($class !== "") $value[$class] = $class;
558
+ }
559
+ }
560
+ else if ($type === "uri")
561
+ {
562
+ $value = str_replace(array("\0", "\r", "\n", "\t", " "), "", $value);
563
+ $pos = strpos($value, ":");
564
+ if ($pos !== false) $value = preg_replace('/[^a-z]/', "", strtolower(substr($value, 0, $pos))) . substr($value, $pos);
565
+ }
566
+ }
567
+
568
+ $attrs[$keyname] = $value;
569
+ }
570
+ }
571
+ } while ($cx < $cy && $state !== "exit");
572
+
573
+ // Break out of the loop if the end of the stream has been reached but not finalized and most likely in the middle of a tag.
574
+ if ($cx >= $cy && !$this->final)
575
+ {
576
+ $cx = $firstcx;
577
+
578
+ break;
579
+ }
580
+
581
+ unset($attrs[""]);
582
+
583
+ if ($cx < $cy && $content{$cx} === ">") $cx++;
584
+
585
+ if (isset($this->options["tag_name_map"][$prefix . $tagname])) $outtagname = $tagname = $this->options["tag_name_map"][$prefix . $tagname];
586
+
587
+ if ($tagname != "")
588
+ {
589
+ if ($open)
590
+ {
591
+ if ($voidtag && isset($this->options["void_tags"][$tagname])) $voidtag = false;
592
+ $this->options["tag_num"]++;
593
+
594
+ // Let a callback handle any necessary changes.
595
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, $open, $prefix . $tagname, &$attrs, $this->options));
596
+ else $funcresult = array();
597
+
598
+ if (!isset($funcresult["keep_tag"])) $funcresult["keep_tag"] = true;
599
+ if (!isset($funcresult["keep_interior"])) $funcresult["keep_interior"] = true;
600
+ if (!isset($funcresult["pre_tag"])) $funcresult["pre_tag"] = "";
601
+ if (!isset($funcresult["post_tag"])) $funcresult["post_tag"] = "";
602
+ if (!isset($funcresult["state"])) $funcresult["state"] = false;
603
+ }
604
+
605
+ if ($open && $funcresult["keep_tag"])
606
+ {
607
+ $opentag = $funcresult["pre_tag"];
608
+ $opentag .= "<" . $prefix . $outtagname;
609
+ foreach ($attrs as $key => $val)
610
+ {
611
+ $opentag .= " " . $key;
612
+
613
+ if (is_array($val)) $val = implode(" ", $val);
614
+ if (is_string($val))
615
+ {
616
+ if ($this->options["charset"] === "UTF-8" && !self::IsValidUTF8($val)) $val = self::MakeValidUTF8($val);
617
+ $opentag .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $this->options["charset"]) . "\"";
618
+ }
619
+ }
620
+ if (($voidtag || isset($this->options["void_tags"][$tagname])) && $this->options["output_mode"] === "xml")
621
+ {
622
+ $opentag .= " /";
623
+
624
+ $voidtag = false;
625
+ }
626
+ $opentag .= ">";
627
+
628
+ if (!isset($this->options["void_tags"][$tagname]) && $prefix === "")
629
+ {
630
+ array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => $opentag, "close_tag" => true, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
631
+ $result = "";
632
+
633
+ if ($voidtag) $open = false;
634
+ }
635
+ else
636
+ {
637
+ $result .= $opentag;
638
+ $result .= $funcresult["post_tag"];
639
+ }
640
+ }
641
+
642
+ if ((!$open || !$funcresult["keep_tag"]) && !isset($this->options["void_tags"][$tagname]))
643
+ {
644
+ if ($open)
645
+ {
646
+ array_unshift($this->stack, array("tag_num" => $this->options["tag_num"], "tag_name" => $tagname, "out_tag_name" => $outtagname, "attrs" => $attrs, "result" => $result, "open_tag" => "", "close_tag" => false, "keep_interior" => $funcresult["keep_interior"], "post_tag" => $funcresult["post_tag"], "state" => $funcresult["state"]));
647
+ $result = "";
648
+ }
649
+
650
+ if (!$open)
651
+ {
652
+ $found = false;
653
+ foreach ($this->stack as $info)
654
+ {
655
+ if ($tagname === $info["tag_name"])
656
+ {
657
+ $found = true;
658
+
659
+ break;
660
+ }
661
+ }
662
+
663
+ if ($found)
664
+ {
665
+ do
666
+ {
667
+ // Let a callback handle any necessary changes.
668
+ $attrs = array();
669
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
670
+ else $funcresult = array();
671
+
672
+ // Force close tag to be kept if the stream already output the open tag.
673
+ if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
674
+
675
+ $info = array_shift($this->stack);
676
+
677
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
678
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
679
+ } while ($tagname !== $info["tag_name"]);
680
+ }
681
+ }
682
+ }
683
+ }
684
+
685
+ //echo "Current output:\n" . $result . "\n\n";
686
+ //echo "Prefix: " . $prefix . "\n\n";
687
+ //echo "Tag: " . $tagname . "\n\n";
688
+ //echo "Attrs:\n";
689
+ //var_dump($attrs);
690
+ //
691
+ //echo "Tag stack:\n";
692
+ //var_dump($this->stack);
693
+ //
694
+ //echo "\n\n";
695
+ //echo $content . "\n";
696
+ //exit();
697
+
698
+ $tag = false;
699
+ }
700
+ else
701
+ {
702
+ $regular = true;
703
+
704
+ // Special content handler for certain tags.
705
+ if (count($this->stack) && isset($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]) && is_callable($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]]))
706
+ {
707
+ $content2 = "";
708
+
709
+ // Expected to return true until the function is no longer interested in the data.
710
+ if (call_user_func_array($this->options["alt_tag_content_rules"][$this->stack[0]["tag_name"]], array($this->stack, $this->final, &$tag, &$content, &$cx, $cy, &$content2, $this->options))) $regular = false;
711
+ else if (!$this->final)
712
+ {
713
+ // Let a callback handle any necessary changes.
714
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
715
+
716
+ $result .= $content2;
717
+
718
+ break;
719
+ }
720
+ }
721
+
722
+ if ($regular)
723
+ {
724
+ // Regular content.
725
+ $pos = strpos($content, "<", $cx);
726
+ if ($pos === false)
727
+ {
728
+ $content2 = str_replace(">", "&gt;", substr($content, $cx));
729
+ $cx = $cy;
730
+ }
731
+ else
732
+ {
733
+ $content2 = str_replace(">", "&gt;", substr($content, $cx, $pos - $cx));
734
+ $cx = $pos;
735
+
736
+ $tag = true;
737
+ }
738
+ }
739
+
740
+ // Let a callback handle any necessary changes.
741
+ if (isset($this->options["content_callback"]) && is_callable($this->options["content_callback"])) call_user_func_array($this->options["content_callback"], array($this->stack, $result, &$content2, $this->options));
742
+
743
+ $result .= $content2;
744
+ }
745
+ }
746
+
747
+ if ($this->final)
748
+ {
749
+ while (count($this->stack))
750
+ {
751
+ // Let a callback handle any necessary changes.
752
+ $attrs = array();
753
+ if (isset($this->options["tag_callback"]) && is_callable($this->options["tag_callback"])) $funcresult = call_user_func_array($this->options["tag_callback"], array($this->stack, &$result, false, "/" . $this->stack[0]["tag_name"], &$attrs, $this->options));
754
+ else $funcresult = array();
755
+
756
+ $info = array_shift($this->stack);
757
+
758
+ // Force close tag to be kept if the stream already output the open tag.
759
+ if (!isset($funcresult["keep_tag"]) || ($info["close_tag"] && $info["open_tag"] == "")) $funcresult["keep_tag"] = true;
760
+
761
+ $result = $info["result"] . ($funcresult["keep_tag"] ? $info["open_tag"] : "") . ($info["keep_interior"] ? $result : "");
762
+ if ($info["close_tag"] && $funcresult["keep_tag"]) $result .= "</" . $info["out_tag_name"] . ">" . $info["post_tag"];
763
+ }
764
+ }
765
+ else
766
+ {
767
+ $this->lastcontent = ($cx < $cy ? substr($content, $cx) : "");
768
+ $this->lastresult = $result;
769
+ $result = "";
770
+ }
771
+
772
+ return $result;
773
+ }
774
+
775
+ public function Finalize()
776
+ {
777
+ $this->final = true;
778
+ }
779
+
780
+ // To cleanly figure out how far in to flush output, call GetStack(true), use TagFilter::GetParentPos(), and call GetResult().
781
+ public function GetStack($invert = false)
782
+ {
783
+ return ($invert ? array_reverse($this->stack) : $this->stack);
784
+ }
785
+
786
+ // Returns the result so far up to the specified stack position and flushes the stored output to keep RAM usage low.
787
+ // NOTE: Callback functions returning 'keep_tag' of false for the closing tag won't work for tags that were already output using this function.
788
+ public function GetResult($invertedstackpos)
789
+ {
790
+ $y = count($this->stack);
791
+ $pos = $y - $invertedstackpos - 1;
792
+ if ($pos < 0) $pos = 0;
793
+
794
+ $result = "";
795
+ for ($x = $y - 1; $x >= $pos; $x--)
796
+ {
797
+ $result .= $this->stack[$x]["result"] . $this->stack[$x]["open_tag"];
798
+
799
+ $this->stack[$x]["result"] = "";
800
+ $this->stack[$x]["open_tag"] = "";
801
+ }
802
+
803
+ if (!$pos)
804
+ {
805
+ $result .= $this->lastresult;
806
+ $this->lastresult = "";
807
+ }
808
+
809
+ return $result;
810
+ }
811
+
812
+ public static function MakeValidUTF8($data)
813
+ {
814
+ $result = "";
815
+ $x = 0;
816
+ $y = strlen($data);
817
+ while ($x < $y)
818
+ {
819
+ $tempchr = ord($data[$x]);
820
+ if ($y - $x > 1) $tempchr2 = ord($data[$x + 1]);
821
+ else $tempchr2 = 0x00;
822
+ if ($y - $x > 2) $tempchr3 = ord($data[$x + 2]);
823
+ else $tempchr3 = 0x00;
824
+ if ($y - $x > 3) $tempchr4 = ord($data[$x + 3]);
825
+ else $tempchr4 = 0x00;
826
+ if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D)
827
+ {
828
+ // ASCII minus control and special characters.
829
+ $result .= chr($tempchr);
830
+ $x++;
831
+ }
832
+ else if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF))
833
+ {
834
+ // Non-overlong (2 bytes).
835
+ $result .= chr($tempchr);
836
+ $result .= chr($tempchr2);
837
+ $x += 2;
838
+ }
839
+ else if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
840
+ {
841
+ // Non-overlong (3 bytes).
842
+ $result .= chr($tempchr);
843
+ $result .= chr($tempchr2);
844
+ $result .= chr($tempchr3);
845
+ $x += 3;
846
+ }
847
+ else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
848
+ {
849
+ // Normal/straight (3 bytes).
850
+ $result .= chr($tempchr);
851
+ $result .= chr($tempchr2);
852
+ $result .= chr($tempchr3);
853
+ $x += 3;
854
+ }
855
+ else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF))
856
+ {
857
+ // Non-surrogates (3 bytes).
858
+ $result .= chr($tempchr);
859
+ $result .= chr($tempchr2);
860
+ $result .= chr($tempchr3);
861
+ $x += 3;
862
+ }
863
+ else if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
864
+ {
865
+ // Planes 1-3 (4 bytes).
866
+ $result .= chr($tempchr);
867
+ $result .= chr($tempchr2);
868
+ $result .= chr($tempchr3);
869
+ $result .= chr($tempchr4);
870
+ $x += 4;
871
+ }
872
+ else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
873
+ {
874
+ // Planes 4-15 (4 bytes).
875
+ $result .= chr($tempchr);
876
+ $result .= chr($tempchr2);
877
+ $result .= chr($tempchr3);
878
+ $result .= chr($tempchr4);
879
+ $x += 4;
880
+ }
881
+ else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F) && ($tempchr3 >= 0x80 && $tempchr3 <= 0xBF) && ($tempchr4 >= 0x80 && $tempchr4 <= 0xBF))
882
+ {
883
+ // Plane 16 (4 bytes).
884
+ $result .= chr($tempchr);
885
+ $result .= chr($tempchr2);
886
+ $result .= chr($tempchr3);
887
+ $result .= chr($tempchr4);
888
+ $x += 4;
889
+ }
890
+ else $x++;
891
+ }
892
+
893
+ return $result;
894
+ }
895
+
896
+ public static function IsValidUTF8($data)
897
+ {
898
+ $x = 0;
899
+ $y = strlen($data);
900
+ while ($x < $y)
901
+ {
902
+ $tempchr = ord($data{$x});
903
+ if (($tempchr >= 0x20 && $tempchr <= 0x7E) || $tempchr == 0x09 || $tempchr == 0x0A || $tempchr == 0x0D) $x++;
904
+ else if ($tempchr < 0xC2) return false;
905
+ else
906
+ {
907
+ $left = $y - $x;
908
+ if ($left > 1) $tempchr2 = ord($data{$x + 1});
909
+ else return false;
910
+
911
+ if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 2;
912
+ else
913
+ {
914
+ if ($left > 2) $tempchr3 = ord($data{$x + 2});
915
+ else return false;
916
+
917
+ if ($tempchr3 < 0x80 || $tempchr3 > 0xBF) return false;
918
+
919
+ if ($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF)) $x += 3;
920
+ else if ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 3;
921
+ else if ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F)) $x += 3;
922
+ else
923
+ {
924
+ if ($left > 3) $tempchr4 = ord($data{$x + 3});
925
+ else return false;
926
+
927
+ if ($tempchr4 < 0x80 || $tempchr4 > 0xBF) return false;
928
+
929
+ if ($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF)) $x += 4;
930
+ else if (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) $x += 4;
931
+ else if ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F)) $x += 4;
932
+ else return false;
933
+ }
934
+ }
935
+ }
936
+ }
937
+
938
+ return true;
939
+ }
940
+
941
+ public static function UTF8Chr($num)
942
+ {
943
+ if ($num < 0 || ($num >= 0xD800 && $num <= 0xDFFF) || ($num >= 0xFDD0 && $num <= 0xFDEF) || ($num & 0xFFFE) == 0xFFFE) return "";
944
+
945
+ if ($num <= 0x7F) $result = chr($num);
946
+ else if ($num <= 0x7FF) $result = chr(0xC0 | ($num >> 6)) . chr(0x80 | ($num & 0x3F));
947
+ else if ($num <= 0xFFFF) $result = chr(0xE0 | ($num >> 12)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
948
+ else if ($num <= 0x10FFFF) $result = chr(0xF0 | ($num >> 18)) . chr(0x80 | (($num >> 12) & 0x3F)) . chr(0x80 | (($num >> 6) & 0x3F)) . chr(0x80 | ($num & 0x3F));
949
+ else $result = "";
950
+
951
+ return $result;
952
+ }
953
+ }
954
+
955
+ // Accessing the data in TagFilterNodes (with an 's') via objects is not the most performance-friendly method of access.
956
+ // The classes TagFilterNode and TagFilterNodeIterator defer method calls to the referenced TagFilterNodes instance.
957
+ // Removed/replaced nodes in the original data will result in undefined behavior with object reuse.
958
+ class TagFilterNode
959
+ {
960
+ private $tfn, $id;
961
+
962
+ public function __construct($tfn, $rootid)
963
+ {
964
+ $this->tfn = $tfn;
965
+ $this->id = $rootid;
966
+ }
967
+
968
+ public function __get($key)
969
+ {
970
+ return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]) ? $this->tfn->nodes[$this->id]["attrs"][$key] : false);
971
+ }
972
+
973
+ public function __set($key, $val)
974
+ {
975
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
976
+ {
977
+ if (is_array($val)) $this->tfn->nodes[$this->id]["attrs"][$key] = $val;
978
+ else if (isset($this->tfn->nodes[$this->id]["attrs"][$key]) && is_array($this->tfn->nodes[$this->id]["attrs"][$key])) $this->tfn->nodes[$this->id]["attrs"][$key][(string)$val] = (string)$val;
979
+ else $this->tfn->nodes[$this->id]["attrs"][$key] = (string)$val;
980
+ }
981
+ }
982
+
983
+ public function __isset($key)
984
+ {
985
+ return (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]) && isset($this->tfn->nodes[$this->id]["attrs"][$key]));
986
+ }
987
+
988
+ public function __unset($key)
989
+ {
990
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"])) unset($this->tfn->nodes[$this->id]["attrs"][$key]);
991
+ }
992
+
993
+ public function __toString()
994
+ {
995
+ return $this->tfn->GetOuterHTML($this->id);
996
+ }
997
+
998
+ public function __debugInfo()
999
+ {
1000
+ $result = (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : array());
1001
+ $result["id"] = $this->id;
1002
+
1003
+ return $result;
1004
+ }
1005
+
1006
+ public function ID()
1007
+ {
1008
+ return $this->id;
1009
+ }
1010
+
1011
+ public function Node()
1012
+ {
1013
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id] : false);
1014
+ }
1015
+
1016
+ public function Type()
1017
+ {
1018
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["type"] : false);
1019
+ }
1020
+
1021
+ public function Tag()
1022
+ {
1023
+ return $this->tfn->GetTag($this->id);
1024
+ }
1025
+
1026
+ public function Text($val = null)
1027
+ {
1028
+ if ($val !== null) $this->tfn->SetText($this->id, $val);
1029
+ else return $this->tfn->GetText($this->id);
1030
+ }
1031
+
1032
+ public function AddClass($name, $attr = "class")
1033
+ {
1034
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1035
+ {
1036
+ if (!isset($this->tfn->nodes[$this->id]["attrs"][$attr]) || !is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) $this->tfn->nodes[$this->id]["attrs"][$attr] = array();
1037
+
1038
+ $this->tfn->nodes[$this->id]["attrs"][$attr][$name] = $name;
1039
+ }
1040
+ }
1041
+
1042
+ public function RemoveClass($name, $attr = "class")
1043
+ {
1044
+ if (isset($this->tfn->nodes[$this->id]) && isset($this->tfn->nodes[$this->id]["attrs"]))
1045
+ {
1046
+ if (isset($this->tfn->nodes[$this->id]["attrs"][$attr]) && is_array($this->tfn->nodes[$this->id]["attrs"][$attr])) unset($this->tfn->nodes[$this->id]["attrs"][$attr][$name]);
1047
+ }
1048
+ }
1049
+
1050
+ public function Parent()
1051
+ {
1052
+ return $this->tfn->GetParent($this->id);
1053
+ }
1054
+
1055
+ public function ParentPos()
1056
+ {
1057
+ return (isset($this->tfn->nodes[$this->id]) ? $this->tfn->nodes[$this->id]["parentpos"] : false);
1058
+ }
1059
+
1060
+ // Passing true to this method has the potential to leak RAM. Passing false is preferred, use with caution.
1061
+ public function Children($objects = false)
1062
+ {
1063
+ return $this->tfn->GetChildren($this->id, $objects);
1064
+ }
1065
+
1066
+ public function Child($pos)
1067
+ {
1068
+ return $this->tfn->GetChild($this->id, $pos);
1069
+ }
1070
+
1071
+ public function PrevSibling()
1072
+ {
1073
+ return $this->tfn->GetPrevSibling($this->id);
1074
+ }
1075
+
1076
+ public function NextSibling()
1077
+ {
1078
+ return $this->tfn->GetNextSibling($this->id);
1079
+ }
1080
+
1081
+ public function Find($query, $cachequery = true, $firstmatch = false)
1082
+ {
1083
+ $result = $this->tfn->Find($query, $this->id, $cachequery, $firstmatch);
1084
+ if (!$result["success"]) return $result;
1085
+
1086
+ return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1087
+ }
1088
+
1089
+ public function Implode($options = array())
1090
+ {
1091
+ return $this->tfn->Implode($this->id, $options);
1092
+ }
1093
+
1094
+ public function GetOuterHTML($mode = "html")
1095
+ {
1096
+ return $this->tfn->GetOuterHTML($this->id, $mode);
1097
+ }
1098
+
1099
+ // Set functions ruin the object.
1100
+ public function SetOuterHTML($src)
1101
+ {
1102
+ return $this->tfn->SetOuterHTML($this->id, $src);
1103
+ }
1104
+
1105
+ public function GetInnerHTML($mode = "html")
1106
+ {
1107
+ return $this->tfn->GetInnerHTML($this->id, $mode);
1108
+ }
1109
+
1110
+ public function SetInnerHTML($src)
1111
+ {
1112
+ return $this->tfn->SetInnerHTML($this->id, $src);
1113
+ }
1114
+
1115
+ public function GetPlainText()
1116
+ {
1117
+ return $this->tfn->GetPlainText($this->id);
1118
+ }
1119
+
1120
+ // Set functions ruin the object.
1121
+ public function SetPlainText($src)
1122
+ {
1123
+ return $this->tfn->SetPlainText($this->id, $src);
1124
+ }
1125
+ }
1126
+
1127
+ class TagFilterNodeIterator implements Iterator, Countable
1128
+ {
1129
+ private $tfn, $ids, $x, $y;
1130
+
1131
+ public function __construct($tfn, $ids)
1132
+ {
1133
+ $this->tfn = $tfn;
1134
+ $this->ids = $ids;
1135
+ $this->x = 0;
1136
+ $this->y = count($ids);
1137
+ }
1138
+
1139
+ public function rewind()
1140
+ {
1141
+ $this->x = 0;
1142
+ }
1143
+
1144
+ public function valid()
1145
+ {
1146
+ return ($this->x < $this->y);
1147
+ }
1148
+
1149
+ public function current()
1150
+ {
1151
+ return $this->tfn->Get($this->ids[$this->x]);
1152
+ }
1153
+
1154
+ public function key()
1155
+ {
1156
+ return $this->ids[$this->x];
1157
+ }
1158
+
1159
+ public function next()
1160
+ {
1161
+ $this->x++;
1162
+ }
1163
+
1164
+ public function count()
1165
+ {
1166
+ return $this->y;
1167
+ }
1168
+
1169
+ public function Filter($query, $cachequery = true)
1170
+ {
1171
+ $result = $this->tfn->Filter($this->ids, $query, $cachequery);
1172
+ if (!$result["success"]) return $result;
1173
+
1174
+ return new TagFilterNodeIterator($this->tfn, $result["ids"]);
1175
+ }
1176
+ }
1177
+
1178
+ // Output from TagFilter::Explode().
1179
+ class TagFilterNodes
1180
+ {
1181
+ public $nodes, $nextid;
1182
+ private $queries;
1183
+
1184
+ public function __construct()
1185
+ {
1186
+ $this->nodes = array(
1187
+ array(
1188
+ "type" => "root",
1189
+ "parent" => false,
1190
+ "parentpos" => false,
1191
+ "children" => array()
1192
+ )
1193
+ );
1194
+
1195
+ $this->nextid = 1;
1196
+ $this->queries = array();
1197
+ }
1198
+
1199
+ // Makes a selector suitable for Find() and Filter() by altering or removing rules. Query is not cached.
1200
+ public static function MakeValidSelector($query)
1201
+ {
1202
+ if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1203
+ else if (isset($query["success"]) && isset($query["tokens"]))
1204
+ {
1205
+ $result = $query;
1206
+ $result["tokens"] = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true);
1207
+ }
1208
+ else
1209
+ {
1210
+ $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens(array_reverse($query), true));
1211
+ }
1212
+
1213
+ // Alter certain CSS3 tokens to equivalent tokens.
1214
+ foreach ($result["tokens"] as $num => $rules)
1215
+ {
1216
+ foreach ($rules as $num2 => $rule)
1217
+ {
1218
+ if ($rule["type"] === "pseudo-class")
1219
+ {
1220
+ if ($rule["pseudo"] === "link") $result["tokens"][$num][$num2] = array("not" => false, "type" => "element", "namespace" => false, "tag" => "a");
1221
+ else if ($rule["pseudo"] === "disabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "disabled", "cmp" => false);
1222
+ else if ($rule["pseudo"] === "enabled") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "enabled", "cmp" => false);
1223
+ else if ($rule["pseudo"] === "checked") $result["tokens"][$num][$num2] = array("not" => false, "type" => "attr", "namespace" => false, "attr" => "checked", "cmp" => false);
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ // Reorder the tokens so that the order is simple for output.
1229
+ $tokens = TagFilter::ReorderSelectorTokens(array_reverse($result["tokens"]), true, array("element" => array(), "id" => array(), "class" => array(), "attr" => array(), "pseudo-class" => array(), "pseudo-element" => array()), false);
1230
+
1231
+ // Generate a duplicate-free Find()-safe string.
1232
+ $result = array();
1233
+ foreach ($tokens as $rules)
1234
+ {
1235
+ $groups = array();
1236
+ $strs = array();
1237
+ $rules = array_reverse($rules);
1238
+ $y = count($rules);
1239
+ for ($x = 0; $x < $y; $x++)
1240
+ {
1241
+ $str = "";
1242
+
1243
+ if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ":not(";
1244
+
1245
+ switch ($rules[$x]["type"])
1246
+ {
1247
+ case "id": $str .= "#" . $rules[$x]["id"]; $valid = true; break;
1248
+ case "element": $str .= ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["tag"]); $valid = true; break;
1249
+ case "class": $str .= "." . $rules[$x]["class"]; $valid = true; break;
1250
+ case "attr": $str .= "[" . ($rules[$x]["namespace"] !== false ? $rules[$x]["namespace"] . "|" : "") . strtolower($rules[$x]["attr"]) . ($rules[$x]["cmp"] !== false ? $rules[$x]["cmp"] . "\"" . str_replace("\"", "\\\"", $rules[$x]["val"]) . "\"" : "") . "]"; $valid = true; break;
1251
+ case "pseudo-class":
1252
+ {
1253
+ $pc = $rules[$x]["pseudo"];
1254
+ $valid = ($pc === "first-child" || $pc === "last-child" || $pc === "only-child" || $pc === "nth-child" || $pc === "nth-last-child" || $pc === "first-child-all" || $pc === "last-child-all" || $pc === "only-child-all" || $pc === "nth-child-all" || $pc === "nth-last-child-all" || $pc === "first-of-type" || $pc === "last-of-type" || $pc === "only-of-type" || $pc === "nth-of-type" || $pc === "nth-last-of-type" || $pc === "empty");
1255
+
1256
+ if ($valid && substr($rules[$x]["pseudo"], 0, 4) === "nth-" && (!isset($rules[$x]["a"]) || !isset($rules[$x]["b"]))) $valid = false;
1257
+
1258
+ break;
1259
+ }
1260
+ case "combine":
1261
+ {
1262
+ switch ($rules[$x]["combine"])
1263
+ {
1264
+ case "prev-parent": $groups[] = implode("", $strs); $groups[] = ">"; $strs = array(); $valid = true; break;
1265
+ case "any-parent": $groups[] = implode("", $strs); $strs = array(); $valid = true; break;
1266
+ case "prev-sibling": $groups[] = implode("", $strs); $groups[] = "+"; $strs = array(); $valid = true; break;
1267
+ case "any-prev-sibling": $groups[] = implode("", $strs); $groups[] = "~"; $strs = array(); $valid = true; break;
1268
+ default: $valid = false;
1269
+ }
1270
+
1271
+ break;
1272
+ }
1273
+ default: $valid = false; break;
1274
+ }
1275
+
1276
+ if (!$valid) break;
1277
+
1278
+ if (isset($rules[$x]["not"]) && $rules[$x]["not"]) $str .= ")";
1279
+
1280
+ $strs[$str] = $str;
1281
+ }
1282
+
1283
+ if ($x == $y)
1284
+ {
1285
+ if (count($strs)) $groups[] = implode("", $strs);
1286
+ $str = implode(" ", $groups);
1287
+ $result[$str] = $str;
1288
+ }
1289
+ }
1290
+
1291
+ return implode(", ", $result);
1292
+ }
1293
+
1294
+ public function Find($query, $id = 0, $cachequery = true, $firstmatch = false)
1295
+ {
1296
+ $id = (int)$id;
1297
+ if (!isset($this->nodes[$id])) return array("success" => false, "error" => "Invalid initial ID.", "errorcode" => "invalid_init_id");
1298
+
1299
+ if (isset($this->queries[$query])) $result = $this->queries[$query];
1300
+ else
1301
+ {
1302
+ if (!is_array($query)) $result = TagFilter::ParseSelector($query, true);
1303
+ else if (isset($query["success"]) && isset($result["selector"]) && isset($query["tokens"]))
1304
+ {
1305
+ $result = $query;
1306
+ $result["tokens"] = TagFilter::ReorderSelectorTokens($result["tokens"], true);
1307
+
1308
+ $query = $result["selector"];
1309
+ }
1310
+ else
1311
+ {
1312
+ $result = array("success" => true, "tokens" => TagFilter::ReorderSelectorTokens($query, true));
1313
+
1314
+ $cachequery = false;
1315
+ }
1316
+
1317
+ if ($cachequery)
1318
+ {
1319
+ foreach ($this->queries as $key => $val)
1320
+ {
1321
+ if (count($this->queries) < 25) break;
1322
+
1323
+ unset($this->queries[$key]);
1324
+ }
1325
+
1326
+ $this->queries[$query] = $result;
1327
+ }
1328
+ }
1329
+
1330
+ if (!$result["success"]) return $result;
1331
+
1332
+ $rules = $result["tokens"];
1333
+ $numrules = count($rules);
1334
+
1335
+ $result = array();
1336
+ $childcache = array();
1337
+ $oftypecache = array();
1338
+ $rootid = $id;
1339
+ $pos = 0;
1340
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1341
+ do
1342
+ {
1343
+ if (!$pos && $this->nodes[$id]["type"] === "element")
1344
+ {
1345
+ // Attempt to match a rule.
1346
+ for ($x = 0; $x < $numrules; $x++)
1347
+ {
1348
+ $id2 = $id;
1349
+ $y = count($rules[$x]);
1350
+ for ($x2 = 0; $x2 < $y; $x2++)
1351
+ {
1352
+ if ($this->nodes[$id2]["type"] === "content" || $this->nodes[$id2]["type"] === "comment")
1353
+ {
1354
+ // Always backtrack at non-element nodes since the rules are element based.
1355
+ $backtrack = !(isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]);
1356
+ }
1357
+ else if (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false && $rules[$x][$x2]["namespace"] !== "*" && (($rules[$x][$x2]["namespace"] === "" && strpos($this->nodes[$id2]["tag"], ":") !== false) || ($rules[$x][$x2]["namespace"] !== "" && strcasecmp(substr($this->nodes[$id2]["tag"], 0, strlen($rules[$x][$x2]["namespace"]) + 1), $rules[$x][$x2]["namespace"] . ":") !== 0)))
1358
+ {
1359
+ $backtrack = true;
1360
+ }
1361
+ else
1362
+ {
1363
+ switch ($rules[$x][$x2]["type"])
1364
+ {
1365
+ case "id": $backtrack = (!isset($this->nodes[$id2]["attrs"]["id"]) || $this->nodes[$id2]["attrs"]["id"] !== $rules[$x][$x2]["id"]); break;
1366
+ case "element": $backtrack = (strcasecmp($this->nodes[$id2]["tag"], (isset($rules[$x][$x2]["namespace"]) && $rules[$x][$x2]["namespace"] !== false ? $rules[$x][$x2]["namespace"] . ":" : "") . $rules[$x][$x2]["tag"]) !== 0); break;
1367
+ case "class": $backtrack = (!isset($this->nodes[$id2]["attrs"]["class"]) || !isset($this->nodes[$id2]["attrs"]["class"][$rules[$x][$x2]["class"]])); break;
1368
+ case "attr":
1369
+ {
1370
+ $attr = strtolower($rules[$x][$x2]["attr"]);
1371
+ if (!isset($this->nodes[$id2]["attrs"][$attr])) $backtrack = true;
1372
+ else
1373
+ {
1374
+ $val = $this->nodes[$id2]["attrs"][$attr];
1375
+ if (is_array($val)) $val = implode(" ", $val);
1376
+
1377
+ switch ($rules[$x][$x2]["cmp"])
1378
+ {
1379
+ case "=": $backtrack = ($val !== $rules[$x][$x2]["val"]); break;
1380
+ case "^=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, 0, strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1381
+ case "$=": $backtrack = ($rules[$x][$x2]["val"] === "" || substr($val, -strlen($rules[$x][$x2]["val"])) !== $rules[$x][$x2]["val"]); break;
1382
+ case "*=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($val, $rules[$x][$x2]["val"]) === false); break;
1383
+ case "~=": $backtrack = ($rules[$x][$x2]["val"] === "" || strpos($rules[$x][$x2]["val"], " ") !== false || strpos(" " . $val . " ", " " . $rules[$x][$x2]["val"] . " ") === false); break;
1384
+ case "|=": $backtrack = ($rules[$x][$x2]["val"] === "" || ($val !== $rules[$x][$x2]["val"] && substr($val, 0, strlen($rules[$x][$x2]["val"]) + 1) !== $rules[$x][$x2]["val"] . "-")); break;
1385
+ default: $backtrack = false; break;
1386
+ }
1387
+ }
1388
+
1389
+ break;
1390
+ }
1391
+ case "pseudo-class":
1392
+ {
1393
+ // Handle various bits of common code.
1394
+ $pid = $this->nodes[$id2]["parent"];
1395
+ $pnum = count($this->nodes[$pid]["children"]);
1396
+
1397
+ $nth = (substr($rules[$x][$x2]["pseudo"], 0, 4) === "nth-");
1398
+ if ($nth && (!isset($rules[$x][$x2]["a"]) || !isset($rules[$x][$x2]["b"]))) return array("success" => false, "error" => "Pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "(n)' requires an expression for 'n'.", "errorcode" => "missing_pseudo_class_expression");
1399
+
1400
+ if (substr($rules[$x][$x2]["pseudo"], -6) === "-child")
1401
+ {
1402
+ if (!isset($childcache[$id2]))
1403
+ {
1404
+ $children = 0;
1405
+ foreach ($this->nodes[$pid]["children"] as $id3)
1406
+ {
1407
+ if ($this->nodes[$id3]["type"] === "element")
1408
+ {
1409
+ $childcache[$id3] = array("cx" => $children);
1410
+
1411
+ $children++;
1412
+ }
1413
+ }
1414
+
1415
+ foreach ($this->nodes[$pid]["children"] as $id3)
1416
+ {
1417
+ if ($this->nodes[$id3]["type"] === "element") $childcache[$id3]["cy"] = $children;
1418
+ }
1419
+ }
1420
+
1421
+ $cx = $childcache[$id2]["cx"];
1422
+ $cy = $childcache[$id2]["cy"];
1423
+ }
1424
+
1425
+ if (substr($rules[$x][$x2]["pseudo"], -8) === "-of-type")
1426
+ {
1427
+ if (!isset($oftypecache[$id2]))
1428
+ {
1429
+ $types = array();
1430
+ foreach ($this->nodes[$pid]["children"] as $id3)
1431
+ {
1432
+ if ($this->nodes[$id3]["type"] === "element")
1433
+ {
1434
+ $tag = $this->nodes[$id3]["tag"];
1435
+ if (!isset($types[$tag])) $types[$tag] = 0;
1436
+
1437
+ $oftypecache[$id3] = array("tx" => $types[$tag]);
1438
+
1439
+ $types[$tag]++;
1440
+ }
1441
+ }
1442
+
1443
+ foreach ($this->nodes[$pid]["children"] as $id3)
1444
+ {
1445
+ if ($this->nodes[$id3]["type"] === "element")
1446
+ {
1447
+ $tag = $this->nodes[$id3]["tag"];
1448
+ $oftypecache[$id3]["ty"] = $types[$tag];
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ $tx = $oftypecache[$id2]["tx"];
1454
+ $ty = $oftypecache[$id2]["ty"];
1455
+ }
1456
+
1457
+ switch ($rules[$x][$x2]["pseudo"])
1458
+ {
1459
+ case "first-child": $backtrack = ($cx !== 0); break;
1460
+ case "last-child": $backtrack = ($cx !== $cy - 1); break;
1461
+ case "only-child": $backtrack = ($cy !== 1); break;
1462
+ case "nth-child": $px = $cx; break;
1463
+ case "nth-last-child": $px = $cy - $cx - 1; break;
1464
+ case "first-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== 0); break;
1465
+ case "last-child-all": $backtrack = ($this->nodes[$id2]["parentpos"] !== $pnum - 1); break;
1466
+ case "only-child-all": $backtrack = ($pnum !== 1); break;
1467
+ case "nth-child-all": $px = $this->nodes[$id2]["parentpos"]; break;
1468
+ case "nth-last-child-all": $px = $pnum - $this->nodes[$id2]["parentpos"] - 1; break;
1469
+ case "first-of-type": $backtrack = ($tx !== 0); break;
1470
+ case "last-of-type": $backtrack = ($tx !== $ty - 1); break;
1471
+ case "only-of-type": $backtrack = ($ty !== 1); break;
1472
+ case "nth-of-type": $px = $tx; break;
1473
+ case "nth-last-of-type": $px = $ty - $tx - 1; break;
1474
+ case "empty":
1475
+ {
1476
+ $backtrack = false;
1477
+ foreach ($this->nodes[$id2]["children"] as $id3)
1478
+ {
1479
+ if ($this->nodes[$id3]["type"] === "element" || ($this->nodes[$id3]["type"] === "content" && trim($this->nodes[$id3]["text"]) !== ""))
1480
+ {
1481
+ $backtrack = true;
1482
+
1483
+ break;
1484
+ }
1485
+ }
1486
+
1487
+ break;
1488
+ }
1489
+ default: return array("success" => false, "error" => "Unknown/Unsupported pseudo-class ':" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unknown_unsupported_pseudo_class");
1490
+ }
1491
+
1492
+ if ($nth)
1493
+ {
1494
+ // Calculated expression: a * n + b - 1 = x
1495
+ // Solved for n: n = (x + 1 - b) / a
1496
+ // Where 'n' is a non-negative integer. When 'a' is 0, solve for 'b' instead.
1497
+ $pa = $rules[$x][$x2]["a"];
1498
+ $pb = $rules[$x][$x2]["b"];
1499
+
1500
+ if ($pa == 0) $backtrack = ($pb != $px + 1);
1501
+ else
1502
+ {
1503
+ $pn = (($px + 1 - $pb) / $pa);
1504
+
1505
+ $backtrack = ($pn < 0 || $pn - (int)$pn > 0.000001);
1506
+ }
1507
+ }
1508
+
1509
+ break;
1510
+ }
1511
+ case "pseudo-element": return array("success" => false, "error" => "Pseudo-elements are not supported. Found '::" . $rules[$x][$x2]["pseudo"] . "'.", "errorcode" => "unsupported_selector_type");
1512
+ case "combine":
1513
+ {
1514
+ switch ($rules[$x][$x2]["combine"])
1515
+ {
1516
+ case "prev-parent":
1517
+ case "any-parent":
1518
+ {
1519
+ $backtrack = ($id2 === $rootid || !$this->nodes[$id2]["parent"]);
1520
+ if (!$backtrack) $id2 = $this->nodes[$id2]["parent"];
1521
+
1522
+ break;
1523
+ }
1524
+ case "prev-sibling":
1525
+ case "any-prev-sibling":
1526
+ {
1527
+ $backtrack = ($this->nodes[$id2]["parentpos"] == 0);
1528
+ if (!$backtrack) $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1529
+
1530
+ break;
1531
+ }
1532
+ default: return array("success" => false, "error" => "Unknown combiner " . $rules[$x][$x2]["pseudo"] . ".", "errorcode" => "unknown_combiner");
1533
+ }
1534
+
1535
+ // For unknown parent/sibling combiners such as '~', use the rule stack to allow for backtracking to try another path if a match fails (e.g. h1 p ~ p).
1536
+ $rules[$x][$x2]["lastid"] = $id2;
1537
+
1538
+ break;
1539
+ }
1540
+ default: return array("success" => false, "error" => "Unknown selector type '" . $rules[$x][$x2]["type"] . "'.", "errorcode" => "unknown_selector_type");
1541
+ }
1542
+ }
1543
+
1544
+ if (isset($rules[$x][$x2]["not"]) && $rules[$x][$x2]["not"]) $backtrack = !$backtrack;
1545
+
1546
+ // Backtrack through the rule to an unknown parent/sibling combiner.
1547
+ if ($backtrack)
1548
+ {
1549
+ if ($x2)
1550
+ {
1551
+ for ($x2--; $x2; $x2--)
1552
+ {
1553
+ if ($rules[$x][$x2]["type"] === "combine")
1554
+ {
1555
+ if ($rules[$x][$x2]["combine"] === "any-parent")
1556
+ {
1557
+ $id2 = $rules[$x][$x2]["lastid"];
1558
+ if ($id2 !== $rootid && $this->nodes[$id2]["parent"])
1559
+ {
1560
+ $id2 = $this->nodes[$id2]["parent"];
1561
+ $rules[$x][$x2]["lastid"] = $id2;
1562
+
1563
+ break;
1564
+ }
1565
+ }
1566
+ else if ($rules[$x][$x2]["combine"] === "any-prev-sibling")
1567
+ {
1568
+ $id2 = $rules[$x][$x2]["lastid"];
1569
+ if ($this->nodes[$id2]["parentpos"] != 0)
1570
+ {
1571
+ $id2 = $this->nodes[$this->nodes[$id2]["parent"]]["children"][$this->nodes[$id2]["parentpos"] - 1];
1572
+ $rules[$x][$x2]["lastid"] = $id2;
1573
+
1574
+ break;
1575
+ }
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+
1581
+ if (!$x2) break;
1582
+ }
1583
+ }
1584
+
1585
+ // Match found.
1586
+ if ($x2 === $y)
1587
+ {
1588
+ $result[] = $id;
1589
+
1590
+ if ($firstmatch) return array("success" => true, "ids" => $result);
1591
+
1592
+ break;
1593
+ }
1594
+ }
1595
+ }
1596
+
1597
+ if ($pos >= $maxpos)
1598
+ {
1599
+ if ($rootid === $id) break;
1600
+
1601
+ $pos = $this->nodes[$id]["parentpos"] + 1;
1602
+ $id = $this->nodes[$id]["parent"];
1603
+ $maxpos = count($this->nodes[$id]["children"]);
1604
+ }
1605
+ else
1606
+ {
1607
+ $id = $this->nodes[$id]["children"][$pos];
1608
+ $pos = 0;
1609
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1610
+ }
1611
+ } while (1);
1612
+
1613
+ return array("success" => true, "ids" => $result);
1614
+ }
1615
+
1616
+ // Filter results from Find() based on a matching query.
1617
+ public function Filter($ids, $query, $cachequery = true)
1618
+ {
1619
+ if (!is_array($ids)) $ids = array($ids);
1620
+
1621
+ // Handle lazy chaining from both Find() and Filter().
1622
+ if (isset($ids["success"]))
1623
+ {
1624
+ if (!$ids["success"]) return $ids;
1625
+ if (!isset($ids["ids"])) return array("success" => false, "error" => "Bad filter input.", "invalid_filter_ids");
1626
+
1627
+ $ids = $ids["ids"];
1628
+ }
1629
+
1630
+ $ids2 = array();
1631
+ if (is_string($query) && strtolower(substr($query, 0, 10)) === "/contains:")
1632
+ {
1633
+ $query = substr($query, 10);
1634
+ foreach ($ids as $id)
1635
+ {
1636
+ if (strpos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1637
+ }
1638
+ }
1639
+ else if (is_string($query) && strtolower(substr($query, 0, 11)) === "/~contains:")
1640
+ {
1641
+ $query = substr($query, 11);
1642
+ foreach ($ids as $id)
1643
+ {
1644
+ if (stripos($this->GetPlainText($id), $query) !== false) $ids2[] = $id;
1645
+ }
1646
+ }
1647
+ else
1648
+ {
1649
+ foreach ($ids as $id)
1650
+ {
1651
+ $result = $this->Find($query, $id, $cachequery, true);
1652
+ if ($result["success"] && count($result["ids"])) $ids2[] = $id;
1653
+ }
1654
+ }
1655
+
1656
+ return array("success" => true, "ids" => $ids2);
1657
+ }
1658
+
1659
+ // Convert all or some of the nodes back into a string.
1660
+ public function Implode($id, $options = array())
1661
+ {
1662
+ $id = (int)$id;
1663
+ if (!isset($this->nodes[$id])) return "";
1664
+
1665
+ if (!isset($options["include_id"])) $options["include_id"] = true;
1666
+ if (!isset($options["types"])) $options["types"] = "element,content,comment";
1667
+ if (!isset($options["output_mode"])) $options["output_mode"] = "html";
1668
+ if (!isset($options["post_elements"])) $options["post_elements"] = array();
1669
+ if (!isset($options["no_content_elements"])) $options["no_content_elements"] = array("script" => true, "style" => true);
1670
+ if (!isset($options["charset"])) $options["charset"] = "UTF-8";
1671
+ $options["charset"] = strtoupper($options["charset"]);
1672
+
1673
+ $types2 = explode(",", $options["types"]);
1674
+ $types = array();
1675
+ foreach ($types2 as $type)
1676
+ {
1677
+ $type = trim($type);
1678
+ if ($type !== "") $types[$type] = true;
1679
+ }
1680
+
1681
+ $result = "";
1682
+ $include = (bool)$options["include_id"];
1683
+ $rootid = $id;
1684
+ $pos = 0;
1685
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1686
+ do
1687
+ {
1688
+ if (!$pos && isset($types[$this->nodes[$id]["type"]]))
1689
+ {
1690
+ switch ($this->nodes[$id]["type"])
1691
+ {
1692
+ case "element":
1693
+ {
1694
+ if ($include || $rootid != $id)
1695
+ {
1696
+ $result .= "<" . $this->nodes[$id]["tag"];
1697
+ foreach ($this->nodes[$id]["attrs"] as $key => $val)
1698
+ {
1699
+ $result .= " " . $key;
1700
+
1701
+ if (is_array($val)) $val = implode(" ", $val);
1702
+ if (is_string($val)) $result .= "=\"" . htmlspecialchars($val, ENT_COMPAT | ENT_HTML5, $options["charset"]) . "\"";
1703
+ }
1704
+ $result .= (!$maxpos && $options["output_mode"] === "xml" ? " />" : ">");
1705
+ }
1706
+
1707
+ break;
1708
+ }
1709
+ case "content":
1710
+ case "comment":
1711
+ {
1712
+ if (isset($types["element"]) || !isset($this->nodes[$this->nodes[$id]["parent"]]["tag"]) || !isset($options["no_content_elements"][$this->nodes[$this->nodes[$id]["parent"]]["tag"]])) $result .= $this->nodes[$id]["text"];
1713
+
1714
+ break;
1715
+ }
1716
+ default: break;
1717
+ }
1718
+ }
1719
+
1720
+ if ($pos >= $maxpos)
1721
+ {
1722
+ if ($this->nodes[$id]["type"] === "element" && is_array($this->nodes[$id]["children"]))
1723
+ {
1724
+ if (($include || $rootid != $id) && isset($types[$this->nodes[$id]["type"]])) $result .= "</" . $this->nodes[$id]["tag"] . ">";
1725
+ }
1726
+
1727
+ if ($this->nodes[$id]["type"] === "element" && isset($options["post_elements"][$this->nodes[$id]["tag"]])) $result .= $options["post_elements"][$this->nodes[$id]["tag"]];
1728
+
1729
+ if ($rootid === $id) break;
1730
+
1731
+ $pos = $this->nodes[$id]["parentpos"] + 1;
1732
+ $id = $this->nodes[$id]["parent"];
1733
+ $maxpos = count($this->nodes[$id]["children"]);
1734
+ }
1735
+ else
1736
+ {
1737
+ $id = $this->nodes[$id]["children"][$pos];
1738
+ $pos = 0;
1739
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1740
+ }
1741
+ } while (1);
1742
+
1743
+ return $result;
1744
+ }
1745
+
1746
+ // Object-oriented access methods. Only Get() supports multiple IDs.
1747
+ public function Get($id = 0)
1748
+ {
1749
+ if (is_array($id))
1750
+ {
1751
+ if (isset($id["success"]) && $id["ids"]) $id = $id["ids"];
1752
+
1753
+ $result = array();
1754
+ foreach ($id as $id2) $result[] = $this->Get($id2);
1755
+
1756
+ return $result;
1757
+ }
1758
+
1759
+ return ($id !== false && isset($this->nodes[$id]) ? new TagFilterNode($this, $id) : false);
1760
+ }
1761
+
1762
+ public function GetParent($id)
1763
+ {
1764
+ return ($id !== false && isset($this->nodes[$id]) && isset($this->nodes[$this->nodes[$id]["parent"]]) ? new TagFilterNode($this, $this->nodes[$id]["parent"]) : false);
1765
+ }
1766
+
1767
+ public function GetChildren($id, $objects = false)
1768
+ {
1769
+ if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1770
+
1771
+ return ($objects ? $this->Get($this->nodes[$id]["children"]) : $this->nodes[$id]["children"]);
1772
+ }
1773
+
1774
+ public function GetChild($id, $pos)
1775
+ {
1776
+ if (!isset($this->nodes[$id]) || !isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
1777
+
1778
+ $pos = (int)$pos;
1779
+ $y = count($this->nodes[$id]["children"]);
1780
+ if ($pos < 0) $pos = $y + $pos;
1781
+ if ($pos < 0 || $pos > $y - 1) return false;
1782
+
1783
+ return $this->Get($this->nodes[$id]["children"][$pos]);
1784
+ }
1785
+
1786
+ public function GetPrevSibling($id)
1787
+ {
1788
+ if (!isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] == 0) return false;
1789
+
1790
+ return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] - 1]);
1791
+ }
1792
+
1793
+ public function GetNextSibling($id)
1794
+ {
1795
+ if ($id === false || !isset($this->nodes[$id]) || $this->nodes[$id]["parentpos"] >= count($this->nodes[$this->nodes[$id]["parent"]]["children"]) - 1) return false;
1796
+
1797
+ return $this->Get($this->nodes[$this->nodes[$id]["parent"]]["children"][$this->nodes[$id]["parentpos"] + 1]);
1798
+ }
1799
+
1800
+ public function GetTag($id)
1801
+ {
1802
+ return (isset($this->nodes[$id]) && $this->nodes[$id]["type"] === "element" ? $this->nodes[$id]["tag"] : false);
1803
+ }
1804
+
1805
+ public function SetText($id, $val)
1806
+ {
1807
+ if (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment")) $this->nodes[$id]["text"] = (string)$val;
1808
+ }
1809
+
1810
+ public function GetText($id)
1811
+ {
1812
+ return (isset($this->nodes[$id]) && ($this->nodes[$id]["type"] === "content" || $this->nodes[$id]["type"] === "comment") ? $this->nodes[$id]["text"] : false);
1813
+ }
1814
+
1815
+ public function Move($src, $newpid, $newpos)
1816
+ {
1817
+ $newpid = (int)$newpid;
1818
+ if (!isset($this->nodes[$newpid]) || !isset($this->nodes[$newpid]["children"]) || !is_array($this->nodes[$newpid]["children"])) return false;
1819
+
1820
+ $newpos = (is_bool($newpos) ? count($this->nodes[$newpid]["children"]) : (int)$newpos);
1821
+ if ($newpos < 0) $newpos = count($this->nodes[$newpid]["children"]) + $newpos;
1822
+ if ($newpos < 0) $newpos = 0;
1823
+ if ($newpos > count($this->nodes[$newpid]["children"])) $newpos = count($this->nodes[$newpid]["children"]);
1824
+
1825
+ if ($src instanceof TagFilterNodes)
1826
+ {
1827
+ if ($src === $this) return false;
1828
+
1829
+ // Bulk node import. Doesn't remove source nodes.
1830
+ foreach ($src->nodes as $id => $node)
1831
+ {
1832
+ if ($node["type"] === "element" || $node["type"] === "content" || $node["type"] === "comment")
1833
+ {
1834
+ $node["parent"] += $this->nextid - 1;
1835
+
1836
+ if (isset($node["children"]) && is_array($node["children"]))
1837
+ {
1838
+ foreach ($node["children"] as $pos => $id2) $node["children"][$pos] += $this->nextid - 1;
1839
+ }
1840
+
1841
+ $this->nodes[$id + $this->nextid - 1] = $node;
1842
+ }
1843
+ }
1844
+
1845
+ // Merge root children.
1846
+ foreach ($src->nodes[0]["children"] as $pos => $id)
1847
+ {
1848
+ $this->nodes[$id + $this->nextid - 1]["parent"] = $newpid;
1849
+ array_splice($this->nodes[$newpid]["children"], $newpos + $pos, 0, array($id + $this->nextid - 1));
1850
+ }
1851
+
1852
+ $this->RealignChildren($newpid, $newpos);
1853
+
1854
+ $this->nextid += $src->nextid - 1;
1855
+ }
1856
+ else if (is_array($src))
1857
+ {
1858
+ // Attach the array to the position if it is valid.
1859
+ if (!isset($src["type"])) return false;
1860
+
1861
+ switch ($src["type"])
1862
+ {
1863
+ case "element":
1864
+ {
1865
+ if (!isset($src["tag"]) || !isset($src["attrs"]) || !is_array($src["attrs"]) || !isset($src["children"])) return false;
1866
+
1867
+ $src["tag"] = (string)$src["tag"];
1868
+ $src["parent"] = $newpid;
1869
+
1870
+ break;
1871
+ }
1872
+ case "content":
1873
+ case "comment":
1874
+ {
1875
+ if (!isset($src["text"]) || isset($src["children"])) return false;
1876
+
1877
+ $src["text"] = (string)$src["text"];
1878
+
1879
+ break;
1880
+ }
1881
+ default: return false;
1882
+ }
1883
+
1884
+ array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($this->nextid));
1885
+ $this->RealignChildren($newpid, $newpos);
1886
+ $this->nextid++;
1887
+ }
1888
+ else if (is_string($src))
1889
+ {
1890
+ return $this->Move(TagFilter::Explode($src, TagFilter::GetHTMLOptions()), $newpid, $newpos);
1891
+ }
1892
+ else
1893
+ {
1894
+ // Reparents an internal id.
1895
+ $id = (int)$src;
1896
+
1897
+ if (!$id || !isset($this->nodes[$id])) return false;
1898
+
1899
+ // Don't allow reparenting to a child node.
1900
+ $id2 = $newpid;
1901
+ while ($id2)
1902
+ {
1903
+ if ($id === $id2) return false;
1904
+
1905
+ $id2 = $this->nodes[$id2]["parent"];
1906
+ }
1907
+
1908
+ // Detach.
1909
+ array_splice($this->nodes[$this->nodes[$id]["parent"]]["children"], $this->nodes[$id]["parentpos"], 1);
1910
+ $this->RealignChildren($this->nodes[$id]["parent"], $this->nodes[$id]["parentpos"]);
1911
+
1912
+ // Attach.
1913
+ array_splice($this->nodes[$newpid]["children"], $newpos, 0, array($id));
1914
+ $this->RealignChildren($newpid, $newpos);
1915
+ }
1916
+
1917
+ return true;
1918
+ }
1919
+
1920
+ // When $keepchildren is true, the node's children are moved into the parent of the node being removed.
1921
+ public function Remove($id, $keepchildren = false)
1922
+ {
1923
+ $id = (int)$id;
1924
+ if (!isset($this->nodes[$id])) return;
1925
+
1926
+ if (!$id)
1927
+ {
1928
+ if (!$keepchildren)
1929
+ {
1930
+ // Reset all nodes.
1931
+ $this->nodes = array(
1932
+ array(
1933
+ "type" => "root",
1934
+ "parent" => false,
1935
+ "parentpos" => false,
1936
+ "children" => array()
1937
+ )
1938
+ );
1939
+
1940
+ $this->nextid = 1;
1941
+ }
1942
+ }
1943
+ else
1944
+ {
1945
+ // Detach the node from the parent.
1946
+ $pid = $this->nodes[$id]["parent"];
1947
+ $pos = $this->nodes[$id]["parentpos"];
1948
+
1949
+ if ($keepchildren)
1950
+ {
1951
+ // Reparent the children and attach them to the new parent.
1952
+ if (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]))
1953
+ {
1954
+ foreach ($this->nodes[$id]["children"] as $cid) $this->nodes[$cid]["parent"] = $pid;
1955
+ array_splice($this->nodes[$pid]["children"], $pos, 1, $this->nodes[$id]["children"]);
1956
+ }
1957
+ else
1958
+ {
1959
+ array_splice($this->nodes[$pid]["children"], $pos, 1);
1960
+ }
1961
+
1962
+ $this->RealignChildren($pid, $pos);
1963
+
1964
+ unset($this->nodes[$id]);
1965
+ }
1966
+ else
1967
+ {
1968
+ array_splice($this->nodes[$pid]["children"], $pos, 1);
1969
+
1970
+ $this->RealignChildren($pid, $pos);
1971
+
1972
+ // Remove node and all children.
1973
+ $rootid = $id;
1974
+ $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1975
+ do
1976
+ {
1977
+ if (!$pos)
1978
+ {
1979
+ $pid = $this->nodes[$id]["parent"];
1980
+ $pos = $this->nodes[$id]["parentpos"];
1981
+
1982
+ unset($this->nodes[$id]);
1983
+ if ($rootid === $id) break;
1984
+
1985
+ $id = $pid;
1986
+ }
1987
+ else
1988
+ {
1989
+ $id = $this->nodes[$id]["children"][$pos - 1];
1990
+ $pos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
1991
+ }
1992
+ } while (1);
1993
+ }
1994
+ }
1995
+ }
1996
+
1997
+ public function Replace($id, $src, $inneronly = false)
1998
+ {
1999
+ $id = (int)$id;
2000
+ if (!isset($this->nodes[$id])) return false;
2001
+
2002
+ if ($inneronly)
2003
+ {
2004
+ // Remove children.
2005
+ if (!isset($this->nodes[$id]["children"]) || !is_array($this->nodes[$id]["children"])) return false;
2006
+
2007
+ while (count($this->nodes[$id]["children"])) $this->Remove($this->nodes[$id]["children"][0]);
2008
+
2009
+ $newpid = $id;
2010
+ $newpos = 0;
2011
+ }
2012
+ else
2013
+ {
2014
+ $newpid = $this->nodes[$id]["parent"];
2015
+ $newpos = $this->nodes[$id]["parentpos"];
2016
+
2017
+ $this->Remove($id);
2018
+ }
2019
+
2020
+ return $this->Move($src, $newpid, $newpos);
2021
+ }
2022
+
2023
+ private static function SplitAt_CopyNode($nodes, &$pid, $node)
2024
+ {
2025
+ // Copy the node.
2026
+ $node["parent"] = $pid;
2027
+ $node["parentpos"] = count($nodes->nodes[$pid]["children"]);
2028
+ if (isset($node["children"])) $node["children"] = (is_array($node["children"]) ? array() : false);
2029
+
2030
+ // Attach the node.
2031
+ $nodes->nodes[$nodes->nextid] = $node;
2032
+ $nodes->nodes[$pid]["children"][] = $nodes->nextid;
2033
+
2034
+ $pid = $nodes->nextid;
2035
+
2036
+ $nodes->nextid++;
2037
+ }
2038
+
2039
+ public function SplitAt($ids, $keepidparents = false)
2040
+ {
2041
+ $ids2 = array();
2042
+ if (!is_array($ids)) $ids = array($ids);
2043
+ foreach ($ids as $id) $ids2[(int)$id] = true;
2044
+ unset($ids2[0]);
2045
+
2046
+ $result = array();
2047
+
2048
+ // Walk the entire set of nodes, cloning until an ID match occurs (if any).
2049
+ $newnodes = new TagFilterNodes();
2050
+ $newpid = 0;
2051
+ $id = 0;
2052
+ $pos = 0;
2053
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2054
+ do
2055
+ {
2056
+ if (!$pos)
2057
+ {
2058
+ if (isset($ids2[$id]) && count($newnodes->nodes[0]["children"]))
2059
+ {
2060
+ // Found an ID match.
2061
+ $result[] = $newnodes;
2062
+ $newnodes = new TagFilterNodes();
2063
+ $newpid = 0;
2064
+
2065
+ if ($keepidparents instanceof TagFilterNodes)
2066
+ {
2067
+ $newnodes = clone $keepidparents;
2068
+ $newpid = $newnodes->nextid - 1;
2069
+ }
2070
+ else if ($keepidparents)
2071
+ {
2072
+ $stack = array();
2073
+ $id2 = $this->nodes[$id]["parent"];
2074
+ while ($id2)
2075
+ {
2076
+ $stack[] = $id2;
2077
+
2078
+ $id2 = $this->nodes[$id2]["parent"];
2079
+ }
2080
+ $stack = array_reverse($stack);
2081
+ foreach ($stack as $id2)
2082
+ {
2083
+ self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ if ($id) self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id]);
2089
+ }
2090
+
2091
+ if ($pos >= $maxpos)
2092
+ {
2093
+ if (!$id) break;
2094
+
2095
+ if (isset($ids2[$id]))
2096
+ {
2097
+ // Start a new set of nodes.
2098
+ $result[] = $newnodes;
2099
+ $newnodes = new TagFilterNodes();
2100
+ $newpid = 0;
2101
+
2102
+ $stack = array();
2103
+ $id2 = $this->nodes[$id]["parent"];
2104
+ while ($id2)
2105
+ {
2106
+ $stack[] = $id2;
2107
+
2108
+ $id2 = $this->nodes[$id2]["parent"];
2109
+ }
2110
+ $stack = array_reverse($stack);
2111
+ foreach ($stack as $id2)
2112
+ {
2113
+ self::SplitAt_CopyNode($newnodes, $newpid, $this->nodes[$id2]);
2114
+ }
2115
+ }
2116
+ else
2117
+ {
2118
+ $newpid = $newnodes->nodes[$newpid]["parent"];
2119
+ }
2120
+
2121
+ $pos = $this->nodes[$id]["parentpos"] + 1;
2122
+ $id = $this->nodes[$id]["parent"];
2123
+ $maxpos = count($this->nodes[$id]["children"]);
2124
+ }
2125
+ else
2126
+ {
2127
+ $id = $this->nodes[$id]["children"][$pos];
2128
+ $pos = 0;
2129
+ $maxpos = (isset($this->nodes[$id]["children"]) && is_array($this->nodes[$id]["children"]) ? count($this->nodes[$id]["children"]) : 0);
2130
+ }
2131
+ } while (1);
2132
+
2133
+ if (!count($result) || count($newnodes->nodes[0]["children"])) $result[] = $newnodes;
2134
+
2135
+ return $result;
2136
+ }
2137
+
2138
+ public function GetOuterHTML($id, $mode = "html")
2139
+ {
2140
+ return $this->Implode($id, array("output_mode" => $mode));
2141
+ }
2142
+
2143
+ public function SetOuterHTML($id, $src)
2144
+ {
2145
+ return $this->Replace($id, $src);
2146
+ }
2147
+
2148
+ public function GetInnerHTML($id, $mode = "html")
2149
+ {
2150
+ return $this->Implode($id, array("include_id" => false, "output_mode" => $mode));
2151
+ }
2152
+
2153
+ public function SetInnerHTML($id, $src)
2154
+ {
2155
+ return $this->Replace($id, $src, true);
2156
+ }
2157
+
2158
+ public function GetPlainText($id)
2159
+ {
2160
+ return $this->Implode($id, array("types" => "content", "post_elements" => array("p" => "\n\n", "br" => "\n")));
2161
+ }
2162
+
2163
+ public function SetPlainText($id, $src)
2164
+ {
2165
+ // Convert $src to a string.
2166
+ if ($src instanceof TagFilterNodes)
2167
+ {
2168
+ $src = $src->GetPlainText(0);
2169
+ }
2170
+ else if (is_array($src))
2171
+ {
2172
+ $temp = new TagFilterNodes();
2173
+ $temp->Move($src, 0, 0);
2174
+
2175
+ $src = $temp->GetPlainText(0);
2176
+ }
2177
+ else if (!is_string($src))
2178
+ {
2179
+ $src = $this->GetPlainText((int)$src);
2180
+ }
2181
+
2182
+ $src = array(
2183
+ "type" => "content",
2184
+ "text" => (string)$src,
2185
+ "parent" => false,
2186
+ "parentpos" => false
2187
+ );
2188
+
2189
+ return $this->Replace($id, $src, true);
2190
+ }
2191
+
2192
+ private function RealignChildren($id, $pos)
2193
+ {
2194
+ $y = count($this->nodes[$id]["children"]);
2195
+ for ($x = $pos; $x < $y; $x++) $this->nodes[$this->nodes[$id]["children"][$x]]["parentpos"] = $x;
2196
+ }
2197
+ }
2198
+
2199
+ class TagFilter
2200
+ {
2201
+ // Internal callback function for extracting interior content of HTML 'script' and 'style' tags.
2202
+ public static function HTMLSpecialTagContentCallback($stack, $final, &$tag, &$content, &$cx, $cy, &$content2, $options)
2203
+ {
2204
+ if (preg_match('/<\s*\/\s*' . $stack[0]["tag_name"] . '(\s*|\s+.+?)>/is', $content, $matches, PREG_OFFSET_CAPTURE, $cx))
2205
+ {
2206
+ $pos = $matches[0][1];
2207
+
2208
+ $content2 = substr($content, $cx, $pos - $cx);
2209
+ $cx = $pos;
2210
+ $tag = true;
2211
+
2212
+ return true;
2213
+ }
2214
+ else
2215
+ {
2216
+ if ($final)
2217
+ {
2218
+ $content2 = substr($content, $cx);
2219
+ $cx = $cy;
2220
+ }
2221
+
2222
+ return false;
2223
+ }
2224
+ }
2225
+
2226
+ public static function GetHTMLOptions()
2227
+ {
2228
+ $result = array(
2229
+ "tag_name_map" => array(
2230
+ "!doctype" => "DOCTYPE"
2231
+ ),
2232
+ "untouched_tag_attr_keys" => array(
2233
+ "doctype" => true,
2234
+ ),
2235
+ "void_tags" => array(
2236
+ "DOCTYPE" => true,
2237
+ "area" => true,
2238
+ "base" => true,
2239
+ "bgsound" => true,
2240
+ "br" => true,
2241
+ "col" => true,
2242
+ "embed" => true,
2243
+ "hr" => true,
2244
+ "img" => true,
2245
+ "input" => true,
2246
+ "keygen" => true,
2247
+ "link" => true,
2248
+ "menuitem" => true,
2249
+ "meta" => true,
2250
+ "param" => true,
2251
+ "source" => true,
2252
+ "track" => true,
2253
+ "wbr" => true
2254
+ ),
2255
+ // Alternate tag internal content rules for specialized tags.
2256
+ "alt_tag_content_rules" => array(
2257
+ "script" => __CLASS__ . "::HTMLSpecialTagContentCallback",
2258
+ "style" => __CLASS__ . "::HTMLSpecialTagContentCallback"
2259
+ ),
2260
+ // Stored as a map for open tag elements.
2261
+ // For example, '"address" => array("p" => true)' means: When an open 'address' tag is encountered,
2262
+ // look for an open 'p' tag anywhere (no '_limit') in the tag stack. Apply a closing '</p>' tag for all matches.
2263
+ //
2264
+ // If '_limit' is defined as a string or an array, then stack walking stops as soon as one of the specified tags is encountered.
2265
+ "pre_close_tags" => array(
2266
+ "body" => array("body" => true, "head" => true),
2267
+
2268
+ "address" => array("p" => true),
2269
+ "article" => array("p" => true),
2270
+ "aside" => array("p" => true),
2271
+ "blockquote" => array("p" => true),
2272
+ "div" => array("p" => true),
2273
+ "dl" => array("p" => true),
2274
+ "fieldset" => array("p" => true),
2275
+ "footer" => array("p" => true),
2276
+ "form" => array("p" => true),
2277
+ "h1" => array("p" => true),
2278
+ "h2" => array("p" => true),
2279
+ "h3" => array("p" => true),
2280
+ "h4" => array("p" => true),
2281
+ "h5" => array("p" => true),
2282
+ "h6" => array("p" => true),
2283
+ "header" => array("p" => true),
2284
+ "hr" => array("p" => true),
2285
+ "menu" => array("p" => true),
2286
+ "nav" => array("p" => true),
2287
+ "ol" => array("p" => true),
2288
+ "pre" => array("p" => true),
2289
+ "section" => array("p" => true),
2290
+ "table" => array("p" => true),
2291
+ "ul" => array("p" => true),
2292
+ "p" => array("p" => true),
2293
+
2294
+ "tbody" => array("_limit" => "table", "thead" => true, "tr" => true, "th" => true, "td" => true),
2295
+ "tr" => array("_limit" => "table", "tr" => true, "th" => true, "td" => true),
2296
+ "th" => array("_limit" => "table", "th" => true, "td" => true),
2297
+ "td" => array("_limit" => "table", "th" => true, "td" => true),
2298
+ "tfoot" => array("_limit" => "table", "thead" => true, "tbody" => true, "tr" => true, "th" => true, "td" => true),
2299
+
2300
+ "optgroup" => array("optgroup" => true, "option" => true),
2301
+ "option" => array("option" => true),
2302
+
2303
+ "dd" => array("_limit" => "dl", "dd" => true, "dt" => true),
2304
+ "dt" => array("_limit" => "dl", "dd" => true, "dt" => true),
2305
+
2306
+ "colgroup" => array("colgroup" => true),
2307
+
2308
+ "li" => array("_limit" => array("ul" => true, "ol" => true, "menu" => true, "dir" => true), "li" => true),
2309
+ ),
2310
+ "process_attrs" => array(
2311
+ "class" => "classes",
2312
+ "href" => "uri",
2313
+ "src" => "uri",
2314
+ "dynsrc" => "uri",
2315
+ "lowsrc" => "uri",
2316
+ "background" => "uri",
2317
+ ),
2318
+ "keep_attr_newlines" => false,
2319
+ "keep_comments" => false,
2320
+ "allow_namespaces" => true,
2321
+ "charset" => "UTF-8",
2322
+ "charset_tags" => true,
2323
+ "charset_attrs" => true,
2324
+ "output_mode" => "html",
2325
+ "lowercase_tags" => true,
2326
+ "lowercase_attrs" => true,
2327
+ );
2328
+
2329
+ return $result;
2330
+ }
2331
+
2332
+ public static function Run($content, $options = array())
2333
+ {
2334
+ $tfs = new TagFilterStream($options);
2335
+ $tfs->Finalize();
2336
+ $result = $tfs->Process($content);
2337
+
2338
+ // Clean up output.
2339
+ $result = trim($result);
2340
+ $result = self::CleanupResults($result);
2341
+
2342
+ if (function_exists("gc_mem_caches")) gc_mem_caches();
2343
+
2344
+ return $result;
2345
+ }
2346
+
2347
+ public static function CleanupResults($content)
2348
+ {
2349
+ $result = str_replace("\r\n", "\n", $content);
2350
+ $result = str_replace("\r", "\n", $result);
2351
+ while (strpos($result, "\n\n\n") !== false) $result = str_replace("\n\n\n", "\n\n", $result);
2352
+
2353
+ return $result;
2354
+ }
2355
+
2356
+ public static function ExplodeTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2357
+ {
2358
+ if ($open)
2359
+ {
2360
+ $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2361
+
2362
+ $tagname2 = (isset($options["tag_name_map"][strtolower($tagname)]) ? $options["tag_name_map"][strtolower($tagname)] : $tagname);
2363
+
2364
+ $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2365
+ "type" => "element",
2366
+ "tag" => $tagname,
2367
+ "attrs" => $attrs,
2368
+ "parent" => $pid,
2369
+ "parentpos" => count($options["nodes"]->nodes[$pid]["children"]),
2370
+ "children" => (isset($options["void_tags"][$tagname2]) ? false : array())
2371
+ );
2372
+
2373
+ $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2374
+
2375
+ // Append non-void tags to the ID stack.
2376
+ if (!isset($options["void_tags"][$tagname2])) array_unshift($options["data"]->stackmap, $options["nodes"]->nextid);
2377
+
2378
+ $options["nodes"]->nextid++;
2379
+ }
2380
+ else
2381
+ {
2382
+ array_shift($options["data"]->stackmap);
2383
+ }
2384
+
2385
+ return array("keep_tag" => false, "keep_interior" => false);
2386
+ }
2387
+
2388
+ public static function ExplodeContentCallback($stack, $result, &$content, $options)
2389
+ {
2390
+ if ($content === "") return;
2391
+
2392
+ $type = (substr($content, 0, 5) === "<!-- " ? "comment" : "content");
2393
+ $pid = (count($options["data"]->stackmap) ? $options["data"]->stackmap[0] : 0);
2394
+ $parentpos = count($options["nodes"]->nodes[$pid]["children"]);
2395
+
2396
+ if ($parentpos && $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["type"] == $type) $options["nodes"]->nodes[$options["nodes"]->nodes[$pid]["children"][$parentpos - 1]]["text"] .= $content;
2397
+ else
2398
+ {
2399
+ $options["nodes"]->nodes[$options["nodes"]->nextid] = array(
2400
+ "type" => $type,
2401
+ "text" => $content,
2402
+ "parent" => $pid,
2403
+ "parentpos" => $parentpos
2404
+ );
2405
+
2406
+ $options["nodes"]->nodes[$pid]["children"][] = $options["nodes"]->nextid;
2407
+
2408
+ $options["nodes"]->nextid++;
2409
+ }
2410
+
2411
+ $content = "";
2412
+ }
2413
+
2414
+ public static function Explode($content, $options = array())
2415
+ {
2416
+ $options["tag_callback"] = __CLASS__ . "::ExplodeTagCallback";
2417
+ $options["content_callback"] = __CLASS__ . "::ExplodeContentCallback";
2418
+ $options["nodes"] = new TagFilterNodes();
2419
+ $options["data"] = new stdClass();
2420
+ $options["data"]->stackmap = array();
2421
+
2422
+ self::Run($content, $options);
2423
+
2424
+ return $options["nodes"];
2425
+ }
2426
+
2427
+ public static function HTMLPurifyTagCallback($stack, &$content, $open, $tagname, &$attrs, $options)
2428
+ {
2429
+ if ($open)
2430
+ {
2431
+ if ($tagname === "script") return array("keep_tag" => false, "keep_interior" => false);
2432
+ if ($tagname === "style") return array("keep_tag" => false, "keep_interior" => false);
2433
+
2434
+ if (isset($attrs["src"]) && substr($attrs["src"], 0, 11) === "javascript:") return array("keep_tag" => false, "keep_interior" => false);
2435
+ if (isset($attrs["href"]) && substr($attrs["href"], 0, 11) === "javascript:") return array("keep_tag" => false);
2436
+
2437
+ if (!isset($options["htmlpurify"]["allowed_tags"][$tagname])) return array("keep_tag" => false);
2438
+
2439
+ if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname])) $attrs = array();
2440
+ else
2441
+ {
2442
+ // For classes, "class" needs to be specified as an allowed attribute.
2443
+ foreach ($attrs as $attr => $val)
2444
+ {
2445
+ if (!isset($options["htmlpurify"]["allowed_attrs"][$tagname][$attr])) unset($attrs[$attr]);
2446
+ }
2447
+ }
2448
+
2449
+ if (isset($options["htmlpurify"]["required_attrs"][$tagname]))
2450
+ {
2451
+ foreach ($options["htmlpurify"]["required_attrs"][$tagname] as $attr => $val)
2452
+ {
2453
+ if (!isset($attrs[$attr])) return array("keep_tag" => false);
2454
+ }
2455
+ }
2456
+
2457
+ if (isset($attrs["class"]))
2458
+ {
2459
+ if (!isset($options["htmlpurify"]["allowed_classes"][$tagname])) unset($attrs["class"]);
2460
+ else
2461
+ {
2462
+ foreach ($attrs["class"] as $class)
2463
+ {
2464
+ if (!isset($options["htmlpurify"]["allowed_classes"][$tagname][$class])) unset($attrs["class"][$class]);
2465
+ }
2466
+
2467
+ if (!count($attrs["class"])) unset($attrs["class"]);
2468
+ }
2469
+ }
2470
+ }
2471
+ else
2472
+ {
2473
+ if (isset($options["htmlpurify"]["remove_empty"][substr($tagname, 1)]) && trim(str_replace(array("&nbsp;", "\xC2\xA0"), " ", $content)) === "")
2474
+ {
2475
+ if ($content !== "") $content = " ";
2476
+
2477
+ return array("keep_tag" => false);
2478
+ }
2479
+ }
2480
+
2481
+ return array();
2482
+ }
2483
+
2484
+ private static function Internal_NormalizeHTMLPurifyOptions($value)
2485
+ {
2486
+ if (is_string($value))
2487
+ {
2488
+ $opts = explode(",", $value);
2489
+ $value = array();
2490
+ foreach ($opts as $opt)
2491
+ {
2492
+ $opt = (string)trim($opt);
2493
+ if ($opt !== "") $value[$opt] = true;
2494
+ }
2495
+ }
2496
+
2497
+ return $value;
2498
+ }
2499
+
2500
+ public static function NormalizeHTMLPurifyOptions($purifyopts)
2501
+ {
2502
+ if (!isset($purifyopts["allowed_tags"])) $purifyopts["allowed_tags"] = array();
2503
+ if (!isset($purifyopts["allowed_attrs"])) $purifyopts["allowed_attrs"] = array();
2504
+ if (!isset($purifyopts["required_attrs"])) $purifyopts["required_attrs"] = array();
2505
+ if (!isset($purifyopts["allowed_classes"])) $purifyopts["allowed_classes"] = array();
2506
+ if (!isset($purifyopts["remove_empty"])) $purifyopts["remove_empty"] = array();
2507
+
2508
+ $purifyopts["allowed_tags"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["allowed_tags"]);
2509
+ foreach ($purifyopts["allowed_attrs"] as $key => $val) $purifyopts["allowed_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2510
+ foreach ($purifyopts["required_attrs"] as $key => $val) $purifyopts["required_attrs"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2511
+ foreach ($purifyopts["allowed_classes"] as $key => $val) $purifyopts["allowed_classes"][$key] = self::Internal_NormalizeHTMLPurifyOptions($val);
2512
+ $purifyopts["remove_empty"] = self::Internal_NormalizeHTMLPurifyOptions($purifyopts["remove_empty"]);
2513
+
2514
+ return $purifyopts;
2515
+ }
2516
+
2517
+ public static function HTMLPurify($content, $htmloptions, $purifyopts)
2518
+ {
2519
+ $htmloptions["tag_callback"] = __CLASS__ . "::HTMLPurifyTagCallback";
2520
+ $htmloptions["htmlpurify"] = self::NormalizeHTMLPurifyOptions($purifyopts);
2521
+
2522
+ return self::Run($content, $htmloptions);
2523
+ }
2524
+
2525
+ public static function ReorderSelectorTokens($tokens, $splitrules, $order = array("pseudo-element" => array(), "pseudo-class" => array(), "attr" => array(), "class" => array(), "element" => array(), "id" => array()), $endnots = true)
2526
+ {
2527
+ // Collapse split rules.
2528
+ if (count($tokens) && !isset($tokens[0]["type"]) && isset($tokens[0][0]["type"]))
2529
+ {
2530
+ $tokens2 = array();
2531
+ foreach ($tokens as $rules)
2532
+ {
2533
+ if (count($tokens2)) $tokens2[] = array("type" => "combine", "combine" => "or");
2534
+ $rules = array_reverse($rules);
2535
+ foreach ($rules as $rule) $tokens2[] = $rule;
2536
+ }
2537
+
2538
+ $tokens = $tokens2;
2539
+ }
2540
+
2541
+ $result = array();
2542
+ $rules = array();
2543
+ $selector = $order;
2544
+ foreach ($tokens as $token)
2545
+ {
2546
+ if ($token["type"] != "combine") array_unshift($selector[$token["type"]], $token);
2547
+ else
2548
+ {
2549
+ foreach ($selector as $vals)
2550
+ {
2551
+ foreach ($vals as $token2)
2552
+ {
2553
+ if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2554
+ }
2555
+
2556
+ foreach ($vals as $token2)
2557
+ {
2558
+ if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2559
+ }
2560
+ }
2561
+
2562
+ if (!$splitrules || $token["combine"] != "or") array_unshift($result, $token);
2563
+ else if ($token["combine"] == "or")
2564
+ {
2565
+ if (count($result)) $rules[] = $result;
2566
+
2567
+ $result = array();
2568
+ }
2569
+
2570
+ $selector = $order;
2571
+ }
2572
+ }
2573
+
2574
+ foreach ($selector as $vals)
2575
+ {
2576
+ foreach ($vals as $token2)
2577
+ {
2578
+ if (($endnots && $token2["not"]) || (!$endnots && !$token2["not"])) array_unshift($result, $token2);
2579
+ }
2580
+
2581
+ foreach ($vals as $token2)
2582
+ {
2583
+ if (($endnots && !$token2["not"]) || (!$endnots && $token2["not"])) array_unshift($result, $token2);
2584
+ }
2585
+ }
2586
+
2587
+ if ($splitrules)
2588
+ {
2589
+ if (count($result)) $rules[] = $result;
2590
+
2591
+ $result = $rules;
2592
+ }
2593
+ else
2594
+ {
2595
+ // Ignore a stray group combiner at the end.
2596
+ if (count($result) && $result[0]["type"] == "combine" && $result[0]["combine"] == "or") array_shift($result);
2597
+ }
2598
+
2599
+ return $result;
2600
+ }
2601
+
2602
+ public static function ParseSelector($query, $splitrules = false)
2603
+ {
2604
+ // Tokenize query into individual action steps.
2605
+ $query = trim($query);
2606
+ $tokens = array();
2607
+ $lastor = 0;
2608
+ $a = ord("A");
2609
+ $a2 = ord("a");
2610
+ $f = ord("F");
2611
+ $f2 = ord("f");
2612
+ $z = ord("Z");
2613
+ $z2 = ord("z");
2614
+ $backslash = ord("\\");
2615
+ $hyphen = ord("-");
2616
+ $underscore = ord("_");
2617
+ $pipe = ord("|");
2618
+ $asterisk = ord("*");
2619
+ $colon = ord(":");
2620
+ $period = ord(".");
2621
+ $zero = ord("0");
2622
+ $nine = ord("9");
2623
+ $cr = ord("\r");
2624
+ $nl = ord("\n");
2625
+ $ff = ord("\f");
2626
+ $cx = 0;
2627
+ $cy = strlen($query);
2628
+ $state = "next_selector";
2629
+ do
2630
+ {
2631
+ $currcx = $cx;
2632
+ $currstate = $state;
2633
+
2634
+ switch ($state)
2635
+ {
2636
+ case "next_selector":
2637
+ {
2638
+ // This state is necessary to handle the :not(selector) function.
2639
+ $token = array("not" => false);
2640
+ }
2641
+ case "selector":
2642
+ {
2643
+ if ($cx >= $cy) break;
2644
+
2645
+ switch ($query{$cx})
2646
+ {
2647
+ case "#":
2648
+ {
2649
+ $token["type"] = "id";
2650
+ $state = "ident_name";
2651
+ $allownamespace = false;
2652
+ $identasterisk = false;
2653
+ $allowperiod = false;
2654
+ $namespace = false;
2655
+ $range = true;
2656
+ $ident = "";
2657
+ $nextstate = "selector_ident_result";
2658
+ $cx++;
2659
+
2660
+ break;
2661
+ }
2662
+ case ".":
2663
+ {
2664
+ $token["type"] = "class";
2665
+ $state = "ident";
2666
+ $allownamespace = false;
2667
+ $identasterisk = false;
2668
+ $allowperiod = false;
2669
+ $nextstate = "selector_ident_result";
2670
+ $cx++;
2671
+
2672
+ break;
2673
+ }
2674
+ case "[":
2675
+ {
2676
+ $token["type"] = "attr";
2677
+ $state = "ident";
2678
+ $state2 = "attr";
2679
+ $allownamespace = true;
2680
+ $identasterisk = false;
2681
+ $allowperiod = false;
2682
+ $nextstate = "selector_ident_result";
2683
+ $cx++;
2684
+
2685
+ // Find a non-whitespace character.
2686
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2687
+
2688
+ break;
2689
+ }
2690
+ case ":":
2691
+ {
2692
+ $cx++;
2693
+ if ($cx >= $cy || $query{$cx} != ":") $token["type"] = "pseudo-class";
2694
+ else
2695
+ {
2696
+ $token["type"] = "pseudo-element";
2697
+ $cx++;
2698
+ }
2699
+
2700
+ $state = "ident";
2701
+ $allownamespace = true;
2702
+ $identasterisk = false;
2703
+ $allowperiod = false;
2704
+ $nextstate = "selector_ident_result";
2705
+
2706
+ break;
2707
+ }
2708
+ case ",":
2709
+ case "+":
2710
+ case ">":
2711
+ case "~":
2712
+ case " ":
2713
+ case "\r":
2714
+ case "\n":
2715
+ case "\t":
2716
+ case "\f":
2717
+ {
2718
+ $state = "combine";
2719
+
2720
+ break;
2721
+ }
2722
+ default:
2723
+ {
2724
+ $token["type"] = "element";
2725
+ $state = "ident";
2726
+ $allownamespace = true;
2727
+ $identasterisk = true;
2728
+ $allowperiod = false;
2729
+ $nextstate = "selector_ident_result";
2730
+
2731
+ break;
2732
+ }
2733
+ }
2734
+
2735
+ break;
2736
+ }
2737
+ case "selector_ident_result":
2738
+ {
2739
+ switch ($token["type"])
2740
+ {
2741
+ case "id":
2742
+ {
2743
+ $token["id"] = $ident;
2744
+ $tokens[] = $token;
2745
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2746
+
2747
+ break;
2748
+ }
2749
+ case "class":
2750
+ {
2751
+ $token["class"] = $ident;
2752
+ $tokens[] = $token;
2753
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2754
+
2755
+ break;
2756
+ }
2757
+ case "element":
2758
+ {
2759
+ $token["namespace"] = $namespace;
2760
+ $token["tag"] = $ident;
2761
+ $tokens[] = $token;
2762
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2763
+
2764
+ break;
2765
+ }
2766
+ case "attr":
2767
+ {
2768
+ if ($state2 == "attr")
2769
+ {
2770
+ $token["namespace"] = $namespace;
2771
+ $token[$state2] = $ident;
2772
+
2773
+ // Find a non-whitespace character.
2774
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2775
+
2776
+ if ($cx >= $cy || $query{$cx} == "]")
2777
+ {
2778
+ $token["cmp"] = false;
2779
+ $tokens[] = $token;
2780
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2781
+ $cx++;
2782
+ }
2783
+ else
2784
+ {
2785
+ if ($query{$cx} == "=")
2786
+ {
2787
+ $token["cmp"] = "=";
2788
+ $cx++;
2789
+ }
2790
+ else if ($cx + 1 < $cy && ($query{$cx} == "^" || $query{$cx} == "$" || $query{$cx} == "*" || $query{$cx} == "~" || $query{$cx} == "|") && $query{$cx + 1} == "=")
2791
+ {
2792
+ $token["cmp"] = substr($query, $cx, 2);
2793
+ $cx += 2;
2794
+ }
2795
+ else
2796
+ {
2797
+ return array("success" => false, "error" => "Unknown or invalid attribute comparison operator '" . $query{$cx} . "' detected at position " . $cx . ".", "errorcode" => "invalid_attr_compare", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2798
+ }
2799
+
2800
+ // Find a non-whitespace character.
2801
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2802
+
2803
+ if ($cx < $cy && ($query{$cx} == "\"" || $query{$cx} == "'"))
2804
+ {
2805
+ $state = "string";
2806
+ $endchr = ord($query{$cx});
2807
+ $cx++;
2808
+ }
2809
+ else
2810
+ {
2811
+ $state = "ident";
2812
+ $allownamespace = false;
2813
+ $identasterisk = false;
2814
+ $allowperiod = false;
2815
+ }
2816
+
2817
+ $state2 = "val";
2818
+ $nextstate = "selector_ident_result";
2819
+ }
2820
+ }
2821
+ else if ($state2 == "val")
2822
+ {
2823
+ $token[$state2] = $ident;
2824
+
2825
+ // Find a non-whitespace character.
2826
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2827
+
2828
+ $tokens[] = $token;
2829
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2830
+
2831
+ if ($cx < $cy && $query{$cx} == "]") $cx++;
2832
+ }
2833
+
2834
+ break;
2835
+ }
2836
+ case "pseudo-class":
2837
+ case "pseudo-element":
2838
+ {
2839
+ $ident = strtolower($ident);
2840
+
2841
+ // Deal with CSS1 and CSS2 compatibility.
2842
+ if ($ident === "first-line" || $ident === "first-letter" || $ident === "before" || $ident === "after") $token["type"] = "pseudo-element";
2843
+
2844
+ if ($token["type"] == "pseudo-class" && $ident == "not")
2845
+ {
2846
+ if ($token["not"]) return array("success" => false, "error" => "Invalid :not() embedded inside another :not() detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2847
+ if ($cx >= $cy || $query{$cx} != "(") return array("success" => false, "error" => "Missing '(' detected at position " . $cx . ".", "errorcode" => "invalid_not", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2848
+
2849
+ unset($token["type"]);
2850
+ $token["not"] = true;
2851
+
2852
+ $state = "selector";
2853
+ $cx++;
2854
+
2855
+ // Find a non-whitespace character.
2856
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2857
+ }
2858
+ else
2859
+ {
2860
+ $token["pseudo"] = $ident;
2861
+
2862
+ if ($cx < $cy && $query{$cx} == "(")
2863
+ {
2864
+ $token["expression"] = "";
2865
+ $ident = "";
2866
+ $state = "pseudo_expression";
2867
+ $cx++;
2868
+ }
2869
+ else
2870
+ {
2871
+ $token["expression"] = false;
2872
+ $tokens[] = $token;
2873
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2874
+ }
2875
+ }
2876
+
2877
+ break;
2878
+ }
2879
+ }
2880
+
2881
+ break;
2882
+ }
2883
+ case "negate_close":
2884
+ {
2885
+ // Find a non-whitespace character.
2886
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2887
+
2888
+ if ($cx < $cy && $query{$cx} != ")") return array("success" => false, "error" => "Invalid :not() close character '" . $query{$cx} . "' detected at position " . $cx . ".", "errorcode" => "invalid_negate_close", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
2889
+
2890
+ $cx++;
2891
+ $state = "next_selector";
2892
+
2893
+ break;
2894
+ }
2895
+ case "pseudo_expression":
2896
+ {
2897
+ $token["expression"] .= $ident;
2898
+
2899
+ // Find a non-whitespace character.
2900
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
2901
+
2902
+ if ($cx >= $cy) break;
2903
+
2904
+ if ($query{$cx} == ")")
2905
+ {
2906
+ if (substr($token["pseudo"], 0, 4) === "nth-")
2907
+ {
2908
+ // Convert the expression to an+b syntax.
2909
+ $exp = strtolower($token["expression"]);
2910
+
2911
+ if ($exp == "even") $exp = "2n";
2912
+ else if ($exp == "odd") $exp = "2n+1";
2913
+ else
2914
+ {
2915
+ do
2916
+ {
2917
+ $currexp = $exp;
2918
+
2919
+ $exp = str_replace(array("++", "+-", "-+", "--"), array("+", "-", "-", "+"), $exp);
2920
+
2921
+ } while ($currexp !== $exp);
2922
+ }
2923
+
2924
+ if (substr($exp, 0, 2) == "-n") $exp = "-1n" . substr($exp, 2);
2925
+ else if (substr($exp, 0, 2) == "+n") $exp = "1n" . substr($exp, 2);
2926
+ else if (substr($exp, 0, 1) == "n") $exp = "1n" . substr($exp, 1);
2927
+
2928
+ $pos = strpos($exp, "n");
2929
+ if ($pos === false)
2930
+ {
2931
+ $token["a"] = 0;
2932
+ $token["b"] = (double)$exp;
2933
+ }
2934
+ else
2935
+ {
2936
+ $token["a"] = (double)$exp;
2937
+ $token["b"] = (double)substr($exp, $pos + 1);
2938
+ }
2939
+
2940
+ $token["expression"] = $token["a"] . "n" . ($token["b"] < 0 ? $token["b"] : "+" . $token["b"]);
2941
+ }
2942
+
2943
+ $tokens[] = $token;
2944
+ $state = ($token["not"] ? "negate_close" : "next_selector");
2945
+ $cx++;
2946
+ }
2947
+ else if ($query{$cx} == "+" || $query{$cx} == "-")
2948
+ {
2949
+ $ident = $query{$cx};
2950
+ $cx++;
2951
+ }
2952
+ else if ($query{$cx} == "\"" || $query{$cx} == "'")
2953
+ {
2954
+ $state = "string";
2955
+ $endchr = ord($query{$cx});
2956
+ $cx++;
2957
+ }
2958
+ else
2959
+ {
2960
+ $val = ord($query{$cx});
2961
+
2962
+ $state = ($val >= $zero && $val <= $nine ? "ident_name" : "ident");
2963
+ $allownamespace = false;
2964
+ $identasterisk = false;
2965
+ $allowperiod = ($val >= $zero && $val <= $nine);
2966
+ $namespace = false;
2967
+ $range = true;
2968
+ $ident = "";
2969
+
2970
+ $nextstate = "pseudo_expression";
2971
+ }
2972
+
2973
+ break;
2974
+ }
2975
+ case "string":
2976
+ {
2977
+ $startcx = $cx;
2978
+ $ident = "";
2979
+
2980
+ for (; $cx < $cy; $cx++)
2981
+ {
2982
+ $val = ord($query{$cx});
2983
+
2984
+ if ($val == $endchr)
2985
+ {
2986
+ $cx++;
2987
+
2988
+ break;
2989
+ }
2990
+ else if ($val == $backslash)
2991
+ {
2992
+ // Escape sequence.
2993
+ if ($cx + 1 >= $cy) $ident .= "\\";
2994
+ else
2995
+ {
2996
+ $cx++;
2997
+ $val = ord($query{$cx});
2998
+
2999
+ if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3000
+ {
3001
+ // Unicode (e.g. \0020)
3002
+ for ($x = $cx + 1; $x < $cy; $x++)
3003
+ {
3004
+ $val = ord($query{$x});
3005
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3006
+ }
3007
+
3008
+ $num = hexdec(substr($query, $cx, $x - $cx));
3009
+ $cx = $x - 1;
3010
+
3011
+ $ident .= TagFilterStream::UTF8Chr($num);
3012
+
3013
+ // Skip one optional \r\n OR a single whitespace char.
3014
+ if ($cx + 2 < $cy && $query{$cx + 1} == "\r" && $query{$cx + 2} == "\n") $cx += 2;
3015
+ else if ($cx + 1 < $cy && ($query{$cx + 1} == " " || $query{$cx + 1} == "\r" || $query{$cx + 1} == "\n" || $query{$cx + 1} == "\t" || $query{$cx + 1} == "\f")) $cx++;
3016
+ }
3017
+ else
3018
+ {
3019
+ $ident .= $query{$cx};
3020
+ }
3021
+ }
3022
+ }
3023
+ else
3024
+ {
3025
+ $ident .= $query{$cx};
3026
+ }
3027
+ }
3028
+
3029
+ $state = $nextstate;
3030
+
3031
+ break;
3032
+ }
3033
+ case "ident":
3034
+ {
3035
+ $namespace = false;
3036
+ $range = false;
3037
+
3038
+ if ($cx >= $cy) break;
3039
+
3040
+ if ($query{$cx} != "-") $ident = "";
3041
+ else
3042
+ {
3043
+ $ident = "-";
3044
+ $cx++;
3045
+ }
3046
+
3047
+ $state = "ident_name";
3048
+
3049
+ break;
3050
+ }
3051
+ case "ident_name":
3052
+ {
3053
+ // Find the first invalid character.
3054
+ $startcx = $cx;
3055
+ for (; $cx < $cy; $cx++)
3056
+ {
3057
+ $val = ord($query{$cx});
3058
+
3059
+ if ($val != $period && ($val < $zero || $val > $nine)) $allowperiod = false;
3060
+
3061
+ if (($val >= $a && $val <= $z) || ($val >= $a2 && $val <= $z2) || $val == $underscore || $val > 127)
3062
+ {
3063
+ $ident .= $query{$cx};
3064
+ }
3065
+ else if ($allowperiod && $val == $period)
3066
+ {
3067
+ $allowperiod = false;
3068
+
3069
+ $ident .= ".";
3070
+ }
3071
+ else if ($val == $hyphen || ($val >= $zero && $val <= $nine))
3072
+ {
3073
+ // Only allowed AFTER the first character.
3074
+ if (!$range) return array("success" => false, "error" => "Invalid identifier character '" . $query{$cx} . "' detected at position " . $cx . ".", "errorcode" => "invalid_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3075
+
3076
+ $allowperiod = false;
3077
+
3078
+ $ident .= $query{$cx};
3079
+ }
3080
+ else if ($val == $backslash)
3081
+ {
3082
+ // Escape sequence.
3083
+ if ($cx + 1 >= $cy) $ident .= "\\";
3084
+ else
3085
+ {
3086
+ $cx++;
3087
+ $val = ord($query{$cx});
3088
+
3089
+ if (($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))
3090
+ {
3091
+ // Unicode (e.g. \0020)
3092
+ for ($x = $cx + 1; $x < $cy; $x++)
3093
+ {
3094
+ $val = ord($query{$x});
3095
+ if (!(($val >= $a && $val <= $f) || ($val >= $a2 && $val <= $f2) || ($val >= $zero && $val <= $nine))) break;
3096
+ }
3097
+
3098
+ $num = hexdec(substr($query, $cx, $x - $cx));
3099
+ $cx = $x - 1;
3100
+
3101
+ $ident .= TagFilterStream::UTF8Chr($num);
3102
+
3103
+ // Skip one optional \r\n OR a single whitespace char.
3104
+ if ($cx + 2 < $cy && $query{$cx + 1} == "\r" && $query{$cx + 2} == "\n") $cx += 2;
3105
+ else if ($cx + 1 < $cy && ($query{$cx + 1} == " " || $query{$cx + 1} == "\r" || $query{$cx + 1} == "\n" || $query{$cx + 1} == "\t" || $query{$cx + 1} == "\f")) $cx++;
3106
+ }
3107
+ else if ($val != $cr && $val != $nl && $val != $ff)
3108
+ {
3109
+ $ident .= $query{$cx};
3110
+ }
3111
+ }
3112
+ }
3113
+ else if ($allownamespace && $val == $pipe && ($cx + 1 >= $cy || $query{$cx + 1} != "="))
3114
+ {
3115
+ // Handle namespaces (rare).
3116
+ if ($ident != "")
3117
+ {
3118
+ $namespace = $ident;
3119
+ $ident = "";
3120
+ }
3121
+
3122
+ $allownamespace = false;
3123
+ }
3124
+ else if ($val == $asterisk)
3125
+ {
3126
+ // Handle wildcard (*) characters.
3127
+ if ($allownamespace && $cx + 1 < $cy && $query{$cx + 1} == "|")
3128
+ {
3129
+ // Wildcard namespace (*|).
3130
+ $namespace = "*";
3131
+ $allownamespace = false;
3132
+ $cx++;
3133
+ }
3134
+ else if ($identasterisk)
3135
+ {
3136
+ if ($ident != "") return array("success" => false, "error" => "Invalid identifier wildcard character '*' detected at position " . $cx . ".", "errorcode" => "invalid_wildcard_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3137
+
3138
+ $ident = "*";
3139
+ $cx++;
3140
+
3141
+ break;
3142
+ }
3143
+ else
3144
+ {
3145
+ // End of ident.
3146
+ break;
3147
+ }
3148
+ }
3149
+ else
3150
+ {
3151
+ // End of ident.
3152
+ break;
3153
+ }
3154
+
3155
+ $range = true;
3156
+ }
3157
+
3158
+ if ($ident == "") return array("success" => false, "error" => "Missing or invalid identifier at position " . $cx . ".", "errorcode" => "missing_ident", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3159
+
3160
+ $state = $nextstate;
3161
+
3162
+ break;
3163
+ }
3164
+ case "combine":
3165
+ {
3166
+ $token = array("type" => "combine");
3167
+
3168
+ // Find a non-whitespace character.
3169
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
3170
+
3171
+ if ($cx < $cy)
3172
+ {
3173
+ switch ($query{$cx})
3174
+ {
3175
+ case ",":
3176
+ {
3177
+ $token["combine"] = "or";
3178
+ $lastor = count($tokens);
3179
+ $cx++;
3180
+
3181
+ break;
3182
+ }
3183
+ case "+":
3184
+ {
3185
+ $token["combine"] = "prev-sibling";
3186
+ $cx++;
3187
+
3188
+ break;
3189
+ }
3190
+ case ">":
3191
+ {
3192
+ $token["combine"] = "prev-parent";
3193
+ $cx++;
3194
+
3195
+ break;
3196
+ }
3197
+ case "~":
3198
+ {
3199
+ $token["combine"] = "any-prev-sibling";
3200
+ $cx++;
3201
+
3202
+ break;
3203
+ }
3204
+ default:
3205
+ {
3206
+ $token["combine"] = "any-parent";
3207
+
3208
+ break;
3209
+ }
3210
+ }
3211
+
3212
+ if (!count($tokens) || $tokens[count($tokens) - 1]["type"] == "combine") return array("success" => false, "error" => "Invalid combiner '" . $token["type"] . "' detected at position " . $cx . ".", "errorcode" => "invalid_combiner", "selector" => $query, "startpos" => $currcx, "pos" => $cx, "state" => $currstate, "tokens" => self::ReorderSelectorTokens(array_slice($tokens, 0, $lastor), $splitrules), "splitrules" => $splitrules);
3213
+
3214
+ $tokens[] = $token;
3215
+
3216
+ // Find a non-whitespace character.
3217
+ while ($cx < $cy && ($query{$cx} == " " || $query{$cx} == "\t" || $query{$cx} == "\r" || $query{$cx} == "\n" || $query{$cx} == "\f")) $cx++;
3218
+ }
3219
+
3220
+ $state = "next_selector";
3221
+
3222
+ break;
3223
+ }
3224
+ }
3225
+ } while ($currstate !== $state || $currcx !== $cx);
3226
+
3227
+ return array("success" => true, "selector" => $query, "tokens" => self::ReorderSelectorTokens($tokens, $splitrules), "splitrules" => $splitrules);
3228
+ }
3229
+
3230
+ public static function GetParentPos($stack, $tagname, $start = 0, $attrs = array())
3231
+ {
3232
+ $y = count($stack);
3233
+ for ($x = $start; $x < $y; $x++)
3234
+ {
3235
+ if ($stack[$x]["tag_name"] === $tagname)
3236
+ {
3237
+ $found = true;
3238
+ foreach ($attrs as $key => $val)
3239
+ {
3240
+ if (!isset($stack[$x]["attrs"][$key])) $found = false;
3241
+ else if (is_string($stack[$x]["attrs"][$key]) && is_string($val) && stripos($stack[$x]["attrs"][$key], $val) === false) $found = false;
3242
+ else if (is_array($stack[$x]["attrs"][$key]))
3243
+ {
3244
+ if (is_string($val)) $val = explode(" ", $val);
3245
+
3246
+ foreach ($val as $val2)
3247
+ {
3248
+ if ($val2 !== "" && !isset($stack[$x]["attrs"][$key][$val2])) $found = false;
3249
+ }
3250
+ }
3251
+ }
3252
+
3253
+ if ($found) return $x;
3254
+ }
3255
+ }
3256
+
3257
+ return false;
3258
+ }
3259
+ }
3260
+ ?>
includes/vendor/ultimate-web-scraper/web_browser.php ADDED
@@ -0,0 +1,1189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP web browser state emulation class.
3
+ // (C) 2016 CubicleSoft. All Rights Reserved.
4
+
5
+ // Requires the CubicleSoft PHP HTTP class for HTTP/HTTPS.
6
+ class WebBrowser
7
+ {
8
+ private $data, $html;
9
+
10
+ public function __construct($prevstate = array())
11
+ {
12
+ if (!class_exists("HTTP", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/http.php";
13
+
14
+ $this->ResetState();
15
+ $this->SetState($prevstate);
16
+ $this->html = false;
17
+ }
18
+
19
+ public function ResetState()
20
+ {
21
+ $this->data = array(
22
+ "allowedprotocols" => array("http" => true, "https" => true),
23
+ "allowedredirprotocols" => array("http" => true, "https" => true),
24
+ "hostauths" => array(),
25
+ "cookies" => array(),
26
+ "referer" => "",
27
+ "autoreferer" => true,
28
+ "useragent" => "firefox",
29
+ "followlocation" => true,
30
+ "maxfollow" => 20,
31
+ "extractforms" => false,
32
+ "httpopts" => array(),
33
+ );
34
+ }
35
+
36
+ public function SetState($options = array())
37
+ {
38
+ $this->data = array_merge($this->data, $options);
39
+ }
40
+
41
+ public function GetState()
42
+ {
43
+ return $this->data;
44
+ }
45
+
46
+ public function ProcessState(&$state)
47
+ {
48
+ while ($state["state"] !== "done")
49
+ {
50
+ switch ($state["state"])
51
+ {
52
+ case "initialize":
53
+ {
54
+ if (!isset($this->data["allowedprotocols"][$state["urlinfo"]["scheme"]]) || !$this->data["allowedprotocols"][$state["urlinfo"]["scheme"]])
55
+ {
56
+ return array("success" => false, "error" => self::WBTranslate("Protocol '%s' is not allowed in '%s'.", $state["urlinfo"]["scheme"], $state["url"]), "errorcode" => "allowed_protocols");
57
+ }
58
+
59
+ $filename = HTTP::ExtractFilename($state["urlinfo"]["path"]);
60
+ $pos = strrpos($filename, ".");
61
+ $fileext = ($pos !== false ? strtolower(substr($filename, $pos + 1)) : "");
62
+
63
+ // Set up some standard headers.
64
+ $headers = array();
65
+ $profile = strtolower($state["profile"]);
66
+ $tempprofile = explode("-", $profile);
67
+ if (count($tempprofile) == 2)
68
+ {
69
+ $profile = $tempprofile[0];
70
+ $fileext = $tempprofile[1];
71
+ }
72
+ if (substr($profile, 0, 2) == "ie" || ($profile == "auto" && substr($this->data["useragent"], 0, 2) == "ie"))
73
+ {
74
+ if ($fileext == "css") $headers["Accept"] = "text/css";
75
+ else if ($fileext == "png" || $fileext == "jpg" || $fileext == "jpeg" || $fileext == "gif" || $fileext == "svg") $headers["Accept"] = "image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5";
76
+ else if ($fileext == "js") $headers["Accept"] = "application/javascript, */*;q=0.8";
77
+ else if ($this->data["referer"] != "" || $fileext == "" || $fileext == "html" || $fileext == "xhtml" || $fileext == "xml") $headers["Accept"] = "text/html, application/xhtml+xml, */*";
78
+ else $headers["Accept"] = "*/*";
79
+
80
+ $headers["Accept-Language"] = "en-US";
81
+ $headers["User-Agent"] = HTTP::GetUserAgent(substr($profile, 0, 2) == "ie" ? $profile : $this->data["useragent"]);
82
+ }
83
+ else if ($profile == "firefox" || ($profile == "auto" && $this->data["useragent"] == "firefox"))
84
+ {
85
+ if ($fileext == "css") $headers["Accept"] = "text/css,*/*;q=0.1";
86
+ else if ($fileext == "png" || $fileext == "jpg" || $fileext == "jpeg" || $fileext == "gif" || $fileext == "svg") $headers["Accept"] = "image/png,image/*;q=0.8,*/*;q=0.5";
87
+ else if ($fileext == "js") $headers["Accept"] = "*/*";
88
+ else $headers["Accept"] = "text/html, application/xhtml+xml, */*";
89
+
90
+ $headers["Accept-Language"] = "en-us,en;q=0.5";
91
+ $headers["Cache-Control"] = "max-age=0";
92
+ $headers["User-Agent"] = HTTP::GetUserAgent("firefox");
93
+ }
94
+ else if ($profile == "opera" || ($profile == "auto" && $this->data["useragent"] == "opera"))
95
+ {
96
+ // Opera has the right idea: Just send the same thing regardless of the request type.
97
+ $headers["Accept"] = "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1";
98
+ $headers["Accept-Language"] = "en-US,en;q=0.9";
99
+ $headers["Cache-Control"] = "no-cache";
100
+ $headers["User-Agent"] = HTTP::GetUserAgent("opera");
101
+ }
102
+ else if ($profile == "safari" || $profile == "chrome" || ($profile == "auto" && ($this->data["useragent"] == "safari" || $this->data["useragent"] == "chrome")))
103
+ {
104
+ if ($fileext == "css") $headers["Accept"] = "text/css,*/*;q=0.1";
105
+ else if ($fileext == "png" || $fileext == "jpg" || $fileext == "jpeg" || $fileext == "gif" || $fileext == "svg" || $fileext == "js") $headers["Accept"] = "*/*";
106
+ else $headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
107
+
108
+ $headers["Accept-Charset"] = "ISO-8859-1,utf-8;q=0.7,*;q=0.3";
109
+ $headers["Accept-Language"] = "en-US,en;q=0.8";
110
+ $headers["User-Agent"] = HTTP::GetUserAgent($profile == "safari" || $profile == "chrome" ? $profile : $this->data["useragent"]);
111
+ }
112
+
113
+ if ($this->data["referer"] != "") $headers["Referer"] = $this->data["referer"];
114
+
115
+ // Generate the final headers array.
116
+ $headers = array_merge($headers, $state["httpopts"]["headers"], $state["tempoptions"]["headers"]);
117
+
118
+ // Calculate the host and reverse host and remove port information.
119
+ $host = (isset($headers["Host"]) ? $headers["Host"] : $state["urlinfo"]["host"]);
120
+ $pos = strpos($host, "]");
121
+ if (substr($host, 0, 1) == "[" && $pos !== false)
122
+ {
123
+ $host = substr($host, 0, $pos + 1);
124
+ }
125
+ else
126
+ {
127
+ $pos = strpos($host, ":");
128
+ if ($pos !== false) $host = substr($host, 0, $pos);
129
+ }
130
+ $dothost = $host;
131
+ $dothost = strtolower($dothost);
132
+ if (substr($dothost, 0, 1) != ".") $dothost = "." . $dothost;
133
+ $state["dothost"] = $dothost;
134
+
135
+ // Append Authorization header.
136
+ if (isset($headers["Authorization"])) $this->data["hostauths"][$host] = $headers["Authorization"];
137
+ else if (isset($this->data["hostauths"][$host])) $headers["Authorization"] = $this->data["hostauths"][$host];
138
+
139
+ // Append cookies and delete old, invalid cookies.
140
+ $secure = ($state["urlinfo"]["scheme"] == "https");
141
+ $cookiepath = $state["urlinfo"]["path"];
142
+ if ($cookiepath == "") $cookiepath = "/";
143
+ $pos = strrpos($cookiepath, "/");
144
+ if ($pos !== false) $cookiepath = substr($cookiepath, 0, $pos + 1);
145
+ $state["cookiepath"] = $cookiepath;
146
+ $cookies = array();
147
+ foreach ($this->data["cookies"] as $domain => $paths)
148
+ {
149
+ if (strlen($dothost) >= strlen($domain) && substr($dothost, -strlen($domain)) === $domain)
150
+ {
151
+ foreach ($paths as $path => $cookies2)
152
+ {
153
+ if (substr($cookiepath, 0, strlen($path)) == $path)
154
+ {
155
+ foreach ($cookies2 as $num => $info)
156
+ {
157
+ if (isset($info["expires_ts"]) && $this->GetExpiresTimestamp($info["expires_ts"]) < time()) unset($this->data["cookies"][$domain][$path][$num]);
158
+ else if ($secure || !isset($info["secure"])) $cookies[$info["name"]] = $info["value"];
159
+ }
160
+
161
+ if (!count($this->data["cookies"][$domain][$path])) unset($this->data["cookies"][$domain][$path]);
162
+ }
163
+ }
164
+
165
+ if (!count($this->data["cookies"][$domain])) unset($this->data["cookies"][$domain]);
166
+ }
167
+ }
168
+
169
+ $cookies2 = array();
170
+ foreach ($cookies as $name => $value) $cookies2[] = rawurlencode($name) . "=" . rawurlencode($value);
171
+ $headers["Cookie"] = implode("; ", $cookies2);
172
+ if ($headers["Cookie"] == "") unset($headers["Cookie"]);
173
+
174
+ // Generate the final options array.
175
+ $state["options"] = array_merge($state["httpopts"], $state["tempoptions"]);
176
+ $state["options"]["headers"] = $headers;
177
+ if ($state["timeout"] !== false) $state["options"]["timeout"] = HTTP::GetTimeLeft($state["startts"], $state["timeout"]);
178
+
179
+ // Let a callback handle any additional state changes.
180
+ if (isset($state["options"]["pre_retrievewebpage_callback"]) && is_callable($state["options"]["pre_retrievewebpage_callback"]) && !call_user_func_array($state["options"]["pre_retrievewebpage_callback"], array(&$state)))
181
+ {
182
+ return array("success" => false, "error" => self::WBTranslate("Pre-RetrieveWebpage callback returned with a failure condition for '%s'.", $state["url"]), "errorcode" => "pre_retrievewebpage_callback");
183
+ }
184
+
185
+ // Process the request.
186
+ $result = HTTP::RetrieveWebpage($state["url"], $state["options"]);
187
+ $result["url"] = $state["url"];
188
+ unset($state["options"]["files"]);
189
+ unset($state["options"]["body"]);
190
+ unset($state["tempoptions"]["headers"]["Content-Type"]);
191
+ $result["options"] = $state["options"];
192
+ $result["firstreqts"] = $state["startts"];
193
+ $result["numredirects"] = $state["numredirects"];
194
+ $result["redirectts"] = $state["redirectts"];
195
+ if (isset($result["rawsendsize"])) $state["totalrawsendsize"] += $result["rawsendsize"];
196
+ $result["totalrawsendsize"] = $state["totalrawsendsize"];
197
+ if (!$result["success"]) return array("success" => false, "error" => self::WBTranslate("Unable to retrieve content. %s", $result["error"]), "info" => $result, "state" => $state, "errorcode" => "retrievewebpage");
198
+
199
+ if (isset($state["options"]["async"]) && $state["options"]["async"])
200
+ {
201
+ $state["async"] = true;
202
+ $state["httpstate"] = $result["state"];
203
+
204
+ $state["state"] = "process_async";
205
+ }
206
+ else
207
+ {
208
+ $state["result"] = $result;
209
+
210
+ $state["state"] = "post_retrieval";
211
+ }
212
+
213
+ break;
214
+ }
215
+ case "process_async":
216
+ {
217
+ // Run a cycle of the HTTP state processor.
218
+ $result = HTTP::ProcessState($state["httpstate"]);
219
+ if (!$result["success"]) return $result;
220
+
221
+ $result["url"] = $state["url"];
222
+ $result["options"] = $state["options"];
223
+ unset($result["options"]["files"]);
224
+ unset($result["options"]["body"]);
225
+ $result["firstreqts"] = $state["startts"];
226
+ $result["numredirects"] = $state["numredirects"];
227
+ $result["redirectts"] = $state["redirectts"];
228
+ if (isset($result["rawsendsize"])) $state["totalrawsendsize"] += $result["rawsendsize"];
229
+ $result["totalrawsendsize"] = $state["totalrawsendsize"];
230
+
231
+ $state["httpstate"] = false;
232
+ $state["result"] = $result;
233
+
234
+ $state["state"] = "post_retrieval";
235
+
236
+ break;
237
+ }
238
+ case "post_retrieval":
239
+ {
240
+ // Set up structures for another round.
241
+ if ($this->data["autoreferer"]) $this->data["referer"] = $state["url"];
242
+ if (isset($state["result"]["headers"]["Location"]) && $this->data["followlocation"])
243
+ {
244
+ $state["redirectts"] = microtime(true);
245
+
246
+ unset($state["tempoptions"]["method"]);
247
+ unset($state["tempoptions"]["write_body_callback"]);
248
+ unset($state["tempoptions"]["body"]);
249
+ unset($state["tempoptions"]["postvars"]);
250
+ unset($state["tempoptions"]["files"]);
251
+
252
+ $state["tempoptions"]["headers"]["Referer"] = $state["url"];
253
+ $state["url"] = $state["result"]["headers"]["Location"][0];
254
+
255
+ // Generate an absolute URL.
256
+ if ($this->data["referer"] != "") $state["url"] = HTTP::ConvertRelativeToAbsoluteURL($this->data["referer"], $state["url"]);
257
+
258
+ $urlinfo2 = HTTP::ExtractURL($state["url"]);
259
+
260
+ if (!isset($this->data["allowedredirprotocols"][$urlinfo2["scheme"]]) || !$this->data["allowedredirprotocols"][$urlinfo2["scheme"]])
261
+ {
262
+ return array("success" => false, "error" => self::WBTranslate("Protocol '%s' is not allowed. Server attempted to redirect to '%s'.", $urlinfo2["scheme"], $state["url"]), "info" => $state["result"], "errorcode" => "allowed_redir_protocols");
263
+ }
264
+
265
+ if ($urlinfo2["host"] != $state["urlinfo"]["host"])
266
+ {
267
+ unset($state["tempoptions"]["headers"]["Host"]);
268
+ unset($state["httpopts"]["headers"]["Host"]);
269
+
270
+ unset($state["httpopts"]["headers"]["Authorization"]);
271
+ unset($state["tempoptions"]["headers"]["Authorization"]);
272
+ }
273
+
274
+ $state["urlinfo"] = $urlinfo2;
275
+ $state["numredirects"]++;
276
+ }
277
+
278
+ // Handle any 'Set-Cookie' headers.
279
+ if (isset($state["result"]["headers"]["Set-Cookie"]))
280
+ {
281
+ foreach ($state["result"]["headers"]["Set-Cookie"] as $cookie)
282
+ {
283
+ $items = explode(";", $cookie);
284
+ $item = trim(array_shift($items));
285
+ if ($item != "")
286
+ {
287
+ $cookie2 = array();
288
+ $pos = strpos($item, "=");
289
+ if ($pos === false)
290
+ {
291
+ $cookie2["name"] = urldecode($item);
292
+ $cookie2["value"] = "";
293
+ }
294
+ else
295
+ {
296
+ $cookie2["name"] = urldecode(substr($item, 0, $pos));
297
+ $cookie2["value"] = urldecode(substr($item, $pos + 1));
298
+ }
299
+
300
+ $cookie = array();
301
+ foreach ($items as $item)
302
+ {
303
+ $item = trim($item);
304
+ if ($item != "")
305
+ {
306
+ $pos = strpos($item, "=");
307
+ if ($pos === false) $cookie[strtolower(trim(urldecode($item)))] = "";
308
+ else $cookie[strtolower(trim(urldecode(substr($item, 0, $pos))))] = urldecode(substr($item, $pos + 1));
309
+ }
310
+ }
311
+ $cookie = array_merge($cookie, $cookie2);
312
+
313
+ if (isset($cookie["expires"]))
314
+ {
315
+ $ts = HTTP::GetDateTimestamp($cookie["expires"]);
316
+ $cookie["expires_ts"] = gmdate("Y-m-d H:i:s", ($ts === false ? time() - 24 * 60 * 60 : $ts));
317
+ }
318
+ else if (isset($cookie["max-age"]))
319
+ {
320
+ $cookie["expires_ts"] = gmdate("Y-m-d H:i:s", time() + (int)$cookie["max-age"]);
321
+ }
322
+ else
323
+ {
324
+ unset($cookie["expires_ts"]);
325
+ }
326
+
327
+ if (!isset($cookie["domain"])) $cookie["domain"] = $state["dothost"];
328
+ if (!isset($cookie["path"])) $cookie["path"] = $state["cookiepath"];
329
+
330
+ $this->SetCookie($cookie);
331
+ }
332
+ }
333
+ }
334
+
335
+ if ($state["numfollow"] > 0) $state["numfollow"]--;
336
+
337
+ // If this is a redirect, handle it by starting over.
338
+ if (isset($state["result"]["headers"]["Location"]) && $this->data["followlocation"] && $state["numfollow"])
339
+ {
340
+ $state["result"] = false;
341
+
342
+ $state["state"] = "initialize";
343
+ }
344
+ else
345
+ {
346
+ $state["result"]["numredirects"] = $state["numredirects"];
347
+ $state["result"]["redirectts"] = $state["redirectts"];
348
+
349
+ // Extract the forms from the page in a parsed format.
350
+ // Call WebBrowser::GenerateFormRequest() to prepare an actual request for Process().
351
+ if ($this->data["extractforms"]) $state["result"]["forms"] = $this->ExtractForms($state["result"]["url"], $state["result"]["body"], (isset($state["tempoptions"]["extractforms_hint"]) ? $state["tempoptions"]["extractforms_hint"] : false));
352
+
353
+ $state["state"] = "done";
354
+ }
355
+
356
+ break;
357
+ }
358
+ }
359
+ }
360
+
361
+ return $state["result"];
362
+ }
363
+
364
+ public function Process($url, $tempoptions = array())
365
+ {
366
+ $startts = microtime(true);
367
+ $redirectts = $startts;
368
+
369
+ // Handle older function call: Process($url, $profile, $tempoptions)
370
+ if (is_string($tempoptions))
371
+ {
372
+ $args = func_get_args();
373
+ if (count($args) < 3) $tempoptions = array();
374
+ else $tempoptions = $args[2];
375
+
376
+ $tempoptions["profile"] = $args[1];
377
+ }
378
+
379
+ $profile = (isset($tempoptions["profile"]) ? $tempoptions["profile"] : "auto");
380
+
381
+ if (isset($tempoptions["timeout"])) $timeout = $tempoptions["timeout"];
382
+ else if (isset($this->data["httpopts"]["timeout"])) $timeout = $this->data["httpopts"]["timeout"];
383
+ else $timeout = false;
384
+
385
+ // Deal with possible application hanging issues.
386
+ if (isset($tempoptions["streamtimeout"])) $streamtimeout = $tempoptions["streamtimeout"];
387
+ else if (isset($this->data["httpopts"]["streamtimeout"])) $streamtimeout = $this->data["httpopts"]["streamtimeout"];
388
+ else $streamtimeout = 300;
389
+ $tempoptions["streamtimeout"] = $streamtimeout;
390
+
391
+ if (!isset($this->data["httpopts"]["headers"])) $this->data["httpopts"]["headers"] = array();
392
+ $this->data["httpopts"]["headers"] = HTTP::NormalizeHeaders($this->data["httpopts"]["headers"]);
393
+ unset($this->data["httpopts"]["method"]);
394
+ unset($this->data["httpopts"]["write_body_callback"]);
395
+ unset($this->data["httpopts"]["body"]);
396
+ unset($this->data["httpopts"]["postvars"]);
397
+ unset($this->data["httpopts"]["files"]);
398
+
399
+ $httpopts = $this->data["httpopts"];
400
+ $numfollow = $this->data["maxfollow"];
401
+ $numredirects = 0;
402
+ $totalrawsendsize = 0;
403
+
404
+ if (!isset($tempoptions["headers"])) $tempoptions["headers"] = array();
405
+ $tempoptions["headers"] = HTTP::NormalizeHeaders($tempoptions["headers"]);
406
+ if (isset($tempoptions["headers"]["Referer"])) $this->data["referer"] = $tempoptions["headers"]["Referer"];
407
+
408
+ // If a referrer is specified, use it to generate an absolute URL.
409
+ if ($this->data["referer"] != "") $url = HTTP::ConvertRelativeToAbsoluteURL($this->data["referer"], $url);
410
+
411
+ $urlinfo = HTTP::ExtractURL($url);
412
+
413
+ // Initialize the process state array.
414
+ $state = array(
415
+ "async" => false,
416
+ "startts" => $startts,
417
+ "redirectts" => $redirectts,
418
+ "timeout" => $timeout,
419
+ "tempoptions" => $tempoptions,
420
+ "httpopts" => $httpopts,
421
+ "numfollow" => $numfollow,
422
+ "numredirects" => $numredirects,
423
+ "totalrawsendsize" => $totalrawsendsize,
424
+ "profile" => $profile,
425
+ "url" => $url,
426
+ "urlinfo" => $urlinfo,
427
+
428
+ "state" => "initialize",
429
+ "httpstate" => false,
430
+ "result" => false,
431
+ );
432
+
433
+ // Run at least one state cycle to properly initialize the state array.
434
+ $result = $this->ProcessState($state);
435
+
436
+ // Return the state for async calls. Caller must call ProcessState().
437
+ if ($state["async"]) return array("success" => true, "state" => $state);
438
+
439
+ return $result;
440
+ }
441
+
442
+ // Implements the correct MultiAsyncHelper responses for WebBrowser instances.
443
+ public function ProcessAsync__Handler($mode, &$data, $key, &$info)
444
+ {
445
+ switch ($mode)
446
+ {
447
+ case "init":
448
+ {
449
+ if ($info["init"]) $data = $info["keep"];
450
+ else
451
+ {
452
+ $info["result"] = $this->Process($info["url"], $info["tempoptions"]);
453
+ if (!$info["result"]["success"])
454
+ {
455
+ $info["keep"] = false;
456
+
457
+ if (is_callable($info["callback"])) call_user_func_array($info["callback"], array($key, $info["url"], $info["result"]));
458
+ }
459
+ else
460
+ {
461
+ $info["state"] = $info["result"]["state"];
462
+
463
+ // Move to the live queue.
464
+ $data = true;
465
+ }
466
+ }
467
+
468
+ break;
469
+ }
470
+ case "update":
471
+ case "read":
472
+ case "write":
473
+ {
474
+ if ($info["keep"])
475
+ {
476
+ $info["result"] = $this->ProcessState($info["state"]);
477
+ if ($info["result"]["success"] || $info["result"]["errorcode"] !== "no_data") $info["keep"] = false;
478
+
479
+ if (is_callable($info["callback"])) call_user_func_array($info["callback"], array($key, $info["url"], $info["result"]));
480
+
481
+ if ($mode === "update") $data = $info["keep"];
482
+ }
483
+
484
+ break;
485
+ }
486
+ case "readfps":
487
+ {
488
+ if ($info["state"]["httpstate"] !== false && HTTP::WantRead($info["state"]["httpstate"])) $data[$key] = $info["state"]["httpstate"]["fp"];
489
+
490
+ break;
491
+ }
492
+ case "writefps":
493
+ {
494
+ if ($info["state"]["httpstate"] !== false && HTTP::WantWrite($info["state"]["httpstate"])) $data[$key] = $info["state"]["httpstate"]["fp"];
495
+
496
+ break;
497
+ }
498
+ case "cleanup":
499
+ {
500
+ // When true, caller is removing. Otherwise, detaching from the queue.
501
+ if ($data === true)
502
+ {
503
+ if (isset($info["state"]))
504
+ {
505
+ if ($info["state"]["httpstate"] !== false) HTTP::ForceClose($info["state"]["httpstate"]);
506
+
507
+ unset($info["state"]);
508
+ }
509
+
510
+ $info["keep"] = false;
511
+ }
512
+
513
+ break;
514
+ }
515
+ }
516
+ }
517
+
518
+ public function ProcessAsync($helper, $key, $callback, $url, $tempoptions = array())
519
+ {
520
+ $tempoptions["async"] = true;
521
+
522
+ // Handle older function call: ProcessAsync($helper, $key, $callback, $url, $profile, $tempoptions)
523
+ if (is_string($tempoptions))
524
+ {
525
+ $args = func_get_args();
526
+ if (count($args) < 6) $tempoptions = array();
527
+ else $tempoptions = $args[5];
528
+
529
+ $tempoptions["profile"] = $args[4];
530
+ }
531
+
532
+ $profile = (isset($tempoptions["profile"]) ? $tempoptions["profile"] : "auto");
533
+
534
+ $info = array(
535
+ "init" => false,
536
+ "keep" => true,
537
+ "callback" => $callback,
538
+ "url" => $url,
539
+ "tempoptions" => $tempoptions,
540
+ "result" => false
541
+ );
542
+
543
+ $helper->Set($key, $info, array($this, "ProcessAsync__Handler"));
544
+
545
+ return array("success" => true);
546
+ }
547
+
548
+ public function ExtractForms($baseurl, $data, $hint = false)
549
+ {
550
+ $result = array();
551
+
552
+ $lasthint = "";
553
+ $hintmap = array();
554
+ if ($this->html === false)
555
+ {
556
+ if (!class_exists("simple_html_dom", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/simple_html_dom.php";
557
+
558
+ $this->html = new simple_html_dom();
559
+ }
560
+ $this->html->load($data);
561
+ $rows = $this->html->find("label[for]");
562
+ foreach ($rows as $row)
563
+ {
564
+ $hintmap[trim($row->for)] = trim($row->plaintext);
565
+ }
566
+ $html5rows = $this->html->find("input[form],textarea[form],select[form],button[form],datalist[id]" . ($hint !== false ? "," . $hint : ""));
567
+ $rows = $this->html->find("form");
568
+ foreach ($rows as $row)
569
+ {
570
+ $info = array();
571
+ if (isset($row->id)) $info["id"] = trim($row->id);
572
+ if (isset($row->name)) $info["name"] = (string)$row->name;
573
+ $info["action"] = (isset($row->action) ? HTTP::ConvertRelativeToAbsoluteURL($baseurl, (string)$row->action) : $baseurl);
574
+ $info["method"] = (isset($row->method) && strtolower(trim($row->method)) == "post" ? "post" : "get");
575
+ if ($info["method"] == "post") $info["enctype"] = (isset($row->enctype) ? strtolower($row->enctype) : "application/x-www-form-urlencoded");
576
+ if (isset($row->{"accept-charset"})) $info["accept-charset"] = (string)$row->{"accept-charset"};
577
+
578
+ $fields = array();
579
+ $rows2 = $row->find("input,textarea,select,button" . ($hint !== false ? "," . $hint : ""));
580
+ foreach ($rows2 as $row2)
581
+ {
582
+ if (!isset($row2->form))
583
+ {
584
+ if (isset($row2->id) && $row2->id != "" && isset($hintmap[trim($row2->id)])) $lasthint = $hintmap[trim($row2->id)];
585
+
586
+ $this->ExtractFieldFromDOM($fields, $row2, $lasthint);
587
+ }
588
+ }
589
+
590
+ // Handle HTML5.
591
+ if (isset($info["id"]) && $info["id"] != "")
592
+ {
593
+ foreach ($html5rows as $row2)
594
+ {
595
+ if (strpos(" " . $info["id"] . " ", " " . $row2->form . " ") !== false)
596
+ {
597
+ if (isset($hintmap[$info["id"]])) $lasthint = $hintmap[$info["id"]];
598
+
599
+ $this->ExtractFieldFromDOM($fields, $row2, $lasthint);
600
+ }
601
+ }
602
+ }
603
+
604
+ $form = new WebBrowserForm();
605
+ $form->info = $info;
606
+ $form->fields = $fields;
607
+ $result[] = $form;
608
+ }
609
+
610
+ return $result;
611
+ }
612
+
613
+ private function ExtractFieldFromDOM(&$fields, $row, &$lasthint)
614
+ {
615
+ switch ($row->tag)
616
+ {
617
+ case "input":
618
+ {
619
+ if (!isset($row->name) && ($row->type === "submit" || $row->type === "image")) $row->name = "";
620
+
621
+ if (isset($row->name) && is_string($row->name))
622
+ {
623
+ $field = array(
624
+ "id" => (isset($row->id) ? (string)$row->id : false),
625
+ "type" => "input." . (isset($row->type) ? strtolower($row->type) : "text"),
626
+ "name" => $row->name,
627
+ "value" => (isset($row->value) ? html_entity_decode($row->value, ENT_COMPAT, "UTF-8") : "")
628
+ );
629
+ if ($field["type"] == "input.radio" || $field["type"] == "input.checkbox")
630
+ {
631
+ $field["checked"] = (isset($row->checked));
632
+
633
+ if ($field["value"] === "") $field["value"] = "on";
634
+ }
635
+
636
+ if (isset($row->placeholder)) $field["hint"] = trim($row->placeholder);
637
+ else if ($field["type"] == "input.submit" || $field["type"] == "input.image") $field["hint"] = $field["type"] . "|" . $field["value"];
638
+ else if ($lasthint !== "") $field["hint"] = $lasthint;
639
+
640
+ $fields[] = $field;
641
+
642
+ $lasthint = "";
643
+ }
644
+
645
+ break;
646
+ }
647
+ case "textarea":
648
+ {
649
+ if (isset($row->name) && is_string($row->name))
650
+ {
651
+ $field = array(
652
+ "id" => (isset($row->id) ? (string)$row->id : false),
653
+ "type" => "textarea",
654
+ "name" => $row->name,
655
+ "value" => html_entity_decode($row->innertext, ENT_COMPAT, "UTF-8")
656
+ );
657
+
658
+ if (isset($row->placeholder)) $field["hint"] = trim($row->placeholder);
659
+ else if ($lasthint !== "") $field["hint"] = $lasthint;
660
+
661
+ $fields[] = $field;
662
+
663
+ $lasthint = "";
664
+ }
665
+
666
+ break;
667
+ }
668
+ case "select":
669
+ {
670
+ if (isset($row->name) && is_string($row->name))
671
+ {
672
+ if (isset($row->multiple))
673
+ {
674
+ // Change the type into multiple checkboxes.
675
+ $rows = $row->find("option");
676
+ foreach ($rows as $row2)
677
+ {
678
+ $field = array(
679
+ "id" => (isset($row->id) ? (string)$row->id : false),
680
+ "type" => "input.checkbox",
681
+ "name" => $row->name,
682
+ "value" => (isset($row2->value) ? html_entity_decode($row2->value, ENT_COMPAT, "UTF-8") : ""),
683
+ "display" => (string)$row2->innertext
684
+ );
685
+ if ($lasthint !== "") $field["hint"] = $lasthint;
686
+
687
+ $fields[] = $field;
688
+ }
689
+ }
690
+ else
691
+ {
692
+ $val = false;
693
+ $options = array();
694
+ $rows = $row->find("option");
695
+ foreach ($rows as $row2)
696
+ {
697
+ $options[$row2->value] = (string)$row2->innertext;
698
+
699
+ if ($val === false && isset($row2->selected)) $val = html_entity_decode($row2->value, ENT_COMPAT, "UTF-8");
700
+ }
701
+ if ($val === false && count($options))
702
+ {
703
+ $val = array_keys($options);
704
+ $val = $val[0];
705
+ }
706
+ if ($val === false) $val = "";
707
+
708
+ $field = array(
709
+ "id" => (isset($row->id) ? (string)$row->id : false),
710
+ "type" => "select",
711
+ "name" => $row->name,
712
+ "value" => $val,
713
+ "options" => $options
714
+ );
715
+ if ($lasthint !== "") $field["hint"] = $lasthint;
716
+
717
+ $fields[] = $field;
718
+ }
719
+
720
+ $lasthint = "";
721
+ }
722
+
723
+ break;
724
+ }
725
+ case "button":
726
+ {
727
+ if (isset($row->name) && is_string($row->name))
728
+ {
729
+ $field = array(
730
+ "id" => (isset($row->id) ? (string)$row->id : false),
731
+ "type" => "button." . (isset($row->type) ? strtolower($row->type) : "submit"),
732
+ "name" => $row->name,
733
+ "value" => (isset($row->value) ? html_entity_decode($row->value, ENT_COMPAT, "UTF-8") : "")
734
+ );
735
+ $field["hint"] = (trim($row->plaintext) !== "" ? trim($row->plaintext) : "button|" . $field["value"]);
736
+
737
+ $fields[] = $field;
738
+
739
+ $lasthint = "";
740
+ }
741
+
742
+ break;
743
+ }
744
+ case "datalist":
745
+ {
746
+ // Do nothing since browsers don't actually enforce this tag's values.
747
+
748
+ break;
749
+ }
750
+ default:
751
+ {
752
+ // Hint for the next element.
753
+ $lasthint = (string)$row->plaintext;
754
+
755
+ break;
756
+ }
757
+ }
758
+ }
759
+
760
+ public static function InteractiveFormFill($forms, $showselected = false)
761
+ {
762
+ if (!is_array($forms)) $forms = array($forms);
763
+
764
+ if (!count($forms)) return false;
765
+
766
+ if (count($forms) == 1) $form = reset($forms);
767
+ else
768
+ {
769
+ echo self::WBTranslate("There are multiple forms available to fill out:\n");
770
+ foreach ($forms as $num => $form)
771
+ {
772
+ echo self::WBTranslate("\t%d:\n", $num + 1);
773
+ foreach ($form->info as $key => $val) echo self::WBTranslate("\t\t%s: %s\n", $key, $val);
774
+ echo self::WBTranslate("\t\tfields: %d\n", count($form->GetVisibleFields(false)));
775
+ echo self::WBTranslate("\t\tbuttons: %d\n", count($form->GetVisibleFields(true)) - count($form->GetVisibleFields(false)));
776
+ echo "\n";
777
+ }
778
+
779
+ do
780
+ {
781
+ echo self::WBTranslate("Select: ");
782
+
783
+ $num = (int)trim(fgets(STDIN)) - 1;
784
+ } while (!isset($forms[$num]));
785
+
786
+ $form = $forms[$num];
787
+ }
788
+
789
+ if ($showselected)
790
+ {
791
+ echo self::WBTranslate("Selected form:\n");
792
+ foreach ($form->info as $key => $val) echo self::WBTranslate("\t%s: %s\n", $key, $val);
793
+ echo "\n";
794
+ }
795
+
796
+ if (count($form->GetVisibleFields(false)))
797
+ {
798
+ echo self::WBTranslate("Select form fields by field number to edit a field. When ready to submit the form, leave 'Field number' empty.\n\n");
799
+
800
+ do
801
+ {
802
+ echo self::WBTranslate("Editable form fields:\n");
803
+ foreach ($form->fields as $num => $field)
804
+ {
805
+ if ($field["type"] == "input.hidden" || $field["type"] == "input.submit" || $field["type"] == "input.image" || $field["type"] == "input.button" || substr($field["type"], 0, 7) == "button.") continue;
806
+
807
+ echo self::WBTranslate("\t%d: %s - %s\n", $num + 1, $field["name"], (is_array($field["value"]) ? json_encode($field["value"], JSON_PRETTY_PRINT) : $field["value"]) . (($field["type"] == "input.radio" || $field["type"] == "input.checkbox") ? ($field["checked"] ? self::WBTranslate(" [Y]") : self::WBTranslate(" [N]")) : "") . (isset($field["hint"]) && $field["hint"] !== "" ? " [" . $field["hint"] . "]" : ""));
808
+ }
809
+ echo "\n";
810
+
811
+ do
812
+ {
813
+ echo self::WBTranslate("Field number: ");
814
+
815
+ $num = trim(fgets(STDIN));
816
+ if ($num === "") break;
817
+
818
+ $num = (int)$num - 1;
819
+ } while (!isset($form->fields[$num]) || $form->fields[$num]["type"] == "input.hidden" || $form->fields[$num]["type"] == "input.submit" || $form->fields[$num]["type"] == "input.image" || $form->fields[$num]["type"] == "input.button" || substr($form->fields[$num]["type"], 0, 7) == "button.");
820
+
821
+ if ($num === "")
822
+ {
823
+ echo "\n";
824
+
825
+ break;
826
+ }
827
+
828
+ $field = $form->fields[$num];
829
+ $prefix = (isset($field["hint"]) && $field["hint"] !== "" ? $field["hint"] . " | " : "") . $field["name"];
830
+
831
+ if ($field["type"] == "select")
832
+ {
833
+ echo self::WBTranslate("[%s] Options:\n", $prefix);
834
+ foreach ($field["options"] as $key => $val)
835
+ {
836
+ echo self::WBTranslate("\t%s: %s\n");
837
+ }
838
+
839
+ do
840
+ {
841
+ echo self::WBTranslate("[%s] Select: ", $prefix);
842
+
843
+ $select = rtrim(fgets(STDIN));
844
+ } while (!isset($field["options"][$select]));
845
+
846
+ $form->fields[$num]["value"] = $select;
847
+ }
848
+ else if ($field["type"] == "input.radio")
849
+ {
850
+ $form->SetFormValue($field["name"], $field["value"], true, "input.radio");
851
+ }
852
+ else if ($field["type"] == "input.checkbox")
853
+ {
854
+ $form->fields[$num]["checked"] = !$field["checked"];
855
+ }
856
+ else if ($field["type"] == "input.file")
857
+ {
858
+ do
859
+ {
860
+ echo self::WBTranslate("[%s] Filename: ", $prefix);
861
+
862
+ $filename = rtrim(fgets(STDIN));
863
+ } while ($filename !== "" && !file_exists($filename));
864
+
865
+ if ($filename === "") $form->fields[$num]["value"] = "";
866
+ else
867
+ {
868
+ $form->fields[$num]["value"] = array(
869
+ "filename" => $filename,
870
+ "type" => "application/octet-stream",
871
+ "datafile" => $filename
872
+ );
873
+ }
874
+ }
875
+ else
876
+ {
877
+ echo self::WBTranslate("[%s] New value: ", $prefix);
878
+
879
+ $form->fields[$num]["value"] = rtrim(fgets(STDIN));
880
+ }
881
+
882
+ echo "\n";
883
+
884
+ } while (1);
885
+ }
886
+
887
+ $submitoptions = array(array("name" => self::WBTranslate("Default action"), "value" => self::WBTranslate("Might not work"), "hint" => "Default action"));
888
+ foreach ($form->fields as $num => $field)
889
+ {
890
+ if ($field["type"] != "input.submit" && $field["type"] != "input.image" && $field["type"] != "input.button" && $field["type"] != "button.submit") continue;
891
+
892
+ $submitoptions[] = $field;
893
+ }
894
+
895
+ if (count($submitoptions) <= 2) $num = count($submitoptions) - 1;
896
+ else
897
+ {
898
+ echo self::WBTranslate("Available submit buttons:\n");
899
+ foreach ($submitoptions as $num => $field)
900
+ {
901
+ echo self::WBTranslate("\t%d: %s - %s\n", $num, $field["name"], $field["value"] . (isset($field["hint"]) && $field["hint"] !== "" ? " [" . $field["hint"] . "]" : ""));
902
+ }
903
+ echo "\n";
904
+
905
+ do
906
+ {
907
+ echo self::WBTranslate("Select: ");
908
+
909
+ $num = (int)fgets(STDIN);
910
+ } while (!isset($submitoptions[$num]));
911
+
912
+ echo "\n";
913
+ }
914
+
915
+ $result = $form->GenerateFormRequest(($num ? $submitoptions[$num]["name"] : false), ($num ? $submitoptions[$num]["value"] : false));
916
+
917
+ return $result;
918
+ }
919
+
920
+ public function GetCookies()
921
+ {
922
+ return $this->data["cookies"];
923
+ }
924
+
925
+ public function SetCookie($cookie)
926
+ {
927
+ if (!isset($cookie["domain"]) || !isset($cookie["path"]) || !isset($cookie["name"]) || !isset($cookie["value"])) return array("success" => false, "error" => self::WBTranslate("SetCookie() requires 'domain', 'path', 'name', and 'value' to be options."), "errorcode" => "missing_information");
928
+
929
+ $cookie["domain"] = strtolower($cookie["domain"]);
930
+ if (substr($cookie["domain"], 0, 1) != ".") $cookie["domain"] = "." . $cookie["domain"];
931
+
932
+ $cookie["path"] = str_replace("\\", "/", $cookie["path"]);
933
+ if (substr($cookie["path"], -1) != "/") $cookie["path"] = "/";
934
+
935
+ if (!isset($this->data["cookies"][$cookie["domain"]])) $this->data["cookies"][$cookie["domain"]] = array();
936
+ if (!isset($this->data["cookies"][$cookie["domain"]][$cookie["path"]])) $this->data["cookies"][$cookie["domain"]][$cookie["path"]] = array();
937
+ $this->data["cookies"][$cookie["domain"]][$cookie["path"]][$cookie["name"]] = $cookie;
938
+
939
+ return array("success" => true);
940
+ }
941
+
942
+ // Simulates closing a web browser.
943
+ public function DeleteSessionCookies()
944
+ {
945
+ foreach ($this->data["cookies"] as $domain => $paths)
946
+ {
947
+ foreach ($paths as $path => $cookies)
948
+ {
949
+ foreach ($cookies as $num => $info)
950
+ {
951
+ if (!isset($info["expires_ts"])) unset($this->data["cookies"][$domain][$path][$num]);
952
+ }
953
+
954
+ if (!count($this->data["cookies"][$domain][$path])) unset($this->data["cookies"][$domain][$path]);
955
+ }
956
+
957
+ if (!count($this->data["cookies"][$domain])) unset($this->data["cookies"][$domain]);
958
+ }
959
+ }
960
+
961
+ public function DeleteCookies($domainpattern, $pathpattern, $namepattern)
962
+ {
963
+ foreach ($this->data["cookies"] as $domain => $paths)
964
+ {
965
+ if ($domainpattern == "" || substr($domain, -strlen($domainpattern)) == $domainpattern)
966
+ {
967
+ foreach ($paths as $path => $cookies)
968
+ {
969
+ if ($pathpattern == "" || substr($path, 0, strlen($pathpattern)) == $pathpattern)
970
+ {
971
+ foreach ($cookies as $num => $info)
972
+ {
973
+ if ($namepattern == "" || strpos($info["name"], $namepattern) !== false) unset($this->data["cookies"][$domain][$path][$num]);
974
+ }
975
+
976
+ if (!count($this->data["cookies"][$domain][$path])) unset($this->data["cookies"][$domain][$path]);
977
+ }
978
+ }
979
+
980
+ if (!count($this->data["cookies"][$domain])) unset($this->data["cookies"][$domain]);
981
+ }
982
+ }
983
+ }
984
+
985
+ private function GetExpiresTimestamp($ts)
986
+ {
987
+ $year = (int)substr($ts, 0, 4);
988
+ $month = (int)substr($ts, 5, 2);
989
+ $day = (int)substr($ts, 8, 2);
990
+ $hour = (int)substr($ts, 11, 2);
991
+ $min = (int)substr($ts, 14, 2);
992
+ $sec = (int)substr($ts, 17, 2);
993
+
994
+ return gmmktime($hour, $min, $sec, $month, $day, $year);
995
+ }
996
+
997
+ public static function WBTranslate()
998
+ {
999
+ $args = func_get_args();
1000
+ if (!count($args)) return "";
1001
+
1002
+ return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args);
1003
+ }
1004
+ }
1005
+
1006
+ class WebBrowserForm
1007
+ {
1008
+ public $info, $fields;
1009
+
1010
+ public function __construct()
1011
+ {
1012
+ $this->info = array();
1013
+ $this->fields = array();
1014
+ }
1015
+
1016
+ public function FindFormFields($name = false, $value = false, $type = false)
1017
+ {
1018
+ $fields = array();
1019
+ foreach ($this->fields as $num => $field)
1020
+ {
1021
+ if (($type === false || $field["type"] === $type) && ($name === false || $field["name"] === $name) && ($value === false || $field["value"] === $value))
1022
+ {
1023
+ $fields[] = $field;
1024
+ }
1025
+ }
1026
+
1027
+ return $fields;
1028
+ }
1029
+
1030
+ public function GetHintMap()
1031
+ {
1032
+ $result = array();
1033
+ foreach ($this->fields as $num => $field)
1034
+ {
1035
+ if (isset($field["hint"])) $result[$field["hint"]] = $field["name"];
1036
+ }
1037
+
1038
+ return $result;
1039
+ }
1040
+
1041
+ public function GetVisibleFields($submit)
1042
+ {
1043
+ $result = array();
1044
+ foreach ($this->fields as $num => $field)
1045
+ {
1046
+ if ($field["type"] == "input.hidden" || (!$submit && ($field["type"] == "input.submit" || $field["type"] == "input.image" || $field["type"] == "input.button" || substr($field["type"], 0, 7) == "button."))) continue;
1047
+
1048
+ $result[$num] = $field;
1049
+ }
1050
+
1051
+ return $result;
1052
+ }
1053
+
1054
+ public function GetFormValue($name, $checkval = false, $type = false)
1055
+ {
1056
+ $val = false;
1057
+ foreach ($this->fields as $field)
1058
+ {
1059
+ if (($type === false || $field["type"] === $type) && $field["name"] === $name)
1060
+ {
1061
+ if (is_string($checkval))
1062
+ {
1063
+ if ($checkval === $field["value"])
1064
+ {
1065
+ if ($field["type"] == "input.radio" || $field["type"] == "input.checkbox") $val = $field["checked"];
1066
+ else $val = $field["value"];
1067
+ }
1068
+ }
1069
+ else if (($field["type"] != "input.radio" && $field["type"] != "input.checkbox") || $field["checked"])
1070
+ {
1071
+ $val = $field["value"];
1072
+ }
1073
+ }
1074
+ }
1075
+
1076
+ return $val;
1077
+ }
1078
+
1079
+ public function SetFormValue($name, $value, $checked = false, $type = false, $create = false)
1080
+ {
1081
+ $result = false;
1082
+ foreach ($this->fields as $num => $field)
1083
+ {
1084
+ if (($type === false || $field["type"] === $type) && $field["name"] === $name)
1085
+ {
1086
+ if ($field["type"] == "input.radio")
1087
+ {
1088
+ $this->fields[$num]["checked"] = ($field["value"] === $value ? $checked : false);
1089
+ $result = true;
1090
+ }
1091
+ else if ($field["type"] == "input.checkbox")
1092
+ {
1093
+ if ($field["value"] === $value) $this->fields[$num]["checked"] = $checked;
1094
+ $result = true;
1095
+ }
1096
+ else if ($field["type"] != "select" || !isset($field["options"]) || isset($field["options"][$value]))
1097
+ {
1098
+ $this->fields[$num]["value"] = $value;
1099
+ $result = true;
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ // Add the field if it doesn't exist.
1105
+ if (!$result && $create)
1106
+ {
1107
+ $this->fields[] = array(
1108
+ "id" => false,
1109
+ "type" => ($type !== false ? $type : "input.text"),
1110
+ "name" => $name,
1111
+ "value" => $value,
1112
+ "checked" => $checked
1113
+ );
1114
+ }
1115
+
1116
+ return $result;
1117
+ }
1118
+
1119
+ public function GenerateFormRequest($submitname = false, $submitvalue = false)
1120
+ {
1121
+ $method = $this->info["method"];
1122
+ $fields = array();
1123
+ $files = array();
1124
+ foreach ($this->fields as $field)
1125
+ {
1126
+ if ($field["type"] == "input.file")
1127
+ {
1128
+ if (is_array($field["value"]))
1129
+ {
1130
+ $field["value"]["name"] = $field["name"];
1131
+ $files[] = $field["value"];
1132
+ $method = "post";
1133
+ }
1134
+ }
1135
+ else if ($field["type"] == "input.reset" || $field["type"] == "button.reset")
1136
+ {
1137
+ }
1138
+ else if ($field["type"] == "input.submit" || $field["type"] == "input.image" || $field["type"] == "button.submit")
1139
+ {
1140
+ if (($submitname === false || $field["name"] === $submitname) && ($submitvalue === false || $field["value"] === $submitvalue))
1141
+ {
1142
+ if ($submitname !== "")
1143
+ {
1144
+ if (!isset($fields[$field["name"]])) $fields[$field["name"]] = array();
1145
+ $fields[$field["name"]][] = $field["value"];
1146
+ }
1147
+
1148
+ if ($field["type"] == "input.image")
1149
+ {
1150
+ if (!isset($fields["x"])) $fields["x"] = array();
1151
+ $fields["x"][] = "1";
1152
+
1153
+ if (!isset($fields["y"])) $fields["y"] = array();
1154
+ $fields["y"][] = "1";
1155
+ }
1156
+ }
1157
+ }
1158
+ else if (($field["type"] != "input.radio" && $field["type"] != "input.checkbox") || $field["checked"])
1159
+ {
1160
+ if (!isset($fields[$field["name"]])) $fields[$field["name"]] = array();
1161
+ $fields[$field["name"]][] = $field["value"];
1162
+ }
1163
+ }
1164
+
1165
+ if ($method == "get")
1166
+ {
1167
+ $url = HTTP::ExtractURL($this->info["action"]);
1168
+ unset($url["query"]);
1169
+ $url["queryvars"] = $fields;
1170
+ $result = array(
1171
+ "url" => HTTP::CondenseURL($url),
1172
+ "options" => array()
1173
+ );
1174
+ }
1175
+ else
1176
+ {
1177
+ $result = array(
1178
+ "url" => $this->info["action"],
1179
+ "options" => array(
1180
+ "postvars" => $fields,
1181
+ "files" => $files
1182
+ )
1183
+ );
1184
+ }
1185
+
1186
+ return $result;
1187
+ }
1188
+ }
1189
+ ?>
includes/vendor/ultimate-web-scraper/websocket.php ADDED
@@ -0,0 +1,654 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // CubicleSoft PHP WebSocket class.
3
+ // (C) 2017 CubicleSoft. All Rights Reserved.
4
+
5
+ // Implements RFC 6455 (WebSocket protocol).
6
+ // Requires the CubicleSoft PHP HTTP/HTTPS class.
7
+ // Requires the CubicleSoft PHP WebBrowser class.
8
+ class WebSocket
9
+ {
10
+ private $fp, $client, $extensions, $csprng, $state, $closemode;
11
+ private $readdata, $maxreadframesize, $readmessages, $maxreadmessagesize;
12
+ private $writedata, $writemessages, $keepalive, $lastkeepalive, $keepalivesent;
13
+ private $rawrecvsize, $rawsendsize;
14
+
15
+ const KEY_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
16
+
17
+ const STATE_CONNECTING = 0;
18
+ const STATE_OPEN = 1;
19
+ const STATE_CLOSE = 2;
20
+
21
+ const CLOSE_IMMEDIATELY = 0;
22
+ const CLOSE_AFTER_CURRENT_MESSAGE = 1;
23
+ const CLOSE_AFTER_ALL_MESSAGES = 2;
24
+
25
+ const FRAMETYPE_CONTINUATION = 0x00;
26
+ const FRAMETYPE_TEXT = 0x01;
27
+ const FRAMETYPE_BINARY = 0x02;
28
+
29
+ const FRAMETYPE_CONNECTION_CLOSE = 0x08;
30
+ const FRAMETYPE_PING = 0x09;
31
+ const FRAMETYPE_PONG = 0x0A;
32
+
33
+ public function __construct()
34
+ {
35
+ $this->Reset();
36
+ }
37
+
38
+ public function __destruct()
39
+ {
40
+ $this->Disconnect();
41
+ }
42
+
43
+ public function Reset()
44
+ {
45
+ $this->fp = false;
46
+ $this->client = true;
47
+ $this->extensions = array();
48
+ $this->csprng = false;
49
+ $this->state = self::STATE_CONNECTING;
50
+ $this->closemode = self::CLOSE_IMMEDIATELY;
51
+ $this->readdata = "";
52
+ $this->maxreadframesize = 2000000;
53
+ $this->readmessages = array();
54
+ $this->maxreadmessagesize = 10000000;
55
+ $this->writedata = "";
56
+ $this->writemessages = array();
57
+ $this->keepalive = 30;
58
+ $this->lastkeepalive = time();
59
+ $this->keepalivesent = false;
60
+ $this->rawrecvsize = 0;
61
+ $this->rawsendsize = 0;
62
+ }
63
+
64
+ public function SetServerMode()
65
+ {
66
+ $this->client = false;
67
+ }
68
+
69
+ public function SetClientMode()
70
+ {
71
+ $this->client = true;
72
+ }
73
+
74
+ public function SetExtensions($extensions)
75
+ {
76
+ $this->extensions = (array)$extensions;
77
+ }
78
+
79
+ public function SetCloseMode($mode)
80
+ {
81
+ $this->closemode = $mode;
82
+ }
83
+
84
+ public function SetKeepAliveTimeout($keepalive)
85
+ {
86
+ $this->keepalive = (int)$keepalive;
87
+ }
88
+
89
+ public function GetKeepAliveTimeout()
90
+ {
91
+ return $this->keepalive;
92
+ }
93
+
94
+ public function SetMaxReadFrameSize($maxsize)
95
+ {
96
+ $this->maxreadframesize = (is_bool($maxsize) ? false : (int)$maxsize);
97
+ }
98
+
99
+ public function SetMaxReadMessageSize($maxsize)
100
+ {
101
+ $this->maxreadmessagesize = (is_bool($maxsize) ? false : (int)$maxsize);
102
+ }
103
+
104
+ public function GetRawRecvSize()
105
+ {
106
+ return $this->rawrecvsize;
107
+ }
108
+
109
+ public function GetRawSendSize()
110
+ {
111
+ return $this->rawsendsize;
112
+ }
113
+
114
+ public function Connect($url, $origin, $options = array(), $web = false)
115
+ {
116
+ $this->Disconnect();
117
+
118
+ if (class_exists("CSPRNG", false) && $this->csprng === false) $this->csprng = new CSPRNG();
119
+
120
+ if (isset($options["connected_fp"]) && is_resource($options["connected_fp"])) $this->fp = $options["connected_fp"];
121
+ else
122
+ {
123
+ if (!class_exists("WebBrowser", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/web_browser.php";
124
+
125
+ // Use WebBrowser to initiate the connection.
126
+ if ($web === false) $web = new WebBrowser();
127
+
128
+ // Transform URL.
129
+ $url2 = HTTP::ExtractURL($url);
130
+ if ($url2["scheme"] != "ws" && $url2["scheme"] != "wss") return array("success" => false, "error" => self::WSTranslate("WebSocket::Connect() only supports the 'ws' and 'wss' protocols."), "errorcode" => "protocol_check");
131
+ $url2["scheme"] = str_replace("ws", "http", $url2["scheme"]);
132
+ $url2 = HTTP::CondenseURL($url2);
133
+
134
+ // Generate correct request headers.
135
+ if (!isset($options["headers"])) $options["headers"] = array();
136
+ $options["headers"]["Connection"] = "keep-alive, Upgrade";
137
+ if ($origin != "") $options["headers"]["Origin"] = $origin;
138
+ $options["headers"]["Pragma"] = "no-cache";
139
+ $key = base64_encode($this->PRNGBytes(16));
140
+ $options["headers"]["Sec-WebSocket-Key"] = $key;
141
+ $options["headers"]["Sec-WebSocket-Version"] = "13";
142
+ $options["headers"]["Upgrade"] = "websocket";
143
+
144
+ // No async support for connecting at this time. Async mode is enabled AFTER connecting though.
145
+ unset($options["async"]);
146
+
147
+ // Connect to the WebSocket.
148
+ $result = $web->Process($url2, $options);
149
+ if (!$result["success"]) return $result;
150
+ if ($result["response"]["code"] != 101) return array("success" => false, "error" => self::WSTranslate("WebSocket::Connect() failed to connect to the WebSocket. Server returned: %s %s", $result["response"]["code"], $result["response"]["meaning"]), "errorcode" => "incorrect_server_response");
151
+ if (!isset($result["headers"]["Sec-Websocket-Accept"])) return array("success" => false, "error" => self::WSTranslate("Server failed to include a 'Sec-WebSocket-Accept' header in its response to the request."), "errorcode" => "missing_server_websocket_accept_header");
152
+
153
+ // Verify the Sec-WebSocket-Accept response.
154
+ if ($result["headers"]["Sec-Websocket-Accept"][0] !== base64_encode(sha1($key . self::KEY_GUID, true))) return array("success" => false, "error" => self::WSTranslate("The server's 'Sec-WebSocket-Accept' header is invalid."), "errorcode" => "invalid_server_websocket_accept_header");
155
+
156
+ $this->fp = $result["fp"];
157
+ }
158
+
159
+ // Enable non-blocking mode.
160
+ stream_set_blocking($this->fp, 0);
161
+
162
+ $this->state = self::STATE_OPEN;
163
+
164
+ $this->readdata = "";
165
+ $this->readmessages = array();
166
+ $this->writedata = "";
167
+ $this->writemessages = array();
168
+ $this->lastkeepalive = time();
169
+ $this->keepalivesent = false;
170
+ $this->rawrecvsize = 0;
171
+ $this->rawsendsize = 0;
172
+
173
+ return array("success" => true);
174
+ }
175
+
176
+ public function Disconnect()
177
+ {
178
+ if ($this->fp !== false && $this->state === self::STATE_OPEN)
179
+ {
180
+ if ($this->closemode === self::CLOSE_IMMEDIATELY) $this->writemessages = array();
181
+ else if ($this->closemode === self::CLOSE_AFTER_CURRENT_MESSAGE) $this->writemessages = array_slice($this->writemessages, 0, 1);
182
+
183
+ $this->state = self::STATE_CLOSE;
184
+
185
+ $this->Write("", self::FRAMETYPE_CONNECTION_CLOSE, true, $this->client);
186
+
187
+ $this->Wait($this->client ? false : 0);
188
+ }
189
+
190
+ if ($this->fp !== false)
191
+ {
192
+ @fclose($this->fp);
193
+
194
+ $this->fp = false;
195
+ }
196
+
197
+ $this->state = self::STATE_CONNECTING;
198
+ $this->readdata = "";
199
+ $this->readmessages = array();
200
+ $this->writedata = "";
201
+ $this->writemessages = array();
202
+ $this->lastkeepalive = time();
203
+ $this->keepalivesent = false;
204
+ }
205
+
206
+ // Reads the next message or message fragment (depending on $finished). Returns immediately unless $wait is not false.
207
+ public function Read($finished = true, $wait = false)
208
+ {
209
+ if ($this->fp === false || $this->state === self::STATE_CONNECTING) return array("success" => false, "error" => self::WSTranslate("Connection not established."), "errorcode" => "no_connection");
210
+
211
+ if ($wait)
212
+ {
213
+ while (!count($this->readmessages) || ($finished && !$this->readmessages[0]["fin"]))
214
+ {
215
+ $result = $this->Wait();
216
+ if (!$result["success"]) return $result;
217
+ }
218
+ }
219
+
220
+ $data = false;
221
+
222
+ if (count($this->readmessages))
223
+ {
224
+ if ($finished)
225
+ {
226
+ if ($this->readmessages[0]["fin"]) $data = array_shift($this->readmessages);
227
+ }
228
+ else
229
+ {
230
+ $data = $this->readmessages[0];
231
+
232
+ $this->readmessages[0]["payload"] = "";
233
+ }
234
+ }
235
+
236
+ return array("success" => true, "data" => $data);
237
+ }
238
+
239
+ // Adds the message to the write queue. Returns immediately unless $wait is not false.
240
+ public function Write($message, $frametype, $last = true, $wait = false, $pos = false)
241
+ {
242
+ if ($this->fp === false || $this->state === self::STATE_CONNECTING) return array("success" => false, "error" => self::WSTranslate("Connection not established."), "errorcode" => "no_connection");
243
+
244
+ $message = (string)$message;
245
+
246
+ $y = count($this->writemessages);
247
+ $lastcompleted = (!$y || $this->writemessages[$y - 1]["fin"]);
248
+ if ($frametype >= 0x08 || $lastcompleted)
249
+ {
250
+ if ($frametype >= 0x08) $last = true;
251
+ else $pos = false;
252
+
253
+ $frame = array(
254
+ "fin" => (bool)$last,
255
+ "framessent" => 0,
256
+ "opcode" => $frametype,
257
+ "payloads" => array($message)
258
+ );
259
+
260
+ array_splice($this->writemessages, ($pos !== false ? $pos : $y), 0, array($frame));
261
+ }
262
+ else
263
+ {
264
+ if ($frametype !== $this->writemessages[$y - 1]["opcode"]) return array("success" => false, "error" => self::WSTranslate("Mismatched frame type (opcode) specified."), "errorcode" => "mismatched_frame_type");
265
+
266
+ $this->writemessages[$y - 1]["fin"] = (bool)$last;
267
+ $this->writemessages[$y - 1]["payloads"][] = $message;
268
+ }
269
+
270
+ if ($wait)
271
+ {
272
+ while ($this->NeedsWrite())
273
+ {
274
+ $result = $this->Wait();
275
+ if (!$result["success"]) return $result;
276
+ }
277
+ }
278
+
279
+ return array("success" => true);
280
+ }
281
+
282
+ public function NeedsWrite()
283
+ {
284
+ $this->FillWriteData();
285
+
286
+ return ($this->writedata !== "");
287
+ }
288
+
289
+ public function NumWriteMessages()
290
+ {
291
+ return count($this->writemessages);
292
+ }
293
+
294
+ // Dangerous but allows for stream_select() calls on multiple, separate stream handles.
295
+ public function GetStream()
296
+ {
297
+ return $this->fp;
298
+ }
299
+
300
+ // Waits until one or more events time out, handles reading and writing, processes the queues (handle control types automatically), and returns the latest status.
301
+ public function Wait($timeout = false)
302
+ {
303
+ if ($this->fp === false || $this->state === self::STATE_CONNECTING) return array("success" => false, "error" => self::WSTranslate("Connection not established."), "errorcode" => "no_connection");
304
+
305
+ $result = $this->ProcessReadData();
306
+ if (!$result["success"]) return $result;
307
+
308
+ $this->FillWriteData();
309
+
310
+ $readfp = array($this->fp);
311
+ $writefp = ($this->writedata !== "" ? array($this->fp) : NULL);
312
+ $exceptfp = NULL;
313
+ if ($timeout === false || $timeout > $this->keepalive) $timeout = $this->keepalive;
314
+ $result = @stream_select($readfp, $writefp, $exceptfp, $timeout);
315
+ if ($result === false) return array("success" => false, "error" => self::WSTranslate("Wait() failed due to stream_select() failure. Most likely cause: Connection failure."), "errorcode" => "stream_select_failed");
316
+
317
+ // Process queues and timeouts.
318
+ $result = $this->ProcessQueuesAndTimeoutState(($result > 0 && count($readfp)), ($result > 0 && $writefp !== NULL && count($writefp)));
319
+
320
+ return $result;
321
+ }
322
+
323
+ // A mostly internal function. Useful for managing multiple simultaneous WebSocket connections.
324
+ public function ProcessQueuesAndTimeoutState($read, $write, $readsize = 65536)
325
+ {
326
+ if ($this->fp === false || $this->state === self::STATE_CONNECTING) return array("success" => false, "error" => self::WSTranslate("Connection not established."), "errorcode" => "no_connection");
327
+
328
+ if ($read)
329
+ {
330
+ $result = @fread($this->fp, $readsize);
331
+ if ($result === false || ($result === "" && feof($this->fp))) return array("success" => false, "error" => self::WSTranslate("ProcessQueuesAndTimeoutState() failed due to fread() failure. Most likely cause: Connection failure."), "errorcode" => "fread_failed");
332
+
333
+ if ($result !== "")
334
+ {
335
+ $this->rawrecvsize += strlen($result);
336
+ $this->readdata .= $result;
337
+
338
+ if ($this->maxreadframesize !== false && strlen($this->readdata) > $this->maxreadframesize) return array("success" => false, "error" => self::WSTranslate("ProcessQueuesAndTimeoutState() failed due to peer sending a single frame exceeding %s bytes of data.", $this->maxreadframesize), "errorcode" => "max_read_frame_size_exceeded");
339
+
340
+ $result = $this->ProcessReadData();
341
+ if (!$result["success"]) return $result;
342
+
343
+ $this->lastkeepalive = time();
344
+ $this->keepalivesent = false;
345
+ }
346
+ }
347
+
348
+ if ($write)
349
+ {
350
+ $result = @fwrite($this->fp, $this->writedata);
351
+ if ($result === false || ($this->writedata === "" && feof($this->fp))) return array("success" => false, "error" => self::WSTranslate("ProcessQueuesAndTimeoutState() failed due to fwrite() failure. Most likely cause: Connection failure."), "errorcode" => "fwrite_failed");
352
+
353
+ if ($result)
354
+ {
355
+ $this->rawsendsize += $result;
356
+ $this->writedata = (string)substr($this->writedata, $result);
357
+
358
+ $this->lastkeepalive = time();
359
+ $this->keepalivesent = false;
360
+ }
361
+ }
362
+
363
+ // Handle timeout state.
364
+ if ($this->lastkeepalive < time() - $this->keepalive)
365
+ {
366
+ if ($this->keepalivesent) return array("success" => false, "error" => self::WSTranslate("ProcessQueuesAndTimeoutState() failed due to non-response from peer to ping frame. Most likely cause: Connection failure."), "errorcode" => "ping_failed");
367
+ else
368
+ {
369
+ $result = $this->Write(time(), self::FRAMETYPE_PING, true, false, 0);
370
+ if (!$result["success"]) return $result;
371
+
372
+ $this->lastkeepalive = time();
373
+ $this->keepalivesent = true;
374
+ }
375
+ }
376
+
377
+ return array("success" => true);
378
+ }
379
+
380
+ protected function ProcessReadData()
381
+ {
382
+ while (($frame = $this->ReadFrame()) !== false)
383
+ {
384
+ // Verify that the opcode is probably valid.
385
+ if (($frame["opcode"] >= 0x03 && $frame["opcode"] <= 0x07) || $frame["opcode"] >= 0x0B) return array("success" => false, "error" => self::WSTranslate("Invalid frame detected. Bad opcode 0x%02X.", $frame["opcode"]), "errorcode" => "bad_frame_opcode");
386
+
387
+ // No extension support (yet).
388
+ if ($frame["rsv1"] || $frame["rsv2"] || $frame["rsv3"]) return array("success" => false, "error" => self::WSTranslate("Invalid frame detected. One or more reserved extension bits are set."), "errorcode" => "bad_reserved_bits_set");
389
+
390
+ if ($frame["opcode"] >= 0x08)
391
+ {
392
+ // Handle the control frame.
393
+ if (!$frame["fin"]) return array("success" => false, "error" => self::WSTranslate("Invalid frame detected. Fragmented control frame was received."), "errorcode" => "bad_control_frame");
394
+
395
+ if ($frame["opcode"] === self::FRAMETYPE_CONNECTION_CLOSE)
396
+ {
397
+ if ($this->state === self::STATE_CLOSE)
398
+ {
399
+ // Already sent the close state.
400
+ @fclose($this->fp);
401
+ $this->fp = false;
402
+
403
+ return array("success" => false, "error" => self::WSTranslate("Connection closed by peer."), "errorcode" => "connection_closed");
404
+ }
405
+ else
406
+ {
407
+ // Change the state to close and send the connection close response to the peer at the appropriate time.
408
+ if ($this->closemode === self::CLOSE_IMMEDIATELY) $this->writemessages = array();
409
+ else if ($this->closemode === self::CLOSE_AFTER_CURRENT_MESSAGE) $this->writemessages = array_slice($this->writemessages, 0, 1);
410
+
411
+ $this->state = self::STATE_CLOSE;
412
+
413
+ $result = $this->Write("", self::FRAMETYPE_CONNECTION_CLOSE);
414
+ if (!$result["success"]) return $result;
415
+ }
416
+ }
417
+ else if ($frame["opcode"] === self::FRAMETYPE_PING)
418
+ {
419
+ if ($this->state !== self::STATE_CLOSE)
420
+ {
421
+ // Received a ping. Respond with a pong with the same payload.
422
+ $result = $this->Write($frame["payload"], self::FRAMETYPE_PONG, true, false, 0);
423
+ if (!$result["success"]) return $result;
424
+ }
425
+ }
426
+ else if ($frame["opcode"] === self::FRAMETYPE_PONG)
427
+ {
428
+ // Do nothing.
429
+ }
430
+ }
431
+ else
432
+ {
433
+ // Add this frame to the read message queue.
434
+ $lastcompleted = (!count($this->readmessages) || $this->readmessages[count($this->readmessages) - 1]["fin"]);
435
+ if ($lastcompleted)
436
+ {
437
+ // Make sure the new frame is the start of a fragment or is not fragemented.
438
+ if ($frame["opcode"] === self::FRAMETYPE_CONTINUATION) return array("success" => false, "error" => self::WSTranslate("Invalid frame detected. Fragment continuation frame was received at the start of a fragment."), "errorcode" => "bad_continuation_frame");
439
+
440
+ $this->readmessages[] = $frame;
441
+ }
442
+ else
443
+ {
444
+ // Make sure the frame is a continuation frame.
445
+ if ($frame["opcode"] !== self::FRAMETYPE_CONTINUATION) return array("success" => false, "error" => self::WSTranslate("Invalid frame detected. Fragment continuation frame was not received for a fragment."), "errorcode" => "missing_continuation_frame");
446
+
447
+ $this->readmessages[count($this->readmessages) - 1]["fin"] = $frame["fin"];
448
+ $this->readmessages[count($this->readmessages) - 1]["payload"] .= $frame["payload"];
449
+ }
450
+
451
+ if ($this->maxreadmessagesize !== false && strlen($this->readmessages[count($this->readmessages) - 1]["payload"]) > $this->maxreadmessagesize) return array("success" => false, "error" => self::WSTranslate("Peer sent a single message exceeding %s bytes of data.", $this->maxreadmessagesize), "errorcode" => "max_read_message_size_exceeded");
452
+ }
453
+
454
+ //var_dump($frame);
455
+ }
456
+
457
+ return array("success" => true);
458
+ }
459
+
460
+ // Parses the current input data to see if there is enough information to extract a single frame.
461
+ // Does not do any error checking beyond loading the frame and decoding any masked data.
462
+ protected function ReadFrame()
463
+ {
464
+ if (strlen($this->readdata) < 2) return false;
465
+
466
+ $chr = ord($this->readdata{0});
467
+ $fin = (($chr & 0x80) ? true : false);
468
+ $rsv1 = (($chr & 0x40) ? true : false);
469
+ $rsv2 = (($chr & 0x20) ? true : false);
470
+ $rsv3 = (($chr & 0x10) ? true : false);
471
+ $opcode = $chr & 0x0F;
472
+
473
+ $chr = ord($this->readdata{1});
474
+ $mask = (($chr & 0x80) ? true : false);
475
+ $length = $chr & 0x7F;
476
+ if ($length == 126) $start = 4;
477
+ else if ($length == 127) $start = 10;
478
+ else $start = 2;
479
+
480
+ if (strlen($this->readdata) < $start + ($mask ? 4 : 0)) return false;
481
+
482
+ // Frame minus payload calculated.
483
+ if ($length == 126) $length = self::UnpackInt(substr($this->readdata, 2, 2));
484
+ else if ($length == 127) $length = self::UnpackInt(substr($this->readdata, 2, 8));
485
+
486
+ if ($mask)
487
+ {
488
+ $maskingkey = substr($this->readdata, $start, 4);
489
+ $start += 4;
490
+ }
491
+
492
+ if (strlen($this->readdata) < $start + $length) return false;
493
+
494
+ $payload = substr($this->readdata, $start, $length);
495
+
496
+ $this->readdata = substr($this->readdata, $start + $length);
497
+
498
+ if ($mask)
499
+ {
500
+ // Decode the payload.
501
+ for ($x = 0; $x < $length; $x++)
502
+ {
503
+ $payload{$x} = chr(ord($payload{$x}) ^ ord($maskingkey{$x % 4}));
504
+ }
505
+ }
506
+
507
+ $result = array(
508
+ "fin" => $fin,
509
+ "rsv1" => $rsv1,
510
+ "rsv2" => $rsv2,
511
+ "rsv3" => $rsv3,
512
+ "opcode" => $opcode,
513
+ "mask" => $mask,
514
+ "payload" => $payload
515
+ );
516
+
517
+ return $result;
518
+ }
519
+
520
+ // Converts messages in the queue to a data stream of frames.
521
+ protected function FillWriteData()
522
+ {
523
+ while (strlen($this->writedata) < 65536 && count($this->writemessages) && count($this->writemessages[0]["payloads"]))
524
+ {
525
+ $payload = array_shift($this->writemessages[0]["payloads"]);
526
+
527
+ $fin = ($this->writemessages[0]["fin"] && !count($this->writemessages[0]["payloads"]));
528
+
529
+ if ($this->writemessages[0]["framessent"] === 0) $opcode = $this->writemessages[0]["opcode"];
530
+ else $opcode = self::FRAMETYPE_CONTINUATION;
531
+
532
+ $this->WriteFrame($fin, $opcode, $payload);
533
+
534
+ $this->writemessages[0]["framessent"]++;
535
+
536
+ if ($fin) array_shift($this->writemessages);
537
+ }
538
+ }
539
+
540
+ // Generates the actual frame data to be sent.
541
+ protected function WriteFrame($fin, $opcode, $payload)
542
+ {
543
+ $rsv1 = false;
544
+ $rsv2 = false;
545
+ $rsv3 = false;
546
+ $mask = $this->client;
547
+
548
+ $data = chr(($fin ? 0x80 : 0x00) | ($rsv1 ? 0x40 : 0x00) | ($rsv2 ? 0x20 : 0x00) | ($rsv3 ? 0x10 : 0x00) | ($opcode & 0x0F));
549
+
550
+ if (strlen($payload) < 126) $length = strlen($payload);
551
+ else if (strlen($payload) < 65536) $length = 126;
552
+ else $length = 127;
553
+
554
+ $data .= chr(($mask ? 0x80 : 0x00) | ($length & 0x7F));
555
+
556
+ if ($length === 126) $data .= pack("n", strlen($payload));
557
+ else if ($length === 127) $data .= self::PackInt64(strlen($payload));
558
+
559
+ if ($mask)
560
+ {
561
+ $maskingkey = $this->PRNGBytes(4);
562
+ $data .= $maskingkey;
563
+
564
+ // Encode the payload.
565
+ $y = strlen($payload);
566
+ for ($x = 0; $x < $y; $x++)
567
+ {
568
+ $payload{$x} = chr(ord($payload{$x}) ^ ord($maskingkey{$x % 4}));
569
+ }
570
+ }
571
+
572
+ $data .= $payload;
573
+
574
+ $this->writedata .= $data;
575
+ }
576
+
577
+ // This function follows the specification IF CSPRNG is available, but it isn't necessary to do so.
578
+ protected function PRNGBytes($length)
579
+ {
580
+ if ($this->csprng !== false) $result = $this->csprng->GetBytes($length);
581
+ else
582
+ {
583
+ $result = "";
584
+ while (strlen($result) < $length) $result .= chr(mt_rand(0, 255));
585
+ }
586
+
587
+ return $result;
588
+ }
589
+
590
+ public static function UnpackInt($data)
591
+ {
592
+ if ($data === false) return false;
593
+
594
+ if (strlen($data) == 2) $result = unpack("n", $data);
595
+ else if (strlen($data) == 4) $result = unpack("N", $data);
596
+ else if (strlen($data) == 8)
597
+ {
598
+ $result = 0;
599
+ for ($x = 0; $x < 8; $x++)
600
+ {
601
+ $result = ($result * 256) + ord($data{$x});
602
+ }
603
+
604
+ return $result;
605
+ }
606
+ else return false;
607
+
608
+ return $result[1];
609
+ }
610
+
611
+ public static function PackInt64($num)
612
+ {
613
+ $result = "";
614
+
615
+ if (is_int(2147483648)) $floatlim = 9223372036854775808;
616
+ else $floatlim = 2147483648;
617
+
618
+ if (is_float($num))
619
+ {
620
+ $num = floor($num);
621
+ if ($num < (double)$floatlim) $num = (int)$num;
622
+ }
623
+
624
+ while (is_float($num))
625
+ {
626
+ $byte = (int)fmod($num, 256);
627
+ $result = chr($byte) . $result;
628
+
629
+ $num = floor($num / 256);
630
+ if (is_float($num) && $num < (double)$floatlim) $num = (int)$num;
631
+ }
632
+
633
+ while ($num > 0)
634
+ {
635
+ $byte = $num & 0xFF;
636
+ $result = chr($byte) . $result;
637
+ $num = $num >> 8;
638
+ }
639
+
640
+ $result = str_pad($result, 8, "\x00", STR_PAD_LEFT);
641
+ $result = substr($result, -8);
642
+
643
+ return $result;
644
+ }
645
+
646
+ public static function WSTranslate()
647
+ {
648
+ $args = func_get_args();
649
+ if (!count($args)) return "";
650
+
651
+ return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args);
652
+ }
653
+ }
654
+ ?>
vendor/icomoon/fonts/ez-toc-icomoon.woff2 ADDED
Binary file
vendor/icomoon/style.css CHANGED
@@ -1,10 +1,12 @@
1
  @font-face {
 
2
  font-family: 'ez-toc-icomoon';
3
- src:url('fonts/ez-toc-icomoon.eot?-5j7dhv');
4
- src:url('fonts/ez-toc-icomoon.eot?#iefix-5j7dhv') format('embedded-opentype'),
5
- url('fonts/ez-toc-icomoon.ttf?-5j7dhv') format('truetype'),
6
- url('fonts/ez-toc-icomoon.woff?-5j7dhv') format('woff'),
7
- url('fonts/ez-toc-icomoon.svg?-5j7dhv#ez-toc-icomoon') format('svg');
 
8
  font-weight: normal;
9
  font-style: normal;
10
  }
1
  @font-face {
2
+ font-display: swap;
3
  font-family: 'ez-toc-icomoon';
4
+ src:url('fonts/ez-toc-icomoon.eot');
5
+ src:url('fonts/ez-toc-icomoon.eot?#iefix') format('embedded-opentype'),
6
+ url('fonts/ez-toc-icomoon.woff2') format('woff2'),
7
+ url('fonts/ez-toc-icomoon.woff') format('woff'),
8
+ url('fonts/ez-toc-icomoon.ttf') format('truetype'),
9
+ url('fonts/ez-toc-icomoon.svg#ez-toc-icomoon') format('svg');
10
  font-weight: normal;
11
  font-style: normal;
12
  }
vendor/js-cookie/js.cookie.js CHANGED
@@ -1,20 +1,25 @@
1
  /*!
2
- * JavaScript Cookie v2.0.3
3
  * https://github.com/js-cookie/js-cookie
4
  *
5
  * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
  * Released under the MIT license
7
  */
8
- (function (factory) {
 
9
  if (typeof define === 'function' && define.amd) {
10
  define(factory);
11
- } else if (typeof exports === 'object') {
 
 
12
  module.exports = factory();
13
- } else {
14
- var _OldCookies = window.Cookies;
 
 
15
  var api = window.Cookies = factory();
16
  api.noConflict = function () {
17
- window.Cookies = _OldCookies;
18
  return api;
19
  };
20
  }
@@ -31,109 +36,128 @@
31
  return result;
32
  }
33
 
 
 
 
 
34
  function init (converter) {
35
- function api (key, value, attributes) {
36
- var result;
37
 
38
- // Write
 
 
 
39
 
40
- if (arguments.length > 1) {
41
- attributes = extend({
42
- path: '/'
43
- }, api.defaults, attributes);
44
 
45
- if (typeof attributes.expires === 'number') {
46
- var expires = new Date();
47
- expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
48
- attributes.expires = expires;
 
 
 
 
 
 
 
49
  }
 
50
 
51
- try {
52
- result = JSON.stringify(value);
53
- if (/^[\{\[]/.test(result)) {
54
- value = result;
55
- }
56
- } catch (e) {}
57
 
58
- value = encodeURIComponent(String(value));
59
- value = value.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
 
60
 
61
- key = encodeURIComponent(String(key));
62
- key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
63
- key = key.replace(/[\(\)]/g, escape);
 
 
 
 
 
 
64
 
65
- return (document.cookie = [
66
- key, '=', value,
67
- attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
68
- attributes.path && '; path=' + attributes.path,
69
- attributes.domain && '; domain=' + attributes.domain,
70
- attributes.secure ? '; secure' : ''
71
- ].join(''));
 
72
  }
73
 
74
- // Read
 
75
 
76
- if (!key) {
77
- result = {};
 
78
  }
79
 
 
80
  // To prevent the for loop in the first place assign an empty array
81
- // in case there are no cookies at all. Also prevents odd result when
82
- // calling "get()"
83
  var cookies = document.cookie ? document.cookie.split('; ') : [];
84
- var rdecode = /(%[0-9A-Z]{2})+/g;
85
  var i = 0;
86
 
87
  for (; i < cookies.length; i++) {
88
  var parts = cookies[i].split('=');
89
- var name = parts[0].replace(rdecode, decodeURIComponent);
90
  var cookie = parts.slice(1).join('=');
91
 
92
- if (cookie.charAt(0) === '"') {
93
  cookie = cookie.slice(1, -1);
94
  }
95
 
96
  try {
97
- cookie = converter && converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent);
 
 
98
 
99
- if (this.json) {
100
  try {
101
  cookie = JSON.parse(cookie);
102
  } catch (e) {}
103
  }
104
 
 
 
105
  if (key === name) {
106
- result = cookie;
107
  break;
108
  }
109
-
110
- if (!key) {
111
- result[name] = cookie;
112
- }
113
  } catch (e) {}
114
  }
115
 
116
- return result;
117
  }
118
 
119
- api.get = api.set = api;
120
- api.getJSON = function () {
121
- return api.apply({
122
- json: true
123
- }, [].slice.call(arguments));
 
124
  };
125
- api.defaults = {};
126
-
127
  api.remove = function (key, attributes) {
128
- api(key, '', extend(attributes, {
129
  expires: -1
130
  }));
131
  };
132
 
 
 
133
  api.withConverter = init;
134
 
135
  return api;
136
  }
137
 
138
- return init();
139
  }));
1
  /*!
2
+ * JavaScript Cookie v2.2.1
3
  * https://github.com/js-cookie/js-cookie
4
  *
5
  * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
  * Released under the MIT license
7
  */
8
+ ;(function (factory) {
9
+ var registeredInModuleLoader;
10
  if (typeof define === 'function' && define.amd) {
11
  define(factory);
12
+ registeredInModuleLoader = true;
13
+ }
14
+ if (typeof exports === 'object') {
15
  module.exports = factory();
16
+ registeredInModuleLoader = true;
17
+ }
18
+ if (!registeredInModuleLoader) {
19
+ var OldCookies = window.Cookies;
20
  var api = window.Cookies = factory();
21
  api.noConflict = function () {
22
+ window.Cookies = OldCookies;
23
  return api;
24
  };
25
  }
36
  return result;
37
  }
38
 
39
+ function decode (s) {
40
+ return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
41
+ }
42
+
43
  function init (converter) {
44
+ function api() {}
 
45
 
46
+ function set (key, value, attributes) {
47
+ if (typeof document === 'undefined') {
48
+ return;
49
+ }
50
 
51
+ attributes = extend({
52
+ path: '/'
53
+ }, api.defaults, attributes);
 
54
 
55
+ if (typeof attributes.expires === 'number') {
56
+ attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
57
+ }
58
+
59
+ // We're using "expires" because "max-age" is not supported by IE
60
+ attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
61
+
62
+ try {
63
+ var result = JSON.stringify(value);
64
+ if (/^[\{\[]/.test(result)) {
65
+ value = result;
66
  }
67
+ } catch (e) {}
68
 
69
+ value = converter.write ?
70
+ converter.write(value, key) :
71
+ encodeURIComponent(String(value))
72
+ .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
 
 
73
 
74
+ key = encodeURIComponent(String(key))
75
+ .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
76
+ .replace(/[\(\)]/g, escape);
77
 
78
+ var stringifiedAttributes = '';
79
+ for (var attributeName in attributes) {
80
+ if (!attributes[attributeName]) {
81
+ continue;
82
+ }
83
+ stringifiedAttributes += '; ' + attributeName;
84
+ if (attributes[attributeName] === true) {
85
+ continue;
86
+ }
87
 
88
+ // Considers RFC 6265 section 5.2:
89
+ // ...
90
+ // 3. If the remaining unparsed-attributes contains a %x3B (";")
91
+ // character:
92
+ // Consume the characters of the unparsed-attributes up to,
93
+ // not including, the first %x3B (";") character.
94
+ // ...
95
+ stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
96
  }
97
 
98
+ return (document.cookie = key + '=' + value + stringifiedAttributes);
99
+ }
100
 
101
+ function get (key, json) {
102
+ if (typeof document === 'undefined') {
103
+ return;
104
  }
105
 
106
+ var jar = {};
107
  // To prevent the for loop in the first place assign an empty array
108
+ // in case there are no cookies at all.
 
109
  var cookies = document.cookie ? document.cookie.split('; ') : [];
 
110
  var i = 0;
111
 
112
  for (; i < cookies.length; i++) {
113
  var parts = cookies[i].split('=');
 
114
  var cookie = parts.slice(1).join('=');
115
 
116
+ if (!json && cookie.charAt(0) === '"') {
117
  cookie = cookie.slice(1, -1);
118
  }
119
 
120
  try {
121
+ var name = decode(parts[0]);
122
+ cookie = (converter.read || converter)(cookie, name) ||
123
+ decode(cookie);
124
 
125
+ if (json) {
126
  try {
127
  cookie = JSON.parse(cookie);
128
  } catch (e) {}
129
  }
130
 
131
+ jar[name] = cookie;
132
+
133
  if (key === name) {
 
134
  break;
135
  }
 
 
 
 
136
  } catch (e) {}
137
  }
138
 
139
+ return key ? jar[key] : jar;
140
  }
141
 
142
+ api.set = set;
143
+ api.get = function (key) {
144
+ return get(key, false /* read as raw */);
145
+ };
146
+ api.getJSON = function (key) {
147
+ return get(key, true /* read as json */);
148
  };
 
 
149
  api.remove = function (key, attributes) {
150
+ set(key, '', extend(attributes, {
151
  expires: -1
152
  }));
153
  };
154
 
155
+ api.defaults = {};
156
+
157
  api.withConverter = init;
158
 
159
  return api;
160
  }
161
 
162
+ return init(function () {});
163
  }));
vendor/js-cookie/js.cookie.min.js CHANGED
@@ -1,2 +1,8 @@
1
- /*! js-cookie v2.0.3 | MIT */
2
- !function(a){if("function"==typeof define&&define.amd)define(a);else if("object"==typeof exports)module.exports=a();else{var b=window.Cookies,c=window.Cookies=a(window.jQuery);c.noConflict=function(){return window.Cookies=b,c}}}(function(){function a(){for(var a=0,b={};a<arguments.length;a++){var c=arguments[a];for(var d in c)b[d]=c[d]}return b}function b(c){function d(b,e,f){var g;if(arguments.length>1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(i){}return e=encodeURIComponent(String(e)),e=e.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(String(b)),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape),document.cookie=[b,"=",e,f.expires&&"; expires="+f.expires.toUTCString(),f.path&&"; path="+f.path,f.domain&&"; domain="+f.domain,f.secure?"; secure":""].join("")}b||(g={});for(var j=document.cookie?document.cookie.split("; "):[],k=/(%[0-9A-Z]{2})+/g,l=0;l<j.length;l++){var m=j[l].split("="),n=m[0].replace(k,decodeURIComponent),o=m.slice(1).join("=");'"'===o.charAt(0)&&(o=o.slice(1,-1));try{if(o=c&&c(o,n)||o.replace(k,decodeURIComponent),this.json)try{o=JSON.parse(o)}catch(i){}if(b===n){g=o;break}b||(g[n]=o)}catch(i){}}return g}return d.get=d.set=d,d.getJSON=function(){return d.apply({json:!0},[].slice.call(arguments))},d.defaults={},d.remove=function(b,c){d(b,"",a(c,{expires:-1}))},d.withConverter=b,d}return b()});
 
 
 
 
 
 
1
+ /*!
2
+ * JavaScript Cookie v2.2.1
3
+ * https://github.com/js-cookie/js-cookie
4
+ *
5
+ * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
+ * Released under the MIT license
7
+ */
8
+ !function(factory){var registeredInModuleLoader;if("function"==typeof define&&define.amd&&(define(factory),registeredInModuleLoader=!0),"object"==typeof exports&&(module.exports=factory(),registeredInModuleLoader=!0),!registeredInModuleLoader){var OldCookies=window.Cookies,api=window.Cookies=factory();api.noConflict=function(){return window.Cookies=OldCookies,api}}}((function(){function extend(){for(var i=0,result={};i<arguments.length;i++){var attributes=arguments[i];for(var key in attributes)result[key]=attributes[key]}return result}function decode(s){return s.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)}function init(converter){function api(){}function set(key,value,attributes){if("undefined"!=typeof document){"number"==typeof(attributes=extend({path:"/"},api.defaults,attributes)).expires&&(attributes.expires=new Date(1*new Date+864e5*attributes.expires)),attributes.expires=attributes.expires?attributes.expires.toUTCString():"";try{var result=JSON.stringify(value);/^[\{\[]/.test(result)&&(value=result)}catch(e){}value=converter.write?converter.write(value,key):encodeURIComponent(String(value)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),key=encodeURIComponent(String(key)).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var stringifiedAttributes="";for(var attributeName in attributes)attributes[attributeName]&&(stringifiedAttributes+="; "+attributeName,!0!==attributes[attributeName]&&(stringifiedAttributes+="="+attributes[attributeName].split(";")[0]));return document.cookie=key+"="+value+stringifiedAttributes}}function get(key,json){if("undefined"!=typeof document){for(var jar={},cookies=document.cookie?document.cookie.split("; "):[],i=0;i<cookies.length;i++){var parts=cookies[i].split("="),cookie=parts.slice(1).join("=");json||'"'!==cookie.charAt(0)||(cookie=cookie.slice(1,-1));try{var name=decode(parts[0]);if(cookie=(converter.read||converter)(cookie,name)||decode(cookie),json)try{cookie=JSON.parse(cookie)}catch(e){}if(jar[name]=cookie,key===name)break}catch(e){}}return key?jar[key]:jar}}return api.set=set,api.get=function(key){return get(key,!1)},api.getJSON=function(key){return get(key,!0)},api.remove=function(key,attributes){set(key,"",extend(attributes,{expires:-1}))},api.defaults={},api.withConverter=init,api}return init((function(){}))}));
vendor/smooth-scroll/jquery.smooth-scroll.js CHANGED
@@ -1,144 +1,170 @@
1
- /*!
2
- * jQuery Smooth Scroll - v1.5.5 - 2015-02-19
3
- * https://github.com/kswedberg/jquery-smooth-scroll
4
- * Copyright (c) 2015 Karl Swedberg
5
- * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT)
6
- */
7
-
8
- (function (factory) {
9
- if (typeof define === 'function' && define.amd) {
10
- // AMD. Register as an anonymous module.
11
- define(['jquery'], factory);
12
- } else if (typeof module === 'object' && module.exports) {
13
- // CommonJS
14
- factory(require('jquery'));
15
- } else {
16
- // Browser globals
17
- factory(jQuery);
18
- }
19
- }(function ($) {
20
-
21
- var version = '1.5.5',
22
- optionOverrides = {},
23
- defaults = {
24
- exclude: [],
25
- excludeWithin:[],
26
- offset: 0,
27
-
28
- // one of 'top' or 'left'
29
- direction: 'top',
30
-
31
- // jQuery set of elements you wish to scroll (for $.smoothScroll).
32
- // if null (default), $('html, body').firstScrollable() is used.
33
- scrollElement: null,
34
-
35
- // only use if you want to override default behavior
36
- scrollTarget: null,
37
-
38
- // fn(opts) function to be called before scrolling occurs.
39
- // `this` is the element(s) being scrolled
40
- beforeScroll: function() {},
41
-
42
- // fn(opts) function to be called after scrolling occurs.
43
- // `this` is the triggering element
44
- afterScroll: function() {},
45
- easing: 'swing',
46
- speed: 400,
47
-
48
- // coefficient for "auto" speed
49
- autoCoefficient: 2,
50
-
51
- // $.fn.smoothScroll only: whether to prevent the default click action
52
- preventDefault: true
53
- },
54
-
55
- getScrollable = function(opts) {
56
- var scrollable = [],
57
- scrolled = false,
58
- dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
59
-
60
- this.each(function() {
61
-
62
- if (this === document || this === window) { return; }
63
- var el = $(this);
64
- if ( el[dir]() > 0 ) {
65
- scrollable.push(this);
66
- } else {
67
- // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
68
- el[dir](1);
69
- scrolled = el[dir]() > 0;
70
- if ( scrolled ) {
71
- scrollable.push(this);
72
- }
73
- // then put it back, of course
74
- el[dir](0);
75
- }
76
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- // If no scrollable elements, fall back to <body>,
79
  // if it's in the jQuery collection
80
  // (doing this because Safari sets scrollTop async,
81
  // so can't set it to 1 and immediately get the value.)
82
- if (!scrollable.length) {
83
- this.each(function() {
84
- if (this.nodeName === 'BODY') {
85
- scrollable = [this];
86
- }
87
- });
88
  }
 
 
89
 
90
- // Use the first scrollable element if we're calling firstScrollable()
91
- if ( opts.el === 'first' && scrollable.length > 1 ) {
92
- scrollable = [ scrollable[0] ];
93
- }
94
 
95
- return scrollable;
96
- };
 
 
97
 
98
  $.fn.extend({
99
  scrollable: function(dir) {
100
  var scrl = getScrollable.call(this, {dir: dir});
 
101
  return this.pushStack(scrl);
102
  },
103
  firstScrollable: function(dir) {
104
  var scrl = getScrollable.call(this, {el: 'first', dir: dir});
 
105
  return this.pushStack(scrl);
106
  },
107
 
108
  smoothScroll: function(options, extra) {
109
  options = options || {};
110
 
111
- if ( options === 'options' ) {
112
- if ( !extra ) {
113
  return this.first().data('ssOpts');
114
  }
 
115
  return this.each(function() {
116
- var $this = $(this),
117
- opts = $.extend($this.data('ssOpts') || {}, extra);
118
 
119
  $(this).data('ssOpts', opts);
120
  });
121
  }
122
 
123
- var opts = $.extend({}, $.fn.smoothScroll.defaults, options),
124
- locationPath = $.smoothScroll.filterPath(location.pathname);
125
-
126
- this
127
- .unbind('click.smoothscroll')
128
- .bind('click.smoothscroll', function(event) {
129
- var link = this,
130
- $link = $(this),
131
- thisOpts = $.extend({}, opts, $link.data('ssOpts') || {}),
132
- exclude = opts.exclude,
133
- excludeWithin = thisOpts.excludeWithin,
134
- elCounter = 0, ewlCounter = 0,
135
- include = true,
136
- clickOpts = {},
137
- hostMatch = ((location.hostname === link.hostname) || !link.hostname),
138
- pathMatch = thisOpts.scrollTarget || ( $.smoothScroll.filterPath(link.pathname) === locationPath ),
139
- thisHash = escapeSelector(link.hash);
140
-
141
- if ( !thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash) ) {
 
 
 
 
 
 
 
 
142
  include = false;
143
  } else {
144
  while (include && elCounter < exclude.length) {
@@ -146,61 +172,108 @@
146
  include = false;
147
  }
148
  }
149
- while ( include && ewlCounter < excludeWithin.length ) {
 
150
  if ($link.closest(excludeWithin[ewlCounter++]).length) {
151
  include = false;
152
  }
153
  }
154
  }
155
 
156
- if ( include ) {
157
-
158
- if ( thisOpts.preventDefault ) {
159
  event.preventDefault();
160
  }
161
 
162
- $.extend( clickOpts, thisOpts, {
163
  scrollTarget: thisOpts.scrollTarget || thisHash,
164
  link: link
165
  });
166
 
167
- $.smoothScroll( clickOpts );
168
  }
169
- });
 
 
 
 
 
 
 
 
 
 
170
 
171
  return this;
172
  }
173
  });
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  $.smoothScroll = function(options, px) {
176
- if ( options === 'options' && typeof px === 'object' ) {
177
  return $.extend(optionOverrides, px);
178
  }
179
- var opts, $scroller, scrollTargetOffset, speed, delta,
180
- scrollerOffset = 0,
181
- offPos = 'offset',
182
- scrollDir = 'scrollTop',
183
- aniProps = {},
184
- aniOpts = {};
185
-
186
- if (typeof options === 'number') {
 
 
187
  opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
188
- scrollTargetOffset = options;
189
  } else {
190
  opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
 
191
  if (opts.scrollElement) {
192
  offPos = 'position';
 
193
  if (opts.scrollElement.css('position') === 'static') {
194
  opts.scrollElement.css('position', 'relative');
195
  }
196
  }
 
 
 
 
197
  }
198
 
199
  scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
200
 
201
- if ( opts.scrollElement ) {
202
  $scroller = opts.scrollElement;
203
- if ( !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName) ) {
 
204
  scrollerOffset = $scroller[scrollDir]();
205
  }
206
  } else {
@@ -210,24 +283,21 @@
210
  // beforeScroll callback function must fire before calculating offset
211
  opts.beforeScroll.call($scroller, opts);
212
 
213
- scrollTargetOffset = (typeof options === 'number') ? options :
214
- px ||
215
- ( $(opts.scrollTarget)[offPos]() &&
216
- $(opts.scrollTarget)[offPos]()[opts.direction] ) ||
217
- 0;
 
218
 
219
- aniProps[scrollDir] = scrollTargetOffset + scrollerOffset + opts.offset;
220
  speed = opts.speed;
221
 
222
  // automatically calculate the speed of the scroll based on distance / coefficient
223
  if (speed === 'auto') {
224
 
225
- // $scroller.scrollTop() is position before scroll, aniProps[scrollDir] is position after
226
  // When delta is greater, speed will be greater.
227
- delta = aniProps[scrollDir] - $scroller.scrollTop();
228
- if(delta < 0) {
229
- delta *= -1;
230
- }
231
 
232
  // Divide the delta by the coefficient
233
  speed = delta / opts.autoCoefficient;
@@ -237,7 +307,7 @@
237
  duration: speed,
238
  easing: opts.easing,
239
  complete: function() {
240
- opts.afterScroll.call(opts.link, opts);
241
  }
242
  };
243
 
@@ -248,25 +318,21 @@
248
  if ($scroller.length) {
249
  $scroller.stop().animate(aniProps, aniOpts);
250
  } else {
251
- opts.afterScroll.call(opts.link, opts);
252
  }
253
  };
254
 
255
  $.smoothScroll.version = version;
256
  $.smoothScroll.filterPath = function(string) {
257
  string = string || '';
 
258
  return string
259
- .replace(/^\//,'')
260
- .replace(/(?:index|default).[a-zA-Z]{3,4}$/,'')
261
- .replace(/\/$/,'');
262
  };
263
 
264
  // default options
265
  $.fn.smoothScroll.defaults = defaults;
266
 
267
- function escapeSelector (str) {
268
- return str.replace(/(:|\.|\/)/g,'\\$1');
269
- }
270
-
271
- }));
272
-
1
+ (function($) {
2
+ var version = '2.2.0';
3
+ var optionOverrides = {};
4
+ var defaults = {
5
+ exclude: [],
6
+ excludeWithin: [],
7
+ offset: 0,
8
+
9
+ // one of 'top' or 'left'
10
+ direction: 'top',
11
+
12
+ // if set, bind click events through delegation
13
+ // supported since jQuery 1.4.2
14
+ delegateSelector: null,
15
+
16
+ // jQuery set of elements you wish to scroll (for $.smoothScroll).
17
+ // if null (default), $('html, body').firstScrollable() is used.
18
+ scrollElement: null,
19
+
20
+ // only use if you want to override default behavior
21
+ scrollTarget: null,
22
+
23
+ // automatically focus the target element after scrolling to it
24
+ autoFocus: false,
25
+
26
+ // fn(opts) function to be called before scrolling occurs.
27
+ // `this` is the element(s) being scrolled
28
+ beforeScroll: function() {},
29
+
30
+ // fn(opts) function to be called after scrolling occurs.
31
+ // `this` is the triggering element
32
+ afterScroll: function() {},
33
+
34
+ // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
35
+ // from jQuery UI or elsewhere
36
+ easing: 'swing',
37
+
38
+ // speed can be a number or 'auto'
39
+ // if 'auto', the speed will be calculated based on the formula:
40
+ // (current scroll position - target scroll position) / autoCoeffic
41
+ speed: 400,
42
+
43
+ // coefficient for "auto" speed
44
+ autoCoefficient: 2,
45
+
46
+ // $.fn.smoothScroll only: whether to prevent the default click action
47
+ preventDefault: true
48
+ };
49
+
50
+ var getScrollable = function(opts) {
51
+ var scrollable = [];
52
+ var scrolled = false;
53
+ var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
54
+
55
+ this.each(function() {
56
+ var el = $(this);
57
+
58
+ if (this === document || this === window) {
59
+ return;
60
+ }
61
+
62
+ if (document.scrollingElement && (this === document.documentElement || this === document.body)) {
63
+ scrollable.push(document.scrollingElement);
64
+
65
+ return false;
66
+ }
67
+
68
+ if (el[dir]() > 0) {
69
+ scrollable.push(this);
70
+ } else {
71
+ // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
72
+ el[dir](1);
73
+ scrolled = el[dir]() > 0;
74
+
75
+ if (scrolled) {
76
+ scrollable.push(this);
77
+ }
78
+ // then put it back, of course
79
+ el[dir](0);
80
+ }
81
+ });
82
+
83
+ if (!scrollable.length) {
84
+ this.each(function() {
85
+ // If no scrollable elements and <html> has scroll-behavior:smooth because
86
+ // "When this property is specified on the root element, it applies to the viewport instead."
87
+ // and "The scroll-behavior property of the … body element is *not* propagated to the viewport."
88
+ // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior
89
+ if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') {
90
+ scrollable = [this];
91
+ }
92
 
93
+ // If still no scrollable elements, fall back to <body>,
94
  // if it's in the jQuery collection
95
  // (doing this because Safari sets scrollTop async,
96
  // so can't set it to 1 and immediately get the value.)
97
+ if (!scrollable.length && this.nodeName === 'BODY') {
98
+ scrollable = [this];
 
 
 
 
99
  }
100
+ });
101
+ }
102
 
103
+ // Use the first scrollable element if we're calling firstScrollable()
104
+ if (opts.el === 'first' && scrollable.length > 1) {
105
+ scrollable = [scrollable[0]];
106
+ }
107
 
108
+ return scrollable;
109
+ };
110
+
111
+ var rRelative = /^([\-\+]=)(\d+)/;
112
 
113
  $.fn.extend({
114
  scrollable: function(dir) {
115
  var scrl = getScrollable.call(this, {dir: dir});
116
+
117
  return this.pushStack(scrl);
118
  },
119
  firstScrollable: function(dir) {
120
  var scrl = getScrollable.call(this, {el: 'first', dir: dir});
121
+
122
  return this.pushStack(scrl);
123
  },
124
 
125
  smoothScroll: function(options, extra) {
126
  options = options || {};
127
 
128
+ if (options === 'options') {
129
+ if (!extra) {
130
  return this.first().data('ssOpts');
131
  }
132
+
133
  return this.each(function() {
134
+ var $this = $(this);
135
+ var opts = $.extend($this.data('ssOpts') || {}, extra);
136
 
137
  $(this).data('ssOpts', opts);
138
  });
139
  }
140
 
141
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
142
+
143
+ var clickHandler = function(event) {
144
+ var escapeSelector = function(str) {
145
+ return str.replace(/(:|\.|\/)/g, '\\$1');
146
+ };
147
+
148
+ var link = this;
149
+ var $link = $(this);
150
+ var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {});
151
+ var exclude = opts.exclude;
152
+ var excludeWithin = thisOpts.excludeWithin;
153
+ var elCounter = 0;
154
+ var ewlCounter = 0;
155
+ var include = true;
156
+ var clickOpts = {};
157
+ var locationPath = $.smoothScroll.filterPath(location.pathname);
158
+ var linkPath = $.smoothScroll.filterPath(link.pathname);
159
+ var hostMatch = location.hostname === link.hostname || !link.hostname;
160
+ var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath);
161
+ var thisHash = escapeSelector(link.hash);
162
+
163
+ if (thisHash && !$(thisHash).length) {
164
+ include = false;
165
+ }
166
+
167
+ if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) {
168
  include = false;
169
  } else {
170
  while (include && elCounter < exclude.length) {
172
  include = false;
173
  }
174
  }
175
+
176
+ while (include && ewlCounter < excludeWithin.length) {
177
  if ($link.closest(excludeWithin[ewlCounter++]).length) {
178
  include = false;
179
  }
180
  }
181
  }
182
 
183
+ if (include) {
184
+ if (thisOpts.preventDefault) {
 
185
  event.preventDefault();
186
  }
187
 
188
+ $.extend(clickOpts, thisOpts, {
189
  scrollTarget: thisOpts.scrollTarget || thisHash,
190
  link: link
191
  });
192
 
193
+ $.smoothScroll(clickOpts);
194
  }
195
+ };
196
+
197
+ if (options.delegateSelector !== null) {
198
+ this
199
+ .off('click.smoothscroll', options.delegateSelector)
200
+ .on('click.smoothscroll', options.delegateSelector, clickHandler);
201
+ } else {
202
+ this
203
+ .off('click.smoothscroll')
204
+ .on('click.smoothscroll', clickHandler);
205
+ }
206
 
207
  return this;
208
  }
209
  });
210
 
211
+ var getExplicitOffset = function(val) {
212
+ var explicit = {relative: ''};
213
+ var parts = typeof val === 'string' && rRelative.exec(val);
214
+
215
+ if (typeof val === 'number') {
216
+ explicit.px = val;
217
+ } else if (parts) {
218
+ explicit.relative = parts[1];
219
+ explicit.px = parseFloat(parts[2]) || 0;
220
+ }
221
+
222
+ return explicit;
223
+ };
224
+
225
+ var onAfterScroll = function(opts) {
226
+ var $tgt = $(opts.scrollTarget);
227
+
228
+ if (opts.autoFocus && $tgt.length) {
229
+ $tgt[0].focus();
230
+
231
+ if (!$tgt.is(document.activeElement)) {
232
+ $tgt.prop({tabIndex: -1});
233
+ $tgt[0].focus();
234
+ }
235
+ }
236
+
237
+ opts.afterScroll.call(opts.link, opts);
238
+ };
239
+
240
  $.smoothScroll = function(options, px) {
241
+ if (options === 'options' && typeof px === 'object') {
242
  return $.extend(optionOverrides, px);
243
  }
244
+ var opts, $scroller, speed, delta;
245
+ var explicitOffset = getExplicitOffset(options);
246
+ var scrollTargetOffset = {};
247
+ var scrollerOffset = 0;
248
+ var offPos = 'offset';
249
+ var scrollDir = 'scrollTop';
250
+ var aniProps = {};
251
+ var aniOpts = {};
252
+
253
+ if (explicitOffset.px) {
254
  opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
 
255
  } else {
256
  opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
257
+
258
  if (opts.scrollElement) {
259
  offPos = 'position';
260
+
261
  if (opts.scrollElement.css('position') === 'static') {
262
  opts.scrollElement.css('position', 'relative');
263
  }
264
  }
265
+
266
+ if (px) {
267
+ explicitOffset = getExplicitOffset(px);
268
+ }
269
  }
270
 
271
  scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
272
 
273
+ if (opts.scrollElement) {
274
  $scroller = opts.scrollElement;
275
+
276
+ if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) {
277
  scrollerOffset = $scroller[scrollDir]();
278
  }
279
  } else {
283
  // beforeScroll callback function must fire before calculating offset
284
  opts.beforeScroll.call($scroller, opts);
285
 
286
+ scrollTargetOffset = explicitOffset.px ? explicitOffset : {
287
+ relative: '',
288
+ px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0
289
+ };
290
+
291
+ aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset);
292
 
 
293
  speed = opts.speed;
294
 
295
  // automatically calculate the speed of the scroll based on distance / coefficient
296
  if (speed === 'auto') {
297
 
298
+ // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after
299
  // When delta is greater, speed will be greater.
300
+ delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]());
 
 
 
301
 
302
  // Divide the delta by the coefficient
303
  speed = delta / opts.autoCoefficient;
307
  duration: speed,
308
  easing: opts.easing,
309
  complete: function() {
310
+ onAfterScroll(opts);
311
  }
312
  };
313
 
318
  if ($scroller.length) {
319
  $scroller.stop().animate(aniProps, aniOpts);
320
  } else {
321
+ onAfterScroll(opts);
322
  }
323
  };
324
 
325
  $.smoothScroll.version = version;
326
  $.smoothScroll.filterPath = function(string) {
327
  string = string || '';
328
+
329
  return string
330
+ .replace(/^\//, '')
331
+ .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '')
332
+ .replace(/\/$/, '');
333
  };
334
 
335
  // default options
336
  $.fn.smoothScroll.defaults = defaults;
337
 
338
+ })(jQuery);
 
 
 
 
 
vendor/smooth-scroll/jquery.smooth-scroll.min.js CHANGED
@@ -1,22 +1 @@
1
- /*!
2
- * jQuery Smooth Scroll - v1.5.5 - 2015-02-19
3
- * https://github.com/kswedberg/jquery-smooth-scroll
4
- * Copyright (c) 2015 Karl Swedberg
5
- * Licensed MIT (https://github.com/kswedberg/jquery-smooth-scroll/blob/master/LICENSE-MIT)
6
- */
7
- (function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a);
8
- }else{if(typeof module==="object"&&module.exports){a(require("jquery"));}else{a(jQuery);}}}(function(d){var b="1.5.5",f={},e={exclude:[],excludeWithin:[],offset:0,direction:"top",scrollElement:null,scrollTarget:null,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficient:2,preventDefault:true},a=function(i){var j=[],h=false,g=i.dir&&i.dir==="left"?"scrollLeft":"scrollTop";
9
- this.each(function(){if(this===document||this===window){return;}var k=d(this);if(k[g]()>0){j.push(this);}else{k[g](1);h=k[g]()>0;if(h){j.push(this);}k[g](0);
10
- }});if(!j.length){this.each(function(){if(this.nodeName==="BODY"){j=[this];}});}if(i.el==="first"&&j.length>1){j=[j[0]];}return j;};d.fn.extend({scrollable:function(g){var h=a.call(this,{dir:g});
11
- return this.pushStack(h);},firstScrollable:function(g){var h=a.call(this,{el:"first",dir:g});return this.pushStack(h);},smoothScroll:function(h,g){h=h||{};
12
- if(h==="options"){if(!g){return this.first().data("ssOpts");}return this.each(function(){var l=d(this),k=d.extend(l.data("ssOpts")||{},g);d(this).data("ssOpts",k);
13
- });}var i=d.extend({},d.fn.smoothScroll.defaults,h),j=d.smoothScroll.filterPath(location.pathname);this.unbind("click.smoothscroll").bind("click.smoothscroll",function(m){var u=this,t=d(this),o=d.extend({},i,t.data("ssOpts")||{}),n=i.exclude,r=o.excludeWithin,v=0,q=0,l=true,w={},p=((location.hostname===u.hostname)||!u.hostname),k=o.scrollTarget||(d.smoothScroll.filterPath(u.pathname)===j),s=c(u.hash);
14
- if(!o.scrollTarget&&(!p||!k||!s)){l=false;}else{while(l&&v<n.length){if(t.is(c(n[v++]))){l=false;}}while(l&&q<r.length){if(t.closest(r[q++]).length){l=false;
15
- }}}if(l){if(o.preventDefault){m.preventDefault();}d.extend(w,o,{scrollTarget:o.scrollTarget||s,link:u});d.smoothScroll(w);}});return this;}});d.smoothScroll=function(r,m){if(r==="options"&&typeof m==="object"){return d.extend(f,m);
16
- }var g,h,q,i,n,p=0,j="offset",l="scrollTop",o={},k={};if(typeof r==="number"){g=d.extend({link:null},d.fn.smoothScroll.defaults,f);q=r;}else{g=d.extend({link:null},d.fn.smoothScroll.defaults,r||{},f);
17
- if(g.scrollElement){j="position";if(g.scrollElement.css("position")==="static"){g.scrollElement.css("position","relative");}}}l=g.direction==="left"?"scrollLeft":l;
18
- if(g.scrollElement){h=g.scrollElement;if(!(/^(?:HTML|BODY)$/).test(h[0].nodeName)){p=h[l]();}}else{h=d("html, body").firstScrollable(g.direction);}g.beforeScroll.call(h,g);
19
- q=(typeof r==="number")?r:m||(d(g.scrollTarget)[j]()&&d(g.scrollTarget)[j]()[g.direction])||0;o[l]=q+p+g.offset;i=g.speed;if(i==="auto"){n=o[l]-h.scrollTop();
20
- if(n<0){n*=-1;}i=n/g.autoCoefficient;}k={duration:i,easing:g.easing,complete:function(){g.afterScroll.call(g.link,g);}};if(g.step){k.step=g.step;}if(h.length){h.stop().animate(o,k);
21
- }else{g.afterScroll.call(g.link,g);}};d.smoothScroll.version=b;d.smoothScroll.filterPath=function(g){g=g||"";return g.replace(/^\//,"").replace(/(?:index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"");
22
- };d.fn.smoothScroll.defaults=e;function c(g){return g.replace(/(:|\.|\/)/g,"\\$1");}}));
1
+ !function($){var version="2.2.0",optionOverrides={},defaults={exclude:[],excludeWithin:[],offset:0,direction:"top",delegateSelector:null,scrollElement:null,scrollTarget:null,autoFocus:!1,beforeScroll:function(){},afterScroll:function(){},easing:"swing",speed:400,autoCoefficient:2,preventDefault:!0},getScrollable=function(opts){var scrollable=[],scrolled=!1,dir=opts.dir&&"left"===opts.dir?"scrollLeft":"scrollTop";return this.each((function(){var el=$(this);if(this!==document&&this!==window)return!document.scrollingElement||this!==document.documentElement&&this!==document.body?void(el[dir]()>0?scrollable.push(this):(el[dir](1),(scrolled=el[dir]()>0)&&scrollable.push(this),el[dir](0))):(scrollable.push(document.scrollingElement),!1)})),scrollable.length||this.each((function(){this===document.documentElement&&"smooth"===$(this).css("scrollBehavior")&&(scrollable=[this]),scrollable.length||"BODY"!==this.nodeName||(scrollable=[this])})),"first"===opts.el&&scrollable.length>1&&(scrollable=[scrollable[0]]),scrollable},rRelative=/^([\-\+]=)(\d+)/;$.fn.extend({scrollable:function(dir){var scrl=getScrollable.call(this,{dir:dir});return this.pushStack(scrl)},firstScrollable:function(dir){var scrl=getScrollable.call(this,{el:"first",dir:dir});return this.pushStack(scrl)},smoothScroll:function(options,extra){if("options"===(options=options||{}))return extra?this.each((function(){var $this=$(this),opts=$.extend($this.data("ssOpts")||{},extra);$(this).data("ssOpts",opts)})):this.first().data("ssOpts");var opts=$.extend({},$.fn.smoothScroll.defaults,options),clickHandler=function(event){var escapeSelector=function(str){return str.replace(/(:|\.|\/)/g,"\\$1")},link=this,$link=$(this),thisOpts=$.extend({},opts,$link.data("ssOpts")||{}),exclude=opts.exclude,excludeWithin=thisOpts.excludeWithin,elCounter=0,ewlCounter=0,include=!0,clickOpts={},locationPath=$.smoothScroll.filterPath(location.pathname),linkPath=$.smoothScroll.filterPath(this.pathname),hostMatch=location.hostname===this.hostname||!this.hostname,pathMatch=thisOpts.scrollTarget||linkPath===locationPath,thisHash=escapeSelector(this.hash);if(thisHash&&!$(thisHash).length&&(include=!1),thisOpts.scrollTarget||hostMatch&&pathMatch&&thisHash){for(;include&&elCounter<exclude.length;)$link.is(escapeSelector(exclude[elCounter++]))&&(include=!1);for(;include&&ewlCounter<excludeWithin.length;)$link.closest(excludeWithin[ewlCounter++]).length&&(include=!1)}else include=!1;include&&(thisOpts.preventDefault&&event.preventDefault(),$.extend(clickOpts,thisOpts,{scrollTarget:thisOpts.scrollTarget||thisHash,link:this}),$.smoothScroll(clickOpts))};return null!==options.delegateSelector?this.off("click.smoothscroll",options.delegateSelector).on("click.smoothscroll",options.delegateSelector,clickHandler):this.off("click.smoothscroll").on("click.smoothscroll",clickHandler),this}});var getExplicitOffset=function(val){var explicit={relative:""},parts="string"==typeof val&&rRelative.exec(val);return"number"==typeof val?explicit.px=val:parts&&(explicit.relative=parts[1],explicit.px=parseFloat(parts[2])||0),explicit},onAfterScroll=function(opts){var $tgt=$(opts.scrollTarget);opts.autoFocus&&$tgt.length&&($tgt[0].focus(),$tgt.is(document.activeElement)||($tgt.prop({tabIndex:-1}),$tgt[0].focus())),opts.afterScroll.call(opts.link,opts)};$.smoothScroll=function(options,px){if("options"===options&&"object"==typeof px)return $.extend(optionOverrides,px);var opts,$scroller,speed,delta,explicitOffset=getExplicitOffset(options),scrollTargetOffset={},scrollerOffset=0,offPos="offset",scrollDir="scrollTop",aniProps={},aniOpts={};explicitOffset.px?opts=$.extend({link:null},$.fn.smoothScroll.defaults,optionOverrides):((opts=$.extend({link:null},$.fn.smoothScroll.defaults,options||{},optionOverrides)).scrollElement&&(offPos="position","static"===opts.scrollElement.css("position")&&opts.scrollElement.css("position","relative")),px&&(explicitOffset=getExplicitOffset(px))),scrollDir="left"===opts.direction?"scrollLeft":scrollDir,opts.scrollElement?($scroller=opts.scrollElement,explicitOffset.px||/^(?:HTML|BODY)$/.test($scroller[0].nodeName)||(scrollerOffset=$scroller[scrollDir]())):$scroller=$("html, body").firstScrollable(opts.direction),opts.beforeScroll.call($scroller,opts),scrollTargetOffset=explicitOffset.px?explicitOffset:{relative:"",px:$(opts.scrollTarget)[offPos]()&&$(opts.scrollTarget)[offPos]()[opts.direction]||0},aniProps[scrollDir]=scrollTargetOffset.relative+(scrollTargetOffset.px+scrollerOffset+opts.offset),"auto"===(speed=opts.speed)&&(speed=(delta=Math.abs(aniProps[scrollDir]-$scroller[scrollDir]()))/opts.autoCoefficient),aniOpts={duration:speed,easing:opts.easing,complete:function(){onAfterScroll(opts)}},opts.step&&(aniOpts.step=opts.step),$scroller.length?$scroller.stop().animate(aniProps,aniOpts):onAfterScroll(opts)},$.smoothScroll.version="2.2.0",$.smoothScroll.filterPath=function(string){return(string=string||"").replace(/^\//,"").replace(/(?:index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"")},$.fn.smoothScroll.defaults=defaults}(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/waypoints/jquery.waypoints.js DELETED
@@ -1,662 +0,0 @@
1
- /*!
2
- Waypoints - 4.0.1
3
- Copyright © 2011-2016 Caleb Troughton
4
- Licensed under the MIT license.
5
- https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6
- */
7
- (function() {
8
- 'use strict'
9
-
10
- var keyCounter = 0
11
- var allWaypoints = {}
12
-
13
- /* http://imakewebthings.com/waypoints/api/waypoint */
14
- function Waypoint(options) {
15
- if (!options) {
16
- throw new Error('No options passed to Waypoint constructor')
17
- }
18
- if (!options.element) {
19
- throw new Error('No element option passed to Waypoint constructor')
20
- }
21
- if (!options.handler) {
22
- throw new Error('No handler option passed to Waypoint constructor')
23
- }
24
-
25
- this.key = 'waypoint-' + keyCounter
26
- this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
27
- this.element = this.options.element
28
- this.adapter = new Waypoint.Adapter(this.element)
29
- this.callback = options.handler
30
- this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
31
- this.enabled = this.options.enabled
32
- this.triggerPoint = null
33
- this.group = Waypoint.Group.findOrCreate({
34
- name: this.options.group,
35
- axis: this.axis
36
- })
37
- this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
38
-
39
- if (Waypoint.offsetAliases[this.options.offset]) {
40
- this.options.offset = Waypoint.offsetAliases[this.options.offset]
41
- }
42
- this.group.add(this)
43
- this.context.add(this)
44
- allWaypoints[this.key] = this
45
- keyCounter += 1
46
- }
47
-
48
- /* Private */
49
- Waypoint.prototype.queueTrigger = function(direction) {
50
- this.group.queueTrigger(this, direction)
51
- }
52
-
53
- /* Private */
54
- Waypoint.prototype.trigger = function(args) {
55
- if (!this.enabled) {
56
- return
57
- }
58
- if (this.callback) {
59
- this.callback.apply(this, args)
60
- }
61
- }
62
-
63
- /* Public */
64
- /* http://imakewebthings.com/waypoints/api/destroy */
65
- Waypoint.prototype.destroy = function() {
66
- this.context.remove(this)
67
- this.group.remove(this)
68
- delete allWaypoints[this.key]
69
- }
70
-
71
- /* Public */
72
- /* http://imakewebthings.com/waypoints/api/disable */
73
- Waypoint.prototype.disable = function() {
74
- this.enabled = false
75
- return this
76
- }
77
-
78
- /* Public */
79
- /* http://imakewebthings.com/waypoints/api/enable */
80
- Waypoint.prototype.enable = function() {
81
- this.context.refresh()
82
- this.enabled = true
83
- return this
84
- }
85
-
86
- /* Public */
87
- /* http://imakewebthings.com/waypoints/api/next */
88
- Waypoint.prototype.next = function() {
89
- return this.group.next(this)
90
- }
91
-
92
- /* Public */
93
- /* http://imakewebthings.com/waypoints/api/previous */
94
- Waypoint.prototype.previous = function() {
95
- return this.group.previous(this)
96
- }
97
-
98
- /* Private */
99
- Waypoint.invokeAll = function(method) {
100
- var allWaypointsArray = []
101
- for (var waypointKey in allWaypoints) {
102
- allWaypointsArray.push(allWaypoints[waypointKey])
103
- }
104
- for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
105
- allWaypointsArray[i][method]()
106
- }
107
- }
108
-
109
- /* Public */
110
- /* http://imakewebthings.com/waypoints/api/destroy-all */
111
- Waypoint.destroyAll = function() {
112
- Waypoint.invokeAll('destroy')
113
- }
114
-
115
- /* Public */
116
- /* http://imakewebthings.com/waypoints/api/disable-all */
117
- Waypoint.disableAll = function() {
118
- Waypoint.invokeAll('disable')
119
- }
120
-
121
- /* Public */
122
- /* http://imakewebthings.com/waypoints/api/enable-all */
123
- Waypoint.enableAll = function() {
124
- Waypoint.Context.refreshAll()
125
- for (var waypointKey in allWaypoints) {
126
- allWaypoints[waypointKey].enabled = true
127
- }
128
- return this
129
- }
130
-
131
- /* Public */
132
- /* http://imakewebthings.com/waypoints/api/refresh-all */
133
- Waypoint.refreshAll = function() {
134
- Waypoint.Context.refreshAll()
135
- }
136
-
137
- /* Public */
138
- /* http://imakewebthings.com/waypoints/api/viewport-height */
139
- Waypoint.viewportHeight = function() {
140
- return window.innerHeight || document.documentElement.clientHeight
141
- }
142
-
143
- /* Public */
144
- /* http://imakewebthings.com/waypoints/api/viewport-width */
145
- Waypoint.viewportWidth = function() {
146
- return document.documentElement.clientWidth
147
- }
148
-
149
- Waypoint.adapters = []
150
-
151
- Waypoint.defaults = {
152
- context: window,
153
- continuous: true,
154
- enabled: true,
155
- group: 'default',
156
- horizontal: false,
157
- offset: 0
158
- }
159
-
160
- Waypoint.offsetAliases = {
161
- 'bottom-in-view': function() {
162
- return this.context.innerHeight() - this.adapter.outerHeight()
163
- },
164
- 'right-in-view': function() {
165
- return this.context.innerWidth() - this.adapter.outerWidth()
166
- }
167
- }
168
-
169
- window.Waypoint = Waypoint
170
- }())
171
- ;(function() {
172
- 'use strict'
173
-
174
- function requestAnimationFrameShim(callback) {
175
- window.setTimeout(callback, 1000 / 60)
176
- }
177
-
178
- var keyCounter = 0
179
- var contexts = {}
180
- var Waypoint = window.Waypoint
181
- var oldWindowLoad = window.onload
182
-
183
- /* http://imakewebthings.com/waypoints/api/context */
184
- function Context(element) {
185
- this.element = element
186
- this.Adapter = Waypoint.Adapter
187
- this.adapter = new this.Adapter(element)
188
- this.key = 'waypoint-context-' + keyCounter
189
- this.didScroll = false
190
- this.didResize = false
191
- this.oldScroll = {
192
- x: this.adapter.scrollLeft(),
193
- y: this.adapter.scrollTop()
194
- }
195
- this.waypoints = {
196
- vertical: {},
197
- horizontal: {}
198
- }
199
-
200
- element.waypointContextKey = this.key
201
- contexts[element.waypointContextKey] = this
202
- keyCounter += 1
203
- if (!Waypoint.windowContext) {
204
- Waypoint.windowContext = true
205
- Waypoint.windowContext = new Context(window)
206
- }
207
-
208
- this.createThrottledScrollHandler()
209
- this.createThrottledResizeHandler()
210
- }
211
-
212
- /* Private */
213
- Context.prototype.add = function(waypoint) {
214
- var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
215
- this.waypoints[axis][waypoint.key] = waypoint
216
- this.refresh()
217
- }
218
-
219
- /* Private */
220
- Context.prototype.checkEmpty = function() {
221
- var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
222
- var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
223
- var isWindow = this.element == this.element.window
224
- if (horizontalEmpty && verticalEmpty && !isWindow) {
225
- this.adapter.off('.waypoints')
226
- delete contexts[this.key]
227
- }
228
- }
229
-
230
- /* Private */
231
- Context.prototype.createThrottledResizeHandler = function() {
232
- var self = this
233
-
234
- function resizeHandler() {
235
- self.handleResize()
236
- self.didResize = false
237
- }
238
-
239
- this.adapter.on('resize.waypoints', function() {
240
- if (!self.didResize) {
241
- self.didResize = true
242
- Waypoint.requestAnimationFrame(resizeHandler)
243
- }
244
- })
245
- }
246
-
247
- /* Private */
248
- Context.prototype.createThrottledScrollHandler = function() {
249
- var self = this
250
- function scrollHandler() {
251
- self.handleScroll()
252
- self.didScroll = false
253
- }
254
-
255
- this.adapter.on('scroll.waypoints', function() {
256
- if (!self.didScroll || Waypoint.isTouch) {
257
- self.didScroll = true
258
- Waypoint.requestAnimationFrame(scrollHandler)
259
- }
260
- })
261
- }
262
-
263
- /* Private */
264
- Context.prototype.handleResize = function() {
265
- Waypoint.Context.refreshAll()
266
- }
267
-
268
- /* Private */
269
- Context.prototype.handleScroll = function() {
270
- var triggeredGroups = {}
271
- var axes = {
272
- horizontal: {
273
- newScroll: this.adapter.scrollLeft(),
274
- oldScroll: this.oldScroll.x,
275
- forward: 'right',
276
- backward: 'left'
277
- },
278
- vertical: {
279
- newScroll: this.adapter.scrollTop(),
280
- oldScroll: this.oldScroll.y,
281
- forward: 'down',
282
- backward: 'up'
283
- }
284
- }
285
-
286
- for (var axisKey in axes) {
287
- var axis = axes[axisKey]
288
- var isForward = axis.newScroll > axis.oldScroll
289
- var direction = isForward ? axis.forward : axis.backward
290
-
291
- for (var waypointKey in this.waypoints[axisKey]) {
292
- var waypoint = this.waypoints[axisKey][waypointKey]
293
- if (waypoint.triggerPoint === null) {
294
- continue
295
- }
296
- var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
297
- var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
298
- var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
299
- var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
300
- if (crossedForward || crossedBackward) {
301
- waypoint.queueTrigger(direction)
302
- triggeredGroups[waypoint.group.id] = waypoint.group
303
- }
304
- }
305
- }
306
-
307
- for (var groupKey in triggeredGroups) {
308
- triggeredGroups[groupKey].flushTriggers()
309
- }
310
-
311
- this.oldScroll = {
312
- x: axes.horizontal.newScroll,
313
- y: axes.vertical.newScroll
314
- }
315
- }
316
-
317
- /* Private */
318
- Context.prototype.innerHeight = function() {
319
- /*eslint-disable eqeqeq */
320
- if (this.element == this.element.window) {
321
- return Waypoint.viewportHeight()
322
- }
323
- /*eslint-enable eqeqeq */
324
- return this.adapter.innerHeight()
325
- }
326
-
327
- /* Private */
328
- Context.prototype.remove = function(waypoint) {
329
- delete this.waypoints[waypoint.axis][waypoint.key]
330
- this.checkEmpty()
331
- }
332
-
333
- /* Private */
334
- Context.prototype.innerWidth = function() {
335
- /*eslint-disable eqeqeq */
336
- if (this.element == this.element.window) {
337
- return Waypoint.viewportWidth()
338
- }
339
- /*eslint-enable eqeqeq */
340
- return this.adapter.innerWidth()
341
- }
342
-
343
- /* Public */
344
- /* http://imakewebthings.com/waypoints/api/context-destroy */
345
- Context.prototype.destroy = function() {
346
- var allWaypoints = []
347
- for (var axis in this.waypoints) {
348
- for (var waypointKey in this.waypoints[axis]) {
349
- allWaypoints.push(this.waypoints[axis][waypointKey])
350
- }
351
- }
352
- for (var i = 0, end = allWaypoints.length; i < end; i++) {
353
- allWaypoints[i].destroy()
354
- }
355
- }
356
-
357
- /* Public */
358
- /* http://imakewebthings.com/waypoints/api/context-refresh */
359
- Context.prototype.refresh = function() {
360
- /*eslint-disable eqeqeq */
361
- var isWindow = this.element == this.element.window
362
- /*eslint-enable eqeqeq */
363
- var contextOffset = isWindow ? undefined : this.adapter.offset()
364
- var triggeredGroups = {}
365
- var axes
366
-
367
- this.handleScroll()
368
- axes = {
369
- horizontal: {
370
- contextOffset: isWindow ? 0 : contextOffset.left,
371
- contextScroll: isWindow ? 0 : this.oldScroll.x,
372
- contextDimension: this.innerWidth(),
373
- oldScroll: this.oldScroll.x,
374
- forward: 'right',
375
- backward: 'left',
376
- offsetProp: 'left'
377
- },
378
- vertical: {
379
- contextOffset: isWindow ? 0 : contextOffset.top,
380
- contextScroll: isWindow ? 0 : this.oldScroll.y,
381
- contextDimension: this.innerHeight(),
382
- oldScroll: this.oldScroll.y,
383
- forward: 'down',
384
- backward: 'up',
385
- offsetProp: 'top'
386
- }
387
- }
388
-
389
- for (var axisKey in axes) {
390
- var axis = axes[axisKey]
391
- for (var waypointKey in this.waypoints[axisKey]) {
392
- var waypoint = this.waypoints[axisKey][waypointKey]
393
- var adjustment = waypoint.options.offset
394
- var oldTriggerPoint = waypoint.triggerPoint
395
- var elementOffset = 0
396
- var freshWaypoint = oldTriggerPoint == null
397
- var contextModifier, wasBeforeScroll, nowAfterScroll
398
- var triggeredBackward, triggeredForward
399
-
400
- if (waypoint.element !== waypoint.element.window) {
401
- elementOffset = waypoint.adapter.offset()[axis.offsetProp]
402
- }
403
-
404
- if (typeof adjustment === 'function') {
405
- adjustment = adjustment.apply(waypoint)
406
- }
407
- else if (typeof adjustment === 'string') {
408
- adjustment = parseFloat(adjustment)
409
- if (waypoint.options.offset.indexOf('%') > - 1) {
410
- adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
411
- }
412
- }
413
-
414
- contextModifier = axis.contextScroll - axis.contextOffset
415
- waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
416
- wasBeforeScroll = oldTriggerPoint < axis.oldScroll
417
- nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
418
- triggeredBackward = wasBeforeScroll && nowAfterScroll
419
- triggeredForward = !wasBeforeScroll && !nowAfterScroll
420
-
421
- if (!freshWaypoint && triggeredBackward) {
422
- waypoint.queueTrigger(axis.backward)
423
- triggeredGroups[waypoint.group.id] = waypoint.group
424
- }
425
- else if (!freshWaypoint && triggeredForward) {
426
- waypoint.queueTrigger(axis.forward)
427
- triggeredGroups[waypoint.group.id] = waypoint.group
428
- }
429
- else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
430
- waypoint.queueTrigger(axis.forward)
431
- triggeredGroups[waypoint.group.id] = waypoint.group
432
- }
433
- }
434
- }
435
-
436
- Waypoint.requestAnimationFrame(function() {
437
- for (var groupKey in triggeredGroups) {
438
- triggeredGroups[groupKey].flushTriggers()
439
- }
440
- })
441
-
442
- return this
443
- }
444
-
445
- /* Private */
446
- Context.findOrCreateByElement = function(element) {
447
- return Context.findByElement(element) || new Context(element)
448
- }
449
-
450
- /* Private */
451
- Context.refreshAll = function() {
452
- for (var contextId in contexts) {
453
- contexts[contextId].refresh()
454
- }
455
- }
456
-
457
- /* Public */
458
- /* http://imakewebthings.com/waypoints/api/context-find-by-element */
459
- Context.findByElement = function(element) {
460
- return contexts[element.waypointContextKey]
461
- }
462
-
463
- window.onload = function() {
464
- if (oldWindowLoad) {
465
- oldWindowLoad()
466
- }
467
- Context.refreshAll()
468
- }
469
-
470
-
471
- Waypoint.requestAnimationFrame = function(callback) {
472
- var requestFn = window.requestAnimationFrame ||
473
- window.mozRequestAnimationFrame ||
474
- window.webkitRequestAnimationFrame ||
475
- requestAnimationFrameShim
476
- requestFn.call(window, callback)
477
- }
478
- Waypoint.Context = Context
479
- }())
480
- ;(function() {
481
- 'use strict'
482
-
483
- function byTriggerPoint(a, b) {
484
- return a.triggerPoint - b.triggerPoint
485
- }
486
-
487
- function byReverseTriggerPoint(a, b) {
488
- return b.triggerPoint - a.triggerPoint
489
- }
490
-
491
- var groups = {
492
- vertical: {},
493
- horizontal: {}
494
- }
495
- var Waypoint = window.Waypoint
496
-
497
- /* http://imakewebthings.com/waypoints/api/group */
498
- function Group(options) {
499
- this.name = options.name
500
- this.axis = options.axis
501
- this.id = this.name + '-' + this.axis
502
- this.waypoints = []
503
- this.clearTriggerQueues()
504
- groups[this.axis][this.name] = this
505
- }
506
-
507
- /* Private */
508
- Group.prototype.add = function(waypoint) {
509
- this.waypoints.push(waypoint)
510
- }
511
-
512
- /* Private */
513
- Group.prototype.clearTriggerQueues = function() {
514
- this.triggerQueues = {
515
- up: [],
516
- down: [],
517
- left: [],
518
- right: []
519
- }
520
- }
521
-
522
- /* Private */
523
- Group.prototype.flushTriggers = function() {
524
- for (var direction in this.triggerQueues) {
525
- var waypoints = this.triggerQueues[direction]
526
- var reverse = direction === 'up' || direction === 'left'
527
- waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
528
- for (var i = 0, end = waypoints.length; i < end; i += 1) {
529
- var waypoint = waypoints[i]
530
- if (waypoint.options.continuous || i === waypoints.length - 1) {
531
- waypoint.trigger([direction])
532
- }
533
- }
534
- }
535
- this.clearTriggerQueues()
536
- }
537
-
538
- /* Private */
539
- Group.prototype.next = function(waypoint) {
540
- this.waypoints.sort(byTriggerPoint)
541
- var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
542
- var isLast = index === this.waypoints.length - 1
543
- return isLast ? null : this.waypoints[index + 1]
544
- }
545
-
546
- /* Private */
547
- Group.prototype.previous = function(waypoint) {
548
- this.waypoints.sort(byTriggerPoint)
549
- var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
550
- return index ? this.waypoints[index - 1] : null
551
- }
552
-
553
- /* Private */
554
- Group.prototype.queueTrigger = function(waypoint, direction) {
555
- this.triggerQueues[direction].push(waypoint)
556
- }
557
-
558
- /* Private */
559
- Group.prototype.remove = function(waypoint) {
560
- var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
561
- if (index > -1) {
562
- this.waypoints.splice(index, 1)
563
- }
564
- }
565
-
566
- /* Public */
567
- /* http://imakewebthings.com/waypoints/api/first */
568
- Group.prototype.first = function() {
569
- return this.waypoints[0]
570
- }
571
-
572
- /* Public */
573
- /* http://imakewebthings.com/waypoints/api/last */
574
- Group.prototype.last = function() {
575
- return this.waypoints[this.waypoints.length - 1]
576
- }
577
-
578
- /* Private */
579
- Group.findOrCreate = function(options) {
580
- return groups[options.axis][options.name] || new Group(options)
581
- }
582
-
583
- Waypoint.Group = Group
584
- }())
585
- ;(function() {
586
- 'use strict'
587
-
588
- var $ = window.jQuery
589
- var Waypoint = window.Waypoint
590
-
591
- function JQueryAdapter(element) {
592
- this.$element = $(element)
593
- }
594
-
595
- $.each([
596
- 'innerHeight',
597
- 'innerWidth',
598
- 'off',
599
- 'offset',
600
- 'on',
601
- 'outerHeight',
602
- 'outerWidth',
603
- 'scrollLeft',
604
- 'scrollTop'
605
- ], function(i, method) {
606
- JQueryAdapter.prototype[method] = function() {
607
- var args = Array.prototype.slice.call(arguments)
608
- return this.$element[method].apply(this.$element, args)
609
- }
610
- })
611
-
612
- $.each([
613
- 'extend',
614
- 'inArray',
615
- 'isEmptyObject'
616
- ], function(i, method) {
617
- JQueryAdapter[method] = $[method]
618
- })
619
-
620
- Waypoint.adapters.push({
621
- name: 'jquery',
622
- Adapter: JQueryAdapter
623
- })
624
- Waypoint.Adapter = JQueryAdapter
625
- }())
626
- ;(function() {
627
- 'use strict'
628
-
629
- var Waypoint = window.Waypoint
630
-
631
- function createExtension(framework) {
632
- return function() {
633
- var waypoints = []
634
- var overrides = arguments[0]
635
-
636
- if (framework.isFunction(arguments[0])) {
637
- overrides = framework.extend({}, arguments[1])
638
- overrides.handler = arguments[0]
639
- }
640
-
641
- this.each(function() {
642
- var options = framework.extend({}, overrides, {
643
- element: this
644
- })
645
- if (typeof options.context === 'string') {
646
- options.context = framework(this).closest(options.context)[0]
647
- }
648
- waypoints.push(new Waypoint(options))
649
- })
650
-
651
- return waypoints
652
- }
653
- }
654
-
655
- if (window.jQuery) {
656
- window.jQuery.fn.waypoint = createExtension(window.jQuery)
657
- }
658
- if (window.Zepto) {
659
- window.Zepto.fn.waypoint = createExtension(window.Zepto)
660
- }
661
- }())
662
- ;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/waypoints/jquery.waypoints.min.js DELETED
@@ -1,7 +0,0 @@
1
- /*!
2
- Waypoints - 4.0.1
3
- Copyright © 2011-2016 Caleb Troughton
4
- Licensed under the MIT license.
5
- https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6
- */
7
- !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,n.windowContext||(n.windowContext=!0,n.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s];if(null!==a.triggerPoint){var l=o.oldScroll<a.triggerPoint,h=o.newScroll>=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=Math.floor(y+l-f),h=w<s.oldScroll,p=d.triggerPoint>=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}();
 
 
 
 
 
 
 
wpml-config.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <wpml-config>
2
+ <admin-texts>
3
+ <key name="ez-toc-settings">
4
+ <key name="heading_text"/>
5
+ </key>
6
+ </admin-texts>
7
+ </wpml-config>