PageSourceSearch

https://www.phonostar.de/download/docs/radio_player_manual/js/all2.js

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

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.