text: /**
   * @license AngularJS v1.2.26
   * (c) 2010-2014 Google, Inc. http://angularjs.org
   * License: MIT
   */
  (function(window, angular, undefined) {'use strict';
  
  var $sanitizeMinErr = angular.$$minErr('$sanitize');
  
  /**
   * @ngdoc module
   * @name ngSanitize
   * @description
   *
   * # ngSanitize
   *
   * The `ngSanitize` module provides functionality to sanitize HTML.
   *
   *
   * <div doc-module-components="ngSanitize"></div>
   *
   * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
   */
  
  /*
   * HTML Parser By Misko Hevery (misko@hevery.com)
   * based on:  HTML Parser By John Resig (ejohn.org)
   * Original code by Erik Arvidsson, Mozilla Public License
   * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
   *
   * // Use like so:
   * htmlParser(htmlString, {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * });
   *
   */
  
  
  /**
   * @ngdoc service
   * @name $sanitize
   * @kind function
   *
   * @description
   *   The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are
   *   then serialized back to properly escaped html string. This means that no unsafe input can make
   *   it into the returned string, however, since our parser is more strict than a typical browser
   *   parser, it's possible that some obscure input, which would be recognized as valid HTML by a
   *   browser, won't make it through the sanitizer.
   *   The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
   *   `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
   *
   * @param {string} html Html input.
   * @returns {string} Sanitized html.
   *
   * @example
     <example module="sanitizeExample" deps="angular-sanitize.js">
     <file name="index.html">
       <script>
           angular.module('sanitizeExample', ['ngSanitize'])
             .controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
               $scope.snippet =
                 '<p style="color:blue">an html\n' +
                 '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
                 'snippet</p>';
               $scope.deliberatelyTrustDangerousSnippet = function() {
                 return $sce.trustAsHtml($scope.snippet);
               };
             }]);
       </script>
       <div ng-controller="ExampleController">
          Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
         <table>
           <tr>
             <td>Directive</td>
             <td>How</td>
             <td>Source</td>
             <td>Rendered</td>
           </tr>
           <tr id="bind-html-with-sanitize">
             <td>ng-bind-html</td>
             <td>Automatically uses $sanitize</td>
             <td><pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
             <td><div ng-bind-html="snippet"></div></td>
           </tr>
           <tr id="bind-html-with-trust">
             <td>ng-bind-html</td>
             <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
             <td>
             <pre>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
  &lt;/div&gt;</pre>
             </td>
             <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
           </tr>
           <tr id="bind-default">
             <td>ng-bind</td>
             <td>Automatically escapes</td>
             <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
             <td><div ng-bind="snippet"></div></td>
           </tr>
         </table>
         </div>
     </file>
     <file name="protractor.js" type="protractor">
       it('should sanitize the html snippet by default', function() {
         expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
           toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
       });
  
       it('should inline raw snippet if bound to a trusted value', function() {
         expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
           toBe("<p style=\"color:blue\">an html\n" +
                "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
                "snippet</p>");
       });
  
       it('should escape snippet without any filter', function() {
         expect(element(by.css('#bind-default div')).getInnerHtml()).
           toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
                "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
                "snippet&lt;/p&gt;");
       });
  
       it('should update', function() {
         element(by.model('snippet')).clear();
         element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
         expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
           toBe('new <b>text</b>');
         expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
           'new <b onclick="alert(1)">text</b>');
         expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
           "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
       });
     </file>
     </example>
   */
  function $SanitizeProvider() {
    this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
      return function(html) {
        var buf = [];
        htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
          return !/^unsafe/.test($$sanitizeUri(uri, isImage));
        }));
        return buf.join('');
      };
    }];
  }
  
  function sanitizeText(chars) {
    var buf = [];
    var writer = htmlSanitizeWriter(buf, angular.noop);
    writer.chars(chars);
    return buf.join('');
  }
  
  
  // Regular Expressions for parsing tags and attributes
  var START_TAG_REGEXP =
         /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,
    END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/,
    ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
    BEGIN_TAG_REGEXP = /^</,
    BEGING_END_TAGE_REGEXP = /^<\//,
    COMMENT_REGEXP = /<!--(.*?)-->/g,
    DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
    CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
    SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
    // Match everything outside of normal chars and " (quote character)
    NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
  
  
  // Good source of info about elements and attributes
  // http://dev.w3.org/html5/spec/Overview.html#semantics
  // http://simon.html5.org/html-elements
  
  // Safe Void Elements - HTML5
  // http://dev.w3.org/html5/spec/Overview.html#void-elements
  var voidElements = makeMap("area,br,col,hr,img,wbr");
  
  // Elements that you can, intentionally, leave open (and which close themselves)
  // http://dev.w3.org/html5/spec/Overview.html#optional-tags
  var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
      optionalEndTagInlineElements = makeMap("rp,rt"),
      optionalEndTagElements = angular.extend({},
                                              optionalEndTagInlineElements,
                                              optionalEndTagBlockElements);
  
  // Safe Block Elements - HTML5
  var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
          "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
          "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
  
  // Inline Elements - HTML5
  var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
          "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
          "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
  
  
  // Special Elements (can contain anything)
  var specialElements = makeMap("script,style");
  
  var validElements = angular.extend({},
                                     voidElements,
                                     blockElements,
                                     inlineElements,
                                     optionalEndTagElements);
  
  //Attributes that have href and hence need to be sanitized
  var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
  var validAttrs = angular.extend({}, uriAttrs, makeMap(
      'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
      'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
      'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
      'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
      'valign,value,vspace,width'));
  
  function makeMap(str) {
    var obj = {}, items = str.split(','), i;
    for (i = 0; i < items.length; i++) obj[items[i]] = true;
    return obj;
  }
  
  
  /**
   * @example
   * htmlParser(htmlString, {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * });
   *
   * @param {string} html string
   * @param {object} handler
   */
  function htmlParser( html, handler ) {
    if (typeof html !== 'string') {
      if (html === null || typeof html === 'undefined') {
        html = '';
      } else {
        html = '' + html;
      }
    }
    var index, chars, match, stack = [], last = html, text;
    stack.last = function() { return stack[ stack.length - 1 ]; };
  
    while ( html ) {
      text = '';
      chars = true;
  
      // Make sure we're not in a script or style element
      if ( !stack.last() || !specialElements[ stack.last() ] ) {
  
        // Comment
        if ( html.indexOf("<!--") === 0 ) {
          // comments containing -- are not allowed unless they terminate the comment
          index = html.indexOf("--", 4);
  
          if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
            if (handler.comment) handler.comment( html.substring( 4, index ) );
            html = html.substring( index + 3 );
            chars = false;
          }
        // DOCTYPE
        } else if ( DOCTYPE_REGEXP.test(html) ) {
          match = html.match( DOCTYPE_REGEXP );
  
          if ( match ) {
            html = html.replace( match[0], '');
            chars = false;
          }
        // end tag
        } else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
          match = html.match( END_TAG_REGEXP );
  
          if ( match ) {
            html = html.substring( match[0].length );
            match[0].replace( END_TAG_REGEXP, parseEndTag );
            chars = false;
          }
  
        // start tag
        } else if ( BEGIN_TAG_REGEXP.test(html) ) {
          match = html.match( START_TAG_REGEXP );
  
          if ( match ) {
            // We only have a valid start-tag if there is a '>'.
            if ( match[4] ) {
              html = html.substring( match[0].length );
              match[0].replace( START_TAG_REGEXP, parseStartTag );
            }
            chars = false;
          } else {
            // no ending tag found --- this piece should be encoded as an entity.
            text += '<';
            html = html.substring(1);
          }
        }
  
        if ( chars ) {
          index = html.indexOf("<");
  
          text += index < 0 ? html : html.substring( 0, index );
          html = index < 0 ? "" : html.substring( index );
  
          if (handler.chars) handler.chars( decodeEntities(text) );
        }
  
      } else {
        html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
          function(all, text){
            text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
  
            if (handler.chars) handler.chars( decodeEntities(text) );
  
            return "";
        });
  
        parseEndTag( "", stack.last() );
      }
  
      if ( html == last ) {
        throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
                                          "of html: {0}", html);
      }
      last = html;
    }
  
    // Clean up any remaining tags
    parseEndTag();
  
    function parseStartTag( tag, tagName, rest, unary ) {
      tagName = angular.lowercase(tagName);
      if ( blockElements[ tagName ] ) {
        while ( stack.last() && inlineElements[ stack.last() ] ) {
          parseEndTag( "", stack.last() );
        }
      }
  
      if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
        parseEndTag( "", tagName );
      }
  
      unary = voidElements[ tagName ] || !!unary;
  
      if ( !unary )
        stack.push( tagName );
  
      var attrs = {};
  
      rest.replace(ATTR_REGEXP,
        function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
          var value = doubleQuotedValue
            || singleQuotedValue
            || unquotedValue
            || '';
  
          attrs[name] = decodeEntities(value);
      });
      if (handler.start) handler.start( tagName, attrs, unary );
    }
  
    function parseEndTag( tag, tagName ) {
      var pos = 0, i;
      tagName = angular.lowercase(tagName);
      if ( tagName )
        // Find the closest opened tag of the same type
        for ( pos = stack.length - 1; pos >= 0; pos-- )
          if ( stack[ pos ] == tagName )
            break;
  
      if ( pos >= 0 ) {
        // Close all the open elements, up the stack
        for ( i = stack.length - 1; i >= pos; i-- )
          if (handler.end) handler.end( stack[ i ] );
  
        // Remove the open elements from the stack
        stack.length = pos;
      }
    }
  }
  
  var hiddenPre=document.createElement("pre");
  var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
  /**
   * decodes all entities into regular string
   * @param value
   * @returns {string} A string with decoded entities.
   */
  function decodeEntities(value) {
    if (!value) { return ''; }
  
    // Note: IE8 does not preserve spaces at the start/end of innerHTML
    // so we must capture them and reattach them afterward
    var parts = spaceRe.exec(value);
    var spaceBefore = parts[1];
    var spaceAfter = parts[3];
    var content = parts[2];
    if (content) {
      hiddenPre.innerHTML=content.replace(/</g,"&lt;");
      // innerText depends on styling as it doesn't display hidden elements.
      // Therefore, it's better to use textContent not to cause unnecessary
      // reflows. However, IE<9 don't support textContent so the innerText
      // fallback is necessary.
      content = 'textContent' in hiddenPre ?
        hiddenPre.textContent : hiddenPre.innerText;
    }
    return spaceBefore + content + spaceAfter;
  }
  
  /**
   * Escapes all potentially dangerous characters, so that the
   * resulting string can be safely inserted into attribute or
   * element text.
   * @param value
   * @returns {string} escaped text
   */
  function encodeEntities(value) {
    return value.
      replace(/&/g, '&amp;').
      replace(SURROGATE_PAIR_REGEXP, function (value) {
        var hi = value.charCodeAt(0);
        var low = value.charCodeAt(1);
        return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
      }).
      replace(NON_ALPHANUMERIC_REGEXP, function(value){
        // unsafe chars are: \u0000-\u001f \u007f-\u009f \u00ad \u0600-\u0604 \u070f \u17b4 \u17b5 \u200c-\u200f \u2028-\u202f \u2060-\u206f \ufeff \ufff0-\uffff from jslint.com/lint.html
        // decimal values are: 0-31, 127-159, 173, 1536-1540, 1807, 6068, 6069, 8204-8207, 8232-8239, 8288-8303, 65279, 65520-65535
        var c = value.charCodeAt(0);
        // if unsafe character encode
        if(c <= 159 ||
          c == 173 ||
          (c >= 1536 && c <= 1540) ||
          c == 1807 ||
          c == 6068 ||
          c == 6069 ||
          (c >= 8204 && c <= 8207) ||
          (c >= 8232 && c <= 8239) ||
          (c >= 8288 && c <= 8303) ||
          c == 65279 ||
          (c >= 65520 && c <= 65535)) return '&#' + c + ';';
        return value; // avoids multilingual issues
      }).
      replace(/</g, '&lt;').
      replace(/>/g, '&gt;');
  }
  
  var trim = (function() {
    // native trim is way faster: http://jsperf.com/angular-trim-test
    // but IE doesn't have it... :-(
    // TODO: we should move this into IE/ES5 polyfill
    if (!String.prototype.trim) {
      return function(value) {
        return angular.isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
      };
    }
    return function(value) {
      return angular.isString(value) ? value.trim() : value;
    };
  })();
  
  // Custom logic for accepting certain style options only - textAngular
  // Currently allows only the color, background-color, text-align, float, width and height attributes
  // all other attributes should be easily done through classes.
  function validStyles(styleAttr){
  	var result = '';
  	var styleArray = styleAttr.split(';');
  	angular.forEach(styleArray, function(value){
  		var v = value.split(':');
  		if(v.length == 2){
  			var key = trim(angular.lowercase(v[0]));
  			var value = trim(angular.lowercase(v[1]));
  			if(
  				(key === 'color' || key === 'background-color') && (
  					value.match(/^rgb\([0-9%,\. ]*\)$/i)
  					|| value.match(/^rgba\([0-9%,\. ]*\)$/i)
  					|| value.match(/^hsl\([0-9%,\. ]*\)$/i)
  					|| value.match(/^hsla\([0-9%,\. ]*\)$/i)
  					|| value.match(/^#[0-9a-f]{3,6}$/i)
  					|| value.match(/^[a-z]*$/i)
  				)
  			||
  				key === 'text-align' && (
  					value === 'left'
  					|| value === 'right'
  					|| value === 'center'
  					|| value === 'justify'
  				)
  			||
  				key === 'float' && (
  					value === 'left'
  					|| value === 'right'
  					|| value === 'none'
  				)
  			||
  				(key === 'width' || key === 'height') && (
  					value.match(/[0-9\.]*(px|em|rem|%)/)
  				)
  			) result += key + ': ' + value + ';';
  		}
  	});
  	return result;
  }
  
  // this function is used to manually allow specific attributes on specific tags with certain prerequisites
  function validCustomTag(tag, attrs, lkey, value){
    // allow data attributes
    if(lkey.lastIndexOf("data-", 0) === 0){
      return true;
    }
  
  	// catch the div placeholder for the iframe replacement
      if (tag === 'img' && attrs['ta-insert-video']){
          if(lkey === 'ta-insert-video' || lkey === 'allowfullscreen' || lkey === 'frameborder' || (lkey === 'contenteditble' && value === 'false')) return true;
      }
      return false;
  }
  
  /**
   * create an HTML/XML writer which writes to buffer
   * @param {Array} buf use buf.jain('') to get out sanitized html string
   * @returns {object} in the form of {
   *     start: function(tag, attrs, unary) {},
   *     end: function(tag) {},
   *     chars: function(text) {},
   *     comment: function(text) {}
   * }
   */
  function htmlSanitizeWriter(buf, uriValidator){
    var ignore = false;
    var out = angular.bind(buf, buf.push);
    return {
      start: function(tag, attrs, unary){
        tag = angular.lowercase(tag);
        if (!ignore && specialElements[tag]) {
          ignore = tag;
        }
        if (!ignore && validElements[tag] === true) {
          out('<');
          out(tag);
          angular.forEach(attrs, function(value, key){
            var lkey=angular.lowercase(key);
            var isImage=(tag === 'img' && lkey === 'src') || (lkey === 'background');
            if ((lkey === 'style' && (value = validStyles(value)) !== '') || validCustomTag(tag, attrs, lkey, value) || validAttrs[lkey] === true &&
              (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
              out(' ');
              out(key);
              out('="');
              out(encodeEntities(value));
              out('"');
            }
          });
          out(unary ? '/>' : '>');
        }
      },
      end: function(tag){
          tag = angular.lowercase(tag);
          if (!ignore && validElements[tag] === true) {
            out('</');
            out(tag);
            out('>');
          }
          if (tag == ignore) {
            ignore = false;
          }
        },
      chars: function(chars){
          if (!ignore) {
            out(encodeEntities(chars));
          }
        }
    };
  }
  
  
  // define ngSanitize module and register $sanitize service
  angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
  
  /* global sanitizeText: false */
  
  /**
   * @ngdoc filter
   * @name linky
   * @kind function
   *
   * @description
   * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
   * plain email address links.
   *
   * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
   *
   * @param {string} text Input text.
   * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
   * @returns {string} Html-linkified text.
   *
   * @usage
     <span ng-bind-html="linky_expression | linky"></span>
   *
   * @example
     <example module="linkyExample" deps="angular-sanitize.js">
       <file name="index.html">
         <script>
           angular.module('linkyExample', ['ngSanitize'])
             .controller('ExampleController', ['$scope', function($scope) {
               $scope.snippet =
                 'Pretty text with some links:\n'+
                 'http://angularjs.org/,\n'+
                 'mailto:us@somewhere.org,\n'+
                 'another@somewhere.org,\n'+
                 'and one more: ftp://127.0.0.1/.';
               $scope.snippetWithTarget = 'http://angularjs.org/';
             }]);
         </script>
         <div ng-controller="ExampleController">
         Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
         <table>
           <tr>
             <td>Filter</td>
             <td>Source</td>
             <td>Rendered</td>
           </tr>
           <tr id="linky-filter">
             <td>linky filter</td>
             <td>
               <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
             </td>
             <td>
               <div ng-bind-html="snippet | linky"></div>
             </td>
           </tr>
           <tr id="linky-target">
            <td>linky target</td>
            <td>
              <pre>&lt;div ng-bind-html="snippetWithTarget | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
            </td>
            <td>
              <div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
            </td>
           </tr>
           <tr id="escaped-html">
             <td>no filter</td>
             <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
             <td><div ng-bind="snippet"></div></td>
           </tr>
         </table>
       </file>
       <file name="protractor.js" type="protractor">
         it('should linkify the snippet with urls', function() {
           expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
               toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
                    'another@somewhere.org, and one more: ftp://127.0.0.1/.');
           expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
         });
  
         it('should not linkify snippet without the linky filter', function() {
           expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
               toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
                    'another@somewhere.org, and one more: ftp://127.0.0.1/.');
           expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
         });
  
         it('should update', function() {
           element(by.model('snippet')).clear();
           element(by.model('snippet')).sendKeys('new http://link.');
           expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
               toBe('new http://link.');
           expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
           expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
               .toBe('new http://link.');
         });
  
         it('should work with the target property', function() {
          expect(element(by.id('linky-target')).
              element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
              toBe('http://angularjs.org/');
          expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
         });
       </file>
     </example>
   */
  angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
    var LINKY_URL_REGEXP =
          /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
        MAILTO_REGEXP = /^mailto:/;
  
    return function(text, target) {
      if (!text) return text;
      var match;
      var raw = text;
      var html = [];
      var url;
      var i;
      while ((match = raw.match(LINKY_URL_REGEXP))) {
        // We can not end in these as they are sometimes found at the end of the sentence
        url = match[0];
        // if we did not match ftp/http/mailto then assume mailto
        if (match[2] == match[3]) url = 'mailto:' + url;
        i = match.index;
        addText(raw.substr(0, i));
        addLink(url, match[0].replace(MAILTO_REGEXP, ''));
        raw = raw.substring(i + match[0].length);
      }
      addText(raw);
      return $sanitize(html.join(''));
  
      function addText(text) {
        if (!text) {
          return;
        }
        html.push(sanitizeText(text));
      }
  
      function addLink(url, text) {
        html.push('<a ');
        if (angular.isDefined(target)) {
          html.push('target="');
          html.push(target);
          html.push('" ');
        }
        html.push('href="');
        html.push(url);
        html.push('">');
        addText(text);
        html.push('</a>');
      }
    };
  }]);
  
  
  })(window, window.angular);
  