PageSourceSearch

https://zpay.com/pw-online-help/js/all2.js

js zpay.com collected 2026-10-06 20:53:44 UTC 141,786 bytes, 3,959 lines download raw bytes

1/*js/drexplain/drexplain.data-manager.js*/
2DR_EXPLAIN.namespace( 'DR_EXPLAIN.dataManager' );
3
4DR_EXPLAIN.dataManager = (function() {
5    var data_resize = DR_EXPLAIN.data_resize;
6    var data_search = DR_EXPLAIN.data_search;
7    var data_menu = DR_EXPLAIN.data_menu;
8
9    var drex_node_names = data_menu.DREX_NODE_NAMES;
10    var drex_node_links = data_menu.DREX_NODE_LINKS;
11    var drex_node_child_start = data_menu.DREX_NODE_CHILD_START;
12    var drex_node_child_end = data_menu.DREX_NODE_CHILD_END;
13
14    var drex_node_parent = new Array();
15    var drex_node_deep = new Array();
16
17    var drex = {};
18
19
20    function drex_node(ndx)
21    {
22      this.node_index = ndx;
23      this.title = drex_node_names[this.node_index];
24      this.link = drex_node_links[this.node_index];
25      this.deep = drex_node_deep[this.node_index];
26
27      this.children = function(){
28        var result = new Array();
29        for (var i = drex_node_child_start[this.node_index]; i < drex_node_child_end[this.node_index]; i++)
30          result.push(new drex_node(i));
31        return result;
32      };
33      this.childrenCount = function(){
34        if (drex_node_child_start[this.node_index] >= drex_node_child_end[this.node_index])
35          return 0;
36        return drex_node_child_end[this.node_index] - drex_node_child_start[this.node_index];
37      };
38      this.parent = function(){
39        if (drex_node_parent[this.node_index] == -1)
40            return null;
41        return new drex_node(drex_node_parent[this.node_index]);
42      };
43      this.isActive = function(){
44        if (!drex.active_node)
45            return false;
46        return (this.node_index == drex.active_node.node_index);
47      };
48    };
49
50    var initMenu = function() {
51
52        drex_node_parent[0] = -1;
53        drex_node_deep[0] = 0;
54        for (var i in drex_node_names)
55        {
56          for (var j = drex_node_child_start[i]; j < drex_node_child_end[i]; j++)
57          {
58            drex_node_parent[j] = i;
59            drex_node_deep[j] = drex_node_deep[i] + 1;
60          }
61        }
62
63        drex = new Object();
64        drex.nodes_count = drex_node_names.length;
65
66        drex.root_node = function()
67        {
68          return new drex_node(0);
69        };
70
71        drex.active_node = null;
72        for (var i in drex_node_links)
73        {
74          if (drex_node_links[i] == getPageFilename())
75            drex.active_node = new drex_node(i);
76        }
77
78
79        function drex_resultContainer(){
80           this.result = "";
81        }
82    };
83
84
85    function drex_keyword(ndx)
86    {
87      this.keyword_index = ndx;
88      this.title = drex_keyword_names[this.keyword_index];
89      this.deep = drex_keyword_deep[this.keyword_index];
90
91      this.children = function(){
92        var result = new Array();
93        for (var i = drex_keyword_child_start[this.keyword_index]; i < drex_keyword_child_end[this.keyword_index]; i++)
94          result.push(new drex_keyword(i));
95        return result;
96      };
97      this.childrenSorted = function(){
98        var result = this.children();
99        result.sort(function(a,b){
100          if (a.title.toLowerCase() < b.title.toLowerCase())
101            return -1;
102          if (a.title.toLowerCase() > b.title.toLowerCase())
103            return 1;
104          return 0;
105        });
106        return result;
107      };
108      this.childrenCount = function(){
109        if (drex_keyword_child_start[this.keyword_index] >= drex_keyword_child_end[this.keyword_index])
110          return 0;
111        return drex_keyword_child_start[this.keyword_index] - drex_keyword_child_end[this.keyword_index];
112      }
113      this.parent = function(){
114        if (drex_keyword_parent[this.keyword_index] == -1)
115            return null;
116        return new drex_keyword(drex_keyword_parent[this.keyword_index]);
117      };
118      this.nodes = function(){
119        var result = new Array();
120        for (var i = drex_keyword_nodes_start[this.keyword_index]; i < drex_keyword_nodes_end[this.keyword_index]; i++)
121          result.push(new drex_node(drex_keyword_nodes[i]));
122        return result;
123      };
124      this.isActive = function(){
125        return this.keyword_index != 0;
126      };
127    };
128
129
130
131
132    var data_index = DR_EXPLAIN.data_index;
133
134    var drex_node_keywords = data_index.DREX_NODE_KEYWORDS;
135    var drex_node_keywords_start = data_index.DREX_NODE_KEYWORDS_START;
136    var drex_node_keywords_end = data_index.DREX_NODE_KEYWORDS_END;
137
138    var drex_keyword_names = data_index.DREX_KEYWORD_NAMES;
139    var drex_keyword_child_start = data_index.DREX_KEYWORD_CHILD_START;
140    var drex_keyword_child_end = data_index.DREX_KEYWORD_CHILD_END;
141
142    var drex_keyword_parent = new Array();
143    var drex_keyword_deep = new Array();
144
145    var drex_keyword_nodes = new Array(drex_node_keywords.length);
146    var drex_keyword_nodes_start = new Array(drex_keyword_names.length);
147    var drex_keyword_nodes_end = new Array(drex_keyword_names.length);
148
149
150
151    var initIndex = function() {
152
153        //keyword tree structure
154        drex_keyword_parent[0] = -1;
155        drex_keyword_deep[0] = 0;
156        for (var i in drex_keyword_names)
157        {
158          for (var j = drex_keyword_child_start[i]; j < drex_keyword_child_end[i]; j++)
159          {
160            drex_keyword_parent[j] = i;
161            drex_keyword_deep[j] = drex_keyword_deep[i] + 1;
162          }
163        }
164
165        drex.keywords_count = drex_keyword_names.length;
166
167
168        //making drex_keyword_nodes from drex_node_keywords
169        var temp_drex_keyword_write_pos = new Array(drex.keywords_count + 1);
170
171        for (var i = 0; i < temp_drex_keyword_write_pos.length; i++)
172          temp_drex_keyword_write_pos[i] = 0;
173        for (var i in drex_node_keywords)
174          ++temp_drex_keyword_write_pos[drex_node_keywords[i] + 1];
175        for (var i = 1; i < temp_drex_keyword_write_pos.length; i++)
176          temp_drex_keyword_write_pos[i] += temp_drex_keyword_write_pos[i-1];
177
178        for (var i = 0; i < drex.keywords_count; i++)
179          drex_keyword_nodes_start[i] = temp_drex_keyword_write_pos[i];
180
181        for (var i = 0; i < drex.nodes_count; i++)
182          for (var j = drex_node_keywords_start[i]; j < drex_node_keywords_end[i]; j++)
183          {
184            var kw = drex_node_keywords[j];
185            drex_keyword_nodes[temp_drex_keyword_write_pos[kw]] = i;
186            ++temp_drex_keyword_write_pos[kw];
187          }
188        for (var i = 0; i < drex.keywords_count; i++)
189            drex_keyword_nodes_end[i] = temp_drex_keyword_write_pos[i];
190
191
192        drex_node.prototype.keywords = function(){
193            var result = new Array();
194            for (var i = drex_node_keywords_start[this.node_index]; i < drex_node_keywords_end[this.node_index]; i++)
195              result.push(new drex_keyword(drex_node_keywords[i]));
196            return result;
197        };
198
199        //interface
200        drex.root_keyword = function()
201        {
202          return new drex_keyword(0);
203        };
204    };
205
206
207    var getPageFilename = function() {
208        if ( window[ 'drex_file_name' ] !== undefined ) {
209            return window.drex_file_name;
210        }
211        else {
212            return null;
213        }
214    };
215
216
217    var API = {
218        init: function() {
219            initMenu();
220            initIndex();
221        },
222
223        fitHeightToWindow: function() {
224            return data_resize.DREXPLAIN_FIT_HEIGHT_TO_WINDOW === 1;
225        },
226
227        getStartingMenuWidth: function() {
228            return parseInt(data_resize.DREX_INITIAL_MENU_WIDTH);
229        },
230
231        getSearchTextNoResults: function() {
232            return data_search.DREXPLAIN_NOT_FOUND;
233        },
234
235        getSearchTextInPreviewMode: function() {
236            return data_search.DREXPLAIN_PREVIEW_MODE_SEARCH_IS_DISABLED_NOTICE;
237        },
238
239        getErrorInLocalSearch: function() {
240            return data_search.DREXPLAIN_ERROR_LOCAL_SEARCH;
241        },
242
243        getErrorInRemoteSearch: function(code) {
244            return data_search.DREXPLAIN_ERROR_REMOTE_SEARCH.replace('{0}', code.toString());
245        },
246
247        getSearchTextEmptyString: function() {
248            return data_search.DREXPLAIN_EMPTY_STRING;
249        },
250
251        getSearchTextInProgress: function() {
252            return data_search.DREXPLAIN_IN_PROGRESS;
253        },
254
255
256        getPageFilename: function() {
257            return getPageFilename();
258        },
259
260
261        //drex.nodes_count
262        getNodesCount: function() {
263            return drex.nodes_count;
264        },
265
266        //drex.root_node()
267        getRootNode: function() {
268            return drex.root_node();
269        },
270
271        //drex.root_node()
272        getRootNodesArray: function() {
273            if (!data_menu.DREX_HAS_ROOT_NODE)
274                return drex.root_node().children();
275            return [drex.root_node()];
276        },
277
278        //drex.active_node
279        getSelectedNode: function() {
280            return drex.active_node;
281        },
282
283        //!drex.active_node
284        isSelectedNodeExists: function() {
285            if ( !drex.active_node ) {
286                return false;
287            }
288            else {
289                return true;
290            }
291        },
292
293        //function drex_node(ndx)
294        createNodeClassByIndex: function( nodeIndex ) {
295            return new drex_node( nodeIndex );
296        },
297
298        // DrexObjectsManager.menu.createNodeClassByIndex( i ) ).deep <= 0 ? 1 : 0;
299        getNodeDeepByIndex: function( nodeIndex ) {
300            return drex_node_deep[ nodeIndex ];
301        },
302
303        getIndexByNode: function( node ) {
304            return node.node_index;
305        },
306
307        getDrex: function() {
308            return drex;
309        },
310
311        getDrexNode: function( ndx ) {
312            return drex_node( ndx );
313        },
314
315        getDrexMenuType: function() {
316            return data_menu.DREX_MENU_TYPE;
317        }
318    };
319
320    return API;
321
322})();
323
324
325/*js/drexplain/drexplain.dom.js*/
326DR_EXPLAIN.namespace( 'DR_EXPLAIN.dom' );
327
328/**
329 * @returns {DomCached}
330 */
331DR_EXPLAIN.dom = {
332    PAGE_CONTENT_HEADER__HIDDEN_CLASS: "m-pageContent__withoutHeader",
333    PAGE_CONTENT_FOOTER__HIDDEN_CLASS: "m-pageContent__withoutFooter",
334    PAGE_CONTENT_LEFT__HIDDEN_CLASS: "m-pageContent__withoutRight",
335    PAGE_CONTENT_RIGHT__HIDDEN_CLASS: "m-pageContent__withoutLeft",
336
337    WORK_ZONE_SIDE_NAV__HIDDEN_CLASS: "m-workZone__withoutSideNav",
338
339    TAB_WRAPPER_ITEM__SELECTED_CLASS: "m-tabs__wrapperItem__selected",
340    TAB_SELECTOR_ITEM__SELECTED_CLASS: "m-tabs__selectorItem__selected",
341
342    FRAME_ENABLED_CLASS: "m-pageView__state__frame",
343
344    _isIeLessThan9: null,
345    _isIe: null,
346
347    init: function() {
348        this.$html = $( "html" );
349        this.$body = $( "body" );
350
351        this.$pageLayout = $("#pageLayout");
352
353        this.$internal_wrapper = $( "#internal_wrapper" );
354        this.$pageContent = $( "#pageContent" );
355        this.$pageContentHeader = $( "#pageContentHeader" );
356        this.$pageContentFooter = $( "#pageContentFooter" );
357        this.$pageContentArticleSide = $( "#pageContentArticleSide" );
358        this.$pageContentLeft = $( "#pageContentLeft" );
359        this.$pageContentRight = $( "#pageContentRight" );
360
361        this.$tabWrapperItems = $( "#tabWrapperItems" );
362
363        this.$article = $( "#article" );
364        this.$articleHeader = $( "#article__header" );
365        this.$articlePreWrapper = this.$article.children( ".b-article__preWrapper" );
366        this.$articleWrapper = this.$article.find( ".b-article__wrapper" );
367        this.$articleInnerWrapper = this.$article.find( ".b-article__innerWrapper" );
368        this.$articleGeneratorCopyright = this.$article.find( ".b-article__generatorCopyright" );
369
370        this.$headerSide__nav = $("#headerSide__nav");
371        this.$headerSide__nav__breadCrumbs = $("#headerSide__nav__breadCrumbs");
372        this.$headerSide__buttons = $("#headerSide__buttons");
373
374        this.$splitter = $( "#splitter" );
375        this.$workZone = $( "#workZone" );
376        this.$workZoneSideNav = $( "#workZone_nav" );
377        this.$workZoneSideNavContent = $( "#workZone_nav_content" );
378        this.$workZoneSideArticle = $( "#workZone_article" );
379        this.$workZoneSideArticleOverlay = $('#workZone_article__overlay');
380
381        this.$presentSideNavButton = $('#presentSideNavButton');
382        this.$dismissSideNavButton = $('#dismissSideNavButton');
383
384        this.$workZoneSideArticleContent = $( "#workZone_article__content" );
385
386        this.$tabsWrapperItems = $( "#tabsWrapperItems" );
387
388
389        this.tabs = {};
390
391        this.tabs.menu = {};
392        this.tabs.menu.$selectorItem = $( "#tabSelector_menu" );
393        this.tabs.menu.$wrapperItem = $( "#tabWrapper_menu" );
394        this.tabs.menu.$wrapperItemInner = this.tabs.menu.$wrapperItem.children( ".b-tabs__wrapperItemInner" );
395        this.tabs.menu.$tree = this.tabs.menu.$wrapperItemInner.children( ".b-tree" );
396
397        this.tabs.index = {};
398        this.tabs.index.$selectorItem = $( "#tabSelector_index" );
399        this.tabs.index.$wrapperItem = $( "#tabWrapper_index" );
400        this.tabs.index.$wrapperItemInner = this.tabs.index.$wrapperItem.children( ".b-tabs__wrapperItemInner" );
401        this.tabs.index.$tree = this.tabs.index.$wrapperItemInner.children( ".b-tree" );
402
403
404        this.tabs.search = {};
405        this.tabs.search.$selectorItem = $( "#tabSelector_search" );
406        this.tabs.search.$wrapperItem = $( "#tabWrapper_search" );
407        this.tabs.search.$wrapperItemInner = this.tabs.search.$wrapperItem.children( ".b-tabs__wrapperItemInner" );
408        this.tabs.search.$tree = this.tabs.search.$wrapperItemInner.children( ".b-tree" );
409
410
411
412            // todo: remove or refactor
413
414                this.$tabWrapperItemArr = this.tabs.menu.$wrapperItem.add( this.tabs.index.$wrapperItem ).add( this.tabs.search.$wrapperItem );
415                this.$tabWrapperItemInnerArr = this.tabs.menu.$wrapperItemInner.add( this.tabs.index.$wrapperItemInner ).add( this.tabs.search.$wrapperItemInner );
416                this.$treeArr = this.$tabWrapperItemInnerArr.find( ".b-tree" );
417                this.$tabWrapperMenu = this.tabs.menu.$wrapperItem;
418
419                // remove:
420                this.$tabWrapperIndex = this.tabs.index.$wrapperItem;
421                this.$tabWrapperSearch = this.tabs.search.$wrapperItem;
422
423                this.$tabSelectorMenu = this.tabs.menu.$selectorItem;
424                this.$tabSelectorIndex = this.tabs.index.$selectorItem;
425                this.$tabSelectorSearch = this.tabs.search.$selectorItem;
426            //
427
428
429        this.$tabSearchFormWrapper = $( "#tabs_searchFormWrapper" );
430
431        this.$tabSearchSubmit = $( "#tabs_searchSubmit" );
432        this.$tabSearchInput = $( "#tabs_searchInput" );
433        this.$tabSearchInputLabel = $( "#tabs_searchInput_label" );
434
435        this.$workZoneSearchSubmit = $( "#workZone_searchSubmit" );
436        this.$workZoneSearchInput = $( "#workZone_searchInput" );
437        this.$workZoneSearchInputLabel = $( "#workZone_searchInput_label" );
438
439
440        this.$keywordContextMenu = $( "#keywordContextMenu" );
441
442        this.$searchProgress = $( "#searchProgress" );
443        this.$hasVerticalScrollbar = {};
444        this.$hasHorizontalScrollbar = {};
445
446
447/*      this.$tabItemWrapperInnerArr = $( ".b-tabs__wrapperItemInner" );
448        this.$treeArr = $( ".b-tabs__wrapperItemInner .b-tree" );*/
449    },
450
451    isIe: function() {
452        if ( this._isIe === null ) {
453            if ( this.$html.hasClass( "ie" ) ) {
454                this._isIe = true;
455            }
456            else {
457                this._isIe = false;
458            }
459        }
460
461        return this._isIeLessThan9;
462    },
463
464    isIeLessThan9: function() {
465        if ( this._isIeLessThan9 === null ) {
466            if ( this.$html.hasClass( "ie6" ) || this.$html.hasClass( "ie7" ) || this.$html.hasClass( "ie8" )) {
467                this._isIeLessThan9 = true;
468            }
469            else {
470                this._isIeLessThan9 = false;
471            }
472        }
473
474        return this._isIeLessThan9;
475    },
476
477    setPageLayoutType: function(layoutType) {
478        var currLayoutType = this.getPageLayoutType();
479        if (layoutType !== currLayoutType) {
480            this.$pageLayout.attr('data-layout', layoutType);
481
482            newClass = 'b-pageLayout__' + layoutType;
483            allClasses = ['b-pageLayout__xs', 'b-pageLayout__sm', 'b-pageLayout__md', 'b-pageLayout__lg'];
484            this.$pageLayout
485                .removeClass(_.without(allClasses, newClass).join(' '))
486                .addClass(newClass);
487
488            $(document).trigger('pageLayoutChange', layoutType);
489        }
490    },
491
492    getPageLayoutType: function() {
493        return this.$pageLayout.attr('data-layout');
494    },
495
496    _getBrowserWindowWidth: function() {
497        /* AT
498            jQuery's .width() doesn't include vertical scrollbar width
499            This is not a bug. According to jQuery docs, width() method returns
500            viewport width.
501            To deliver better mobile experience we need to detect browser window
502            width correctly. So we are using window.innerWidth. It is not
503            supported in IE<9, so we are using other values as a fallback.
504
505            Note that this method will return the same result as .width()
506            for IE<9. It is a known downside, and it won't be fixed.
507        */
508        return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
509    },
510
511    updatePageLayoutType: function() {
512        var browserWindowWidth = this._getBrowserWindowWidth();
513        if (browserWindowWidth < 768) {
514            this.setPageLayoutType('xs');
515        } else if (browserWindowWidth < 992) {
516            this.setPageLayoutType('sm');
517        } else if (browserWindowWidth < 1200) {
518            this.setPageLayoutType('md');
519        } else {
520            this.setPageLayoutType('lg');
521        }
522    },
523
524    getVisibleTab: function() {
525        if ( this.isTabVisible( this.tabs.menu ) ) {
526            return this.tabs.menu;
527        }
528        else if ( this.isTabVisible( this.tabs.index ) ) {
529            return this.tabs.index;
530        }
531        else if ( this.isTabVisible( this.tabs.search ) ) {
532            return this.tabs.search;
533        }
534        else {
535            return null;
536        }
537    },
538
539    getVisibleItemWrapperInner: function() {
540        var visibleTab = this.getVisibleTab();
541        if ( visibleTab !== null ) {
542            return visibleTab.$wrapperItemInner;
543        }
544        else {
545            return null;
546        }
547    },
548
549    isTabVisible: function( tab ) {
550        if (_.contains(['xs'], this.getPageLayoutType()) && !this.$workZoneSideNav.hasClass('topmost')) {
551            return false;
552        }
553        return tab.$wrapperItem.hasClass(this.TAB_WRAPPER_ITEM__SELECTED_CLASS);
554    },
555
556    isKeywordContextMenuVisible: function() {
557        if ( this.$keywordContextMenu.hasClass( "m-tree__contextMenu__visible" ) ) {
558            return true;
559        }
560        else {
561            return false;
562        }
563    },
564
565    getCssNumericValue: function( $elem, cssProp ) {
566        return parseInt( $elem.css( cssProp ), 10 );
567    },
568
569    isPageHeaderVisible: function() {
570        return !(this.$pageContent.hasClass(this.PAGE_CONTENT_HEADER__HIDDEN_CLASS) ||
571                 _.contains(['xs'], this.getPageLayoutType()));
572    },
573
574    isPageFooterVisible: function() {
575        return !(this.$pageContent.hasClass(this.PAGE_CONTENT_FOOTER__HIDDEN_CLASS) ||
576                 _.contains(['xs'], this.getPageLayoutType()));
577    },
578
579    isPageLeftVisible: function() {
580        return !(this.$pageContent.hasClass(this.PAGE_CONTENT_LEFT__HIDDEN_CLASS) ||
581                 _.contains(['xs'], this.getPageLayoutType()));
582    },
583
584    isPageRightVisible: function() {
585        return !(this.$pageContent.hasClass(this.PAGE_CONTENT_RIGHT__HIDDEN_CLASS) ||
586                 _.contains(['xs'], this.getPageLayoutType()));
587    },
588
589    isRtl: function() {
590        return this.$html.attr('dir') === 'rtl';
591    }
592};
593
594
595DR_EXPLAIN.namespace( 'DR_EXPLAIN.wordSplitter' );
596DR_EXPLAIN.wordSplitter = (function() {
597
598
599    function rangesToArray(ranges, rangesObj)
600    {
601        var rangeElements = ranges.split(/[-,]/);
602        if (rangeElements.length % 2 != 0)
603        {
604            alert("Error #398, please report it to [email protected]");
605            return;
606        }
607        for (var i = 0; i < rangeElements.length; i += 2)
608        {
609            var startEl = parseInt(rangeElements[i]);
610            var endEl = parseInt(rangeElements[i + 1]);
611            rangesObj.addRange(startEl, endEl);
612        }
613        rangesObj.filled = true;
614    }
615    var Ranges = function() {
616        this.filled = false;
617        this.starts = new Array();
618        this.ends = new Array();
619        this.contains
620    };
621    Ranges.prototype.addRange = function(start, end)
622    {
623        this.starts.push(start);
624        this.ends.push(end);
625        if (this.starts.length != this.ends.length)
626            alert("starts.length != ends.length!");
627    };
628    Ranges.prototype.checkContains = function(val)
629    {
630        if (!this.filled)
631            return false;
632        var it = this.upperBound(val);
633        if (it == 0)
634            return false;
635        --it;
636        var nBegin = this.starts[it];
637        var nEnd = this.ends[it]
638        if (nBegin <= val && val < nEnd)
639            return true;
640        return false;
641    };
642    Ranges.prototype.upperBound = function(val)
643    {
644        var lo = 0, hi = this.starts.length - 1;
645        while (lo < hi) {
646            var mid = ((hi + lo + 1)/2)>>0; /*integer division*/
647                if (this.starts[mid] <= val)
648                    lo = mid;
649                else
650                    hi = mid - 1;
651        }
652        if (this.starts[lo] <= val)
653         return lo + 1;
654        return this.starts.length;
655    };
656    var stPunctuation = new Ranges();
657    function isPunctuationSymbol(codePoint)
658    {
659        if (!stPunctuation.filled)
660        {
661            rangesToArray( 
662                "33-36,37-43,44-48,58-60,63-65,91-94,123-124,125-126,161-162,167-168,171-172,182-184,187-188,191-192,894-895,903-904,1370-1376,1417-1419,1470-1471," +
663                "1472-1473,1475-1476,1478-1479,1523-1525,1545-1547,1548-1550,1563-1564,1566-1568,1642-1646,1748-1749,1792-1806,2039-2042,2096-2111,2142-2143,2404-2406," +
664                "2416-2417,2800-2801,3572-3573,3663-3664,3674-3676,3844-3859,3860-3861,3898-3902,3973-3974,4048-4053,4057-4059,4170-4176,4347-4348,4960-4969,5120-5121," +
665                "5741-5743,5787-5789,5867-5870,5941-5943,6100-6103,6104-6107,6144-6155,6468-6470,6686-6688,6816-6823,6824-6830,7002-7009,7164-7168,7227-7232,7294-7296," +
666                "7360-7368,7379-7380,8208-8232,8240-8260,8261-8274,8275-8287,8317-8319,8333-8335,8968-8972,9001-9003,10088-10102,10181-10183,10214-10224,10627-10649," +
667                "10712-10716,10748-10750,11513-11517,11518-11520,11632-11633,11776-11823,11824-11843,12289-12292,12296-12306,12308-12320,12336-12337,12349-12350," +
668                "12448-12449,12539-12540,42238-42240,42509-42512,42611-42612,42622-42623,42738-42744,43124-43128,43214-43216,43256-43259,43260-43261,43310-43312," +
669                "43359-43360,43457-43470,43486-43488,43612-43616,43742-43744,43760-43762,44011-44012,64830-64832,65040-65050,65072-65107,65108-65122,65123-65124," +
670                "65128-65129,65130-65132,65281-65284,65285-65291,65292-65296,65306-65308,65311-65313,65339-65342,65343-65344,65371-65372,65373-65374,65375-65382," +
671                "65792-65795,66463-66464,66512-66513,66927-66928,67671-67672,67871-67872,67903-67904,68176-68185,68223-68224,68336-68343,68409-68416,68505-68509," +
672                "69703-69710,69819-69821,69822-69826,69952-69956,70004-70006,70085-70090,70093-70094,70107-70108,70109-70112,70200-70206,70313-70314,70854-70855," +
673                "71105-71128,71233-71236,71484-71487,74864-74869,92782-92784,92917-92918,92983-92988,92996-92997,113823-113824,121479-121484",
674                stPunctuation
675            );
676        }
677        if (stPunctuation.checkContains(codePoint))
678            return true;
679        return false;
680    }
681    var stWordSymbols = new Ranges();
682    function isWordSymbol(codePoint)
683    {
684        if (!stWordSymbols.filled)
685        {
686            rangesToArray( 
687                "33-36,37-43,44-60,63-94,95-96,97-124,125-126,161-162,167-168,170-172,178-180,181-184,185-215,216-247,248-706,710-722,736-741,748-749,750-751,768-885," +
688                "886-888,890-896,902-907,908-909,910-930,931-1014,1015-1154,1155-1328,1329-1367,1369-1376,1377-1416,1417-1419,1425-1480,1488-1515,1520-1525,1545-1547," +
689                "1548-1550,1552-1564,1566-1757,1759-1769,1770-1789,1791-1806,1808-1867,1869-1970,1984-2038,2039-2043,2048-2094,2096-2111,2112-2140,2142-2143,2208-2229," +
690                "2275-2436,2437-2445,2447-2449,2451-2473,2474-2481,2482-2483,2486-2490,2492-2501,2503-2505,2507-2511,2519-2520,2524-2526,2527-2532,2534-2546,2548-2554," +
691                "2561-2564,2565-2571,2575-2577,2579-2601,2602-2609,2610-2612,2613-2615,2616-2618,2620-2621,2622-2627,2631-2633,2635-2638,2641-2642,2649-2653,2654-2655," +
692                "2662-2678,2689-2692,2693-2702,2703-2706,2707-2729,2730-2737,2738-2740,2741-2746,2748-2758,2759-2762,2763-2766,2768-2769,2784-2788,2790-2801,2809-2810," +
693                "2817-2820,2821-2829,2831-2833,2835-2857,2858-2865,2866-2868,2869-2874,2876-2885,2887-2889,2891-2894,2902-2904,2908-2910,2911-2916,2918-2928,2929-2936," +
694                "2946-2948,2949-2955,2958-2961,2962-2966,2969-2971,2972-2973,2974-2976,2979-2981,2984-2987,2990-3002,3006-3011,3014-3017,3018-3022,3024-3025,3031-3032," +
695                "3046-3059,3072-3076,3077-3085,3086-3089,3090-3113,3114-3130,3133-3141,3142-3145,3146-3150,3157-3159,3160-3163,3168-3172,3174-3184,3192-3199,3201-3204," +
696                "3205-3213,3214-3217,3218-3241,3242-3252,3253-3258,3260-3269,3270-3273,3274-3278,3285-3287,3294-3295,3296-3300,3302-3312,3313-33
69615,3329-3332,3333-3341," +
697                "3342-3345,3346-3387,3389-3397,3398-3401,3402-3407,3415-3416,3423-3428,3430-3446,3450-3456,3458-3460,3461-3479,3482-3506,3507-3516,3517-3518,3520-3527," +
698                "3530-3531,3535-3541,3542-3543,3544-3552,3558-3568,3570-3573,3585-3643,3648-3676,3713-3715,3716-3717,3719-3721,3722-3723,3725-3726,3732-3736,3737-3744," +
699                "3745-3748,3749-3750,3751-3752,3754-3756,3757-3770,3771-3774,3776-3781,3782-3783,3784-3790,3792-3802,3804-3808,3840-3841,3844-3859,3860-3861,3864-3866," +
700                "3872-3892,3893-3894,3895-3896,3897-3912,3913-3949,3953-3992,3993-4029,4038-4039,4048-4053,4057-4059,4096-4254,4256-4294,4295-4296,4301-4302,4304-4681," +
701                "4682-4686,4688-4695,4696-4697,4698-4702,4704-4745,4746-4750,4752-4785,4786-4790,4792-4799,4800-4801,4802-4806,4808-4823,4824-4881,4882-4886,4888-4955," +
702                "4957-4989,4992-5008,5024-5110,5112-5118,5120-5760,5761-5789,5792-5881,5888-5901,5902-5909,5920-5943,5952-5972,5984-5997,5998-6001,6002-6004,6016-6107," +
703                "6108-6110,6112-6122,6128-6138,6144-6158,6160-6170,6176-6264,6272-6315,6320-6390,6400-6431,6432-6444,6448-6460,6468-6510,6512-6517,6528-6572,6576-6602," +
704                "6608-6619,6656-6684,6686-6751,6752-6781,6783-6794,6800-6810,6816-6830,6832-6847,6912-6988,6992-7009,7019-7028,7040-7156,7164-7224,7227-7242,7245-7296," +
705                "7360-7368,7376-7415,7416-7418,7424-7670,7676-7958,7960-7966,7968-8006,8008-8014,8016-8024,8025-8026,8027-8028,8029-8030,8031-8062,8064-8117,8118-8125," +
706                "8126-8127,8130-8133,8134-8141,8144-8148,8150-8156,8160-8173,8178-8181,8182-8189,8208-8232,8240-8260,8261-8274,8275-8287,8304-8306,8308-8314,8317-8330," +
707                "8333-8335,8336-8349,8400-8433,8450-8451,8455-8456,8458-8468,8469-8470,8473-8478,8484-8485,8486-8487,8488-8489,8490-8494,8495-8506,8508-8512,8517-8522," +
708                "8526-8527,8528-8586,8968-8972,9001-9003,9312-9472,10088-10132,10181-10183,10214-10224,10627-10649,10712-10716,10748-10750,11264-11311,11312-11359," +
709                "11360-11493,11499-11508,11513-11558,11559-11560,11565-11566,11568-11624,11631-11633,11647-11671,11680-11687,11688-11695,11696-11703,11704-11711," +
710                "11712-11719,11720-11727,11728-11735,11736-11743,11744-11843,12289-12292,12293-12306,12308-12320,12321-12342,12344-12350,12353-12439,12441-12443," +
711                "12445-12544,12549-12590,12593-12687,12690-12694,12704-12731,12784-12800,12832-12842,12872-12880,12881-12896,12928-12938,12977-12992,13312-19894," +
712                "19968-40918,40960-42125,42192-42540,42560-42744,42775-42784,42786-42889,42891-42926,42928-42936,42999-43048,43056-43062,43072-43128,43136-43205," +
713                "43214-43226,43232-43262,43264-43348,43359-43389,43392-43470,43471-43482,43486-43519,43520-43575,43584-43598,43600-43610,43612-43639,43642-43715," +
714                "43739-43767,43777-43783,43785-43791,43793-43799,43808-43815,43816-43823,43824-43867,43868-43878,43888-44014,44016-44026,44032-55204,55216-55239," +
715                "55243-55292,63744-64110,64112-64218,64256-64263,64275-64280,64285-64297,64298-64311,64312-64317,64318-64319,64320-64322,64323-64325,64326-64434," +
716                "64467-64832,64848-64912,64914-64968,65008-65020,65024-65050,65056-65107,65108-65122,65123-65124,65128-65129,65130-65132,65136-65141,65142-65277," +
717                "65281-65284,65285-65291,65292-65308,65311-65342,65343-65344,65345-65372,65373-65374,65375-65471,65474-65480,65482-65488,65490-65496,65498-65501," +
718                "65536-65548,65549-65575,65576-65595,65596-65598,65599-65614,65616-65630,65664-65787,65792-65795,65799-65844,65856-65913,65930-65932,66045-66046," +
719                "66176-66205,66208-66257,66272-66300,66304-66340,66352-66379,66384-66427,66432-66462,66463-66500,66504-66518,66560-66718,66720-66730,66816-66856," +
720                "66864-66916,66927-66928,67072-67383,67392-67414,67424-67432,67584-67590,67592-67593,67594-67638,67639-67641,67644-67645,67647-67670,67671-67703," +
721                "67705-67743,67751-67760,67808-67827,67828-67830,67835-67868,67871-67898,67903-67904,67968-68024,68028-68048,68050-68100,68101-68103,68108-68116," +
722                "68117-68120,68121-68148,68152-68155,68159-68168,68176-68185,68192-68256,68288-68296,68297-68327,68331-68343,68352-68406,68409-68438,68440-68467," +
723                "68472-68498,68505-68509,68521-68528,68608-68681,68736-68787,68800-68851,68858-68864,69216-69247,69632-69710,69714-69744,69759-69821,69822-69826," +
724                "69840-69865,69872-69882,69888-69941,69942-69956,69968-70007,70016-70094,70096-70112,70113-70133,70144-70162,70163-70206,70272-70279,70280-70281," +
725                "70282-70286,70287-70302,70303-70314,70320-70379,70384-70394,70400-70404,70405-70413,70415-70417,70419-70441,70442-70449,70450-70452,70453-70458," +
726                "70460-70469,70471-70473,70475-70478,70480-70481,70487-70488,70493-70500,70502-70509,70512-70517,70784-70856,70864-70874,71040-71094,71096-71134," +
727                "71168-71237,71248-71258,71296-71352,71360-71370,71424-71450,71453-71468,71472-71487,71840-71923,71935-71936,72384-72441,73728-74650,74752-74863," +
728                "74864-74869,74880-75076,77824-78895,82944-83527,92160-92729,92736-92767,92768-92778,92782-92784,92880-92910,92912-92918,92928-92988,92992-92997," +
729                "93008-93018,93019-93026,93027-93048,93053-93072,93952-94021,94032-94079,94095-94112,110592-110594,113664-113771,113776-113789,113792-113801," +
730                "113808-113818,113821-113824,119141-119146,119149-119155,119163-119171,119173-119180,119210-119214,119362-119365,119648-119666,119808-119893," +
731                "119894-119965,119966-119968,119970-119971,119973-119975,119977-119981,119982-119994,119995-119996,119997-120004,120005-120070,120071-120075," +
732                "120077-120085,120086-120093,120094-120122,120123-120127,120128-120133,120134-120135,120138-120145,120146-120486,120488-120513,120514-120539," +
733                "120540-120571,120572-120597,120598-120629,120630-120655,120656-120687,120688-120713,120714-120745,120746-120771,120772-120780,120782-120832," +
734                "121344-121399,121403-121453,121461-121462,121476-121477,121479-121484,121499-121504,121505-121520,124928-125125,125127-125143,126464-126468," +
735                "126469-126496,126497-126499,126500-126501,126503-126504,126505-126515,126516-126520,126521-126522,126523-126524,126530-126531,126535-126536," +
736                "126537-126538,126539-126540,126541-126544,126545-126547,126548-126549,126551-126552,126553-126554,126555-126556,126557-126558,126559-126560," +
737                "126561-126563,126564-126565,126567-126571,126572-126579,126580-126584,126585-126589,126590-126591,126592-126602,126603-126620,126625-126628," +
738                "126629-126634,126635-126652,127232-127245,131072-173783,173824-177973,177984-178206,178208-183970,194560-195102,917760-918000",
739                stWordSymbols
740            );
741        }
742        if (stWordSymbols.checkContains(codePoint))
743            return true;
744        return false;
745    }
746    function toCodePoints(str)
747    {
748        var chars = [];
749        for (var lengthProcessed = 0; lengthProcessed < str.length;)
750        {
751         var ch = str.codePointAt(lengthProcessed);
752         chars.push(ch);
753         if (ch > 0xffff)
754          lengthProcessed += 2;
755         else
756          ++lengthProcessed;
757        }
758        return chars;
759    }
760    function fromCodePoints(chars)
761    {
762     return String.fromCodePoint.apply(null, chars);
763    }
764    function splitString(str)
765    {
766        var chars = toCodePoints(str);
767        var result = new Array();
768        var word = new Array();
769        for (var i = 0; i <= chars.length; ++i)
770        {
771            if (i != chars.length && isWordSymbol(chars[i]) && !isPunctuationSymbol(chars[i]))
772            {
773                word.push(chars[i]);
774            }
775            else
776            {
777                if (word.length != 0)
778                {
779                    result.push(fromCodePoints(word));
780                    word = new Array();
781                }
782            }
783        }
784        return result;
785    }
786    var API = {
787        splitString: function(str) {
788            return splitString(str);
789        }
790    };
791
792    return API;
793})();
794
795/*js/drexplain/drexplain.search-engine.js*/
796DR_EXPLAIN.namespace( 'DR_EXPLAIN.searchEngine' );
797DR_EXPLAIN.searchEngine = (function() {
798    function isRemoteSearch()
799    {
800        return window.location.protocol === 'https:' || window.location.protocol === 'http:';
801    }
802    /**
803    * Append a tag to the properties of an object for each item in an array
804    *
805    * @param {Object} tags
806    *         The object whose property values will be modified
807    * @param {Array} items
808    *         The list of property names to set on the object
809    * @param {String} tag
810    *         The value to append to each property value in the object
811    */
812    function setTag(tags, items, tag) {
813        for (var i = 0; i < items.length; i++) {
814            var item = items[i];
815
816            if (tags.hasOwnProperty(item)) {
817                tags[item] += tag;
818            } else {
819                tags[item] = tag;
820            }
821        }
822    }
823
824    /**
825    * Return a filtered list of property names for the specified object.
826    * Each property value that causes the specified match function to
827    * return true will be returned in the resulting array
828    *
829    * @param {Object} tags
830    *         The object whose property names will be filtered
831    * @param {Function} matchFunction
832    *         A function that takes a single parameter, returning true or
833    *         false based on the value of that parameter. "filter" will pass
834    *         in each property name of the "tags" object to determine if it
835    *         should be included in the resulting array
836    * @return {Array} Returns an array of property names whose values
837    *         were accepted by the matchFunction
838    */
839    function filter(tags, matchFunction) {
840        var result = [];
841
842        for (var p in tags) {
843            if (matchFunction(tags[p])) {
844                result.push(p);
845            }
846        }
847
848        return result;
849    }
850
851    /**
852    * Find the intersection of two sets
853    *
854    * @param {Array} setA
855    * @param {Array} setB
856    * @return {Array} Returns the result of this set operation
857    */
858    function intersect(setA, setB) {
859        var tags = {};
860
861        setTag(tags, setA, "A");
862        setTag(tags, setB, "B");
863
864        return filter(tags, function(value) { return value == "AB" });
865    }
866
867    /**
868    * Find the difference of two sets
869    *
870    * @param {Array} setA
871    * @param {Array} setB
872    * @return {Array} Returns the result of this set operation
873    */
874    function difference(setA, setB) {
875        var tags = {};
876
877        setTag(tags, setA, "A");
878        setTag(tags, setB, "B");
879
880        return filter(tags, function(value) { return value != "AB" });
881    }
882
883    /**
884    * Remove all members of setA from setB
885    *
886    * @param {Array} setA
887    * @param {Array} setB
888    * @return {Array} Returns the result of this operation
889    */
890    function remove(setA, setB) {
891        var tags = {};
892
893        setTag(tags, setA, "A");
894        setTag(tags, setB, "B");
895
896        return filter(tags, function(value) { return value == "B" });
897    }
898    function unite(setA, setB)
899    {
900        var tags = {};
901
902        setTag(tags, setA, "A");
903        setTag(tags, setB, "B");
904        return filter(tags, function(value) { return true;});
905    }
906    /**
907     * @author 1
908     */
909    /*
910    var strFoundNothing = "Nothing was found";
911    var strSearchStringIsEmpty = "Please, enter a string for search!";
912    var strSearchInProgress = "Searching...";
913    */
914
915    var IndexOfFiles = new Array();
916    var StringsForSearch = new Array();
917    var StringPairArray = new Array();
918    var SearchResults=new Array();
919    var iStringToSearch=0;
920    var HTTP = {};
921
922    HTTP.newRequest = function()
923    {
924        var xmlhttp=false;
925        /* running locally on IE5.5, IE6, IE7 */                                              
926        if(location.protocol=="file:"){
927            if(!xmlhttp)try{ xmlhttp=new ActiveXObject("MSXML2.XMLHTTP"); }catch(e){xmlhttp=false;}
928            if(!xmlhttp)try{ xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){xmlhttp=false;}
929        }                                                                                
930        /* IE7, Firefox, Safari, Opera...  */
931        if(!xmlhttp)try{ xmlhttp=new XMLHttpRequest(); }catch(e){xmlhttp=false;}
932        /* IE6 */
933        if(typeof ActiveXObject != "undefined"){
934            if(!xmlhttp)try{ xmlhttp=new ActiveXObject("MSXML2.XMLHTTP"); }catch(e){xmlhttp=false;}
935            if(!xmlhttp)try{ xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){xmlhttp=false;}
936        }
937        /* IceBrowser */
938        if(!xmlhttp)try{ xmlhttp=createRequest(); }catch(e){xmlhttp=false;}
939
940        if (!xmlhttp)
941        {
942            throw new Error("Failed to initialize XMLHttpRequest");
943        }
944        return xmlhttp;
945    };
946
947
948    var request = HTTP.newRequest();
949
950    function ID()
951    {
952        if (!SearchResults.length) getSearchResultOutput();
953        var sID = dirname() + "/de_search/ids.json";
954        request.open("GET", sID, true);
955        request.onreadystatechange = function()
956        {
957            if (request.readyState == 4)
958            if (request.status == 200 || request.status == 0)
959            {
960                var arrFileId;
961                try
962                {
963                    arrFileId = JSON.parse(request.responseText);
964                }
965                catch(e)
966                {
967                    //Something is wrong, abort search
968                    SearchResults = new Array();
969                    SearchResults[0] = new Array();
970                    SearchResults[0][0] = "Error!";
971                    SearchResults[0][1] = "mailto:[email protected]";
972                    getSearchResultOutput();
973                    return;
974                }
975
976                var id;
977                for (var i = 0; i < SearchResults.length; i++)
978                {
979                    id = SearchResults[i];
980                    SearchResults[i] = new Array();
981                    SearchResults[i][0] = arrFileId[id][0];
982                    SearchResults[i][1] = arrFileId[id][1];
983                }
984                getSearchResultOutput();
985            }
986        }
987        request.send(null);
988
989    }
990
991    function getSearchResultOutput()
992    {
993        $( document ).trigger( "searchComplete" );
994    }
995
996    function SearchInFile()
997    {
998        if (request.readyState != 4) return;
999        if (request.status != 200 && request.status != 0)  return;
1000
1001        var arrFileStrings;
1002        try
1003        {
1004            arrFileStrings = JSON.parse(request.responseText);
1005        }
1006        catch(e)
1007        {
1008            return;
1009        }
1010
1011        var stToSearch      = StringPairArray[iStringToSearch][0];
1012
1013        var isFirstIteration = true;
1014        var wasFound        = false;
1015        var curResults = new Array();
1016        for (var i = 0; i < arrFileStrings.length; i++)
1017        {
1018            if (arrFileStrings[i].s.indexOf(stToSearch) == 0)
1019            {
1020                curResults = unite(curResults, arrFileStrings[i].p);
1021                wasFound = true;
1022            }
1023        }
1024        if (iStringToSearch == 0) //this is first result - adding all curResults to SearchResults
1025            SearchResults = SearchResults.concat(curResults);
1026        else
1027            SearchResults = intersect(SearchResults, curResults);
1028        // If there are no results after a certain iteration then there's no sense to AND-search anymore
1029        if (!SearchResults.length) return getSearchResultOutput();
1030        iStringToSearch++;
1031        SearchForNextString();
1032    }
1033
1034
1035
1036    function SearchForNextString()
1037    {
1038        if (iStringToSearch >= StringsForSearch.length) return ID();
1039        var sURL = dirname() + "/de_search/"+StringPairArray[iStringToSearch][1];
1040        request.open("GET", sURL, true);
1041        request.onreadystatechange = SearchInFile;
1042        request.send(null);
1043    }
1044    function strcmp ( str1, str2 ) {
1045        // Binary safe string comparison
1046        //
1047        // version: 909.322
1048        // discuss at: http://phpjs.org/functions/strcmp
1049        // +   original by: Waldo Malqui Silva
1050        // +      input by: Steve Hilder
1051        // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
1052        // +    revised by: gorthaur
1053        // *     example 1: strcmp( 'waldo', 'owald' );
1054        // *     returns 1: 1
1055        // *     example 2: strcmp( 'owald', 'waldo' );
1056        // *     returns 2: -1
1057        return ( ( str1 == str2 ) ? 0 : ( ( str1 > str2 ) ? 1 : -1 ) );
1058    }
1059    function AttachFilesToStrings()
1060    {
1061        for (var i = 0; i < StringsForSearch.length; i++)
1062        {
1063            var st = StringsForSearch[i].toUpperCase();
1064            var st1 = st.substr(0,1);
1065            var j = 0;
1066            var bFound = -1;
1067            while (j < IndexOfFiles.length && bFound == -1)
1068            {
1069                switch (strcmp(st1, IndexOfFiles[j].first.substr(0,1)))
1070                {
1071                    case 0: bFound = true; break;
1072                    case -1: bFound = false; break;
1073                    case 1: ++j;
1074                }
1075            }
1076            if (bFound == -1 || bFound == false)
1077            {
1078                getSearchResultOutput();
1079                return;
1080            }
1081            //We have found words beginning with first letter of st
1082            bFound = false;
1083            switch (strcmp(st, IndexOfFiles[j].first))
1084            {
1085                case -1:
1086                {
1087                    if (IndexOfFiles[j].first.indexOf(st) == 0) //st = 'skin', IndexOfFiles[j].first = 'skinner'
1088                        bFound = true;
1089                    break;
1090                }
1091                case 0:
1092                {
1093                    bFound = true;
1094                    break;
1095                }
1096                case 1: //st = 'skinner', IndexOfFiles[j].first = 'skin'
1097                {
1098                    switch (strcmp(st, IndexOfFiles[j].last))
1099                    {
1100                        case -1:
1101                        case 0:
1102                        {
1103                            bFound = true;
1104                            break;
1105                        }
1106                        case 1:
1107                        {
1108                            if (st.indexOf(IndexOfFiles[j].last) == 0) //st = 'skinner', IndexOfFiles[j].last = 'skin'
1109                                bFound = true;
1110                            break;
1111                        }
1112                    }
1113                }
1114            }
1115            if (!bFound)
1116            {
1117                getSearchResultOutput();
1118                return;
1119            }
1120
1121            //Replace strings for search with pairs (string,index file)
1122            StringPairArray[i] = new Array();
1123            StringPairArray[i][0]=st;
1124            StringPairArray[i][1]=IndexOfFiles[j].fileName;
1125        }
1126        SearchResults=new Array();
1127        iStringToSearch=0;
1128        SearchForNextString();
1129    }
1130
1131    //Downloads prefixes.json
1132    //Fills IndexOfFiles array
1133    function GetIndex()
1134    {
1135        SearchResults=new Array();
1136        NextStringToSearch=0; //?
1137        var sURL = dirname() + "/de_search/prefixes.json";
1138        request.open("GET", sURL);
1139        request.onreadystatechange = function() {
1140            if (request.readyState === 4)
1141            {
1142                if (request.status === 200 || request.status === 0 && request.responseText !== '')
1143                {
1144                    try
1145                    {
1146                        IndexOfFiles = JSON.parse(request.responseText);
1147                    }
1148                    catch(e)
1149                    {
1150                        $(document).trigger("searchError");
1151                        if (isRemoteSearch())
1152                            DR_EXPLAIN.searchManager.showRemoteSearchError(-34);
1153                        else
1154                            DR_EXPLAIN.searchManager.showLocalSearchError();
1155                        return;
1156                    }
1157                    AttachFilesToStrings();
1158                }
1159                else
1160                {
1161                    $(document).trigger("searchError");
1162                    if (isRemoteSearch())
1163                        DR_EXPLAIN.searchManager.showRemoteSearchError(request.status);
1164                    else
1165                        DR_EXPLAIN.searchManager.showLocalSearchError();
1166                }
1167            }
1168        };
1169        request.send(null);
1170    }
1171
1172    function dirname()
1173    {
1174        var retValue = window.location.href;
1175        retValue = retValue.substring(0, retValue.lastIndexOf('/'));
1176        return retValue;
1177    }
1178
1179    function reverse(str) {
1180        if(!str) return str;
1181        return str.charAt(str.length-1) + reverse(str.substring(0,str.length-1));
1182    }
1183
1184    function trimLeft(str) {
1185        for (var i=0; str.charAt(i) == ' '; i++);
1186        return str.substring(i, str.length);
1187    }
1188
1189    function trimRight(str) {
1190        return reverse(trimLeft(reverse(str)));
1191    }
1192
1193    function trim(str) {
1194        return trimRight(trimLeft(str));
1195    }
1196
1197    function isEmpty(sToCheck) {
1198        var sTest;
1199        sTest = trim(sToCheck)
1200        if (sTest == null || sTest == "") {
1201            return true;
1202        }
1203        return false;
1204    }
1205
1206    function searchmain(str)
1207    {
1208        $( document ).trigger( "searchBegin" );
1209        SearchResults=new Array();
1210        iStringToSearch=0;
1211
1212        //Split the string into words
1213        var strs = DR_EXPLAIN.wordSplitter.splitString(str);
1214        StringsForSearch = new Array();
1215        for (var i = 0; i < strs.length; ++i)
1216            if (!isEmpty(strs[i]))
1217                StringsForSearch.push(strs[i]);
1218        //Download index.txt asynchronously and fill array of indexes
1219        GetIndex();
1220
1221        return 1;
1222    }
1223
1224    function max(a,b){
1225        return a>b?a:b;
1226    }
1227    function min(a,b){
1228        return a<b?a:b;
1229    }
1230
1231
1232
1233    var API = {
1234        trim: function( str ) {
1235            return trim( str );
1236        },
1237
1238        doSearch: function( str ) {
1239            return searchmain( str );
1240        },
1241
1242        getSearchResults: function() {
1243            return SearchResults;
1244        }
1245    };
1246
1247    return API;
1248
1249
1250})();
1251
1252
1253/*js/drexplain/drexplain.search-manager.js*/
1254DR_EXPLAIN.namespace( 'DR_EXPLAIN.searchManager' );
1255DR_EXPLAIN.searchManager = (function(){
1256    var _class = {
1257        elementsArr: null,
1258        isFirstSearch: true,
1259        dom: null,
1260        highlightManager: null,
1261        dataManager: null,
1262        urlEncoder: null,
1263        searchEngine: null,
1264        wordSplitter: null,
1265
1266
1267        init: function() {
1268            this.doSetDom();
1269            this.doSetHighlightManager();
1270            this.doSetDataManager();
1271            this.doSetNavTreeSearch();
1272            this.doSetUrlEncoder();
1273            this.doSetSearchEngine();
1274            this.doSetSearchInProgressText();
1275            this.doSetWordSplitter();
1276        },
1277
1278        doSetSearchInProgressText: function() {
1279            this.dom.$searchProgress.prop( "alt", this.dataManager.getSearchTextInProgress() );
1280        },
1281
1282        doSetHighlightManager: function() {
1283            this.highlightManager = DR_EXPLAIN.highlightManager;
1284        },
1285
1286        doSetDataManager: function() {
1287            this.dataManager = DR_EXPLAIN.dataManager;
1288        },
1289
1290        doSearchIfQueryStringNotEmpty: function() {
1291            this.doSetQueryStringByUrlEncoder();
1292            if ( this.elementsArr[ 0 ].$input.prop( "value" ) !== '' ) {
1293                this.elementsArr[ 0 ].$submit.trigger( "click" );
1294            }
1295        },
1296
1297        runCustomButtons: function() {
1298            var searchInWorkZone = new CustomButton( this.dom.$workZoneSearchSubmit );
1299            searchInWorkZone.run();
1300
1301            var searchInTab = new CustomButton( this.dom.$tabSearchSubmit );
1302            searchInTab.run();
1303        },
1304
1305        runInputPlaceholders: function() {
1306            var searchInTabPlaceholder = new InputPlaceholder( this.dom.$tabSearchInput, this.dom.$tabSearchInputLabel, true );
1307            searchInTabPlaceholder.run();
1308
1309            var searchInWorkZonePlaceholder = new InputPlaceholder( this.dom.$workZoneSearchInput, this.dom.$workZoneSearchInputLabel, true );
1310            searchInWorkZonePlaceholder.run();
1311        },
1312
1313        runInputSync: function() {
1314            var that = this;
1315
1316            var $inputArr = this.dom.$tabSearchInput.add( this.dom.$workZoneSearchInput );
1317            var inputSync = new InputSync( $inputArr );
1318            inputSync.run();
1319
1320            this.dom.$workZoneSearchSubmit.on( "click",function() {
1321                that.dom.$tabSelectorSearch.click();
1322            });
1323        },
1324
1325        doSetNavTreeSearch: function() {
1326            this.navTreeSearch = DR_EXPLAIN.navTree_Search;
1327        },
1328
1329        doSetDom: function() {
1330            this.dom = DR_EXPLAIN.dom;
1331            this.elementsArr = [
1332                                { $input: this.dom.$tabSearchInput, $submit: this.dom.$tabSearchSubmit },
1333                                { $input: this.dom.$workZoneSearchInput, $submit: this.dom.$workZoneSearchSubmit }
1334                            ];
1335        },
1336
1337        doSetUrlEncoder: function() {
1338            var that = this;
1339
1340            this.urlEncoder = DR_EXPLAIN.urlEncoder;
1341            this.urlEncoder.addSaveFunc(
1342                    function() {
1343                        if ( that.isSearchTabSelected() ) {
1344                            return that.getSearchQuery();
1345                        }
1346                        else {
1347                            return "";
1348                        }
1349
1350                    },
1351                    this.urlEncoder.KEY_NAME__SEARCH_QUERY
1352                );
1353        },
1354
1355        doSetSearchEngine: function() {
1356            this.searchEngine = DR_EXPLAIN.searchEngine;
1357        },
1358
1359        doSetWordSplitter: function() {
1360            this.wordSplitter = DR_EXPLAIN.wordSplitter;
1361        },
1362
1363
1364        setUrlEncoder: function( urlEncoder, urlEncoderKeyName ) {
1365            this.urlEncoder = urlEncoder;
1366            this.urlEncoderKey = urlEncoderKeyName;
1367        },
1368
1369        doSetQueryStringByUrlEncoder: function() {
1370            if( this.urlEncoder !== null ) {
1371                var queryString = this.urlEncoder.getValueByKey( this.urlEncoder.KEY_NAME__SEARCH_QUERY );
1372                if ( queryString !== null ) {
1373                    for ( var index = 0; index < this.elementsArr.length; index += 1 ) {
1374                        this.elementsArr[ index ].$input.prop( "value", queryString );
1375                        this.elementsArr[ index ].$input.trigger( "keypressSync" );
1376                    }
1377                }
1378            }
1379        },
1380
1381        doBindEvents: function() {
1382            for ( var index = 0; index < this.elementsArr.length; index += 1 ) {
1383                this.bindEventToElement( this.elementsArr[ index ] );
1384            }
1385
1386            var that = this;
1387
1388            $( document ).on( "searchComplete.search", function() {
1389                that.searchComplete();
1390                that.hideSearchProgress();
1391            });
1392
1393            $( document ).on( "searchBegin.search", function() {
1394                that.showSearchProgress();
1395            });
1396
1397            $( document ).on( "searchError.search", function() {
1398                that.hideSearchProgress();
1399            });
1400        },
1401
1402        hideSearchProgress: function() {
1403            if ( this.dom.$searchProgress.is( ":visible" ) ) {
1404                this.dom.$searchProgress.fadeOut( 333 );
1405            }
1406            else {
1407                this.dom.$searchProgress.css( "display", "none" );
1408            }
1409
1410        },
1411
1412        showSearchProgress: function() {
1413            $( "#searchProgress" ).fadeIn( 333 );
1414        },
1415
1416        bindEventToElement: function( elem ) {
1417            var that = this;
1418            elem.$submit.closest( "form" ).on( "submit", function( e ){
1419                elem.$input.blur();
1420                that.dom.$tabSelectorSearch.click();
1421                that.onClick( elem );
1422                return false;
1423            });
1424        },
1425
1426        onClick: function( elem ) {
1427            var s = this.searchEngine.trim(document.getElementById( elem.$input.prop( "id" ) ).value).replace(/\r/g,'').replace(/\n/g,'').replace(/\t/g,' ').replace(/\u00A0/g,'');
1428            s = s.replace(/[,;]/g, ' ');
1429            this.performSearch(s);
1430        },
1431
1432        performSearch: function( s ) {
1433            var queryArray = this.wordSplitter.splitString(s);
1434            var output = '';
1435            if (queryArray.length == 0 || queryArray[0] == '')
1436                this.showSearchTextEmptyString();
1437            else
1438                this.searchEngine.doSearch(s);
1439        },
1440
1441        searchComplete: function() {
1442            this.highlightManager.hide();
1443            var searchResultsArr = this.searchEngine.getSearchResults();
1444            if ( searchResultsArr.length > 0 ) {
1445                this.navTreeSearch.setNewContentBySearchResults( searchResultsArr );
1446                this.navTreeSearch.show();
1447                $( document ).trigger( "searchCompleteBuildTree" );
1448
1449
1450                var searchQuery = this.getSearchQuery();
1451                var searchQueryArr = this.wordSplitter.splitString(searchQuery);
1452                this.highlightManager.show( searchQueryArr );
1453
1454                if ( this.isFirstSearch && this.isSearchTabSelectedOnStart() ) {
1455                    if ( this.isFirstSearch ) {
1456                        $( document ).trigger( "firstSearchCompleteWithSelectedSearchTab" );
1457                        this.isFirstSearch = false;
1458                    }
1459
1460                }
1461            }
1462            else {
1463                var $msg = $( '<div class="b-tree__searchResultText">' + this.dataManager.getSearchTextNoResults() + '</div>' );
1464                this.dom.tabs.search.$tree.html( $msg );
1465                $( document ).trigger( "searchCompleteBuildTree" );
1466            }
1467        },
1468
1469        showSearchTextEmptyString: function() {
1470            this.highlightManager.hide();
1471            var $msg = $( '<div class="b-tree__searchResultText">' + this.dataManager.getSearchTextEmptyString() + '</div>' );
1472            this.dom.tabs.search.$tree.html( $msg );
1473            $( document ).trigger( "searchCompleteBuildTree" );
1474        },
1475
1476        showLocalSearchError: function() {
1477            this.highlightManager.hide();
1478            var $msg = $( '<div class="b-tree__searchResultText">' + this.dataManager.getErrorInLocalSearch() + '</div>' );
1479            this.dom.tabs.search.$tree.html( $msg );
1480            $( document ).trigger( "searchCompleteBuildTree" );
1481        },
1482
1483        showRemoteSearchError: function(code) {
1484            this.highlightManager.hide();
1485            var $msg = $( '<div class="b-tree__searchResultText">' + this.dataManager.getErrorInRemoteSearch(code) + '</div>' );
1486            this.dom.tabs.search.$tree.html( $msg );
1487            $( document ).trigger( "searchCompleteBuildTree" );
1488        },
1489
1490        isSearchTabSelected: function() {
1491            var $navTree_search = this.dom.tabs.search.$wrapperItem;
1492            if ( $navTree_search.hasClass( "m-tabs__wrapperItem__selected" ) ) {
1493                return true;
1494            }
1495            else {
1496                return false;
1497            }
1498        },
1499
1500        isSearchTabSelectedOnStart: function() {
1501            var $navTree_search = this.dom.tabs.search.$wrapperItem;
1502            if ( $navTree_search.index() === parseInt( this.urlEncoder.getValueByKey( this.urlEncoder.KEY_NAME__TAB_INDEX ) ) ) {
1503                return true;
1504            }
1505            else {
1506                return false;
1507            }
1508        },
1509
1510        getSearchQuery: function() {
1511            if ( this.elementsArr[ 0 ] !== undefined ) {
1512                return this.elementsArr[ 0 ].$input.prop( "value" );
1513            }
1514            else {
1515                return null;
1516            }
1517        },
1518
1519        isSearchQueryNotEmpty: function() {
1520            var query = this.getSearchQuery();
1521            if ( query !== null ) {
1522                if ( query !== '' ) {
1523                    return true;
1524                }
1525            }
1526            return false;
1527        }
1528    };
1529
1530    var API = {
1531        init: function() {
1532            _class.init();
1533        },
1534
1535        runCustomButtons: function() {
1536            _class.runCustomButtons();
1537        },
1538
1539        runInputSync: function() {
1540            _class.runInputSync();
1541        },
1542
1543        runInputPlaceholders: function() {
1544            _class.runInputPlaceholders();
1545        },
1546
1547        doBindEvents: function() {
1548            _class.doBindEvents();
1549        },
1550
1551        doSearchIfQueryStringNotEmpty: function() {
1552            _class.doSearchIfQueryStringNotEmpty();
1553        },
1554
1555        showLocalSearchError: function() {
1556            _class.showLocalSearchError();
1557        },
1558
1559        showRemoteSearchError: function(code) {
1560            _class.showRemoteSearchError(code);
1561        }
1562    };
1563
1564    return API;
1565})();
1566
1567
1568/*js/drexplain/drexplain.highlight-manager.js*/
1569DR_EXPLAIN.namespace( 'DR_EXPLAIN.highlightManager' );
1570DR_EXPLAIN.highlightManager = (function(){
1571
1572    var _class = {
1573        dom: null,
1574        $content: null,
1575
1576        init: function() {
1577            this.doSetDom();
1578        },
1579
1580        doSetDom: function() {
1581            this.dom = DR_EXPLAIN.dom;
1582            this.$content = this.dom.$articleInnerWrapper;
1583        },
1584
1585        show: function( wordsArr ) {
1586            this.hide();
1587            var tempArr = new Array();
1588            for ( var index = 0; index < wordsArr.length; index += 1 )
1589                tempArr.push(wordsArr[index]);
1590            tempArr.sort(function(a, b){
1591                a = a.toUpperCase();
1592                b = b.toUpperCase();
1593                if (a < b) return -1;
1594                if (a > b) return 1;
1595                return 0;
1596            }).reverse();
1597            for ( var index = 0; index < tempArr.length; index += 1 ) {
1598                this.$content.highlight( tempArr[ index ] );
1599            }
1600            this.hideFromCopyright();
1601        },
1602
1603        hide: function() {
1604            this.$content.removeHighlight();
1605        },
1606
1607        hideFromCopyright: function() {
1608            this.dom.$articleGeneratorCopyright.removeHighlight();
1609        }
1610    };
1611
1612    var API = {
1613        init: function() {
1614            _class.init();
1615        },
1616        show: function( wordsArr ) {
1617            _class.show( wordsArr );
1618        },
1619        hide: function() {
1620            _class.hide();
1621        }
1622    };
1623
1624    return API;
1625})();
1626
1627
1628/*js/drexplain/drexplain.tab-controller.js*/
1629DR_EXPLAIN.namespace( 'DR_EXPLAIN.tabController' );
1630
1631DR_EXPLAIN.tabController = (function(){
1632    var _class = {
1633        DREX_SHOW_MENU: 1,
1634        DREX_SHOW_SEARCH: 1,
1635        DREX_SHOW_INDEX: 1,
1636        DREXPLAIN_MAKE_TAB_COUNT: 3,
1637
1638        tabArr: [],
1639        urlEncoder: null,
1640        dom: null,
1641
1642        init: function() {
1643
1644            this.doSetDom();
1645            this.doSetUrlEncoder();
1646            this.doAddTabs();
1647        },
1648
1649        addTab: function( $tabSelector, $tabWrapper, $tabWrapperInner ) {
1650            this.tabArr.push({
1651                $selector: $tabSelector,
1652                $wrapper: $tabWrapper,
1653                $wrapperInner: $tabWrapperInner,
1654                scrollTop: 0
1655            });
1656        },
1657
1658        doSetDom: function() {
1659            this.dom = DR_EXPLAIN.dom;
1660        },
1661
1662        doAddTabs: function() {
1663            if (this.DREX_SHOW_MENU)
1664                this.addTab( this.dom.tabs.menu.$selectorItem , this.dom.tabs.menu.$wrapperItem, this.dom.tabs.menu.$wrapperItemInner );
1665            if (this.DREX_SHOW_INDEX)
1666                this.addTab( this.dom.tabs.index.$selectorItem , this.dom.tabs.index.$wrapperItem, this.dom.tabs.index.$wrapperItemInner );
1667            if (this.DREX_SHOW_SEARCH)
1668                this.addTab( this.dom.tabs.search.$selectorItem , this.dom.tabs.search.$wrapperItem, this.dom.tabs.search.$wrapperItemInner );
1669        },
1670
1671        doSetUrlEncoder: function() {
1672            var that  = this;
1673            this.urlEncoder = DR_EXPLAIN.urlEncoder;
1674
1675
1676            this.urlEncoder.addSaveFunc(
1677                    function() {
1678                        return that.getSelectedTabIndex();
1679                    },
1680                    that.urlEncoder.KEY_NAME__TAB_INDEX
1681                );
1682
1683            this.urlEncoder.addSaveFunc(
1684                    function() {
1685                        return that.getVisibleTabScrollTop();
1686                    },
1687                    that.urlEncoder.KEY_NAME__MENU_SCROLL_TOP
1688            );
1689        },
1690
1691        getVisibleTabScrollTop: function() {
1692            var selectedTab = this.getSelectedTab();
1693            if (!selectedTab)
1694                return 0;
1695            var $wrapperItemInner = selectedTab.$wrapperInner;
1696            var scrollTop = 0;
1697            if ( $wrapperItemInner !== null ) {
1698                scrollTop = $wrapperItemInner.scrollTop();
1699            }
1700
1701            return scrollTop;
1702        },
1703
1704        doSetScrollTopByUrlEncoder: function() {
1705            if( this.urlEncoder !== null ) {
1706                var scrollTop = this.urlEncoder.getValueByKey( this.urlEncoder.KEY_NAME__MENU_SCROLL_TOP );
1707                if ( scrollTop !== null ) {
1708                    var selectedTab = this.getSelectedTab();
1709                    if (!selectedTab)
1710                        return;
1711                    var $visibleWrapperItemInner = selectedTab.$wrapperInner;
1712                    $visibleWrapperItemInner.scrollTop( scrollTop ).trigger( "scroll" );
1713                }
1714                else {
1715                    var $selectedTreeElem = this.dom.tabs.menu.$tree.find( ".m-tree__itemContent__selected" );
1716                    if ( $selectedTreeElem.length > 0 ) {
1717                        var selectedTreeElemTop = ( $selectedTreeElem.offset() ).top - ( this.dom.$tabWrapperItems.offset() ).top - $selectedTreeElem.height() / 2;
1718                        this.dom.tabs.menu.$wrapperItemInner.scrollTop( selectedTreeElemTop  ).trigger( "scroll" );
1719                    }
1720                }
1721            }
1722        },
1723
1724        doSetTabIndexByUrlEncoder: function() {
1725            if( this.urlEncoder !== null ) {
1726                var tabIndex = this.urlEncoder.getValueByKey( this.urlEncoder.KEY_NAME__TAB_INDEX );
1727                if ( tabIndex !== null ) {
1728                    if ( this.tabArr[ tabIndex ] !== undefined ) {
1729                        this.toggleTabState( this.tabArr[ tabIndex ].$selector );
1730                    }
1731                }
1732            }
1733        },
1734
1735        doBindEvents: function() {
1736            for ( var index = 0; index < this.tabArr.length; index += 1 ) {
1737                this.doBindEventToggleState( index );
1738                this.doBindScrollTopSaver( index );
1739            }
1740
1741            this.doBindEventHover();
1742            var that = this;
1743            $( document ).on( "navResize",function() {
1744                that.doSetScrollPositionToSelectedTab();
1745            });
1746            $( document ).on( "firstSearchCompleteWithSelectedSearchTab",function() {
1747                that.doSetScrollTopByUrlEncoder();
1748            });
1749        },
1750
1751        doBindEventToggleState: function( index ) {
1752            var that = this;
1753
1754            this.tabArr[ index ].$selector.click(function(){
1755                if ( !$( this ).hasClass( "m-tabs__selectorItem__selected" ) ) {
1756                    that.toggleTabState( $( this ) );
1757                    $( window ).resize();
1758                }
1759            });
1760        },
1761
1762        doBindScrollTopSaver: function( index ) {
1763            var that = this;
1764
1765            this.tabArr[ index ].$wrapperInner.on( "scroll", function() {
1766                that.tabArr[ index ].scrollTop = $( this ).scrollTop();
1767            });
1768        },
1769
1770        doBindEventHover: function() {
1771            if (this.tabArr.length == 0)
1772                return;
1773
1774            var $selectorItems = this.tabArr[ 0 ].$selector.parent();
1775
1776            $selectorItems.on( "mouseenter", ".b-tabs__selectorItem", function(){
1777                if ( $( this ).hasClass( "m-tabs__selectorItem__selected") )
1778                    return false;
1779                $( this ).addClass( "m-tabs__selectorItem__hovered" );
1780            });
1781
1782            $selectorItems.on( "mouseleave", ".b-tabs__selectorItem", function(){
1783                if ( $( this ).hasClass( "m-tabs__selectorItem__selected") )
1784                    return false;
1785                $( this ).removeClass( "m-tabs__selectorItem__hovered" );
1786            });
1787        },
1788
1789        toggleTabState: function( $selectedTabSelector ) {
1790            for ( var index = 0; index < this.tabArr.length; index += 1 ) {
1791                var $currTabSelector = this.tabArr[ index ].$selector;
1792                if ( $currTabSelector.prop( "id" ) === $selectedTabSelector.prop( "id" ) ) {
1793                    this.showTabByIndex( index );
1794                }
1795                else {
1796                    this.hideTabByIndex( index );
1797                }
1798            }
1799
1800            $( document ).trigger( "newTabSelected.tabs" );
1801        },
1802
1803        showTabByIndex: function( index ) {
1804            if (index == -1)
1805                return;
1806            var $tabSelector = this.tabArr[ index ].$selector;
1807            var $tabWrapper = this.tabArr[ index ].$wrapper;
1808            var $tabWrapperInner = this.tabArr[ index ].$wrapperInner;
1809            var scrollTop = this.tabArr[ index ].scrollTop;
1810
1811            //console.log( 'show tab: %s %s', $tabSelector.prop( "id" ), $tabWrapper.prop( "id" ) );
1812
1813            $tabSelector.
1814                addClass( "m-tabs__selectorItem__selected" ).
1815                removeClass( "m-tabs__selectorItem__hovered" ).
1816                removeClass( "m-tabs__selectorItem__unselected" );
1817
1818            $tabWrapper.addClass( "m-tabs__wrapperItem__selected" );
1819            $tabWrapperInner.scrollTop( scrollTop );
1820        },
1821
1822        hideTabByIndex: function( index ) {
1823            var $tabSelector = this.tabArr[ index ].$selector;
1824            var $tabWrapper = this.tabArr[ index ].$wrapper;
1825
1826            //console.log( 'hide tab: %s %s', $tabSelector.prop( "id" ), $tabWrapper.prop( "id" ) );
1827
1828
1829            $tabSelector.
1830                removeClass( "m-tabs__selectorItem__selected" ).
1831                addClass( "m-tabs__selectorItem__unselected" );
1832
1833            $tabWrapper.removeClass( "m-tabs__wrapperItem__selected" );
1834
1835        },
1836
1837        getSelectedTabIndex: function() {
1838            for ( var index = 0; index < this.tabArr.length; index += 1 ) {
1839                var $currTabSelector = this.tabArr[ index ].$selector;
1840                if ( $currTabSelector.hasClass( "m-tabs__selectorItem__selected" ) ) {
1841                    return index;
1842                }
1843            }
1844            if (this.tabArr.length == 0)
1845                return -1;
1846            return 0;
1847        },
1848
1849        getSelectedTab: function() {
1850            var selectedTabIndex = this.getSelectedTabIndex();
1851            if (selectedTabIndex == -1)
1852                return null;
1853            return this.tabArr[ selectedTabIndex ];
1854        },
1855
1856        doSetScrollPositionToSelectedTab: function() {
1857            var selectedTabIndex = this.getSelectedTabIndex();
1858            this.showTabByIndex( selectedTabIndex );
1859        }
1860    };
1861
1862    var API = {
1863        init: function() {
1864            _class.init();
1865        },
1866
1867        doBindEvents: function() {
1868            _class.doBindEvents();
1869        },
1870
1871        doSetTabIndexByUrlEncoder: function() {
1872            _class.doSetTabIndexByUrlEncoder();
1873        },
1874
1875        doSetScrollTopByUrlEncoder: function() {
1876            _class.doSetScrollTopByUrlEncoder();
1877        },
1878
1879        tabsCount: function() {
1880            return _class.DREXPLAIN_MAKE_TAB_COUNT;
1881        },
1882
1883        isMenuTabShown: function() {
1884            return _class.DREX_SHOW_MENU != 0;
1885        },
1886
1887        isSearchTabShown: function() {
1888            return _class.DREX_SHOW_SEARCH != 0;
1889        },
1890
1891        isIndexTabShown: function() {
1892            return _class.DREX_SHOW_INDEX != 0;
1893        }
1894    };
1895
1896    return API;
1897
1898})();
1899
1900
1901/*js/drexplain/drexplain.url-encoder.js*/
1902DR_EXPLAIN.namespace( 'DR_EXPLAIN.urlEncoder' );
1903DR_EXPLAIN.urlEncoder = (function(){
1904    var _class = {
1905
1906        urlDecoded: null,
1907        funcArr: [],
1908        utils: null,
1909        dom: null,
1910
1911        init: function() {
1912            this.utils = DR_EXPLAIN.utils;
1913            this.dom = DR_EXPLAIN.dom;
1914        },
1915
1916        doBindOpenNextPageWithEncodedStringToLinks: function() {
1917            var that = this;
1918            this.dom.$pageContent.on( "click", "a.local_link, a.b-breadCrumbs__link, a.b-controlButtons__link, a.b-tree__itemLink", function(e) {
1919                that.openNextPage( $( this ).prop( "href" ), $( this ).attr("href"), $( this ).prop( "target" ) == "_blank" );
1920                e.preventDefault();
1921                return false;
1922            });
1923        },
1924        doBindOpenNextPageWithEncodedStringToLinksInClonedNode: function() {
1925            var that = this;
1926            $(".cloned_node").on("click", "a", function(e) {
1927                that.openNextPage( $( this ).prop( "href" ), $( this ).attr("href"), $( this ).prop( "target" ) == "_blank" );
1928                e.preventDefault();
1929                return false;
1930            });
1931        },
1932
1933        doBindOpenNextPageWithEncodedStringToLinksInKeywordContextMenu: function() {
1934            var that = this;
1935            this.dom.$keywordContextMenu.on( "click", "a.b-tree__itemLink", function(e) {
1936                that.openNextPage( $( this ).prop( "href" ), $( this ).attr("href"), $( this ).prop( "target" ) == "_blank" );
1937                e.preventDefault();
1938                return false;
1939            });
1940        },
1941
1942
1943        openNextPage: function( nextpage, nextPageHref, atNewPage ) {
1944
1945            atNewPage = typeof(atNewPage) != 'undefined' ? atNewPage : false;
1946
1947            var stateParams = this.getEncodedUrl();
1948
1949            var targetUrl = nextpage;
1950            if (nextPageHref && nextPageHref.length > 0 && nextPageHref.charAt(0) == '#')
1951            {
1952                targetUrl = nextPageHref;
1953                nextpage = nextPageHref;
1954            }
1955            if ( $( "html" ).hasClass( "ie" ) )
1956                targetUrl = this.utils.escapeXml(nextpage);
1957            var anch = "";
1958            var anchPos = -1;
1959            if ((anchPos = nextpage.indexOf("#")) != -1) {
1960                targetUrl = nextpage.substr(0, anchPos);
1961                anch = nextpage.substr(anchPos);
1962            }
1963            targetUrl += "?" + stateParams + anch;
1964            window.open(targetUrl, atNewPage ? "_blank" : "_self");
1965        },
1966
1967
1968        doDecodeUrl: function() {
1969            var map = [];
1970            var urlParams = {};
1971                var e,
1972                    a = /\+/g,  // Regex for replacing addition symbol with a space
1973                    r = /([^&=]+)=?([^&]*)/g,
1974                    d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
1975                    q = window.location.search.substring(1);
1976
1977                while (e = r.exec(q))
1978                   urlParams[d(e[1])] = d(e[2]);
1979
1980            for ( var key in urlParams ) {
1981                var value = this.decodeString( urlParams[ key ] );
1982                map[key] = value;
1983            }
1984
1985            this.urlDecoded = map;
1986        },
1987
1988
1989        getValueByKey: function( key ) {
1990            if( this.urlDecoded[ key ] !== undefined ) {
1991                return this.urlDecoded[ key ];
1992            }
1993            else {
1994                return null;
1995            }
1996        },
1997
1998
1999        addSaveFunc: function( func, key ) {
2000            this.funcArr[ key ] = func;
2001        },
2002
2003        getEncodedUrl: function() {
2004            var result = "";
2005            for ( var key in this.funcArr ) {
2006                var currFunc = this.funcArr[ key ];
2007                var value = currFunc();
2008
2009                value = this.encodeString( value.toString() );
2010
2011                if ( value.toString().length > 0 ) {
2012                    if (result != "") {
2013                        result += "&";
2014                    }
2015                    result += key + "=" + encodeURIComponent(value);
2016                }
2017            }
2018            return result;
2019        },
2020
2021
2022        decodeString: function( str ) {
2023            var bits = this.utils.base64.decode(str, 0, true, true);
2024            if ( bits === null ) {
2025                return null;
2026            }
2027            var result = this.utils.ar2str(bits);
2028            result = this.utils.utf8.decode(result);
2029            return result;
2030        },
2031
2032        encodeString: function( str )
2033        {
2034            var compressedStr = str;
2035            var utfEncodedStr = this.utils.utf8.encode(compressedStr);
2036            var bitArray = this.utils.str2ar(utfEncodedStr);
2037            return this.utils.base64.encode(bitArray, false, true);
2038        }
2039    };
2040
2041    var API = {
2042        KEY_NAME__MENU_WIDTH: "mw",
2043        KEY_NAME__MENU_STATE: "ms",
2044        KEY_NAME__TAB_INDEX: "st",
2045        KEY_NAME__MENU_SCROLL_TOP: "sct",
2046        KEY_NAME__SEARCH_QUERY: "q",
2047
2048        init: function() {
2049            _class.init();
2050        },
2051
2052        doBindOpenNextPageWithEncodedStringToLinks: function() {
2053            _class.doBindOpenNextPageWithEncodedStringToLinks();
2054        },
2055
2056        doBindOpenNextPageWithEncodedStringToLinksInClonedNode: function() {
2057            _class.doBindOpenNextPageWithEncodedStringToLinksInClonedNode();
2058        },
2059
2060        doBindOpenNextPageWithEncodedStringToLinksInKeywordContextMenu: function() {
2061            _class.doBindOpenNextPageWithEncodedStringToLinksInKeywordContextMenu();
2062        },
2063
2064        doDecodeUrl: function() {
2065            _class.doDecodeUrl();
2066        },
2067
2068        getValueByKey: function( key ) {
2069            return _class.getValueByKey( key );
2070        },
2071
2072        addSaveFunc: function( func, key ) {
2073            _class.addSaveFunc(func, key);
2074        }
2075    };
2076
2077    return API;
2078})();
2079
2080
2081DR_EXPLAIN.namespace('DR_EXPLAIN.mapAreasKeeper');
2082
2083DR_EXPLAIN.mapAreasKeeper = (function($, Math) {
2084    var API = {
2085        recalculate: function() {
2086            $('map').each(function() {
2087                var $map = $(this);
2088                var $img = $('img[usemap="#' + $map.attr('id') + '"]');
2089                if ($img.length > 0) {
2090                    var originalWidth = $img.attr('width');
2091                    var realWidth = $img.width();
2092                    var horizCoef = realWidth / originalWidth;
2093
2094                    var originalHeight = $img.attr('height');
2095                    var realHeight = $img.height();
2096                    var vertCoef = realHeight / originalHeight;
2097
2098                    if (isFinite(horizCoef) && isFinite(vertCoef)) {
2099                        $map.find('area').each(function() {
2100                            var $area = $(this);
2101
2102                            var originalCoordLeft = parseInt($area.attr('data-coord-left'), 10);
2103                            var originalCoordTop = parseInt($area.attr('data-coord-top'), 10);
2104                            var originalCoordRight = parseInt($area.attr('data-coord-right'), 10);
2105                            var originalCoordBottom = parseInt($area.attr('data-coord-bottom'), 10);
2106
2107                            var coordLeft = Math.round(originalCoordLeft * horizCoef);
2108                            var coordTop = Math.round(originalCoordTop * vertCoef);
2109                            var coordRight = Math.round(originalCoordRight * horizCoef);
2110                            var coordBottom = Math.round(originalCoordBottom * vertCoef);
2111
2112                            var coordsAttr = [coordLeft, coordTop, coordRight, coordBottom].join(',');
2113                            $area.attr('coords', coordsAttr);
2114                        });
2115                    }
2116                }
2117            });
2118        }
2119    };
2120
2121    return API;
2122})($, Math);
2123
2124
2125/*js/drexplain/drexplain.work-zone-sizer.js*/
2126DR_EXPLAIN.namespace( 'DR_EXPLAIN.workZoneSizer' );
2127
2128DR_EXPLAIN.workZoneSizer = (function(){
2129    var _class = {
2130        NAV_MIN_WIDTH_DEFAULT: 250,
2131        ARTICLE_MIN_WIDTH_DEFAULT: 400,
2132        //IE_SCROLLBAR_SIZE: 24,
2133
2134        dom: null,
2135        dataManager: null,
2136        mapAreasKeeper: null,
2137
2138        currNavWidth: 0,
2139        currArticleWidth: 0,
2140        minNavWidth: null,
2141        maxNavWidth: null,
2142
2143        minArticleWidth: null,
2144
2145        visibleTabLongestTreeItemWidth: null,
2146
2147        preferredNavWidth: 0,
2148
2149        timeoutId: null,
2150        WINDOW_RECALCULATING_DELAY: 100,
2151
2152        init: function() {
2153            this.doSetCachedDom();
2154            this.doSetUrlEncoder();
2155            this.doSetDataManager();
2156            this.doSetNavMinWidth();
2157            this.doSetArticleMinWidth();
2158            if (!is_touch_device()) {
2159                this.doSetSplitter();
2160            }
2161            this.doSetFrameModeSizer();
2162            this.doSetFlowModeSizer();
2163            this.doSetCurrNavWidth();
2164            this.doSetMapAreasKeeper();
2165        },
2166
2167        doSetCachedDom: function() {
2168            this.dom = DR_EXPLAIN.dom;
2169        },
2170
2171        doSetDataManager: function() {
2172            this.dataManager = DR_EXPLAIN.dataManager;
2173        },
2174
2175        doSetMapAreasKeeper: function() {
2176            this.mapAreasKeeper = DR_EXPLAIN.mapAreasKeeper;
2177        },
2178
2179        doSetUrlEncoder: function() {
2180            var that = this;
2181
2182            this._urlEncoder = DR_EXPLAIN.urlEncoder;
2183            this._urlEncoder.addSaveFunc(function(){
2184                return that.currNavWidth;
2185            }, that._urlEncoder.KEY_NAME__MENU_WIDTH );
2186        },
2187
2188        doSetCurrNavWidth: function() {
2189            var currNavWidth = null;
2190            if( this._urlEncoder !== null ) {
2191                currNavWidth = this._urlEncoder.getValueByKey( this._urlEncoder.KEY_NAME__MENU_WIDTH );
2192                if ( currNavWidth !== null ) {
2193                    this.currNavWidth = currNavWidth;
2194                }
2195            }
2196
2197            if ( currNavWidth === null ) {
2198                var startingMenuWidth = this.dataManager.getStartingMenuWidth();
2199                if ( $.isNumeric( startingMenuWidth ) ) {
2200                    this.currNavWidth = startingMenuWidth;
2201                } else {
2202                    this.currNavWidth = this.dom.$workZoneSideNav.width();
2203                }
2204            }
2205
2206            this.preferredNavWidth = this.currNavWidth;
2207        },
2208
2209        getTabWidth: function(tabId) {
2210            var curTab = document.getElementById(tabId);
2211            if (curTab)
2212                return $('#' + tabId).outerWidth(true);
2213            return 0;
2214        },
2215
2216        doSetNavMinWidth: function() {
2217            var minWidth = parseInt( this.dom.$workZoneSideNav.css( "minWidth" ), 10 );
2218            if ( $.isNumeric( minWidth ) && ( minWidth !== 0 ) ) {
2219                this.minNavWidth = minWidth;
2220            }
2221            else {
2222                this.minNavWidth = this.NAV_MIN_WIDTH_DEFAULT;
2223            }
2224            var summaryTabWidth = 0;
2225            summaryTabWidth += this.getTabWidth("tabSelector_menu");
2226            summaryTabWidth += this.getTabWidth("tabSelector_index");
2227            summaryTabWidth += this.getTabWidth("tabSelector_search");
2228            this.minNavWidth = Math.max(this.minNavWidth, summaryTabWidth + 20);
2229        },
2230
2231        doSetArticleMinWidth: function() {
2232            var minWidth = parseInt( this.dom.$workZoneSideArticle.css( "minWidth" ), 10 );
2233            if ( $.isNumeric( minWidth ) && ( minWidth !== 0 ) ) {
2234                this.minArticleWidth = minWidth;
2235            }
2236            else {
2237                this.minArticleWidth = this.ARTICLE_MIN_WIDTH_DEFAULT;
2238            }
2239        },
2240
2241        recalculateNavMaxWidth: function() {
2242            // AT: we do not need to calculate this if nav is hidden or displayed in side pane
2243            // AT: if side pane is active, max nav width can be set as window width - 40px
2244            if (this.isNavTopmost()) {
2245                this.maxNavWidth = $(window).width() - 40;
2246                return;
2247            }
2248
2249            var userLeftSideWidth = 0;
2250            var userRightSideWidth = 0;
2251            var isUserLeftSideExistsAndVisible = ( ( this.dom.$pageContentLeft.length ) > 0 && this.dom.isPageLeftVisible() );
2252            var isUserRightSideExistsAndVisible = ( ( this.dom.$pageContentRight.length ) > 0 && this.dom.isPageRightVisible() );
2253
2254            if ( isUserLeftSideExistsAndVisible ) {
2255                userLeftSideWidth = this.dom.$pageContentLeft.outerWidth( true );
2256            }
2257
2258            if ( isUserRightSideExistsAndVisible ) {
2259                userRightSideWidth = this.dom.$pageContentRight.outerWidth( true );
2260            }
2261
2262            var windowWidth = $(window).width();
2263            var minArticleWidth = this.minArticleWidth;
2264            if (this.dom.$headerSide__nav.length)
2265            {
2266                var headerSide__buttons_width = this.dom.$headerSide__buttons.outerWidth();
2267
2268                var headerSide__nav_paddings = this.dom.$headerSide__nav.outerWidth() - this.dom.$headerSide__nav.width();
2269                var maxBreadCrumbWidth = 0;
2270                this.dom.$headerSide__nav__breadCrumbs.find("li").each(function(index) { maxBreadCrumbWidth = Math.max(maxBreadCrumbWidth, $(this).outerWidth()) });
2271                var headerSide__nav__breadCrumbs_width = maxBreadCrumbWidth;
2272                var articlePaddings = this.dom.$article.outerWidth() - this.dom.$article.width();
2273                var workZoneSideArticlePaddings = this.dom.$workZoneSideArticle.outerWidth() - this.dom.$workZoneSideArticle.width();
2274                var workZoneSideArticleContentPaddings = this.dom.$workZoneSideArticleContent.outerWidth() - this.dom.$workZoneSideArticleContent.width();
2275                var workZoneNavPaddings = this.dom.$workZoneSideNav.outerWidth() - this.dom.$workZoneSideNav.width();
2276
2277                minArticleWidth = Math.max(minArticleWidth, headerSide__buttons_width + headerSide__nav__breadCrumbs_width +headerSide__nav_paddings + articlePaddings + workZoneSideArticlePaddings + workZoneSideArticleContentPaddings + workZoneNavPaddings);
2278            }
2279
2280            var maxContentAreaWidth = this.dom.$internal_wrapper.css("width");
2281            if (!maxContentAreaWidth || maxContentAreaWidth.length < 2)
2282            {
2283                maxContentAreaWidth = windowWidth;
2284            }
2285            else
2286            {
2287                if (maxContentAreaWidth.charAt(maxContentAreaWidth.length - 1) == '%')
2288                {
2289                    maxContentAreaWidth = parseInt(maxContentAreaWidth, 10) * windowWidth / 100;
2290                }
2291                else
2292                {
2293                    maxContentAreaWidth = parseInt(maxContentAreaWidth, 10);
2294                }
2295            }
2296            var maxWidth = maxContentAreaWidth - minArticleWidth - userLeftSideWidth - userRightSideWidth;
2297
2298            if ( maxWidth < this.NAV_MIN_WIDTH_DEFAULT ) {
2299                maxWidth = this.NAV_MIN_WIDTH_DEFAULT;
2300            }
2301
2302            this.maxNavWidth = maxWidth;
2303            //console.log( [windowWidth,minArticleWidth,userLeftSideWidth,userRightSideWidth, maxWidth, this.minArticleWidth ] );
2304        },
2305
2306        isNavEnabled: function() {
2307            return !this.dom.$workZone.hasClass('m-workZone__withoutSideNav');
2308        },
2309
2310        isNavTopmost: function() {
2311            return this.dom.$workZoneSideNav.hasClass('topmost');
2312        },
2313
2314        showNavTopmost: function() {
2315            this.currArticleWidth = this.dom.$workZoneSideArticle.width();
2316
2317            this.dom.$workZoneSideNav.addClass('topmost').show();
2318            this.dom.$workZoneSideArticle.addClass('overlayed');
2319            this.dom.$body.addClass('no-horizontal-scroll');
2320
2321            $(document).trigger('sideNavTopmostPresent');
2322
2323            var that = this;
2324            this.dom.$workZoneSideArticleOverlay.on('click', function(e) {
2325                e.preventDefault();
2326                that.hideNavTopmost();
2327            });
2328
2329            this.dom.$dismissSideNavButton.on('click', function(e) {
2330                e.preventDefault();
2331                that.hideNavTopmost();
2332            });
2333        },
2334
2335        hideNavTopmost: function() {
2336            this.dom.$workZoneSideNav.removeClass('topmost').hide();
2337            this.dom.$workZoneSideArticle.removeClass('overlayed').width('100%');
2338            this.dom.$body.removeClass('no-horizontal-scroll');
2339
2340            $(document).trigger('sideNavTopmostDismiss');
2341
2342            this.dom.$workZoneSideArticleOverlay.off('click');
2343            this.dom.$dismissSideNavButton.off('click');
2344        },
2345
2346        getDesirableNavWidth: function() {
2347            return _.min([
2348                _.max([
2349                    this.dataManager.getStartingMenuWidth(),
2350                    this.visibleTabLongestTreeItemWidth + 22,
2351                    this.minNavWidth,
2352                    this.currNavWidth
2353                ]),
2354                this.maxNavWidth
2355            ]);
2356        },
2357
2358        recalculateAll: function() {
2359            this.dom.updatePageLayoutType();
2360            this.recalculateNavMaxWidth();
2361            this.recalculateVisibleTabLongestTreeItemWidth();
2362
2363            if (this.dom.$workZoneSideNav.is(':visible')) {
2364                this.dom.$hasHorizontalScrollbar = {};
2365                this.dom.$hasVerticalScrollbar = {};
2366                if (this.isNavTopmost()) {
2367                    var desirableWidth = this.getDesirableNavWidth();
2368                    this.setNewNavWidth(desirableWidth);
2369                } else {
2370                    this.setNewNavWidth(this.preferredNavWidth);
2371                }
2372            }
2373
2374            if (this.isNavTopmost()) {
2375                this.dom.$workZoneSideArticle.width(this.currArticleWidth);
2376            } else {
2377                this.frameModeSizer.recalculateIfEnabled();
2378            }
2379
2380            this.flowModeSizer.recalculateIfEnabled();
2381            this.mapAreasKeeper.recalculate();
2382        },
2383
2384        ensureModeSizer: function() {
2385            if (this.dataManager.fitHeightToWindow() && !is_touch_device() && this.dom.getPageLayoutType() != 'xs') {
2386                this.flowModeSizer.disableRecalculatingEvents();
2387                this.frameModeSizer.enableRecalculatingEvents();
2388            } else {
2389                this.frameModeSizer.disableRecalculatingEvents();
2390                this.flowModeSizer.enableRecalculatingEvents();
2391            }
2392        },
2393
2394        doBindEvents: function() {
2395            this.doBindEventsSizer();
2396
2397            if (!is_touch_device()) {
2398                this.splitter.doBindEvents();
2399            }
2400
2401            this.ensureModeSizer();
2402
2403            var that = this;
2404            if (this.dom.$presentSideNavButton.length > 0) {
2405                this.dom.$presentSideNavButton.on('click', function (e) {
2406                    e.preventDefault();
2407                    that.showNavTopmost();
2408                });
2409            }
2410
2411            $(document).on("pageLayoutChange", function(e, layoutType) {
2412                if (_.contains(['sm', 'md', 'lg'], layoutType)) {
2413                    if (that.isNavTopmost()) {
2414                        that.hideNavTopmost();
2415                    }
2416
2417                    if (that.isNavEnabled()) {
2418                        that.dom.$workZoneSideNav.show();
2419                    }
2420                } else if (layoutType === 'xs') {
2421                    that.dom.$workZoneSideNav.hide();
2422                }
2423                that.ensureModeSizer();
2424                that.recalculateAll();
2425            });
2426        },
2427
2428        doBindEventsSizer: function() {
2429            var that = this;
2430
2431            $( document ).on( "newTabSelected.tabs", function(){
2432                that.recalculateAll();
2433            });
2434
2435            $( document ).on( "nodeVisibleChanged", function(){
2436                that.recalculateAll();
2437            });
2438
2439            $( document ).on( "searchCompleteBuildTree", function(){
2440                that.recalculateAll();
2441            });
2442
2443            $(document).on('sideNavTopmostPresent', function() {
2444                that.recalculateAll();
2445            })
2446
2447            $(document).on('sideNavTopmostDismiss', function() {
2448                that.recalculateAll();
2449            })
2450
2451            $( window ).resize(function() {
2452                clearTimeout( that.timeoutId );
2453                that.timeoutId = setTimeout( function() {
2454                    that.recalculateAll();
2455                }, that.WINDOW_RECALCULATING_DELAY );
2456            });
2457
2458        },
2459
2460        doSetSplitter: function() {
2461            var that = this;
2462
2463            this.splitter = DR_EXPLAIN.workZoneSizer_Splitter;
2464            this.splitter.setOnMouseMoveCallback(function( newWidth ) {
2465                that.changeWorkZoneSizeOnMouseMove( newWidth );
2466                that.preferredNavWidth = newWidth;
2467                that.recalculateAll();
2468            });
2469            this.splitter.setOnMouseUpCallback(function() {
2470                that.recalculateAll();
2471            });
2472            this.splitter.init();
2473        },
2474
2475        doSetFrameModeSizer: function() {
2476            this.frameModeSizer = DR_EXPLAIN.workZoneSizer_FrameMode;
2477            this.frameModeSizer.init();
2478        },
2479
2480        doSetFlowModeSizer: function() {
2481            this.flowModeSizer = DR_EXPLAIN.workZoneSizer_FlowMode;
2482            this.flowModeSizer.init();
2483        },
2484
2485        changeWorkZoneSizeOnMouseMove: function( newWidth ) {
2486            this.setNewNavWidth( newWidth );
2487        },
2488
2489        setNewNavWidth: function( newNavWidth ) {
2490            var finalNewNavWidth = this.getFinalNewNavWidth( newNavWidth );
2491
2492            var longestTreeItemWidthWithPaddings = this.visibleTabLongestTreeItemWidth;
2493            var selectedTab = this.dom.getVisibleTab();
2494            var tabId = null;
2495            if (selectedTab)
2496                tabId = selectedTab.$wrapperItem.prop("id");
2497            //console.log("setNewNavWidth: this.dom.$hasVerticalScrollbar[" + tabId + "] = " + this.dom.$hasVerticalScrollbar[tabId]);
2498
2499            if ( this.dom.$hasVerticalScrollbar[tabId] )
2500                longestTreeItemWidthWithPaddings += $.getScrollbarWidth() * 1;
2501            var dx = finalNewNavWidth - this.dom.$workZoneSideNav.width();
2502
2503            var finalTreeWidth = 0;
2504            if (selectedTab)
2505            {
2506                //console.log("setNewNavWidth: " + tabId);
2507                var $wrapperItem = selectedTab.$wrapperItem;
2508
2509                finalTreeWidth += $wrapperItem.width();
2510            }
2511            finalTreeWidth += dx;
2512            this.dom.$hasHorizontalScrollbar[tabId] = finalTreeWidth < longestTreeItemWidthWithPaddings;
2513            //console.log("setNewNavWidth: this.dom.$hasHorizontalScrollbar[" + tabId + "] = " + this.dom.$hasHorizontalScrollbar[tabId]);
2514            if ( !this.dom.$hasHorizontalScrollbar[tabId] ) {
2515                this.dom.$treeArr.css( "width", "auto" );
2516            }
2517            else {
2518                this.dom.$treeArr.css({
2519                    width: this.visibleTabLongestTreeItemWidth + "px"
2520                });
2521            }
2522
2523            this.dom.$workZoneSideNav.css( "width", finalNewNavWidth + "px" );
2524            this.currNavWidth = finalNewNavWidth;
2525        },
2526
2527        getFinalNewNavWidth: function( newNavWidth ) {
2528            var finalNewNavWidth = newNavWidth;
2529
2530            if ( newNavWidth > this.maxNavWidth ) {
2531                finalNewNavWidth = this.maxNavWidth;
2532            } else if (newNavWidth < this.minNavWidth ) {
2533                finalNewNavWidth = this.minNavWidth;
2534            }
2535
2536            return finalNewNavWidth;
2537        },
2538
2539        recalculateVisibleTabLongestTreeItemWidth: function() {
2540            var $visibleTab = this.dom.getVisibleItemWrapperInner();
2541            if ($visibleTab) {
2542                var $tree = $visibleTab.children( "div" );
2543                var $treeTable = $tree.children( "table" );
2544
2545                $treeTable.css( "width", "auto" );
2546                var treeTableWidth = $treeTable.width();
2547                $treeTable.css( "width", "100%" );
2548                if (treeTableWidth !== null) {
2549                    this.visibleTabLongestTreeItemWidth = treeTableWidth;
2550                } else {
2551                    this.visibleTabLongestTreeItemWidth = 0;
2552                }
2553            } else {
2554                this.visibleTabLongestTreeItemWidth = 0;
2555            }
2556        }
2557    };
2558
2559    var API = {
2560        init: function() {
2561            _class.init();
2562        },
2563
2564        recalculateAll: function() {
2565            _class.recalculateAll();
2566        },
2567
2568        doBindEvents: function() {
2569            _class.doBindEvents();
2570        }
2571    };
2572
2573    return API;
2574})();
2575
2576
2577/*js/drexplain/drexplain.work-zone-sizer.splitter.js*/
2578DR_EXPLAIN.namespace( 'DR_EXPLAIN.workZoneSizer_Splitter' );
2579
2580DR_EXPLAIN.workZoneSizer_Splitter = (function(){
2581    var _class = {
2582        $splitter: null,
2583        $resizable: null,
2584        $body: null,
2585        splitterOldX: 0,
2586        timeoutId: null,
2587        dom: null,
2588        DELAY: 1,
2589
2590        onMouseDownCallback: null,
2591        onMouseMoveCallback: null,
2592        onMouseUpCallback: null,
2593
2594        init: function() {
2595            this.doSetDom();
2596        },
2597
2598        doSetDom: function() {
2599            this.dom = DR_EXPLAIN.dom;
2600            this.$splitter = this.dom.$splitter;
2601            this.$resizable = this.dom.$workZoneSideNav;
2602            this.$body = this.dom.$body;
2603        },
2604
2605
2606        doBindEvents: function() {
2607            var that = this;
2608
2609            $( this.$splitter ).on( "mousedown.splitter", function( e ){
2610                that.onMouseDown( e );
2611            });
2612        },
2613
2614        bindMouseEvents: function() {
2615            var that = this;
2616
2617            $( document ).on( "mouseup.splitter", function(){
2618                that.onMouseUp();
2619            });
2620
2621            $( document ).on( "mousemove.splitter", function( e ){
2622                clearTimeout( that.timeoutId );
2623                that.timeoutId = setTimeout(function(){
2624                    that.onMouseMove( e );
2625                }, that.DELAY );
2626            });
2627        },
2628
2629        unbindMouseEvents: function() {
2630            $( document ).off( ".splitter" );
2631        },
2632
2633
2634        onMouseDown: function( e ) {
2635            this.splitterOldX = e.pageX;
2636            this._resizableOldWidth = this.$resizable.width();
2637            this.addCursorIconToBody();
2638            this.disableSelection();
2639            this.bindMouseEvents();
2640        },
2641
2642
2643        onMouseUp: function() {
2644            this.removeCursorIconFromBody();
2645            this.enableSelection();
2646            this.unbindMouseEvents();
2647            return this.onMouseUpCallback();
2648        },
2649
2650        onMouseMove: function( e ) {
2651            // IE mouseup check - mouseup happened when mouse was out of window
2652            if ($.browser.msie && !(document.documentMode >= 9) && !e.button) {
2653                return this.onMouseUp();
2654            }
2655
2656            var delta = e.pageX - this.splitterOldX;
2657            if (this.dom.isRtl()) {
2658                delta = -delta;
2659            }
2660
2661            var newWidth = this._resizableOldWidth + delta;
2662
2663            return this.onMouseMoveCallback( newWidth );
2664        },
2665
2666        setOnMouseMoveCallback: function( callback ) {
2667            this.onMouseMoveCallback = callback;
2668        },
2669
2670        setOnMouseUpCallback: function( callback ) {
2671            this.onMouseUpCallback = callback;
2672        },
2673
2674        getResizableWidth: function() {
2675            return parseInt( this.$resizable.css( "width" ), 10 );
2676        },
2677
2678        addCursorIconToBody: function() {
2679            this.$body.css( "cursor", "e-resize" );
2680        },
2681
2682        removeCursorIconFromBody: function() {
2683            this.$body.css( "cursor", "auto" );
2684        },
2685
2686        disableSelection: function() {
2687            this.$body.disableTextSelect();
2688        },
2689
2690        enableSelection: function() {
2691            this.$body.enableTextSelect();
2692        }
2693    };
2694
2695    var API = {
2696        init: function() {
2697            _class.init();
2698        },
2699
2700        doBindEvents: function() {
2701            _class.doBindEvents();
2702        },
2703
2704        setOnMouseMoveCallback: function( callback ) {
2705            _class.setOnMouseMoveCallback( callback );
2706        },
2707
2708        setOnMouseUpCallback: function( callback ) {
2709            _class.setOnMouseUpCallback( callback );
2710        }
2711    };
2712
2713    return API;
2714})();
2715
2716
2717/*js/drexplain/drexplain.work-zone-sizer.frame-mode.js*/
2718DR_EXPLAIN.namespace( 'DR_EXPLAIN.workZoneSizer_FrameMode' );
2719DR_EXPLAIN.workZoneSizer_FrameMode = (function(){
2720    var _class = {
2721        dom: null,
2722        timeoutId: null,
2723        isRecalculatingEventsEnabled: false,
2724        recalculateDomNodes: [],
2725        RESIZE_TIME_INTERVAL: 50,
2726
2727        init: function() {
2728            this.doSetDom();
2729        },
2730
2731        doSetDom: function( ) {
2732            this.dom = DR_EXPLAIN.dom;
2733        },
2734
2735        doBindEvents: function() {
2736            this.doBindKeywordContextEvents();
2737        },
2738
2739        doBindKeywordContextEvents: function() {
2740            var that = this;
2741            this.dom.$keywordContextMenu.on( "show.contextMenu", function(e, $elemInTree ) {
2742                that.dom.$keywordContextMenu_elemInTree = $elemInTree;
2743                that.recalculate();
2744            });
2745
2746            this.dom.tabs.index.$wrapperItemInner.on( "scroll.contextMenu", function() {
2747                that.recalculateIndexContextMenu();
2748            });
2749        },
2750
2751        addDomNodeToRecalculate: function( $dom, newValue ) {
2752            this.recalculateDomNodes.push({
2753                $dom: $dom,
2754                value: newValue
2755            });
2756        },
2757
2758        enableRecalculatingEvents: function() {
2759            this.isRecalculatingEventsEnabled = true;
2760            this.dom.$html.addClass( this.dom.FRAME_ENABLED_CLASS );
2761            this.doBindEvents();
2762        },
2763
2764        disableRecalculatingEvents: function() {
2765            this.isRecalculatingEventsEnabled = false;
2766            $( window ).off( ".contextMenu" );
2767
2768            this.dom.$html.removeClass( this.dom.FRAME_ENABLED_CLASS );
2769
2770            this.dom.$workZone.css( "height", "auto" );
2771            this.dom.$article.css( "height", "auto" );
2772            this.dom.$articleWrapper.css( "height", "auto" );
2773            this.dom.$articlePreWrapper.css( "height", "auto" );
2774            this.dom.$articleInnerWrapper.css( "height", "auto" );
2775            this.dom.$tabWrapperItemInnerArr.css({ height: "auto", overflow: "auto" });
2776            this.dom.$treeArr.css( "height", "auto" );
2777            this.dom.$keywordContextMenu.css( "height", "auto" );
2778        },
2779
2780        toggleRecalculatingEvents: function() {
2781            if ( this.isRecalculatingEventsEnabled ) {
2782                this.disableRecalculatingEvents();
2783            }
2784            else {
2785                this.enableRecalculatingEvents();
2786            }
2787        },
2788
2789        recalculateIfEnabled: function() {
2790            if ( this.isRecalculatingEventsEnabled ) {
2791                this.recalculate();
2792            }
2793        },
2794
2795        recalculate: function() {
2796
2797
2798            if ( !this.isRecalculatingEventsEnabled ) {
2799                return false;
2800            }
2801
2802            this.recalculateWorkZone();
2803            this.recalculateArticle();
2804            this.recalculateNav();
2805            this.recalculateIndexContextMenu();
2806
2807            for ( var index = 0; index < this.recalculateDomNodes.length; index += 1 ) {
2808                var node = this.recalculateDomNodes[ index ];
2809                if ( typeof( node.value ) === "object" ) {
2810                    node.$dom.css( node.value );
2811                }
2812                else {
2813                    node.$dom.css( "height", node.value + "px" );
2814                }
2815            }
2816
2817            this.recalculateDomNodes = [];
2818
2819            //console.log( this.getHeaderHeight() );
2820        },
2821
2822        recalculateIndexContextMenu: function() {
2823            if ( this.dom.$keywordContextMenu_elemInTree === undefined ) {
2824                return false;
2825            }
2826            var $contextMenu = this.dom.$keywordContextMenu;
2827            if ( !this.dom.isKeywordContextMenuVisible() ) {
2828                return false;
2829            }
2830
2831            $contextMenu.css({ height: "auto", overflow: "visible" });
2832            var $workZone = this.dom.getVisibleItemWrapperInner();
2833
2834            var $elemInTree = this.dom.$keywordContextMenu_elemInTree;
2835            var elemInTreePos = $elemInTree.offset();
2836            var elemInTreeHeight = $elemInTree.height();
2837            var elemInTreePosTop = elemInTreePos.top;
2838
2839            var workZonePos = $workZone.offset();
2840            var workZoneHeight = $workZone.height();
2841
2842            var contextMenuHeight = $contextMenu.height();
2843
2844            if ( ( elemInTreePosTop < workZonePos.top ) || ( elemInTreePosTop > workZonePos.top + workZoneHeight ) ) {
2845                 this.dom.$keywordContextMenu_elemInTree.trigger( "click" );
2846                 return false;
2847                //elemInTreePosTop = workZonePos.top;
2848    /*          elemInTreePosTop = workZonePos.top;
2849                elemInTreePosTop = workZonePos.top + workZoneHeight;*/
2850            }
2851            else {
2852                //$contextMenu.show();
2853            }
2854
2855            var topSpaceHeight = elemInTreePosTop - workZonePos.top;
2856            var bottomSpaceHeight = workZoneHeight - topSpaceHeight - elemInTreeHeight;
2857
2858
2859
2860            var contextMenuNewTop = 0;
2861
2862            var contextMenuNewLeft = elemInTreePos.left;
2863            var contextMenuNewRight = $(window).width() - (elemInTreePos.left + $elemInTree.outerWidth());
2864
2865            var contextMenuNewWidth = "auto";
2866            var contextMenuNewHeight = "auto";
2867            var contextMenuNewOverflow = "hidden";
2868
2869            var isContextMenuBiggerThenBottomSpace = ( contextMenuHeight > bottomSpaceHeight );
2870            var isContextMenuBiggerThenTopSpace = ( contextMenuHeight > topSpaceHeight );
2871            var isBottomSpaceBiggerThenTopSpace = ( bottomSpaceHeight > topSpaceHeight );
2872            var isContextMenuHeightInContainer = ( !isContextMenuBiggerThenBottomSpace && !isContextMenuBiggerThenTopSpace );
2873
2874
2875
2876            if ( !isContextMenuBiggerThenBottomSpace ) {
2877                contextMenuNewTop = elemInTreePosTop + elemInTreeHeight;
2878            }
2879            else if ( !isContextMenuBiggerThenTopSpace )  {
2880                contextMenuNewTop = elemInTreePosTop - contextMenuHeight;
2881            }
2882            else {
2883                if ( isBottomSpaceBiggerThenTopSpace ) {
2884                    contextMenuNewHeight = bottomSpaceHeight;
2885                    contextMenuNewTop = elemInTreePosTop + elemInTreeHeight;
2886                }
2887                else {
2888                    contextMenuNewHeight = topSpaceHeight;
2889                    contextMenuNewTop = elemInTreePosTop - contextMenuNewHeight;
2890                }
2891                contextMenuNewOverflow = "scroll";
2892            }
2893
2894
2895            if ( contextMenuNewHeight !== "auto" ) {
2896                contextMenuNewHeight += "px";
2897            }
2898
2899            var styleOptions = {
2900                top: contextMenuNewTop  + "px",
2901                height: contextMenuNewHeight,
2902                overflow: contextMenuNewOverflow
2903            };
2904
2905            if (this.dom.isRtl()) {
2906                styleOptions.right = contextMenuNewRight + "px";
2907                styleOptions.padding = "0 0 0 20px";
2908            } else {
2909                styleOptions.left = contextMenuNewLeft + "px";
2910                styleOptions.padding = "0 20px 0 0";
2911            }
2912
2913            $contextMenu.css(styleOptions);
2914    /*
2915            this.addDomNodeToRecalculate( $contextMenu, {
2916                top: contextMenuNewTop  + "px",
2917                left: contextMenuNewLeft + "px",
2918                height: contextMenuNewHeight,
2919                overflow: contextMenuNewOverflow,
2920                padding: contextMenuPadding
2921            });*/
2922
2923        },
2924
2925
2926        recalculateWorkZone: function() {
2927            var newWorkZoneHeight = $( window ).height() - this.getHeaderHeight() - this.getFooterHeight();
2928            //this.dom.$workZone.css( "height", newWorkZoneHeight + "px" );
2929            this.addDomNodeToRecalculate( this.dom.$workZone, newWorkZoneHeight );
2930        },
2931
2932        recalculateArticle: function() {
2933            var newArticleHeight = $( window ).height()
2934                - ( this.dom.$article.offset() ).top
2935                - this.dom.getCssNumericValue( this.dom.$workZoneSideArticleContent, "paddingBottom" )
2936                - this.dom.getCssNumericValue( this.dom.$article, "paddingBottom" )
2937                - this.dom.getCssNumericValue( this.dom.$article, "paddingTop" )
2938                - this.getFooterHeight()
2939                ;
2940
2941            var newArticleInnerWrapperHeight = $( window ).height()
2942                - ( this.dom.$articleWrapper.offset() ).top
2943                - this.dom.getCssNumericValue( this.dom.$articleWrapper, "paddingTop" )
2944                //- this.dom.getCssNumericValue( this.dom.$articleWrapper, "marginTop" )
2945                - this.dom.getCssNumericValue( this.dom.$articleWrapper, "paddingBottom" )
2946                - this.dom.getCssNumericValue( this.dom.$article, "paddingBottom" )
2947                - this.dom.getCssNumericValue( this.dom.$workZoneSideArticleContent, "paddingBottom" )
2948                - this.getFooterHeight()
2949                - 0
2950                ;
2951
2952            var newArticleWrapperHeight = newArticleHeight
2953                - this.dom.$articleHeader.outerHeight( true )
2954                - this.dom.getCssNumericValue( this.dom.$articleWrapper, "borderTopWidth" )
2955                - this.dom.getCssNumericValue( this.dom.$articleWrapper, "borderBottomWidth" )
2956            ;
2957            newArticleInnerWrapperHeight = newArticleHeight
2958                + this.dom.getCssNumericValue( this.dom.$articleInnerWrapper, "paddingBottom" )
2959                ;
2960
2961
2962    /*      this.dom.$article.css( "height", newArticleHeight + "px" );
2963            this.dom.$articlePreWrapper.css( "height", newArticleHeight + "px" );
2964            this.dom.$articleWrapper.css( "height", newArticleWrapperHeight + "px" );*/
2965
2966            this.addDomNodeToRecalculate( this.dom.$article, newArticleHeight );
2967            this.addDomNodeToRecalculate( this.dom.$articlePreWrapper, newArticleHeight );
2968            this.addDomNodeToRecalculate( this.dom.$articleWrapper, newArticleWrapperHeight );
2969
2970            //console.log( 'article newArticleHeight', newArticleHeight, 'newArticleInnerWrapperHeight', newArticleInnerWrapperHeight );
2971        },
2972
2973        recalculateNav: function() {
2974            var that = this;
2975
2976            this.recalculateMenuNav();
2977            this.recalculateIndexNav();
2978            this.recalculateSearchNav();
2979
2980            $( document ).trigger( "navResize" );
2981        },
2982
2983        recalculateMenuNav: function() {
2984            this.recalculateNavWithTreeOnly( this.dom.tabs.menu );
2985        },
2986
2987        recalculateIndexNav: function() {
2988            this.recalculateNavWithTreeOnly( this.dom.tabs.index );
2989        },
2990
2991        recalculateSearchNav: function() {
2992            this.recalculateNavWithTreeAndSearchInput( this.dom.tabs.search );
2993        },
2994
2995        recalculateNavWithTreeOnly: function( tab ) {
2996            var workZoneHeight = this.dom.$workZone.height();
2997
2998            var navOuterPaddingTop = ( this.dom.$tabWrapperItems.offset() ).top;
2999            var navOuterPaddingBottom = this.dom.getCssNumericValue( this.dom.$workZoneSideNavContent, "paddingBottom" ) + this.getFooterHeight();
3000
3001            var navInnerPaddingTop = this.dom.getCssNumericValue( tab.$wrapperItem, "paddingTop" );
3002            var navInnerPaddingBottom = this.dom.getCssNumericValue( tab.$wrapperItem, "paddingBottom" );
3003
3004            tab.$tree.css( "height", "auto" );
3005            var realTreeHeight = tab.$tree.height();
3006
3007            var newTotalNavHeight = $( window ).height()
3008                - navInnerPaddingTop
3009                - navInnerPaddingBottom
3010                - navOuterPaddingBottom
3011                - navOuterPaddingTop;
3012
3013            var newNavHeightWithoutHorizontalScrollbar = newTotalNavHeight;
3014            var tabId = tab.$wrapperItem.prop("id");
3015            if ( this.dom.$hasHorizontalScrollbar[tabId] )
3016                newNavHeightWithoutHorizontalScrollbar -= $.getScrollbarWidth() * 1;
3017
3018            //console.log("recalculateNavWithTreeOnly(" + tabId + "): (realTreeHeight > newNavHeightWithoutHorizontalScrollbar) <=> " + realTreeHeight + " > " + newNavHeightWithoutHorizontalScrollbar);
3019            this.dom.$hasVerticalScrollbar[tabId] = realTreeHeight > newNavHeightWithoutHorizontalScrollbar;
3020            //console.log("recalculateNavWithTreeOnly: this.dom.$hasVerticalScrollbar[" + tabId + "] = " + this.dom.$hasVerticalScrollbar[tabId]);
3021            //console.log("recalculateNavWithTreeOnly: this.dom.$hasHorizontalScrollbar[" + tabId + "] = " + this.dom.$hasHorizontalScrollbar[tabId]);
3022
3023            if ( !this.dom.$hasVerticalScrollbar[tabId] ) {
3024                var SCROLL_COMPENSATION = 0;
3025                if ( this.dom.isIeLessThan9() ) {
3026                    SCROLL_COMPENSATION += 2;
3027                }
3028                //tab.$tree.css( "height", newTotalNavHeight - SCROLL_COMPENSATION + "px" );
3029                this.addDomNodeToRecalculate( tab.$tree, newNavHeightWithoutHorizontalScrollbar - SCROLL_COMPENSATION );
3030            }
3031            else {
3032                //tab.$wrapperItemInner.css( "overflow", "auto" );
3033                this.addDomNodeToRecalculate( tab.$wrapperItemInner, { overflow: "auto" });
3034            }
3035
3036            //tab.$wrapperItemInner.css( "height", newTotalNavHeight + "px" );
3037            this.addDomNodeToRecalculate( tab.$wrapperItemInner, newTotalNavHeight );
3038        },
3039
3040        recalculateNavWithTreeAndSearchInput: function( tab ) {
3041            if ( !this.dom.isTabVisible( tab ) ) {
3042                return false;
3043            }
3044            var workZoneHeight = this.dom.$workZone.height();
3045
3046            var navOuterPaddingTop = ( this.dom.$tabWrapperItems.offset() ).top;
3047            var navOuterPaddingBottom = this.dom.getCssNumericValue( this.dom.$workZoneSideNavContent, "paddingBottom" ) + this.getFooterHeight();
3048
3049            var navInnerPaddingTop = this.dom.getCssNumericValue( tab.$wrapperItem, "paddingTop" ) + this.dom.$tabSearchFormWrapper.height() + this.dom.getCssNumericValue( this.dom.$tabSearchFormWrapper, "marginBottom" );
3050            var navInnerPaddingBottom = this.dom.getCssNumericValue( tab.$wrapperItem, "paddingBottom" );
3051
3052            tab.$tree.css( "height", "auto" );
3053            var realTreeHeight = tab.$tree.height();
3054
3055            var newTotalNavHeight = $( window ).height() - navInnerPaddingTop - navInnerPaddingBottom - navOuterPaddingBottom - navOuterPaddingTop;
3056
3057            var newNavHeightWithoutHorizontalScrollbar = newTotalNavHeight;
3058            var tabId = tab.$wrapperItem.prop("id");
3059            if ( this.dom.$hasHorizontalScrollbar[tabId] )
3060                newNavHeightWithoutHorizontalScrollbar -= $.getScrollbarWidth() * 1;
3061            this.dom.$hasVerticalScrollbar[tabId] = realTreeHeight > newNavHeightWithoutHorizontalScrollbar;
3062
3063            if ( !this.dom.$hasVerticalScrollbar[tabId] ) {
3064                var SCROLL_COMPENSATION = 0;
3065                if ( this.dom.isIeLessThan9() ) {
3066                    SCROLL_COMPENSATION += 2;
3067                }
3068                //tab.$tree.css( "height", newTotalNavHeight - SCROLL_COMPENSATION + "px" );
3069                this.addDomNodeToRecalculate( tab.$tree, newNavHeightWithoutHorizontalScrollbar - SCROLL_COMPENSATION );
3070            }
3071            else {
3072                //tab.$wrapperItemInner.css( "overflow", "auto" );
3073                this.addDomNodeToRecalculate( tab.$wrapperItemInner, { overflow: "auto" });
3074            }
3075
3076            //tab.$wrapperItemInner.css( "height", newTotalNavHeight + "px" );
3077            this.addDomNodeToRecalculate( tab.$wrapperItemInner, newTotalNavHeight );
3078        },
3079
3080        getHeaderHeight: function() {
3081            if ( this.dom.isPageHeaderVisible() ) {
3082                return this.dom.$pageContentHeader.height();
3083            }
3084            else {
3085                return 0;
3086            }
3087        },
3088
3089        getFooterHeight: function() {
3090            if ( this.dom.isPageFooterVisible() ) {
3091                return this.dom.$pageContentFooter.height();
3092            }
3093            else {
3094                return 0;
3095            }
3096        }
3097    };
3098
3099    var API = {
3100        init: function() {
3101            _class.init();
3102        },
3103
3104        enableRecalculatingEvents: function() {
3105            _class.enableRecalculatingEvents();
3106        },
3107
3108        disableRecalculatingEvents: function() {
3109            _class.disableRecalculatingEvents();
3110        },
3111
3112        recalculateIfEnabled: function() {
3113            _class.recalculateIfEnabled();
3114        },
3115
3116        toggleRecalculatingEvents: function() {
3117            _class.toggleRecalculatingEvents();
3118        }
3119    };
3120
3121    return API;
3122})();
3123
3124
3125/*js/drexplain/drexplain.work-zone-sizer.flow-mode.js*/
3126DR_EXPLAIN.namespace( 'DR_EXPLAIN.workZoneSizer_FlowMode' );
3127DR_EXPLAIN.workZoneSizer_FlowMode = (function(){
3128    var _class = {
3129        dom: null,
3130        isRecalculatingEventsEnabled: false,
3131
3132        init: function() {
3133            this.doSetDom();
3134        },
3135
3136        doSetDom: function( ) {
3137            this.dom = DR_EXPLAIN.dom;
3138        },
3139
3140        enableRecalculatingEvents: function() {
3141            this.isRecalculatingEventsEnabled = true;
3142        },
3143
3144        disableRecalculatingEvents: function() {
3145            this.isRecalculatingEventsEnabled = false;
3146        },
3147
3148        recalculateIfEnabled: function() {
3149            if ( this.isRecalculatingEventsEnabled ) {
3150                this.recalculate();
3151            }
3152        },
3153
3154        recalculate: function() {
3155            var article = $("#article");
3156            var articleOffset = article.offset();
3157            var articleOuterHeight = article.outerHeight(true);
3158
3159            var bTabs = $(".b-tabs");
3160            var bTabsOffset = bTabs.offset();
3161            var bTabsCurrentLowestPoint = bTabsOffset.top + bTabs.outerHeight(true);
3162
3163            var articleLowestPointMustBe = bTabsCurrentLowestPoint;
3164            var articleCurrentLowestPoint = articleOffset.top + articleOuterHeight;
3165            var articleWrapper = $(".b-article__wrapper");
3166            var articleMustBeResizedBy = articleLowestPointMustBe - articleCurrentLowestPoint;
3167
3168            var articleWrapperHeight = articleWrapper.height();
3169            articleWrapper.css("min-height", Math.max(articleWrapperHeight + articleMustBeResizedBy, 0));
3170        }
3171    };
3172
3173    var API = {
3174        init: function() {
3175            _class.init();
3176        },
3177
3178        enableRecalculatingEvents: function() {
3179            _class.enableRecalculatingEvents();
3180        },
3181
3182        disableRecalculatingEvents: function() {
3183            _class.disableRecalculatingEvents();
3184        },
3185
3186        recalculateIfEnabled: function() {
3187            _class.recalculateIfEnabled();
3188        }
3189    };
3190
3191    return API;
3192})();
3193
3194
3195/*js/drexplain/nav-tree/drexplain.nav-tree.menu.js*/
3196DR_EXPLAIN.namespace( 'DR_EXPLAIN.navTree_Menu' );
3197DR_EXPLAIN.navTree_Menu = (function(){
3198    var _class = {
3199    $navTree: null,
3200    urlEncoder: null,
3201    dom: null,
3202    navTreeView: null,
3203    navArr: null,
3204    nodeVisibleStatusArr: [],
3205
3206
3207
3208    init: function() {
3209        this.doSetDom();
3210        this.doSetUtils();
3211        this.doSetUrlEncoder();
3212        this.doSetDataManager();
3213        this.doSetNodeVisibleStatusArrByUrlEncoder();
3214
3215        this.navArr = this.populateTable( this.dataManager.getRootNodesArray(), true);
3216        var navTreeItemsCollection = this.getNavCollection( this.navArr, null );
3217        this.navTreeView = navTreeView = new NavTree__View({ collection: navTreeItemsCollection, $navTree: this.$navTree });
3218
3219        var flatCollection = new NavTree__ItemsNodes_Collection( this.navTreeView.models );
3220        flatCollection.on(
3221            "change:isVisible",
3222            this.onNodeVisibleChange,
3223            this
3224        );
3225    },
3226
3227    renderNode: function(containerElement, node, model, depth)
3228    {
3229        var li = containerElement.appendChild(document.createElement("li"));
3230        li.className = "b-tree_item";
3231        var div = li.appendChild(document.createElement("div"));
3232        div.className = "b-tree__itemContent";
3233        if (node.isSelected)
3234            div.className += " m-tree__itemContent__selected";
3235        div.title = node.title;
3236
3237        var emptySpacerCount = depth;
3238        if (node.childs != null)
3239            --emptySpacerCount;
3240        for (var i = 0; i < emptySpacerCount; ++i)
3241            div.appendChild(document.createElement("span")).className = "b-tree__spacer";
3242              
3243        if (node.childs != null)
3244        {
3245            var bVisible = model.get("isVisible");
3246            //Create expander
3247            var spacer = div.appendChild(document.createElement("span"));
3248            spacer.className = "b-tree__spacer";
3249            var expanderSpan = spacer.appendChild(document.createElement("span"));
3250            expanderSpan.className = bVisible ? "b-tree__i_expander_doClose" : "b-tree__i_expander_doOpen";
3251            
3252            var expanderImg = expanderSpan.appendChild(document.createElement("span"));
3253            expanderImg.className = bVisible ? "expander_img b-tree__i_expander_doClose_inner" : "expander_img b-tree__i_expander_doOpen_inner";
3254            
3255            //Add folder icon
3256            spacer = div.appendChild(document.createElement("span"));
3257            spacer.className = "b-tree__spacer";
3258            var folderSpan = spacer.appendChild(document.createElement("span"));
3259            folderSpan.className = bVisible ? "b-tree__i_folder_opened" : "b-tree__i_folder_closed";
3260            var folderSpanInner = folderSpan.appendChild(document.createElement("span"));
3261            folderSpanInner.className = bVisible ? "b-tree__i_folder_opened_inner" : "b-tree__i_folder_closed_inner";
3262            
3263            //Create ul for inner elements
3264            var ul = li.appendChild(document.createElement("ul"));
3265            ul.className = "b-tree__items";
3266            for (var i = 0; i < node.childs.length; ++i)
3267                this.renderNode(ul, node.childs[i], model.attributes.childs.models[i], depth + 1);
3268            node.toggleClasses = function() {
3269                $(expanderSpan).toggleClass( "b-tree__i_expander_doClose b-tree__i_expander_doOpen" );
3270                $(expanderImg).toggleClass( "b-tree__i_expander_doClose_inner b-tree__i_expander_doOpen_inner" );
3271
3272                $(folderSpan).toggleClass( "b-tree__i_folder_opened b-tree__i_folder_closed" );
3273                $(folderSpanInner).toggleClass( "b-tree__i_folder_opened_inner b-tree__i_folder_closed_inner" );
3274            };
3275            node.showExpander = function(e) {
3276                $(ul).show();
3277                node.toggleClasses();
3278                model.set({ "isVisible": 1 });
3279                $(expanderSpan).unbind("click");
3280                $(expanderSpan).click(function(e) {
3281                    node.hideExpander();
3282                });
3283            };
3284            node.hideExpander = function(e) {
3285                $(ul).hide();
3286                node.toggleClasses();
3287                model.set({ "isVisible": 0 });
3288                $(expanderSpan).unbind("click");
3289                $(expanderSpan).click(function(e) {
3290                    node.showExpander();
3291                });
3292            };
3293
3294            $(expanderSpan).click(function(e) {
3295                if (bVisible)
3296                    node.hideExpander();
3297                else
3298                    node.showExpander();
3299            });
3300            if (!bVisible)
3301            {
3302                ul.style.display = "none";
3303                model.set({ "isVisible": 0 });
3304            }
3305        }
3306        else
3307        {
3308            //Add article icon
3309            var spacer = div.appendChild(document.createElement("span"));
3310            spacer.className = "b-tree__spacer";
3311            var articleSpan = spacer.appendChild(document.createElement("span"));
3312            articleSpan.className = "b-tree__i_article";
3313            var articleInnerSpan = articleSpan.appendChild(document.createElement("span"));
3314            articleInnerSpan.className = "b-tree__i_article_inner";
3315        }        
3316        var itemTextSpan = div.appendChild(document.createElement("span"));
3317        
3318        if (node.isSelected)
3319        {
3320            itemTextSpan.className = "b-tree__itemText m-tree__itemText__selected";
3321            itemTextSpan.appendChild(document.createTextNode(node.title));
3322        }
3323        else
3324        {
3325            itemTextSpan.className = "b-tree__itemText";
3326            var link = itemTextSpan.appendChild(document.createElement("a"));
3327            link.className = "b-tree__itemLink";
3328            link.href = node.link;
3329            link.appendChild(document.createTextNode(node.title));
3330        }
3331    },
3332
3333    show: function() {
3334        var $navTree = this.navTreeView.$navTree.find( ".b-tree" );
3335        $navTree.empty();
3336        var table = document.createElement("table");
3337        table.className = "b-tree__layout";
3338        table.cellSpacing = 0;
3339        var tr = document.createElement("tr");
3340        var td = document.createElement("td");
3341        td.className = "b-tree__layoutSide";
3342        
3343        var ul = document.createElement("ul");
3344        ul.className = "b-tree__items";
3345        for (var i = 0; i < this.navArr.length; ++i)
3346            this.renderNode(ul, this.navArr[i], this.navTreeView.collection.models[i], 1);
3347
3348        td.appendChild(ul);
3349        tr.appendChild(td);
3350        table.appendChild(tr);
3351        $navTree[0].appendChild(table);
3352    },
3353
3354    doSetDom: function() {
3355        this.dom = DR_EXPLAIN.dom;
3356        this.$navTree = this.dom.tabs.menu.$wrapperItem;
3357    },
3358
3359    doSetDataManager: function() {
3360        this.dataManager = DR_EXPLAIN.dataManager;
3361    },
3362
3363    doSetUtils: function() {
3364        this.utils = DR_EXPLAIN.utils;
3365    },
3366
3367    doSetUrlEncoder: function() {
3368        var that = this;
3369
3370        this.urlEncoder = DR_EXPLAIN.urlEncoder;
3371        this.urlEncoder.addSaveFunc(
3372            function() {
3373                return that.getCurrVisibleStatusArrAsString();
3374            },
3375            that.urlEncoder.KEY_NAME__MENU_STATE
3376        );
3377    },
3378
3379    getDefaultNodeVisibleStatusArr: function() {
3380        var result = new Array( this.dataManager.getNodesCount() );
3381        if (this.dataManager.getDrexMenuType() == 3 || this.dataManager.getDrexMenuType() == 1)
3382        {
3383            for (var i = 0; i < this.dataManager.getDrex().nodes_count; i++)
3384                result[i] = 1;
3385        }
3386        else
3387        {
3388            var deep_border = (this.dataManager.getRootNodesArray().length <= 1 ? 1 : 0);
3389            for (var i = 0; i < this.dataManager.getDrex().nodes_count; i++) {
3390                result[i] = ( this.dataManager.getNodeDeepByIndex( i ) <= deep_border ? 1 : 0 );
3391            }
3392
3393        }
3394        return result;
3395    },
3396
3397    getCurrVisibleStatusArrAsString: function() {
3398        var menuMinimized = this.getDefaultNodeVisibleStatusArr();
3399        var VarTOpnd = this.nodeVisibleStatusArr;
3400
3401        for (var i = 0; i < VarTOpnd.length; i++)
3402            menuMinimized[i] ^= VarTOpnd[i];
3403
3404        var bits = new Array();
3405        for (var i = 0; i < menuMinimized.length; i++)
3406            bits.push(menuMinimized[i]);
3407
3408
3409        var bytes = this.utils.bitsToByte(bits, 7);
3410        bits = new Array();
3411        for (var i = 0; i < bytes.length; i++)
3412            if (bytes[i] == 0)
3413                bits.push(0);
3414            else
3415                bits.push(1);
3416
3417
3418        var result = this.utils.bitsToByte(bits, 7);
3419
3420        for (var i = 0; i < bytes.length; i++)
3421            if (bytes[i] != 0)
3422                result.push(bytes[i]);
3423
3424
3425        var str = "";
3426        for (var i = 0; i < result.length; ++i) {
3427            str += String.fromCharCode(result[i]);
3428        }
3429
3430        var menuStateString = str;
3431
3432        if (menuStateString != "") {
3433            return menuStateString;
3434        }
3435        else {
3436            return null;
3437        }
3438    },
3439
3440    doSetNodeVisibleStatusArrByUrlEncoder: function() {
3441        var t = this.urlEncoder.getValueByKey( this.urlEncoder.KEY_NAME__MENU_STATE );
3442        var VarTOpnd = this.getDefaultNodeVisibleStatusArr();
3443        if (t !== null )
3444        {
3445            var bytes = t;
3446            bytes = this.utils.str2ar(bytes);
3447            var bits = this.utils.byteToBits(bytes, 7);
3448
3449            var prefixLen = this.utils.encodingPrefixLen(VarTOpnd.length, 7);
3450            var readPos = prefixLen;
3451            var result = new Array();
3452            for (var i = 0; i < prefixLen * 8; i++)
3453                if (bits[i] == 0)
3454                    result.push(0);
3455                else
3456                    result.push(bytes[readPos++]);
3457
3458            var MyBB = this.utils.byteToBits(result, 7);
3459            for (var i = 0; i < VarTOpnd.length; ++i)
3460                VarTOpnd[i] ^= MyBB[i];
3461        }
3462
3463        this.nodeVisibleStatusArr = VarTOpnd;
3464        this.validateOpenState();
3465    },
3466
3467
3468    onNodeVisibleChange: function( model, newValue ) {
3469        this.nodeVisibleStatusArr[ model.get( "nodeIndex" ) ] = newValue;
3470        if (!DR_EXPLAIN.disableTriggers)
3471          $( document ).trigger( "nodeVisibleChanged" );
3472
3473    },
3474
3475    validateOpenState: function()
3476    {
3477        var VarTOpnd = this.nodeVisibleStatusArr;
3478
3479        var rootNodeIndex = this.dataManager.getIndexByNode( this.dataManager.getRootNode() );
3480        VarTOpnd[ rootNodeIndex ] = 1;
3481        if ( !this.dataManager.isSelectedNodeExists() ) {
3482            return;
3483        }
3484
3485
3486        var currentNode = this.dataManager.getSelectedNode().parent();
3487        while (currentNode)
3488        {
3489            VarTOpnd[currentNode.node_index] = 1;
3490            currentNode = currentNode.parent();
3491        }
3492
3493        //console.log( 'validateOpenState:', VarTOpnd );
3494    },
3495
3496    populateTable: function( nodeArr, isVisible ) {
3497
3498        if ( nodeArr.length === 0 ) {
3499            return null;
3500        }
3501
3502        var itemArr = [];
3503
3504        for ( var index = 0; index < nodeArr.length; index += 1 ) {
3505            var node = nodeArr[ index ];
3506            var isOpened = this.nodeVisibleStatusArr[ node.node_index ];
3507            var isNodeVisible = !!(isVisible && isOpened);
3508
3509            itemArr.push({
3510                'title': node.title,
3511                'link': node.link,
3512                'nodeIndex': node.node_index,
3513                'childs': this.populateTable( node.children(), isNodeVisible ),
3514                'isVisible': isNodeVisible,
3515                'isSelected': ( node.link === this.dataManager.getPageFilename() )
3516            });
3517        }
3518        return itemArr;
3519    },
3520
3521    getNavCollection: function( navArr, parentModel ) {
3522        if ( navArr === null ) {
3523            return null;
3524        }
3525
3526        var that = this;
3527        var collection = new NavTree__ItemsNodes_Collection( navArr );
3528        _.each( collection.models, function( model, index ){
3529            model.set({
3530                childs: that.getNavCollection( model.get( "childs" ), model ),
3531                parent: parentModel
3532            });
3533        });
3534        return collection;
3535    }
3536    };
3537
3538    var API = {
3539        init: function() {
3540            _class.init();
3541        },
3542
3543        show: function() {
3544            _class.show();
3545        }
3546    };
3547
3548    return API;
3549})();
3550
3551
3552/*js/drexplain/nav-tree/drexplain.nav-tree.index.js*/
3553DR_EXPLAIN.namespace( 'DR_EXPLAIN.navTree_Index' );
3554DR_EXPLAIN.navTree_Index = (function(){
3555
3556    var _class = {
3557        $navTree: null,
3558        navTreeView: null,
3559
3560        init: function() {
3561            this.doSetDom();
3562            this.doSetDataManager();
3563
3564            var navArr = this.populateTable( [this.dataManager.getDrex().root_keyword()] );
3565            var navTreeItemsCollection = this.getNavCollection( navArr, null );
3566            this.navTreeView = new NavTree__Keywords_View({ collection: navTreeItemsCollection, $navTree: this.$navTree });
3567        },
3568
3569        show: function() {
3570            this.navTreeView.render();
3571        },
3572
3573        doSetDom: function() {
3574            this.dom = DR_EXPLAIN.dom;
3575            this.$navTree = this.dom.tabs.index.$wrapperItem;
3576        },
3577
3578        doSetDataManager: function() {
3579            this.dataManager = DR_EXPLAIN.dataManager;
3580        },
3581
3582        populateTable: function( keywordArr ) {
3583
3584            if ( keywordArr.length === 0 ) {
3585                return null;
3586            }
3587
3588            var itemArr = [];
3589
3590            for ( var index = 0; index < keywordArr.length; index += 1 ) {
3591                var keyword = keywordArr[ index ];
3592
3593                if (keyword.isActive())
3594                {
3595                    itemArr.push({
3596                        'title': keyword.title,
3597                        'keywordIndex': keyword.keyword_index,
3598                        'childs': this.populateTable( keyword.childrenSorted() ),
3599                        'links': this.getLinks( keyword )
3600                    });
3601                }
3602                else {
3603                    var childrenArr = this.populateTable( keyword.childrenSorted() );
3604                    if (childrenArr !== null)
3605                        itemArr = itemArr.concat(childrenArr);
3606                }
3607            }
3608            return itemArr;
3609        },
3610
3611        getLinks: function( keyword ) {
3612            var links = keyword.nodes();
3613            var itemArr = [];
3614            for (var i = 0; i < links.length; i++) {
3615                itemArr.push({
3616                    title: links[i].title,
3617                    link: links[i].link,
3618                    nodeIndex: links[i].node_index
3619                });
3620            }
3621
3622            return itemArr;
3623
3624        },
3625
3626        getNavCollection: function( navArr, parentModel ) {
3627            if ( navArr === null ) {
3628                return null;
3629            }
3630
3631            var that = this;
3632            var collection = new NavTree__ItemsKeywords_Collection( navArr );
3633            _.each( collection.models, function( model, index ){
3634                model.set({
3635                    childs: that.getNavCollection( model.get( "childs" ), model ),
3636                    links: new NavTree__ItemsNodes_Collection( model.get( "links" ) ),
3637                    parent: parentModel
3638                });
3639            });
3640            return collection;
3641        }
3642    };
3643
3644    var API = {
3645        init: function() {
3646            _class.init();
3647        },
3648
3649        show: function() {
3650            _class.show();
3651        }
3652    };
3653
3654    return API;
3655})();
3656
3657
3658/*js/drexplain/nav-tree/drexplain.nav-tree.search.js*/
3659DR_EXPLAIN.namespace( 'DR_EXPLAIN.navTree_Search' );
3660DR_EXPLAIN.navTree_Search = (function(){
3661    var _class = {
3662        $navTree: null,
3663        navTreeView: null,
3664
3665
3666        init: function( ) {
3667            this.doSetDom();
3668            this.doSetDataManager();
3669        },
3670
3671        setNewContentBySearchResults: function( searchResultsArr ) {
3672            var navArr = this.getNavArr( searchResultsArr );
3673            var navTreeItemsCollection = this.getNavCollection( navArr, null );
3674            var navTreeView = new NavTree__Search_View({ collection: navTreeItemsCollection, $navTree: this.$navTree });
3675            this.navTreeView = navTreeView;
3676        },
3677
3678        show: function() {
3679            this.navTreeView.render();
3680        },
3681
3682        doSetDom: function() {
3683            this.dom = DR_EXPLAIN.dom;
3684            this.$navTree = this.dom.tabs.search.$wrapperItem;
3685        },
3686
3687        doSetDataManager: function() {
3688            this.dataManager = DR_EXPLAIN.dataManager;
3689        },
3690
3691        getNavCollection: function( navArr, parentModel ) {
3692            if ( navArr === null ) {
3693                return null;
3694            }
3695
3696            var that = this;
3697            var collection = new NavTree__ItemsNodes_Collection( navArr );
3698            _.each( collection.models, function( model, index ){
3699                model.set({
3700                    childs: that.getNavCollection( model.get( "childs" ), model ),
3701                    parent: parentModel
3702                });
3703            });
3704            return collection;
3705        },
3706
3707        getNavArr: function( searchResultsArr ) {
3708
3709            var itemArr = [];
3710
3711            for ( var index = 0; index < searchResultsArr.length; index++ ) {
3712                var currNode = searchResultsArr[ index ];
3713                itemArr.push({
3714                    'title':  currNode[ 0 ],
3715                    'link':  currNode[ 1 ],
3716                    'childs': null,
3717                    'isSelected': (  currNode[ 1 ] === this.dataManager.getPageFilename() )
3718                });
3719            }
3720            return itemArr;
3721        }
3722    };
3723
3724    var API = {
3725        init: function() {
3726            _class.init();
3727        },
3728
3729        setNewContentBySearchResults: function( searchResultsArr ) {
3730            _class.setNewContentBySearchResults( searchResultsArr );
3731        },
3732
3733        show: function() {
3734            _class.show();
3735        }
3736    };
3737
3738    return API;
3739})();
3740
3741
3742/*js/app.js*/
3743function initTabs() {
3744	var app = DR_EXPLAIN;
3745
3746    if (app.tabController.tabsCount() == 0)
3747        return;
3748
3749    app.navTree_Menu.init();
3750    app.navTree_Index.init();
3751    app.navTree_Search.init();
3752
3753    if (app.tabController.isMenuTabShown())
3754        app.navTree_Menu.show();
3755    if (app.tabController.isIndexTabShown())
3756        app.navTree_Index.show();
3757}
3758
3759function onDocumentReady(app) {
3760    DR_EXPLAIN.disableTriggers = true;
3761    app.dataManager.init();
3762
3763    if (app.dataManager.fitHeightToWindow()) {
3764        $("#pageContentMiddle").removeClass("hidden");
3765        $("#pageContentFooter").removeClass("hidden");
3766
3767        if (!is_touch_device()) {
3768            $("iframe").each(function() {
3769                $(this).prop("real_src", $(this).prop("src"));
3770                $(this).prop("src", "about:blank");
3771            });
3772        }
3773    }
3774
3775    app.dom.init();
3776
3777    if (app.dataManager.getDrexMenuType() === 1) {
3778        app.dom.tabs.menu.$wrapperItem.find('.b-tree').addClass('b-tree__withoutControls');
3779    }
3780
3781    if (is_touch_device()) {
3782        app.dom.$workZone.addClass('m-workZone__withoutSplitter');
3783    }
3784
3785    app.dom.updatePageLayoutType();
3786
3787    app.urlEncoder.init();
3788    app.urlEncoder.doDecodeUrl();
3789
3790    if (app.dataManager.fitHeightToWindow()) {
3791        initTabs();
3792    }
3793
3794    app.urlEncoder.doBindOpenNextPageWithEncodedStringToLinks();
3795
3796    app.highlightManager.init();
3797
3798    app.searchManager.init();
3799    app.searchManager.runCustomButtons();
3800    app.searchManager.runInputSync();
3801    app.searchManager.runInputPlaceholders();
3802
3803    app.tabController.init();
3804    app.tabController.doBindEvents();
3805    app.tabController.doSetTabIndexByUrlEncoder();
3806
3807    app.workZoneSizer.init();
3808    app.workZoneSizer.recalculateAll();
3809
3810    if (!app.dataManager.fitHeightToWindow()) {
3811        initTabs();
3812    } else {
3813        var $hc = $("#hiddenContent");
3814        $hc.detach();
3815        $hc.removeClass("hiddenContent");
3816        $hc.appendTo("#description_on_page_placeholder");
3817        $("iframe").each(function() {
3818            $(this).prop("src", $(this).prop("real_src"));
3819        });
3820    }
3821    
3822    DR_EXPLAIN.disableTriggers = false;
3823
3824    app.searchManager.doBindEvents();
3825    app.searchManager.doSearchIfQueryStringNotEmpty();
3826
3827    app.workZoneSizer.doBindEvents();
3828    app.workZoneSizer.recalculateAll();
3829
3830    app.tabController.doSetScrollTopByUrlEncoder();
3831
3832    if (window.location.hash !== "#")
3833        window.location.hash = window.location.hash;
3834}
3835
3836$(document).ready(function() {
3837    onDocumentReady(DR_EXPLAIN);
3838});
3839
3840
3841/*! https://mths.be/fromcodepoint v0.2.1 by @mathias */
3842if (!String.fromCodePoint) {
3843	(function() {
3844		var defineProperty = (function() {
3845			// IE 8 only supports `Object.defineProperty` on DOM elements
3846			try {
3847				var object = {};
3848				var fDefineProperty = Object.defineProperty;
3849				var result = fDefineProperty(object, object, object) && fDefineProperty;
3850			} catch(error) {}
3851			return result;
3852		}());
3853		var stringFromCharCode = String.fromCharCode;
3854		var floor = Math.floor;
3855		var fromCodePoint = function(_) {
3856			var MAX_SIZE = 0x4000;
3857			var codeUnits = [];
3858			var highSurrogate;
3859			var lowSurrogate;
3860			var index = -1;
3861			var length = arguments.length;
3862			if (!length) {
3863				return '';
3864			}
3865			var result = '';
3866			while (++index < length) {
3867				var codePoint = Number(arguments[index]);
3868				if (
3869					!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
3870					codePoint < 0 || // not a valid Unicode code point
3871					codePoint > 0x10FFFF || // not a valid Unicode code point
3872					floor(codePoint) != codePoint // not an integer
3873				) {
3874					throw RangeError('Invalid code point: ' + codePoint);
3875				}
3876				if (codePoint <= 0xFFFF) { // BMP code point
3877					codeUnits.push(codePoint);
3878				} else { // Astral code point; split in surrogate halves
3879					// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
3880					codePoint -= 0x10000;
3881					highSurrogate = (codePoint >> 10) + 0xD800;
3882					lowSurrogate = (codePoint % 0x400) + 0xDC00;
3883					codeUnits.push(highSurrogate, lowSurrogate);
3884				}
3885				if (index + 1 == length || codeUnits.length > MAX_SIZE) {
3886					result += stringFromCharCode.apply(null, codeUnits);
3887					codeUnits.length = 0;
3888				}
3889			}
3890			return result;
3891		};
3892		if (defineProperty) {
3893			defineProperty(String, 'fromCodePoint', {
3894				'value': fromCodePoint,
3895				'configurable': true,
3896				'writable': true
3897			});
3898		} else {
3899			String.fromCodePoint = fromCodePoint;
3900		}
3901	}());
3902}
3903
3904
3905/*! https://mths.be/codepointat v0.2.0 by @mathias */
3906if (!String.prototype.codePointAt) {
3907	(function() {
3908		'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
3909		var defineProperty = (function() {
3910			// IE 8 only supports `Object.defineProperty` on DOM elements
3911			try {
3912				var object = {};
3913				var fDefineProperty = Object.defineProperty;
3914				var result = fDefineProperty(object, object, object) && fDefineProperty;
3915			} catch(error) {}
3916			return result;
3917		}());
3918		var codePointAt = function(position) {
3919			if (this == null) {
3920				throw TypeError();
3921			}
3922			var string = String(this);
3923			var size = string.length;
3924			// `ToInteger`
3925			var index = position ? Number(position) : 0;
3926			if (index != index) { // better `isNaN`
3927				index = 0;
3928			}
3929			// Account for out-of-bounds indices:
3930			if (index < 0 || index >= size) {
3931				return undefined;
3932			}
3933			// Get the first code unit
3934			var first = string.charCodeAt(index);
3935			var second;
3936			if ( // check if it’s the start of a surrogate pair
3937				first >= 0xD800 && first <= 0xDBFF && // high surrogate
3938				size > index + 1 // there is a next code unit
3939			) {
3940				second = string.charCodeAt(index + 1);
3941				if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
3942					// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
3943					return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
3944				}
3945			}
3946			return first;
3947		};
3948		if (defineProperty) {
3949			defineProperty(String.prototype, 'codePointAt', {
3950				'value': codePointAt,
3951				'configurable': true,
3952				'writable': true
3953			});
3954		} else {
3955			String.prototype.codePointAt = codePointAt;
3956		}
3957	}());
3958}
3959

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.