Inline scripts were extracted from Polymer elements.
[chromium-blink-merge.git] / third_party / polymer / components-chromium / core-component-page / core-component-page-extracted.js
blobfe36fb744a631d657baefb8657f8b6e4d4ef4c8d
2   
3   (function() {
4   
5     Polymer('core-layout', {
7       isContainer: false,
8       /**
9        * Controls if the element lays out vertically or not.
10        *
11        * @attribute vertical
12        * @type boolean
13        * @default false
14        */
15       vertical: false,
16       /**
17        * Controls how the items are aligned in the main-axis direction. For 
18        * example for a horizontal layout, this controls how each item is aligned
19        * horizontally.
20        *
21        * @attribute justify
22        * @type string start|center|end|between
23        * @default ''
24        */
25       justify: '',
26       /**
27        * Controls how the items are aligned in cross-axis direction. For 
28        * example for a horizontal layout, this controls how each item is aligned
29        * vertically.
30        *
31        * @attribute align
32        * @type string start|center|end
33        * @default ''
34        */
35       align: '',
36       /**
37        * Controls whether or not the items layout in reverse order.
38        *
39        * @attribute reverse
40        * @type boolean
41        * @default false
42        */
43       reverse: false,
44       layoutPrefix: 'core-',
45   
46       // NOTE: include template so that styles are loaded, but remove
47       // so that we can decide dynamically what part to include
48       registerCallback: function(polymerElement) {
49         var template = polymerElement.querySelector('template');
50         this.styles = template.content.querySelectorAll('style').array();
51         this.styles.forEach(function(s) {
52           s.removeAttribute('no-shim');
53         })
54       },
55   
56       fetchTemplate: function() {
57         return null;
58       },
59   
60       attached: function() {
61         this.installScopeStyle(this.styles[0]);
62         if (this.children.length) {
63           this.isContainer = true;
64         }
65         var container = this.isContainer ? this : this.parentNode;  
66         // detect if laying out a shadowRoot host.
67         var forHost = container instanceof ShadowRoot;
68         if (forHost) {
69           this.installScopeStyle(this.styles[1], 'host');
70           container = container.host || document.body;
71         }
72         this.layoutContainer = container;
73       },
75       detached: function() {
76         this.layoutContainer = null;
77       },
79       layoutContainerChanged: function(old) {
80         this.style.display = this.layoutContainer === this ? null : 'none';
81         this.verticalChanged();
82         this.alignChanged();
83         this.justifyChanged();
84       },
86       setLayoutClass: function(prefix, old, newValue) {
87         if (this.layoutContainer) {
88           prefix = this.layoutPrefix + prefix;
89           if (old) {
90             this.layoutContainer.classList.remove(prefix + old);
91           }
92           if (newValue) {
93             this.layoutContainer.classList.add(prefix + newValue);
94           }
95         }
96       },
98       verticalChanged: function(old) {
99         old = old ? 'v' : 'h';
100         var vertical = this.vertical ? 'v' : 'h';
101         this.setLayoutClass('', old, vertical);
102       },
104       alignChanged: function(old) {
105         this.setLayoutClass('align-', old, this.align);
106       },
108       justifyChanged: function(old) {
109         this.setLayoutClass('justify-', old, this.justify);
110       },
112       reverseChanged: function(old) {
113         old = old ? 'reverse' : '';
114         var newValue = this.reverse ? 'reverse' : '';
115         this.setLayoutClass('', old, newValue);
116       }
118     });
120   })();
121   ;
124   (function() {
125     
126     var SKIP_ID = 'meta';
127     var metaData = {}, metaArray = {};
129     Polymer('core-meta', {
130       
131       /**
132        * The type of meta-data.  All meta-data with the same type with be
133        * stored together.
134        * 
135        * @attribute type
136        * @type string
137        * @default 'default'
138        */
139       type: 'default',
140       
141       alwaysPrepare: true,
142       
143       ready: function() {
144         this.register(this.id);
145       },
146       
147       get metaArray() {
148         var t = this.type;
149         if (!metaArray[t]) {
150           metaArray[t] = [];
151         }
152         return metaArray[t];
153       },
154       
155       get metaData() {
156         var t = this.type;
157         if (!metaData[t]) {
158           metaData[t] = {};
159         }
160         return metaData[t];
161       },
162       
163       register: function(id, old) {
164         if (id && id !== SKIP_ID) {
165           this.unregister(this, old);
166           this.metaData[id] = this;
167           this.metaArray.push(this);
168         }
169       },
170       
171       unregister: function(meta, id) {
172         delete this.metaData[id || meta.id];
173         var i = this.metaArray.indexOf(meta);
174         if (i >= 0) {
175           this.metaArray.splice(i, 1);
176         }
177       },
178       
179       /**
180        * Returns a list of all meta-data elements with the same type.
181        * 
182        * @attribute list
183        * @type array
184        * @default []
185        */
186       get list() {
187         return this.metaArray;
188       },
189       
190       /**
191        * Retrieves meta-data by ID.
192        *
193        * @method byId
194        * @param {String} id The ID of the meta-data to be returned.
195        * @returns Returns meta-data.
196        */
197       byId: function(id) {
198         return this.metaData[id];
199       }
200       
201     });
202     
203   })();
204   
207   
208     Polymer('core-iconset', {
209   
210       /**
211        * The URL of the iconset image.
212        *
213        * @attribute src
214        * @type string
215        * @default ''
216        */
217       src: '',
219       /**
220        * The width of the iconset image. This must only be specified if the
221        * icons are arranged into separate rows inside the image.
222        *
223        * @attribute width
224        * @type number
225        * @default 0
226        */
227       width: 0,
229       /**
230        * A space separated list of names corresponding to icons in the iconset
231        * image file. This list must be ordered the same as the icon images
232        * in the image file.
233        *
234        * @attribute icons
235        * @type string
236        * @default ''
237        */
238       icons: '',
240       /**
241        * The size of an individual icon. Note that icons must be square.
242        *
243        * @attribute iconSize
244        * @type number
245        * @default 24
246        */
247       iconSize: 24,
249       /**
250        * The horizontal offset of the icon images in the inconset src image.
251        * This is typically used if the image resource contains additional images
252        * beside those intended for the iconset.
253        *
254        * @attribute offsetX
255        * @type number
256        * @default 0
257        */
258       offsetX: 0,
259       /**
260        * The vertical offset of the icon images in the inconset src image.
261        * This is typically used if the image resource contains additional images
262        * beside those intended for the iconset.
263        *
264        * @attribute offsetY
265        * @type number
266        * @default 0
267        */
268       offsetY: 0,
269       type: 'iconset',
271       created: function() {
272         this.iconMap = {};
273         this.iconNames = [];
274         this.themes = {};
275       },
276   
277       ready: function() {
278         // TODO(sorvell): ensure iconset's src is always relative to the main
279         // document
280         if (this.src && (this.ownerDocument !== document)) {
281           this.src = this.resolvePath(this.src, this.ownerDocument.baseURI);
282         }
283         this.super();
284         this.updateThemes();
285       },
287       iconsChanged: function() {
288         var ox = this.offsetX;
289         var oy = this.offsetY;
290         this.icons && this.icons.split(/\s+/g).forEach(function(name, i) {
291           this.iconNames.push(name);
292           this.iconMap[name] = {
293             offsetX: ox,
294             offsetY: oy
295           }
296           if (ox + this.iconSize < this.width) {
297             ox += this.iconSize;
298           } else {
299             ox = this.offsetX;
300             oy += this.iconSize;
301           }
302         }, this);
303       },
305       updateThemes: function() {
306         var ts = this.querySelectorAll('property[theme]');
307         ts && ts.array().forEach(function(t) {
308           this.themes[t.getAttribute('theme')] = {
309             offsetX: parseInt(t.getAttribute('offsetX')) || 0,
310             offsetY: parseInt(t.getAttribute('offsetY')) || 0
311           };
312         }, this);
313       },
315       // TODO(ffu): support retrived by index e.g. getOffset(10);
316       /**
317        * Returns an object containing `offsetX` and `offsetY` properties which
318        * specify the pixel locaion in the iconset's src file for the given
319        * `icon` and `theme`. It's uncommon to call this method. It is useful,
320        * for example, to manually position a css backgroundImage to the proper
321        * offset. It's more common to use the `applyIcon` method.
322        *
323        * @method getOffset
324        * @param {String|Number} icon The name of the icon or the index of the
325        * icon within in the icon image.
326        * @param {String} theme The name of the theme.
327        * @returns {Object} An object specifying the offset of the given icon 
328        * within the icon resource file; `offsetX` is the horizontal offset and
329        * `offsetY` is the vertical offset. Both values are in pixel units.
330        */
331       getOffset: function(icon, theme) {
332         var i = this.iconMap[icon];
333         if (!i) {
334           var n = this.iconNames[Number(icon)];
335           i = this.iconMap[n];
336         }
337         var t = this.themes[theme];
338         if (i && t) {
339           return {
340             offsetX: i.offsetX + t.offsetX,
341             offsetY: i.offsetY + t.offsetY
342           }
343         }
344         return i;
345       },
347       /**
348        * Applies an icon to the given element as a css background image. This
349        * method does not size the element, and it's often necessary to set 
350        * the element's height and width so that the background image is visible.
351        *
352        * @method applyIcon
353        * @param {Element} element The element to which the background is
354        * applied.
355        * @param {String|Number} icon The name or index of the icon to apply.
356        * @param {String} theme (optional) The name of the theme for the icon.
357        * @param {Number} scale (optional, defaults to 1) A scaling factor 
358        * with which the icon can be magnified.
359        */
360       applyIcon: function(element, icon, scale) {
361          var offset = this.getOffset(icon);
362          scale = scale || 1;
363          if (element && offset) {
364            var style = element.style;
365            style.backgroundImage = 'url(' + this.src + ')';
366            style.backgroundPosition = (-offset.offsetX * scale + 'px') + 
367               ' ' + (-offset.offsetY * scale + 'px');
368            style.backgroundSize = scale === 1 ? 'auto' :
369               this.width * scale + 'px';
370          }
371       }
373     });
375   ;
378     Polymer('core-iconset-svg', {
381       /**
382        * The size of an individual icon. Note that icons must be square.
383        *
384        * @attribute iconSize
385        * @type number
386        * @default 24
387        */
388       iconSize: 24,
389       type: 'iconset',
391       created: function() {
392         this._icons = {};
393       },
395       ready: function() {
396         this.super();
397         this.updateIcons();
398       },
400       iconById: function(id) {
401         return this._icons[id] || (this._icons[id] = this.querySelector('#' + id));
402       },
404       cloneIcon: function(id) {
405         var icon = this.iconById(id);
406         if (icon) {
407           var content = icon.cloneNode(true);
408           var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
409           svg.setAttribute('viewBox', '0 0 ' + this.iconSize + ' ' +
410               this.iconSize);
411           // NOTE(dfreedm): work around https://crbug.com/370136
412           svg.style.pointerEvents = 'none';
413           svg.appendChild(content);
414           return svg;
415         }
416       },
418       get iconNames() {
419         if (!this._iconNames) {
420           this._iconNames = this.findIconNames();
421         }
422         return this._iconNames;
423       },
425       findIconNames: function() {
426         var icons = this.querySelectorAll('[id]').array();
427         if (icons.length) {
428           return icons.map(function(n){ return n.id });
429         }
430       },
432       /**
433        * Applies an icon to the given element. The svg icon is added to the
434        * element's shadowRoot if one exists or directly to itself.
435        *
436        * @method applyIcon
437        * @param {Element} element The element to which the icon is
438        * applied.
439        * @param {String|Number} icon The name the icon to apply.
440        */
441       applyIcon: function(element, icon, scale) {
442         var root = element.shadowRoot || element;
443         // remove old
444         var old = root.querySelector('svg');
445         if (old) {
446           old.remove();
447         }
448         // install new
449         var svg = this.cloneIcon(icon);
450         if (!svg) {
451           return;
452         }
453         var size = scale * this.iconSize;
454         if (size) {
455           svg.style.height = svg.style.width = size + 'px';
456         } else {
457           svg.setAttribute('height', '100%');
458           svg.setAttribute('width', '100%');
459           svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
460         }
461         svg.style.display = 'block';
462         root.insertBefore(svg, root.firstElementChild);
463       },
464       
465       /**
466        * Tell users of the iconset, that the set has loaded.
467        * This finds all elements matching the selector argument and calls 
468        * the method argument on them.
469        * @method updateIcons
470        * @param selector {string} css selector to identify iconset users, 
471        * defaults to '[icon]'
472        * @param method {string} method to call on found elements, 
473        * defaults to 'updateIcon'
474        */
475       updateIcons: function(selector, method) {
476         selector = selector || '[icon]';
477         method = method || 'updateIcon';
478         var deep = window.ShadowDOMPolyfill ? '' : 'html /deep/ ';
479         var i$ = document.querySelectorAll(deep + selector);
480         for (var i=0, e; e=i$[i]; i++) {
481           if (e[method]) {
482             e[method].call(e);
483           }
484         }
485       }
486       
488     });
490   ;
492 (function() {
493   
494   // mono-state
495   var meta;
496   
497   Polymer('core-icon', {
499     /**
500      * The URL of an image for the icon. If the src property is specified,
501      * the icon property should not be.
502      *
503      * @attribute src
504      * @type string
505      * @default ''
506      */
507     src: '',
509     /**
510      * Specifies the size of the icon in pixel units.
511      *
512      * @attribute size
513      * @type string
514      * @default 24
515      */
516     size: 24,
518     /**
519      * Specifies the icon name or index in the set of icons available in
520      * the icon's icon set. If the icon property is specified,
521      * the src property should not be.
522      *
523      * @attribute icon
524      * @type string
525      * @default ''
526      */
527     icon: '',
529     observe: {
530       'size icon': 'updateIcon'
531     },
533     defaultIconset: 'icons',
535     ready: function() {
536       if (!meta) {
537         meta = document.createElement('core-iconset');
538       }
539       this.updateIcon();
540     },
542     srcChanged: function() {
543       this.style.backgroundImage = 'url(' + this.src + ')';
544       this.style.backgroundPosition = 'center';
545       this.style.backgroundSize = this.size + 'px ' + this.size + 'px';
546     },
548     getIconset: function(name) {
549       return meta.byId(name || this.defaultIconset);
550     },
552     updateIcon: function() {
553       if (this.size) {
554         this.style.width = this.style.height = this.size + 'px';
555       }
556       if (this.icon) {
557         var parts = String(this.icon).split(':');
558         var icon = parts.pop();
559         if (icon) {
560           var set = this.getIconset(parts.pop());
561           if (set) {
562             set.applyIcon(this, icon, this.size / set.iconSize);
563           }
564         }
565       }
566     }
568   });
569   
570 })();
574     Polymer('core-icon-button', {
576       /**
577        * The URL of an image for the icon.  Should not use `icon` property
578        * if you are using this property.
579        *
580        * @attribute src
581        * @type string
582        * @default ''
583        */
584       src: '',
586       /**
587        * If true, border is placed around the button to indicate it's
588        * active state.
589        *
590        * @attribute active
591        * @type boolean
592        * @default false
593        */
594       active: false,
596       /**
597        * Specifies the icon name or index in the set of icons available in
598        * the icon set.  Should not use `src` property if you are using this
599        * property.
600        *
601        * @attribute icon
602        * @type string
603        * @default ''
604        */
605       icon: '',
607       activeChanged: function() {
608         this.classList.toggle('selected', this.active);
609       }
611     });
613   ;
614 Polymer('core-toolbar');;
617   Polymer('core-header-panel', {
619     publish: {
620       /**
621        * Controls header and scrolling behavior. Options are
622        * `standard`, `seamed`, `waterfall`, `waterfall-tall`, 
623        * `waterfall-medium-tall`, `scroll` and `cover`.
624        * Default is `standard`.
625        *
626        * `standard`: The header is a step above the panel. The header will consume the 
627        * panel at the point of entry, preventing it from passing through to the 
628        * opposite side.
629        *
630        * `seamed`: The header is presented as seamed with the panel.
631        *
632        * `waterfall`: Similar to standard mode, but header is initially presented as 
633        * seamed with panel, but then separates to form the step.
634        *
635        * `waterfall-tall`: The header is initially taller (`tall` class is added to 
636        * the header).  As the user scrolls, the header separates (forming an edge)
637        * while condensing (`tall` class is removed from the header).
638        *
639        * `scroll`: The header keeps its seam with the panel, and is pushed off screen.
640        *
641        * `cover`: The panel covers the whole `core-header-panel` including the
642        * header. This allows user to style the panel in such a way that the panel is
643        * partially covering the header.
644        *
645        *     <style>
646        *       core-header-panel[mode=cover]::shadow #mainContainer {
647        *         left: 80px;
648        *       }
649        *       .content {
650        *         margin: 60px 60px 60px 0;
651        *       }
652        *     </style>
653        * 
654        *     <core-header-panel mode="cover">
655        *       <core-appbar class="tall">
656        *         <core-icon-button icon="menu"></core-icon-button>
657        *       </core-appbar>
658        *       <div class="content"></div>
659        *     </core-header-panel>
660        *
661        * @attribute mode
662        * @type string
663        * @default ''
664        */
665       mode: {value: '', reflect: true},
666       
667       /**
668        * The class used in waterfall-tall mode.  Change this if the header
669        * accepts a different class for toggling height, e.g. "medium-tall"
670        *
671        * @attribute tallClass
672        * @type string
673        * @default 'tall'
674        */
675       tallClass: 'tall',
676       
677       /**
678        * If true, the drop-shadow is always shown no matter what mode is set to.
679        *
680        * @attribute shadow
681        * @type boolean
682        * @default false
683        */
684       shadow: false,
685     },
686     
687     domReady: function() {
688       this.async('scroll');
689     },
691     modeChanged: function() {
692       this.scroll();
693     },
695     get header() {
696       return this.$.headerContent.getDistributedNodes()[0];
697     },
698     
699     scroll: function() {
700       var shadowMode = {'waterfall': 1, 'waterfall-tall': 1};
701       var noShadow = {'seamed': 1, 'cover': 1, 'scroll': 1};
702       var tallMode = {'waterfall-tall': 1};
703       
704       var main = this.$.mainContainer;
705       var header = this.header;
706       
707       var sTop = main.scrollTop;
708       var atTop = sTop === 0;
709       
710       if (header) {
711         this.$.dropShadow.classList.toggle('hidden', !this.shadow &&
712             (atTop && shadowMode[this.mode] || noShadow[this.mode]));
713         
714         if (tallMode[this.mode]) {
715           header.classList.toggle(this.tallClass, atTop);
716         }
717         
718         header.classList.toggle('animate', tallMode[this.mode]);
719       }
720     }
722   });
726  * marked - a markdown parser
727  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
728  * https://github.com/chjj/marked
729  */
731 ;(function() {
734  * Block-Level Grammar
735  */
737 var block = {
738   newline: /^\n+/,
739   code: /^( {4}[^\n]+\n*)+/,
740   fences: noop,
741   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
742   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
743   nptable: noop,
744   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
745   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
746   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
747   html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
748   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
749   table: noop,
750   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
751   text: /^[^\n]+/
754 block.bullet = /(?:[*+-]|\d+\.)/;
755 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
756 block.item = replace(block.item, 'gm')
757   (/bull/g, block.bullet)
758   ();
760 block.list = replace(block.list)
761   (/bull/g, block.bullet)
762   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
763   ('def', '\\n+(?=' + block.def.source + ')')
764   ();
766 block.blockquote = replace(block.blockquote)
767   ('def', block.def)
768   ();
770 block._tag = '(?!(?:'
771   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
772   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
773   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
775 block.html = replace(block.html)
776   ('comment', /<!--[\s\S]*?-->/)
777   ('closed', /<(tag)[\s\S]+?<\/\1>/)
778   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
779   (/tag/g, block._tag)
780   ();
782 block.paragraph = replace(block.paragraph)
783   ('hr', block.hr)
784   ('heading', block.heading)
785   ('lheading', block.lheading)
786   ('blockquote', block.blockquote)
787   ('tag', '<' + block._tag)
788   ('def', block.def)
789   ();
792  * Normal Block Grammar
793  */
795 block.normal = merge({}, block);
798  * GFM Block Grammar
799  */
801 block.gfm = merge({}, block.normal, {
802   fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
803   paragraph: /^/
806 block.gfm.paragraph = replace(block.paragraph)
807   ('(?!', '(?!'
808     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
809     + block.list.source.replace('\\1', '\\3') + '|')
810   ();
813  * GFM + Tables Block Grammar
814  */
816 block.tables = merge({}, block.gfm, {
817   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
818   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
822  * Block Lexer
823  */
825 function Lexer(options) {
826   this.tokens = [];
827   this.tokens.links = {};
828   this.options = options || marked.defaults;
829   this.rules = block.normal;
831   if (this.options.gfm) {
832     if (this.options.tables) {
833       this.rules = block.tables;
834     } else {
835       this.rules = block.gfm;
836     }
837   }
841  * Expose Block Rules
842  */
844 Lexer.rules = block;
847  * Static Lex Method
848  */
850 Lexer.lex = function(src, options) {
851   var lexer = new Lexer(options);
852   return lexer.lex(src);
856  * Preprocessing
857  */
859 Lexer.prototype.lex = function(src) {
860   src = src
861     .replace(/\r\n|\r/g, '\n')
862     .replace(/\t/g, '    ')
863     .replace(/\u00a0/g, ' ')
864     .replace(/\u2424/g, '\n');
866   return this.token(src, true);
870  * Lexing
871  */
873 Lexer.prototype.token = function(src, top, bq) {
874   var src = src.replace(/^ +$/gm, '')
875     , next
876     , loose
877     , cap
878     , bull
879     , b
880     , item
881     , space
882     , i
883     , l;
885   while (src) {
886     // newline
887     if (cap = this.rules.newline.exec(src)) {
888       src = src.substring(cap[0].length);
889       if (cap[0].length > 1) {
890         this.tokens.push({
891           type: 'space'
892         });
893       }
894     }
896     // code
897     if (cap = this.rules.code.exec(src)) {
898       src = src.substring(cap[0].length);
899       cap = cap[0].replace(/^ {4}/gm, '');
900       this.tokens.push({
901         type: 'code',
902         text: !this.options.pedantic
903           ? cap.replace(/\n+$/, '')
904           : cap
905       });
906       continue;
907     }
909     // fences (gfm)
910     if (cap = this.rules.fences.exec(src)) {
911       src = src.substring(cap[0].length);
912       this.tokens.push({
913         type: 'code',
914         lang: cap[2],
915         text: cap[3]
916       });
917       continue;
918     }
920     // heading
921     if (cap = this.rules.heading.exec(src)) {
922       src = src.substring(cap[0].length);
923       this.tokens.push({
924         type: 'heading',
925         depth: cap[1].length,
926         text: cap[2]
927       });
928       continue;
929     }
931     // table no leading pipe (gfm)
932     if (top && (cap = this.rules.nptable.exec(src))) {
933       src = src.substring(cap[0].length);
935       item = {
936         type: 'table',
937         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
938         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
939         cells: cap[3].replace(/\n$/, '').split('\n')
940       };
942       for (i = 0; i < item.align.length; i++) {
943         if (/^ *-+: *$/.test(item.align[i])) {
944           item.align[i] = 'right';
945         } else if (/^ *:-+: *$/.test(item.align[i])) {
946           item.align[i] = 'center';
947         } else if (/^ *:-+ *$/.test(item.align[i])) {
948           item.align[i] = 'left';
949         } else {
950           item.align[i] = null;
951         }
952       }
954       for (i = 0; i < item.cells.length; i++) {
955         item.cells[i] = item.cells[i].split(/ *\| */);
956       }
958       this.tokens.push(item);
960       continue;
961     }
963     // lheading
964     if (cap = this.rules.lheading.exec(src)) {
965       src = src.substring(cap[0].length);
966       this.tokens.push({
967         type: 'heading',
968         depth: cap[2] === '=' ? 1 : 2,
969         text: cap[1]
970       });
971       continue;
972     }
974     // hr
975     if (cap = this.rules.hr.exec(src)) {
976       src = src.substring(cap[0].length);
977       this.tokens.push({
978         type: 'hr'
979       });
980       continue;
981     }
983     // blockquote
984     if (cap = this.rules.blockquote.exec(src)) {
985       src = src.substring(cap[0].length);
987       this.tokens.push({
988         type: 'blockquote_start'
989       });
991       cap = cap[0].replace(/^ *> ?/gm, '');
993       // Pass `top` to keep the current
994       // "toplevel" state. This is exactly
995       // how markdown.pl works.
996       this.token(cap, top, true);
998       this.tokens.push({
999         type: 'blockquote_end'
1000       });
1002       continue;
1003     }
1005     // list
1006     if (cap = this.rules.list.exec(src)) {
1007       src = src.substring(cap[0].length);
1008       bull = cap[2];
1010       this.tokens.push({
1011         type: 'list_start',
1012         ordered: bull.length > 1
1013       });
1015       // Get each top-level item.
1016       cap = cap[0].match(this.rules.item);
1018       next = false;
1019       l = cap.length;
1020       i = 0;
1022       for (; i < l; i++) {
1023         item = cap[i];
1025         // Remove the list item's bullet
1026         // so it is seen as the next token.
1027         space = item.length;
1028         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
1030         // Outdent whatever the
1031         // list item contains. Hacky.
1032         if (~item.indexOf('\n ')) {
1033           space -= item.length;
1034           item = !this.options.pedantic
1035             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
1036             : item.replace(/^ {1,4}/gm, '');
1037         }
1039         // Determine whether the next list item belongs here.
1040         // Backpedal if it does not belong in this list.
1041         if (this.options.smartLists && i !== l - 1) {
1042           b = block.bullet.exec(cap[i + 1])[0];
1043           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
1044             src = cap.slice(i + 1).join('\n') + src;
1045             i = l - 1;
1046           }
1047         }
1049         // Determine whether item is loose or not.
1050         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
1051         // for discount behavior.
1052         loose = next || /\n\n(?!\s*$)/.test(item);
1053         if (i !== l - 1) {
1054           next = item.charAt(item.length - 1) === '\n';
1055           if (!loose) loose = next;
1056         }
1058         this.tokens.push({
1059           type: loose
1060             ? 'loose_item_start'
1061             : 'list_item_start'
1062         });
1064         // Recurse.
1065         this.token(item, false, bq);
1067         this.tokens.push({
1068           type: 'list_item_end'
1069         });
1070       }
1072       this.tokens.push({
1073         type: 'list_end'
1074       });
1076       continue;
1077     }
1079     // html
1080     if (cap = this.rules.html.exec(src)) {
1081       src = src.substring(cap[0].length);
1082       this.tokens.push({
1083         type: this.options.sanitize
1084           ? 'paragraph'
1085           : 'html',
1086         pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
1087         text: cap[0]
1088       });
1089       continue;
1090     }
1092     // def
1093     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
1094       src = src.substring(cap[0].length);
1095       this.tokens.links[cap[1].toLowerCase()] = {
1096         href: cap[2],
1097         title: cap[3]
1098       };
1099       continue;
1100     }
1102     // table (gfm)
1103     if (top && (cap = this.rules.table.exec(src))) {
1104       src = src.substring(cap[0].length);
1106       item = {
1107         type: 'table',
1108         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
1109         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
1110         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
1111       };
1113       for (i = 0; i < item.align.length; i++) {
1114         if (/^ *-+: *$/.test(item.align[i])) {
1115           item.align[i] = 'right';
1116         } else if (/^ *:-+: *$/.test(item.align[i])) {
1117           item.align[i] = 'center';
1118         } else if (/^ *:-+ *$/.test(item.align[i])) {
1119           item.align[i] = 'left';
1120         } else {
1121           item.align[i] = null;
1122         }
1123       }
1125       for (i = 0; i < item.cells.length; i++) {
1126         item.cells[i] = item.cells[i]
1127           .replace(/^ *\| *| *\| *$/g, '')
1128           .split(/ *\| */);
1129       }
1131       this.tokens.push(item);
1133       continue;
1134     }
1136     // top-level paragraph
1137     if (top && (cap = this.rules.paragraph.exec(src))) {
1138       src = src.substring(cap[0].length);
1139       this.tokens.push({
1140         type: 'paragraph',
1141         text: cap[1].charAt(cap[1].length - 1) === '\n'
1142           ? cap[1].slice(0, -1)
1143           : cap[1]
1144       });
1145       continue;
1146     }
1148     // text
1149     if (cap = this.rules.text.exec(src)) {
1150       // Top-level should never reach here.
1151       src = src.substring(cap[0].length);
1152       this.tokens.push({
1153         type: 'text',
1154         text: cap[0]
1155       });
1156       continue;
1157     }
1159     if (src) {
1160       throw new
1161         Error('Infinite loop on byte: ' + src.charCodeAt(0));
1162     }
1163   }
1165   return this.tokens;
1169  * Inline-Level Grammar
1170  */
1172 var inline = {
1173   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
1174   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
1175   url: noop,
1176   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
1177   link: /^!?\[(inside)\]\(href\)/,
1178   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
1179   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
1180   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
1181   em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
1182   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
1183   br: /^ {2,}\n(?!\s*$)/,
1184   del: noop,
1185   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
1188 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
1189 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
1191 inline.link = replace(inline.link)
1192   ('inside', inline._inside)
1193   ('href', inline._href)
1194   ();
1196 inline.reflink = replace(inline.reflink)
1197   ('inside', inline._inside)
1198   ();
1201  * Normal Inline Grammar
1202  */
1204 inline.normal = merge({}, inline);
1207  * Pedantic Inline Grammar
1208  */
1210 inline.pedantic = merge({}, inline.normal, {
1211   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
1212   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
1216  * GFM Inline Grammar
1217  */
1219 inline.gfm = merge({}, inline.normal, {
1220   escape: replace(inline.escape)('])', '~|])')(),
1221   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
1222   del: /^~~(?=\S)([\s\S]*?\S)~~/,
1223   text: replace(inline.text)
1224     (']|', '~]|')
1225     ('|', '|https?://|')
1226     ()
1230  * GFM + Line Breaks Inline Grammar
1231  */
1233 inline.breaks = merge({}, inline.gfm, {
1234   br: replace(inline.br)('{2,}', '*')(),
1235   text: replace(inline.gfm.text)('{2,}', '*')()
1239  * Inline Lexer & Compiler
1240  */
1242 function InlineLexer(links, options) {
1243   this.options = options || marked.defaults;
1244   this.links = links;
1245   this.rules = inline.normal;
1246   this.renderer = this.options.renderer || new Renderer;
1247   this.renderer.options = this.options;
1249   if (!this.links) {
1250     throw new
1251       Error('Tokens array requires a `links` property.');
1252   }
1254   if (this.options.gfm) {
1255     if (this.options.breaks) {
1256       this.rules = inline.breaks;
1257     } else {
1258       this.rules = inline.gfm;
1259     }
1260   } else if (this.options.pedantic) {
1261     this.rules = inline.pedantic;
1262   }
1266  * Expose Inline Rules
1267  */
1269 InlineLexer.rules = inline;
1272  * Static Lexing/Compiling Method
1273  */
1275 InlineLexer.output = function(src, links, options) {
1276   var inline = new InlineLexer(links, options);
1277   return inline.output(src);
1281  * Lexing/Compiling
1282  */
1284 InlineLexer.prototype.output = function(src) {
1285   var out = ''
1286     , link
1287     , text
1288     , href
1289     , cap;
1291   while (src) {
1292     // escape
1293     if (cap = this.rules.escape.exec(src)) {
1294       src = src.substring(cap[0].length);
1295       out += cap[1];
1296       continue;
1297     }
1299     // autolink
1300     if (cap = this.rules.autolink.exec(src)) {
1301       src = src.substring(cap[0].length);
1302       if (cap[2] === '@') {
1303         text = cap[1].charAt(6) === ':'
1304           ? this.mangle(cap[1].substring(7))
1305           : this.mangle(cap[1]);
1306         href = this.mangle('mailto:') + text;
1307       } else {
1308         text = escape(cap[1]);
1309         href = text;
1310       }
1311       out += this.renderer.link(href, null, text);
1312       continue;
1313     }
1315     // url (gfm)
1316     if (!this.inLink && (cap = this.rules.url.exec(src))) {
1317       src = src.substring(cap[0].length);
1318       text = escape(cap[1]);
1319       href = text;
1320       out += this.renderer.link(href, null, text);
1321       continue;
1322     }
1324     // tag
1325     if (cap = this.rules.tag.exec(src)) {
1326       if (!this.inLink && /^<a /i.test(cap[0])) {
1327         this.inLink = true;
1328       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
1329         this.inLink = false;
1330       }
1331       src = src.substring(cap[0].length);
1332       out += this.options.sanitize
1333         ? escape(cap[0])
1334         : cap[0];
1335       continue;
1336     }
1338     // link
1339     if (cap = this.rules.link.exec(src)) {
1340       src = src.substring(cap[0].length);
1341       this.inLink = true;
1342       out += this.outputLink(cap, {
1343         href: cap[2],
1344         title: cap[3]
1345       });
1346       this.inLink = false;
1347       continue;
1348     }
1350     // reflink, nolink
1351     if ((cap = this.rules.reflink.exec(src))
1352         || (cap = this.rules.nolink.exec(src))) {
1353       src = src.substring(cap[0].length);
1354       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
1355       link = this.links[link.toLowerCase()];
1356       if (!link || !link.href) {
1357         out += cap[0].charAt(0);
1358         src = cap[0].substring(1) + src;
1359         continue;
1360       }
1361       this.inLink = true;
1362       out += this.outputLink(cap, link);
1363       this.inLink = false;
1364       continue;
1365     }
1367     // strong
1368     if (cap = this.rules.strong.exec(src)) {
1369       src = src.substring(cap[0].length);
1370       out += this.renderer.strong(this.output(cap[2] || cap[1]));
1371       continue;
1372     }
1374     // em
1375     if (cap = this.rules.em.exec(src)) {
1376       src = src.substring(cap[0].length);
1377       out += this.renderer.em(this.output(cap[2] || cap[1]));
1378       continue;
1379     }
1381     // code
1382     if (cap = this.rules.code.exec(src)) {
1383       src = src.substring(cap[0].length);
1384       out += this.renderer.codespan(escape(cap[2], true));
1385       continue;
1386     }
1388     // br
1389     if (cap = this.rules.br.exec(src)) {
1390       src = src.substring(cap[0].length);
1391       out += this.renderer.br();
1392       continue;
1393     }
1395     // del (gfm)
1396     if (cap = this.rules.del.exec(src)) {
1397       src = src.substring(cap[0].length);
1398       out += this.renderer.del(this.output(cap[1]));
1399       continue;
1400     }
1402     // text
1403     if (cap = this.rules.text.exec(src)) {
1404       src = src.substring(cap[0].length);
1405       out += escape(this.smartypants(cap[0]));
1406       continue;
1407     }
1409     if (src) {
1410       throw new
1411         Error('Infinite loop on byte: ' + src.charCodeAt(0));
1412     }
1413   }
1415   return out;
1419  * Compile Link
1420  */
1422 InlineLexer.prototype.outputLink = function(cap, link) {
1423   var href = escape(link.href)
1424     , title = link.title ? escape(link.title) : null;
1426   return cap[0].charAt(0) !== '!'
1427     ? this.renderer.link(href, title, this.output(cap[1]))
1428     : this.renderer.image(href, title, escape(cap[1]));
1432  * Smartypants Transformations
1433  */
1435 InlineLexer.prototype.smartypants = function(text) {
1436   if (!this.options.smartypants) return text;
1437   return text
1438     // em-dashes
1439     .replace(/--/g, '\u2014')
1440     // opening singles
1441     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
1442     // closing singles & apostrophes
1443     .replace(/'/g, '\u2019')
1444     // opening doubles
1445     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
1446     // closing doubles
1447     .replace(/"/g, '\u201d')
1448     // ellipses
1449     .replace(/\.{3}/g, '\u2026');
1453  * Mangle Links
1454  */
1456 InlineLexer.prototype.mangle = function(text) {
1457   var out = ''
1458     , l = text.length
1459     , i = 0
1460     , ch;
1462   for (; i < l; i++) {
1463     ch = text.charCodeAt(i);
1464     if (Math.random() > 0.5) {
1465       ch = 'x' + ch.toString(16);
1466     }
1467     out += '&#' + ch + ';';
1468   }
1470   return out;
1474  * Renderer
1475  */
1477 function Renderer(options) {
1478   this.options = options || {};
1481 Renderer.prototype.code = function(code, lang, escaped) {
1482   if (this.options.highlight) {
1483     var out = this.options.highlight(code, lang);
1484     if (out != null && out !== code) {
1485       escaped = true;
1486       code = out;
1487     }
1488   }
1490   if (!lang) {
1491     return '<pre><code>'
1492       + (escaped ? code : escape(code, true))
1493       + '\n</code></pre>';
1494   }
1496   return '<pre><code class="'
1497     + this.options.langPrefix
1498     + escape(lang, true)
1499     + '">'
1500     + (escaped ? code : escape(code, true))
1501     + '\n</code></pre>\n';
1504 Renderer.prototype.blockquote = function(quote) {
1505   return '<blockquote>\n' + quote + '</blockquote>\n';
1508 Renderer.prototype.html = function(html) {
1509   return html;
1512 Renderer.prototype.heading = function(text, level, raw) {
1513   return '<h'
1514     + level
1515     + ' id="'
1516     + this.options.headerPrefix
1517     + raw.toLowerCase().replace(/[^\w]+/g, '-')
1518     + '">'
1519     + text
1520     + '</h'
1521     + level
1522     + '>\n';
1525 Renderer.prototype.hr = function() {
1526   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
1529 Renderer.prototype.list = function(body, ordered) {
1530   var type = ordered ? 'ol' : 'ul';
1531   return '<' + type + '>\n' + body + '</' + type + '>\n';
1534 Renderer.prototype.listitem = function(text) {
1535   return '<li>' + text + '</li>\n';
1538 Renderer.prototype.paragraph = function(text) {
1539   return '<p>' + text + '</p>\n';
1542 Renderer.prototype.table = function(header, body) {
1543   return '<table>\n'
1544     + '<thead>\n'
1545     + header
1546     + '</thead>\n'
1547     + '<tbody>\n'
1548     + body
1549     + '</tbody>\n'
1550     + '</table>\n';
1553 Renderer.prototype.tablerow = function(content) {
1554   return '<tr>\n' + content + '</tr>\n';
1557 Renderer.prototype.tablecell = function(content, flags) {
1558   var type = flags.header ? 'th' : 'td';
1559   var tag = flags.align
1560     ? '<' + type + ' style="text-align:' + flags.align + '">'
1561     : '<' + type + '>';
1562   return tag + content + '</' + type + '>\n';
1565 // span level renderer
1566 Renderer.prototype.strong = function(text) {
1567   return '<strong>' + text + '</strong>';
1570 Renderer.prototype.em = function(text) {
1571   return '<em>' + text + '</em>';
1574 Renderer.prototype.codespan = function(text) {
1575   return '<code>' + text + '</code>';
1578 Renderer.prototype.br = function() {
1579   return this.options.xhtml ? '<br/>' : '<br>';
1582 Renderer.prototype.del = function(text) {
1583   return '<del>' + text + '</del>';
1586 Renderer.prototype.link = function(href, title, text) {
1587   if (this.options.sanitize) {
1588     try {
1589       var prot = decodeURIComponent(unescape(href))
1590         .replace(/[^\w:]/g, '')
1591         .toLowerCase();
1592     } catch (e) {
1593       return '';
1594     }
1595     if (prot.indexOf('javascript:') === 0) {
1596       return '';
1597     }
1598   }
1599   var out = '<a href="' + href + '"';
1600   if (title) {
1601     out += ' title="' + title + '"';
1602   }
1603   out += '>' + text + '</a>';
1604   return out;
1607 Renderer.prototype.image = function(href, title, text) {
1608   var out = '<img src="' + href + '" alt="' + text + '"';
1609   if (title) {
1610     out += ' title="' + title + '"';
1611   }
1612   out += this.options.xhtml ? '/>' : '>';
1613   return out;
1617  * Parsing & Compiling
1618  */
1620 function Parser(options) {
1621   this.tokens = [];
1622   this.token = null;
1623   this.options = options || marked.defaults;
1624   this.options.renderer = this.options.renderer || new Renderer;
1625   this.renderer = this.options.renderer;
1626   this.renderer.options = this.options;
1630  * Static Parse Method
1631  */
1633 Parser.parse = function(src, options, renderer) {
1634   var parser = new Parser(options, renderer);
1635   return parser.parse(src);
1639  * Parse Loop
1640  */
1642 Parser.prototype.parse = function(src) {
1643   this.inline = new InlineLexer(src.links, this.options, this.renderer);
1644   this.tokens = src.reverse();
1646   var out = '';
1647   while (this.next()) {
1648     out += this.tok();
1649   }
1651   return out;
1655  * Next Token
1656  */
1658 Parser.prototype.next = function() {
1659   return this.token = this.tokens.pop();
1663  * Preview Next Token
1664  */
1666 Parser.prototype.peek = function() {
1667   return this.tokens[this.tokens.length - 1] || 0;
1671  * Parse Text Tokens
1672  */
1674 Parser.prototype.parseText = function() {
1675   var body = this.token.text;
1677   while (this.peek().type === 'text') {
1678     body += '\n' + this.next().text;
1679   }
1681   return this.inline.output(body);
1685  * Parse Current Token
1686  */
1688 Parser.prototype.tok = function() {
1689   switch (this.token.type) {
1690     case 'space': {
1691       return '';
1692     }
1693     case 'hr': {
1694       return this.renderer.hr();
1695     }
1696     case 'heading': {
1697       return this.renderer.heading(
1698         this.inline.output(this.token.text),
1699         this.token.depth,
1700         this.token.text);
1701     }
1702     case 'code': {
1703       return this.renderer.code(this.token.text,
1704         this.token.lang,
1705         this.token.escaped);
1706     }
1707     case 'table': {
1708       var header = ''
1709         , body = ''
1710         , i
1711         , row
1712         , cell
1713         , flags
1714         , j;
1716       // header
1717       cell = '';
1718       for (i = 0; i < this.token.header.length; i++) {
1719         flags = { header: true, align: this.token.align[i] };
1720         cell += this.renderer.tablecell(
1721           this.inline.output(this.token.header[i]),
1722           { header: true, align: this.token.align[i] }
1723         );
1724       }
1725       header += this.renderer.tablerow(cell);
1727       for (i = 0; i < this.token.cells.length; i++) {
1728         row = this.token.cells[i];
1730         cell = '';
1731         for (j = 0; j < row.length; j++) {
1732           cell += this.renderer.tablecell(
1733             this.inline.output(row[j]),
1734             { header: false, align: this.token.align[j] }
1735           );
1736         }
1738         body += this.renderer.tablerow(cell);
1739       }
1740       return this.renderer.table(header, body);
1741     }
1742     case 'blockquote_start': {
1743       var body = '';
1745       while (this.next().type !== 'blockquote_end') {
1746         body += this.tok();
1747       }
1749       return this.renderer.blockquote(body);
1750     }
1751     case 'list_start': {
1752       var body = ''
1753         , ordered = this.token.ordered;
1755       while (this.next().type !== 'list_end') {
1756         body += this.tok();
1757       }
1759       return this.renderer.list(body, ordered);
1760     }
1761     case 'list_item_start': {
1762       var body = '';
1764       while (this.next().type !== 'list_item_end') {
1765         body += this.token.type === 'text'
1766           ? this.parseText()
1767           : this.tok();
1768       }
1770       return this.renderer.listitem(body);
1771     }
1772     case 'loose_item_start': {
1773       var body = '';
1775       while (this.next().type !== 'list_item_end') {
1776         body += this.tok();
1777       }
1779       return this.renderer.listitem(body);
1780     }
1781     case 'html': {
1782       var html = !this.token.pre && !this.options.pedantic
1783         ? this.inline.output(this.token.text)
1784         : this.token.text;
1785       return this.renderer.html(html);
1786     }
1787     case 'paragraph': {
1788       return this.renderer.paragraph(this.inline.output(this.token.text));
1789     }
1790     case 'text': {
1791       return this.renderer.paragraph(this.parseText());
1792     }
1793   }
1797  * Helpers
1798  */
1800 function escape(html, encode) {
1801   return html
1802     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
1803     .replace(/</g, '&lt;')
1804     .replace(/>/g, '&gt;')
1805     .replace(/"/g, '&quot;')
1806     .replace(/'/g, '&#39;');
1809 function unescape(html) {
1810   return html.replace(/&([#\w]+);/g, function(_, n) {
1811     n = n.toLowerCase();
1812     if (n === 'colon') return ':';
1813     if (n.charAt(0) === '#') {
1814       return n.charAt(1) === 'x'
1815         ? String.fromCharCode(parseInt(n.substring(2), 16))
1816         : String.fromCharCode(+n.substring(1));
1817     }
1818     return '';
1819   });
1822 function replace(regex, opt) {
1823   regex = regex.source;
1824   opt = opt || '';
1825   return function self(name, val) {
1826     if (!name) return new RegExp(regex, opt);
1827     val = val.source || val;
1828     val = val.replace(/(^|[^\[])\^/g, '$1');
1829     regex = regex.replace(name, val);
1830     return self;
1831   };
1834 function noop() {}
1835 noop.exec = noop;
1837 function merge(obj) {
1838   var i = 1
1839     , target
1840     , key;
1842   for (; i < arguments.length; i++) {
1843     target = arguments[i];
1844     for (key in target) {
1845       if (Object.prototype.hasOwnProperty.call(target, key)) {
1846         obj[key] = target[key];
1847       }
1848     }
1849   }
1851   return obj;
1856  * Marked
1857  */
1859 function marked(src, opt, callback) {
1860   if (callback || typeof opt === 'function') {
1861     if (!callback) {
1862       callback = opt;
1863       opt = null;
1864     }
1866     opt = merge({}, marked.defaults, opt || {});
1868     var highlight = opt.highlight
1869       , tokens
1870       , pending
1871       , i = 0;
1873     try {
1874       tokens = Lexer.lex(src, opt)
1875     } catch (e) {
1876       return callback(e);
1877     }
1879     pending = tokens.length;
1881     var done = function() {
1882       var out, err;
1884       try {
1885         out = Parser.parse(tokens, opt);
1886       } catch (e) {
1887         err = e;
1888       }
1890       opt.highlight = highlight;
1892       return err
1893         ? callback(err)
1894         : callback(null, out);
1895     };
1897     if (!highlight || highlight.length < 3) {
1898       return done();
1899     }
1901     delete opt.highlight;
1903     if (!pending) return done();
1905     for (; i < tokens.length; i++) {
1906       (function(token) {
1907         if (token.type !== 'code') {
1908           return --pending || done();
1909         }
1910         return highlight(token.text, token.lang, function(err, code) {
1911           if (code == null || code === token.text) {
1912             return --pending || done();
1913           }
1914           token.text = code;
1915           token.escaped = true;
1916           --pending || done();
1917         });
1918       })(tokens[i]);
1919     }
1921     return;
1922   }
1923   try {
1924     if (opt) opt = merge({}, marked.defaults, opt);
1925     return Parser.parse(Lexer.lex(src, opt), opt);
1926   } catch (e) {
1927     e.message += '\nPlease report this to https://github.com/chjj/marked.';
1928     if ((opt || marked.defaults).silent) {
1929       return '<p>An error occured:</p><pre>'
1930         + escape(e.message + '', true)
1931         + '</pre>';
1932     }
1933     throw e;
1934   }
1938  * Options
1939  */
1941 marked.options =
1942 marked.setOptions = function(opt) {
1943   merge(marked.defaults, opt);
1944   return marked;
1947 marked.defaults = {
1948   gfm: true,
1949   tables: true,
1950   breaks: false,
1951   pedantic: false,
1952   sanitize: false,
1953   smartLists: false,
1954   silent: false,
1955   highlight: null,
1956   langPrefix: 'lang-',
1957   smartypants: false,
1958   headerPrefix: '',
1959   renderer: new Renderer,
1960   xhtml: false
1964  * Expose
1965  */
1967 marked.Parser = Parser;
1968 marked.parser = Parser.parse;
1970 marked.Renderer = Renderer;
1972 marked.Lexer = Lexer;
1973 marked.lexer = Lexer.lex;
1975 marked.InlineLexer = InlineLexer;
1976 marked.inlineLexer = InlineLexer.output;
1978 marked.parse = marked;
1980 if (typeof exports === 'object') {
1981   module.exports = marked;
1982 } else if (typeof define === 'function' && define.amd) {
1983   define(function() { return marked; });
1984 } else {
1985   this.marked = marked;
1988 }).call(function() {
1989   return this || (typeof window !== 'undefined' ? window : global);
1990 }());
1994   Polymer('marked-element', {
1996     text: '',
1998     attached: function() {
1999       marked.setOptions({
2000         highlight: this.highlight.bind(this)
2001       });
2002       if (!this.text) {
2003         this.text = this.innerHTML;
2004       }
2005     },
2007     textChanged: function () {
2008       this.innerHTML = marked(this.text);
2009     },
2011     highlight: function(code, lang) {
2012       var event = this.fire('marked-js-highlight', {code: code, lang: lang});
2013       return event.detail.code || code;
2014     }
2016   });
2019 // Copyright (C) 2006 Google Inc.
2021 // Licensed under the Apache License, Version 2.0 (the "License");
2022 // you may not use this file except in compliance with the License.
2023 // You may obtain a copy of the License at
2025 //      http://www.apache.org/licenses/LICENSE-2.0
2027 // Unless required by applicable law or agreed to in writing, software
2028 // distributed under the License is distributed on an "AS IS" BASIS,
2029 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2030 // See the License for the specific language governing permissions and
2031 // limitations under the License.
2035  * @fileoverview
2036  * some functions for browser-side pretty printing of code contained in html.
2038  * <p>
2039  * For a fairly comprehensive set of languages see the
2040  * <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs">README</a>
2041  * file that came with this source.  At a minimum, the lexer should work on a
2042  * number of languages including C and friends, Java, Python, Bash, SQL, HTML,
2043  * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk
2044  * and a subset of Perl, but, because of commenting conventions, doesn't work on
2045  * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.
2046  * <p>
2047  * Usage: <ol>
2048  * <li> include this source file in an html page via
2049  *   {@code <script type="text/javascript" src="/path/to/prettify.js"><\/script>}
2050  * <li> define style rules.  See the example page for examples.
2051  * <li> mark the {@code <pre>} and {@code <code>} tags in your source with
2052  *    {@code class=prettyprint.}
2053  *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty
2054  *    printer needs to do more substantial DOM manipulations to support that, so
2055  *    some css styles may not be preserved.
2056  * </ol>
2057  * That's it.  I wanted to keep the API as simple as possible, so there's no
2058  * need to specify which language the code is in, but if you wish, you can add
2059  * another class to the {@code <pre>} or {@code <code>} element to specify the
2060  * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
2061  * starts with "lang-" followed by a file extension, specifies the file type.
2062  * See the "lang-*.js" files in this directory for code that implements
2063  * per-language file handlers.
2064  * <p>
2065  * Change log:<br>
2066  * cbeust, 2006/08/22
2067  * <blockquote>
2068  *   Java annotations (start with "@") are now captured as literals ("lit")
2069  * </blockquote>
2070  * @requires console
2071  */
2073 // JSLint declarations
2074 /*global console, document, navigator, setTimeout, window, define */
2077  * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
2078  * UI events.
2079  * If set to {@code false}, {@code prettyPrint()} is synchronous.
2080  */
2081 window['PR_SHOULD_USE_CONTINUATION'] = true;
2084  * Find all the {@code <pre>} and {@code <code>} tags in the DOM with
2085  * {@code class=prettyprint} and prettify them.
2087  * @param {Function?} opt_whenDone if specified, called when the last entry
2088  *     has been finished.
2089  */
2090 var prettyPrintOne;
2092  * Pretty print a chunk of code.
2094  * @param {string} sourceCodeHtml code as html
2095  * @return {string} code as html, but prettier
2096  */
2097 var prettyPrint;
2100 (function () {
2101   var win = window;
2102   // Keyword lists for various languages.
2103   // We use things that coerce to strings to make them compact when minified
2104   // and to defeat aggressive optimizers that fold large string constants.
2105   var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"];
2106   var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," + 
2107       "double,enum,extern,float,goto,int,long,register,short,signed,sizeof," +
2108       "static,struct,switch,typedef,union,unsigned,void,volatile"];
2109   var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," +
2110       "new,operator,private,protected,public,this,throw,true,try,typeof"];
2111   var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignof,align_union,asm,axiom,bool," +
2112       "concept,concept_map,const_cast,constexpr,decltype," +
2113       "dynamic_cast,explicit,export,friend,inline,late_check," +
2114       "mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast," +
2115       "template,typeid,typename,using,virtual,where"];
2116   var JAVA_KEYWORDS = [COMMON_KEYWORDS,
2117       "abstract,boolean,byte,extends,final,finally,implements,import," +
2118       "instanceof,null,native,package,strictfp,super,synchronized,throws," +
2119       "transient"];
2120   var CSHARP_KEYWORDS = [JAVA_KEYWORDS,
2121       "as,base,by,checked,decimal,delegate,descending,dynamic,event," +
2122       "fixed,foreach,from,group,implicit,in,interface,internal,into,is,let," +
2123       "lock,object,out,override,orderby,params,partial,readonly,ref,sbyte," +
2124       "sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort," +
2125       "var,virtual,where"];
2126   var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," +
2127       "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," +
2128       "throw,true,try,unless,until,when,while,yes";
2129   var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,
2130       "debugger,eval,export,function,get,null,set,undefined,var,with," +
2131       "Infinity,NaN"];
2132   var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +
2133       "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +
2134       "sub,undef,unless,until,use,wantarray,while,BEGIN,END";
2135   var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "and,as,assert,class,def,del," +
2136       "elif,except,exec,finally,from,global,import,in,is,lambda," +
2137       "nonlocal,not,or,pass,print,raise,try,with,yield," +
2138       "False,True,None"];
2139   var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," +
2140       "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," +
2141       "rescue,retry,self,super,then,true,undef,unless,until,when,yield," +
2142       "BEGIN,END"];
2143   var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," +
2144       "function,in,local,set,then,until"];
2145   var ALL_KEYWORDS = [
2146       CPP_KEYWORDS, CSHARP_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS +
2147       PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];
2148   var C_TYPES = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;
2150   // token style names.  correspond to css classes
2151   /**
2152    * token style for a string literal
2153    * @const
2154    */
2155   var PR_STRING = 'str';
2156   /**
2157    * token style for a keyword
2158    * @const
2159    */
2160   var PR_KEYWORD = 'kwd';
2161   /**
2162    * token style for a comment
2163    * @const
2164    */
2165   var PR_COMMENT = 'com';
2166   /**
2167    * token style for a type
2168    * @const
2169    */
2170   var PR_TYPE = 'typ';
2171   /**
2172    * token style for a literal value.  e.g. 1, null, true.
2173    * @const
2174    */
2175   var PR_LITERAL = 'lit';
2176   /**
2177    * token style for a punctuation string.
2178    * @const
2179    */
2180   var PR_PUNCTUATION = 'pun';
2181   /**
2182    * token style for plain text.
2183    * @const
2184    */
2185   var PR_PLAIN = 'pln';
2187   /**
2188    * token style for an sgml tag.
2189    * @const
2190    */
2191   var PR_TAG = 'tag';
2192   /**
2193    * token style for a markup declaration such as a DOCTYPE.
2194    * @const
2195    */
2196   var PR_DECLARATION = 'dec';
2197   /**
2198    * token style for embedded source.
2199    * @const
2200    */
2201   var PR_SOURCE = 'src';
2202   /**
2203    * token style for an sgml attribute name.
2204    * @const
2205    */
2206   var PR_ATTRIB_NAME = 'atn';
2207   /**
2208    * token style for an sgml attribute value.
2209    * @const
2210    */
2211   var PR_ATTRIB_VALUE = 'atv';
2213   /**
2214    * A class that indicates a section of markup that is not code, e.g. to allow
2215    * embedding of line numbers within code listings.
2216    * @const
2217    */
2218   var PR_NOCODE = 'nocode';
2223  * A set of tokens that can precede a regular expression literal in
2224  * javascript
2225  * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html
2226  * has the full list, but I've removed ones that might be problematic when
2227  * seen in languages that don't support regular expression literals.
2229  * <p>Specifically, I've removed any keywords that can't precede a regexp
2230  * literal in a syntactically legal javascript program, and I've removed the
2231  * "in" keyword since it's not a keyword in many languages, and might be used
2232  * as a count of inches.
2234  * <p>The link above does not accurately describe EcmaScript rules since
2235  * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
2236  * very well in practice.
2238  * @private
2239  * @const
2240  */
2241 var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*';
2243 // CAVEAT: this does not properly handle the case where a regular
2244 // expression immediately follows another since a regular expression may
2245 // have flags for case-sensitivity and the like.  Having regexp tokens
2246 // adjacent is not valid in any language I'm aware of, so I'm punting.
2247 // TODO: maybe style special characters inside a regexp as punctuation.
2250   /**
2251    * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
2252    * matches the union of the sets of strings matched by the input RegExp.
2253    * Since it matches globally, if the input strings have a start-of-input
2254    * anchor (/^.../), it is ignored for the purposes of unioning.
2255    * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
2256    * @return {RegExp} a global regex.
2257    */
2258   function combinePrefixPatterns(regexs) {
2259     var capturedGroupIndex = 0;
2260   
2261     var needToFoldCase = false;
2262     var ignoreCase = false;
2263     for (var i = 0, n = regexs.length; i < n; ++i) {
2264       var regex = regexs[i];
2265       if (regex.ignoreCase) {
2266         ignoreCase = true;
2267       } else if (/[a-z]/i.test(regex.source.replace(
2268                      /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
2269         needToFoldCase = true;
2270         ignoreCase = false;
2271         break;
2272       }
2273     }
2274   
2275     var escapeCharToCodeUnit = {
2276       'b': 8,
2277       't': 9,
2278       'n': 0xa,
2279       'v': 0xb,
2280       'f': 0xc,
2281       'r': 0xd
2282     };
2283   
2284     function decodeEscape(charsetPart) {
2285       var cc0 = charsetPart.charCodeAt(0);
2286       if (cc0 !== 92 /* \\ */) {
2287         return cc0;
2288       }
2289       var c1 = charsetPart.charAt(1);
2290       cc0 = escapeCharToCodeUnit[c1];
2291       if (cc0) {
2292         return cc0;
2293       } else if ('0' <= c1 && c1 <= '7') {
2294         return parseInt(charsetPart.substring(1), 8);
2295       } else if (c1 === 'u' || c1 === 'x') {
2296         return parseInt(charsetPart.substring(2), 16);
2297       } else {
2298         return charsetPart.charCodeAt(1);
2299       }
2300     }
2301   
2302     function encodeEscape(charCode) {
2303       if (charCode < 0x20) {
2304         return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
2305       }
2306       var ch = String.fromCharCode(charCode);
2307       return (ch === '\\' || ch === '-' || ch === ']' || ch === '^')
2308           ? "\\" + ch : ch;
2309     }
2310   
2311     function caseFoldCharset(charSet) {
2312       var charsetParts = charSet.substring(1, charSet.length - 1).match(
2313           new RegExp(
2314               '\\\\u[0-9A-Fa-f]{4}'
2315               + '|\\\\x[0-9A-Fa-f]{2}'
2316               + '|\\\\[0-3][0-7]{0,2}'
2317               + '|\\\\[0-7]{1,2}'
2318               + '|\\\\[\\s\\S]'
2319               + '|-'
2320               + '|[^-\\\\]',
2321               'g'));
2322       var ranges = [];
2323       var inverse = charsetParts[0] === '^';
2324   
2325       var out = ['['];
2326       if (inverse) { out.push('^'); }
2327   
2328       for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
2329         var p = charsetParts[i];
2330         if (/\\[bdsw]/i.test(p)) {  // Don't muck with named groups.
2331           out.push(p);
2332         } else {
2333           var start = decodeEscape(p);
2334           var end;
2335           if (i + 2 < n && '-' === charsetParts[i + 1]) {
2336             end = decodeEscape(charsetParts[i + 2]);
2337             i += 2;
2338           } else {
2339             end = start;
2340           }
2341           ranges.push([start, end]);
2342           // If the range might intersect letters, then expand it.
2343           // This case handling is too simplistic.
2344           // It does not deal with non-latin case folding.
2345           // It works for latin source code identifiers though.
2346           if (!(end < 65 || start > 122)) {
2347             if (!(end < 65 || start > 90)) {
2348               ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
2349             }
2350             if (!(end < 97 || start > 122)) {
2351               ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
2352             }
2353           }
2354         }
2355       }
2356   
2357       // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
2358       // -> [[1, 12], [14, 14], [16, 17]]
2359       ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
2360       var consolidatedRanges = [];
2361       var lastRange = [];
2362       for (var i = 0; i < ranges.length; ++i) {
2363         var range = ranges[i];
2364         if (range[0] <= lastRange[1] + 1) {
2365           lastRange[1] = Math.max(lastRange[1], range[1]);
2366         } else {
2367           consolidatedRanges.push(lastRange = range);
2368         }
2369       }
2370   
2371       for (var i = 0; i < consolidatedRanges.length; ++i) {
2372         var range = consolidatedRanges[i];
2373         out.push(encodeEscape(range[0]));
2374         if (range[1] > range[0]) {
2375           if (range[1] + 1 > range[0]) { out.push('-'); }
2376           out.push(encodeEscape(range[1]));
2377         }
2378       }
2379       out.push(']');
2380       return out.join('');
2381     }
2382   
2383     function allowAnywhereFoldCaseAndRenumberGroups(regex) {
2384       // Split into character sets, escape sequences, punctuation strings
2385       // like ('(', '(?:', ')', '^'), and runs of characters that do not
2386       // include any of the above.
2387       var parts = regex.source.match(
2388           new RegExp(
2389               '(?:'
2390               + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
2391               + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
2392               + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
2393               + '|\\\\[0-9]+'  // a back-reference or octal escape
2394               + '|\\\\[^ux0-9]'  // other escape sequence
2395               + '|\\(\\?[:!=]'  // start of a non-capturing group
2396               + '|[\\(\\)\\^]'  // start/end of a group, or line start
2397               + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
2398               + ')',
2399               'g'));
2400       var n = parts.length;
2401   
2402       // Maps captured group numbers to the number they will occupy in
2403       // the output or to -1 if that has not been determined, or to
2404       // undefined if they need not be capturing in the output.
2405       var capturedGroups = [];
2406   
2407       // Walk over and identify back references to build the capturedGroups
2408       // mapping.
2409       for (var i = 0, groupIndex = 0; i < n; ++i) {
2410         var p = parts[i];
2411         if (p === '(') {
2412           // groups are 1-indexed, so max group index is count of '('
2413           ++groupIndex;
2414         } else if ('\\' === p.charAt(0)) {
2415           var decimalValue = +p.substring(1);
2416           if (decimalValue) {
2417             if (decimalValue <= groupIndex) {
2418               capturedGroups[decimalValue] = -1;
2419             } else {
2420               // Replace with an unambiguous escape sequence so that
2421               // an octal escape sequence does not turn into a backreference
2422               // to a capturing group from an earlier regex.
2423               parts[i] = encodeEscape(decimalValue);
2424             }
2425           }
2426         }
2427       }
2428   
2429       // Renumber groups and reduce capturing groups to non-capturing groups
2430       // where possible.
2431       for (var i = 1; i < capturedGroups.length; ++i) {
2432         if (-1 === capturedGroups[i]) {
2433           capturedGroups[i] = ++capturedGroupIndex;
2434         }
2435       }
2436       for (var i = 0, groupIndex = 0; i < n; ++i) {
2437         var p = parts[i];
2438         if (p === '(') {
2439           ++groupIndex;
2440           if (!capturedGroups[groupIndex]) {
2441             parts[i] = '(?:';
2442           }
2443         } else if ('\\' === p.charAt(0)) {
2444           var decimalValue = +p.substring(1);
2445           if (decimalValue && decimalValue <= groupIndex) {
2446             parts[i] = '\\' + capturedGroups[decimalValue];
2447           }
2448         }
2449       }
2450   
2451       // Remove any prefix anchors so that the output will match anywhere.
2452       // ^^ really does mean an anchored match though.
2453       for (var i = 0; i < n; ++i) {
2454         if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
2455       }
2456   
2457       // Expand letters to groups to handle mixing of case-sensitive and
2458       // case-insensitive patterns if necessary.
2459       if (regex.ignoreCase && needToFoldCase) {
2460         for (var i = 0; i < n; ++i) {
2461           var p = parts[i];
2462           var ch0 = p.charAt(0);
2463           if (p.length >= 2 && ch0 === '[') {
2464             parts[i] = caseFoldCharset(p);
2465           } else if (ch0 !== '\\') {
2466             // TODO: handle letters in numeric escapes.
2467             parts[i] = p.replace(
2468                 /[a-zA-Z]/g,
2469                 function (ch) {
2470                   var cc = ch.charCodeAt(0);
2471                   return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
2472                 });
2473           }
2474         }
2475       }
2476   
2477       return parts.join('');
2478     }
2479   
2480     var rewritten = [];
2481     for (var i = 0, n = regexs.length; i < n; ++i) {
2482       var regex = regexs[i];
2483       if (regex.global || regex.multiline) { throw new Error('' + regex); }
2484       rewritten.push(
2485           '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
2486     }
2487   
2488     return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
2489   }
2492   /**
2493    * Split markup into a string of source code and an array mapping ranges in
2494    * that string to the text nodes in which they appear.
2495    *
2496    * <p>
2497    * The HTML DOM structure:</p>
2498    * <pre>
2499    * (Element   "p"
2500    *   (Element "b"
2501    *     (Text  "print "))       ; #1
2502    *   (Text    "'Hello '")      ; #2
2503    *   (Element "br")            ; #3
2504    *   (Text    "  + 'World';")) ; #4
2505    * </pre>
2506    * <p>
2507    * corresponds to the HTML
2508    * {@code <p><b>print </b>'Hello '<br>  + 'World';</p>}.</p>
2509    *
2510    * <p>
2511    * It will produce the output:</p>
2512    * <pre>
2513    * {
2514    *   sourceCode: "print 'Hello '\n  + 'World';",
2515    *   //                     1          2
2516    *   //           012345678901234 5678901234567
2517    *   spans: [0, #1, 6, #2, 14, #3, 15, #4]
2518    * }
2519    * </pre>
2520    * <p>
2521    * where #1 is a reference to the {@code "print "} text node above, and so
2522    * on for the other text nodes.
2523    * </p>
2524    *
2525    * <p>
2526    * The {@code} spans array is an array of pairs.  Even elements are the start
2527    * indices of substrings, and odd elements are the text nodes (or BR elements)
2528    * that contain the text for those substrings.
2529    * Substrings continue until the next index or the end of the source.
2530    * </p>
2531    *
2532    * @param {Node} node an HTML DOM subtree containing source-code.
2533    * @param {boolean} isPreformatted true if white-space in text nodes should
2534    *    be considered significant.
2535    * @return {Object} source code and the text nodes in which they occur.
2536    */
2537   function extractSourceSpans(node, isPreformatted) {
2538     var nocode = /(?:^|\s)nocode(?:\s|$)/;
2539   
2540     var chunks = [];
2541     var length = 0;
2542     var spans = [];
2543     var k = 0;
2544   
2545     function walk(node) {
2546       switch (node.nodeType) {
2547         case 1:  // Element
2548           if (nocode.test(node.className)) { return; }
2549           for (var child = node.firstChild; child; child = child.nextSibling) {
2550             walk(child);
2551           }
2552           var nodeName = node.nodeName.toLowerCase();
2553           if ('br' === nodeName || 'li' === nodeName) {
2554             chunks[k] = '\n';
2555             spans[k << 1] = length++;
2556             spans[(k++ << 1) | 1] = node;
2557           }
2558           break;
2559         case 3: case 4:  // Text
2560           var text = node.nodeValue;
2561           if (text.length) {
2562             if (!isPreformatted) {
2563               text = text.replace(/[ \t\r\n]+/g, ' ');
2564             } else {
2565               text = text.replace(/\r\n?/g, '\n');  // Normalize newlines.
2566             }
2567             // TODO: handle tabs here?
2568             chunks[k] = text;
2569             spans[k << 1] = length;
2570             length += text.length;
2571             spans[(k++ << 1) | 1] = node;
2572           }
2573           break;
2574       }
2575     }
2576   
2577     walk(node);
2578   
2579     return {
2580       sourceCode: chunks.join('').replace(/\n$/, ''),
2581       spans: spans
2582     };
2583   }
2586   /**
2587    * Apply the given language handler to sourceCode and add the resulting
2588    * decorations to out.
2589    * @param {number} basePos the index of sourceCode within the chunk of source
2590    *    whose decorations are already present on out.
2591    */
2592   function appendDecorations(basePos, sourceCode, langHandler, out) {
2593     if (!sourceCode) { return; }
2594     var job = {
2595       sourceCode: sourceCode,
2596       basePos: basePos
2597     };
2598     langHandler(job);
2599     out.push.apply(out, job.decorations);
2600   }
2602   var notWs = /\S/;
2604   /**
2605    * Given an element, if it contains only one child element and any text nodes
2606    * it contains contain only space characters, return the sole child element.
2607    * Otherwise returns undefined.
2608    * <p>
2609    * This is meant to return the CODE element in {@code <pre><code ...>} when
2610    * there is a single child element that contains all the non-space textual
2611    * content, but not to return anything where there are multiple child elements
2612    * as in {@code <pre><code>...</code><code>...</code></pre>} or when there
2613    * is textual content.
2614    */
2615   function childContentWrapper(element) {
2616     var wrapper = undefined;
2617     for (var c = element.firstChild; c; c = c.nextSibling) {
2618       var type = c.nodeType;
2619       wrapper = (type === 1)  // Element Node
2620           ? (wrapper ? element : c)
2621           : (type === 3)  // Text Node
2622           ? (notWs.test(c.nodeValue) ? element : wrapper)
2623           : wrapper;
2624     }
2625     return wrapper === element ? undefined : wrapper;
2626   }
2628   /** Given triples of [style, pattern, context] returns a lexing function,
2629     * The lexing function interprets the patterns to find token boundaries and
2630     * returns a decoration list of the form
2631     * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
2632     * where index_n is an index into the sourceCode, and style_n is a style
2633     * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
2634     * all characters in sourceCode[index_n-1:index_n].
2635     *
2636     * The stylePatterns is a list whose elements have the form
2637     * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
2638     *
2639     * Style is a style constant like PR_PLAIN, or can be a string of the
2640     * form 'lang-FOO', where FOO is a language extension describing the
2641     * language of the portion of the token in $1 after pattern executes.
2642     * E.g., if style is 'lang-lisp', and group 1 contains the text
2643     * '(hello (world))', then that portion of the token will be passed to the
2644     * registered lisp handler for formatting.
2645     * The text before and after group 1 will be restyled using this decorator
2646     * so decorators should take care that this doesn't result in infinite
2647     * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
2648     * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
2649     * '<script>foo()<\/script>', which would cause the current decorator to
2650     * be called with '<script>' which would not match the same rule since
2651     * group 1 must not be empty, so it would be instead styled as PR_TAG by
2652     * the generic tag rule.  The handler registered for the 'js' extension would
2653     * then be called with 'foo()', and finally, the current decorator would
2654     * be called with '<\/script>' which would not match the original rule and
2655     * so the generic tag rule would identify it as a tag.
2656     *
2657     * Pattern must only match prefixes, and if it matches a prefix, then that
2658     * match is considered a token with the same style.
2659     *
2660     * Context is applied to the last non-whitespace, non-comment token
2661     * recognized.
2662     *
2663     * Shortcut is an optional string of characters, any of which, if the first
2664     * character, gurantee that this pattern and only this pattern matches.
2665     *
2666     * @param {Array} shortcutStylePatterns patterns that always start with
2667     *   a known character.  Must have a shortcut string.
2668     * @param {Array} fallthroughStylePatterns patterns that will be tried in
2669     *   order if the shortcut ones fail.  May have shortcuts.
2670     *
2671     * @return {function (Object)} a
2672     *   function that takes source code and returns a list of decorations.
2673     */
2674   function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
2675     var shortcuts = {};
2676     var tokenizer;
2677     (function () {
2678       var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
2679       var allRegexs = [];
2680       var regexKeys = {};
2681       for (var i = 0, n = allPatterns.length; i < n; ++i) {
2682         var patternParts = allPatterns[i];
2683         var shortcutChars = patternParts[3];
2684         if (shortcutChars) {
2685           for (var c = shortcutChars.length; --c >= 0;) {
2686             shortcuts[shortcutChars.charAt(c)] = patternParts;
2687           }
2688         }
2689         var regex = patternParts[1];
2690         var k = '' + regex;
2691         if (!regexKeys.hasOwnProperty(k)) {
2692           allRegexs.push(regex);
2693           regexKeys[k] = null;
2694         }
2695       }
2696       allRegexs.push(/[\0-\uffff]/);
2697       tokenizer = combinePrefixPatterns(allRegexs);
2698     })();
2700     var nPatterns = fallthroughStylePatterns.length;
2702     /**
2703      * Lexes job.sourceCode and produces an output array job.decorations of
2704      * style classes preceded by the position at which they start in
2705      * job.sourceCode in order.
2706      *
2707      * @param {Object} job an object like <pre>{
2708      *    sourceCode: {string} sourceText plain text,
2709      *    basePos: {int} position of job.sourceCode in the larger chunk of
2710      *        sourceCode.
2711      * }</pre>
2712      */
2713     var decorate = function (job) {
2714       var sourceCode = job.sourceCode, basePos = job.basePos;
2715       /** Even entries are positions in source in ascending order.  Odd enties
2716         * are style markers (e.g., PR_COMMENT) that run from that position until
2717         * the end.
2718         * @type {Array.<number|string>}
2719         */
2720       var decorations = [basePos, PR_PLAIN];
2721       var pos = 0;  // index into sourceCode
2722       var tokens = sourceCode.match(tokenizer) || [];
2723       var styleCache = {};
2725       for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
2726         var token = tokens[ti];
2727         var style = styleCache[token];
2728         var match = void 0;
2730         var isEmbedded;
2731         if (typeof style === 'string') {
2732           isEmbedded = false;
2733         } else {
2734           var patternParts = shortcuts[token.charAt(0)];
2735           if (patternParts) {
2736             match = token.match(patternParts[1]);
2737             style = patternParts[0];
2738           } else {
2739             for (var i = 0; i < nPatterns; ++i) {
2740               patternParts = fallthroughStylePatterns[i];
2741               match = token.match(patternParts[1]);
2742               if (match) {
2743                 style = patternParts[0];
2744                 break;
2745               }
2746             }
2748             if (!match) {  // make sure that we make progress
2749               style = PR_PLAIN;
2750             }
2751           }
2753           isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
2754           if (isEmbedded && !(match && typeof match[1] === 'string')) {
2755             isEmbedded = false;
2756             style = PR_SOURCE;
2757           }
2759           if (!isEmbedded) { styleCache[token] = style; }
2760         }
2762         var tokenStart = pos;
2763         pos += token.length;
2765         if (!isEmbedded) {
2766           decorations.push(basePos + tokenStart, style);
2767         } else {  // Treat group 1 as an embedded block of source code.
2768           var embeddedSource = match[1];
2769           var embeddedSourceStart = token.indexOf(embeddedSource);
2770           var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
2771           if (match[2]) {
2772             // If embeddedSource can be blank, then it would match at the
2773             // beginning which would cause us to infinitely recurse on the
2774             // entire token, so we catch the right context in match[2].
2775             embeddedSourceEnd = token.length - match[2].length;
2776             embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
2777           }
2778           var lang = style.substring(5);
2779           // Decorate the left of the embedded source
2780           appendDecorations(
2781               basePos + tokenStart,
2782               token.substring(0, embeddedSourceStart),
2783               decorate, decorations);
2784           // Decorate the embedded source
2785           appendDecorations(
2786               basePos + tokenStart + embeddedSourceStart,
2787               embeddedSource,
2788               langHandlerForExtension(lang, embeddedSource),
2789               decorations);
2790           // Decorate the right of the embedded section
2791           appendDecorations(
2792               basePos + tokenStart + embeddedSourceEnd,
2793               token.substring(embeddedSourceEnd),
2794               decorate, decorations);
2795         }
2796       }
2797       job.decorations = decorations;
2798     };
2799     return decorate;
2800   }
2802   /** returns a function that produces a list of decorations from source text.
2803     *
2804     * This code treats ", ', and ` as string delimiters, and \ as a string
2805     * escape.  It does not recognize perl's qq() style strings.
2806     * It has no special handling for double delimiter escapes as in basic, or
2807     * the tripled delimiters used in python, but should work on those regardless
2808     * although in those cases a single string literal may be broken up into
2809     * multiple adjacent string literals.
2810     *
2811     * It recognizes C, C++, and shell style comments.
2812     *
2813     * @param {Object} options a set of optional parameters.
2814     * @return {function (Object)} a function that examines the source code
2815     *     in the input job and builds the decoration list.
2816     */
2817   function sourceDecorator(options) {
2818     var shortcutStylePatterns = [], fallthroughStylePatterns = [];
2819     if (options['tripleQuotedStrings']) {
2820       // '''multi-line-string''', 'single-line-string', and double-quoted
2821       shortcutStylePatterns.push(
2822           [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
2823            null, '\'"']);
2824     } else if (options['multiLineStrings']) {
2825       // 'multi-line-string', "multi-line-string"
2826       shortcutStylePatterns.push(
2827           [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
2828            null, '\'"`']);
2829     } else {
2830       // 'single-line-string', "single-line-string"
2831       shortcutStylePatterns.push(
2832           [PR_STRING,
2833            /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
2834            null, '"\'']);
2835     }
2836     if (options['verbatimStrings']) {
2837       // verbatim-string-literal production from the C# grammar.  See issue 93.
2838       fallthroughStylePatterns.push(
2839           [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
2840     }
2841     var hc = options['hashComments'];
2842     if (hc) {
2843       if (options['cStyleComments']) {
2844         if (hc > 1) {  // multiline hash comments
2845           shortcutStylePatterns.push(
2846               [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']);
2847         } else {
2848           // Stop C preprocessor declarations at an unclosed open comment
2849           shortcutStylePatterns.push(
2850               [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
2851                null, '#']);
2852         }
2853         // #include <stdio.h>
2854         fallthroughStylePatterns.push(
2855             [PR_STRING,
2856              /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,
2857              null]);
2858       } else {
2859         shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
2860       }
2861     }
2862     if (options['cStyleComments']) {
2863       fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
2864       fallthroughStylePatterns.push(
2865           [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
2866     }
2867     if (options['regexLiterals']) {
2868       /**
2869        * @const
2870        */
2871       var REGEX_LITERAL = (
2872           // A regular expression literal starts with a slash that is
2873           // not followed by * or / so that it is not confused with
2874           // comments.
2875           '/(?=[^/*])'
2876           // and then contains any number of raw characters,
2877           + '(?:[^/\\x5B\\x5C]'
2878           // escape sequences (\x5C),
2879           +    '|\\x5C[\\s\\S]'
2880           // or non-nesting character sets (\x5B\x5D);
2881           +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
2882           // finally closed by a /.
2883           + '/');
2884       fallthroughStylePatterns.push(
2885           ['lang-regex',
2886            new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
2887            ]);
2888     }
2890     var types = options['types'];
2891     if (types) {
2892       fallthroughStylePatterns.push([PR_TYPE, types]);
2893     }
2895     var keywords = ("" + options['keywords']).replace(/^ | $/g, '');
2896     if (keywords.length) {
2897       fallthroughStylePatterns.push(
2898           [PR_KEYWORD,
2899            new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'),
2900            null]);
2901     }
2903     shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
2905     var punctuation =
2906       // The Bash man page says
2908       // A word is a sequence of characters considered as a single
2909       // unit by GRUB. Words are separated by metacharacters,
2910       // which are the following plus space, tab, and newline: { }
2911       // | & $ ; < >
2912       // ...
2913       
2914       // A word beginning with # causes that word and all remaining
2915       // characters on that line to be ignored.
2917       // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a
2918       // comment but empirically
2919       // $ echo {#}
2920       // {#}
2921       // $ echo \$#
2922       // $#
2923       // $ echo }#
2924       // }#
2926       // so /(?:^|[|&;<>\s])/ is more appropriate.
2928       // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3
2929       // suggests that this definition is compatible with a
2930       // default mode that tries to use a single token definition
2931       // to recognize both bash/python style comments and C
2932       // preprocessor directives.
2934       // This definition of punctuation does not include # in the list of
2935       // follow-on exclusions, so # will not be broken before if preceeded
2936       // by a punctuation character.  We could try to exclude # after
2937       // [|&;<>] but that doesn't seem to cause many major problems.
2938       // If that does turn out to be a problem, we should change the below
2939       // when hc is truthy to include # in the run of punctuation characters
2940       // only when not followint [|&;<>].
2941       /^.[^\s\w\.$@\'\"\`\/\\]*/;
2943     fallthroughStylePatterns.push(
2944         // TODO(mikesamuel): recognize non-latin letters and numerals in idents
2945         [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
2946         [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null],
2947         [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
2948         [PR_LITERAL,
2949          new RegExp(
2950              '^(?:'
2951              // A hex number
2952              + '0x[a-f0-9]+'
2953              // or an octal or decimal number,
2954              + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
2955              // possibly in scientific notation
2956              + '(?:e[+\\-]?\\d+)?'
2957              + ')'
2958              // with an optional modifier like UL for unsigned long
2959              + '[a-z]*', 'i'),
2960          null, '0123456789'],
2961         // Don't treat escaped quotes in bash as starting strings.  See issue 144.
2962         [PR_PLAIN,       /^\\[\s\S]?/, null],
2963         [PR_PUNCTUATION, punctuation, null]);
2965     return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
2966   }
2968   var decorateSource = sourceDecorator({
2969         'keywords': ALL_KEYWORDS,
2970         'hashComments': true,
2971         'cStyleComments': true,
2972         'multiLineStrings': true,
2973         'regexLiterals': true
2974       });
2976   /**
2977    * Given a DOM subtree, wraps it in a list, and puts each line into its own
2978    * list item.
2979    *
2980    * @param {Node} node modified in place.  Its content is pulled into an
2981    *     HTMLOListElement, and each line is moved into a separate list item.
2982    *     This requires cloning elements, so the input might not have unique
2983    *     IDs after numbering.
2984    * @param {boolean} isPreformatted true iff white-space in text nodes should
2985    *     be treated as significant.
2986    */
2987   function numberLines(node, opt_startLineNum, isPreformatted) {
2988     var nocode = /(?:^|\s)nocode(?:\s|$)/;
2989     var lineBreak = /\r\n?|\n/;
2990   
2991     var document = node.ownerDocument;
2992   
2993     var li = document.createElement('li');
2994     while (node.firstChild) {
2995       li.appendChild(node.firstChild);
2996     }
2997     // An array of lines.  We split below, so this is initialized to one
2998     // un-split line.
2999     var listItems = [li];
3000   
3001     function walk(node) {
3002       switch (node.nodeType) {
3003         case 1:  // Element
3004           if (nocode.test(node.className)) { break; }
3005           if ('br' === node.nodeName) {
3006             breakAfter(node);
3007             // Discard the <BR> since it is now flush against a </LI>.
3008             if (node.parentNode) {
3009               node.parentNode.removeChild(node);
3010             }
3011           } else {
3012             for (var child = node.firstChild; child; child = child.nextSibling) {
3013               walk(child);
3014             }
3015           }
3016           break;
3017         case 3: case 4:  // Text
3018           if (isPreformatted) {
3019             var text = node.nodeValue;
3020             var match = text.match(lineBreak);
3021             if (match) {
3022               var firstLine = text.substring(0, match.index);
3023               node.nodeValue = firstLine;
3024               var tail = text.substring(match.index + match[0].length);
3025               if (tail) {
3026                 var parent = node.parentNode;
3027                 parent.insertBefore(
3028                     document.createTextNode(tail), node.nextSibling);
3029               }
3030               breakAfter(node);
3031               if (!firstLine) {
3032                 // Don't leave blank text nodes in the DOM.
3033                 node.parentNode.removeChild(node);
3034               }
3035             }
3036           }
3037           break;
3038       }
3039     }
3040   
3041     // Split a line after the given node.
3042     function breakAfter(lineEndNode) {
3043       // If there's nothing to the right, then we can skip ending the line
3044       // here, and move root-wards since splitting just before an end-tag
3045       // would require us to create a bunch of empty copies.
3046       while (!lineEndNode.nextSibling) {
3047         lineEndNode = lineEndNode.parentNode;
3048         if (!lineEndNode) { return; }
3049       }
3050   
3051       function breakLeftOf(limit, copy) {
3052         // Clone shallowly if this node needs to be on both sides of the break.
3053         var rightSide = copy ? limit.cloneNode(false) : limit;
3054         var parent = limit.parentNode;
3055         if (parent) {
3056           // We clone the parent chain.
3057           // This helps us resurrect important styling elements that cross lines.
3058           // E.g. in <i>Foo<br>Bar</i>
3059           // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.
3060           var parentClone = breakLeftOf(parent, 1);
3061           // Move the clone and everything to the right of the original
3062           // onto the cloned parent.
3063           var next = limit.nextSibling;
3064           parentClone.appendChild(rightSide);
3065           for (var sibling = next; sibling; sibling = next) {
3066             next = sibling.nextSibling;
3067             parentClone.appendChild(sibling);
3068           }
3069         }
3070         return rightSide;
3071       }
3072   
3073       var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);
3074   
3075       // Walk the parent chain until we reach an unattached LI.
3076       for (var parent;
3077            // Check nodeType since IE invents document fragments.
3078            (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {
3079         copiedListItem = parent;
3080       }
3081       // Put it on the list of lines for later processing.
3082       listItems.push(copiedListItem);
3083     }
3084   
3085     // Split lines while there are lines left to split.
3086     for (var i = 0;  // Number of lines that have been split so far.
3087          i < listItems.length;  // length updated by breakAfter calls.
3088          ++i) {
3089       walk(listItems[i]);
3090     }
3091   
3092     // Make sure numeric indices show correctly.
3093     if (opt_startLineNum === (opt_startLineNum|0)) {
3094       listItems[0].setAttribute('value', opt_startLineNum);
3095     }
3096   
3097     var ol = document.createElement('ol');
3098     ol.className = 'linenums';
3099     var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0;
3100     for (var i = 0, n = listItems.length; i < n; ++i) {
3101       li = listItems[i];
3102       // Stick a class on the LIs so that stylesheets can
3103       // color odd/even rows, or any other row pattern that
3104       // is co-prime with 10.
3105       li.className = 'L' + ((i + offset) % 10);
3106       if (!li.firstChild) {
3107         li.appendChild(document.createTextNode('\xA0'));
3108       }
3109       ol.appendChild(li);
3110     }
3111   
3112     node.appendChild(ol);
3113   }
3115   /**
3116    * Breaks {@code job.sourceCode} around style boundaries in
3117    * {@code job.decorations} and modifies {@code job.sourceNode} in place.
3118    * @param {Object} job like <pre>{
3119    *    sourceCode: {string} source as plain text,
3120    *    spans: {Array.<number|Node>} alternating span start indices into source
3121    *       and the text node or element (e.g. {@code <BR>}) corresponding to that
3122    *       span.
3123    *    decorations: {Array.<number|string} an array of style classes preceded
3124    *       by the position at which they start in job.sourceCode in order
3125    * }</pre>
3126    * @private
3127    */
3128   function recombineTagsAndDecorations(job) {
3129     var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent);
3130     isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;
3131     var newlineRe = /\n/g;
3132   
3133     var source = job.sourceCode;
3134     var sourceLength = source.length;
3135     // Index into source after the last code-unit recombined.
3136     var sourceIndex = 0;
3137   
3138     var spans = job.spans;
3139     var nSpans = spans.length;
3140     // Index into spans after the last span which ends at or before sourceIndex.
3141     var spanIndex = 0;
3142   
3143     var decorations = job.decorations;
3144     var nDecorations = decorations.length;
3145     // Index into decorations after the last decoration which ends at or before
3146     // sourceIndex.
3147     var decorationIndex = 0;
3148   
3149     // Remove all zero-length decorations.
3150     decorations[nDecorations] = sourceLength;
3151     var decPos, i;
3152     for (i = decPos = 0; i < nDecorations;) {
3153       if (decorations[i] !== decorations[i + 2]) {
3154         decorations[decPos++] = decorations[i++];
3155         decorations[decPos++] = decorations[i++];
3156       } else {
3157         i += 2;
3158       }
3159     }
3160     nDecorations = decPos;
3161   
3162     // Simplify decorations.
3163     for (i = decPos = 0; i < nDecorations;) {
3164       var startPos = decorations[i];
3165       // Conflate all adjacent decorations that use the same style.
3166       var startDec = decorations[i + 1];
3167       var end = i + 2;
3168       while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {
3169         end += 2;
3170       }
3171       decorations[decPos++] = startPos;
3172       decorations[decPos++] = startDec;
3173       i = end;
3174     }
3175   
3176     nDecorations = decorations.length = decPos;
3177   
3178     var sourceNode = job.sourceNode;
3179     var oldDisplay;
3180     if (sourceNode) {
3181       oldDisplay = sourceNode.style.display;
3182       sourceNode.style.display = 'none';
3183     }
3184     try {
3185       var decoration = null;
3186       while (spanIndex < nSpans) {
3187         var spanStart = spans[spanIndex];
3188         var spanEnd = spans[spanIndex + 2] || sourceLength;
3189   
3190         var decEnd = decorations[decorationIndex + 2] || sourceLength;
3191   
3192         var end = Math.min(spanEnd, decEnd);
3193   
3194         var textNode = spans[spanIndex + 1];
3195         var styledText;
3196         if (textNode.nodeType !== 1  // Don't muck with <BR>s or <LI>s
3197             // Don't introduce spans around empty text nodes.
3198             && (styledText = source.substring(sourceIndex, end))) {
3199           // This may seem bizarre, and it is.  Emitting LF on IE causes the
3200           // code to display with spaces instead of line breaks.
3201           // Emitting Windows standard issue linebreaks (CRLF) causes a blank
3202           // space to appear at the beginning of every line but the first.
3203           // Emitting an old Mac OS 9 line separator makes everything spiffy.
3204           if (isIE8OrEarlier) {
3205             styledText = styledText.replace(newlineRe, '\r');
3206           }
3207           textNode.nodeValue = styledText;
3208           var document = textNode.ownerDocument;
3209           var span = document.createElement('span');
3210           span.className = decorations[decorationIndex + 1];
3211           var parentNode = textNode.parentNode;
3212           parentNode.replaceChild(span, textNode);
3213           span.appendChild(textNode);
3214           if (sourceIndex < spanEnd) {  // Split off a text node.
3215             spans[spanIndex + 1] = textNode
3216                 // TODO: Possibly optimize by using '' if there's no flicker.
3217                 = document.createTextNode(source.substring(end, spanEnd));
3218             parentNode.insertBefore(textNode, span.nextSibling);
3219           }
3220         }
3221   
3222         sourceIndex = end;
3223   
3224         if (sourceIndex >= spanEnd) {
3225           spanIndex += 2;
3226         }
3227         if (sourceIndex >= decEnd) {
3228           decorationIndex += 2;
3229         }
3230       }
3231     } finally {
3232       if (sourceNode) {
3233         sourceNode.style.display = oldDisplay;
3234       }
3235     }
3236   }
3239   /** Maps language-specific file extensions to handlers. */
3240   var langHandlerRegistry = {};
3241   /** Register a language handler for the given file extensions.
3242     * @param {function (Object)} handler a function from source code to a list
3243     *      of decorations.  Takes a single argument job which describes the
3244     *      state of the computation.   The single parameter has the form
3245     *      {@code {
3246     *        sourceCode: {string} as plain text.
3247     *        decorations: {Array.<number|string>} an array of style classes
3248     *                     preceded by the position at which they start in
3249     *                     job.sourceCode in order.
3250     *                     The language handler should assigned this field.
3251     *        basePos: {int} the position of source in the larger source chunk.
3252     *                 All positions in the output decorations array are relative
3253     *                 to the larger source chunk.
3254     *      } }
3255     * @param {Array.<string>} fileExtensions
3256     */
3257   function registerLangHandler(handler, fileExtensions) {
3258     for (var i = fileExtensions.length; --i >= 0;) {
3259       var ext = fileExtensions[i];
3260       if (!langHandlerRegistry.hasOwnProperty(ext)) {
3261         langHandlerRegistry[ext] = handler;
3262       } else if (win['console']) {
3263         console['warn']('cannot override language handler %s', ext);
3264       }
3265     }
3266   }
3267   function langHandlerForExtension(extension, source) {
3268     if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
3269       // Treat it as markup if the first non whitespace character is a < and
3270       // the last non-whitespace character is a >.
3271       extension = /^\s*</.test(source)
3272           ? 'default-markup'
3273           : 'default-code';
3274     }
3275     return langHandlerRegistry[extension];
3276   }
3277   registerLangHandler(decorateSource, ['default-code']);
3278   registerLangHandler(
3279       createSimpleLexer(
3280           [],
3281           [
3282            [PR_PLAIN,       /^[^<?]+/],
3283            [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
3284            [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
3285            // Unescaped content in an unknown language
3286            ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
3287            ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
3288            [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
3289            ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
3290            // Unescaped content in javascript.  (Or possibly vbscript).
3291            ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
3292            // Contains unescaped stylesheet content
3293            ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
3294            ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
3295           ]),
3296       ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
3297   registerLangHandler(
3298       createSimpleLexer(
3299           [
3300            [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
3301            [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
3302            ],
3303           [
3304            [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
3305            [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
3306            ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
3307            [PR_PUNCTUATION,  /^[=<>\/]+/],
3308            ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
3309            ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
3310            ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
3311            ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
3312            ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
3313            ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
3314            ]),
3315       ['in.tag']);
3316   registerLangHandler(
3317       createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
3318   registerLangHandler(sourceDecorator({
3319           'keywords': CPP_KEYWORDS,
3320           'hashComments': true,
3321           'cStyleComments': true,
3322           'types': C_TYPES
3323         }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
3324   registerLangHandler(sourceDecorator({
3325           'keywords': 'null,true,false'
3326         }), ['json']);
3327   registerLangHandler(sourceDecorator({
3328           'keywords': CSHARP_KEYWORDS,
3329           'hashComments': true,
3330           'cStyleComments': true,
3331           'verbatimStrings': true,
3332           'types': C_TYPES
3333         }), ['cs']);
3334   registerLangHandler(sourceDecorator({
3335           'keywords': JAVA_KEYWORDS,
3336           'cStyleComments': true
3337         }), ['java']);
3338   registerLangHandler(sourceDecorator({
3339           'keywords': SH_KEYWORDS,
3340           'hashComments': true,
3341           'multiLineStrings': true
3342         }), ['bsh', 'csh', 'sh']);
3343   registerLangHandler(sourceDecorator({
3344           'keywords': PYTHON_KEYWORDS,
3345           'hashComments': true,
3346           'multiLineStrings': true,
3347           'tripleQuotedStrings': true
3348         }), ['cv', 'py']);
3349   registerLangHandler(sourceDecorator({
3350           'keywords': PERL_KEYWORDS,
3351           'hashComments': true,
3352           'multiLineStrings': true,
3353           'regexLiterals': true
3354         }), ['perl', 'pl', 'pm']);
3355   registerLangHandler(sourceDecorator({
3356           'keywords': RUBY_KEYWORDS,
3357           'hashComments': true,
3358           'multiLineStrings': true,
3359           'regexLiterals': true
3360         }), ['rb']);
3361   registerLangHandler(sourceDecorator({
3362           'keywords': JSCRIPT_KEYWORDS,
3363           'cStyleComments': true,
3364           'regexLiterals': true
3365         }), ['js']);
3366   registerLangHandler(sourceDecorator({
3367           'keywords': COFFEE_KEYWORDS,
3368           'hashComments': 3,  // ### style block comments
3369           'cStyleComments': true,
3370           'multilineStrings': true,
3371           'tripleQuotedStrings': true,
3372           'regexLiterals': true
3373         }), ['coffee']);
3374   registerLangHandler(
3375       createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
3377   function applyDecorator(job) {
3378     var opt_langExtension = job.langExtension;
3380     try {
3381       // Extract tags, and convert the source code to plain text.
3382       var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);
3383       /** Plain text. @type {string} */
3384       var source = sourceAndSpans.sourceCode;
3385       job.sourceCode = source;
3386       job.spans = sourceAndSpans.spans;
3387       job.basePos = 0;
3389       // Apply the appropriate language handler
3390       langHandlerForExtension(opt_langExtension, source)(job);
3392       // Integrate the decorations and tags back into the source code,
3393       // modifying the sourceNode in place.
3394       recombineTagsAndDecorations(job);
3395     } catch (e) {
3396       if (win['console']) {
3397         console['log'](e && e['stack'] ? e['stack'] : e);
3398       }
3399     }
3400   }
3402   /**
3403    * @param sourceCodeHtml {string} The HTML to pretty print.
3404    * @param opt_langExtension {string} The language name to use.
3405    *     Typically, a filename extension like 'cpp' or 'java'.
3406    * @param opt_numberLines {number|boolean} True to number lines,
3407    *     or the 1-indexed number of the first line in sourceCodeHtml.
3408    */
3409   function prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {
3410     var container = document.createElement('pre');
3411     // This could cause images to load and onload listeners to fire.
3412     // E.g. <img onerror="alert(1337)" src="nosuchimage.png">.
3413     // We assume that the inner HTML is from a trusted source.
3414     container.innerHTML = sourceCodeHtml;
3415     if (opt_numberLines) {
3416       numberLines(container, opt_numberLines, true);
3417     }
3419     var job = {
3420       langExtension: opt_langExtension,
3421       numberLines: opt_numberLines,
3422       sourceNode: container,
3423       pre: 1
3424     };
3425     applyDecorator(job);
3426     return container.innerHTML;
3427   }
3429   function prettyPrint(opt_whenDone) {
3430     function byTagName(tn) { return document.getElementsByTagName(tn); }
3431     // fetch a list of nodes to rewrite
3432     var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
3433     var elements = [];
3434     for (var i = 0; i < codeSegments.length; ++i) {
3435       for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
3436         elements.push(codeSegments[i][j]);
3437       }
3438     }
3439     codeSegments = null;
3441     var clock = Date;
3442     if (!clock['now']) {
3443       clock = { 'now': function () { return +(new Date); } };
3444     }
3446     // The loop is broken into a series of continuations to make sure that we
3447     // don't make the browser unresponsive when rewriting a large page.
3448     var k = 0;
3449     var prettyPrintingJob;
3451     var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/;
3452     var prettyPrintRe = /\bprettyprint\b/;
3453     var prettyPrintedRe = /\bprettyprinted\b/;
3454     var preformattedTagNameRe = /pre|xmp/i;
3455     var codeRe = /^code$/i;
3456     var preCodeXmpRe = /^(?:pre|code|xmp)$/i;
3458     function doWork() {
3459       var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ?
3460                      clock['now']() + 250 /* ms */ :
3461                      Infinity);
3462       for (; k < elements.length && clock['now']() < endTime; k++) {
3463         var cs = elements[k];
3464         var className = cs.className;
3465         if (prettyPrintRe.test(className)
3466             // Don't redo this if we've already done it.
3467             // This allows recalling pretty print to just prettyprint elements
3468             // that have been added to the page since last call.
3469             && !prettyPrintedRe.test(className)) {
3471           // make sure this is not nested in an already prettified element
3472           var nested = false;
3473           for (var p = cs.parentNode; p; p = p.parentNode) {
3474             var tn = p.tagName;
3475             if (preCodeXmpRe.test(tn)
3476                 && p.className && prettyPrintRe.test(p.className)) {
3477               nested = true;
3478               break;
3479             }
3480           }
3481           if (!nested) {
3482             // Mark done.  If we fail to prettyprint for whatever reason,
3483             // we shouldn't try again.
3484             cs.className += ' prettyprinted';
3486             // If the classes includes a language extensions, use it.
3487             // Language extensions can be specified like
3488             //     <pre class="prettyprint lang-cpp">
3489             // the language extension "cpp" is used to find a language handler
3490             // as passed to PR.registerLangHandler.
3491             // HTML5 recommends that a language be specified using "language-"
3492             // as the prefix instead.  Google Code Prettify supports both.
3493             // http://dev.w3.org/html5/spec-author-view/the-code-element.html
3494             var langExtension = className.match(langExtensionRe);
3495             // Support <pre class="prettyprint"><code class="language-c">
3496             var wrapper;
3497             if (!langExtension && (wrapper = childContentWrapper(cs))
3498                 && codeRe.test(wrapper.tagName)) {
3499               langExtension = wrapper.className.match(langExtensionRe);
3500             }
3502             if (langExtension) { langExtension = langExtension[1]; }
3504             var preformatted;
3505             if (preformattedTagNameRe.test(cs.tagName)) {
3506               preformatted = 1;
3507             } else {
3508               var currentStyle = cs['currentStyle'];
3509               var whitespace = (
3510                   currentStyle
3511                   ? currentStyle['whiteSpace']
3512                   : (document.defaultView
3513                      && document.defaultView.getComputedStyle)
3514                   ? document.defaultView.getComputedStyle(cs, null)
3515                   .getPropertyValue('white-space')
3516                   : 0);
3517               preformatted = whitespace
3518                   && 'pre' === whitespace.substring(0, 3);
3519             }
3521             // Look for a class like linenums or linenums:<n> where <n> is the
3522             // 1-indexed number of the first line.
3523             var lineNums = cs.className.match(/\blinenums\b(?::(\d+))?/);
3524             lineNums = lineNums
3525                 ? lineNums[1] && lineNums[1].length ? +lineNums[1] : true
3526                 : false;
3527             if (lineNums) { numberLines(cs, lineNums, preformatted); }
3529             // do the pretty printing
3530             prettyPrintingJob = {
3531               langExtension: langExtension,
3532               sourceNode: cs,
3533               numberLines: lineNums,
3534               pre: preformatted
3535             };
3536             applyDecorator(prettyPrintingJob);
3537           }
3538         }
3539       }
3540       if (k < elements.length) {
3541         // finish up in a continuation
3542         setTimeout(doWork, 250);
3543       } else if (opt_whenDone) {
3544         opt_whenDone();
3545       }
3546     }
3548     doWork();
3549   }
3551   /**
3552    * Contains functions for creating and registering new language handlers.
3553    * @type {Object}
3554    */
3555   var PR = win['PR'] = {
3556         'createSimpleLexer': createSimpleLexer,
3557         'registerLangHandler': registerLangHandler,
3558         'sourceDecorator': sourceDecorator,
3559         'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
3560         'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
3561         'PR_COMMENT': PR_COMMENT,
3562         'PR_DECLARATION': PR_DECLARATION,
3563         'PR_KEYWORD': PR_KEYWORD,
3564         'PR_LITERAL': PR_LITERAL,
3565         'PR_NOCODE': PR_NOCODE,
3566         'PR_PLAIN': PR_PLAIN,
3567         'PR_PUNCTUATION': PR_PUNCTUATION,
3568         'PR_SOURCE': PR_SOURCE,
3569         'PR_STRING': PR_STRING,
3570         'PR_TAG': PR_TAG,
3571         'PR_TYPE': PR_TYPE,
3572         'prettyPrintOne': win['prettyPrintOne'] = prettyPrintOne,
3573         'prettyPrint': win['prettyPrint'] = prettyPrint
3574       };
3576   // Make PR available via the Asynchronous Module Definition (AMD) API.
3577   // Per https://github.com/amdjs/amdjs-api/wiki/AMD:
3578   // The Asynchronous Module Definition (AMD) API specifies a
3579   // mechanism for defining modules such that the module and its
3580   // dependencies can be asynchronously loaded.
3581   // ...
3582   // To allow a clear indicator that a global define function (as
3583   // needed for script src browser loading) conforms to the AMD API,
3584   // any global define function SHOULD have a property called "amd"
3585   // whose value is an object. This helps avoid conflict with any
3586   // other existing JavaScript code that could have defined a define()
3587   // function that does not conform to the AMD API.
3588   if (typeof define === "function" && define['amd']) {
3589     define(function () {
3590       return PR; 
3591     });
3592   }
3593 })();
3595 (function(scope) {
3596   
3597   var ContextFreeParser = {
3598     parse: function(text) {
3599       var top = {};
3600       var entities = [];
3601       var current = top;
3602       var subCurrent = {};
3603   
3604       var scriptDocCommentClause = '\\/\\*\\*([\\s\\S]*?)\\*\\/';
3605       var htmlDocCommentClause = '<!--([\\s\\S]*?)-->';
3606   
3607       // matches text between /** and */ inclusive and <!-- and --> inclusive
3608       var docCommentRegex = new RegExp(scriptDocCommentClause + '|' + htmlDocCommentClause, 'g');
3609   
3610       // acquire all script doc comments
3611       var docComments = text.match(docCommentRegex) || [];
3612   
3613       // each match represents a single block of doc comments
3614       docComments.forEach(function(m) {
3615         // unify line ends, remove all comment characters, split into individual lines
3616         var lines = m.replace(/\r\n/g, '\n').replace(/^\s*\/\*\*|^\s*\*\/|^\s*\* ?|^\s*\<\!-\-|^s*\-\-\>/gm, '').split('\n');
3617   
3618         // pragmas (@-rules) must occur on a line by themselves
3619         var pragmas = [];
3620         // filter lines whose first non-whitespace character is @ into the pragma list
3621         // (and out of the `lines` array)
3622         lines = lines.filter(function(l) {
3623           var m = l.match(/\s*@([\w-]*) (.*)/);
3624           if (!m) {
3625             return true;
3626           }
3627           pragmas.push(m);
3628         });
3629   
3630         // collect all other text into a single block
3631         var code = lines.join('\n');
3632         
3633         // process pragmas
3634         pragmas.forEach(function(m) {
3635           var pragma = m[1], content = m[2];
3636           switch (pragma) {
3637   
3638             // currently all entities are either @class or @element
3639             case 'class':
3640             case 'element':
3641               current = {
3642                 name: content,
3643                 description: code
3644               };
3645               entities.push(current);
3646               break;
3647             
3648             // an entity may have these describable sub-features
3649             case 'attribute':
3650             case 'property':
3651             case 'method':
3652             case 'event':
3653               subCurrent = {
3654                 name: content,
3655                 description: code
3656               };
3657               var label = pragma == 'property' ? 'properties' : pragma + 's';
3658               makePragma(current, label, subCurrent);
3659               break;
3660   
3661             // sub-feature pragmas
3662             case 'default':
3663             case 'type':
3664               subCurrent[pragma] = content;
3665               break;
3666   
3667             // everything else
3668             default:
3669               current[pragma] = content;
3670               break;
3671           }
3672         });
3673   
3674         // utility function, yay hoisting
3675         function makePragma(object, pragma, content) {
3676           var p$ = object;
3677           var p = p$[pragma];
3678           if (!p) {
3679             p$[pragma] = p = [];
3680           }
3681           p.push(content);
3682         }
3683   
3684       });
3685   
3686       if (entities.length === 0) {
3687         entities.push({name: 'Entity', description: '**Undocumented**'});
3688       }
3689       return entities;
3690     }
3691   };
3692   
3693   if (typeof module !== 'undefined' && module.exports) {
3694     module.exports = ContextFreeParser;
3695   } else {
3696     scope.ContextFreeParser = ContextFreeParser;
3697   }
3698   
3699 })(this);;
3702     Polymer('core-xhr', {
3704       /**
3705        * Sends a HTTP request to the server and returns the XHR object.
3706        *
3707        * @method request
3708        * @param {Object} inOptions
3709        *    @param {String} inOptions.url The url to which the request is sent.
3710        *    @param {String} inOptions.method The HTTP method to use, default is GET.
3711        *    @param {boolean} inOptions.sync By default, all requests are sent asynchronously. To send synchronous requests, set to true.
3712        *    @param {Object} inOptions.params Data to be sent to the server.
3713        *    @param {Object} inOptions.body The content for the request body for POST method.
3714        *    @param {Object} inOptions.headers HTTP request headers.
3715        *    @param {String} inOptions.responseType The response type. Default is 'text'.
3716        *    @param {boolean} inOptions.withCredentials Whether or not to send credentials on the request. Default is false.
3717        *    @param {Object} inOptions.callback Called when request is completed.
3718        * @returns {Object} XHR object.
3719        */
3720       request: function(options) {
3721         var xhr = new XMLHttpRequest();
3722         var url = options.url;
3723         var method = options.method || 'GET';
3724         var async = !options.sync;
3725         //
3726         var params = this.toQueryString(options.params);
3727         if (params && method == 'GET') {
3728           url += (url.indexOf('?') > 0 ? '&' : '?') + params;
3729         }
3730         var xhrParams = this.isBodyMethod(method) ? (options.body || params) : null;
3731         //
3732         xhr.open(method, url, async);
3733         if (options.responseType) {
3734           xhr.responseType = options.responseType;
3735         }
3736         if (options.withCredentials) {
3737           xhr.withCredentials = true;
3738         }
3739         this.makeReadyStateHandler(xhr, options.callback);
3740         this.setRequestHeaders(xhr, options.headers);
3741         xhr.send(xhrParams);
3742         if (!async) {
3743           xhr.onreadystatechange(xhr);
3744         }
3745         return xhr;
3746       },
3747     
3748       toQueryString: function(params) {
3749         var r = [];
3750         for (var n in params) {
3751           var v = params[n];
3752           n = encodeURIComponent(n);
3753           r.push(v == null ? n : (n + '=' + encodeURIComponent(v)));
3754         }
3755         return r.join('&');
3756       },
3758       isBodyMethod: function(method) {
3759         return this.bodyMethods[(method || '').toUpperCase()];
3760       },
3761       
3762       bodyMethods: {
3763         POST: 1,
3764         PUT: 1,
3765         DELETE: 1
3766       },
3768       makeReadyStateHandler: function(xhr, callback) {
3769         xhr.onreadystatechange = function() {
3770           if (xhr.readyState == 4) {
3771             callback && callback.call(null, xhr.response, xhr);
3772           }
3773         };
3774       },
3776       setRequestHeaders: function(xhr, headers) {
3777         if (headers) {
3778           for (var name in headers) {
3779             xhr.setRequestHeader(name, headers[name]);
3780           }
3781         }
3782       }
3784     });
3786   ;
3789   Polymer('core-ajax', {
3790     /**
3791      * Fired when a response is received.
3792      * 
3793      * @event core-response
3794      */
3796     /**
3797      * Fired when an error is received.
3798      * 
3799      * @event core-error
3800      */
3802     /**
3803      * Fired whenever a response or an error is received.
3804      *
3805      * @event core-complete
3806      */
3808     /**
3809      * The URL target of the request.
3810      * 
3811      * @attribute url
3812      * @type string
3813      * @default ''
3814      */
3815     url: '',
3817     /**
3818      * Specifies what data to store in the `response` property, and
3819      * to deliver as `event.response` in `response` events.
3820      * 
3821      * One of:
3822      * 
3823      *    `text`: uses `XHR.responseText`.
3824      *    
3825      *    `xml`: uses `XHR.responseXML`.
3826      *    
3827      *    `json`: uses `XHR.responseText` parsed as JSON.
3828      *
3829      *    `arraybuffer`: uses `XHR.response`.
3830      *
3831      *    `blob`: uses `XHR.response`.
3832      *
3833      *    `document`: uses `XHR.response`.
3834      *  
3835      * @attribute handleAs
3836      * @type string
3837      * @default 'text'
3838      */
3839     handleAs: '',
3841     /**
3842      * If true, automatically performs an Ajax request when either `url` or `params` changes.
3843      *
3844      * @attribute auto
3845      * @type boolean
3846      * @default false
3847      */
3848     auto: false,
3850     /**
3851      * Parameters to send to the specified URL, as JSON.
3852      *  
3853      * @attribute params
3854      * @type string (JSON)
3855      * @default ''
3856      */
3857     params: '',
3859     /**
3860      * Returns the response object.
3861      *
3862      * @attribute response
3863      * @type Object
3864      * @default null
3865      */
3866     response: null,
3868     /**
3869      * The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'.
3870      * Default is 'GET'.
3871      *
3872      * @attribute method
3873      * @type string
3874      * @default ''
3875      */
3876     method: '',
3878     /**
3879      * HTTP request headers to send.
3880      *
3881      * Example:
3882      *
3883      *     <core-ajax 
3884      *         auto
3885      *         url="http://somesite.com"
3886      *         headers='{"X-Requested-With": "XMLHttpRequest"}'
3887      *         handleAs="json"
3888      *         on-core-response="{{handleResponse}}"></core-ajax>
3889      *  
3890      * @attribute headers
3891      * @type Object
3892      * @default null
3893      */
3894     headers: null,
3896     /**
3897      * Optional raw body content to send when method === "POST".
3898      *
3899      * Example:
3900      *
3901      *     <core-ajax method="POST" auto url="http://somesite.com"
3902      *         body='{"foo":1, "bar":2}'>
3903      *     </core-ajax>
3904      *  
3905      * @attribute body
3906      * @type Object
3907      * @default null
3908      */
3909     body: null,
3911     /**
3912      * Content type to use when sending data.
3913      *
3914      * @attribute contentType
3915      * @type string
3916      * @default 'application/x-www-form-urlencoded'
3917      */
3918     contentType: 'application/x-www-form-urlencoded',
3920     /**
3921      * Set the withCredentials flag on the request.
3922      * 
3923      * @attribute withCredentials
3924      * @type boolean
3925      * @default false
3926      */
3927     withCredentials: false,
3928     
3929     /**
3930      * Additional properties to send to core-xhr.
3931      *
3932      * Can be set to an object containing default properties
3933      * to send as arguments to the `core-xhr.request()` method
3934      * which implements the low-level communication.
3935      * 
3936      * @property xhrArgs
3937      * @type Object
3938      * @default null
3939      */
3940     xhrArgs: null,
3941      
3942     ready: function() {
3943       this.xhr = document.createElement('core-xhr');
3944     },
3946     receive: function(response, xhr) {
3947       if (this.isSuccess(xhr)) {
3948         this.processResponse(xhr);
3949       } else {
3950         this.error(xhr);
3951       }
3952       this.complete(xhr);
3953     },
3955     isSuccess: function(xhr) {
3956       var status = xhr.status || 0;
3957       return !status || (status >= 200 && status < 300);
3958     },
3960     processResponse: function(xhr) {
3961       var response = this.evalResponse(xhr);
3962       this.response = response;
3963       this.fire('core-response', {response: response, xhr: xhr});
3964     },
3966     error: function(xhr) {
3967       var response = xhr.status + ': ' + xhr.responseText;
3968       this.fire('core-error', {response: response, xhr: xhr});
3969     },
3971     complete: function(xhr) {
3972       this.fire('core-complete', {response: xhr.status, xhr: xhr});
3973     },
3975     evalResponse: function(xhr) {
3976       return this[(this.handleAs || 'text') + 'Handler'](xhr);
3977     },
3979     xmlHandler: function(xhr) {
3980       return xhr.responseXML;
3981     },
3983     textHandler: function(xhr) {
3984       return xhr.responseText;
3985     },
3987     jsonHandler: function(xhr) {
3988       var r = xhr.responseText;
3989       try {
3990         return JSON.parse(r);
3991       } catch (x) {
3992         return r;
3993       }
3994     },
3996     documentHandler: function(xhr) {
3997       return xhr.response;
3998     },
4000     blobHandler: function(xhr) {
4001       return xhr.response;
4002     },
4004     arraybufferHandler: function(xhr) {
4005       return xhr.response;
4006     },
4008     urlChanged: function() {
4009       if (!this.handleAs) {
4010         var ext = String(this.url).split('.').pop();
4011         switch (ext) {
4012           case 'json':
4013             this.handleAs = 'json';
4014             break;
4015         }
4016       }
4017       this.autoGo();
4018     },
4020     paramsChanged: function() {
4021       this.autoGo();
4022     },
4024     autoChanged: function() {
4025       this.autoGo();
4026     },
4028     // TODO(sorvell): multiple side-effects could call autoGo 
4029     // during one micro-task, use a job to have only one action 
4030     // occur
4031     autoGo: function() {
4032       if (this.auto) {
4033         this.goJob = this.job(this.goJob, this.go, 0);
4034       }
4035     },
4037     /**
4038      * Performs an Ajax request to the specified URL.
4039      *
4040      * @method go
4041      */
4042     go: function() {
4043       var args = this.xhrArgs || {};
4044       // TODO(sjmiles): we may want XHR to default to POST if body is set
4045       args.body = this.body || args.body;
4046       args.params = this.params || args.params;
4047       if (args.params && typeof(args.params) == 'string') {
4048         args.params = JSON.parse(args.params);
4049       }
4050       args.headers = this.headers || args.headers || {};
4051       if (args.headers && typeof(args.headers) == 'string') {
4052         args.headers = JSON.parse(args.headers);
4053       }
4054       if (this.contentType) {
4055         args.headers['content-type'] = this.contentType;
4056       }
4057       if (this.handleAs === 'arraybuffer' || this.handleAs === 'blob' ||
4058           this.handleAs === 'document') {
4059         args.responseType = this.handleAs;
4060       }
4061       args.withCredentials = this.withCredentials;
4062       args.callback = this.receive.bind(this);
4063       args.url = this.url;
4064       args.method = this.method;
4065       return args.url && this.xhr.request(args);
4066     }
4068   });
4073   Polymer('context-free-parser', {
4075     text: null,
4077     textChanged: function() {
4078       if (this.text) {
4079         var entities = ContextFreeParser.parse(this.text);
4080         if (!entities || entities.length === 0) {
4081           entities = [
4082             {name: this.url.split('/').pop(), description: '**Undocumented**'}
4083           ];
4084         }
4085         this.data = { classes: entities };
4086       }
4087     },
4089     dataChanged: function() {
4090       this.fire('data-ready');
4091     }
4093   });
4098     Polymer('core-doc-page', {
4100       hilight: function(event, detail, sender) {
4101         detail.code = prettyPrintOne((detail.code || '').replace(/</g,'&lt;').replace(/>/g,'&gt;'));
4102       },
4104       homepageFilter: function(data) {
4105         if (!data) {
4106           return '';
4107         }
4108         if (!data.homepage || data.homepage === 'github.io') {
4109           return '//polymer.github.io/' + data.name;
4110         } else {
4111           return data.homepage;
4112         }
4113       }
4115     });
4117   ;
4119     Polymer('core-selection', {
4120       /**
4121        * If true, multiple selections are allowed.
4122        *
4123        * @attribute multi
4124        * @type boolean
4125        * @default false
4126        */
4127       multi: false,
4128       ready: function() {
4129         this.clear();
4130       },
4131       clear: function() {
4132         this.selection = [];
4133       },
4134       /**
4135        * Retrieves the selected item(s).
4136        * @method getSelection
4137        * @returns Returns the selected item(s). If the multi property is true,
4138        * getSelection will return an array, otherwise it will return 
4139        * the selected item or undefined if there is no selection.
4140       */
4141       getSelection: function() {
4142         return this.multi ? this.selection : this.selection[0];
4143       },
4144       /**
4145        * Indicates if a given item is selected.
4146        * @method isSelected
4147        * @param {any} item The item whose selection state should be checked.
4148        * @returns Returns true if `item` is selected.
4149       */
4150       isSelected: function(item) {
4151         return this.selection.indexOf(item) >= 0;
4152       },
4153       setItemSelected: function(item, isSelected) {
4154         if (item !== undefined && item !== null) {
4155           if (isSelected) {
4156             this.selection.push(item);
4157           } else {
4158             var i = this.selection.indexOf(item);
4159             if (i >= 0) {
4160               this.selection.splice(i, 1);
4161             }
4162           }
4163           this.fire("core-select", {isSelected: isSelected, item: item});
4164         }
4165       },
4166       /**
4167        * Set the selection state for a given `item`. If the multi property
4168        * is true, then the selected state of `item` will be toggled; otherwise
4169        * the `item` will be selected.
4170        * @method select
4171        * @param {any} item: The item to select.
4172       */
4173       select: function(item) {
4174         if (this.multi) {
4175           this.toggle(item);
4176         } else if (this.getSelection() !== item) {
4177           this.setItemSelected(this.getSelection(), false);
4178           this.setItemSelected(item, true);
4179         }
4180       },
4181       /**
4182        * Toggles the selection state for `item`.
4183        * @method toggle
4184        * @param {any} item: The item to toggle.
4185       */
4186       toggle: function(item) {
4187         this.setItemSelected(item, !this.isSelected(item));
4188       }
4189     });
4190   ;
4193     Polymer('core-selector', {
4195       /**
4196        * Gets or sets the selected element.  Default to use the index
4197        * of the item element.
4198        *
4199        * If you want a specific attribute value of the element to be
4200        * used instead of index, set "valueattr" to that attribute name.
4201        *
4202        * Example:
4203        *
4204        *     <core-selector valueattr="label" selected="foo">
4205        *       <div label="foo"></div>
4206        *       <div label="bar"></div>
4207        *       <div label="zot"></div>
4208        *     </core-selector>
4209        *
4210        * In multi-selection this should be an array of values.
4211        *
4212        * Example:
4213        *
4214        *     <core-selector id="selector" valueattr="label" multi>
4215        *       <div label="foo"></div>
4216        *       <div label="bar"></div>
4217        *       <div label="zot"></div>
4218        *     </core-selector>
4219        *
4220        *     this.$.selector.selected = ['foo', 'zot'];
4221        *
4222        * @attribute selected
4223        * @type Object
4224        * @default null
4225        */
4226       selected: null,
4228       /**
4229        * If true, multiple selections are allowed.
4230        *
4231        * @attribute multi
4232        * @type boolean
4233        * @default false
4234        */
4235       multi: false,
4237       /**
4238        * Specifies the attribute to be used for "selected" attribute.
4239        *
4240        * @attribute valueattr
4241        * @type string
4242        * @default 'name'
4243        */
4244       valueattr: 'name',
4246       /**
4247        * Specifies the CSS class to be used to add to the selected element.
4248        * 
4249        * @attribute selectedClass
4250        * @type string
4251        * @default 'core-selected'
4252        */
4253       selectedClass: 'core-selected',
4255       /**
4256        * Specifies the property to be used to set on the selected element
4257        * to indicate its active state.
4258        *
4259        * @attribute selectedProperty
4260        * @type string
4261        * @default ''
4262        */
4263       selectedProperty: '',
4265       /**
4266        * Specifies the attribute to set on the selected element to indicate
4267        * its active state.
4268        *
4269        * @attribute selectedAttribute
4270        * @type string
4271        * @default 'active'
4272        */
4273       selectedAttribute: 'active',
4275       /**
4276        * Returns the currently selected element. In multi-selection this returns
4277        * an array of selected elements.
4278        * 
4279        * @attribute selectedItem
4280        * @type Object
4281        * @default null
4282        */
4283       selectedItem: null,
4285       /**
4286        * In single selection, this returns the model associated with the
4287        * selected element.
4288        * 
4289        * @attribute selectedModel
4290        * @type Object
4291        * @default null
4292        */
4293       selectedModel: null,
4295       /**
4296        * In single selection, this returns the selected index.
4297        *
4298        * @attribute selectedIndex
4299        * @type number
4300        * @default -1
4301        */
4302       selectedIndex: -1,
4304       /**
4305        * The target element that contains items.  If this is not set 
4306        * core-selector is the container.
4307        * 
4308        * @attribute target
4309        * @type Object
4310        * @default null
4311        */
4312       target: null,
4314       /**
4315        * This can be used to query nodes from the target node to be used for 
4316        * selection items.  Note this only works if the 'target' property is set.
4317        *
4318        * Example:
4319        *
4320        *     <core-selector target="{{$.myForm}}" itemsSelector="input[type=radio]"></core-selector>
4321        *     <form id="myForm">
4322        *       <label><input type="radio" name="color" value="red"> Red</label> <br>
4323        *       <label><input type="radio" name="color" value="green"> Green</label> <br>
4324        *       <label><input type="radio" name="color" value="blue"> Blue</label> <br>
4325        *       <p>color = {{color}}</p>
4326        *     </form>
4327        * 
4328        * @attribute itemSelector
4329        * @type string
4330        * @default ''
4331        */
4332       itemsSelector: '',
4334       /**
4335        * The event that would be fired from the item element to indicate
4336        * it is being selected.
4337        *
4338        * @attribute activateEvent
4339        * @type string
4340        * @default 'tap'
4341        */
4342       activateEvent: 'tap',
4344       /**
4345        * Set this to true to disallow changing the selection via the
4346        * `activateEvent`.
4347        *
4348        * @attribute notap
4349        * @type boolean
4350        * @default false
4351        */
4352       notap: false,
4354       ready: function() {
4355         this.activateListener = this.activateHandler.bind(this);
4356         this.observer = new MutationObserver(this.updateSelected.bind(this));
4357         if (!this.target) {
4358           this.target = this;
4359         }
4360       },
4362       get items() {
4363         if (!this.target) {
4364           return [];
4365         }
4366         var nodes = this.target !== this ? (this.itemsSelector ? 
4367             this.target.querySelectorAll(this.itemsSelector) : 
4368                 this.target.children) : this.$.items.getDistributedNodes();
4369         return Array.prototype.filter.call(nodes || [], function(n) {
4370           return n && n.localName !== 'template';
4371         });
4372       },
4374       targetChanged: function(old) {
4375         if (old) {
4376           this.removeListener(old);
4377           this.observer.disconnect();
4378           this.clearSelection();
4379         }
4380         if (this.target) {
4381           this.addListener(this.target);
4382           this.observer.observe(this.target, {childList: true});
4383           this.updateSelected();
4384         }
4385       },
4387       addListener: function(node) {
4388         node.addEventListener(this.activateEvent, this.activateListener);
4389       },
4391       removeListener: function(node) {
4392         node.removeEventListener(this.activateEvent, this.activateListener);
4393       },
4395       get selection() {
4396         return this.$.selection.getSelection();
4397       },
4399       selectedChanged: function() {
4400         this.updateSelected();
4401       },
4403       updateSelected: function() {
4404         this.validateSelected();
4405         if (this.multi) {
4406           this.clearSelection();
4407           this.selected && this.selected.forEach(function(s) {
4408             this.valueToSelection(s);
4409           }, this);
4410         } else {
4411           this.valueToSelection(this.selected);
4412         }
4413       },
4415       validateSelected: function() {
4416         // convert to an array for multi-selection
4417         if (this.multi && !Array.isArray(this.selected) && 
4418             this.selected !== null && this.selected !== undefined) {
4419           this.selected = [this.selected];
4420         }
4421       },
4423       clearSelection: function() {
4424         if (this.multi) {
4425           this.selection.slice().forEach(function(s) {
4426             this.$.selection.setItemSelected(s, false);
4427           }, this);
4428         } else {
4429           this.$.selection.setItemSelected(this.selection, false);
4430         }
4431         this.selectedItem = null;
4432         this.$.selection.clear();
4433       },
4435       valueToSelection: function(value) {
4436         var item = (value === null || value === undefined) ? 
4437             null : this.items[this.valueToIndex(value)];
4438         this.$.selection.select(item);
4439       },
4441       updateSelectedItem: function() {
4442         this.selectedItem = this.selection;
4443       },
4445       selectedItemChanged: function() {
4446         if (this.selectedItem) {
4447           var t = this.selectedItem.templateInstance;
4448           this.selectedModel = t ? t.model : undefined;
4449         } else {
4450           this.selectedModel = null;
4451         }
4452         this.selectedIndex = this.selectedItem ? 
4453             parseInt(this.valueToIndex(this.selected)) : -1;
4454       },
4456       valueToIndex: function(value) {
4457         // find an item with value == value and return it's index
4458         for (var i=0, items=this.items, c; (c=items[i]); i++) {
4459           if (this.valueForNode(c) == value) {
4460             return i;
4461           }
4462         }
4463         // if no item found, the value itself is probably the index
4464         return value;
4465       },
4467       valueForNode: function(node) {
4468         return node[this.valueattr] || node.getAttribute(this.valueattr);
4469       },
4471       // events fired from <core-selection> object
4472       selectionSelect: function(e, detail) {
4473         this.updateSelectedItem();
4474         if (detail.item) {
4475           this.applySelection(detail.item, detail.isSelected);
4476         }
4477       },
4479       applySelection: function(item, isSelected) {
4480         if (this.selectedClass) {
4481           item.classList.toggle(this.selectedClass, isSelected);
4482         }
4483         if (this.selectedProperty) {
4484           item[this.selectedProperty] = isSelected;
4485         }
4486         if (this.selectedAttribute && item.setAttribute) {
4487           if (isSelected) {
4488             item.setAttribute(this.selectedAttribute, '');
4489           } else {
4490             item.removeAttribute(this.selectedAttribute);
4491           }
4492         }
4493       },
4495       // event fired from host
4496       activateHandler: function(e) {
4497         if (!this.notap) {
4498           var i = this.findDistributedTarget(e.target, this.items);
4499           if (i >= 0) {
4500             var item = this.items[i];
4501             var s = this.valueForNode(item) || i;
4502             if (this.multi) {
4503               if (this.selected) {
4504                 this.addRemoveSelected(s);
4505               } else {
4506                 this.selected = [s];
4507               }
4508             } else {
4509               this.selected = s;
4510             }
4511             this.asyncFire('core-activate', {item: item});
4512           }
4513         }
4514       },
4516       addRemoveSelected: function(value) {
4517         var i = this.selected.indexOf(value);
4518         if (i >= 0) {
4519           this.selected.splice(i, 1);
4520         } else {
4521           this.selected.push(value);
4522         }
4523         this.valueToSelection(value);
4524       },
4526       findDistributedTarget: function(target, nodes) {
4527         // find first ancestor of target (including itself) that
4528         // is in nodes, if any
4529         while (target && target != this) {
4530           var i = Array.prototype.indexOf.call(nodes, target);
4531           if (i >= 0) {
4532             return i;
4533           }
4534           target = target.parentNode;
4535         }
4536       }
4537     });
4538   ;
4540   Polymer('core-menu',{});
4544   Polymer('core-item', {
4545     
4546     /**
4547      * The URL of an image for the icon.
4548      *
4549      * @attribute src
4550      * @type string
4551      * @default ''
4552      */
4554     /**
4555      * Specifies the icon from the Polymer icon set.
4556      *
4557      * @attribute icon
4558      * @type string
4559      * @default ''
4560      */
4562     /**
4563      * Specifies the label for the menu item.
4564      *
4565      * @attribute label
4566      * @type string
4567      * @default ''
4568      */
4570   });
4575     Polymer('core-doc-toc', {\r
4577       searchAction: function() {\r
4578         this.$.searchBar.style.opacity = 1;\r
4579         this.$.searchBar.style.display = '';\r
4580       },\r
4582       closeSearchAction: function() {\r
4583         this.$.searchBar.style.opacity = 0;\r
4584         this.$.searchBar.style.display = 'none';\r
4585       }\r
4587     });\r
4589   ;
4592     Polymer('core-doc-viewer', {
4593       /**
4594        * A single file to parse for docs
4595        *
4596        * @attribute url
4597        * @type String
4598        * @default ''
4599        */
4601       /**
4602        * Class documentation extracted from the parser
4603        *
4604        * @property classes
4605        * @type Array
4606        * @default []
4607        */
4608       classes: [],
4610       /**
4611        * Files to parse for docs
4612        *
4613        * @attribute sources
4614        * @type Array
4615        * @default []
4616        */
4617       sources: [],
4619       ready: function() {
4620         window.addEventListener('hashchange', this.parseLocationHash.bind(this));
4621         this.parseLocationHash();
4622       },
4624       parseLocationHash: function() {
4625         this.route = window.location.hash.slice(1);
4626       },
4628       routeChanged: function() {
4629         this.validateRoute();
4630       },
4632       validateRoute: function() {
4633         if (this.route) {
4634           this.classes.some(function(c) {
4635             if (c.name === this.route) {
4636               this.data = c;
4637               this.route = '';
4638               return;
4639             }
4640           }, this);
4641         }
4642       },
4644       selectedChanged: function() { 
4645         this.data = this.classes[this.selected];
4646       },
4648       parserDataReady: function(event) {
4649         this.assimilateData(event.target.data);
4650       },
4652       assimilateData: function(data) {
4653         this.classes = this.classes.concat(data.classes);
4654         this.classes.sort(function(a, b) {
4655           var na = a && a.name.toLowerCase(), nb = b && b.name.toLowerCase();
4656           return (na < nb) ? -1 : (na == nb) ? 0 : 1;
4657         });
4658         if (!this.data && !this.route && this.classes.length) {
4659           this.data = this.classes[0];
4660         }
4661         if (this.classes.length > 1) {
4662           this.$.toc.style.display = 'block';
4663         }
4664         this.validateRoute();
4665       }
4667     });
4669   ;
4672     Polymer('core-component-page', {
4674       moduleName: '',
4675       // TODO(sjmiles): needed this to force Object type for deserialization
4676       sources: [],
4678       ready: function() {
4679         this.moduleName = this.moduleName || this.findModuleName();
4680       },
4682       moduleNameChanged: function() {
4683         document.title = this.moduleName;
4684         this.url = !this.sources.length && this.moduleName ? this.moduleName + '.html' : '';
4685       },
4687       findModuleName: function() {
4688         var path = location.pathname.split('/');
4689         var name = path.pop() || path.pop();
4690         if (name.indexOf('.html') >= 0) {
4691           name = path.pop();
4692         }
4693         return name || '';
4694       }
4696     });
4698