<ins> /** * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @jsx React.DOM * @emails react-core */ "use strict"; var React; var ReactDescriptor; describe('ReactDescriptor', function() { beforeEach(function() { React = require('React'); ReactDescriptor = require('ReactDescriptor'); }); it('should identify valid descriptors correctly', function() { var Component = React.createClass({ render: function() { return <div />; } }); expect(ReactDescriptor.isValidDescriptor(<div />)).toEqual(true); expect(ReactDescriptor.isValidDescriptor(<Component />)).toEqual(true); expect(ReactDescriptor.isValidDescriptor(null)).toEqual(false); expect(ReactDescriptor.isValidDescriptor(true)).toEqual(false); expect(ReactDescriptor.isValidDescriptor({})).toEqual(false); expect(ReactDescriptor.isValidDescriptor("string")).toEqual(false); expect(ReactDescriptor.isValidDescriptor(React.DOM.div)).toEqual(false); expect(ReactDescriptor.isValidDescriptor(Component)).toEqual(false); }); }); </ins>


*    React Core     .  General Purpose Event Plugin System */ <ins> var hasEventPageXY; </ins> var alreadyListeningTo = {}; var isMonitoringScrollValue = false; var reactTopListenersCounter = 0;


* Listens to window scroll and resize events. We cache scroll values so that * application code can access them without triggering reflows. * <ins> * ViewportMetrics is only used by SyntheticMouse/TouchEvent and only when * pageX/pageY isn't supported (legacy browsers). * </ins> * NOTE: Scroll events do not bubble. * * @see http://www.quirksmode.org/dom/events/scroll.html */ <del> ensureScrollValueMonitoring: function() { if (!isMonitoringScrollValue) { </del> <ins> ensureScrollValueMonitoring: function(){ if (hasEventPageXY === undefined) { hasEventPageXY = document.createEvent && 'pageX' in document.createEvent('MouseEvent'); } if (!hasEventPageXY && !isMonitoringScrollValue) { </ins> var refresh = ViewportMetrics.refreshScrollValues; ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh); isMonitoringScrollValue = true;


form: MUST_USE_ATTRIBUTE, formNoValidate: HAS_BOOLEAN_VALUE, frameBorder: MUST_USE_ATTRIBUTE, <ins> headers: null, </ins> height: MUST_USE_ATTRIBUTE, hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, href: null,


var assign = require('Object.assign'); var findDOMNode = require('findDOMNode'); var onlyChild = require('onlyChild'); <ins> var warning = require('warning'); </ins> ReactDefaultInjection.inject();


} } <ins> // If we're in IE8, check to see if we are in combatibility mode and provide // information on preventing compatibility mode var ieCompatibilityMode = document.documentMode && document.documentMode < 8; warning( !ieCompatibilityMode, 'Internet Explorer is running in compatibility mode, please add the following ' + 'tag to your HTML to prevent this from happening: ' + '<meta http-equiv="X-UA-Compatible" content="IE=edge" />' ); </ins> var expectedFeatures = [ // shims Array.isArray,


var MARKDOWN_COMPONENT = ` <del> var converter = new Showdown.converter(); </del> var MarkdownEditor = React.createClass({ getInitialState: function() { return {value: 'Type some *markdown* here!'};


<div className="content" dangerouslySetInnerHTML={{  __html: converter.makeHtml(this.state.value)   __html: marked(this.state.value, {sanitize: true})  }} />


<script type="text/javascript" src="/react/js/react.js"></script> <script type="text/javascript" src="/react/js/JSXTransformer.js"></script> <script type="text/javascript" src="/react/js/live_editor.js"></script> <del> <script type="text/javascript" src="/react/js/showdown.js"></script> </del> </head> <body>


Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized. <del> First, add the third-party **Showdown** library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </del> <ins> First, add the third-party library **marked** to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </ins> ```html{7} <!-- index.html -->


<script src="https://fb.me/react-{{site.react_version}}.js"></script> <script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script> <script src="https://code.jquery.com/jquery-1.10.0.min.js"></script> <del> <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script> </del> <ins> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script> </ins> </head> ``` Next, let's convert the comment text to Markdown and output it: <del> ```javascript{2,10} </del> <ins> ```javascript{9} </ins> // tutorial6.js <del> var converter = new Showdown.converter(); </del> var Comment = React.createClass({ render: function() { return (


 {this.props.author}
  {converter.makeHtml(this.props.children.toString())}   {marked(this.props.children.toString())}
 ); } }); ``` <del> All we're doing here is calling the Showdown library. We need to convert `this.props.children` from React's wrapped text to a raw string that Showdown will understand so we explicitly call `toString()`. </del> <ins> All we're doing here is calling the marked library. We need to convert `this.props.children` from React's wrapped text to a raw string that marked will understand so we explicitly call `toString()`. </ins> But there's a problem! Our rendered comments look like this in the browser: "`<p>`This is `<em>`another`</em>` comment`</p>`". We want those tags to actually render as HTML. That's React protecting you from an XSS attack. There's a way to get around it but the framework warns you not to use it: <del> ```javascript{5,11}   ```javascript{4,10}  // tutorial7.js  var converter = new Showdown.converter();  var Comment = React.createClass({ render: function() {  var rawMarkup = converter.makeHtml(this.props.children.toString());   var rawMarkup = marked(this.props.children.toString(), {sanitize: true});  return (


}); ``` <del> This is a special API that intentionally makes it difficult to insert raw HTML, but for Showdown we'll take advantage of this backdoor. </del> <ins> This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor. </ins> <del> **Remember:** by using this feature you're relying on Showdown to be secure. </del> <ins> **Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged. </ins> ### Hook up the data model


A Component Using External Plugins

 React is flexible and provides hooks that allow you to interface with  other libraries and frameworks. This example uses Showdown, an external   other libraries and frameworks. This example uses **marked**, an external  Markdown library, to convert the textarea's value in real-time.


 /** * marked - a markdown parser * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) * https://github.com/chjj/marked */ (function(){var block={newline:/^n+/,code:/^( {4}[^n]+n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:n+|$)/,heading:/^ *(#{1,6}) *([^n]+?) *#* *(?:n+|$)/,nptable:noop,lheading:/^([^n]+)n *(=|-){2,} *(?:n+|$)/,blockquote:/^( *>[^n]+(n(?!def)[^n]+)*n*)+/,list:/^( *)(bull) [sS]+?(?:hr|def|n{2,}(?! )(?!1bull )n*|s*$)/,html:/^ *(?:comment|closed|closing) *(?:n{2,}|s*$)/,def:/^ *[([^]]+)]: *<?([^s>]+)>?(?: +["(]([^n]+)[")])? *(?:n+|$)/,table:noop,paragraph:/^((?:[^n]+n?(?!hr|heading|lheading|blockquote|tag|def))+)n*/,text:/^[^n]+/};block.bullet=/(?:[*+-]|d+.)/;block.item=/^( *)(bull) [^n]*(?:n(?!1bull )[^n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","n+(?=1?(?:[-*_] *){3,}(?:n+|$))")("def","n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)b)w+(?!:/|[^ws@]*@)b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[sS]+?</1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(S+)? *n([sS]+?)s*1 *(?:n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("1","2")+"|"+block.list.source.replace("1","3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(S.*|.*)n *([-:]+ *|[-| :]*)n((?:.*|.*(?:n|$))*)n*/,table:/^ *|(.+)n *|( *[-:]+[-| :]*)n((?: *|.*(?:n|$))*)n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/rn|r/g,"n").replace(/t/g,"    ").replace(/u00a0/g," ").replace(/u2424/g,"n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *| *$/g,"").split(/ *| */),align:cap[2].replace(/^ *|| *$/g,"").split(/ *| */),cells:cap[3].replace(/n$/,"").split("n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|d+.) +/,"");if(~item.indexOf("n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("n")+src;i=l-1}}loose=next||/nn(?!s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *| *$/g,"").split(/ *| */),align:cap[2].replace(/^ *|| *$/g,"").split(/ *| */),cells:cap[3].replace(/(?: *| *)?n$/,"").split("n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *| *| *| *$/g,"").split(/ *| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^([`*{}[]()#+-.!_>])/,autolink:/^<([^ >]+(@|:/)[^ >]+)>/,url:noop,tag:/^|^</?w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?[(inside)](href)/,reflink:/^!?[(inside)]s*[([^]]*)]/,nolink:/^!?[((?:[[^]]*]|[^[]])*)]/,strong:/^__([sS]+?)__(?!_)|^**([sS]+?)**(?!*)/,em:/^b_((?:__|[sS])+?)_b|^*((?:**|[sS])+?)*(?!*)/,code:/^(`+)s*([sS]*?[^`])s*1(?!`)/,br:/^ {2,}n(?!s*$)/,del:noop,text:/^[sS]+?(?=[<![_*`]| {2,}n|$)/};inline._inside=/(?:[[^]]*]|[^[]]|](?=[^[]*]))*/;inline._href=/s*<?([sS]*?)>?(?:s+['"]([sS]*?)['"])?s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=S)([sS]*?S)__(?!_)|^**(?=S)([sS]*?S)**(?!*)/,em:/^_(?=S)([sS]*?S)_(?!_)|^*(?=S)([sS]*?S)*(?!*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?://[^s<]+[^<.,:;"')]s])/,del:/^~~(?=S)([sS]*?S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-u2014/([{"s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-u2014/([{u2018s])"/g,"$1“").replace(/"/g,"”").replace(/.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
"+(escaped?code:escape(code,true))+"n
"}return'
'+(escaped?code:escape(code,true))+"n
n"};Renderer.prototype.blockquote=function(quote){return"
n"+quote+"
n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^w]+/g,"-")+'">'+text+"</h"+level+">n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
n":"
n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">n"+body+"</"+type+">n"};Renderer.prototype.listitem=function(text){return"
"+text+"
n"};Renderer.prototype.paragraph=function(text){return"
"+text+"
n"};Renderer.prototype.table=function(header,body){return"
n"+"
n"+header+"
n"+"
n"+body+"
n"+"
n"};Renderer.prototype.tablerow=function(content){return"
n"+content+"
n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
":"
"};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='"+text+"";return out};Renderer.prototype.image=function(href,title,text){var out='":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?w+;)/g:/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^[])^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(){var out,err;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"
An error occured:

"+escape(e.message+"",true)+"
"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());   No newline at end of file


 // // showdown.js -- A javascript port of Markdown. // // Copyright (c) 2007 John Fraser. // // Original Markdown Copyright (c) 2004-2005 John Gruber //   <http://daringfireball.net/projects/markdown/> // // Redistributable under a BSD-style open source license. // See license.txt for more information. // // The full source distribution is at: // //				A A L //				T C A //				T K B // //   <http://www.attacklab.net/> // // // Wherever possible, Showdown is a straight, line-by-line port // of the Perl version of Markdown. // // This is not a normal parser design; it's basically just a // series of string substitutions.  It's hard to read and // maintain this way,  but keeping Showdown close to the original // design makes it easier to port new features. // // More importantly, Showdown behaves like markdown.pl in most // edge cases.  So web applications can do client-side preview // in Javascript, and then build identical HTML on the server. // // This port needs the new RegExp functionality of ECMA 262, // 3rd Edition (i.e. Javascript 1.5).  Most modern web browsers // should do fine.  Even with the new regular expression features, // We do a lot of work to emulate Perl's regex functionality. // The tricky changes in this file mostly have the "attacklab:" // label.  Major or self-explanatory changes don't. // // Smart diff tools like Araxis Merge will be able to match up // this file with markdown.pl in a useful way.  A little tweaking // helps: in a copy of markdown.pl, replace "#" with "//" and // replace "$text" with "text".  Be sure to ignore whitespace // and line endings. // // // Showdown usage: // //   var text = "Markdown *rocks*."; // //   var converter = new Showdown.converter(); //   var html = converter.makeHtml(text); // //   alert(html); // // Note: move the sample code to the bottom of this // file before uncommenting it. // // // Showdown namespace // var Showdown = {}; // // converter // // Wraps all "globals" so that the only thing // exposed is makeHtml(). // Showdown.converter = function() { // // Globals: // // Global hashes, used by various utility routines var g_urls; var g_titles; var g_html_blocks; // Used to track when we're inside an ordered or unordered list // (see _ProcessListItems() for details): var g_list_level = 0; this.makeHtml = function(text) { // // Main function. The order in which other subs are called here is // essential. Link and image substitutions need to happen before // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the  // and  tags get encoded. // // Clear the global hashes. If we don't clear these, you get conflicts // from other articles when generating a page which contains more than // one article (e.g. an index page that shows the N most recent // articles): g_urls = new Array(); g_titles = new Array(); g_html_blocks = new Array(); // attacklab: Replace ~ with ~T // This lets us use tilde as an escape char to avoid md5 hashes // The choice of character is arbitray; anything that isn't // magic in Markdown will work. text = text.replace(/~/g,"~T"); // attacklab: Replace $ with ~D // RegExp interprets $ as a special character // when it's in a replacement string text = text.replace(/$/g,"~D"); // Standardize line endings text = text.replace(/rn/g,"n"); // DOS to Unix text = text.replace(/r/g,"n"); // Mac to Unix // Make sure text begins and ends with a couple of newlines: text = "nn" + text + "nn"; // Convert all tabs to spaces. text = _Detab(text); // Strip any lines consisting only of spaces and tabs. // This makes subsequent regexen easier to write, because we can // match consecutive blank lines with /n+/ instead of something // contorted like /[ t]*n+/ . text = text.replace(/^[ t]+$/mg,""); // Turn block-level HTML blocks into hash entries text = _HashHTMLBlocks(text); // Strip link definitions, store in hashes. text = _StripLinkDefinitions(text); text = _RunBlockGamut(text); text = _UnescapeSpecialChars(text); // attacklab: Restore dollar signs text = text.replace(/~D/g,"$$"); // attacklab: Restore tildes text = text.replace(/~T/g,"~"); return text; } var _StripLinkDefinitions = function(text) { // // Strips link definitions from text, stores the URLs and titles in // hash references. // // Link defs are in the form: ^[id]: url "optional title" /* var text = text.replace(/ ^[ ]{0,3}[(.+)]:  // id = $1  attacklab: g_tab_width - 1 [ t]* n?				// maybe *one* newline [ t]* <?(S+?)>?			// url = $2 [ t]* n?				// maybe one newline [ t]* (?: (n*)				// any lines skipped = $3 attacklab: lookbehind removed ["(] (.+?)				// title = $4 [")] [ t]* )?					// title is optional (?:n+|$) /gm, function(){...}); */ var text = text.replace(/^[ ]{0,3}[(.+)]:[ t]*n?[ t]*<?(S+?)>?[ t]*n?[ t]*(?:(n*)["(](.+?)[")][ t]*)?(?:n+|Z)/gm, function (wholeMatch,m1,m2,m3,m4) { m1 = m1.toLowerCase(); g_urls[m1] = _EncodeAmpsAndAngles(m2);  // Link IDs are case-insensitive if (m3) { // Oops, found blank lines, so it's not a title. // Put back the parenthetical statement we stole. return m3+m4; } else if (m4) { g_titles[m1] = m4.replace(/"/g,"""); } // Completely remove the definition from the text return ""; } ); return text; } var _HashHTMLBlocks = function(text) { // attacklab: Double up blank lines to reduce lookaround text = text.replace(/n/g,"nn"); // Hashify HTML blocks: // We only want to do this for block-level HTML tags, such as headers, // lists, and tables. That's because we still want to wrap
s around // "paragraphs" that are wrapped in non-block-level tags, such as anchors, // phrase emphasis, and spans. The list of tags we're looking for is // hard-coded: var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" // First, look for nested blocks, e.g.: //
 //
 //     tags for inner block must be indented. //
 //
 // // The outermost tags must start at the left margin for this to match, and // the inner nested divs must be indented. // We need to do this before the next, more liberal match, because the next // match will start at the first `<div>` and stop at the first `</div>`. // attacklab: This regex can be expensive when it fails. /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_a)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?n			// any number of lines, minimally matching </2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)b[^r]*?n</2>[ t]*(?=n+))/gm,hashElement); // // Now match more liberally, simply from `n<tag>` to `</tag>n` // /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_b)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?				// any number of lines, minimally matching .*</2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)b[^r]*?.*</2>[ t]*(?=n+)n)/gm,hashElement); // Special case just for
. It was easier to make a special case than // to make the other regex more complicated. /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3} (<(hr)				// start tag = $2 b					// word break ([^<>])*?			// /?>)				// the matching end tag [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(n[ ]{0,3}(<(hr)b([^<>])*?/?>)[ t]*(?=n{2,}))/g,hashElement); // Special case for standalone HTML comments: /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3}			// attacklab: g_tab_width - 1 <! (--[^r]*?--s*)+ > [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(nn[ ]{0,3}<!(--[^r]*?--s*)+>[ t]*(?=n{2,}))/g,hashElement); // PHP and ASP-style processor instructions (<?...?> and <%...%>) /* text = text.replace(/ (?: nn				// Starting after a blank line ) (						// save in $1 [ ]{0,3}			// attacklab: g_tab_width - 1 (?: <([?%])			// $2 [^r]*? 2> ) [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(?:nn)([ ]{0,3}(?:<([?%])[^r]*?2>)[ t]*(?=n{2,}))/g,hashElement); // attacklab: Undo double lines (see comment at top of this function) text = text.replace(/nn/g,"n"); return text; } var hashElement = function(wholeMatch,m1) { var blockText = m1; // Undo double lines blockText = blockText.replace(/nn/g,"n"); blockText = blockText.replace(/^n/,""); // strip trailing blank lines blockText = blockText.replace(/n+$/g,""); // Replace the element text with a marker ("~KxK" where x is its key) blockText = "nn~K" + (g_html_blocks.push(blockText)-1) + "Knn"; return blockText; }; var _RunBlockGamut = function(text) { // // These are all the transformations that form block-level // tags like paragraphs, headers, and list items. // text = _DoHeaders(text); // Do Horizontal Rules: var key = hashBlock("
"); text = text.replace(/^[ ]{0,2}([ ]?*[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ t]*$/gm,key); text = _DoLists(text); text = _DoCodeBlocks(text); text = _DoBlockQuotes(text); // We already ran _HashHTMLBlocks() before, in Markdown(), but that // was to escape raw HTML in the original Markdown source. This time, // we're escaping the markup we've just created, so that we don't wrap //
 tags around block-level tags. text = _HashHTMLBlocks(text); text = _FormParagraphs(text); return text; } var _RunSpanGamut = function(text) { // // These are all the transformations that occur *within* block-level // tags like paragraphs, headers, and list items. // text = _DoCodeSpans(text); text = _EscapeSpecialCharsWithinTagAttributes(text); text = _EncodeBackslashEscapes(text); // Process anchor and image tags. Images must come first, // because ![foo][f] looks like an anchor. text = _DoImages(text); text = _DoAnchors(text); // Make links out of things like `<http://example.com/>` // Must come after _DoAnchors(), because you can use < and > // delimiters in inline links like [this](<url>). text = _DoAutoLinks(text); text = _EncodeAmpsAndAngles(text); text = _DoItalicsAndBold(text); // Do hard breaks: text = text.replace(/  +n/g,"
n"); return text; } var _EscapeSpecialCharsWithinTagAttributes = function(text) { // // Within tags -- meaning between < and > -- encode [ ` * _] so they // don't conflict with their use in Markdown for code, italics and strong. // // Build a regex to find HTML tags and comments.  See Friedl's // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. var regex = /(<[a-z/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--s*)+>)/gi; text = text.replace(regex, function(wholeMatch) { var tag = wholeMatch.replace(/(.)</?code>(?=.)/g,"$1`"); tag = escapeCharacters(tag,"`*_"); return tag; }); return text; } var _DoAnchors = function(text) { // // Turn Markdown link shortcuts into XHTML  tags. // // // First, handle reference-style links: [link text] [id] // /* text = text.replace(/ (							// wrap whole match in $1 [ ( (?: [[^]]*]		// allow brackets nested one level | [^[]			// or anything else )* ) ] [ ]?					// one optional space (?:n[ ]*)?				// one optional newline followed by spaces [ (.*?)					// id = $3 ] )()()()()					// pad remaining backreferences /g,_DoAnchors_callback); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeAnchorTag); // // Next, inline-style links: [link text](url "optional title") // /* text = text.replace(/ (						// wrap whole match in $1 [ ( (?: [[^]]*]	// allow brackets nested one level | [^[]]			// or anything else ) ) ] (						// literal paren [ t]* ()						// no id, so leave $3 empty <?(.*?)>?				// href = $4 [ t]* (						// $5 (['"])				// quote char = $6 (.*?)				// Title = $7 6					// matching quote [ t]*				// ignore any spaces/tabs between closing quote and ) )?						// title is optional ) ) /g,writeAnchorTag); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)]([ t]*()<?(.*?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeAnchorTag); // // Last, handle reference-style shortcuts: [link text] // These must come last in case you've also got [link test][1] // or [link test](/foo) // /* text = text.replace(/ (		 					// wrap whole match in $1 [ ([^[]]+)				// link text = $2; can't contain '[' or ']' ] )()()()()()					// pad rest of backreferences /g, writeAnchorTag); */ text = text.replace(/([([^[]]+)])()()()()()/g, writeAnchorTag); return text; } var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { if (m7 == undefined) m7 = ""; var whole_match = m1; var link_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = link_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { if (whole_match.search(/(s*)$/m)>-1) { // Special case for explicit empty url url = ""; } else { return whole_match; } } } url = escapeCharacters(url,"*_"); var result = "" + link_text + ""; return result; } var _DoImages = function(text) { // // Turn Markdown image shortcuts into  tags. // // // First, handle reference-style labeled images: ![alt text][id] // /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] [ ]?				// one optional space (?:n[ ]*)?			// one optional newline followed by spaces [ (.*?)				// id = $3 ] )()()()()				// pad rest of backreferences /g,writeImageTag); */ text = text.replace(/(![(.*?)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeImageTag); // // Next, handle inline images:  ![alt text](url "optional title") // Don't forget: encode * and _ /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] s?					// One optional whitespace character (					// literal paren [ t]* ()					// no id, so leave $3 empty <?(S+?)>?			// src url = $4 [ t]* (					// $5 (['"])			// quote char = $6 (.*?)			// title = $7 6				// matching quote [ t]* )?					// title is optional ) ) /g,writeImageTag); */ text = text.replace(/(![(.*?)]s?([ t]*()<?(S+?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeImageTag); return text; } var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { var whole_match = m1; var alt_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (!title) title = ""; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = alt_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { return whole_match; } } alt_text = alt_text.replace(/"/g,"""); url = escapeCharacters(url,"*_"); var result = ""; return result; } var _DoHeaders = function(text) { // Setext-style headers: //	Header 1 //	======== // //	Header 2 //	-------- // text = text.replace(/^(.+)[ t]*n=+[ t]*n+/gm, function(wholeMatch,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); text = text.replace(/^(.+)[ t]*n-+[ t]*n+/gm, function(matchFound,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); // atx-style headers: //  # Header 1 //  ## Header 2 //  ## Header 2 with closing hashes ## //  ... //  ###### Header 6 // /* text = text.replace(/ ^(#{1,6})				// $1 = string of #'s [ t]* (.+?)					// $2 = Header text [ t]* #*						// optional closing #'s (not counted) n+ /gm, function() {...}); */ text = text.replace(/^(#{1,6})[ t]*(.+?)[ t]*#*n+/gm, function(wholeMatch,m1,m2) { var h_level = m1.length; return hashBlock("<h" + h_level + ' id="' + headerId(m2) + '">' + _RunSpanGamut(m2) + "</h" + h_level + ">"); }); function headerId(m) { return m.replace(/[^w]/g, '').toLowerCase(); } return text; } // This declaration keeps Dojo compressor from outputting garbage: var _ProcessListItems; var _DoLists = function(text) { // // Form HTML ordered (numbered) and unordered (bulleted) lists. // // attacklab: add sentinel to hack around khtml/safari bug: // http://bugs.webkit.org/show_bug.cgi?id=11231 text += "~0"; // Re-usable pattern to match any entirel ul or ol list: /* var whole_list = / (									// $1 = whole list (								// $2 [ ]{0,3}					// attacklab: g_tab_width - 1 ([*+-]|d+[.])				// $3 = first list item marker [ t]+ ) [^r]+? (								// $4 ~0							// sentinel for workaround; should be $ | n{2,} (?=S) (?!							// Negative lookahead for another list item marker [ t]* (?:[*+-]|d+[.])[ t]+ ) ) )/g */ var whole_list = /^(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/gm; if (g_list_level) { text = text.replace(whole_list,function(wholeMatch,m1,m2) { var list = m1; var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); // Trim any trailing whitespace, to put the closing `</$list_type>` // up on the preceding line, to get it past the current stupid // HTML block parser. This is a hack to work around the terrible // hack that is the HTML block parser. result = result.replace(/s+$/,""); result = "<"+list_type+">" + result + "</"+list_type+">n"; return result; }); } else { whole_list = /(nn|^n?)(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/g; text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) { var runup = m1; var list = m2; var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: var list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); result = runup + "<"+list_type+">n" + result + "</"+list_type+">n"; return result; }); } // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } _ProcessListItems = function(list_str) { // //  Process the contents of a single ordered or unordered list, splitting it //  into individual list items. // // The $g_list_level global keeps track of when we're inside a list. // Each time we enter a list, we increment it; when we leave a list, // we decrement. If it's zero, we're not in a list anymore. // // We do this because when we're not inside a list, we want to treat // something like this: // //    I recommend upgrading to version //    8. Oops, now this line is treated //    as a sub-list. // // As a single paragraph, despite the fact that the second line starts // with a digit-period-space sequence. // // Whereas when we're inside a list (or sub-list), that line will be // treated as the start of a sub-list. What a kludge, huh? This is // an aspect of Markdown's syntax that's hard to parse perfectly // without resorting to mind-reading. Perhaps the solution is to // change the syntax rules such that sub-lists must start with a // starting cardinal number; e.g. "1." or "a.". g_list_level++; // trim trailing blank lines: list_str = list_str.replace(/n{2,}$/,"n"); // attacklab: add sentinel to emulate z list_str += "~0"; /* list_str = list_str.replace(/ (n)?							// leading line = $1 (^[ t]*)						// leading whitespace = $2 ([*+-]|d+[.]) [ t]+			// list marker = $3 ([^r]+?						// list item text   = $4 (n{1,2})) (?= n* (~0 | 2 ([*+-]|d+[.]) [ t]+)) /gm, function(){...}); */ list_str = list_str.replace(/(n)?(^[ t]*)([*+-]|d+[.])[ t]+([^r]+?(n{1,2}))(?=n*(~0|2([*+-]|d+[.])[ t]+))/gm, function(wholeMatch,m1,m2,m3,m4){ var item = m4; var leading_line = m1; var leading_space = m2; if (leading_line || (item.search(/n{2,}/)>-1)) { item = _RunBlockGamut(_Outdent(item)); } else { // Recursion for sub-lists: item = _DoLists(_Outdent(item)); item = item.replace(/n$/,""); // chomp(item) item = _RunSpanGamut(item); } return  "
" + item + "
n"; } ); // attacklab: strip sentinel list_str = list_str.replace(/~0/g,""); g_list_level--; return list_str; } var _DoCodeBlocks = function(text) { // //  Process Markdown `<pre><code>` blocks. // /* text = text.replace(text, /(?:nn|^) (								// $1 = the code block -- one or more lines, starting with a space/tab (?: (?:[ ]{4}|t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width .*n+ )+ ) (n*[ ]{0,3}[^ tn]|(?=~0))	// attacklab: g_tab_width /g,function(){...}); */ // attacklab: sentinel workarounds for lack of A and Z, safarikhtml bug text += "~0"; text = text.replace(/(?:nn|^)((?:(?:[ ]{4}|t).*n+)+)(n*[ ]{0,3}[^ tn]|(?=~0))/g, function(wholeMatch,m1,m2) { var codeblock = m1; var nextChar = m2; codeblock = _EncodeCode( _Outdent(codeblock)); codeblock = _Detab(codeblock); codeblock = codeblock.replace(/^n+/g,""); // trim leading newlines codeblock = codeblock.replace(/n+$/g,""); // trim trailing whitespace codeblock = "
" + codeblock + "n
"; return hashBlock(codeblock) + nextChar; } ); // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } var hashBlock = function(text) { text = text.replace(/(^n+|n+$)/g,""); return "nn~K" + (g_html_blocks.push(text)-1) + "Knn"; } var _DoCodeSpans = function(text) { // //   *  Backtick quotes are used for  spans. // //   *  You can use multiple backticks as the delimiters if you want to //	 include literal backticks in the code span. So, this input: // //		 Just type ``foo `bar` baz`` at the prompt. // //	   Will translate to: // //
Just type foo `bar` baz at the prompt.
 // //	There's no arbitrary limit to the number of backticks you //	can use as delimters. If you need three consecutive backticks //	in your code, use four for delimiters, etc. // //  *  You can use spaces to get literal backticks at the edges: // //		 ... type `` `bar` `` ... // //	   Turns to: // //		 ... type `bar` ... // /* text = text.replace(/ (^|[^])					// Character before opening ` can't be a backslash (`+)						// $2 = Opening run of ` (							// $3 = The code block [^r]*? [^`]					// attacklab: work around lack of lookbehind ) 2							// Matching closer (?!`) /gm, function(){...}); */ text = text.replace(/(^|[^])(`+)([^r]*?[^`])2(?!`)/gm, function(wholeMatch,m1,m2,m3,m4) { var c = m3; c = c.replace(/^([ t]*)/g,"");	// leading whitespace c = c.replace(/[ t]*$/g,"");	// trailing whitespace c = _EncodeCode(c); return m1+""+c+""; }); return text; } var _EncodeCode = function(text) { // // Encode/escape certain characters inside Markdown code runs. // The point is that in code, these characters are literals, // and lose their special Markdown meanings. // // Encode all ampersands; HTML entities are not // entities within a Markdown code span. text = text.replace(/&/g,"&"); // Do the angle bracket song and dance: text = text.replace(/</g,"<"); text = text.replace(/>/g,">"); // Now, escape characters that are magic in Markdown: text = escapeCharacters(text,"*_{}[]",false); // jj the line above breaks this: //--- //* Item //   1. Subitem //            special char: * //--- return text; } var _DoItalicsAndBold = function(text) { //  must go first: text = text.replace(/(**|__)(?=S)([^r]*?S[*_]*)1/g, "$2"); text = text.replace(/(*|_)(?=S)([^r]*?S)1/g, "$2"); return text; } var _DoBlockQuotes = function(text) { /* text = text.replace(/ (								// Wrap whole match in $1 ( ^[ t]*>[ t]?			// '>' at the start of a line .+n					// rest of the first line (.+n)*					// subsequent consecutive lines n*						// blanks )+ ) /gm, function(){...}); */ text = text.replace(/((^[ t]*>[ t]?.+n(.+n)*n*)+)/gm, function(wholeMatch,m1) { var bq = m1; // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" bq = bq.replace(/^[ t]*>[ t]?/gm,"~0");	// trim one level of quoting // attacklab: clean up hack bq = bq.replace(/~0/g,""); bq = bq.replace(/^[ t]+$/gm,"");		// trim whitespace-only lines bq = _RunBlockGamut(bq);				// recurse bq = bq.replace(/(^|n)/g,"$1  "); // These leading spaces screw with
 content, so we need to fix that: bq = bq.replace( /(s*
[^r]+?
)/gm, function(wholeMatch,m1) { var pre = m1; // attacklab: hack around Konqueror 3.5.4 bug: pre = pre.replace(/^  /mg,"~0"); pre = pre.replace(/~0/g,""); return pre; }); return hashBlock("
n" + bq + "n
"); }); return text; } var _FormParagraphs = function(text) { // //  Params: //    $text - string to process with html
 tags // // Strip leading and trailing lines: text = text.replace(/^n+/g,""); text = text.replace(/n+$/g,""); var grafs = text.split(/n{2,}/g); var grafsOut = new Array(); // // Wrap
 tags. // var end = grafs.length; for (var i=0; i<end; i++) { var str = grafs[i]; // if this is an HTML marker, copy it if (str.search(/~K(d+)K/g) >= 0) { grafsOut.push(str); } else if (str.search(/S/) >= 0) { str = _RunSpanGamut(str); str = str.replace(/^([ t]*)/g,"
"); str += "
" grafsOut.push(str); } } // // Unhashify HTML blocks // end = grafsOut.length; for (var i=0; i<end; i++) { // if this is a marker for an html block... while (grafsOut[i].search(/~K(d+)K/) >= 0) { var blockText = g_html_blocks[RegExp.$1]; blockText = blockText.replace(/$/g,"$$$$"); // Escape any dollar signs grafsOut[i] = grafsOut[i].replace(/~Kd+K/,blockText); } } return grafsOut.join("nn"); } var _EncodeAmpsAndAngles = function(text) { // Smart processing for ampersands and angle brackets that need to be encoded. // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: //   http://bumppo.net/projects/amputator/ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|w+);)/g,"&"); // Encode naked <'s text = text.replace(/<(?![a-z/?$!])/gi,"<"); return text; } var _EncodeBackslashEscapes = function(text) { // //   Parameter:  String. //   Returns:	The string, with after processing the following backslash //			   escape sequences. // // attacklab: The polite way to do this is with the new // escapeCharacters() function: // // 	text = escapeCharacters(text,"",true); // 	text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); // // ...but we're sidestepping its use of the (slow) RegExp constructor // as an optimization for Firefox.  This function gets called a LOT. text = text.replace(/()/g,escapeCharacters_callback); text = text.replace(/([`*_{}[]()>#+-.!])/g,escapeCharacters_callback); return text; } var _DoAutoLinks = function(text) { text = text.replace(/<((https?|ftp|dict):[^'">s]+)>/gi,"$1"); // Email addresses: <address@domain.foo> /* text = text.replace(/ < (?:mailto:)? ( [-.w]+ @ [-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+ ) > /gi, _DoAutoLinks_callback()); */ text = text.replace(/<(?:mailto:)?([-.w]+@[-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+)>/gi, function(wholeMatch,m1) { return _EncodeEmailAddress( _UnescapeSpecialChars(m1) ); } ); return text; } var _EncodeEmailAddress = function(addr) { // //  Input: an email address, e.g. "foo@example.com" // //  Output: the email address as a mailto link, with each character //	of the address encoded as either a decimal or hex entity, in //	the hopes of foiling most address harvesting spam bots. E.g.: // //	foo //	   @example.com // //  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk //  mailing list: <http://tinyurl.com/yu7ue> // // attacklab: why can't javascript speak hex? function char2hex(ch) { var hexDigits = '0123456789ABCDEF'; var dec = ch.charCodeAt(0); return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15)); } var encode = [ function(ch){return "&#"+ch.charCodeAt(0)+";";}, function(ch){return "&#x"+char2hex(ch)+";";}, function(ch){return ch;} ]; addr = "mailto:" + addr; addr = addr.replace(/./g, function(ch) { if (ch == "@") { // this *must* be encoded. I insist. ch = encode[Math.floor(Math.random()*2)](ch); } else if (ch !=":") { // leave ':' alone (to spot mailto: later) var r = Math.random(); // roughly 10% raw, 45% hex, 45% dec ch =  ( r > .9  ?	encode[2](ch)   : r > .45 ?	encode[1](ch)   : encode[0](ch) ); } return ch; }); addr = "" + addr + ""; addr = addr.replace(/">.+:/g,"">"); // strip the mailto: from the visible part return addr; } var _UnescapeSpecialChars = function(text) { // // Swap back in all the special characters we've hidden. // text = text.replace(/~E(d+)E/g, function(wholeMatch,m1) { var charCodeToReplace = parseInt(m1); return String.fromCharCode(charCodeToReplace); } ); return text; } var _Outdent = function(text) { // // Remove one level of line-leading tabs or spaces // // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" text = text.replace(/^(t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width // attacklab: clean up hack text = text.replace(/~0/g,"") return text; } var _Detab = function(text) { // attacklab: Detab's completely rewritten for speed. // In perl we could fix it by anchoring the regexp with G. // In javascript we're less fortunate. // expand first n-1 tabs text = text.replace(/t(?=t)/g,"    "); // attacklab: g_tab_width // replace the nth with two sentinels text = text.replace(/t/g,"~A~B"); // use the sentinel to anchor our regex so it doesn't explode text = text.replace(/~B(.+?)~A/g, function(wholeMatch,m1,m2) { var leadingText = m1; var numSpaces = 4 - leadingText.length % 4;  // attacklab: g_tab_width // there *must* be a better way to do this: for (var i=0; i<numSpaces; i++) leadingText+=" "; return leadingText; } ); // clean up sentinels text = text.replace(/~A/g,"    ");  // attacklab: g_tab_width text = text.replace(/~B/g,""); return text; } // //  attacklab: Utility functions // var escapeCharacters = function(text, charsToEscape, afterBackslash) { // First we have to escape the escape characters so that // we can build a character class out of them var regexString = "([" + charsToEscape.replace(/([[]])/g,"$1") + "])"; if (afterBackslash) { regexString = "" + regexString; } var regex = new RegExp(regexString,"g"); text = text.replace(regex,escapeCharacters_callback); return text; } var escapeCharacters_callback = function(wholeMatch,m1) { var charCodeToEscape = m1.charCodeAt(0); return "~E"+charCodeToEscape+"E"; } } // end of Showdown.converter // export if (typeof exports != 'undefined') exports.Showdown = Showdown;   No newline at end of file


if (!context) { context = emptyObject; } <del> var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true); this._render(element, transaction, context); ReactUpdates.ReactReconcileTransaction.release(transaction); </del> <ins> ReactUpdates.batchedUpdates(_batchedRender, this, element, context); </ins> return this.getRenderOutput(); }; <ins> function _batchedRender(renderer, element, context) { var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true); renderer._render(element, transaction, context); ReactUpdates.ReactReconcileTransaction.release(transaction); } </ins> ReactShallowRenderer.prototype.getRenderOutput = function() { return ( (this._instance && this._instance._renderedComponent &&


expect(result.props.className).toEqual('clicked'); });  it('can setState in componentWillMount when shallow rendering', function() { var SimpleComponent = React.createClass({ componentWillMount() { this.setState({groovy: 'doovy'}); }, render() { return
{this.state.groovy}
; }, }); var shallowRenderer = ReactTestUtils.createRenderer(); var result = shallowRenderer.render(<SimpleComponent />); expect(result).toEqual(
doovy
); });  it('can pass context when shallowly rendering', function() { var SimpleComponent = React.createClass({ contextTypes: {


1. Assign a `ref` attribute to anything returned from `render` such as: <del> ```html <input ref="myInput" /> ``` </del> <ins> ```html <input ref="myInput" /> ``` </ins> 2. In some other code (typically event handler code), access the **backing instance** via `this.refs` as in: <del> ```javascript this.refs.myInput ``` </del> <ins> ```javascript this.refs.myInput ``` </ins> You can access the component's DOM node directly by calling `React.findDOMNode(this.refs.myInput)`.


It's as simple as assigning a `ref` attribute to anything returned from `render` such as: <del> ```html <input ref={ function(component){ React.findDOMNode(component).focus();} } /> ``` </del> <ins> ```html render: function() { return <TextInput ref={(c) => this._input = c} } />; }, componentDidMount: function() { this._input.focus(); }, ``` or ```html render: function() { return ( <TextInput ref={function(input) { if (input != null) { input.focus(); } }} /> ); }, ``` Note that when the referenced component is unmounted and whenever the ref changes, the old ref will be called with `null` as an argument. This prevents memory leaks in the case that the instance is stored, as in the first example. Note that when writing refs with inline function expressions as in the examples here, React sees a different function object each time so on every update, ref will be called with `null` immediately before it's called with the component instance. </ins> ## Completing the Example


* @param {*} parentType node's parent's type. */ function validateChildKeys(node, parentType) { <ins> if (typeof node !== 'object') { return; } </ins> if (Array.isArray(node)) { for (var i = 0; i < node.length; i++) { var child = node[i];


expect(console.error.argsForCall.length).toBe(0); }); <ins> it('should not enumerate enumerable numbers (#4776)', function() { /*eslint-disable no-extend-native */ Number.prototype['@@iterator'] = function() { throw new Error('number iterator called'); }; /*eslint-enable no-extend-native */ try { void ( <div> {5} {12} {13} </div> ); } finally { delete Number.prototype['@@iterator']; } }); </ins> });


); }); <ins> it('should not enumerate enumerable numbers (#4776)', function() { /*eslint-disable no-extend-native */ Number.prototype['@@iterator'] = function() { throw new Error('number iterator called'); }; /*eslint-enable no-extend-native */ try { var instance = ( <div> {5} {12} {13} </div> ); var traverseFn = jasmine.createSpy(); traverseAllChildren(instance.props.children, traverseFn, null); expect(traverseFn.calls.length).toBe(3); expect(traverseFn).toHaveBeenCalledWith( null, 5, '.0' ); expect(traverseFn).toHaveBeenCalledWith( null, 12, '.1' ); expect(traverseFn).toHaveBeenCalledWith( null, 13, '.2' ); } finally { delete Number.prototype['@@iterator']; } }); </ins> });


* real browser event. */ if (typeof window !== 'undefined' && <del> typeof window.dispatchEvent === 'function' && typeof Event === 'function') { </del> <ins> typeof window.dispatchEvent === 'function') { </ins> var fakeNode = document.createElement('react'); ReactErrorUtils.invokeGuardedCallback = function(name, func, a, b) { var boundFunc = func.bind(null, a, b); fakeNode.addEventListener(name, boundFunc, false); <del> fakeNode.dispatchEvent(new Event(name)); </del> <ins> var evt = document.createEvent('Event'); evt.initEvent(name, false, false); fakeNode.dispatchEvent(evt); </ins> fakeNode.removeEventListener(name, boundFunc, false); }; }


invariant( typeof callback === 'function', 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + <del> '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 'isn't callable.' </del> <ins> '`setState`, `replaceState`, or `forceUpdate` with a callback of type ' + '%s. A function is expected', typeof callback === 'object' && Object.keys(callback).length && Object.keys(callback).length < 20 ? typeof callback + ' (keys: ' + Object.keys(callback) + ')' : typeof callback </ins> ); var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);


invariant( typeof callback === 'function', 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + <del> '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 'isn't callable.' </del> <ins> '`setState`, `replaceState`, or `forceUpdate` with a callback of type ' + '%s. A function is expected', typeof callback === 'object' && Object.keys(callback).length && Object.keys(callback).length < 20 ? typeof callback + ' (keys: ' + Object.keys(callback) + ')' : typeof callback </ins> ); if (internalInstance._pendingCallbacks) { internalInstance._pendingCallbacks.push(callback);


*/ function createLinkTypeChecker(linkType) { var shapes = { <del> value: typeof linkType === 'undefined' ? </del> <ins> value: linkType === undefined ? </ins> React.PropTypes.any.isRequired : linkType.isRequired, requestChange: React.PropTypes.func.isRequired,


var initialState = this.getInitialState ? this.getInitialState() : null; if (__DEV__) { // We allow auto-mocks to proceed as if they're returning null. <del> if (typeof initialState === 'undefined' && </del> <ins> if (initialState === undefined && </ins> this.getInitialState._isMockFunction) { // This is probably bad practice. Consider warning here and // deprecating this convenience.


if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { <del> if (typeof props[propName] === 'undefined') { </del> <ins> if (props[propName] === undefined) { </ins> props[propName] = defaultProps[propName]; } }


var range = document.selection.createRange().duplicate(); var start, end; <del> if (typeof offsets.end === 'undefined') { </del> <ins> if (offsets.end === undefined) { </ins> start = offsets.start; end = start; } else if (offsets.start > offsets.end) {


var selection = window.getSelection(); var length = node[getTextContentAccessor()].length; var start = Math.min(offsets.start, length); <del> var end = typeof offsets.end === 'undefined' ? </del> <ins> var end = offsets.end === undefined ? </ins> start : Math.min(offsets.end, length); // IE 11 uses modern selection, but doesn't support the extend method.


setSelection: function(input, offsets) { var start = offsets.start; var end = offsets.end; <del> if (typeof end === 'undefined') { </del> <ins> if (end === undefined) { </ins> end = start; }


Component.displayName || Component.name || 'Component'; warning( <del> typeof inst.props === 'undefined' || !propsMutated, </del> <ins> inst.props === undefined || !propsMutated, </ins> '%s(...): When calling super() in `%s`, make sure to pass ' + 'up the same props that your component's constructor was passed.', componentName, componentName


if (__DEV__) { warning( <del> typeof shouldUpdate !== 'undefined', </del> <ins> shouldUpdate !== undefined, </ins> '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent'


var renderedComponent = inst.render(); if (__DEV__) { // We allow auto-mocks to proceed as if they're returning null. <del> if (typeof renderedComponent === 'undefined' && </del> <ins> if (renderedComponent === undefined && </ins> inst.render._isMockFunction) { // This is probably bad practice. Consider warning here and // deprecating this convenience.


'use strict'; <del> // NOTE: We're explicitly not using JSX in this file. This is intended to test // classic JS without JSX. </del> var React; var ReactDOM; var ReactTestUtils;


React = require('React'); ReactDOM = require('ReactDOM'); ReactTestUtils = require('ReactTestUtils'); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> ComponentClass = React.createClass({ render: function() { return React.createElement('div');


expect(console.error.argsForCall.length).toBe(0); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('allows static methods to be called using the type property', function() { spyOn(console, 'error');


expect(console.error.argsForCall.length).toBe(0); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('identifies valid elements', function() { var Component = React.createClass({ render: function() {


expect(typeof Component.specialType.isRequired).toBe('function'); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('is indistinguishable from a plain object', function() { var element = React.createElement('div', {className: 'foo'}); var object = {}; expect(element.constructor).toBe(object.constructor); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('should use default prop value when removing a prop', function() { var Component = React.createClass({ getDefaultProps: function() {


expect(instance.props.fruit).toBe('persimmon'); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('should normalize props with default values', function() { var Component = React.createClass({ getDefaultProps: function() {


expect(console.error.argsForCall.length).toBe(0); }); <ins> // NOTE: We're explicitly not using JSX here. This is intended to test // classic JS without JSX. </ins> it('identifies elements, but not JSON, if Symbols are supported', function() { // Rudimentary polyfill // Once all jest engines support Symbols natively we can swap this to test


expect(isTagStackValid(['table', 'tr'])).toBe(false); expect(isTagStackValid(['div', 'ul', 'li', 'div', 'li'])).toBe(false); expect(isTagStackValid(['div', 'html'])).toBe(false); <ins> expect(isTagStackValid(['body', 'body'])).toBe(false); expect(isTagStackValid(['svg', 'foreignObject', 'body', 'p'])).toBe(false); </ins> }); });


case 'rt': return impliedEndTags.indexOf(parentTag) === -1; <ins> case 'body': </ins> case 'caption': case 'col': case 'colgroup':


} } <ins> function stripComplexValues(key, value) { if (typeof value !== 'object' || Array.isArray(value) || value == null) { return value; } var prototype = Object.getPrototypeOf(value); if (!prototype || prototype === Object.prototype) { return value; } return '<not serializable>'; } </ins> // This implementation of ReactPerf is going away some time mid 15.x. // While we plan to keep most of the API, the actual format of measurements // will change dramatically. To signal this, we wrap them into an opaque-ish


var result = {}; result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id; result.type = item.type; <del> result.args = JSON.stringify(item.args); </del> <ins> result.args = JSON.stringify(item.args, stripComplexValues); </ins> return result; })); console.log(


expect(summary).toEqual([]); });  it('should print a table after calling printOperations', function() { var container = document.createElement('div'); var measurements = measure(() => { ReactDOM.render(
hey
, container); }); spyOn(console, 'table'); ReactDefaultPerf.printOperations(measurements); expect(console.table.calls.length).toBe(1); expect(console.table.argsForCall[0][0]).toEqual([{ 'data-reactid': '', type: 'set innerHTML', args: '{"node":"<not serializable>","children":[],"html":null,"text":null}', }]); });  it('warns once when using getMeasurementsSummaryMap', function() { var measurements = measure(() => {}); spyOn(console, 'error');


); }); <del> it('should properly log warnings when events simulated with rendered components', function() { </del> <ins> // TODO: reenable this test. We are currently silencing these warnings when // using TestUtils.Simulate to avoid spurious warnings that result from the // way we simulate events. xit('should properly log warnings when events simulated with rendered components', function() { </ins> spyOn(console, 'error'); var event; var element = document.createElement('div');


fakeNativeEvent, node ); <ins> // Since we aren't using pooling, always persist the event. This will make // sure it's marked and won't warn when setting additional properties. event.persist(); </ins> Object.assign(event, eventData); if (dispatchConfig.phasedRegistrationNames) {


expect(handler).not.toHaveBeenCalled(); });  it('should not warn when simulating events with extra properties', function() { spyOn(console, 'error'); var CLIENT_X = 100; var Component = React.createClass({ handleClick: function(e) { expect(e.clientX).toBe(CLIENT_X); }, render: function() { return
; }, }); var element = document.createElement('div'); var instance = ReactDOM.render(<Component />, element); ReactTestUtils.Simulate.click( ReactDOM.findDOMNode(instance), {clientX: CLIENT_X} ); expect(console.error.calls.length).toBe(0); });  it('can scry with stateless components involved', function() { var Stateless = () =>

; var SomeComponent = React.createClass({


var args = [ "bin/jsx", <ins> "--cache-dir", ".module-cache", </ins> config.sourceDir, config.outputDir ];


2. If you've added code that should be tested, add tests! 3. If you've changed APIs, update the documentation. 4. Ensure the test suite passes (`npm test`). <del> 5. Make sure your code lints (`npm run lint`). 6. Format your code with [prettier](https://github.com/prettier/prettier) (`npm run prettier`). </del> <ins> 5. Format your code with [prettier](https://github.com/prettier/prettier) (`npm run prettier`). 6. Make sure your code lints (`npm run lint`). </ins> 7. Run the [Flow](https://flowtype.org/) typechecks (`npm run flow`). 8. If you added or removed any tests, run `./scripts/fiber/record-tests` before submitting the pull request, and commit the resulting changes. 9. If you haven't already, complete the CLA.


var invariant = require('fbjs/lib/invariant'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); <del> // TODO: There's no way to cancel these, because Fiber doesn't atm. let rAF: (callback: (time: number) => void) => number; </del> <ins> // TODO: There's no way to cancel, because Fiber doesn't atm. </ins> let rIC: (callback: (deadline: Deadline) => void) => number; if (!ExecutionEnvironment.canUseDOM) { <del> rAF = function(frameCallback: (time: number) => void): number { setTimeout(frameCallback, 16); return 0; }; </del> rIC = function(frameCallback: (deadline: Deadline) => void): number { setTimeout(() => { frameCallback({


'polyfill in older browsers.', ); } else if (typeof requestIdleCallback !== 'function') { <del> // Wrap requestAnimationFrame and polyfill requestIdleCallback. </del> <ins> // Polyfill requestIdleCallback. </ins> var scheduledRAFCallback = null; var scheduledRICCallback = null;


isIdleScheduled = false; var callback = scheduledRICCallback; scheduledRICCallback = null; <del> if (callback) { </del> <ins> if (callback !== null) { </ins> callback(frameDeadlineObject); } };


} var callback = scheduledRAFCallback; scheduledRAFCallback = null; <del> if (callback) { </del> <ins> if (callback !== null) { </ins> callback(rafTime); } }; <del> rAF = function(callback: (time: number) => void): number { // This assumes that we only schedule one callback at a time because that's // how Fiber uses it. scheduledRAFCallback = callback; if (!isAnimationFrameScheduled) { // If rIC didn't already schedule one, we need to schedule a frame. isAnimationFrameScheduled = true; requestAnimationFrame(animationTick); } return 0; }; </del> rIC = function(callback: (deadline: Deadline) => void): number { // This assumes that we only schedule one callback at a time because that's // how Fiber uses it.


return 0; }; } else { <del> rAF = requestAnimationFrame; </del> rIC = requestIdleCallback; } <del> exports.rAF = rAF; </del> exports.rIC = rIC;


```javascript render() { return [ <del> <li key="A"/>First item</li>, <li key="B"/>Second item</li>, <li key="C"/>Third item</li>, </del> <ins> <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, </ins> ]; } ```


}, }} className="gatsby-highlight"> <del> <LiveEditor onChange={this._onChange} /> </del> <ins> <LiveEditor onChange={this._onChange} ignoreTabKey={true} /> </ins> </div> </div> {error &&


function getUnboundedScrollPosition(scrollable) { if (scrollable === window) { return { <del> x: document.documentElement.scrollLeft || document.body.scrollLeft, y: document.documentElement.scrollTop  || document.body.scrollTop </del> <ins> x: window.pageXOffset || document.documentElement.scrollLeft, y: window.pageYOffset || document.documentElement.scrollTop </ins> }; } return {


import requestAnimationFrameForReact from 'shared/requestAnimationFrameForReact'; import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; <ins> import invariant from 'fbjs/lib/invariant'; import warning from 'fbjs/lib/warning'; </ins> // We capture a local reference to any global, in case it gets polyfilled after // this module is initially evaluated.


localClearTimeout(timeoutId); }; } else { <ins> if (__DEV__) { if (typeof requestAnimationFrameForReact !== 'function') { warning( false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills', ); } } let localRequestAnimationFrame = typeof requestAnimationFrameForReact === 'function' ? requestAnimationFrameForReact : function(callback: Function) { invariant( false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills', ); }; </ins> let headOfPendingCallbacksLinkedList: CallbackConfigType | null = null; let tailOfPendingCallbacksLinkedList: CallbackConfigType | null = null;


if (!isAnimationFrameScheduled) { // Schedule another animation callback so we retry later. isAnimationFrameScheduled = true; <del> requestAnimationFrameForReact(animationTick); </del> <ins> localRequestAnimationFrame(animationTick); </ins> } } };


// might want to still have setTimeout trigger scheduleWork as a backup to ensure // that we keep performing work. isAnimationFrameScheduled = true; <del> requestAnimationFrameForReact(animationTick); </del> <ins> localRequestAnimationFrame(animationTick); </ins> } return scheduledCallbackConfig; };


'use strict'; <del> import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; import warning from 'fbjs/lib/warning'; </del> // We capture a local reference to any global, in case it gets polyfilled after // this module is initially evaluated. // We want to be using a consistent implementation. <del> const localRequestAnimationFrame = requestAnimationFrame; </del> <ins> const localRequestAnimationFrame = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : undefined; </ins> <del> if (__DEV__) { if ( ExecutionEnvironment.canUseDOM && typeof localRequestAnimationFrame !== 'function' ) { warning( false, 'React depends on requestAnimationFrame. Make sure that you load a ' + 'polyfill in older browsers. https://fb.me/react-polyfills', ); } } </del> <ins> // The callsites should check if the requestAnimationFrame imported from this module is a function, // fire a developer warning if it doesn't exist, and substitute it by a shim in that case // (e.g. that throws on call). </ins> export default localRequestAnimationFrame;


time: true, // There are working polyfills for <dialog>. Let people use it. dialog: true, <ins> // Electron ships a custom <webview> tag to display external web content in // an isolated frame and process. // This tag is not present in non Electron environments such as JSDom which // is often used for testing purposes. // @see https://electronjs.org/docs/api/webview-tag webview: true, </ins> }; validatePropertiesInDevelopment = function(type, props) {


): null | Fiber { if (current === null) { let type = Component.type; <del> if (isSimpleFunctionComponent(type) && Component.compare === null) { </del> <ins> if ( isSimpleFunctionComponent(type) && Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. Component.defaultProps === undefined ) { </ins> // If this is a plain function component without default props, // and with only the default shallow comparison, we upgrade it // to a SimpleMemoComponent to allow fast path updates.


case MemoComponent: { const type = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; <del> const resolvedProps = resolveDefaultProps(type.type, unresolvedProps); </del> <ins> // Resolve outer props first, then resolve inner props. let resolvedProps = resolveDefaultProps(type, unresolvedProps); resolvedProps = resolveDefaultProps(type.type, resolvedProps); </ins> return updateMemoComponent( current, workInProgress,


expect(root).toMatchRenderedOutput('FooBar'); expect(ref.current).not.toBe(null); }); <ins> // Regression test for #14310 it('supports defaultProps defined on the memo() return value', async () => { const Add = React.memo(props => { return props.inner + props.outer; }); Add.defaultProps = { inner: 2, }; const LazyAdd = lazy(() => fakeImport(Add)); const root = ReactTestRenderer.create( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={2} /> </Suspense>, { unstable_isConcurrent: true, }, ); expect(root).toFlushAndYield(['Loading...']); expect(root).toMatchRenderedOutput(null); // Mount await Promise.resolve(); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('4'); // Update (shallowly equal) root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={2} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('4'); // Update root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={3} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('5'); // Update (shallowly equal) root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={3} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('5'); // Update (explicit props) root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={1} inner={1} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('2'); // Update (explicit props, shallowly equal) root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={1} inner={1} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('2'); // Update root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={1} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('3'); }); it('merges defaultProps in the correct order', async () => { let Add = React.memo(props => { return props.inner + props.outer; }); Add.defaultProps = { inner: 100, }; Add = React.memo(Add); Add.defaultProps = { inner: 2, outer: 0, }; const LazyAdd = lazy(() => fakeImport(Add)); const root = ReactTestRenderer.create( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={2} /> </Suspense>, { unstable_isConcurrent: true, }, ); expect(root).toFlushAndYield(['Loading...']); expect(root).toMatchRenderedOutput(null); // Mount await Promise.resolve(); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('4'); // Update root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd outer={3} /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('5'); // Update root.update( <Suspense fallback={<Text text="Loading..." />}> <LazyAdd /> </Suspense>, ); root.unstable_flushAll(); expect(root).toMatchRenderedOutput('2'); }); </ins> });


unstable_continueExecution, unstable_wrapCallback, unstable_getCurrentPriorityLevel, <ins> unstable_IdlePriority, unstable_ImmediatePriority, unstable_LowPriority, unstable_NormalPriority, unstable_UserBlockingPriority, </ins> } from 'scheduler'; import { __interactionsRef,


unstable_pauseExecution, unstable_continueExecution, unstable_getCurrentPriorityLevel, <ins> unstable_IdlePriority, unstable_ImmediatePriority, unstable_LowPriority, unstable_NormalPriority, unstable_UserBlockingPriority, </ins> }, SchedulerTracing: { __interactionsRef,


unstable_continueExecution: unstable_continueExecution, unstable_pauseExecution: unstable_pauseExecution, unstable_getFirstCallbackNode: unstable_getFirstCallbackNode, <ins> get unstable_IdlePriority() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .Scheduler.unstable_IdlePriority; }, get unstable_ImmediatePriority() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .Scheduler.unstable_ImmediatePriority; }, get unstable_LowPriority() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .Scheduler.unstable_LowPriority; }, get unstable_NormalPriority() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .Scheduler.unstable_NormalPriority; }, get unstable_UserBlockingPriority() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .Scheduler.unstable_UserBlockingPriority; }, </ins> }); });


}); function filterPrivateKeys(name) { <del> // TODO: Figure out how to forward priority levels. return !name.startsWith('_') && !name.endsWith('Priority'); </del> <ins> // Be very careful adding things to this whitelist! // It's easy to introduce bugs by doing it: // https://github.com/facebook/react/issues/14904 switch (name) { case '__interactionsRef': case '__subscriberRef': // Don't forward these. (TODO: why?) return false; default: return true; } </ins> } function validateForwardedAPIs(api, forwardedAPIs) {


<ins> /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ const {useState} = require('react'); const {useCustom} = require('./useCustom'); function Component(props) { const [count] = useState(0); useCustom(); return count; } module.exports = {Component}; </ins>  No newline at end of file


<ins> /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ const {useEffect} = require('react'); function useCustom() { useEffect(() => { // ... }, []); } module.exports = {useCustom}; </ins>  No newline at end of file


expectHookNamesToEqual(hookNames, ['foo', 'bar', 'baz']); }); <del> it('should return null for hooks without names like useEffect', async () => { </del> <ins> it('should skip loading source files for unnamed hooks like useEffect', async () => { </ins> const Component = require('./__source__/__untransformed__/ComponentWithUseEffect') .Component; <ins> // Since this component contains only unnamed hooks, the source code should not even be loaded. fetchMock.mockIf(/.+$/, request => { throw Error(`Unexpected file request for "${request.url}"`); }); </ins> const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, []); // No hooks with names }); <ins> it('should skip loading source files for unnamed hooks like useEffect (alternate)', async () => { const Component = require('./__source__/__untransformed__/ComponentWithExternalUseEffect') .Component; fetchMock.mockIf(/.+$/, request => { // Since th custom hook contains only unnamed hooks, the source code should not be loaded. if (request.url.endsWith('useCustom.js')) { throw Error(`Unexpected file request for "${request.url}"`); } return Promise.resolve(requireText(request.url, 'utf8')); }); const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, ['count', null]); // No hooks with names }); </ins> it('should parse names for custom hooks', async () => { const Component = require('./__source__/__untransformed__/ComponentWithNamedCustomHooks') .Component;


await test( './__source__/__compiled__/external/ComponentWithMultipleHooksPerLine', ); // external source map <del> await test( './__source__/__compiled__/bundle', 'ComponentWithMultipleHooksPerLine', ); // bundle source map </del> <ins> // await test( //   './__source__/__compiled__/bundle', //   'ComponentWithMultipleHooksPerLine', // ); // bundle source map </ins> }); // TODO Inline require (e.g. require("react").useState()) isn't supported yet.


return /^use[A-Z0-9].*$/.test(name); } <del> // Determines whether incoming hook is a primitive hook that gets assigned to variables. export function isNonDeclarativePrimitiveHook(hook: HooksNode) { return ['Effect', 'ImperativeHandle', 'LayoutEffect', 'DebugValue'].includes( hook.name, ); } </del> // Check if the AST Node COULD be a React Hook function isPotentialHookDeclaration(path: NodePath): boolean { // The array potentialHooksFound will contain all potential hook declaration cases we support


import {enableHookNameParsing} from 'react-devtools-feature-flags'; import LRU from 'lru-cache'; import {SourceMapConsumer} from 'source-map'; <del> import {getHookName, isNonDeclarativePrimitiveHook} from './astUtils'; </del> <ins> import {getHookName} from './astUtils'; </ins> import {areSourceMapsAppliedToErrors} from './ErrorTester'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; import {getHookSourceLocationKey} from 'react-devtools-shared/src/hookNamesCache';


const map: HookNames = new Map(); hooksList.map(hook => { <del> // TODO (named hooks) We should probably filter before this point, // otherwise we are loading and parsing source maps and ASTs for nothing. if (isNonDeclarativePrimitiveHook(hook)) { if (__DEBUG__) { console.log('findHookNames() Non declarative primitive hook'); } // Not all hooks have names (e.g. useEffect or useLayoutEffect) return null; } </del> // We already guard against a null HookSource in parseHookNames() const hookSource = ((hook.hookSource: any): HookSource); const fileName = hookSource.fileName;


): void { for (let i = 0; i < hooksTree.length; i++) { const hook = hooksTree[i]; <ins> if (isUnnamedBuiltInHook(hook)) { // No need to load source code or do any parsing for unnamed hooks. if (__DEBUG__) { console.log('flattenHooksList() Skipping unnamed hook', hook); } continue; } </ins> hooksList.push(hook); if (hook.subHooks.length > 0) { flattenHooksList(hook.subHooks, hooksList);


} } <ins> // Determines whether incoming hook is a primitive hook that gets assigned to variables. function isUnnamedBuiltInHook(hook: HooksNode) { return ['Effect', 'ImperativeHandle', 'LayoutEffect', 'DebugValue'].includes( hook.name, ); } </ins> function updateLruCache( locationKeyToHookSourceData: Map<string, HookSourceData>, ): Promise<*> {


}); }); <ins> it('inspecting nested renderers should not throw', async () => { // Ignoring react art warnings spyOn(console, 'error'); const ReactArt = require('react-art'); const ArtSVGMode = require('art/modes/svg'); const ARTCurrentMode = require('art/modes/current'); store.componentFilters = []; ARTCurrentMode.setCurrent(ArtSVGMode); const {Surface, Group} = ReactArt; function Child() { return ( <Surface width={1} height={1}> <Group /> </Surface> ); } function App() { return <Child />; } await utils.actAsync(() => { legacyRender(<App />, document.createElement('div')); }); expect(store).toMatchInlineSnapshot(` [root] ▾ <App> ▾ <Child> ▾ <Surface> <svg> [root] <Group> `); const inspectedElement = await inspectElementAtIndex(4); expect(inspectedElement.owners).toMatchInlineSnapshot(` Array [ Object { "displayName": "Child", "hocDisplayNames": null, "id": 3, "key": null, "type": 5, }, Object { "displayName": "App", "hocDisplayNames": null, "id": 2, "key": null, "type": 5, }, ] `); }); </ins> describe('error boundary', () => { it('can toggle error', async () => { class LocalErrorBoundary extends React.Component<any> {


}; } <ins> // Map of one or more Fibers in a pair to their unique id number. // We track both Fibers to support Fast Refresh, // which may forcefully replace one of the pair as part of hot reloading. // In that case it's still important to be able to locate the previous ID during subsequent renders. const fiberToIDMap: Map<Fiber, number> = new Map(); // Map of id to one (arbitrary) Fiber in a pair. // This Map is used to e.g. get the display name for a Fiber or schedule an update, // operations that should be the same whether the current and work-in-progress Fiber is used. const idToArbitraryFiberMap: Map<number, Fiber> = new Map(); </ins> export function attach( hook: DevToolsHook, rendererID: number,


} } <del> // Map of one or more Fibers in a pair to their unique id number. // We track both Fibers to support Fast Refresh, // which may forcefully replace one of the pair as part of hot reloading. // In that case it's still important to be able to locate the previous ID during subsequent renders. const fiberToIDMap: Map<Fiber, number> = new Map(); // Map of id to one (arbitrary) Fiber in a pair. // This Map is used to e.g. get the display name for a Fiber or schedule an update, // operations that should be the same whether the current and work-in-progress Fiber is used. const idToArbitraryFiberMap: Map<number, Fiber> = new Map(); </del> // When profiling is supported, we store the latest tree base durations for each Fiber. // This is so that we can quickly capture a snapshot of those values if profiling starts. // If we didn't store these values, we'd have to crawl the tree when profiling started,


visitor: { CallExpression: function(path, file) { <del> if (file.filename.indexOf('shared/assign') !== -1) { </del> <ins> if (/shared(/|)assign/.test(file.filename)) { </ins> // Don't replace Object.assign if we're transforming shared/assign return; }


}, MemberExpression: function(path, file) { <del> if (file.filename.indexOf('shared/assign') !== -1) { </del> <ins> if (/shared(/|)assign/.test(file.filename)) { </ins> // Don't replace Object.assign if we're transforming shared/assign return; }


1 Note that at this time, an _experimental_ build is required because DevTools depends on the `createRoot` API.  To install all necessary dependencies, run the following command from the root of the repository: ```sh yarn install ```  #### Build from source To build dependencies from source, run the following command from the root of the repository: ```sh


props: Object, resumableState: ResumableState, renderState: RenderState, <del> pictureTagInScope: boolean, </del> <ins> pictureOrNoScriptTagInScope: boolean, </ins> ): null { const {src, srcSet} = props; if (


(typeof src === 'string' || src == null) && (typeof srcSet === 'string' || srcSet == null) && props.fetchPriority !== 'low' && <del> pictureTagInScope === false && </del> <ins> pictureOrNoScriptTagInScope === false && </ins> // We exclude data URIs in src and srcSet since these should not be preloaded !( typeof src === 'string' &&


props, resumableState, renderState, <del> !!(formatContext.tagScope & PICTURE_SCOPE), </del> <ins> !!(formatContext.tagScope & (PICTURE_SCOPE | NOSCRIPT_SCOPE)), </ins> ); } // Omitted close tags


); });  // Fixes: https://github.com/facebook/react/issues/27910 it('omits preloads for images inside noscript tags', async () => { function App() { return (         ); } await act(() => { renderToPipeableStream(<App />).pipe(writable); }); expect(getMeaningfulChildren(document)).toEqual(   <link rel="preload" href="foo" as="image" />    <img src="bar">  , ); });  it('should handle media on image preload', async () => { function App({isClient}) { ReactDOM.preload('/server', {