diff options
author | Andres Rey <[email protected]> | 2017-12-03 12:24:28 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2017-12-03 12:24:28 +0000 |
commit | 0d02e2916d1659bb79426969c5d48848ff402598 (patch) | |
tree | 043f85fe97b68d24027bb067029ab6e3b7cb627d | |
parent | bbf6068a6440c2390956993a6845952a02219722 (diff) | |
parent | 62deed54da3c5248e5d8ac13805c0d1c0d2bf1d6 (diff) |
Merge pull request #33 from andreskrey/v1.0
v1.0
110 files changed, 2786 insertions, 2519 deletions
diff --git a/.travis.yml b/.travis.yml index 664bd60..18105c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,9 @@ language: php install: composer install php: - - "5.4" - - "5.5" - "5.6" - "7.0" - "7.1" + - "7.2" sudo: false
\ No newline at end of file @@ -1,6 +1,9 @@ # Authors -Readability.php developed by **Andres Rey**. Copyright (c) 2010 Arc90 Inc +Readability.php developed by **Andres Rey**. + +Based on Arc90's readability.js (1.7.1) script available at: http://code.google.com/p/arc90labs-readability. +Copyright (c) 2010 Arc90 Inc The AUTHORS/Contributors are (and/or have been): diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f931a..527f618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. ## Unreleased +## [v1.0.0](https://github.com/andreskrey/readability.php/releases/tag/v1.0.0) + +- Node encapsulation is gone. Pre v1 all nodes where encapsulated in a Readability class, which created lots of trouble with dependencies, responsibilities, and properties. Now all the encapsulation is gone: all the DOMNodes inside the Readability class are extensions of the original DOM classes, which allows the system to take advantage of the functions and properties of DOMDocument. +- HTMLParser is gone, Readability is the new main class. Switched things a bit for this release. Pre v1 you had to create an HTMLParser class to parse the HTML. Now you have to create a Readability class, feed it the text, and check the result. +- No more dumb arrays as a result. If you want to get the title, content, images, or anything else you'll have to use the getters of the Readability class. +- Environment class is gone. Now you have to create a configuration class and use setters to set your configuration options. +- Exceptions. Make sure you wrap your Readability class in a try catch block, because if it fails to parse your HTML, it will throw a `ParseException`. +- Minimum PHP version bumped to 5.6. + ## [v0.3.1](https://github.com/andreskrey/readability.php/releases/tag/v0.3.1) - Trim titles when detecting hierarchical separators to avoid false negatives on strings with spaces. @@ -1,15 +1,19 @@ # Readability.php [![Latest Stable Version](https://poser.pugx.org/andreskrey/readability.php/v/stable)](https://packagist.org/packages/andreskrey/readability.php) [![StyleCI](https://styleci.io/repos/71042668/shield?branch=master)](https://styleci.io/repos/71042668) [![Build Status](https://travis-ci.org/andreskrey/readability.php.svg?branch=master)](https://travis-ci.org/andreskrey/readability.php) [![Total Downloads](https://poser.pugx.org/andreskrey/readability.php/downloads)](https://packagist.org/packages/andreskrey/readability.php) [![Monthly Downloads](https://poser.pugx.org/andreskrey/readability.php/d/monthly)](https://packagist.org/packages/andreskrey/readability.php) -PHP port of *Mozilla's* **[Readability.js](https://github.com/mozilla/readability)**. Parses html text (usually news and other articles) and returns title, byline and text content without nav bars, ads, footers, or anything that isn't the main body of the text. Analizes each text node, gives an score and orders them based on this calculation. +PHP port of *Mozilla's* **[Readability.js](https://github.com/mozilla/readability)**. Parses html text (usually news and other articles) and returns **title**, **author**, **main image** and **text content** without nav bars, ads, footers, or anything that isn't the main body of the text. Analyzes each node, gives them a score, and determines what's relevant and what can be discarded. -**Requires**: PHP 5.4+ & DOMDocument (libxml) +![Screenshot](https://raw.githubusercontent.com/andreskrey/readability.php/assets/screenshot.png) -**Lead Developer**: Andres Rey +The project aim is to be a 1 to 1 port of Mozilla's version and to follow closely all changes introduced there, but there are some major differences on the structure. Most of the code is a 1:1 copy –even the comments were imported– but some functions and structures were adapted to suit better the PHP language. + +## Requirements -## Status +PHP 5.6+, ext-dom, ext-xml, and ext-mbstring. To install all this dependencies (in the rare case your system does not have them already), you could try something like this in *nix like environments: -Current status is stable. Version 1.0 is around the corner. +`$ sudo apt-get install php7.1-xml php7.1-mbstring` + +**Lead Developer**: Andres Rey ## How to use it @@ -17,50 +21,73 @@ First you have to require the library using composer: `composer require andreskrey/readability.php` -Then, create and HTMLParser object with your preferences, feed the `parse()` function with your HTML and check the resulting array: +Then, create a Readability class and pass a Configuration class, feed the `parse()` function with your HTML and echo the variable: ```php use andreskrey\Readability\HTMLParser; +use andreskrey\Readability\Configuration; -$readability = new HTMLParser(); +$readability = new Readability(new Configuration()); $html = file_get_contents('http://your.favorite.newspaper/article.html'); -$result = $readability->parse($html); +try { + $readability->parse($html); + echo $readability; +} catch (ParseException $e) { + echo sprintf('Error processing text: %s', $e->getMessage); +} ``` -The `$result` variable now will hold the following information: +Your script will output the parsed text or inform about any errors. You should always wrap the `->parse` call in a try/catch block because if the HTML cannot be parsed correctly, a `ParseException` will be thrown. + +If you want to have a finer control on the output, just call the properties one by one, wrapping it with your own HTML. + +```php +<h1><?= $readability->getTitle(); ?></h1> +<h2>By <?= $readability->getAuthor(); ?></h2> +<div class="content"><?= $readability->getContent(); ?></div> -``` -$result = [ - 'title' => 'Title of the article', - 'author' => 'Name of the author of the article', - 'image' => 'Main image of the article', - 'images' => 'All images of the article', - 'article' => 'DOMDocument with the full article text, scored and parsed' -] ``` -If the parsing process was unsuccessful the HTMLParser will return `false` +Here's a list of the available properties: + +- Article title: `->getTitle();` +- Article content: `->getContent();` +- Excerpt: `->getExcerpt();` +- Main image: `->getImage();` +- All images: `->getImages();` +- Author: `->getAuthor();` +- Text direction (ltr or rtl): `->getDirection();` ## Options -- **maxTopCandidates**: default value `5`, max amount of top level candidates. -- **wordThreshold**: default value `500`, minimum amount of characters to consider that the article was parsed successful. -- **articleByLine**: default value `false`, search for the article byline and remove it from the text. It will be moved to the article metadata. -- **stripUnlikelyCandidates**: default value `true`, remove nodes that are unlikely to have relevant information. Useful for debugging or parsing complex or non-standard articles. -- **cleanConditionally**: default value `true`, remove certain nodes after parsing to return a cleaner result. -- **weightClasses**: default value `true`, weight classes during the rating phase. -- **removeReadabilityTags**: default value `true`, remove the data-readability tags inside the nodes that are added during the rating phase. -- **fixRelativeURLs**: default value `false`, convert relative URLs to absolute. Like `/test` to `http://host/test`. -- **substituteEntities**: default value `false`, disables the `substituteEntities` flag of libxml. Will avoid substituting HTML entities. Like `á` to á. -- **normalizeEntities**: default value `false`, converts UTF-8 characters to its HTML Entity equivalent. Useful to parse HTML with mixed encoding. -- **originalURL**: default value `http://fakehost`, original URL from the article used to fix relative URLs. -- **summonCthulhu**: default value `false`, remove all `<script>` nodes via regex. This is not ideal as it might break things, but might be the only solution to [libxml problems with unescaped javascript](https://github.com/andreskrey/readability.php#known-issues). +You can change the behaviour of Readability via the Configuration object. For example, if you want to fix relative URLs and declare the original URL, you could set up the configuration like this: + +```php +$configuration = new Configuration(); +$configuration->setFixRelativeURLs(true) + ->setOriginalURL('http://my.newspaper.url/article/something-interesting-to-read.html'); +``` + +Then you pass this Configuration object to Readability. The following options are available. Remember to prepend `set` when calling them. + +- **MaxTopCandidates**: default value `5`, max amount of top level candidates. +- **WordThreshold**: default value `500`, minimum amount of characters to consider that the article was parsed successful. +- **ArticleByLine**: default value `false`, search for the article byline and remove it from the text. It will be moved to the article metadata. +- **StripUnlikelyCandidates**: default value `true`, remove nodes that are unlikely to have relevant information. Useful for debugging or parsing complex or non-standard articles. +- **CleanConditionally**: default value `true`, remove certain nodes after parsing to return a cleaner result. +- **WeightClasses**: default value `true`, weight classes during the rating phase. +- **RemoveReadabilityTags**: default value `true`, remove the data-readability tags inside the nodes that are added during the rating phase. +- **FixRelativeURLs**: default value `false`, convert relative URLs to absolute. Like `/test` to `http://host/test`. +- **SubstituteEntities**: default value `false`, disables the `substituteEntities` flag of libxml. Will avoid substituting HTML entities. Like `á` to á. +- **NormalizeEntities**: default value `false`, converts UTF-8 characters to its HTML Entity equivalent. Useful to parse HTML with mixed encoding. +- **OriginalURL**: default value `http://fakehost`, original URL from the article used to fix relative URLs. +- **SummonCthulhu**: default value `false`, remove all `<script>` nodes via regex. This is not ideal as it might break things, but might be the only solution to [libxml problems with unescaped javascript](https://github.com/andreskrey/readability.php#known-issues). If you're not parsing Javascript tutorials, it's recommended to always set this option as `true`. ## Limitations -Of course the main limitation is PHP. Websites that load the content through lazy loading, AJAX, or any type of javascript fueled call will be ignored (actually, *not ran*) and the resulting text will be incorrect, compared to the readability.js results. All the articles you want to parse with readability.php will need to be complete and all the content should be in the HTML already. +Of course the main limitation is PHP. Websites that load the content through lazy loading, AJAX, or any type of javascript fueled call will be ignored (actually, *not ran*) and the resulting text will be incorrect, compared to the readability.js results. All the articles you want to parse with readability.php need to be complete and all the content should be in the HTML already. ## Known Issues @@ -76,7 +103,7 @@ DOMDocument has some issues while parsing javascript with unescaped HTML on stri </script> ``` -If you would like to remove the scripts of the HTML (like readability does), you would expect ending up with just one div and one comment on the final HTML. The problem is that libxml takes that closing div tag inside the javascript string as a HTML tag, effectively closing the unclosed tag and leaving the rest of the javascript as a string withing a P tag. If you save that node, the final HTML will end up like this: +If you would like to remove the scripts of the HTML (like readability does), you would expect ending up with just one div and one comment on the final HTML. The problem is that libxml takes that closing div tag inside the javascript string as a HTML tag, effectively closing the unclosed tag and leaving the rest of the javascript as a string within a P tag. If you save that node, the final HTML will end up like this: ```html <div> <!-- Offending div without closing tag --> @@ -99,12 +126,12 @@ Self closing tags like `<br />` get automatically expanded to `<br></br`. No way ## Dependencies -Readability uses the Element interface and class from *The PHP League's* **[html-to-markdown](https://github.com/thephpleague/html-to-markdown/)**. The Readability object is an extension of the Element class. It overrides some methods but relies on it for basic DOMElement parsing. +Readability.php has no dependencies to other libraries. ## To-do -- Right now the Readability object is an extension of the Element object of html-to-markdown. This is a problem because you lose context. The scoring when creating a new Readability object must be reloaded manually. The DOMDocument object is consistent across the same document. You change one value here and that will update all other nodes in other variables. By using the element interface you lose that reference and the score must be restored manually. Ideally, the Readability object should be an extension of the DOMDocument or DOMElement objects, the score should be saved within that object and no restoration or recalculation would be needed. -- There are a lot of problems with responsabilities. Right now there are two classes: HTMLParser and Readability. HTMLParser does a lot of things that should be a responsibility of Readability. It also does a lot of things that should be part of another class, specially when building the final article DOMDocument. +- Keep up with Readability.js changes +- Add a small template engine for the __toString() method, instead of using a hardcoded one. ## How it works @@ -114,12 +141,10 @@ Readability parses all the text with DOMDocument, scans the text nodes and gives Up to date with readability.js as of [16 Oct 2017](https://github.com/mozilla/readability/commit/c3ff1a2d2c94c1db257b2c9aa88a4b8fbeb221c5). -## TO-DOs of the current port: - - - Port `_cleanStyles` to avoid style attributes inside other tags (like `<p style="hello ">`) - ## License +Based on Arc90's readability.js (1.7.1) script available at: http://code.google.com/p/arc90labs-readability + Copyright (c) 2010 Arc90 Inc Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/composer.json b/composer.json index c7034e8..74ddac7 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,12 @@ } }, "require": { - "php": ">=5.4.0", + "php": ">=5.6.0", "ext-dom": "*", "ext-xml": "*", - "league/html-to-markdown": "^4.2" + "ext-mbstring": "*" }, "require-dev": { - "phpunit/phpunit": "4.*" + "phpunit/phpunit": "^5.7" } } diff --git a/phpunit.xml b/phpunit.xml index c31223d..291085a 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,4 +8,9 @@ <directory>./test/</directory> </testsuite> </testsuites> -</phpunit>
\ No newline at end of file + <filter> + <whitelist> + <directory suffix=".php">src/</directory> + </whitelist> + </filter> +</phpunit> diff --git a/src/Configuration.php b/src/Configuration.php index d2fa6a7..1a405de 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -2,59 +2,298 @@ namespace andreskrey\Readability; +/** + * Class Configuration. + */ class Configuration { - protected $config; + /** + * @var int + */ + protected $maxTopCandidates = 5; + /** + * @var int + */ + protected $wordThreshold = 500; + /** + * @var bool + */ + protected $articleByLine = false; + /** + * @var bool + */ + protected $stripUnlikelyCandidates = true; + /** + * @var bool + */ + protected $cleanConditionally = true; + /** + * @var bool + */ + protected $weightClasses = true; + /** + * @var bool + */ + protected $removeReadabilityTags = true; + /** + * @var bool + */ + protected $fixRelativeURLs = false; + /** + * @var bool + */ + protected $substituteEntities = false; + /** + * @var bool + */ + protected $normalizeEntities = false; + /** + * @var string + */ + protected $originalURL = 'http://fakehost'; + + /** + * @return int + */ + public function getMaxTopCandidates() + { + return $this->maxTopCandidates; + } /** - * @param array $config + * @param int $maxTopCandidates + * + * @return $this */ - public function __construct(array $config = []) + public function setMaxTopCandidates($maxTopCandidates) { - $this->config = $config; + $this->maxTopCandidates = $maxTopCandidates; + + return $this; } /** - * @param array $config + * @return int */ - public function merge(array $config = []) + public function getWordThreshold() { - $this->config = array_replace_recursive($this->config, $config); + return $this->wordThreshold; } /** - * @param array $config + * @param int $wordThreshold + * + * @return $this */ - public function replace(array $config = []) + public function setWordThreshold($wordThreshold) { - $this->config = $config; + $this->wordThreshold = $wordThreshold; + + return $this; } /** - * @param string $key - * @param mixed $value + * @return bool */ - public function setOption($key, $value) + public function getArticleByLine() { - $this->config[$key] = $value; + return $this->articleByLine; } /** - * @param string|null $key - * @param mixed|null $default + * @param bool $articleByLine * - * @return mixed|null + * @return $this */ - public function getOption($key = null, $default = null) + public function setArticleByLine($articleByLine) { - if ($key === null) { - return $this->config; - } + $this->articleByLine = $articleByLine; - if (!isset($this->config[$key])) { - return $default; - } + return $this; + } - return $this->config[$key]; + /** + * @return bool + */ + public function getStripUnlikelyCandidates() + { + return $this->stripUnlikelyCandidates; + } + + /** + * @param bool $stripUnlikelyCandidates + * + * @return $this + */ + public function setStripUnlikelyCandidates($stripUnlikelyCandidates) + { + $this->stripUnlikelyCandidates = $stripUnlikelyCandidates; + + return $this; + } + + /** + * @return bool + */ + public function getCleanConditionally() + { + return $this->cleanConditionally; + } + + /** + * @param bool $cleanConditionally + * + * @return $this + */ + public function setCleanConditionally($cleanConditionally) + { + $this->cleanConditionally = $cleanConditionally; + + return $this; + } + + /** + * @return bool + */ + public function getWeightClasses() + { + return $this->weightClasses; + } + + /** + * @param bool $weightClasses + * + * @return $this + */ + public function setWeightClasses($weightClasses) + { + $this->weightClasses = $weightClasses; + + return $this; + } + + /** + * @return bool + */ + public function getRemoveReadabilityTags() + { + return $this->removeReadabilityTags; } + + /** + * @param bool $removeReadabilityTags + * + * @return $this + */ + public function setRemoveReadabilityTags($removeReadabilityTags) + { + $this->removeReadabilityTags = $removeReadabilityTags; + + return $this; + } + + /** + * @return bool + */ + public function getFixRelativeURLs() + { + return $this->fixRelativeURLs; + } + + /** + * @param bool $fixRelativeURLs + * + * @return $this + */ + public function setFixRelativeURLs($fixRelativeURLs) + { + $this->fixRelativeURLs = $fixRelativeURLs; + + return $this; + } + + /** + * @return bool + */ + public function getSubstituteEntities() + { + return $this->substituteEntities; + } + + /** + * @param bool $substituteEntities + * + * @return $this + */ + public function setSubstituteEntities($substituteEntities) + { + $this->substituteEntities = $substituteEntities; + + return $this; + } + + /** + * @return bool + */ + public function getNormalizeEntities() + { + return $this->normalizeEntities; + } + + /** + * @param bool $normalizeEntities + * + * @return $this + */ + public function setNormalizeEntities($normalizeEntities) + { + $this->normalizeEntities = $normalizeEntities; + + return $this; + } + + /** + * @return string + */ + public function getOriginalURL() + { + return $this->originalURL; + } + + /** + * @param string $originalURL + * + * @return $this + */ + public function setOriginalURL($originalURL) + { + $this->originalURL = $originalURL; + + return $this; + } + + /** + * @return bool + */ + public function getSummonCthulhu() + { + return $this->summonCthulhu; + } + + /** + * @param bool $summonCthulhu + * + * @return $this + */ + public function setSummonCthulhu($summonCthulhu) + { + $this->summonCthulhu = $summonCthulhu; + + return $this; + } + + /** + * @var bool + */ + protected $summonCthulhu = false; } diff --git a/src/Environment.php b/src/Environment.php deleted file mode 100644 index 6e88783..0000000 --- a/src/Environment.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -namespace andreskrey\Readability; - -final class Environment -{ - /** - * @var Configuration - */ - protected $config; - - public function __construct(array $config = []) - { - $this->config = new Configuration($config); - } - - /** - * @return Configuration - */ - public function getConfig() - { - return $this->config; - } - - /** - * @param array $config - * - * @return Environment - */ - public static function createDefaultEnvironment(array $config = []) - { - $environment = new static($config); - - return $environment; - } -} diff --git a/src/HTMLParser.php b/src/HTMLParser.php deleted file mode 100644 index e4ed4bb..0000000 --- a/src/HTMLParser.php +++ /dev/null @@ -1,1598 +0,0 @@ -<?php - -namespace andreskrey\Readability; - -use DOMDocument; - -/** - * Class HTMLParser. - * - * A helper class to parse HTML and get a Readability object. - */ -class HTMLParser -{ - /** - * @var DOMDocument - */ - private $dom = null; - - /** - * TODO Make this an object? Instead of a dumb array. - * - * @var array - */ - private $metadata = []; - - /** - * @var array - */ - private $regexps = [ - 'unlikelyCandidates' => '/banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|modal|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i', - 'okMaybeItsACandidate' => '/and|article|body|column|main|shadow/i', - 'extraneous' => '/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i', - 'byline' => '/byline|author|dateline|writtenby|p-author/i', - 'replaceFonts' => '/<(\/?)font[^>]*>/gi', - 'normalize' => '/\s{2,}/', - 'videos' => '/\/\/(www\.)?(dailymotion|youtube|youtube-nocookie|player\.vimeo)\.com/i', - 'nextLink' => '/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i', - 'prevLink' => '/(prev|earl|old|new|<|«)/i', - 'whitespace' => '/^\s*$/', - 'hasContent' => '/\S$/', - // \x{00A0} is the unicode version of - 'onlyWhitespace' => '/\x{00A0}|\s+/u' - ]; - - private $defaultTagsToScore = [ - 'section', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'p', - 'td', - 'pre', - ]; - - /** - * @var array - */ - private $alterToDIVExceptions = [ - 'div', - 'article', - 'section', - 'p', - // TODO, check if this is correct, #text elements do not exist in js - '#text', - ]; - - /** - * @var array - */ - private $divToPElements = [ - 'a', - 'blockquote', - 'dl', - 'div', - 'img', - 'ol', - 'p', - 'pre', - 'table', - 'ul', - 'select', - ]; - - /** - * Constructor. - * - * @param array $options Options to override the default ones - */ - public function __construct(array $options = []) - { - $defaults = [ - 'maxTopCandidates' => 5, - 'wordThreshold' => 500, - 'articleByLine' => false, - 'stripUnlikelyCandidates' => true, - 'cleanConditionally' => true, - 'weightClasses' => true, - 'removeReadabilityTags' => true, - 'fixRelativeURLs' => false, - 'substituteEntities' => true, - 'normalizeEntities' => false, - 'summonCthulhu' => false, - 'originalURL' => 'http://fakehost', - ]; - - $this->environment = Environment::createDefaultEnvironment($defaults); - - $this->environment->getConfig()->merge($options); - - // To avoid having a gazillion of errors on malformed HTMLs - libxml_use_internal_errors(true); - } - - /** - * Parse the html. This is the main entry point of the HTMLParser. - * - * @param string $html Full html of the website, page, etc. - * - * #return ? TBD - */ - public function parse($html) - { - $this->dom = $this->loadHTML($html); - - $this->metadata = $this->getMetadata(); - - $this->metadata['image'] = $this->getMainImage(); - - // Checking for minimum HTML to work with. - if (!($root = $this->dom->getElementsByTagName('body')->item(0)) || !$root->firstChild) { - return false; - } - - $parseSuccessful = true; - while (true) { - $root = new Readability($root->firstChild); - - $elementsToScore = $this->getNodes($root); - - $result = $this->rateNodes($elementsToScore); - - /* - * Now that we've gone through the full algorithm, check to see if - * we got any meaningful content. If we didn't, we may need to re-run - * grabArticle with different flags set. This gives us a higher likelihood of - * finding the content, and the sieve approach gives us a higher likelihood of - * finding the -right- content. - */ - - // TODO Better way to count resulting text. Textcontent usually has alt titles and that stuff - // that doesn't really count to the quality of the result. - $length = 0; - foreach ($result->getElementsByTagName('p') as $p) { - $length += mb_strlen($p->textContent); - } - if ($result && mb_strlen(preg_replace('/\s/', '', $result->textContent)) < $this->getConfig()->getOption('wordThreshold')) { - $this->dom = $this->loadHTML($html); - $root = $this->dom->getElementsByTagName('body')->item(0); - - if ($this->getConfig()->getOption('stripUnlikelyCandidates')) { - $this->getConfig()->setOption('stripUnlikelyCandidates', false); - } elseif ($this->getConfig()->getOption('weightClasses')) { - $this->getConfig()->setOption('weightClasses', false); - } elseif ($this->getConfig()->getOption('cleanConditionally')) { - $this->getConfig()->setOption('cleanConditionally', false); - } else { - $parseSuccessful = false; - break; - } - } else { - break; - } - } - - if (!$parseSuccessful) { - return false; - } - - $result = $this->postProcessContent($result); - - // Todo, fix return, check for values, maybe create a function to create the return object - return [ - 'title' => isset($this->metadata['title']) ? $this->metadata['title'] : null, - 'author' => isset($this->metadata['author']) ? $this->metadata['author'] : null, - 'image' => isset($this->metadata['image']) ? $this->metadata['image'] : null, - 'images' => $this->getImages(), - 'article' => $result, - 'html' => $result->C14N(), - 'dir' => isset($this->metadata['articleDir']) ? $this->metadata['articleDir'] : null, - ]; - } - - /** - * Creates a DOM Document object and loads the provided HTML on it. - * - * Used for the first load of Readability and subsequent reloads (when disabling flags and rescanning the text) - * Previous versions of Readability used this method one time and cloned the DOM to keep a backup. This caused bugs - * because cloning the DOM object keeps a relation between the clone and the original one, doing changes in both - * objects and ruining the backup. - * - * @param string $html - * - * @return DOMDocument - */ - private function loadHTML($html) - { - $dom = new DOMDocument('1.0', 'utf-8'); - - if (!$this->getConfig()->getOption('substituteEntities')) { - // Keep the original HTML entities - $dom->substituteEntities = false; - } - - if ($this->getConfig()->getOption('normalizeEntities')) { - // Replace UTF-8 characters with the HTML Entity equivalent. Useful to fix html with mixed content - $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); - } - - if ($this->getConfig()->getOption('summonCthulhu')) { - $html = preg_replace('/<script\b[^>]*>([\s\S]*?)<\/script>/', '', $html); - } - - // Prepend the XML tag to avoid having issues with special characters. Should be harmless. - $dom->loadHTML('<?xml encoding="UTF-8">' . $html); - $dom->encoding = 'UTF-8'; - - $this->removeScripts($dom); - - $this->prepDocument($dom); - - return $dom; - } - - /** - * @return Configuration - */ - public function getConfig() - { - return $this->environment->getConfig(); - } - - /** - * Removes all the scripts of the html. - * - * @param DOMDocument $dom - */ - private function removeScripts(DOMDocument $dom) - { - $toRemove = ['script', 'noscript']; - - foreach ($toRemove as $tag) { - while ($script = $dom->getElementsByTagName($tag)) { - if ($script->item(0)) { - $script->item(0)->parentNode->removeChild($script->item(0)); - } else { - break; - } - } - } - } - - /** - * Prepares the document for parsing. - * - * @param DOMDocument $dom - */ - private function prepDocument(DOMDocument $dom) - { - /* - * DOMNodeList must be converted to an array before looping over it. - * This is done to avoid node shifting when removing nodes. - * - * Reverse traversing cannot be done here because we need to find brs that are right next to other brs. - * (If we go the other way around we need to search for previous nodes forcing the creation of new functions - * that will be used only here) - */ - foreach (iterator_to_array($dom->getElementsByTagName('br')) as $br) { - $next = $br->nextSibling; - - /* - * Whether 2 or more <br> elements have been found and replaced with a - * <p> block. - */ - $replaced = false; - - /* - * If we find a <br> chain, remove the <br>s until we hit another element - * or non-whitespace. This leaves behind the first <br> in the chain - * (which will be replaced with a <p> later). - */ - while (($next = $this->nextElement($next)) && ($next->nodeName === 'br')) { - $replaced = true; - $brSibling = $next->nextSibling; - $next->parentNode->removeChild($next); - $next = $brSibling; - } - - /* - * If we removed a <br> chain, replace the remaining <br> with a <p>. Add - * all sibling nodes as children of the <p> until we hit another <br> - * chain. - */ - - if ($replaced) { - $p = $dom->createElement('p'); - $br->parentNode->replaceChild($p, $br); - - $next = $p->nextSibling; - while ($next) { - // If we've hit another <br><br>, we're done adding children to this <p>. - if ($next->nodeName === 'br') { - $nextElem = $this->nextElement($next); - if ($nextElem && $nextElem->nodeName === 'br') { - break; - } - } - - // Otherwise, make this node a child of the new <p>. - $sibling = $next->nextSibling; - $p->appendChild($next); - $next = $sibling; - } - } - } - - // Replace font tags with span - $fonts = $dom->getElementsByTagName('font'); - $length = $fonts->length; - for ($i = 0; $i < $length; $i++) { - $font = $fonts->item($length - 1 - $i); - $span = new Readability($font); - $span->setNodeTag('span', true); - } - } - - public function postProcessContent(DOMDocument $article) - { - // Readability cannot open relative uris so we convert them to absolute uris. - if ($this->getConfig()->getOption('fixRelativeURLs')) { - foreach (iterator_to_array($article->getElementsByTagName('a')) as $link) { - /** @var \DOMElement $link */ - $href = $link->getAttribute('href'); - if ($href) { - // Replace links with javascript: URIs with text content, since - // they won't work after scripts have been removed from the page. - if (strpos($href, 'javascript:') === 0) { - $text = $article->createTextNode($link->textContent); - $link->parentNode->replaceChild($text, $link); - } else { - $link->setAttribute('href', $this->toAbsoluteURI($href)); - } - } - } - - foreach ($article->getElementsByTagName('img') as $img) { - /** @var \DOMElement $img */ - $src = $img->getAttribute('src'); - if ($src) { - $img->setAttribute('src', $this->toAbsoluteURI($src)); - } - } - } - - return $article; - } - - private function toAbsoluteURI($uri) - { - list($pathBase, $scheme, $prePath) = $this->getPathInfo($this->getConfig()->getOption('originalURL')); - - // If this is already an absolute URI, return it. - if (preg_match('/^[a-zA-Z][a-zA-Z0-9\+\-\.]*:/', $uri)) { - return $uri; - } - - // Scheme-rooted relative URI. - if (substr($uri, 0, 2) === '//') { - return $scheme . '://' . substr($uri, 2); - } - - // Prepath-rooted relative URI. - if (substr($uri, 0, 1) === '/') { - return $prePath . $uri; - } - - // Dotslash relative URI. - if (strpos($uri, './') === 0) { - return $pathBase . substr($uri, 2); - } - // Ignore hash URIs: - if (substr($uri, 0, 1) === '#') { - return $uri; - } - - // Standard relative URI; add entire path. pathBase already includes a - // trailing "/". - return $pathBase . $uri; - } - - /** - * @param string $url - * - * @return array [$pathBase, $scheme, $prePath] - */ - public function getPathInfo($url) - { - $pathBase = parse_url($url, PHP_URL_SCHEME) . '://' . parse_url($url, PHP_URL_HOST) . dirname(parse_url($url, PHP_URL_PATH)) . '/'; - $scheme = parse_url($pathBase, PHP_URL_SCHEME); - $prePath = $scheme . '://' . parse_url($pathBase, PHP_URL_HOST); - - return [$pathBase, $scheme, $prePath]; - } - - private function nextElement($node) - { - $next = $node; - while ($next - && $next->nodeName !== '#text' - && trim($next->textContent)) { - $next = $next->nextSibling; - } - - return $next; - } - - /** - * Tries to guess relevant info from metadata of the html. - * - * @return array Metadata info. May have title, excerpt and or byline. - */ - private function getMetadata() - { - $metadata = $values = []; - // Match "description", or Twitter's "twitter:description" (Cards) - // in name attribute. - $namePattern = '/^\s*((twitter)\s*:\s*)?(description|title|image)\s*$/i'; - - // Match Facebook's Open Graph title & description properties. - $propertyPattern = '/^\s*og\s*:\s*(description|title|image)\s*$/i'; - - foreach ($this->dom->getElementsByTagName('meta') as $meta) { - /* @var Readability $meta */ - $elementName = $meta->getAttribute('name'); - $elementProperty = $meta->getAttribute('property'); - - if (in_array('author', [$elementName, $elementProperty])) { - $metadata['byline'] = $meta->getAttribute('content'); - continue; - } - - $name = null; - if (preg_match($namePattern, $elementName)) { - $name = $elementName; - } elseif (preg_match($propertyPattern, $elementProperty)) { - $name = $elementProperty; - } - - if ($name) { - $content = $meta->getAttribute('content'); - if ($content) { - // Convert to lowercase and remove any whitespace - // so we can match below. - $name = preg_replace('/\s/', '', strtolower($name)); - $values[$name] = trim($content); - } - } - } - if (array_key_exists('description', $values)) { - $metadata['excerpt'] = $values['description']; - } elseif (array_key_exists('og:description', $values)) { - // Use facebook open graph description. - $metadata['excerpt'] = $values['og:description']; - } elseif (array_key_exists('twitter:description', $values)) { - // Use twitter cards description. - $metadata['excerpt'] = $values['twitter:description']; - } - - $metadata['title'] = $this->getTitle(); - - if (!$metadata['title']) { - if (array_key_exists('og:title', $values)) { - // Use facebook open graph title. - $metadata['title'] = $values['og:title']; - } elseif (array_key_exists('twitter:title', $values)) { - // Use twitter cards title. - $metadata['title'] = $values['twitter:title']; - } - } - - if (array_key_exists('og:image', $values) || array_key_exists('twitter:image', $values)) { - $metadata['image'] = array_key_exists('og:image', $values) ? $values['og:image'] : $values['twitter:image']; - } else { - $metadata['image'] = null; - } - - return $metadata; - } - - /** - * Tries to get the main article image. Will only update the metadata if the getMetadata function couldn't - * find a correct image. - * - * @return bool|string URL of the top image or false if unsuccessful. - */ - public function getMainImage() - { - $imgUrl = false; - - if ($this->metadata['image'] !== null) { - $imgUrl = $this->metadata['image']; - } - - if (!$imgUrl) { - foreach ($this->dom->getElementsByTagName('link') as $link) { - /** @var \DOMElement $link */ - /* - * Check for the rel attribute, then check if the rel attribute is either img_src or image_src, and - * finally check for the existence of the href attribute, which should hold the image url. - */ - if ($link->hasAttribute('rel') && ($link->getAttribute('rel') === 'img_src' || $link->getAttribute('rel') === 'image_src') && $link->hasAttribute('href')) { - $imgUrl = $link->getAttribute('href'); - break; - } - } - } - - if (!empty($imgUrl) && $this->getConfig()->getOption('fixRelativeURLs')) { - $imgUrl = $this->toAbsoluteURI($imgUrl); - } - - return $imgUrl; - } - - /** - * @return array - */ - public function getImages() - { - $result = []; - if (!empty($this->metadata['image'])) { - $result[] = $this->metadata['image']; - } - if (null == $this->dom) { - return $result; - } - - foreach ($this->dom->getElementsByTagName('img') as $img) { - if ($src = $img->getAttribute('src')) { - $result[] = $src; - } - } - - if ($this->getConfig()->getOption('fixRelativeURLs')) { - foreach ($result as &$imgSrc) { - $imgSrc = $this->toAbsoluteURI($imgSrc); - } - } - - $result = array_unique(array_filter($result)); - - return $result; - } - - /** - * Get the density of links as a percentage of the content - * This is the amount of text that is inside a link divided by the total text in the node. - * - * @param Readability $readability - * - * @return int - */ - public function getLinkDensity($readability) - { - $linkLength = 0; - $textLength = mb_strlen($readability->getTextContent(true)); - - if (!$textLength) { - return 0; - } - - $links = $readability->getAllLinks(); - - if ($links) { - /** @var Readability $link */ - foreach ($links as $link) { - $linkLength += mb_strlen($link->getTextContent(true)); - } - } - - return $linkLength / $textLength; - } - - /** - * Returns the title of the html. Prioritizes the title from the metadata against the title tag. - * - * @return string|null - */ - private function getTitle() - { - $originalTitle = null; - - if (isset($this->metadata['title'])) { - $originalTitle = $this->metadata['title']; - } else { - $titleTag = $this->dom->getElementsByTagName('title'); - if ($titleTag->length > 0) { - $originalTitle = $titleTag->item(0)->nodeValue; - } - } - - if ($originalTitle === null) { - return null; - } - - $curTitle = $originalTitle; - $titleHadHierarchicalSeparators = false; - - /* - * If there's a separator in the title, first remove the final part - * - * Sanity warning: if you eval this match in PHPStorm's "Evaluate expression" box, it will return false - * I can assure you it works properly if you let the code run. - */ - if (preg_match('/ [\|\-\\\\\/>»] /i', $curTitle)) { - $titleHadHierarchicalSeparators = (bool)preg_match('/ [\\\\\/>»] /', $curTitle); - $curTitle = preg_replace('/(.*)[\|\-\\\\\/>»] .*/i', '$1', $originalTitle); - - // If the resulting title is too short (3 words or fewer), remove - // the first part instead: - if (count(preg_split('/\s+/', $curTitle)) < 3) { - $curTitle = preg_replace('/[^\|\-\\\\\/>»]*[\|\-\\\\\/>»](.*)/i', '$1', $originalTitle); - } - } elseif (strpos($curTitle, ': ') !== false) { - // Check if we have an heading containing this exact string, so we - // could assume it's the full title. - $match = false; - for ($i = 1; $i <= 2; $i++) { - foreach ($this->dom->getElementsByTagName('h' . $i) as $hTag) { - // Trim texts to avoid having false negatives when the title is surrounded by spaces or tabs - if (trim($hTag->nodeValue) === trim($curTitle)) { - $match = true; - } - } - } - - // If we don't, let's extract the title out of the original title string. - if (!$match) { - $curTitle = substr($originalTitle, strrpos($originalTitle, ':') + 1); - - // If the title is now too short, try the first colon instead: - if (count(preg_split('/\s+/', $curTitle)) < 3) { - $curTitle = substr($originalTitle, strpos($originalTitle, ':') + 1); - } - } - } elseif (mb_strlen($curTitle) > 150 || mb_strlen($curTitle) < 15) { - $hOnes = $this->dom->getElementsByTagName('h1'); - - if ($hOnes->length === 1) { - $curTitle = $hOnes->item(0)->nodeValue; - } - } - - $curTitle = trim($curTitle); - - /* - * If we now have 4 words or fewer as our title, and either no - * 'hierarchical' separators (\, /, > or ») were found in the original - * title or we decreased the number of words by more than 1 word, use - * the original title. - */ - $curTitleWordCount = count(preg_split('/\s+/', $curTitle)); - $originalTitleWordCount = count(preg_split('/\s+/', preg_replace('/[\|\-\\\\\/>»]+/', '', $originalTitle))) - 1; - - if ($curTitleWordCount <= 4 && - (!$titleHadHierarchicalSeparators || $curTitleWordCount !== $originalTitleWordCount)) { - $curTitle = $originalTitle; - } - - return $curTitle; - } - - /** - * Gets nodes from the root element. - * - * @param $node Readability - * - * @return array - */ - private function getNodes(Readability $node) - { - $stripUnlikelyCandidates = $this->getConfig()->getOption('stripUnlikelyCandidates'); - - $elementsToScore = []; - - /* - * First, node prepping. Trash nodes that look cruddy (like ones with the - * class name "comment", etc), and turn divs into P tags where they have been - * used inappropriately (as in, where they contain no other block level elements.) - */ - - while ($node) { - $matchString = $node->getAttribute('class') . ' ' . $node->getAttribute('id'); - - // Remove DOMComments nodes as we don't need them and mess up children counting - if ($node->nodeTypeEqualsTo(XML_COMMENT_NODE)) { - $node = $node->removeAndGetNext($node); - continue; - } - - // Check to see if this node is a byline, and remove it if it is. - if ($this->checkByline($node, $matchString)) { - $node = $node->removeAndGetNext($node); - continue; - } - - // Remove unlikely candidates - if ($stripUnlikelyCandidates) { - if ( - preg_match($this->regexps['unlikelyCandidates'], $matchString) && - !preg_match($this->regexps['okMaybeItsACandidate'], $matchString) && - !$node->tagNameEqualsTo('body') && - !$node->tagNameEqualsTo('a') - ) { - $node = $node->removeAndGetNext($node); - continue; - } - } - - // Remove DIV, SECTION, and HEADER nodes without any content(e.g. text, image, video, or iframe). - if (($node->tagNameEqualsTo('div') || $node->tagNameEqualsTo('section') || $node->tagNameEqualsTo('header') || - $node->tagNameEqualsTo('h1') || $node->tagNameEqualsTo('h2') || $node->tagNameEqualsTo('h3') || - $node->tagNameEqualsTo('h4') || $node->tagNameEqualsTo('h5') || $node->tagNameEqualsTo('h6') || - $node->tagNameEqualsTo('p')) && - $node->isElementWithoutContent()) { - $node = $node->removeAndGetNext($node); - continue; - } - - if (in_array(strtolower($node->getTagName()), $this->defaultTagsToScore)) { - $elementsToScore[] = $node; - } - - // Turn all divs that don't have children block level elements into p's - if ($node->tagNameEqualsTo('div')) { - /* - * Sites like http://mobile.slate.com encloses each paragraph with a DIV - * element. DIVs with only a P element inside and no text content can be - * safely converted into plain P elements to avoid confusing the scoring - * algorithm with DIVs with are, in practice, paragraphs. - */ - if ($this->hasSinglePNode($node)) { - $pNode = $node->getChildren(true)[0]; - $node->replaceChild($pNode); - $node = $pNode; - $elementsToScore[] = $node; - } elseif (!$this->hasSingleChildBlockElement($node)) { - $node->setNodeTag('p'); - $elementsToScore[] = $node; - } else { - // EXPERIMENTAL - foreach ($node->getChildren() as $child) { - /** @var Readability $child */ - if ($child->isText() && mb_strlen(trim($child->getTextContent())) > 0) { - $newNode = $node->createNode($child, 'p'); - $child->replaceChild($newNode); - } - } - } - } - - $node = $node->getNextNode($node); - } - - return $elementsToScore; - } - - /** - * Assign scores to each node. This function will rate each node and return a Readability object for each one. - * - * @param array $nodes - * - * @return DOMDocument|bool - */ - private function rateNodes($nodes) - { - $candidates = []; - - /** @var Readability $node */ - foreach ($nodes as $node) { - if (!$node->getParent()) { - continue; - } - // Discard nodes with less than 25 characters, without blank space - if (mb_strlen($node->getTextContent(true)) < 25) { - continue; - } - - $ancestors = $node->getNodeAncestors(); - - // Exclude nodes with no ancestor - if (count($ancestors) === 0) { - continue; - } - - // Start with a point for the paragraph itself as a base. - $contentScore = 1; - - // Add points for any commas within this paragraph. - $contentScore += count(explode(',', $node->getTextContent(true))); - - // For every 100 characters in this paragraph, add another point. Up to 3 points. - $contentScore += min(floor(mb_strlen($node->getTextContent(true)) / 100), 3); - - // Initialize and score ancestors. - /** @var Readability $ancestor */ - foreach ($ancestors as $level => $ancestor) { - if (!$ancestor->isInitialized()) { - $ancestor->initializeNode(); - $candidates[] = $ancestor; - } - - /* - * Node score divider: - * - parent: 1 (no division) - * - grandparent: 2 - * - great grandparent+: ancestor level * 3 - */ - - if ($level === 0) { - $scoreDivider = 1; - } elseif ($level === 1) { - $scoreDivider = 2; - } else { - $scoreDivider = $level * 3; - } - - $currentScore = $ancestor->getContentScore(); - $ancestor->setContentScore($currentScore + ($contentScore / $scoreDivider)); - } - } - - /* - * TODO This is an horrible hack because I don't know how to properly pass by reference. - * When candidates are added to the $candidates array, they lose the reference to the original object - * and on each loop, the object inside $candidates doesn't get updated. This function restores the score - * by getting it of the data-readability tag. This should be fixed using proper references and good coding - * practices (which I lack) - */ - - foreach ($candidates as $candidate) { - $candidate->reloadScore(); - } - - /* - * After we've calculated scores, loop through all of the possible - * candidate nodes we found and find the one with the highest score. - */ - - $topCandidates = []; - foreach ($candidates as $candidate) { - - /* - * Scale the final candidates score based on link density. Good content - * should have a relatively small link density (5% or less) and be mostly - * unaffected by this operation. - */ - - $candidate->setContentScore($candidate->getContentScore() * (1 - $this->getLinkDensity($candidate))); - - for ($i = 0; $i < $this->getConfig()->getOption('maxTopCandidates'); $i++) { - $aTopCandidate = isset($topCandidates[$i]) ? $topCandidates[$i] : null; - - if (!$aTopCandidate || $candidate->getContentScore() > $aTopCandidate->getContentScore()) { - array_splice($topCandidates, $i, 0, [$candidate]); - if (count($topCandidates) > $this->getConfig()->getOption('maxTopCandidates')) { - array_pop($topCandidates); - } - break; - } - } - } - - $topCandidate = isset($topCandidates[0]) ? $topCandidates[0] : null; - $neededToCreateTopCandidate = false; - $parentOfTopCandidate = null; - - /* - * If we still have no top candidate, just use the body as a last resort. - * We also have to copy the body node so it is something we can modify. - */ - - if ($topCandidate === null || $topCandidate->tagNameEqualsTo('body')) { - // Move all of the page's children into topCandidate - $topCandidate = new DOMDocument('1.0', 'utf-8'); - $topCandidate->encoding = 'UTF-8'; - $topCandidate->appendChild($topCandidate->createElement('div', '')); - $kids = $this->dom->getElementsByTagName('body')->item(0)->childNodes; - - // Cannot be foreached, don't ask me why. - for ($i = 0; $i < $kids->length; $i++) { - $import = $topCandidate->importNode($kids->item($i), true); - $topCandidate->firstChild->appendChild($import); - } - - // Readability must be created using firstChild to grab the DOMElement instead of the DOMDocument. - $topCandidate = new Readability($topCandidate->firstChild); - $topCandidate->initializeNode(); - - //TODO on the original code, $topCandidate is added to the page variable, which holds the whole HTML - // Should be done this here also? (line 823 in readability.js) - } elseif ($topCandidate) { - // Find a better top candidate node if it contains (at least three) nodes which belong to `topCandidates` array - // and whose scores are quite closed with current `topCandidate` node. - $alternativeCandidateAncestors = []; - for ($i = 1; $i < count($topCandidates); $i++) { - if ($topCandidates[$i]->getContentScore() / $topCandidate->getContentScore() >= 0.75) { - array_push($alternativeCandidateAncestors, $topCandidates[$i]->getNodeAncestors(false)); - } - } - - $MINIMUM_TOPCANDIDATES = 3; - if (count($alternativeCandidateAncestors) >= $MINIMUM_TOPCANDIDATES) { - $parentOfTopCandidate = $topCandidate->getParent(); - while (!$parentOfTopCandidate->tagNameEqualsTo('body')) { - $listsContainingThisAncestor = 0; - for ($ancestorIndex = 0; $ancestorIndex < count($alternativeCandidateAncestors) && $listsContainingThisAncestor < $MINIMUM_TOPCANDIDATES; $ancestorIndex++) { - $listsContainingThisAncestor += (int)in_array($parentOfTopCandidate, $alternativeCandidateAncestors[$ancestorIndex]); - } - if ($listsContainingThisAncestor >= $MINIMUM_TOPCANDIDATES) { - $topCandidate = $parentOfTopCandidate; - break; - } - $parentOfTopCandidate = $parentOfTopCandidate->getParent(); - } - } - - /* - * Because of our bonus system, parents of candidates might have scores - * themselves. They get half of the node. There won't be nodes with higher - * scores than our topCandidate, but if we see the score going *up* in the first - * few steps up the tree, that's a decent sign that there might be more content - * lurking in other places that we want to unify in. The sibling stuff - * below does some of that - but only if we've looked high enough up the DOM - * tree. - */ - - $parentOfTopCandidate = $topCandidate->getParent(); - $lastScore = $topCandidate->getContentScore(); - - // The scores shouldn't get too low. - $scoreThreshold = $lastScore / 3; - - /* @var Readability $parentOfTopCandidate */ - while (!$parentOfTopCandidate->tagNameEqualsTo('body')) { - $parentScore = $parentOfTopCandidate->getContentScore(); - if ($parentScore < $scoreThreshold) { - break; - } - - if ($parentScore > $lastScore) { - // Alright! We found a better parent to use. - $topCandidate = $parentOfTopCandidate; - break; - } - $lastScore = $parentOfTopCandidate->getContentScore(); - $parentOfTopCandidate = $parentOfTopCandidate->getParent(); - } - - // If the top candidate is the only child, use parent instead. This will help sibling - // joining logic when adjacent content is actually located in parent's sibling node. - $parentOfTopCandidate = $topCandidate->getParent(); - while (!$parentOfTopCandidate->tagNameEqualsTo('body') && count($parentOfTopCandidate->getChildren(true)) === 1) { - $topCandidate = $parentOfTopCandidate; - $parentOfTopCandidate = $topCandidate->getParent(); - } - } - - /* - * Now that we have the top candidate, look through its siblings for content - * that might also be related. Things like preambles, content split by ads - * that we removed, etc. - */ - - $articleContent = new DOMDocument('1.0', 'utf-8'); - $articleContent->createElement('div'); - - $siblingScoreThreshold = max(10, $topCandidate->getContentScore() * 0.2); - // Keep potential top candidate's parent node to try to get text direction of it later. - $parentOfTopCandidate = $topCandidate->getParent(); - $siblings = $parentOfTopCandidate->getChildren(); - - $hasContent = false; - - /** @var Readability $sibling */ - foreach ($siblings as $sibling) { - $append = false; - - if ($sibling->compareNodes($sibling, $topCandidate)) { - $append = true; - } else { - $contentBonus = 0; - - // Give a bonus if sibling nodes and top candidates have the example same classname - if ($sibling->getAttribute('class') === $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') !== '') { - $contentBonus += $topCandidate->getContentScore() * 0.2; - } - if ($sibling->getContentScore() + $contentBonus >= $siblingScoreThreshold) { - $append = true; - } elseif ($sibling->tagNameEqualsTo('p')) { - $linkDensity = $this->getLinkDensity($sibling); - $nodeContent = $sibling->getTextContent(true); - - if (mb_strlen($nodeContent) > 80 && $linkDensity < 0.25) { - $append = true; - } elseif ($nodeContent && mb_strlen($nodeContent) < 80 && $linkDensity === 0 && preg_match('/\.( |$)/', $nodeContent)) { - $append = true; - } - } - } - - if ($append) { - $hasContent = true; - - if (!in_array(strtolower($sibling->getTagName()), $this->alterToDIVExceptions)) { - /* - * We have a node that isn't a common block level element, like a form or td tag. - * Turn it into a div so it doesn't get filtered out later by accident. - */ - - $sibling->setNodeTag('div'); - } - - $import = $articleContent->importNode($sibling->getDOMNode(), true); - $articleContent->appendChild($import); - - /* - * No node shifting needs to be check because when calling getChildren, an array is made with the - * children of the parent node, instead of using the DOMElement childNodes function, which, when used - * along with appendChild, would shift the nodes position and the current foreach will behave in - * unpredictable ways. - */ - } - } - - $articleContent = $this->prepArticle($articleContent); - - if ($hasContent) { - // Find out text direction from ancestors of final top candidate. - $ancestors = array_merge([$parentOfTopCandidate, $topCandidate], $parentOfTopCandidate->getNodeAncestors()); - foreach ($ancestors as $ancestor) { - $articleDir = $ancestor->getAttribute('dir'); - if ($articleDir) { - $this->metadata['articleDir'] = $articleDir; - break; - } - } - - return $articleContent; - } else { - return false; - } - } - - /** - * TODO To be moved to Readability. - * - * @param DOMDocument $article - * - * @return DOMDocument - */ - public function prepArticle(DOMDocument $article) - { - $this->_cleanStyles($article); - $this->_clean($article, 'style'); - - // Check for data tables before we continue, to avoid removing items in - // those tables, which will often be isolated even though they're - // visually linked to other content-ful elements (text, images, etc.). - $this->_markDataTables($article); - - // Clean out junk from the article content - $this->_cleanConditionally($article, 'form'); - $this->_cleanConditionally($article, 'fieldset'); - $this->_clean($article, 'object'); - $this->_clean($article, 'embed'); - $this->_clean($article, 'h1'); - $this->_clean($article, 'footer'); - - // Clean out elements have "share" in their id/class combinations from final top candidates, - // which means we don't remove the top candidates even they have "share". - foreach ($article->childNodes as $child) { - $this->_cleanMatchedNodes($child, '/share/i'); - } - - /* - * If there is only one h2 and its text content substantially equals article title, - * they are probably using it as a header and not a subheader, - * so remove it since we already extract the title separately. - */ - $h2 = $article->getElementsByTagName('h2'); - if ($h2->length === 1) { - $lengthSimilarRate = (mb_strlen($h2->item(0)->textContent) - mb_strlen($this->metadata['title'])) / max(mb_strlen($this->metadata['title']), 1); - - if (abs($lengthSimilarRate) < 0.5) { - if ($lengthSimilarRate > 0) { - $titlesMatch = strpos($h2->item(0)->textContent, $this->metadata['title']) !== false; - } else { - $titlesMatch = strpos($this->metadata['title'], $h2->item(0)->textContent) !== false; - } - if ($titlesMatch) { - $this->_clean($article, 'h2'); - } - } - } - - $this->_clean($article, 'iframe'); - $this->_clean($article, 'input'); - $this->_clean($article, 'textarea'); - $this->_clean($article, 'select'); - $this->_clean($article, 'button'); - $this->_cleanHeaders($article); - - // Do these last as the previous stuff may have removed junk - // that will affect these - $this->_cleanConditionally($article, 'table'); - $this->_cleanConditionally($article, 'ul'); - $this->_cleanConditionally($article, 'div'); - - $this->_cleanExtraParagraphs($article); - - $this->_cleanReadabilityTags($article); - - foreach (iterator_to_array($article->getElementsByTagName('br')) as $br) { - $next = $br->nextSibling; - if ($next && $next->nodeName === 'p') { - $br->parentNode->removeChild($br); - } - } - - return $article; - } - - /** - * Look for 'data' (as opposed to 'layout') tables, for which we use - * similar checks as - * https://dxr.mozilla.org/mozilla-central/rev/71224049c0b52ab190564d3ea0eab089a159a4cf/accessible/html/HTMLTableAccessible.cpp#920. - * - * TODO To be moved to Readability. WARNING: check if we actually keep the "readabilityDataTable" param and - * maybe switch to a readability data-tag? - * - * @param DOMDocument $article - * - * @return void - */ - public function _markDataTables(DOMDocument $article) - { - $tables = $article->getElementsByTagName('table'); - foreach ($tables as $table) { - /** @var \DOMElement $table */ - $role = $table->getAttribute('role'); - if ($role === 'presentation') { - $table->readabilityDataTable = false; - continue; - } - $datatable = $table->getAttribute('datatable'); - if ($datatable == '0') { - $table->readabilityDataTable = false; - continue; - } - $summary = $table->getAttribute('summary'); - if ($summary) { - $table->readabilityDataTable = true; - continue; - } - - $caption = $table->getElementsByTagName('caption'); - if ($caption->length > 0 && $caption->item(0)->childNodes->length > 0) { - $table->readabilityDataTable = true; - continue; - } - - // If the table has a descendant with any of these tags, consider a data table: - foreach (['col', 'colgroup', 'tfoot', 'thead', 'th'] as $dataTableDescendants) { - if ($table->getElementsByTagName($dataTableDescendants)->length > 0) { - $table->readabilityDataTable = true; - continue 2; - } - } - - // Nested tables indicate a layout table: - if ($table->getElementsByTagName('table')->length > 0) { - $table->readabilityDataTable = false; - continue; - } - - $sizeInfo = $this->_getRowAndColumnCount($table); - if ($sizeInfo['rows'] >= 10 || $sizeInfo['columns'] > 4) { - $table->readabilityDataTable = true; - continue; - } - // Now just go by size entirely: - $table->readabilityDataTable = $sizeInfo['rows'] * $sizeInfo['columns'] > 10; - } - } - - /** - * Return an array indicating how many rows and columns this table has. - * - * @param \DOMElement $table - * - * @return array - */ - public function _getRowAndColumnCount(\DOMElement $table) - { - $rows = $columns = 0; - $trs = $table->getElementsByTagName('tr'); - foreach ($trs as $tr) { - /** @var \DOMElement $tr */ - $rowspan = $tr->getAttribute('rowspan'); - $rows += ($rowspan || 1); - - // Now look for column-related info - $columnsInThisRow = 0; - $cells = $tr->getElementsByTagName('td'); - foreach ($cells as $cell) { - /** @var \DOMElement $cell */ - $colspan = $cell->getAttribute('colspan'); - $columnsInThisRow += ($colspan || 1); - } - $columns = max($columns, $columnsInThisRow); - } - - return ['rows' => $rows, 'columns' => $columns]; - } - - /** - * TODO To be moved to Readability. - * - * @param DOMDocument $article - * - * @return void - */ - public function _cleanReadabilityTags(DOMDocument $article) - { - if ($this->getConfig()->getOption('removeReadabilityTags')) { - foreach ($article->getElementsByTagName('*') as $tag) { - if ($tag->hasAttribute('data-readability')) { - $tag->removeAttribute('data-readability'); - } - } - } - } - - /** - * Remove the style attribute on every e and under. - * TODO: To be moved to Readability. - * - * @param $node \DOMDocument|\DOMNode - **/ - public function _cleanStyles($node) - { - if (property_exists($node, 'tagName') && $node->tagName === 'svg') { - return; - } - - // Do not bother if there's no method to remove an attribute - if (method_exists($node, 'removeAttribute')) { - $presentational_attributes = ['align', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'frame', 'hspace', 'rules', 'style', 'valign', 'vspace']; - // Remove `style` and deprecated presentational attributes - foreach ($presentational_attributes as $presentational_attribute) { - $node->removeAttribute($presentational_attribute); - } - - $deprecated_size_attribute_elems = ['table', 'th', 'td', 'hr', 'pre']; - if (property_exists($node, 'tagName') && in_array($node->tagName, $deprecated_size_attribute_elems)) { - $node->removeAttribute('width'); - $node->removeAttribute('height'); - } - } - - $cur = $node->firstChild; - while ($cur !== null) { - $this->_cleanStyles($cur); - $cur = $cur->nextSibling; - } - } - - /** - * Clean out elements whose id/class combinations match specific string. - * - * TODO To be moved to readability - * - * @param string $regex Match id/class combination. - * - * @return void - **/ - public function _cleanMatchedNodes($node, $regex) - { - $node = new Readability($node); - $endOfSearchMarkerNode = $node->getNextNode($node, true); - $next = $node->getNextNode($node); - while ($next && $next !== $endOfSearchMarkerNode) { - if (preg_match($regex, sprintf('%s %s', $next->getAttribute('class'), $next->getAttribute('id')))) { - $next = $next->removeAndGetNext($next); - } else { - $next = $next->getNextNode($next); - } - } - } - - /** - * TODO To be moved to Readability. - * - * @param DOMDocument $article - * - * @return void - */ - public function _cleanExtraParagraphs(DOMDocument $article) - { - $paragraphs = $article->getElementsByTagName('p'); - $length = $paragraphs->length; - - for ($i = 0; $i < $length; $i++) { - $paragraph = $paragraphs->item($length - 1 - $i); - - $imgCount = $paragraph->getElementsByTagName('img')->length; - $embedCount = $paragraph->getElementsByTagName('embed')->length; - $objectCount = $paragraph->getElementsByTagName('object')->length; - // At this point, nasty iframes have been removed, only remain embedded video ones. - $iframeCount = $paragraph->getElementsByTagName('iframe')->length; - $totalCount = $imgCount + $embedCount + $objectCount + $iframeCount; - - if ($totalCount === 0 && !preg_replace($this->regexps['onlyWhitespace'], '', $paragraph->textContent)) { - // TODO must be done via readability - $paragraph->parentNode->removeChild($paragraph); - } - } - } - - /** - * TODO To be moved to Readability. - * - * @param DOMDocument $article - * - * @return void - */ - public function _cleanConditionally(DOMDocument $article, $tag) - { - if (!$this->getConfig()->getOption('cleanConditionally')) { - return; - } - - $isList = in_array($tag, ['ul', 'ol']); - - /* - * Gather counts for other typical elements embedded within. - * Traverse backwards so we can remove nodes at the same time - * without effecting the traversal. - */ - - $DOMNodeList = $article->getElementsByTagName($tag); - $length = $DOMNodeList->length; - for ($i = 0; $i < $length; $i++) { - $node = $DOMNodeList->item($length - 1 - $i); - - $node = new Readability($node); - - // First check if we're in a data table, in which case don't remove us. - if ($node->hasAncestorTag($node, 'table', -1) && isset($node->readabilityDataTable)) { - continue; - } - - $weight = $node->getClassWeight(); - - if ($weight < 0) { - $this->removeNode($node->getDOMNode()); - continue; - } - - if (substr_count($node->getTextContent(), ',') < 10) { - /* - * If there are not very many commas, and the number of - * non-paragraph elements is more than paragraphs or other - * ominous signs, remove the element. - */ - - // TODO Horrible hack, must be removed once this function is inside Readability - $p = $node->getDOMNode()->getElementsByTagName('p')->length; - $img = $node->getDOMNode()->getElementsByTagName('img')->length; - $li = $node->getDOMNode()->getElementsByTagName('li')->length - 100; - $input = $node->getDOMNode()->getElementsByTagName('input')->length; - - $embedCount = 0; - $embeds = $node->getDOMNode()->getElementsByTagName('embed'); - - foreach ($embeds as $embedNode) { - if (preg_match($this->regexps['videos'], $embedNode->C14N())) { - $embedCount++; - } - } - - $linkDensity = $this->getLinkDensity($node); - $contentLength = mb_strlen($node->getTextContent(true)); - - $haveToRemove = - ($img > 1 && $p / $img < 0.5 && !$node->hasAncestorTag($node, 'figure')) || - (!$isList && $li > $p) || - ($input > floor($p / 3)) || - (!$isList && $contentLength < 25 && ($img === 0 || $img > 2) && !$node->hasAncestorTag($node, 'figure')) || - (!$isList && $weight < 25 && $linkDensity > 0.2) || - ($weight >= 25 && $linkDensity > 0.5) || - (($embedCount === 1 && $contentLength < 75) || $embedCount > 1); - - if ($haveToRemove) { - $this->removeNode($node->getDOMNode()); - } - } - } - } - - /** - * Clean a node of all elements of type "tag". - * (Unless it's a youtube/vimeo video. People love movies.). - * - * TODO To be moved to Readability - * - * @param $article DOMDocument - * @param $tag string tag to clean - * - * @return void - **/ - public function _clean(DOMDocument $article, $tag) - { - $isEmbed = in_array($tag, ['object', 'embed', 'iframe']); - - $DOMNodeList = $article->getElementsByTagName($tag); - $length = $DOMNodeList->length; - for ($i = 0; $i < $length; $i++) { - $item = $DOMNodeList->item($length - 1 - $i); - - // Allow youtube and vimeo videos through as people usually want to see those. - if ($isEmbed) { - $attributeValues = []; - foreach ($item->attributes as $name => $value) { - $attributeValues[] = $value->nodeValue; - } - $attributeValues = implode('|', $attributeValues); - - // First, check the elements attributes to see if any of them contain youtube or vimeo - if (preg_match($this->regexps['videos'], $attributeValues)) { - continue; - } - - // Then check the elements inside this element for the same. - if (preg_match($this->regexps['videos'], $item->C14N())) { - continue; - } - } - $this->removeNode($item); - } - } - - /** - * Clean out spurious headers from an Element. Checks things like classnames and link density. - * - * TODO To be moved to Readability - * - * @param DOMDocument $article - * - * @return void - **/ - public function _cleanHeaders(DOMDocument $article) - { - for ($headerIndex = 1; $headerIndex < 3; $headerIndex++) { - $headers = $article->getElementsByTagName('h' . $headerIndex); - foreach ($headers as $header) { - $header = new Readability($header); - if ($header->getClassWeight() < 0) { - $this->removeNode($header->getDOMNode()); - } - } - } - } - - /** - * Remove the passed node. - * - * TODO To be moved to Readability - * - * @param \DOMNode $node - * - * @return void - **/ - public function removeNode(\DOMNode $node) - { - $parent = $node->parentNode; - if ($parent) { - $parent->removeChild($node); - } - } - - /** - * Checks if the node is a byline. - * - * @param Readability $node - * @param string $matchString - * - * @return bool - */ - private function checkByline($node, $matchString) - { - if (!$this->getConfig()->getOption('articleByLine')) { - return false; - } - - /* - * Check if the byline is already set - */ - if (isset($this->metadata['byline'])) { - return false; - } - - $rel = $node->getAttribute('rel'); - - if ($rel === 'author' || preg_match($this->regexps['byline'], $matchString) && $this->isValidByline($node->getTextContent())) { - $this->metadata['byline'] = trim($node->getTextContent()); - - return true; - } - - return false; - } - - /** - * Checks the validity of a byLine. Based on string length. - * - * @param string $text - * - * @return bool - */ - private function isValidByline($text) - { - if (gettype($text) == 'string') { - $byline = trim($text); - - return (mb_strlen($byline) > 0) && (mb_strlen($text) < 100); - } - - return false; - } - - /** - * Checks if the current node has a single child and if that child is a P node. - * Useful to convert <div><p> nodes to a single <p> node and avoid confusing the scoring system since div with p - * tags are, in practice, paragraphs. - * - * @param Readability $node - * - * @return bool - */ - private function hasSinglePNode(Readability $node) - { - // There should be exactly 1 element child which is a P: - if (count($children = $node->getChildren(true)) !== 1 || !$children[0]->tagNameEqualsTo('p')) { - return false; - } - - // And there should be no text nodes with real content (param true on ->getChildren) - foreach ($children as $child) { - /** @var $child Readability */ - if ($child->nodeTypeEqualsTo(XML_TEXT_NODE) && !preg_match('/\S$/', $child->getTextContent())) { - return false; - } - } - - return true; - } - - private function hasSingleChildBlockElement(Readability $node) - { - $result = false; - if ($node->hasChildren()) { - /** @var Readability $child */ - foreach ($node->getChildren() as $child) { - if (in_array($child->getTagName(), $this->divToPElements)) { - $result = true; - } else { - // If any of the hasSingleChildBlockElement calls return true, return true then. - $result = ($result || $this->hasSingleChildBlockElement($child)); - } - } - } - - return $result; - } -} diff --git a/src/Nodes/DOM/DOMAttr.php b/src/Nodes/DOM/DOMAttr.php new file mode 100644 index 0000000..91729f3 --- /dev/null +++ b/src/Nodes/DOM/DOMAttr.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMAttr extends \DOMAttr +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMCdataSection.php b/src/Nodes/DOM/DOMCdataSection.php new file mode 100644 index 0000000..4535e4e --- /dev/null +++ b/src/Nodes/DOM/DOMCdataSection.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMCdataSection extends \DOMCdataSection +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMCharacterData.php b/src/Nodes/DOM/DOMCharacterData.php new file mode 100644 index 0000000..e4db11a --- /dev/null +++ b/src/Nodes/DOM/DOMCharacterData.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMCharacterData extends \DOMCharacterData +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMComment.php b/src/Nodes/DOM/DOMComment.php new file mode 100644 index 0000000..13b004a --- /dev/null +++ b/src/Nodes/DOM/DOMComment.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMComment extends \DOMComment +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMDocument.php b/src/Nodes/DOM/DOMDocument.php new file mode 100644 index 0000000..b99d464 --- /dev/null +++ b/src/Nodes/DOM/DOMDocument.php @@ -0,0 +1,28 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMDocument extends \DOMDocument +{ + use NodeTrait; + + public function __construct($version, $encoding) + { + parent::__construct($version, $encoding); + + $this->registerNodeClass('DOMAttr', DOMAttr::class); + $this->registerNodeClass('DOMCdataSection', DOMCdataSection::class); + $this->registerNodeClass('DOMCharacterData', DOMCharacterData::class); + $this->registerNodeClass('DOMComment', DOMComment::class); + $this->registerNodeClass('DOMDocument', self::class); + $this->registerNodeClass('DOMDocumentFragment', DOMDocumentFragment::class); + $this->registerNodeClass('DOMDocumentType', DOMDocumentType::class); + $this->registerNodeClass('DOMElement', DOMElement::class); + $this->registerNodeClass('DOMNode', DOMNode::class); + $this->registerNodeClass('DOMNotation', DOMNotation::class); + $this->registerNodeClass('DOMProcessingInstruction', DOMProcessingInstruction::class); + $this->registerNodeClass('DOMText', DOMText::class); + } +} diff --git a/src/Nodes/DOM/DOMDocumentFragment.php b/src/Nodes/DOM/DOMDocumentFragment.php new file mode 100644 index 0000000..bcb8946 --- /dev/null +++ b/src/Nodes/DOM/DOMDocumentFragment.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMDocumentFragment extends \DOMDocumentFragment +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMDocumentType.php b/src/Nodes/DOM/DOMDocumentType.php new file mode 100644 index 0000000..18705a7 --- /dev/null +++ b/src/Nodes/DOM/DOMDocumentType.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMDocumentType extends \DOMDocumentType +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMElement.php b/src/Nodes/DOM/DOMElement.php new file mode 100644 index 0000000..c07670b --- /dev/null +++ b/src/Nodes/DOM/DOMElement.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMElement extends \DOMElement +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMNode.php b/src/Nodes/DOM/DOMNode.php new file mode 100644 index 0000000..f1944c4 --- /dev/null +++ b/src/Nodes/DOM/DOMNode.php @@ -0,0 +1,13 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +/** + * @method getAttribute($attribute) + */ +class DOMNode extends \DOMNode +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMNotation.php b/src/Nodes/DOM/DOMNotation.php new file mode 100644 index 0000000..2e888ce --- /dev/null +++ b/src/Nodes/DOM/DOMNotation.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMNotation extends \DOMNotation +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMProcessingInstruction.php b/src/Nodes/DOM/DOMProcessingInstruction.php new file mode 100644 index 0000000..9dd4c5c --- /dev/null +++ b/src/Nodes/DOM/DOMProcessingInstruction.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMProcessingInstruction extends \DOMProcessingInstruction +{ + use NodeTrait; +} diff --git a/src/Nodes/DOM/DOMText.php b/src/Nodes/DOM/DOMText.php new file mode 100644 index 0000000..42c575b --- /dev/null +++ b/src/Nodes/DOM/DOMText.php @@ -0,0 +1,10 @@ +<?php + +namespace andreskrey\Readability\Nodes\DOM; + +use andreskrey\Readability\Nodes\NodeTrait; + +class DOMText extends \DOMText +{ + use NodeTrait; +} diff --git a/src/Nodes/NodeTrait.php b/src/Nodes/NodeTrait.php new file mode 100644 index 0000000..f9bf8f9 --- /dev/null +++ b/src/Nodes/NodeTrait.php @@ -0,0 +1,430 @@ +<?php + +namespace andreskrey\Readability\Nodes; + +use andreskrey\Readability\Nodes\DOM\DOMElement; +use andreskrey\Readability\Nodes\DOM\DOMNode; +use andreskrey\Readability\Nodes\DOM\DOMText; + +trait NodeTrait +{ + /** + * Content score of the node. Used to determine the value of the content. + * + * @var int + */ + public $contentScore = 0; + + /** + * Flag for initialized status. + * + * @var bool + */ + private $initialized = false; + + /** + * Flag data tables. + * + * @var bool + */ + private $readabilityDataTable = false; + + /** + * @var array + */ + private $divToPElements = [ + 'a', + 'blockquote', + 'dl', + 'div', + 'img', + 'ol', + 'p', + 'pre', + 'table', + 'ul', + 'select', + ]; + + /** + * initialized getter. + * + * @return bool + */ + public function isInitialized() + { + return $this->initialized; + } + + /** + * @return bool + */ + public function isReadabilityDataTable() + { + return $this->readabilityDataTable; + } + + /** + * @param bool $param + */ + public function setReadabilityDataTable($param) + { + $this->readabilityDataTable = $param; + } + + /** + * Initializer. Calculates the current score of the node and returns a full Readability object. + * + * @ TODO: I don't like the weightClasses param. How can we get the config here? + * + * @param $weightClasses bool Weight classes? + * + * @return static + */ + public function initializeNode($weightClasses) + { + if (!$this->isInitialized()) { + $contentScore = 0; + + switch ($this->nodeName) { + case 'div': + $contentScore += 5; + break; + + case 'pre': + case 'td': + case 'blockquote': + $contentScore += 3; + break; + + case 'address': + case 'ol': + case 'ul': + case 'dl': + case 'dd': + case 'dt': + case 'li': + case 'form': + $contentScore -= 3; + break; + + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + case 'th': + $contentScore -= 5; + break; + } + + $this->contentScore = $contentScore + ($weightClasses ? $this->getClassWeight() : 0); + + $this->initialized = true; + } + + return $this; + } + + /** + * Override for native getAttribute method. Some nodes have the getAttribute method, some don't, so we need + * to check first the existence of the attributes property. + * + * @param $attributeName string Attribute to retrieve + * + * @return string + */ + public function getAttribute($attributeName) + { + if (!is_null($this->attributes)) { + return parent::getAttribute($attributeName); + } + + return ''; + } + + /** + * Get the ancestors of the current node. + * + * @param int|bool $maxLevel Max amount of ancestors to get. False for all of them + * + * @return array + */ + public function getNodeAncestors($maxLevel = 3) + { + $ancestors = []; + $level = 0; + + $node = $this->parentNode; + + while ($node) { + $ancestors[] = $node; + $level++; + if ($level === $maxLevel) { + break; + } + $node = $node->parentNode; + } + + return $ancestors; + } + + /** + * Returns all links from the current element. + * + * @return array + */ + public function getAllLinks() + { + return iterator_to_array($this->getElementsByTagName('a')); + } + + /** + * Get the density of links as a percentage of the content + * This is the amount of text that is inside a link divided by the total text in the node. + * + * @return int + */ + public function getLinkDensity() + { + $linkLength = 0; + $textLength = mb_strlen($this->getTextContent(true)); + + if (!$textLength) { + return 0; + } + + $links = $this->getAllLinks(); + + if ($links) { + /** @var DOMElement $link */ + foreach ($links as $link) { + $linkLength += mb_strlen($link->getTextContent(true)); + } + } + + return $linkLength / $textLength; + } + + /** + * Calculates the weight of the class/id of the current element. + * + * @return int + */ + public function getClassWeight() + { + $weight = 0; + + // Look for a special classname + $class = $this->getAttribute('class'); + if (trim($class)) { + if (preg_match(NodeUtility::$regexps['negative'], $class)) { + $weight -= 25; + } + + if (preg_match(NodeUtility::$regexps['positive'], $class)) { + $weight += 25; + } + } + + // Look for a special ID + $id = $this->getAttribute('id'); + if (trim($id)) { + if (preg_match(NodeUtility::$regexps['negative'], $id)) { + $weight -= 25; + } + + if (preg_match(NodeUtility::$regexps['positive'], $id)) { + $weight += 25; + } + } + + return $weight; + } + + /** + * Returns the full text of the node. + * + * @param bool $normalize Normalize white space? + * + * @return string + */ + public function getTextContent($normalize = false) + { + $nodeValue = $this->nodeValue; + if ($normalize) { + $nodeValue = trim(preg_replace('/\s{2,}/', ' ', $nodeValue)); + } + + return $nodeValue; + } + + /** + * Returns the children of the current node. + * + * @param bool $filterEmptyDOMText Filter empty DOMText nodes? + * + * @return array + */ + public function getChildren($filterEmptyDOMText = false) + { + $ret = iterator_to_array($this->childNodes); + if ($filterEmptyDOMText) { + // Array values is used to discard the key order. Needs to be 0 to whatever without skipping any number + $ret = array_values(array_filter($ret, function ($node) { + return $node->nodeName !== '#text' || mb_strlen(trim($node->nodeValue)); + })); + } + + return $ret; + } + + /** + * Return an array indicating how many rows and columns this table has. + * + * @return array + */ + public function getRowAndColumnCount() + { + $rows = $columns = 0; + $trs = $this->getElementsByTagName('tr'); + foreach ($trs as $tr) { + /** @var \DOMElement $tr */ + $rowspan = $tr->getAttribute('rowspan'); + $rows += ($rowspan || 1); + + // Now look for column-related info + $columnsInThisRow = 0; + $cells = $tr->getElementsByTagName('td'); + foreach ($cells as $cell) { + /** @var \DOMElement $cell */ + $colspan = $cell->getAttribute('colspan'); + $columnsInThisRow += ($colspan || 1); + } + $columns = max($columns, $columnsInThisRow); + } + + return ['rows' => $rows, 'columns' => $columns]; + } + + /** + * Creates a new node based on the text content of the original node. + * + * @param $originalNode DOMNode + * @param $tagName string + * + * @return DOMElement + */ + public function createNode($originalNode, $tagName) + { + $text = $originalNode->getTextContent(); + $newNode = $originalNode->ownerDocument->createElement($tagName, $text); + + return $newNode; + } + + /** + * Check if a given node has one of its ancestor tag name matching the + * provided one. + * + * @param DOMElement $node + * @param string $tagName + * @param int $maxDepth + * + * @return bool + */ + public function hasAncestorTag($node, $tagName, $maxDepth = 3) + { + $depth = 0; + while ($node->parentNode) { + if ($maxDepth > 0 && $depth > $maxDepth) { + return false; + } + if ($node->parentNode->nodeName === $tagName) { + return true; + } + $node = $node->parentNode; + $depth++; + } + + return false; + } + + /** + * Checks if the current node has a single child and if that child is a P node. + * Useful to convert <div><p> nodes to a single <p> node and avoid confusing the scoring system since div with p + * tags are, in practice, paragraphs. + * + * @param DOMNode $node + * + * @return bool + */ + public function hasSinglePNode() + { + // There should be exactly 1 element child which is a P: + if (count($children = $this->getChildren(true)) !== 1 || $children[0]->nodeName !== 'p') { + return false; + } + + // And there should be no text nodes with real content (param true on ->getChildren) + foreach ($children as $child) { + /** @var $child DOMNode */ + if ($child->nodeType === XML_TEXT_NODE && !preg_match('/\S$/', $child->getTextContent())) { + return false; + } + } + + return true; + } + + /** + * Check if the current element has a single child block element. + * Block elements are the ones defined in the divToPElements array. + * + * @return bool + */ + public function hasSingleChildBlockElement() + { + $result = false; + if ($this->hasChildNodes()) { + foreach ($this->getChildren() as $child) { + if (in_array($child->nodeName, $this->divToPElements)) { + $result = true; + } else { + // If any of the hasSingleChildBlockElement calls return true, return true then. + /** @var $child DOMElement */ + $result = ($result || $child->hasSingleChildBlockElement()); + } + } + } + + return $result; + } + + /** + * Determines if a node has no content or it is just a bunch of dividing lines and/or whitespace. + * + * @return bool + */ + public function isElementWithoutContent() + { + return $this instanceof DOMElement && + mb_strlen(preg_replace(NodeUtility::$regexps['onlyWhitespace'], '', $this->textContent)) === 0 && + ($this->childNodes->length === 0 || + $this->childNodes->length === $this->getElementsByTagName('br')->length + $this->getElementsByTagName('hr')->length + /* + * Special PHP DOMDocument case: We also need to count how many DOMText we have inside the node. + * If there's an empty tag with an space inside and a BR (for example "<p> <br/></p>) counting only BRs and + * HRs will will say that the example has 2 nodes, instead of one. This happens because in DOMDocument, + * DOMTexts are also nodes (which doesn't happen in JS). So we need to also count how many DOMText we + * are dealing with (And at this point we know they are empty or are just whitespace, because of the + * mb_strlen in this chain of checks). + */ + + count(array_filter(iterator_to_array($this->childNodes), function ($child) { + return $child instanceof DOMText; + })) + + ); + } +} diff --git a/src/Nodes/NodeUtility.php b/src/Nodes/NodeUtility.php new file mode 100644 index 0000000..0e1072f --- /dev/null +++ b/src/Nodes/NodeUtility.php @@ -0,0 +1,159 @@ +<?php + +namespace andreskrey\Readability\Nodes; + +use andreskrey\Readability\Nodes\DOM\DOMDocument; +use andreskrey\Readability\Nodes\DOM\DOMElement; +use andreskrey\Readability\Nodes\DOM\DOMNode; + +/** + * Class NodeUtility. + */ +class NodeUtility +{ + /** + * Collection of regexps to check the node usability. + * + * @var array + */ + public static $regexps = [ + 'unlikelyCandidates' => '/banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|modal|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i', + 'okMaybeItsACandidate' => '/and|article|body|column|main|shadow/i', + 'extraneous' => '/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i', + 'byline' => '/byline|author|dateline|writtenby|p-author/i', + 'replaceFonts' => '/<(\/?)font[^>]*>/gi', + 'normalize' => '/\s{2,}/', + 'videos' => '/\/\/(www\.)?(dailymotion|youtube|youtube-nocookie|player\.vimeo)\.com/i', + 'nextLink' => '/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i', + 'prevLink' => '/(prev|earl|old|new|<|«)/i', + 'whitespace' => '/^\s*$/', + 'hasContent' => '/\S$/', + 'positive' => '/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i', + 'negative' => '/hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|modal|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i', + // \x{00A0} is the unicode version of + 'onlyWhitespace' => '/\x{00A0}|\s+/u' + ]; + + /** + * Imported from the Element class on league\html-to-markdown. + * + * @param $node + * + * @return DOMElement + */ + public static function nextElement($node) + { + $next = $node; + while ($next + && $next->nodeName !== '#text' + && trim($next->textContent)) { + $next = $next->nextSibling; + } + + return $next; + } + + /** + * Changes the node tag name. Since tagName on DOMElement is a read only value, this must be done creating a new + * element with the new tag name and importing it to the main DOMDocument. + * + * @param string $value + * @param bool $importAttributes + * + * @return DOMNode + */ + public static function setNodeTag($node, $value, $importAttributes = false) + { + $new = new DOMDocument('1.0', 'utf-8'); + $new->appendChild($new->createElement($value)); + + $children = $node->childNodes; + /** @var $children \DOMNodeList $i */ + for ($i = 0; $i < $children->length; $i++) { + $import = $new->importNode($children->item($i), true); + $new->firstChild->appendChild($import); + } + + if ($importAttributes) { + // Import attributes from the original node. + foreach ($node->attributes as $attribute) { + $new->firstChild->setAttribute($attribute->nodeName, $attribute->nodeValue); + } + } + + // The import must be done on the firstChild of $new, since $new is a DOMDocument and not a DOMElement. + $import = $node->ownerDocument->importNode($new->firstChild, true); + $node->parentNode->replaceChild($import, $node); + + return $import; + } + + /** + * Removes the current node and returns the next node to be parsed (child, sibling or parent). + * + * @param DOMNode $node + * + * @return DOMNode + */ + public static function removeAndGetNext($node) + { + $nextNode = self::getNextNode($node, true); + $node->parentNode->removeChild($node); + + return $nextNode; + } + + /** + * Remove the selected node. + * + * @param $node DOMElement + * + * @return void + **/ + public static function removeNode($node) + { + $parent = $node->parentNode; + if ($parent) { + $parent->removeChild($node); + } + } + + /** + * Returns the next node. First checks for children (if the flag allows it), then for siblings, and finally + * for parents. + * + * @param DOMNode $originalNode + * @param bool $ignoreSelfAndKids + * + * @return DOMNode + */ + public static function getNextNode($originalNode, $ignoreSelfAndKids = false) + { + /* + * Traverse the DOM from node to node, starting at the node passed in. + * Pass true for the second parameter to indicate this node itself + * (and its kids) are going away, and we want the next node over. + * + * Calling this in a loop will traverse the DOM depth-first. + */ + + // First check for kids if those aren't being ignored + if (!$ignoreSelfAndKids && $originalNode->firstChild) { + return $originalNode->firstChild; + } + + // Then for siblings... + if ($originalNode->nextSibling) { + return $originalNode->nextSibling; + } + + // And finally, move up the parent chain *and* find a sibling + // (because this is depth-first traversal, we will have already + // seen the parent nodes themselves). + do { + $originalNode = $originalNode->parentNode; + } while ($originalNode && !$originalNode->nextSibling); + + return ($originalNode) ? $originalNode->nextSibling : $originalNode; + } +} diff --git a/src/ParseException.php b/src/ParseException.php new file mode 100644 index 0000000..646c04a --- /dev/null +++ b/src/ParseException.php @@ -0,0 +1,7 @@ +<?php + +namespace andreskrey\Readability; + +class ParseException extends \Exception +{ +} diff --git a/src/Readability.php b/src/Readability.php index bf8cdf8..19ccd5d 100644 --- a/src/Readability.php +++ b/src/Readability.php @@ -2,547 +2,1521 @@ namespace andreskrey\Readability; -use League\HTMLToMarkdown\Element; +use andreskrey\Readability\Nodes\DOM\DOMDocument; +use andreskrey\Readability\Nodes\DOM\DOMElement; +use andreskrey\Readability\Nodes\DOM\DOMNode; +use andreskrey\Readability\Nodes\DOM\DOMText; +use andreskrey\Readability\Nodes\NodeUtility; /** - * Class DOMElement. - * - * This is a extension of the original Element class from League\HTMLToMarkdown\Element. - * This class adds functions specific to Readability.php and overloads some of them to fit the purpose of this project. + * Class Readability. */ -class Readability extends Element implements ReadabilityInterface +class Readability { /** - * @var \DOMNode|\DOMElement + * Main DOMDocument where all the magic happens. + * + * @var DOMDocument + */ + protected $dom; + + /** + * Title of the article. + * + * @var string|null + */ + protected $title = null; + + /** + * HTML content article. + * + * @var string|null + */ + protected $content = null; + + /** + * Excerpt of the article. + * + * @var string|null */ - protected $node; + protected $excerpt = null; /** - * @var int + * Main image of the article. + * + * @var string|null + */ + protected $image = null; + + /** + * Author of the article. Extracted from the byline tags and other social media properties. + * + * @var string|null + */ + protected $author = null; + + /** + * Direction of the text. + * + * @var string|null + */ + protected $direction = null; + + /** + * Configuration object. + * + * @var Configuration */ - protected $contentScore = 0; + private $configuration; /** - * @var int + * @var array */ - protected $initialized = false; + private $defaultTagsToScore = [ + 'section', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'p', + 'td', + 'pre', + ]; /** * @var array */ - private $regexps = [ - 'positive' => '/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i', - 'negative' => '/hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|modal|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i', + private $alterToDIVExceptions = [ + 'div', + 'article', + 'section', + 'p', ]; /** - * Constructor. + * Readability constructor. * - * @param \DOMNode $node Selected element from DOMDocument + * @param Configuration $configuration */ - public function __construct(\DOMNode $node) + public function __construct(Configuration $configuration) { - parent::__construct($node); - - /* - * Restore the score if the object has been already scored. - * - * An if must be added before calling the getAttribute function, because if we reach the DOMDocument - * by getting the node parents we'll get a undefined function fatal error - */ - if (method_exists($node, 'getAttribute')) { - if ($node->hasAttribute('data-readability')) { - // Node was initialized previously. Restoring score and setting flag. - $this->initialized = true; - $score = $node->getAttribute('data-readability'); - $this->setContentScore($score); - } - } + $this->configuration = $configuration; } /** - * Checks for the tag name. Case insensitive. + * Main parse function. * - * @param string $value Name to compare to the current tag + * @param $html * - * @return bool + * @throws ParseException + * + * @return array|bool */ - public function tagNameEqualsTo($value) + public function parse($html) { - $tagName = $this->getTagName(); - if (strtolower($value) === strtolower($tagName)) { - return true; + $this->dom = $this->loadHTML($html); + + $this->getMetadata(); + + $this->getMainImage(); + + // Checking for minimum HTML to work with. + if (!($root = $this->dom->getElementsByTagName('body')->item(0)) || !$root->firstChild) { + throw new ParseException('Invalid or incomplete HTML.'); } - return false; + while (true) { + $root = $root->firstChild; + + $elementsToScore = $this->getNodes($root); + + $result = $this->rateNodes($elementsToScore); + + /* + * Now that we've gone through the full algorithm, check to see if + * we got any meaningful content. If we didn't, we may need to re-run + * grabArticle with different flags set. This gives us a higher likelihood of + * finding the content, and the sieve approach gives us a higher likelihood of + * finding the -right- content. + */ + + $length = 0; + foreach ($result->getElementsByTagName('p') as $p) { + $length += mb_strlen($p->textContent); + } + if ($result && mb_strlen(preg_replace('/\s/', '', $result->textContent)) < $this->configuration->getWordThreshold()) { + $this->dom = $this->loadHTML($html); + $root = $this->dom->getElementsByTagName('body')->item(0); + + if ($this->configuration->getStripUnlikelyCandidates()) { + $this->configuration->setStripUnlikelyCandidates(false); + } elseif ($this->configuration->getWeightClasses()) { + $this->configuration->setWeightClasses(false); + } elseif ($this->configuration->getCleanConditionally()) { + $this->configuration->setCleanConditionally(false); + } else { + throw new ParseException('Could not parse text.'); + } + } else { + break; + } + } + + $result = $this->postProcessContent($result); + + // If we haven't found an excerpt in the article's metadata, use the article's + // first paragraph as the excerpt. This can be used for displaying a preview of + // the article's content. + if (!$this->getExcerpt()) { + $paragraphs = $result->getElementsByTagName('p'); + if ($paragraphs->length > 0) { + $this->setExcerpt(trim($paragraphs->item(0)->textContent)); + } + } + + $this->setContent($result->C14N()); + + return true; } /** - * Checks for the node type. + * Creates a DOM Document object and loads the provided HTML on it. * - * @param string $value Type of node to compare to + * Used for the first load of Readability and subsequent reloads (when disabling flags and rescanning the text) + * Previous versions of Readability used this method one time and cloned the DOM to keep a backup. This caused bugs + * because cloning the DOM object keeps a relation between the clone and the original one, doing changes in both + * objects and ruining the backup. * - * @return bool + * @param string $html + * + * @return DOMDocument */ - public function nodeTypeEqualsTo($value) + private function loadHTML($html) { - return $this->node->nodeType === $value; + // To avoid throwing a gazillion of errors on malformed HTMLs + libxml_use_internal_errors(true); + + $dom = new DOMDocument('1.0', 'utf-8'); + + if (!$this->configuration->getSubstituteEntities()) { + // Keep the original HTML entities + $dom->substituteEntities = false; + } + + if ($this->configuration->getNormalizeEntities()) { + // Replace UTF-8 characters with the HTML Entity equivalent. Useful to fix html with mixed content + $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); + } + + if ($this->configuration->getSummonCthulhu()) { + $html = preg_replace('/<script\b[^>]*>([\s\S]*?)<\/script>/', '', $html); + } + + // Prepend the XML tag to avoid having issues with special characters. Should be harmless. + $dom->loadHTML('<?xml encoding="UTF-8">' . $html); + $dom->encoding = 'UTF-8'; + + $this->removeScripts($dom); + + $this->prepDocument($dom); + + return $dom; } /** - * Get the ancestors of the current node. - * - * @param int|bool $maxLevel Max amount of ancestors to get. False for all of them - * - * @return array + * Tries to guess relevant info from metadata of the html. Sets the results in the Readability properties. */ - public function getNodeAncestors($maxLevel = 3) + private function getMetadata() { - $ancestors = []; - $level = 0; + $values = []; + // Match "description", or Twitter's "twitter:description" (Cards) + // in name attribute. + $namePattern = '/^\s*((twitter)\s*:\s*)?(description|title|image)\s*$/i'; - $node = $this->getParent(); + // Match Facebook's Open Graph title & description properties. + $propertyPattern = '/^\s*og\s*:\s*(description|title|image)\s*$/i'; - while ($node) { - $ancestors[] = $node; - $level++; - if ($level === $maxLevel) { - break; + foreach ($this->dom->getElementsByTagName('meta') as $meta) { + /* @var DOMNode $meta */ + $elementName = $meta->getAttribute('name'); + $elementProperty = $meta->getAttribute('property'); + + if (in_array('author', [$elementName, $elementProperty])) { + $this->setAuthor($meta->getAttribute('content')); + continue; + } + + $name = null; + if (preg_match($namePattern, $elementName)) { + $name = $elementName; + } elseif (preg_match($propertyPattern, $elementProperty)) { + $name = $elementProperty; + } + + if ($name) { + $content = $meta->getAttribute('content'); + if ($content) { + // Convert to lowercase and remove any whitespace + // so we can match below. + $name = preg_replace('/\s/', '', strtolower($name)); + $values[$name] = trim($content); + } + } + } + if (array_key_exists('description', $values)) { + $this->setExcerpt($values['description']); + } elseif (array_key_exists('og:description', $values)) { + // Use facebook open graph description. + $this->setExcerpt($values['og:description']); + } elseif (array_key_exists('twitter:description', $values)) { + // Use twitter cards description. + $this->setExcerpt($values['twitter:description']); + } + + $this->setTitle($this->getArticleTitle()); + + if (!$this->getTitle()) { + if (array_key_exists('og:title', $values)) { + // Use facebook open graph title. + $this->setTitle($values['og:title']); + } elseif (array_key_exists('twitter:title', $values)) { + // Use twitter cards title. + $this->setTitle($values['twitter:title']); } - $node = $node->getParent(); } - return $ancestors; + if (array_key_exists('og:image', $values) || array_key_exists('twitter:image', $values)) { + $this->setImage(array_key_exists('og:image', $values) ? $values['og:image'] : $values['twitter:image']); + } } /** - * Overloading the getParent function from League\HTMLToMarkdown\Element due to a bug when there are no more parents - * on the selected element. + * Returns all the images of the parsed article. * - * @return Readability|null + * @return array */ - public function getParent() + public function getImages() { - $node = $this->node->parentNode; + $result = []; + if ($this->getImage()) { + $result[] = $this->getImage(); + } + + if (null == $this->dom) { + return $result; + } + + foreach ($this->dom->getElementsByTagName('img') as $img) { + if ($src = $img->getAttribute('src')) { + $result[] = $src; + } + } - return ($node) ? new self($node) : null; + if ($this->configuration->getFixRelativeURLs()) { + foreach ($result as &$imgSrc) { + $imgSrc = $this->toAbsoluteURI($imgSrc); + } + } + + $result = array_unique(array_filter($result)); + + return $result; } /** - * Returns all links from the current element. - * - * @return array|null + * Tries to get the main article image. Will only update the metadata if the getMetadata function couldn't + * find a correct image. */ - public function getAllLinks() + public function getMainImage() { - if (($this->isText())) { - return null; - } else { - $links = []; - foreach ($this->node->getElementsByTagName('a') as $link) { - $links[] = new self($link); + $imgUrl = false; + + if ($this->getImage() !== null) { + $imgUrl = $this->getImage(); + } + + if (!$imgUrl) { + foreach ($this->dom->getElementsByTagName('link') as $link) { + /** @var \DOMElement $link */ + /* + * Check for the rel attribute, then check if the rel attribute is either img_src or image_src, and + * finally check for the existence of the href attribute, which should hold the image url. + */ + if ($link->hasAttribute('rel') && ($link->getAttribute('rel') === 'img_src' || $link->getAttribute('rel') === 'image_src') && $link->hasAttribute('href')) { + $imgUrl = $link->getAttribute('href'); + break; + } } + } - return $links; + if (!empty($imgUrl) && $this->configuration->getFixRelativeURLs()) { + $this->setImage($this->toAbsoluteURI($imgUrl)); } } /** - * Initializer. Calculates the current score of the node and returns a full Readability object. + * Returns the title of the html. Prioritizes the title from the metadata against the title tag. * - * @return Readability + * @return string|null */ - public function initializeNode() + private function getArticleTitle() { - if (!$this->initialized) { - $contentScore = 0; + $originalTitle = null; - switch ($this->getTagName()) { - case 'div': - $contentScore += 5; - break; + if ($this->getTitle()) { + $originalTitle = $this->getTitle(); + } else { + $titleTag = $this->dom->getElementsByTagName('title'); + if ($titleTag->length > 0) { + $originalTitle = $titleTag->item(0)->nodeValue; + } + } - case 'pre': - case 'td': - case 'blockquote': - $contentScore += 3; - break; + if ($originalTitle === null) { + return null; + } - case 'address': - case 'ol': - case 'ul': - case 'dl': - case 'dd': - case 'dt': - case 'li': - case 'form': - $contentScore -= 3; - break; + $curTitle = $originalTitle; + $titleHadHierarchicalSeparators = false; - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': - case 'th': - $contentScore -= 5; - break; + /* + * If there's a separator in the title, first remove the final part + * + * Sanity warning: if you eval this match in PHPStorm's "Evaluate expression" box, it will return false + * I can assure you it works properly if you let the code run. + */ + if (preg_match('/ [\|\-\\\\\/>»] /i', $curTitle)) { + $titleHadHierarchicalSeparators = (bool)preg_match('/ [\\\\\/>»] /', $curTitle); + $curTitle = preg_replace('/(.*)[\|\-\\\\\/>»] .*/i', '$1', $originalTitle); + + // If the resulting title is too short (3 words or fewer), remove + // the first part instead: + if (count(preg_split('/\s+/', $curTitle)) < 3) { + $curTitle = preg_replace('/[^\|\-\\\\\/>»]*[\|\-\\\\\/>»](.*)/i', '$1', $originalTitle); + } + } elseif (strpos($curTitle, ': ') !== false) { + // Check if we have an heading containing this exact string, so we + // could assume it's the full title. + $match = false; + for ($i = 1; $i <= 2; $i++) { + foreach ($this->dom->getElementsByTagName('h' . $i) as $hTag) { + // Trim texts to avoid having false negatives when the title is surrounded by spaces or tabs + if (trim($hTag->nodeValue) === trim($curTitle)) { + $match = true; + } + } } - $this->setContentScore($contentScore + $this->getClassWeight()); + // If we don't, let's extract the title out of the original title string. + if (!$match) { + $curTitle = substr($originalTitle, strrpos($originalTitle, ':') + 1); - $this->initialized = true; + // If the title is now too short, try the first colon instead: + if (count(preg_split('/\s+/', $curTitle)) < 3) { + $curTitle = substr($originalTitle, strpos($originalTitle, ':') + 1); + } + } + } elseif (mb_strlen($curTitle) > 150 || mb_strlen($curTitle) < 15) { + $hOnes = $this->dom->getElementsByTagName('h1'); + + if ($hOnes->length === 1) { + $curTitle = $hOnes->item(0)->nodeValue; + } } - return $this; + $curTitle = trim($curTitle); + + /* + * If we now have 4 words or fewer as our title, and either no + * 'hierarchical' separators (\, /, > or ») were found in the original + * title or we decreased the number of words by more than 1 word, use + * the original title. + */ + $curTitleWordCount = count(preg_split('/\s+/', $curTitle)); + $originalTitleWordCount = count(preg_split('/\s+/', preg_replace('/[\|\-\\\\\/>»]+/', '', $originalTitle))) - 1; + + if ($curTitleWordCount <= 4 && + (!$titleHadHierarchicalSeparators || $curTitleWordCount !== $originalTitleWordCount)) { + $curTitle = $originalTitle; + } + + return $curTitle; } /** - * Calculates the weight of the class/id of the current element. + * Convert URI to an absolute URI. * - * @todo check for flag that lets this function run or not + * @param $uri string URI to convert * - * @return int + * @return string */ - public function getClassWeight() + private function toAbsoluteURI($uri) { - // TODO To implement. How to get config from html parser from readability -// if ($this->getConfig()->getOption('weightClasses')) { -// return 0; -// } -// - $weight = 0; + list($pathBase, $scheme, $prePath) = $this->getPathInfo($this->configuration->getOriginalURL()); - // Look for a special classname - $class = $this->getAttribute('class'); - if (trim($class)) { - if (preg_match($this->regexps['negative'], $class)) { - $weight -= 25; - } + // If this is already an absolute URI, return it. + if (preg_match('/^[a-zA-Z][a-zA-Z0-9\+\-\.]*:/', $uri)) { + return $uri; + } - if (preg_match($this->regexps['positive'], $class)) { - $weight += 25; - } + // Scheme-rooted relative URI. + if (substr($uri, 0, 2) === '//') { + return $scheme . '://' . substr($uri, 2); } - // Look for a special ID - $id = $this->getAttribute('id'); - if (trim($id)) { - if (preg_match($this->regexps['negative'], $id)) { - $weight -= 25; - } + // Prepath-rooted relative URI. + if (substr($uri, 0, 1) === '/') { + return $prePath . $uri; + } - if (preg_match($this->regexps['positive'], $id)) { - $weight += 25; - } + // Dotslash relative URI. + if (strpos($uri, './') === 0) { + return $pathBase . substr($uri, 2); + } + // Ignore hash URIs: + if (substr($uri, 0, 1) === '#') { + return $uri; } - return $weight; + // Standard relative URI; add entire path. pathBase already includes a + // trailing "/". + return $pathBase . $uri; } /** - * Returns the current score of the Readability object. + * Returns full path info of an URL. * - * @return int + * @param string $url + * + * @return array [$pathBase, $scheme, $prePath] */ - public function getContentScore() + public function getPathInfo($url) { - return $this->contentScore; + $pathBase = parse_url($url, PHP_URL_SCHEME) . '://' . parse_url($url, PHP_URL_HOST) . dirname(parse_url($url, PHP_URL_PATH)) . '/'; + $scheme = parse_url($pathBase, PHP_URL_SCHEME); + $prePath = $scheme . '://' . parse_url($pathBase, PHP_URL_HOST); + + return [$pathBase, $scheme, $prePath]; } /** - * Returns the current score of the Readability object. + * Gets nodes from the root element. * - * @param int $score + * @param $node DOMNode|DOMText * - * @return int + * @return array */ - public function setContentScore($score) + private function getNodes($node) { - // Check if the setAttribute method exists, as some elements lack of it (and calling it anyway throws an exception) - if (method_exists($this->node, 'setAttribute')) { - $this->contentScore = (float)$score; + $stripUnlikelyCandidates = $this->configuration->getStripUnlikelyCandidates(); + + $elementsToScore = []; + + /* + * First, node prepping. Trash nodes that look cruddy (like ones with the + * class name "comment", etc), and turn divs into P tags where they have been + * used inappropriately (as in, where they contain no other block level elements.) + */ + + while ($node) { + $matchString = $node->getAttribute('class') . ' ' . $node->getAttribute('id'); - // Set score in an attribute of the tag to prevent losing it while creating new Readability objects. - $this->node->setAttribute('data-readability', $this->contentScore); + // Remove DOMComments nodes as we don't need them and mess up children counting + if ($node->nodeType === XML_COMMENT_NODE) { + $node = NodeUtility::removeAndGetNext($node); + continue; + } + + // Check to see if this node is a byline, and remove it if it is. + if ($this->checkByline($node, $matchString)) { + $node = NodeUtility::removeAndGetNext($node); + continue; + } + + // Remove unlikely candidates + if ($stripUnlikelyCandidates) { + if ( + preg_match(NodeUtility::$regexps['unlikelyCandidates'], $matchString) && + !preg_match(NodeUtility::$regexps['okMaybeItsACandidate'], $matchString) && + $node->nodeName !== 'body' && + $node->nodeName !== 'a' + ) { + $node = NodeUtility::removeAndGetNext($node); + continue; + } + } + + // Remove DIV, SECTION, and HEADER nodes without any content(e.g. text, image, video, or iframe). + if (($node->nodeName === 'div' || $node->nodeName === 'section' || $node->nodeName === 'header' || + $node->nodeName === 'h1' || $node->nodeName === 'h2' || $node->nodeName === 'h3' || + $node->nodeName === 'h4' || $node->nodeName === 'h5' || $node->nodeName === 'h6' || + $node->nodeName === 'p') && + $node->isElementWithoutContent()) { + $node = NodeUtility::removeAndGetNext($node); + continue; + } - return $this->contentScore; + if (in_array(strtolower($node->nodeName), $this->defaultTagsToScore)) { + $elementsToScore[] = $node; + } + + // Turn all divs that don't have children block level elements into p's + if ($node->nodeName === 'div') { + /* + * Sites like http://mobile.slate.com encloses each paragraph with a DIV + * element. DIVs with only a P element inside and no text content can be + * safely converted into plain P elements to avoid confusing the scoring + * algorithm with DIVs with are, in practice, paragraphs. + */ + if ($node->hasSinglePNode()) { + $pNode = $node->getChildren(true)[0]; + $node->parentNode->replaceChild($pNode, $node); + $node = $pNode; + $elementsToScore[] = $node; + } elseif (!$node->hasSingleChildBlockElement()) { + $node = NodeUtility::setNodeTag($node, 'p'); + $elementsToScore[] = $node; + } else { + // EXPERIMENTAL + foreach ($node->getChildren() as $child) { + /** @var $child DOMNode */ + if ($child->nodeType === XML_TEXT_NODE && mb_strlen(trim($child->getTextContent())) > 0) { + $newNode = $node->createNode($child, 'p'); + $child->parentNode->replaceChild($newNode, $child); + } + } + } + } + + $node = NodeUtility::getNextNode($node); } - return 0; + return $elementsToScore; } /** - * Returns the full text of the node. + * Checks if the node is a byline. * - * @param bool $normalize Normalize white space? + * @param DOMNode $node + * @param string $matchString * - * @return string + * @return bool */ - public function getTextContent($normalize = false) + private function checkByline($node, $matchString) { - $nodeValue = $this->node->nodeValue; - if ($normalize) { - $nodeValue = trim(preg_replace('/\s{2,}/', ' ', $nodeValue)); + if (!$this->configuration->getArticleByLine()) { + return false; + } + + /* + * Check if the byline is already set + */ + if ($this->getAuthor()) { + return false; } - return $nodeValue; + $rel = $node->getAttribute('rel'); + + if ($rel === 'author' || preg_match(NodeUtility::$regexps['byline'], $matchString) && $this->isValidByline($node->getTextContent())) { + $this->setAuthor(trim($node->getTextContent())); + + return true; + } + + return false; } /** - * Changes the node tag name. Since tagName on DOMElement is a read only value, this must be done creating a new - * element with the new tag name and importing it to the main DOMDocument. + * Checks the validity of a byLine. Based on string length. * - * @param string $value - * @param bool $importAttributes + * @param string $text + * + * @return bool */ - public function setNodeTag($value, $importAttributes = false) + private function isValidByline($text) { - $new = new \DOMDocument(); - $new->appendChild($new->createElement($value)); - - $childs = $this->node->childNodes; - for ($i = 0; $i < $childs->length; $i++) { - $import = $new->importNode($childs->item($i), true); - $new->firstChild->appendChild($import); - } + if (gettype($text) == 'string') { + $byline = trim($text); - if ($importAttributes) { - // Import attributes from the original node. - foreach ($this->node->attributes as $attribute) { - $new->firstChild->setAttribute($attribute->nodeName, $attribute->nodeValue); - } + return (mb_strlen($byline) > 0) && (mb_strlen($text) < 100); } - // The import must be done on the firstChild of $new, since $new is a DOMDocument and not a DOMElement. - $import = $this->node->ownerDocument->importNode($new->firstChild, true); - $this->node->parentNode->replaceChild($import, $this->node); - - $this->node = $import; + return false; } /** - * Returns the current DOMNode. + * Removes all the scripts of the html. * - * @return \DOMNode + * @param DOMDocument $dom */ - public function getDOMNode() + private function removeScripts(DOMDocument $dom) { - return $this->node; + $toRemove = ['script', 'noscript']; + + foreach ($toRemove as $tag) { + while ($script = $dom->getElementsByTagName($tag)) { + if ($script->item(0)) { + $script->item(0)->parentNode->removeChild($script->item(0)); + } else { + break; + } + } + } } /** - * Removes the current node and returns the next node to be parsed (child, sibling or parent). - * - * @param Readability $node + * Prepares the document for parsing. * - * @return Readability + * @param DOMDocument $dom */ - public function removeAndGetNext($node) + private function prepDocument(DOMDocument $dom) { - $nextNode = $this->getNextNode($node, true); - $node->node->parentNode->removeChild($node->node); + /* + * DOMNodeList must be converted to an array before looping over it. + * This is done to avoid node shifting when removing nodes. + * + * Reverse traversing cannot be done here because we need to find brs that are right next to other brs. + * (If we go the other way around we need to search for previous nodes forcing the creation of new functions + * that will be used only here) + */ + foreach (iterator_to_array($dom->getElementsByTagName('br')) as $br) { + $next = $br->nextSibling; + + /* + * Whether 2 or more <br> elements have been found and replaced with a + * <p> block. + */ + $replaced = false; + + /* + * If we find a <br> chain, remove the <br>s until we hit another element + * or non-whitespace. This leaves behind the first <br> in the chain + * (which will be replaced with a <p> later). + */ + while (($next = NodeUtility::nextElement($next)) && ($next->nodeName === 'br')) { + $replaced = true; + $brSibling = $next->nextSibling; + $next->parentNode->removeChild($next); + $next = $brSibling; + } + + /* + * If we removed a <br> chain, replace the remaining <br> with a <p>. Add + * all sibling nodes as children of the <p> until we hit another <br> + * chain. + */ + + if ($replaced) { + $p = $dom->createElement('p'); + $br->parentNode->replaceChild($p, $br); + + $next = $p->nextSibling; + while ($next) { + // If we've hit another <br><br>, we're done adding children to this <p>. + if ($next->nodeName === 'br') { + $nextElem = NodeUtility::nextElement($next); + if ($nextElem && $nextElem->nodeName === 'br') { + break; + } + } + + // Otherwise, make this node a child of the new <p>. + $sibling = $next->nextSibling; + $p->appendChild($next); + $next = $sibling; + } + } + } - return $nextNode; + // Replace font tags with span + $fonts = $dom->getElementsByTagName('font'); + $length = $fonts->length; + for ($i = 0; $i < $length; $i++) { + $font = $fonts->item($length - 1 - $i); + NodeUtility::setNodeTag($font, 'span', true); + } } /** - * Returns the next node. First checks for childs (if the flag allows it), then for siblings, and finally - * for parents. + * Assign scores to each node. Returns full article parsed or false on error. * - * @param Readability $originalNode - * @param bool $ignoreSelfAndKids + * @param array $nodes * - * @return Readability + * @return DOMDocument|bool */ - public function getNextNode($originalNode, $ignoreSelfAndKids = false) + private function rateNodes($nodes) { + $candidates = []; + + /** @var DOMElement $node */ + foreach ($nodes as $node) { + if (is_null($node->parentNode)) { + continue; + } + + // Discard nodes with less than 25 characters, without blank space + if (mb_strlen($node->getTextContent(true)) < 25) { + continue; + } + + $ancestors = $node->getNodeAncestors(); + + // Exclude nodes with no ancestor + if (count($ancestors) === 0) { + continue; + } + + // Start with a point for the paragraph itself as a base. + $contentScore = 1; + + // Add points for any commas within this paragraph. + $contentScore += count(explode(',', $node->getTextContent(true))); + + // For every 100 characters in this paragraph, add another point. Up to 3 points. + $contentScore += min(floor(mb_strlen($node->getTextContent(true)) / 100), 3); + + /** @var $ancestor DOMElement */ + foreach ($ancestors as $level => $ancestor) { + if (!$ancestor->isInitialized()) { + $ancestor->initializeNode($this->configuration->getWeightClasses()); + $candidates[] = $ancestor; + } + + /* + * Node score divider: + * - parent: 1 (no division) + * - grandparent: 2 + * - great grandparent+: ancestor level * 3 + */ + + if ($level === 0) { + $scoreDivider = 1; + } elseif ($level === 1) { + $scoreDivider = 2; + } else { + $scoreDivider = $level * 3; + } + + $currentScore = $ancestor->contentScore; + $ancestor->contentScore = $currentScore + ($contentScore / $scoreDivider); + } + } + /* - * Traverse the DOM from node to node, starting at the node passed in. - * Pass true for the second parameter to indicate this node itself - * (and its kids) are going away, and we want the next node over. - * - * Calling this in a loop will traverse the DOM depth-first. + * After we've calculated scores, loop through all of the possible + * candidate nodes we found and find the one with the highest score. + */ + + $topCandidates = []; + foreach ($candidates as $candidate) { + + /* + * Scale the final candidates score based on link density. Good content + * should have a relatively small link density (5% or less) and be mostly + * unaffected by this operation. + */ + + $candidate->contentScore = $candidate->contentScore * (1 - $candidate->getLinkDensity()); + + for ($i = 0; $i < $this->configuration->getMaxTopCandidates(); $i++) { + $aTopCandidate = isset($topCandidates[$i]) ? $topCandidates[$i] : null; + + if (!$aTopCandidate || $candidate->contentScore > $aTopCandidate->contentScore) { + array_splice($topCandidates, $i, 0, [$candidate]); + if (count($topCandidates) > $this->configuration->getMaxTopCandidates()) { + array_pop($topCandidates); + } + break; + } + } + } + + $topCandidate = isset($topCandidates[0]) ? $topCandidates[0] : null; + $parentOfTopCandidate = null; + + /* + * If we still have no top candidate, just use the body as a last resort. + * We also have to copy the body node so it is something we can modify. */ - // First check for kids if those aren't being ignored - if (!$ignoreSelfAndKids && $originalNode->node->firstChild) { - return new self($originalNode->node->firstChild); + if ($topCandidate === null || $topCandidate->nodeName === 'body') { + // Move all of the page's children into topCandidate + $topCandidate = new DOMDocument('1.0', 'utf-8'); + $topCandidate->encoding = 'UTF-8'; + $topCandidate->appendChild($topCandidate->createElement('div', '')); + $kids = $this->dom->getElementsByTagName('body')->item(0)->childNodes; + + // Cannot be foreached, don't ask me why. + for ($i = 0; $i < $kids->length; $i++) { + $import = $topCandidate->importNode($kids->item($i), true); + $topCandidate->firstChild->appendChild($import); + } + + // Candidate must be created using firstChild to grab the DOMElement instead of the DOMDocument. + $topCandidate = $topCandidate->firstChild; + } elseif ($topCandidate) { + // Find a better top candidate node if it contains (at least three) nodes which belong to `topCandidates` array + // and whose scores are quite closed with current `topCandidate` node. + $alternativeCandidateAncestors = []; + for ($i = 1; $i < count($topCandidates); $i++) { + if ($topCandidates[$i]->contentScore / $topCandidate->contentScore >= 0.75) { + array_push($alternativeCandidateAncestors, $topCandidates[$i]->getNodeAncestors(false)); + } + } + + $MINIMUM_TOPCANDIDATES = 3; + if (count($alternativeCandidateAncestors) >= $MINIMUM_TOPCANDIDATES) { + $parentOfTopCandidate = $topCandidate->parentNode; + while ($parentOfTopCandidate->nodeName !== 'body') { + $listsContainingThisAncestor = 0; + for ($ancestorIndex = 0; $ancestorIndex < count($alternativeCandidateAncestors) && $listsContainingThisAncestor < $MINIMUM_TOPCANDIDATES; $ancestorIndex++) { + $listsContainingThisAncestor += (int)in_array($parentOfTopCandidate, $alternativeCandidateAncestors[$ancestorIndex]); + } + if ($listsContainingThisAncestor >= $MINIMUM_TOPCANDIDATES) { + $topCandidate = $parentOfTopCandidate; + break; + } + $parentOfTopCandidate = $parentOfTopCandidate->parentNode; + } + } + + /* + * Because of our bonus system, parents of candidates might have scores + * themselves. They get half of the node. There won't be nodes with higher + * scores than our topCandidate, but if we see the score going *up* in the first + * few steps up the tree, that's a decent sign that there might be more content + * lurking in other places that we want to unify in. The sibling stuff + * below does some of that - but only if we've looked high enough up the DOM + * tree. + */ + + $parentOfTopCandidate = $topCandidate->parentNode; + $lastScore = $topCandidate->contentScore; + + // The scores shouldn't get too low. + $scoreThreshold = $lastScore / 3; + + /* @var DOMElement $parentOfTopCandidate */ + while ($parentOfTopCandidate->nodeName !== 'body') { + $parentScore = $parentOfTopCandidate->contentScore; + if ($parentScore < $scoreThreshold) { + break; + } + + if ($parentScore > $lastScore) { + // Alright! We found a better parent to use. + $topCandidate = $parentOfTopCandidate; + break; + } + $lastScore = $parentOfTopCandidate->contentScore; + $parentOfTopCandidate = $parentOfTopCandidate->parentNode; + } + + // If the top candidate is the only child, use parent instead. This will help sibling + // joining logic when adjacent content is actually located in parent's sibling node. + $parentOfTopCandidate = $topCandidate->parentNode; + while ($parentOfTopCandidate->nodeName !== 'body' && count($parentOfTopCandidate->getChildren(true)) === 1) { + $topCandidate = $parentOfTopCandidate; + $parentOfTopCandidate = $topCandidate->parentNode; + } } - // Then for siblings... - if ($originalNode->node->nextSibling) { - return new self($originalNode->node->nextSibling); + /* + * Now that we have the top candidate, look through its siblings for content + * that might also be related. Things like preambles, content split by ads + * that we removed, etc. + */ + + $articleContent = new DOMDocument('1.0', 'utf-8'); + $articleContent->createElement('div'); + + $siblingScoreThreshold = max(10, $topCandidate->contentScore * 0.2); + // Keep potential top candidate's parent node to try to get text direction of it later. + $parentOfTopCandidate = $topCandidate->parentNode; + $siblings = $parentOfTopCandidate->getChildren(); + + $hasContent = false; + + /** @var DOMElement $sibling */ + foreach ($siblings as $sibling) { + $append = false; + + if ($sibling === $topCandidate) { + $append = true; + } else { + $contentBonus = 0; + + // Give a bonus if sibling nodes and top candidates have the example same classname + if ($sibling->getAttribute('class') === $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') !== '') { + $contentBonus += $topCandidate->contentScore * 0.2; + } + if ($sibling->contentScore + $contentBonus >= $siblingScoreThreshold) { + $append = true; + } elseif ($sibling->nodeName === 'p') { + $linkDensity = $sibling->getLinkDensity(); + $nodeContent = $sibling->getTextContent(true); + + if (mb_strlen($nodeContent) > 80 && $linkDensity < 0.25) { + $append = true; + } elseif ($nodeContent && mb_strlen($nodeContent) < 80 && $linkDensity === 0 && preg_match('/\.( |$)/', $nodeContent)) { + $append = true; + } + } + } + + if ($append) { + $hasContent = true; + + if (!in_array(strtolower($sibling->nodeName), $this->alterToDIVExceptions)) { + /* + * We have a node that isn't a common block level element, like a form or td tag. + * Turn it into a div so it doesn't get filtered out later by accident. + */ + + $sibling = NodeUtility::setNodeTag($sibling, 'div'); + } + + $import = $articleContent->importNode($sibling, true); + $articleContent->appendChild($import); + + /* + * No node shifting needs to be check because when calling getChildren, an array is made with the + * children of the parent node, instead of using the DOMElement childNodes function, which, when used + * along with appendChild, would shift the nodes position and the current foreach will behave in + * unpredictable ways. + */ + } } - // And finally, move up the parent chain *and* find a sibling - // (because this is depth-first traversal, we will have already - // seen the parent nodes themselves). - do { - $originalNode = $originalNode->getParent(); - } while ($originalNode && !$originalNode->node->nextSibling); + $articleContent = $this->prepArticle($articleContent); + + if ($hasContent) { + // Find out text direction from ancestors of final top candidate. + $ancestors = array_merge([$parentOfTopCandidate, $topCandidate], $parentOfTopCandidate->getNodeAncestors()); + foreach ($ancestors as $ancestor) { + $articleDir = $ancestor->getAttribute('dir'); + if ($articleDir) { + $this->setDirection($articleDir); + break; + } + } - return ($originalNode) ? new self($originalNode->node->nextSibling) : $originalNode; + return $articleContent; + } else { + return false; + } } /** - * Compares nodes. Checks for tag name and text content. - * - * It's a replacement of the original JS code, which looked like this: - * - * $node1 == $node2 + * Cleans up the final article. * - * I'm not sure this works the same in PHP, so I created a mock function to check the actual content of the node. - * Should serve the same porpuse as the original comparison. + * @param DOMDocument $article * - * @param Readability $node1 - * @param Readability $node2 - * - * @return bool + * @return DOMDocument */ - public function compareNodes($node1, $node2) + public function prepArticle(DOMDocument $article) { - if ($node1->getTagName() !== $node2->getTagName()) { - return false; + $this->_cleanStyles($article); + $this->_clean($article, 'style'); + + // Check for data tables before we continue, to avoid removing items in + // those tables, which will often be isolated even though they're + // visually linked to other content-ful elements (text, images, etc.). + $this->_markDataTables($article); + + // Clean out junk from the article content + $this->_cleanConditionally($article, 'form'); + $this->_cleanConditionally($article, 'fieldset'); + $this->_clean($article, 'object'); + $this->_clean($article, 'embed'); + $this->_clean($article, 'h1'); + $this->_clean($article, 'footer'); + + // Clean out elements have "share" in their id/class combinations from final top candidates, + // which means we don't remove the top candidates even they have "share". + foreach ($article->childNodes as $child) { + $this->_cleanMatchedNodes($child, '/share/i'); } - if ($node1->getTextContent(true) !== $node2->getTextContent(true)) { - return false; + /* + * If there is only one h2 and its text content substantially equals article title, + * they are probably using it as a header and not a subheader, + * so remove it since we already extract the title separately. + */ + $h2 = $article->getElementsByTagName('h2'); + if ($h2->length === 1) { + $lengthSimilarRate = (mb_strlen($h2->item(0)->textContent) - mb_strlen($this->getTitle())) / max(mb_strlen($this->getTitle()), 1); + + if (abs($lengthSimilarRate) < 0.5) { + if ($lengthSimilarRate > 0) { + $titlesMatch = strpos($h2->item(0)->textContent, $this->getTitle()) !== false; + } else { + $titlesMatch = strpos($this->getTitle(), $h2->item(0)->textContent) !== false; + } + if ($titlesMatch) { + $this->_clean($article, 'h2'); + } + } } - return true; + $this->_clean($article, 'iframe'); + $this->_clean($article, 'input'); + $this->_clean($article, 'textarea'); + $this->_clean($article, 'select'); + $this->_clean($article, 'button'); + $this->_cleanHeaders($article); + + // Do these last as the previous stuff may have removed junk + // that will affect these + $this->_cleanConditionally($article, 'table'); + $this->_cleanConditionally($article, 'ul'); + $this->_cleanConditionally($article, 'div'); + + $this->_cleanExtraParagraphs($article); + + foreach (iterator_to_array($article->getElementsByTagName('br')) as $br) { + $next = $br->nextSibling; + if ($next && $next->nodeName === 'p') { + $br->parentNode->removeChild($br); + } + } + + return $article; } /** - * Replaces child node with a new one. + * Look for 'data' (as opposed to 'layout') tables, for which we use + * similar checks as + * https://dxr.mozilla.org/mozilla-central/rev/71224049c0b52ab190564d3ea0eab089a159a4cf/accessible/html/HTMLTableAccessible.cpp#920. * - * @param Readability $newNode + * @param DOMDocument $article + * + * @return void */ - public function replaceChild(self $newNode) + public function _markDataTables(DOMDocument $article) { - $this->node->parentNode->replaceChild($newNode->node, $this->node); + $tables = $article->getElementsByTagName('table'); + foreach ($tables as $table) { + /** @var DOMElement $table */ + $role = $table->getAttribute('role'); + if ($role === 'presentation') { + $table->setReadabilityDataTable(false); + continue; + } + $datatable = $table->getAttribute('datatable'); + if ($datatable == '0') { + $table->setReadabilityDataTable(false); + continue; + } + $summary = $table->getAttribute('summary'); + if ($summary) { + $table->setReadabilityDataTable(true); + continue; + } + + $caption = $table->getElementsByTagName('caption'); + if ($caption->length > 0 && $caption->item(0)->childNodes->length > 0) { + $table->setReadabilityDataTable(true); + continue; + } + + // If the table has a descendant with any of these tags, consider a data table: + foreach (['col', 'colgroup', 'tfoot', 'thead', 'th'] as $dataTableDescendants) { + if ($table->getElementsByTagName($dataTableDescendants)->length > 0) { + $table->setReadabilityDataTable(true); + continue 2; + } + } + + // Nested tables indicate a layout table: + if ($table->getElementsByTagName('table')->length > 0) { + $table->setReadabilityDataTable(false); + continue; + } + + $sizeInfo = $table->getRowAndColumnCount(); + if ($sizeInfo['rows'] >= 10 || $sizeInfo['columns'] > 4) { + $table->setReadabilityDataTable(true); + continue; + } + // Now just go by size entirely: + $table->setReadabilityDataTable($sizeInfo['rows'] * $sizeInfo['columns'] > 10); + } } /** - * Creates a new node based on the text content of the original node. - * - * @param Readability $originalNode - * @param string $tagName + * Remove the style attribute on every e and under. * - * @return Readability - */ - public function createNode(self $originalNode, $tagName) + * @param $node DOMDocument|DOMNode + **/ + public function _cleanStyles($node) { - $text = $originalNode->getTextContent(); - $newNode = $originalNode->node->ownerDocument->createElement($tagName, $text); + if (property_exists($node, 'tagName') && $node->tagName === 'svg') { + return; + } + + // Do not bother if there's no method to remove an attribute + if (method_exists($node, 'removeAttribute')) { + $presentational_attributes = ['align', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'frame', 'hspace', 'rules', 'style', 'valign', 'vspace']; + // Remove `style` and deprecated presentational attributes + foreach ($presentational_attributes as $presentational_attribute) { + $node->removeAttribute($presentational_attribute); + } - return new static($newNode); + $deprecated_size_attribute_elems = ['table', 'th', 'td', 'hr', 'pre']; + if (property_exists($node, 'tagName') && in_array($node->tagName, $deprecated_size_attribute_elems)) { + $node->removeAttribute('width'); + $node->removeAttribute('height'); + } + } + + $cur = $node->firstChild; + while ($cur !== null) { + $this->_cleanStyles($cur); + $cur = $cur->nextSibling; + } } /** - * Checks if the object is initialized. + * Clean out elements whose id/class combinations match specific string. * - * @return bool - */ - public function isInitialized() + * @param $node DOMElement Node to clean + * @param $regex string Match id/class combination. + * + * @return void + **/ + public function _cleanMatchedNodes($node, $regex) { - return $this->initialized; + $endOfSearchMarkerNode = NodeUtility::getNextNode($node, true); + $next = NodeUtility::getNextNode($node); + while ($next && $next !== $endOfSearchMarkerNode) { + if (preg_match($regex, sprintf('%s %s', $next->getAttribute('class'), $next->getAttribute('id')))) { + $next = NodeUtility::removeAndGetNext($next); + } else { + $next = NodeUtility::getNextNode($next); + } + } } /** - * Reloads the score stores in the data-readability tag. + * @param DOMDocument $article * - * @return int|bool + * @return void */ - public function reloadScore() + public function _cleanExtraParagraphs(DOMDocument $article) { - if (method_exists($this->node, 'getAttribute')) { - if ($this->node->hasAttribute('data-readability')) { - $this->initialized = true; - $score = $this->node->getAttribute('data-readability'); - $this->setContentScore($score); + $paragraphs = $article->getElementsByTagName('p'); + $length = $paragraphs->length; - return $score; + for ($i = 0; $i < $length; $i++) { + $paragraph = $paragraphs->item($length - 1 - $i); + + $imgCount = $paragraph->getElementsByTagName('img')->length; + $embedCount = $paragraph->getElementsByTagName('embed')->length; + $objectCount = $paragraph->getElementsByTagName('object')->length; + // At this point, nasty iframes have been removed, only remain embedded video ones. + $iframeCount = $paragraph->getElementsByTagName('iframe')->length; + $totalCount = $imgCount + $embedCount + $objectCount + $iframeCount; + + if ($totalCount === 0 && !preg_replace(NodeUtility::$regexps['onlyWhitespace'], '', $paragraph->textContent)) { + $paragraph->parentNode->removeChild($paragraph); } } - - return false; } /** - * Check if a given node has one of its ancestor tag name matching the - * provided one. - * - * @param Readability $node - * @param string $tagName - * @param int $maxDepth + * @param DOMDocument $article * - * @return bool + * @return void */ - public function hasAncestorTag(self $node, $tagName, $maxDepth = 3) + public function _cleanConditionally(DOMDocument $article, $tag) { - $depth = 0; - while ($node->getParent()) { - if ($maxDepth > 0 && $depth > $maxDepth) { - return false; + if (!$this->configuration->getCleanConditionally()) { + return; + } + + $isList = in_array($tag, ['ul', 'ol']); + + /* + * Gather counts for other typical elements embedded within. + * Traverse backwards so we can remove nodes at the same time + * without effecting the traversal. + */ + + $DOMNodeList = $article->getElementsByTagName($tag); + $length = $DOMNodeList->length; + for ($i = 0; $i < $length; $i++) { + /** @var $node DOMElement */ + $node = $DOMNodeList->item($length - 1 - $i); + + // First check if we're in a data table, in which case don't remove us. + if ($node->hasAncestorTag($node, 'table', -1) && $node->isReadabilityDataTable()) { + continue; } - if ($node->getParent()->tagNameEqualsTo($tagName)) { - return true; + + $weight = 0; + if ($this->configuration->getWeightClasses()) { + $weight = $node->getClassWeight(); } - $node = $node->getParent(); - $depth++; - } - return false; + if ($weight < 0) { + NodeUtility::removeNode($node); + continue; + } + + if (substr_count($node->getTextContent(), ',') < 10) { + /* + * If there are not very many commas, and the number of + * non-paragraph elements is more than paragraphs or other + * ominous signs, remove the element. + */ + + $p = $node->getElementsByTagName('p')->length; + $img = $node->getElementsByTagName('img')->length; + $li = $node->getElementsByTagName('li')->length - 100; + $input = $node->getElementsByTagName('input')->length; + + $embedCount = 0; + $embeds = $node->getElementsByTagName('embed'); + + foreach ($embeds as $embedNode) { + if (preg_match(NodeUtility::$regexps['videos'], $embedNode->C14N())) { + $embedCount++; + } + } + + $linkDensity = $node->getLinkDensity(); + $contentLength = mb_strlen($node->getTextContent(true)); + + $haveToRemove = + ($img > 1 && $p / $img < 0.5 && !$node->hasAncestorTag($node, 'figure')) || + (!$isList && $li > $p) || + ($input > floor($p / 3)) || + (!$isList && $contentLength < 25 && ($img === 0 || $img > 2) && !$node->hasAncestorTag($node, 'figure')) || + (!$isList && $weight < 25 && $linkDensity > 0.2) || + ($weight >= 25 && $linkDensity > 0.5) || + (($embedCount === 1 && $contentLength < 75) || $embedCount > 1); + + if ($haveToRemove) { + NodeUtility::removeNode($node); + } + } + } } /** - * Returns the children of the current node. + * Clean a node of all elements of type "tag". + * (Unless it's a youtube/vimeo video. People love movies.). * - * @param bool $filterEmptyDOMText Filter empty DOMText nodes? + * @param $article DOMDocument + * @param $tag string tag to clean * - * @return array - */ - public function getChildren($filterEmptyDOMText = false) + * @return void + **/ + public function _clean(DOMDocument $article, $tag) { - $ret = []; - /** @var \DOMNode $node */ - foreach ($this->node->childNodes as $node) { - if ($filterEmptyDOMText && $node->nodeName === '#text' && !trim($node->nodeValue)) { - continue; + $isEmbed = in_array($tag, ['object', 'embed', 'iframe']); + + $DOMNodeList = $article->getElementsByTagName($tag); + $length = $DOMNodeList->length; + for ($i = 0; $i < $length; $i++) { + $item = $DOMNodeList->item($length - 1 - $i); + + // Allow youtube and vimeo videos through as people usually want to see those. + if ($isEmbed) { + $attributeValues = []; + foreach ($item->attributes as $name => $value) { + $attributeValues[] = $value->nodeValue; + } + $attributeValues = implode('|', $attributeValues); + + // First, check the elements attributes to see if any of them contain youtube or vimeo + if (preg_match(NodeUtility::$regexps['videos'], $attributeValues)) { + continue; + } + + // Then check the elements inside this element for the same. + if (preg_match(NodeUtility::$regexps['videos'], $item->C14N())) { + continue; + } } - - $ret[] = new static($node); + NodeUtility::removeNode($item); } + } - return $ret; + /** + * Clean out spurious headers from an Element. Checks things like classnames and link density. + * + * @param DOMDocument $article + * + * @return void + **/ + public function _cleanHeaders(DOMDocument $article) + { + for ($headerIndex = 1; $headerIndex < 3; $headerIndex++) { + $headers = $article->getElementsByTagName('h' . $headerIndex); + /** @var $header DOMElement */ + foreach ($headers as $header) { + $weight = 0; + if ($this->configuration->getWeightClasses()) { + $weight = $header->getClassWeight(); + } + + if ($weight < 0) { + NodeUtility::removeNode($header); + } + } + } } /** - * Determines if a node has no content or it is just a bunch of dividing lines and/or whitespace. + * @param DOMDocument $article * - * @return bool + * @return DOMDocument */ - public function isElementWithoutContent() + public function postProcessContent(DOMDocument $article) { - return $this->node instanceof \DOMElement && - // /\x{00A0}|\s+/u TODO to be replaced with regexps array - mb_strlen(preg_replace('/\x{00A0}|\s+/u', '', $this->node->textContent)) === 0 && - ($this->node->childNodes->length === 0 || - $this->node->childNodes->length === $this->node->getElementsByTagName('br')->length + $this->node->getElementsByTagName('hr')->length + // Readability cannot open relative uris so we convert them to absolute uris. + if ($this->configuration->getFixRelativeURLs()) { + foreach (iterator_to_array($article->getElementsByTagName('a')) as $link) { + /** @var DOMElement $link */ + $href = $link->getAttribute('href'); + if ($href) { + // Replace links with javascript: URIs with text content, since + // they won't work after scripts have been removed from the page. + if (strpos($href, 'javascript:') === 0) { + $text = $article->createTextNode($link->textContent); + $link->parentNode->replaceChild($text, $link); + } else { + $link->setAttribute('href', $this->toAbsoluteURI($href)); + } + } + } + + foreach ($article->getElementsByTagName('img') as $img) { + /** @var DOMElement $img */ /* - * Special DOMDocument case: We also need to count how many DOMText we have inside the node. - * If there's an empty tag with an space inside and a BR (for example "<p> <br/></p>) counting only BRs and - * HRs will will say that the example has 2 nodes, instead of one. This happens because in DOMDocument, - * DOMTexts are also nodes (which doesn't happen in JS). So we need to also count how many DOMText we - * are dealing with (And at this point we know they are empty or are just whitespace, because of the - * mb_strlen in this chain of checks). + * Extract all possible sources of img url and select the first one on the list. */ - + count(array_filter(iterator_to_array($this->node->childNodes), function ($child) { - return $child instanceof \DOMText; - })) + $url = [ + $img->getAttribute('src'), + $img->getAttribute('data-original'), + $img->getAttribute('data-url') + ]; + + $src = array_filter($url); + $src = reset($src); + if ($src) { + $img->setAttribute('src', $this->toAbsoluteURI($src)); + } + } + } + + return $article; + } - ); + /** + * @return null|string + */ + public function __toString() + { + return sprintf('<h1>%s</h1>%s', $this->getTitle(), $this->getContent()); + } + + /** + * @return string|null + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + */ + protected function setTitle($title) + { + $this->title = $title; + } + + /** + * @return string|null + */ + public function getContent() + { + return $this->content; + } + + /** + * @param string $content + */ + protected function setContent($content) + { + $this->content = $content; + } + + /** + * @return null|string + */ + public function getExcerpt() + { + return $this->excerpt; + } + + /** + * @param null|string $excerpt + */ + public function setExcerpt($excerpt) + { + $this->excerpt = $excerpt; + } + + /** + * @return string|null + */ + public function getImage() + { + return $this->image; + } + + /** + * @param string $image + */ + protected function setImage($image) + { + $this->image = $image; + } + + /** + * @return string|null + */ + public function getAuthor() + { + return $this->author; + } + + /** + * @param string $author + */ + protected function setAuthor($author) + { + $this->author = $author; + } + + /** + * @return null|string + */ + public function getDirection() + { + return $this->direction; + } + + /** + * @param null|string $direction + */ + public function setDirection($direction) + { + $this->direction = $direction; } } diff --git a/src/ReadabilityInterface.php b/src/ReadabilityInterface.php deleted file mode 100644 index 0dee01b..0000000 --- a/src/ReadabilityInterface.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php - -namespace andreskrey\Readability; - -use League\HTMLToMarkdown\ElementInterface; - -interface ReadabilityInterface extends ElementInterface -{ - /** - * @param string $value - * - * @return bool - */ - public function tagNameEqualsTo($value); - - /** - * @return int - */ - public function getNodeAncestors(); - - /** - * @return Readability|null - */ - public function getAllLinks(); - - /** - * @return int - */ - public function getContentScore(); - - /** - * @return Readability - */ - public function initializeNode(); - - /** - * @return int - */ - public function getClassWeight(); - - /** - * @param int $score - * - * @return int - */ - public function setContentScore($score); - - /** - * @param bool $normalize Normalize white space? - * - * @return string - */ - public function getTextContent($normalize); - - /** - * @param string $value - */ - public function setNodeTag($value); - - /** - * @return \DOMNode - */ - public function getDOMNode(); - - /** - * @param Readability $node - * - * @return Readability - */ - public function removeAndGetNext($node); - - /** - * @param Readability $originalNode - * @param bool $ignoreSelfAndKids - * - * @return Readability - */ - public function getNextNode($originalNode, $ignoreSelfAndKids = false); - - /** - * @param Readability $node1 - * @param Readability $node2 - * - * @return bool - */ - public function compareNodes($node1, $node2); - - /** - * @param Readability $newNode - */ - public function replaceChild(Readability $newNode); -} diff --git a/test/HTMLParserTest.php b/test/HTMLParserTest.php deleted file mode 100644 index 2aafa65..0000000 --- a/test/HTMLParserTest.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php - -namespace andreskrey\Readability\Test; - -use andreskrey\Readability\HTMLParser; - -class HTMLParserTest extends \PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getSamplePages - */ - public function testHTMLParserParsesHTML($html, $expectedResult, $expectedMetadata, $config, $expectedImages) - { - $options = ['originalURL' => 'http://fakehost/test/test.html', - 'fixRelativeURLs' => true, - 'substituteEntities' => true, - ]; - - if ($config) { - $options = array_merge($options, $config); - } - - $readability = new HTMLParser($options); - $result = $readability->parse($html); - - $this->assertEquals($expectedResult, $result['html']); - } - - /** - * @dataProvider getSamplePages - */ - public function testHTMLParserParsesImages($html, $expectedResult, $expectedMetadata, $config, $expectedImages) - { - $options = ['originalURL' => 'http://fakehost/test/test.html', - 'fixRelativeURLs' => true, - 'substituteEntities' => true, - ]; - - if ($config) { - $options = array_merge($options, $config); - } - - $readability = new HTMLParser($options); - $result = $readability->parse($html); - $this->assertEquals($expectedImages, json_encode($result['images'])); - } - - public function getSamplePages() - { - $path = pathinfo(__FILE__, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'test-pages'; - $testPages = scandir($path); - if (in_array('.DS_Store', $testPages)) { - unset($testPages[array_search('.DS_Store', $testPages)]); - } - - $pages = []; - - foreach (array_slice($testPages, 2) as $testPage) { - $source = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'source.html'); - $expectedHTML = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected.html'); - $expectedMetadata = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected-metadata.json'); - $expectedImages = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected-images.json'); - - $config = null; - if (file_exists($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'config.json')) { - $config = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'config.json'); - if ($config) { - $config = json_decode($config, true); - } - } - - $pages[$testPage] = [$source, $expectedHTML, $expectedMetadata, $config, $expectedImages]; - } - - return $pages; - } -} diff --git a/test/ReadabilityTest.php b/test/ReadabilityTest.php index ec96ef4..e074983 100644 --- a/test/ReadabilityTest.php +++ b/test/ReadabilityTest.php @@ -2,11 +2,119 @@ namespace andreskrey\Readability\Test; +use andreskrey\Readability\Configuration; +use andreskrey\Readability\ParseException; +use andreskrey\Readability\Readability; + class ReadabilityTest extends \PHPUnit_Framework_TestCase { - public function testDummy() + /** + * @dataProvider getSamplePages + */ + public function testReadabilityParsesHTML($html, $expectedResult, $expectedMetadata, $config, $expectedImages) + { + $options = ['originalURL' => 'http://fakehost/test/test.html', + 'FixRelativeURLs' => true, + 'SubstituteEntities' => true, + 'ArticleByLine' => true + ]; + + if ($config === null || $expectedMetadata === null) { + $this->markTestSkipped('Wrong test configuration'); + } + + if ($config) { + $options = array_merge($config, $options); + } + + $configuration = new Configuration(); + + foreach ($options as $key => $value) { + $name = 'set' . $key; + $configuration->$name($value); + } + + $readability = new Readability($configuration); + $readability->parse($html); + + $this->assertEquals($expectedResult, $readability->getContent()); + + foreach ($expectedMetadata as $key => $metadata) { + $function = 'get' . $key; + $this->assertEquals($metadata, $readability->$function()); + } + } + + /** + * @dataProvider getSamplePages + */ + public function testHTMLParserParsesImages($html, $expectedResult, $expectedMetadata, $config, $expectedImages) + { + $options = ['originalURL' => 'http://fakehost/test/test.html', + 'fixRelativeURLs' => true, + 'substituteEntities' => true, + ]; + + if ($config) { + $options = array_merge($options, $config); + } + $configuration = new Configuration(); + + foreach ($options as $key => $value) { + $name = 'set' . $key; + $configuration->$name($value); + } + + $readability = new Readability($configuration); + $readability->parse($html); + + $this->assertEquals($expectedImages, json_encode($readability->getImages())); + } + + public function getSamplePages() + { + $path = pathinfo(__FILE__, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'test-pages'; + $testPages = scandir($path); + if (in_array('.DS_Store', $testPages)) { + unset($testPages[array_search('.DS_Store', $testPages)]); + } + + $pages = []; + + foreach (array_slice($testPages, 2) as $testPage) { + $source = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'source.html'); + $expectedHTML = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected.html'); + $expectedImages = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected-images.json'); + + $expectedMetadata = json_decode(file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'expected-metadata.json')); + + $config = false; + if (file_exists($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'config.json')) { + $config = file_get_contents($path . DIRECTORY_SEPARATOR . $testPage . DIRECTORY_SEPARATOR . 'config.json'); + if ($config) { + $config = json_decode($config, true); + } + } + + $pages[$testPage] = [$source, $expectedHTML, $expectedMetadata, $config, $expectedImages]; + } + + return $pages; + } + + public function testReadabilityThrowsExceptionWithMalformedHTML() + { + $parser = new Readability(new Configuration()); + $this->expectException(ParseException::class); + $this->expectExceptionMessage('Invalid or incomplete HTML.'); + $parser->parse('<html>'); + } + + public function testReadabilityThrowsExceptionWithUnparseableHTML() { - //TODO - $this->assertEquals(true, true); + $parser = new Readability(new Configuration()); + $this->expectException(ParseException::class); + $this->expectExceptionMessage('Could not parse text.'); + $parser->parse('<html><body><p>hello</p></body></html>'); } } diff --git a/test/test-pages/001/config.json b/test/test-pages/001/config.json new file mode 100644 index 0000000..0ac6816 --- /dev/null +++ b/test/test-pages/001/config.json @@ -0,0 +1,3 @@ +{ + "ArticleByLine": true +}
\ No newline at end of file diff --git a/test/test-pages/001/expected-metadata.json b/test/test-pages/001/expected-metadata.json index ee91098..c58545d 100644 --- a/test/test-pages/001/expected-metadata.json +++ b/test/test-pages/001/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Get your Frontend JavaScript Code Covered | Code", - "byline": "Nicolas Perriault —", - "excerpt": "Nicolas Perriault's homepage.", - "readerable": true + "Title": "Get your Frontend JavaScript Code Covered | Code", + "Author": "Nicolas Perriault —", + "Excerpt": "Nicolas Perriault's homepage." } diff --git a/test/test-pages/002/expected-metadata.json b/test/test-pages/002/expected-metadata.json index 9b020e4..210e551 100644 --- a/test/test-pages/002/expected-metadata.json +++ b/test/test-pages/002/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "This API is so Fetching! ✩ Mozilla Hacks – the Web developer blog", - "byline": "Nikhil Marathe", - "excerpt": "For more than a decade the Web has used XMLHttpRequest (XHR) to achieve asynchronous requests in JavaScript. While very useful, XHR is not a very ...", - "readerable": true + "Title": "This API is so Fetching! ✩ Mozilla Hacks – the Web developer blog", + "Author": "Nikhil Marathe", + "Excerpt": "For more than a decade the Web has used XMLHttpRequest (XHR) to achieve asynchronous requests in JavaScript. While very useful, XHR is not a very ..." } diff --git a/test/test-pages/ars-1/config.json b/test/test-pages/ars-1/config.json index 6441edf..0ac6816 100644 --- a/test/test-pages/ars-1/config.json +++ b/test/test-pages/ars-1/config.json @@ -1,3 +1,3 @@ { - "articleByLine": true + "ArticleByLine": true }
\ No newline at end of file diff --git a/test/test-pages/ars-1/expected-metadata.json b/test/test-pages/ars-1/expected-metadata.json index 5d06095..8b3d493 100644 --- a/test/test-pages/ars-1/expected-metadata.json +++ b/test/test-pages/ars-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Just-released Minecraft exploit makes it easy to crash game servers", - "byline": "by Dan Goodin - Apr 16, 2015 8:02 pm UTC", - "excerpt": "Two-year-old bug exposes thousands of servers to crippling attack.", - "readerable": true + "Title": "Just-released Minecraft exploit makes it easy to crash game servers", + "Author": "by Dan Goodin - Apr 16, 2015 8:02 pm UTC", + "Excerpt": "Two-year-old bug exposes thousands of servers to crippling attack." } diff --git a/test/test-pages/base-url/expected-metadata.json b/test/test-pages/base-url/expected-metadata.json index 0e28053..b26e5cf 100644 --- a/test/test-pages/base-url/expected-metadata.json +++ b/test/test-pages/base-url/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Base URL test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": false + "Title": "Base URL test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/basic-tags-cleaning/expected-metadata.json b/test/test-pages/basic-tags-cleaning/expected-metadata.json index baa8c73..f3292d5 100644 --- a/test/test-pages/basic-tags-cleaning/expected-metadata.json +++ b/test/test-pages/basic-tags-cleaning/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Basic tag cleaning test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua.", - "readerable": true + "Title": "Basic tag cleaning test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua." } diff --git a/test/test-pages/bbc-1/expected-metadata.json b/test/test-pages/bbc-1/expected-metadata.json index 028bc58..7569b8f 100644 --- a/test/test-pages/bbc-1/expected-metadata.json +++ b/test/test-pages/bbc-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Obama admits US gun laws are his 'biggest frustration'", - "byline": null, - "excerpt": "President Barack Obama tells the BBC his failure to pass", - "readerable": true + "Title": "Obama admits US gun laws are his 'biggest frustration'", + "Author": null, + "Excerpt": "President Barack Obama tells the BBC his failure to pass" } diff --git a/test/test-pages/blogger/expected-metadata.json b/test/test-pages/blogger/expected-metadata.json index 69c631c..f912e3b 100644 --- a/test/test-pages/blogger/expected-metadata.json +++ b/test/test-pages/blogger/expected-metadata.json @@ -1,7 +1,5 @@ { - "title": "Open Verilog flow for Silego GreenPak4 programmable logic devices", - "byline": null, - "dir": "ltr", - "excerpt": "I've written a couple of posts in the past few months but they were all for", - "readerable": true + "Title": "Open Verilog flow for Silego GreenPak4 programmable logic devices", + "Author": null, + "Excerpt": "I've written a couple of posts in the past few months but they were all for the blog at work so I figured I'm long overdue for one on Silic..." } diff --git a/test/test-pages/breitbart/config.json b/test/test-pages/breitbart/config.json index 6441edf..0ac6816 100644 --- a/test/test-pages/breitbart/config.json +++ b/test/test-pages/breitbart/config.json @@ -1,3 +1,3 @@ { - "articleByLine": true + "ArticleByLine": true }
\ No newline at end of file diff --git a/test/test-pages/breitbart/expected-metadata.json b/test/test-pages/breitbart/expected-metadata.json index c5a2d02..2b968e7 100644 --- a/test/test-pages/breitbart/expected-metadata.json +++ b/test/test-pages/breitbart/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "'Neutral' Snopes Fact-Checker David Emery: 'Are There Any Un-Angry Trump Supporters?'", - "byline": "by Lucas Nolan22 Dec 2016651", - "dir": null, - "excerpt": "Snopes fact checker and staff writer David Emery posted to Twitter asking if there were “any un-angry Trump supporters?”", - "readerable": true + "Title": "'Neutral' Snopes Fact-Checker David Emery: 'Are There Any Un-Angry Trump Supporters?'", + "Author": "by Lucas Nolan22 Dec 2016651", + "Direction": null, + "Excerpt": "Snopes fact checker and staff writer David Emery posted to Twitter asking if there were “any un-angry Trump supporters?”" } diff --git a/test/test-pages/bug-1255978/expected-metadata.json b/test/test-pages/bug-1255978/expected-metadata.json index 7df5a41..0acbbdf 100644 --- a/test/test-pages/bug-1255978/expected-metadata.json +++ b/test/test-pages/bug-1255978/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "The seven secrets that hotel owners don't want you to know", - "byline": "Hazel Sheffield", - "dir": null, - "excerpt": "Most people go to hotels for the pleasure of sleeping in a giant bed with clean white sheets and waking up to fresh towels in the morning. But those towels and sheets might not be as clean as they look, according to the hotel bosses that responded to an online thread about the things hotel owners don’t want you to know.", - "readerable": true + "Title": "The seven secrets that hotel owners don't want you to know", + "Author": "Hazel Sheffield", + "Direction": null, + "Excerpt": "Most people go to hotels for the pleasure of sleeping in a giant bed with clean white sheets and waking up to fresh towels in the morning. But those towels and sheets might not be as clean as they look, according to the hotel bosses that responded to an online thread about the things hotel owners don’t want you to know." } diff --git a/test/test-pages/buzzfeed-1/expected-metadata.json b/test/test-pages/buzzfeed-1/expected-metadata.json index 8f171df..d5eca27 100644 --- a/test/test-pages/buzzfeed-1/expected-metadata.json +++ b/test/test-pages/buzzfeed-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Student Dies After Diet Pills She Bought Online \"Burned Her Up From Within\"", - "byline": "Mark Di Stefano", - "excerpt": "An inquest into Eloise Parry's death has been adjourned until July...", - "readerable": true + "Title": "Student Dies After Diet Pills She Bought Online \"Burned Her Up From Within\"", + "Author": "Mark Di Stefano", + "Excerpt": "An inquest into Eloise Parry's death has been adjourned until July..." } diff --git a/test/test-pages/challenges/expected-metadata.json b/test/test-pages/challenges/expected-metadata.json index e69de29..3b8b0a4 100644 --- a/test/test-pages/challenges/expected-metadata.json +++ b/test/test-pages/challenges/expected-metadata.json @@ -0,0 +1,3 @@ +{ + "Title": "Les motivations du tueur de Las Vegas demeurent floues" +} diff --git a/test/test-pages/clean-links/expected-metadata.json b/test/test-pages/clean-links/expected-metadata.json index c7b4e36..7993d55 100644 --- a/test/test-pages/clean-links/expected-metadata.json +++ b/test/test-pages/clean-links/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Bartleby the Scrivener Web Study Text", - "byline": null, - "excerpt": "Ere introducing the scrivener, as he first appeared to me, it is fit \n I make some mention of myself, my employees, my business, my chambers, \n and general surroundings; because some such description is indispensable \n to an adequate understanding of the chief character about to be presented.", - "readerable": true + "Title": "Bartleby the Scrivener Web Study Text", + "Author": null, + "Excerpt": "Ere introducing the scrivener, as he first appeared to me, it is fit \n I make some mention of myself, my employees, my business, my chambers, \n and general surroundings; because some such description is indispensable \n to an adequate understanding of the chief character about to be presented." } diff --git a/test/test-pages/cnet/expected-metadata.json b/test/test-pages/cnet/expected-metadata.json index 4f99537..744652d 100644 --- a/test/test-pages/cnet/expected-metadata.json +++ b/test/test-pages/cnet/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Zuckerberg offers peek at Facebook's acquisition strategies", - "byline": "Steven Musil", - "dir": null, - "excerpt": "Facebook CEO says be a friend and have a shared vision, but scare them when you have to and move fast.", - "readerable": true + "Title": "Zuckerberg offers peek at Facebook's acquisition strategies", + "Author": "Steven Musil", + "Direction": null, + "Excerpt": "Facebook CEO says be a friend and have a shared vision, but scare them when you have to and move fast." } diff --git a/test/test-pages/cnn/expected-metadata.json b/test/test-pages/cnn/expected-metadata.json index 723989b..d88d406 100644 --- a/test/test-pages/cnn/expected-metadata.json +++ b/test/test-pages/cnn/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "The 'birth lottery' and economic mobility", - "byline": "Ahiza Garcia", - "dir": null, - "excerpt": "A recently-released report on poverty and inequality found that the U.S. ranks the lowest among countries with welfare states.", - "readerable": true + "Title": "The 'birth lottery' and economic mobility", + "Author": "Ahiza Garcia", + "Direction": null, + "Excerpt": "A recently-released report on poverty and inequality found that the U.S. ranks the lowest among countries with welfare states." } diff --git a/test/test-pages/comment-inside-script-parsing/expected-metadata.json b/test/test-pages/comment-inside-script-parsing/expected-metadata.json index d3857ba..e5ad501 100644 --- a/test/test-pages/comment-inside-script-parsing/expected-metadata.json +++ b/test/test-pages/comment-inside-script-parsing/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Test script parsing", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua.", - "readerable": true + "Title": "Test script parsing", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua." } diff --git a/test/test-pages/daringfireball-1/expected-metadata.json b/test/test-pages/daringfireball-1/expected-metadata.json index 18f4c6b..477261f 100644 --- a/test/test-pages/daringfireball-1/expected-metadata.json +++ b/test/test-pages/daringfireball-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Daring Fireball: Colophon", - "byline": null, - "excerpt": "Daring Fireball is written and produced by John Gruber.", - "readerable": true + "Title": "Daring Fireball: Colophon", + "Author": null, + "Excerpt": "Daring Fireball is written and produced by John Gruber." } diff --git a/test/test-pages/ehow-1/expected-metadata.json b/test/test-pages/ehow-1/expected-metadata.json index 0299347..6cfa7b0 100644 --- a/test/test-pages/ehow-1/expected-metadata.json +++ b/test/test-pages/ehow-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "How to Build a Terrarium (with Pictures)", - "byline": "Lucy Akins", - "excerpt": "How to Build a Terrarium. Glass cloche terrariums are not only appealing to the eye, but they also preserve a bit of nature in your home and serve as a simple, yet beautiful, piece of art. Closed terrariums are easy to care for, as they retain much of their own moisture and provide a warm environment with a consistent level of humidity. You...", - "readerable": true + "Title": "How to Build a Terrarium (with Pictures)", + "Author": "Lucy Akins", + "Excerpt": "How to Build a Terrarium. Glass cloche terrariums are not only appealing to the eye, but they also preserve a bit of nature in your home and serve as a simple, yet beautiful, piece of art. Closed terrariums are easy to care for, as they retain much of their own moisture and provide a warm environment with a consistent level of humidity. You..." } diff --git a/test/test-pages/ehow-2/expected-metadata.json b/test/test-pages/ehow-2/expected-metadata.json index 68b0560..653912e 100644 --- a/test/test-pages/ehow-2/expected-metadata.json +++ b/test/test-pages/ehow-2/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "How to Throw a Graduation Party on a Budget (with Pictures)", - "byline": "Gina Roberts-Grey", - "excerpt": "How to Throw a Graduation Party on a Budget. Graduation parties are a great way to commemorate the years of hard work teens and college co-eds devote to education. They’re also costly for mom and dad.The average cost of a graduation party in 2013 was a whopping $1,200, according to Graduationparty.com; $700 of that was allocated for food....", - "readerable": true + "Title": "How to Throw a Graduation Party on a Budget (with Pictures)", + "Author": "Gina Roberts-Grey", + "Excerpt": "How to Throw a Graduation Party on a Budget. Graduation parties are a great way to commemorate the years of hard work teens and college co-eds devote to education. They’re also costly for mom and dad.The average cost of a graduation party in 2013 was a whopping $1,200, according to Graduationparty.com; $700 of that was allocated for food...." } diff --git a/test/test-pages/embedded-videos/expected-metadata.json b/test/test-pages/embedded-videos/expected-metadata.json index 0d38424..46e3094 100644 --- a/test/test-pages/embedded-videos/expected-metadata.json +++ b/test/test-pages/embedded-videos/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Embedded videos test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": false + "Title": "Embedded videos test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/extract-img-url-from-other-sources/expected-images.json b/test/test-pages/extract-img-url-from-other-sources/expected-images.json new file mode 100644 index 0000000..7bc23b2 --- /dev/null +++ b/test/test-pages/extract-img-url-from-other-sources/expected-images.json @@ -0,0 +1 @@ +{"0":"https:\/\/www.infobae.com\/new-resizer\/shi8E0F5ldd8a7vtvFaJomRURqU=\/1200x0\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/12\/01154429\/Rugbier-golpeado-1920.jpg","1":"https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/10\/04135319\/logo-gente-chico.png","2":"https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/10\/13163150\/parati-chico-quick.png","3":"https:\/\/www.infobae.com\/new-resizer\/IL3kQvq3jxh8MdYbOw9b15XuxPc=\/0x200\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-authors\/mauricio_luna.jpg","4":"https:\/\/www.infobae.com\/new-resizer\/kDRrc7yzsAnENGeWAxXxNTL7aN4=\/0x200\/filters:quality(100)\/s3.amazonaws.com\/arc-authors\/infobae\/9e4a86e5-0832-4826-8e82-fbe41f1d1be7.jpg","5":"http:\/\/www.infobae.com\/resizer\/?op=resize&url=https:\/\/s3.amazonaws.com\/wapopartners.com\/infobae-wp\/wp-content\/uploads\/2016\/03\/29190548\/infobae.png&mode=crop&h=24&q=75&token=bar","6":"https:\/\/www.infobae.com\/new-resizer\/R1RvY0B8ow2txSDcg233vSkrhEs=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/11\/29180028\/leonardo-mercado-ympa-banda-del-millon-02.jpg","7":"https:\/\/www.infobae.com\/new-resizer\/N_NvH9Omw_814ujN5txdgAG57D8=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2016\/06\/04180802\/asesinato-Mario-Agust%C3%ADn-Salto-1920-4.jpg","8":"https:\/\/www.infobae.com\/new-resizer\/9Ms00i-xfAU9gbJSgqTnoF9zFkA=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/11\/30160846\/Sonia-Sanchez-8.jpg","9":"https:\/\/www.infobae.com\/new-resizer\/RUk9KmlnV9ross113tr-1jXTx5U=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2016\/08\/17135104\/luli.jpg","10":"https:\/\/www.infobae.com\/new-resizer\/h3EUdxrpI48Hz9UOkeb3mxyE12I=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/09\/19112338\/NEUQUEN2.jpg","11":"https:\/\/www.infobae.com\/new-resizer\/kUIgIYssfcsPB48GUiOIDg2AxuU=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/11\/30184950\/Erzs%C3%A9bet-Isabel-Bathory.jpg","12":"https:\/\/www.infobae.com\/new-resizer\/2QIoCOtACpHy-5EpMxIDP4pDzjY=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/12\/02094537\/albinen-suiza-1920-4.jpg","13":"https:\/\/www.infobae.com\/new-resizer\/V0Xe13tXim1KgOjta3O03N_WTD0=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2016\/08\/31084830\/063_592638926.jpg","14":"https:\/\/www.infobae.com\/new-resizer\/akM-LtOKQ5lEGQkcupgQSGBNDWQ=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/11\/30120001\/pre-fama-famosos-partida-301117.jpg","15":"https:\/\/www.infobae.com\/new-resizer\/2PT_ACjXRhuL5RpF8JEBizadhSI=\/130x130\/filters:quality(100)\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/12\/01153823\/Suicidio-familiar-Mexico-1.jpg","16":"http:\/\/www.infobae.com\/resizer\/?op=resize&url=https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2016\/09\/22145201\/closed-envelope.png&mode=crop&h=24&q=75&token=bar","18":"https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/10\/02173813\/gente-25.png","19":"https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/05\/22094331\/the-washington-post_logo.png","20":"http:\/\/www.infobae.com\/resizer\/?op=resize&url=https:\/\/s3.amazonaws.com\/arc-wordpress-client-uploads\/infobae-wp\/wp-content\/uploads\/2017\/09\/14154721\/logo_vice.png&mode=crop&h=24&q=75&token=bar"}
\ No newline at end of file diff --git a/test/test-pages/extract-img-url-from-other-sources/expected-metadata.json b/test/test-pages/extract-img-url-from-other-sources/expected-metadata.json new file mode 100644 index 0000000..e8b24b1 --- /dev/null +++ b/test/test-pages/extract-img-url-from-other-sources/expected-metadata.json @@ -0,0 +1,5 @@ +{ + "Title": "Una patota de varones atacó a un rugbier gay: \"Te vamos a matar por puto\"", + "Author": "Por Mauricio Luna 1 de diciembre de 2017", + "Excerpt": "Jonathan Castellari fue salvajemente golpeado en un local de comidas rápidas, mientras esperaba el desayuno junto a un amigo. Podría perder un ojo" +} diff --git a/test/test-pages/extract-img-url-from-other-sources/expected.html b/test/test-pages/extract-img-url-from-other-sources/expected.html new file mode 100644 index 0000000..5d1afcc --- /dev/null +++ b/test/test-pages/extract-img-url-from-other-sources/expected.html @@ -0,0 +1 @@ +<div class="article-body article-body-elements" id="article-body"> <div id="article-content"> <div class="row"> <figure class="element element-image col-xs-12"><div class="single-image"> <img alt="Jonathan Castellari tiene 25 años y fue golpeado por una patota de 8 hombres" class="image-lazy" data-original="https://www.infobae.com/new-resizer/b_LU5bsrOM_BmZtNMzegvdNoPNE=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" height="422.32142857142856" id="QU6XDTECU5EDVI4HBTME4PLIOQ" src="https://www.infobae.com/new-resizer/b_LU5bsrOM_BmZtNMzegvdNoPNE=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg" width="750"></img></div> <figcaption class=""><span class="credit">Jonathan Castellari tiene 25 años y fue golpeado por una patota de 8 hombres</span> </figcaption></figure></div> <div class="row"> <p class="element element-paragraph"> Eran casi las 6:30 de la mañana. Jonathan Castellari, de 25 años, volvía de bailar junto a Sebastián, su amigo. Les pareció una buena idea detenerse en el Mc Donald's de Avenida Córdoba al 3100 con el objetivo de desayunar y continuar el viaje hasta sus hogares. Mientras esperaban la comida, un grupo de 8 chicos de entre 20 y 25 años ingresó al local con el mismo objetivo, aunque adoptaron otro plan: mirarlos fijamente, reírse de ellos y hacer chistes sobre la sexualidad de ambos.</p> </div> <div class="row"> <p class="element element-paragraph"> Sebastián relató a<strong> Infobae:</strong> "Estábamos esperando nuestro pedido, haciéndonos chistes, riéndonos de lo sucedido durante la noche. Hablábamos entre nosotros. En ese momento entró un grupo de 8 chicos, de contextura grande, y notamos que estaban alcoholizados. Nos miraban, hacían chistes, se reían de nosotros. Fue ahí cuando decidimos salir con Jonathan a fumar un cigarrillo y esperar que se fueran. <strong>Él salió primero y vi que uno de estos pibes lo abrazó y se lo llevó. Instantáneamente se metieron los demás a pegarle. Le pegaron mucho.</strong> Quise pararlos y no pude. Ligué yo también, pero nada en comparación a lo que sufrió Jonathan. Cuando lo soltaron lo agarré como pude y justo una enfermera del Sanatorio Güemes (está a dos cuadras del local) estaba tomando un café y le dio los primeros auxilios".</p> </div> <div class="row"> <figure class="element element-image col-xs-12"><div class="single-image"> <img alt="" class="image-lazy" data-original="https://www.infobae.com/new-resizer/PUJQSwJZOtaetM7tXKqic4Ib1Wg=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161934/Jonathan-Castellani-SF-2.jpg" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" height="937.7289377289377" id="NH7MLFDU4JH4VOSMUUN6JPRYUQ" src="https://www.infobae.com/new-resizer/PUJQSwJZOtaetM7tXKqic4Ib1Wg=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161934/Jonathan-Castellani-SF-2.jpg" width="750"></img></div> <figcaption class=""><span class="credit"></span> </figcaption></figure></div> <div class="row"> <p class="element element-paragraph"> "Fuimos a verlo recién, no paraba de llorar y de decirnos que le pegaron por puto", dijo a <strong>Infobae</strong> María Rachid, titular del Instituto contra la Discriminación de la Defensoría del Pueblo CABA. "Lamentablemente su situación es delicada. Recién nos informaron que lo van a intervenir quirúrgicamente porque <strong>podría perder un ojo</strong>".</p> </div> <div class="row"> <p class="element element-paragraph"> Como Jonathan no conoce a los agresores, desde la Defensoría y la Federación LGBT se comunicaron con autoridades del Ministerio de Seguridad para que soliciten las cámaras de seguridad del Mc Donald's, del sanatorio Güemes y de otros negocios de la cuadra para poder identificarlos.</p> </div> <div class="row"> <figure class="element element-image col-xs-12"><div class="single-image"> <img alt="" class="image-lazy" data-original="https://www.infobae.com/new-resizer/yS5kphJxw_CBn1mycqbcrMjoNmQ=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163101/JonathanGay2.jpg" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" height="422.32142857142856" id="O7QMD7FTTNCIJOVETW7KYJVVDA" src="https://www.infobae.com/new-resizer/yS5kphJxw_CBn1mycqbcrMjoNmQ=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163101/JonathanGay2.jpg" width="750"></img></div> <figcaption class=""><span class="credit"></span> </figcaption></figure></div> <div class="row"> <p class="element element-paragraph"> Gastón Llopart, abogado de Sebastián, le detalló a <strong>Infobae</strong> que Jonathan está "próximo a recibir una intervención quirúrgica, ya que<strong> tuvo fractura en el hueso del pómulo derecho de su rostro. Sebastián llamó al 911 dos veces y no fueron.</strong> Me contaron que los agresores los siguieron hasta el sanatorio mientras los insultaban: la gente de seguridad tuvo que echarlos".</p> </div> <div class="row"> <p class="element element-paragraph"> Llopart agregó que la patota, <strong>mientras lo golpeaban, le gritaba: "Te vamos a matar por puto"</strong>. La familia de Jonathan está en el sanatorio a la espera de la intervención quirúrgica. Llopart dijo que "harán la denuncia el lunes por la mañana, cuando existan mayores precisiones de lo ocurrido".</p> </div> <div class="row"> <figure class="element element-image col-xs-12"><div class="single-image"> <img alt="" class="image-lazy" data-original="https://www.infobae.com/new-resizer/cFidtpanVMHP25zNoWF78I4qjMA=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161927/Jonathan-Castellani-1920.jpg" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" height="422.32142857142856" id="7BCY2NEI6ZADBA3TRJGQC6R3BU" src="https://www.infobae.com/new-resizer/cFidtpanVMHP25zNoWF78I4qjMA=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161927/Jonathan-Castellani-1920.jpg" width="750"></img></div> <figcaption class=""><span class="credit"></span> </figcaption></figure></div> <div class="row"> <p class="element element-paragraph"> Jonathan y Sebastián forman parte de Ciervos Pampas Rugby Club, un equipo que nació hace cinco años como el primer equipo de la Argentina por la diversidad sexual. Se trata de un combinado que no está integrado en un 100% por varones gays, pero en el que estos encuentran un lugar en el cual expresar libremente su orientación sexual, <strong>sin miedo a los prejuicios o a la discriminación.</strong> El club emitió un comunicado en su cuenta de Facebook, relatando los hechos y solidarizándose con Jonathan.</p> </div> </div> </div>
\ No newline at end of file diff --git a/test/test-pages/extract-img-url-from-other-sources/source.html b/test/test-pages/extract-img-url-from-other-sources/source.html new file mode 100644 index 0000000..8d6832e --- /dev/null +++ b/test/test-pages/extract-img-url-from-other-sources/source.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> <html itemscope itemtype="http://schema.org/ItemList" class="story"><head> <link rel="shortcut icon" href="/pb/resources/favicon.ico" type="image/x-icon"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta charset="UTF-8"/> <meta id="viewport" name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, minimum-scale=0.5, maximum-scale=2.0"/> <meta property="keywords" content="Violencia, Homofobia, Agresión homosexual,"> <meta itemprop="description" name="description" value="Jonathan Castellari fue salvajemente golpeado en un local de comidas rápidas, mientras esperaba el desayuno junto a un amigo. Podría perder un ojo "/> <meta name="news_keywords" content="Violencia, Homofobia, Agresión homosexual,"/> <meta name="twitter:site" value="@infobae"/> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:creator" content="@infobae"> <meta property="og:description" content="Jonathan Castellari fue salvajemente golpeado en un local de comidas rápidas, mientras esperaba el desayuno junto a un amigo. Podría perder un ojo "/> <meta name="twitter:description" content="Jonathan Castellari fue salvajemente golpeado en un local de comidas rápidas, mientras esperaba el desayuno junto a un amigo. Podría perder un ojo "/> <meta property="og:type" content="article"/> <meta property="og:site_name" content="Infobae"/> <meta property="og:locale" content="es_LA"/> <meta name="robots" content="index, follow"/> <meta name="distribution" content="global"/> <meta name="rating" content="general"/> <meta name="language" content="es_ES"/> <meta itemprop="image" property="og:image" content="https://www.infobae.com/new-resizer/shi8E0F5ldd8a7vtvFaJomRURqU=/1200x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg"/> <meta name="twitter:image" content="https://www.infobae.com/new-resizer/shi8E0F5ldd8a7vtvFaJomRURqU=/1200x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg"/> <meta property="og:title" content="Una patota de varones atacó a un rugbier gay: "Te vamos a matar por puto""/> <meta name="twitter:title" content="Una patota de varones atacó a un rugbier gay: "Te vamos a matar por puto""/> <meta property="article:publisher" content="https://www.facebook.com/infobae"> <meta property="fb:app_id" content="303536999846097"/> <meta property="fb:pages" content="34839376970"/> <meta property="fb:pages" content="436205896728888"/> <meta property="fb:pages" content="142361755806396"/> <meta property="og:url" content="https://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/"/> <link rel="canonical" href="https://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/"/> <link rel="amphtml" href="https://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/?outputType=amp-type"/> <title>Una patota de varones atacó a un rugbier gay: "Te vamos a matar por puto" - Infobae</title> <meta property="article:tag" content="Homofobia, violencia de género"> <meta property="article:section" content="Sociedad"> <meta name="dfpPageType" content="nota"/> <meta name="fb:pages" content="34839376970"/> <meta name="external" content="true"/> <link href="/pb/gr/c/default/rxO4LI1ihN8KCq/css/da39a3ee5e.css?_=2f025" rel="stylesheet"/> <link href="https://static.infobae.com/tools/elecciones-2017-v2.css" rel="stylesheet"/> <link href="/pb/gr/c/default/rxO4LI1ihN8KCq/css/934059ed2a.css?_=2f025" rel="stylesheet"/> <link href="/pb/resources/assets/fontawesome/latest/css/font-awesome.min.css" rel="stylesheet"/> <link href="/pb/gr/p/default/rxO4LI1ihN8KCq/style.css?_=c91be" rel="stylesheet"/><script src="/pb/resources/scripts/jquery/jquery-2.2.4.min.js"></script> <script>var isMobile={Android:function(){return navigator.userAgent.match(/Android/i)?!0:!1},AndroidOld:function(){return navigator.userAgent.match(/Android 2.3.3/i)?!0:!1},AndroidTablet:function(){return navigator.userAgent.match(/Android/i)&&!navigator.userAgent.match(/Mobile/i)?!0:!1},Kindle:function(){return navigator.userAgent.match(/Kindle/i)?!0:!1},KindleFire:function(){return navigator.userAgent.match(/KFOT/i)?!0:!1},Silk:function(){return navigator.userAgent.match(/Silk/i)?!0:!1},BlackBerry:function(){return navigator.userAgent.match(/BlackBerry/i)? +!0:!1},iOS:function(){return navigator.userAgent.match(/iPhone|iPad|iPod/i)?!0:!1},iPhone:function(){return navigator.userAgent.match(/iPhone|iPod/i)?!0:!1},iPad:function(){return navigator.userAgent.match(/iPad/i)?!0:!1},Windows:function(){return navigator.userAgent.match(/IEMobile/i)?!0:!1},FirefoxOS:function(){return navigator.userAgent.match(/Mozilla/i)&&navigator.userAgent.match(/Mobile/i)?!0:!1},Retina:function(){return window.retina||1<window.devicePixelRatio?!0:!1},any:function(){return isMobile.Android()|| +isMobile.Kindle()||isMobile.KindleFire()||isMobile.Silk()||isMobile.BlackBerry()||isMobile.iOS()||isMobile.Windows()||isMobile.FirefoxOS()},all:function(){return navigator.userAgent},tablet:function(){return isMobile.AndroidTablet()||isMobile.iPad()||isMobile.Kindle()||isMobile.KindleFire()||isMobile.Silk()}},mobile_browser=isMobile.any()?1:0,iphone_browser=isMobile.iPhone()?1:0,ipad_browser=isMobile.iPad()?1:0,android_browser=isMobile.Android()?1:0,android233_browser=isMobile.AndroidOld()?1:0,kindle_browser= +isMobile.Kindle()?1:0,retina_browser=isMobile.Retina()?1:0,mobile_tablet=isMobile.tablet()?1:0;</script><script>(function(a,e,f,g,b,c,d){a.GoogleAnalyticsObject=b;a[b]=a[b]||function(){(a[b].q=a[b].q||[]).push(arguments)};a[b].l=1*new Date;c=e.createElement(f);d=e.getElementsByTagName(f)[0];c.async=0;c.src=g;d.parentNode.insertBefore(c,d)})(window,document,"script","//www.google-analytics.com/analytics.js","ga");ga("create","UA-759511-1","auto");ga("send","pageview");</script> <script>(function(){function f(a){b.BOOMR_onload=a&&a.timeStamp||(new Date).getTime()}if(!window.BOOMR||!window.BOOMR.version){var d,c,e,a=document.createElement("iframe"),b=window;b.addEventListener?b.addEventListener("load",f,!1):b.attachEvent&&b.attachEvent("onload",f);a.src="javascript:void(0)";a.title="";a.role="presentation";(a.frameElement||a).style.cssText="width:0;height:0;border:0;display:none;";e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(a,e);try{c=a.contentWindow.document}catch(g){d= +document.domain,a.src="javascript:var d\x3ddocument.open();d.domain\x3d'"+d+"';void(0);",c=a.contentWindow.document}c.open()._l=function(){var a=this.createElement("script");d&&(this.domain=d);a.id="boomr-if-as";a.src="https://c.go-mpulse.net/boomerang/VSGA2-YTLVV-VY5L5-HB56H-W3YTX";BOOMR_lstart=(new Date).getTime();this.body.appendChild(a)};c.write('\x3cbody onload\x3d"document._l();"\x3e');c.close()}})();</script> <script>var _comscore=_comscore||[];_comscore.push({c1:"2",c2:"8030908"});(function(){var a=document.createElement("script"),b=document.getElementsByTagName("script")[0];a.async=!0;a.src=("https:"==document.location.protocol?"https://sb":"http://b")+".scorecardresearch.com/beacon.js";b.parentNode.insertBefore(a,b)})();</script> <noscript> <img src="http://b.scorecardresearch.com/p?c1=2&c2=8030908&cv=2.0&cj=1"/> </noscript> <script>var _sf_startpt=(new Date).getTime();</script> <script>var limit="10:00",parselimit=limit.split(":"),parselimit=60*parselimit[0]+1*parselimit[1];localStorage.setItem("preventAutoRefresh",!1); +function beginrefresh(){var a=!0;"true"==localStorage.getItem("preventAutoRefresh")&&(a=!1);if(1==parselimit&&a){for(var c=$(".jwplayer"),b=0;b<c.length;b++)if(playerID=$(c).eq(b).attr("id"),playerStat=window.jwplayer(playerID).getState(),"playing"==playerStat||"paused"==playerStat){a=!1;break}a?window.location.reload():(parselimit=limit.split(":"),parselimit=60*parselimit[0]+1*parselimit[1],setTimeout("beginrefresh()",1E3))}else a&&(--parselimit,setTimeout("beginrefresh()",1E3))} +window.addEventListener?window.addEventListener("load",beginrefresh,!1):window.attachEvent&&window.attachEvent("load",beginrefresh);var handleAutoRefresh=function(a){"stopAutoRefresh"==a.type?localStorage.setItem("preventAutoRefresh",!0):(localStorage.setItem("preventAutoRefresh",!1),beginrefresh())};$(window).on("stopAutoRefresh",handleAutoRefresh);$(window).on("restartAutoRefresh",handleAutoRefresh);</script> <script>var dfpAdHelper={adSlots:[],pendingSlots:{},cmd:[],appendAd:function(a,b,c,d){dfpAdHelper.renderedAdSlots=dfpAdHelper.renderedAdSlots||{};dfpAdHelper.renderedAdSlots[a]||(dfpAdHelper.adSlots.push({slotName:a,fullAdSlot:b,dimensions:c,slotType:d}),dfpAdHelper.renderedAdSlots[a]=!0)},runAds:function(){var a=document.createElement("script");a.async=!0;a.src="https://www.googletagservices.com/tag/js/gpt.js";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);a=document.createElement("script"); +a.async=!0;a.src="http://www.infobae.com/resources/scripts/infobae-dfp-js-libraries/dfpHelper.v1.js";b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);dfpAdHelper.cmd.push({event:"runAds"});dfpAdHelper.run&&dfpAdHelper.run()}};</script> <script src="/pb/gr/c/default/rxO4LI1ihN8KCq/load_immediately/230c792bb8.js?_=319d2"></script> + <script>var w=window;if(w.performance||w.mozPerformance||w.msPerformance||w.webkitPerformance){var d=document;AKSB=w.AKSB||{},AKSB.q=AKSB.q||[],AKSB.mark=AKSB.mark||function(e,_){AKSB.q.push(["mark",e,_||(new Date).getTime()])},AKSB.measure=AKSB.measure||function(e,_,t){AKSB.q.push(["measure",e,_,t||(new Date).getTime()])},AKSB.done=AKSB.done||function(e){AKSB.q.push(["done",e])},AKSB.mark("firstbyte",(new Date).getTime()),AKSB.prof={custid:"619111",ustr:"",originlat:"0",clientrtt:"15",ghostip:"88.221.89.182",ipv6:false,pct:"10",clientip:"109.255.39.253",requestid:"942cffa",region:"24021",protocol:"",blver:13,akM:"g",akN:"ae",akTT:"O",akTX:"1",akTI:"942cffa",ai:"403159",ra:"false",pmgn:"",pmgi:"",pmp:"",qc:""},function(e){var _=d.createElement("script");_.async="async",_.src=e;var t=d.getElementsByTagName("script"),t=t[t.length-1];t.parentNode.insertBefore(_,t)}(("https:"===d.location.protocol?"https:":"http:")+"//ds-aksb-a.akamaihd.net/aksb.min.js")}</script> + </head> <body> <script>var pb_global={pageName:"infobae-article",pageId:"rxO4LI1ihN8KCq",contextPath:"/pb",isAdmin:!1,layoutEngineName:"",environment:"prod",resourceToken:"",dfpVideoPath:"infobae/sociedad/nota",videoAdOverride:""};</script> <div id="fb-root"></div> <style type="text/css">.jw-media>video.sas-video{background-color:transparent !important}</style> <div id="pb-root" class=""><section id="top" class=""> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-header-nav-dfp" id="fXZA622EOu6IBq"> <div id="siteheader" class="headernav fixed skinny slimline navOnTop"> <div class="row-two" style="background-color: #FFFFFF"> <div class="top-banner-wrapper"> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-ads-dfp" id=""> <div id="top-banner-970x80" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-970X60" data-slot-name="top-banner-970x80" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-off"></div> <script>window.dfpAdHelper.appendAd("top-banner-970x80","/1058609/infobae/sociedad/nota/top_banner_970x80",[[970,60],[970,80],[320,50]],"");</script> </div> </div> <div class="nav-items-wrapper"> <div class="left-burger-logo"> <span class="icon-burger"></span> <span class="burger-text" style="color: #000000;"></span> <a href="/?noredirect"><img class="scroll-logo nav-hp-link" src="https://www.infobae.com/new-resizer/cftaRoICqtw9YTIGBmJn0ysCM4A=/600x0/filters:quality(100)/s3.amazonaws.com/wapopartners.com/infobae-wp/wp-content/uploads/2016/03/29190548/infobae.png" alt="Infobae"/></a> </div> <div class="center-nav"> <ul class="top-nav-list hidden-sm hidden-xs"> <a href="https://www.infobae.com/ultimas-noticias/"><li class="top-nav-list-item first">Últimas Noticias</li></a> <a href="https://www.infobae.com/politica/"><li class="top-nav-list-item">Política</li></a> <a href="https://www.infobae.com/sociedad/"><li class="top-nav-list-item">Sociedad</li></a> <a href="https://www.infobae.com/deportes/"><li class="top-nav-list-item">Deportes</li></a> <a href="https://www.infobae.com/tecno/"><li class="top-nav-list-item">Tecno</li></a> <a href="https://www.infobae.com/economia/"><li class="top-nav-list-item">Economía</li></a> <a href="https://www.infobae.com/tendencias/"><li class="top-nav-list-item">Tendencias</li></a> <a href="https://www.infobae.com/la-vidriera-de-infobae/"><li class="top-nav-list-item">Vidriera</li></a> <a href="https://www.infobae.com/salud/"><li class="top-nav-list-item">Salud</li></a> <a href="http://www.infobae.com/series-peliculas/"><li class="top-nav-list-item">Series</li></a> <a href="https://www.infobae.com/autos/"><li class="top-nav-list-item">Autos</li></a> <a href="https://www.infobae.com/turismo/"><li class="top-nav-list-item">Turismo</li></a> <a href="https://www.infobae.com/cultura/"><li class="top-nav-list-item">Cultura</li></a> <a href="https://www.infobae.com/grandes-libros"><li class="top-nav-list-item">Grandes Libros</li></a> <a href="https://www.infobae.com/mix5411"><li class="top-nav-list-item">Mix5411</li></a> <a href="https://www.infobae.com/tests/"><li class="top-nav-list-item">Tests y Trivias</li></a> <a href="https://www.infobae.com/horoscopo"><li class="top-nav-list-item last">Horóscopo</li></a> </ul> </div> <div class="search-container "> <form class="search" action="/search/" method="GET" onsubmit="javascript:this.action+=this.q.value.replace(/ /g,'+')" style="background-color: #FFFFFF"> <input type="submit" class="submit"/> <button class="button search-icon icon-loupe" style="background-color: #FFFFFF"></button> <input type="text-field" class="text-field" id="q" name="q"/> </form> </div> </div> </div> <div id="drawer"> <div id="slider-menu"> <div id="slider-menu-scroll"> <ul class="sections hover-selected" id="slider-menu-nav-list"> <li class="main-nav main-nav-sections main-nav-selected"> <a class="main-nav-item main-nav-item-selected" href="/?noredirect" target="_blank">Argentina</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/america/" target="_blank">América</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/tendencias/" target="_blank">Tendencias</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/teleshow/" target="_blank">Teleshow</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/deportes/" target="_blank">Deportes</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/gente/" target="_blank">Revista Gente</a> </li> <li class="main-nav main-nav-sections"> <a class="main-nav-item" href="/parati/" target="_blank">Revista Para Ti</a> </li> <li class="main-nav-border"></li> <li id="mainnav-0" class="main-nav" data-subnav="0"> <a class="main-nav-item" href="https://www.infobae.com/ultimas-noticias/">Últimas Noticias</a> </li> <li id="mainnav-1" class="main-nav" data-subnav="1"> <a class="main-nav-item" href="https://www.infobae.com/politica/">Política</a> </li> <li id="mainnav-2" class="main-nav" data-subnav="2"> <a class="main-nav-item" href="https://www.infobae.com/sociedad/">Sociedad</a> </li> <li id="mainnav-3" class="main-nav" data-subnav="3"> <a class="main-nav-item" href="https://www.infobae.com/deportes/">Deportes</a> </li> <li id="mainnav-4" class="main-nav" data-subnav="4"> <a class="main-nav-item" href="https://www.infobae.com/tecno/">Tecno</a> </li> <li id="mainnav-5" class="main-nav" data-subnav="5"> <a class="main-nav-item" href="https://www.infobae.com/economia/">Economía</a> <i class="fa fa-angle-right main-nav-angle"></i> </li> <li id="mainnav-6" class="main-nav" data-subnav="6"> <a class="main-nav-item" href="https://www.infobae.com/tendencias/">Tendencias</a> <i class="fa fa-angle-right main-nav-angle"></i> </li> <li id="mainnav-7" class="main-nav" data-subnav="7"> <a class="main-nav-item" href="https://www.infobae.com/la-vidriera-de-infobae/">Vidriera</a> </li> <li id="mainnav-8" class="main-nav" data-subnav="8"> <a class="main-nav-item" href="https://www.infobae.com/salud/">Salud</a> <i class="fa fa-angle-right main-nav-angle"></i> </li> <li id="mainnav-9" class="main-nav" data-subnav="9"> <a class="main-nav-item" href="http://www.infobae.com/series-peliculas/">Series</a> </li> <li id="mainnav-10" class="main-nav" data-subnav="10"> <a class="main-nav-item" href="https://www.infobae.com/autos/">Autos</a> </li> <li id="mainnav-11" class="main-nav" data-subnav="11"> <a class="main-nav-item" href="https://www.infobae.com/turismo/">Turismo</a> </li> <li id="mainnav-12" class="main-nav" data-subnav="12"> <a class="main-nav-item" href="https://www.infobae.com/cultura/">Cultura</a> </li> <li id="mainnav-13" class="main-nav" data-subnav="13"> <a class="main-nav-item" href="https://www.infobae.com/grandes-libros">Grandes Libros</a> </li> <li id="mainnav-14" class="main-nav" data-subnav="14"> <a class="main-nav-item" href="https://www.infobae.com/mix5411">Mix5411</a> </li> <li id="mainnav-15" class="main-nav" data-subnav="15"> <a class="main-nav-item" href="https://www.infobae.com/tests/">Tests y Trivias</a> </li> <li id="mainnav-16" class="main-nav" data-subnav="16"> <a class="main-nav-item" href="https://www.infobae.com/horoscopo">Horóscopo</a> </li> </ul> </div> </div> <div id="arrow-5" class="sub-nav-arrow"></div> <ul id="subnav-5" class="sub-nav hover-selected"> <li class="sub-nav-item"> <a href="https://www.infobae.com/economia/finanzas-y-negocios">Finanzas y Negocios</a> </li> <li class="sub-nav-item"> <a href="https://www.infobae.com/economia/real-estate/">Real Estate</a> </li> <li class="sub-nav-item"> <a href="https://www.infobae.com/economia/rse">RSE & Sustentabilidad</a> </li> </ul> <div id="arrow-6" class="sub-nav-arrow"></div> <ul id="subnav-6" class="sub-nav hover-selected"> <li class="sub-nav-item"> <a href="https://www.infobae.com/tendencias/lifestyle/">Lifestyle</a> </li> <li class="sub-nav-item"> <a href="https://www.infobae.com/tendencias/nutriglam/">NutriGlam</a> </li> <li class="sub-nav-item"> <a href="https://www.infobae.com/tendencias/mascotas">Mascotas</a> </li> </ul> <div id="arrow-8" class="sub-nav-arrow"></div> <ul id="subnav-8" class="sub-nav hover-selected"> <li class="sub-nav-item"> <a href="https://www.infobae.com/salud/ciencia/">Ciencia</a> </li> <li class="sub-nav-item"> <a href="https://www.infobae.com/salud/fitness/">Fitness</a> </li> </ul> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-sharebar" id="fxoRBF1EOu6IBq"> <div id="sharebar_2856" class="sharebar-top-desktop sharebar-wrapper sharebar-top-mobile"> <div class="social-tools-wrapper"> <span class="social-tools-primary"> <div class="social-tools"> <a onclick="ga('.send', 'event', 'Share Bar Click', 'click', 'Facebook'); window.open('https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F','share_facebook','width=658,height=354,scrollbars=no');" tabindex=_tbidx_> <div class="facebook tool first"><span class="hideText">Share on Facebook</span><span class="fa fa-facebook-square"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'Twitter'); window.open('https://twitter.com/share?url=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F&text=Una+patota+de+varones+atac%C3%B3+a+un+rugbier+gay%3A+%22Te+vamos+a+matar+por+puto%22','share_twitter','width=550, height=350, scrollbars=no');" tabindex=_tbidx_> <div class="twitter tool"><span class="hideText">Share on Twitter</span><span class="fa fa-twitter"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'email'); window.location.href = 'mailto:?subject=Una%20patota%20de%20varones%20atac%C3%B3%20a%20un%20rugbier%20gay%3A%20%22Te%20vamos%20a%20matar%20por%20puto%22&body=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F';" tabindex=_tbidx_> <div class="email tool"><span class="hideText">Share via Email</span><span class="fa fa-envelope"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'Whatsapp'); window.location.href = 'whatsapp://send?text=Una%20patota%20de%20varones%20atac%C3%B3%20a%20un%20rugbier%20gay%3A%20%22Te%20vamos%20a%20matar%20por%20puto%22 - http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F';" tabindex=_tbidx_> <div class="whatsapp tool"><span class="hideText">Share on Whatsapp</span><span class="fa fa-whatsapp"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'Telegram'); window.location.href = 'https://telegram.me/share/url?url=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F';" tabindex=_tbidx_> <div class="telegram tool"><span class="hideText">Share on Telegram</span><span class="fa fa-paper-plane"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'LinkedIn'); window.open('https://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F&title=Una+patota+de+varones+atac%C3%B3+a+un+rugbier+gay%3A+%22Te+vamos+a+matar+por+puto%22','share_linkedin','width=830,height=460,scrollbars=no');" tabindex=_tbidx_> <div class="linkedin tool"><span class="hideText">Share on LinkedIn</span><span class="fa fa-linkedin"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'Google+'); window.open('https://plus.google.com/share?url=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F','share_google-plus','width=832,height=472,scrollbars=no');" tabindex=_tbidx_> <div class="google-plus tool"><span class="hideText">Share on Google Plus</span><span class="fa fa-google-plus"></span></div> </a><a onclick="ga('send', 'event', 'Share Bar Click', 'click', 'Pinterest'); window.open('//pinterest.com/pin/create/button/?url=%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F&media=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg&description=Una+patota+de+varones+atac%C3%B3+a+un+rugbier+gay%3A+%22Te+vamos+a+matar+por+puto%22','share_linkedin','width=550,height=450,scrollbars=no');" tabindex=_tbidx_> <div class="pinterest tool"><span class="hideText">Share on Pinterest</span><span class="fa fa-pinterest"></span></div> </a><a class="sms-share-device unprocessed" onclick="ga('send', 'event', 'Share Bar Click', 'click', 'SMS'); window.location.href = 'sms://&body=Una%20patota%20de%20varones%20atac%C3%B3%20a%20un%20rugbier%20gay%3A%20%22Te%20vamos%20a%20matar%20por%20puto%22%20-%20http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F%3Ftid=ss_sms'; return false;" tabindex=_tbidx_> <div class="sms tool"><span class="hideText">Share on SMS</span><span class="fa fa-commenting"></span></div> </a></div> </span> </div> </div> <div class="clear"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-breaking-alert" id="f0EWJzVEOu6IBq"> <div id="breaking-alert-wrapper" data-render-bar="true" data-href="/pb/api/v2/render/feature?name=homepage-breaking-news&uri=/homepage/&loadNews=true"> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fG3jHV1EOu6IBq"> <div id="megalateral-250x600" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod megalateral ad-250X600" data-slot-name="megalateral-250x600" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("megalateral-250x600","/1058609/infobae/sociedad/nota/megalateral_250x600",[250,600],"megalateral");</script> </div> <div class="pb-container"> </div></section> <section id="main" class="container"> <div class="pb-container"> <div class="wrapper clearfix col-lg-12 pb-feature pb-layout-item pb-f-homepage-masthead-with-dfp col-md-12 col-sm-12 col-xs-12" id="fqwId91EOu6IBq"> <div id="mastnav-wrapper" class="row mastnav hidden-xs"> <div id="mastnav-container"> <div class="masthead headerbox"> <div class="home-masthead-image"> <div class="masthead-ad-wrapper-left"> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-ads-dfp" id=""> <div id="header-izq-180x70" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-180X70 hide-mobile" data-slot-name="header-izq-180x70" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-off hide-mobile"></div> <script>window.dfpAdHelper.appendAd("header-izq-180x70","/1058609/infobae/sociedad/nota/header_izq_180x70",[180,70],"");</script> </div> </div> <a href="/?noredirect" class="logo hidden-xs" title="Infobae"> <img class="wplogo" src="https://www.infobae.com/new-resizer/cftaRoICqtw9YTIGBmJn0ysCM4A=/600x0/filters:quality(100)/s3.amazonaws.com/wapopartners.com/infobae-wp/wp-content/uploads/2016/03/29190548/infobae.png" alt="Infobae"/> </a> <div class="masthead-ad-wrapper-right"> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-ads-dfp" id=""> <div id="header-der-180x70" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-180X70 hide-mobile" data-slot-name="header-der-180x70" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-off hide-mobile"></div> <script>window.dfpAdHelper.appendAd("header-der-180x70","/1058609/infobae/sociedad/nota/header_der_180x70",[180,70],"");</script> </div> </div> </div> <div id="edition-toggle" class="logo-sub-nav"> <div class="day-container pr15"> <div class="full-date"> Domingo 3 de Diciembre de 2017 </div> </div> <div class="toggle-container"> <ul class="button-group even-2 edition-toggle"> <li><a href="/america/" target="_blank" id="edition-one" class="tiny mb0">América</a></li> <li><a href="/teleshow/" target="_blank" id="edition-two" class="tiny mb0">Teleshow</a></li> <li><a href="/tendencias/" target="_blank" id="edition-three" class="tiny mb0">Tendencias</a></li> <li><a href="/mix5411/" target="_blank" id="edition-four" class="tiny mb0">Mix5411</a></li> <li><a href="/grandes-libros/" target="_blank" id="edition-five" class="tiny mb0">Grandes Libros</a></li> </ul> </div> </div> </div> </div> </div> <div class="clear"></div> <div class="border-bottom-thick-tight border-bottom- mastnav-separator hidden-xs"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-hot-topics" id="f06hLD9EOu6IBq"> <div class=" hot-topics hidden-sm hidden-xs border-bottom-tight-hairline no-space border-top-no-space "> <div class="hot-topics-wrapper"> <p> <a href=" http://www.infobae.com/ultimas-noticias/">Últimas Noticias</a> </p> <p> <a href=" https://www.infobae.com/g20/"> G20</a> </p> <p> <a href=" https://www.infobae.com/deportes/mundial-rusia-2018/"> Mundial 2018</a> </p> <p> <a href=" https://www.infobae.com/tag/la-busqueda-del-submarino-ara-san-juan/"> La búsqueda del ARA San Juan</a> </p> <p> <a href=" https://www.infobae.com/politica/2017/11/10/el-gobierno-establecio-cuales-seran-los-feriados-puente-en-2018-y-2019/"> Feriados 2018</a> </p> <p> <a href=" https://www.infobae.com/la-vidriera-de-infobae/"> Vidriera</a> </p> <p> <a href=" https://www.infobae.com/sociedad/personajes/"> Personajes</a> </p> <p> <a href=" https://www.infobae.com/play-tv/"> Play TV</a> </p> <p> <a href=" https://www.infobae.com/tag/fotos-al-100/"> Fotos al 100</a> </p> <p> <a href=" http://www.infobae.com/gente/</a>"> <a href="http://www.infobae.com/gente" target="_blank"><img src="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/04135319/logo-gente-chico.png"></a> </p> <p> <a href=""><a href="http://www.infobae.com/parati" target="_blank"><img src="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/13163150/parati-chico-quick.png"></a></a> </p> </div> </div> <div class="clearfix clear"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f09RG6kEOu6IBq"> <div id="exp-push-1-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-1-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-airy hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-1-970x250","/1058609/infobae/sociedad/nota/exp_push_1_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="pb-container"> <div class="wrapper clearfix col-lg-12 pb-feature pb-layout-item pb-f-article-header col-md-12 col-sm-12 col-xs-12" id="fA2Drw1EOu6IBq"> <div class="row"> <header class="article-header hed-first col-sm-12"> <div class="header-label"> <a href="/sociedad/">Sociedad</a> </div> <h1>Una patota de varones atacó a un rugbier gay: "Te vamos a matar por puto"</h1> <span class="subheadline">Jonathan Castellari fue salvajemente golpeado en un local de comidas rápidas, mientras esperaba el desayuno junto a un amigo. Podría perder un ojo </span> </header> </div> </div> <div class="wrapper clearfix col-lg-12 col-md-12 pb-feature pb-layout-item pb-f-article-byline col-sm-12 col-xs-12" id="fZ8gS02EOu6IBq"> <div class="byline col-md-8 col-xs-12 col-print-12"> <div class="clearfix"> <img src="https://www.infobae.com/new-resizer/IL3kQvq3jxh8MdYbOw9b15XuxPc=/0x200/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-authors/mauricio_luna.jpg"/> <div class="byline-author"> Por <a class="author-name" href="/autor/mauricio-luna/" rel="author">Mauricio Luna</a> <span class="byline-date"> 1 de diciembre de 2017 </span> </div> <div class="byline-bio"> [email protected] </div> </div> <div class="clearfix"> <img src="https://www.infobae.com/new-resizer/kDRrc7yzsAnENGeWAxXxNTL7aN4=/0x200/filters:quality(100)/s3.amazonaws.com/arc-authors/infobae/9e4a86e5-0832-4826-8e82-fbe41f1d1be7.jpg"/> <div class="byline-author"> Por <a class="author-name" href="/autor/gisele-sousa-dias/" rel="author">Gisele Sousa Dias</a> <span class="byline-date"> 1 de diciembre de 2017 </span> </div> <div class="byline-bio"> [email protected] </div> </div> </div> </div> <div class="col-md-8 col-sm-12 col-xs-12 pb-layout-item pb-chain pb-c-list-chain" id="cLqIjw1EOu6IBq"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-article-body" id="f08MimYEOu6IBq"> <div id="article-body" class="article-body article-body-elements"> <div id="article-content"> <div class="row"> <figure class="element element-image col-xs-12"> <div class="single-image"> <div class="shares"> <div class="share-button share"><span class="fa fa-share-square-o"></span></div> <div class="share-button facebook" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" data-original="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg"><span class="fa fa-facebook"></span></div> <a target="_blank" href="https://twitter.com/intent/tweet?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" class="share-button twitter"><span class="fa fa-twitter"></span></a> <a target="_blank" href="http://pinterest.com/pin/create/button/?&media=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg&description=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" class="share-button pinterest"><span class="fa fa-pinterest"></span></a> <a target="_blank" href="whatsapp://send?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"%20-%20http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" class="share-button whatsapp"><span class="fa fa-whatsapp"></span></a> <a target="_blank" href="https://telegram.me/share/url?url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ&text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"" class="share-button telegram"><span class="fa fa-paper-plane"></span></a> </div> <img id="QU6XDTECU5EDVI4HBTME4PLIOQ" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23QU6XDTECU5EDVI4HBTME4PLIOQ" data-original="https://www.infobae.com/new-resizer/b_LU5bsrOM_BmZtNMzegvdNoPNE=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01154429/Rugbier-golpeado-1920.jpg" alt="Jonathan Castellari tiene 25 años y fue golpeado por una patota de 8 hombres" height="422.32142857142856" width="750" class="image-lazy"> </div> <figcaption class=""> <span class="credit">Jonathan Castellari tiene 25 años y fue golpeado por una patota de 8 hombres</span> </figcaption> </figure> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Eran casi las 6:30 de la mañana. Jonathan Castellari, de 25 años, volvía de bailar junto a Sebastián, su amigo. Les pareció una buena idea detenerse en el Mc Donald's de Avenida Córdoba al 3100 con el objetivo de desayunar y continuar el viaje hasta sus hogares. Mientras esperaban la comida, un grupo de 8 chicos de entre 20 y 25 años ingresó al local con el mismo objetivo, aunque adoptaron otro plan: mirarlos fijamente, reírse de ellos y hacer chistes sobre la sexualidad de ambos.</p> </div> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Sebastián relató a<strong> Infobae:</strong> "Estábamos esperando nuestro pedido, haciéndonos chistes, riéndonos de lo sucedido durante la noche. Hablábamos entre nosotros. En ese momento entró un grupo de 8 chicos, de contextura grande, y notamos que estaban alcoholizados. Nos miraban, hacían chistes, se reían de nosotros. Fue ahí cuando decidimos salir con Jonathan a fumar un cigarrillo y esperar que se fueran. <strong>Él salió primero y vi que uno de estos pibes lo abrazó y se lo llevó. Instantáneamente se metieron los demás a pegarle. Le pegaron mucho.</strong> Quise pararlos y no pude. Ligué yo también, pero nada en comparación a lo que sufrió Jonathan. Cuando lo soltaron lo agarré como pude y justo una enfermera del Sanatorio Güemes (está a dos cuadras del local) estaba tomando un café y le dio los primeros auxilios".</p> </div> </div> <div class="row"> <figure class="element element-image col-xs-12"> <div class="single-image"> <div class="shares"> <div class="share-button share"><span class="fa fa-share-square-o"></span></div> <div class="share-button facebook" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" data-original="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161934/Jonathan-Castellani-SF-2.jpg"><span class="fa fa-facebook"></span></div> <a target="_blank" href="https://twitter.com/intent/tweet?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" class="share-button twitter"><span class="fa fa-twitter"></span></a> <a target="_blank" href="http://pinterest.com/pin/create/button/?&media=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161934/Jonathan-Castellani-SF-2.jpg&description=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" class="share-button pinterest"><span class="fa fa-pinterest"></span></a> <a target="_blank" href="whatsapp://send?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"%20-%20http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" class="share-button whatsapp"><span class="fa fa-whatsapp"></span></a> <a target="_blank" href="https://telegram.me/share/url?url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ&text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"" class="share-button telegram"><span class="fa fa-paper-plane"></span></a> </div> <img id="NH7MLFDU4JH4VOSMUUN6JPRYUQ" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23NH7MLFDU4JH4VOSMUUN6JPRYUQ" data-original="https://www.infobae.com/new-resizer/PUJQSwJZOtaetM7tXKqic4Ib1Wg=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161934/Jonathan-Castellani-SF-2.jpg" alt="" height="937.7289377289377" width="750" class="image-lazy"> </div> <figcaption class=""> <span class="credit"></span> </figcaption> </figure> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> "Fuimos a verlo recién, no paraba de llorar y de decirnos que le pegaron por puto", dijo a <strong>Infobae</strong> María Rachid, titular del Instituto contra la Discriminación de la Defensoría del Pueblo CABA. "Lamentablemente su situación es delicada. Recién nos informaron que lo van a intervenir quirúrgicamente porque <strong>podría perder un ojo</strong>".</p> </div> </div> <div class="row"> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-ads-dfp" id=""> <div id="inline" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-1X1" data-slot-name="inline" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-"></div> <script>window.dfpAdHelper.appendAd("inline","/1058609/infobae/sociedad/nota/inline",[1,1],"");</script> </div> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Como Jonathan no conoce a los agresores, desde la Defensoría y la Federación LGBT se comunicaron con autoridades del Ministerio de Seguridad para que soliciten las cámaras de seguridad del Mc Donald's, del sanatorio Güemes y de otros negocios de la cuadra para poder identificarlos.</p> </div> </div> <div class="row"> <figure class="element element-image col-xs-12"> <div class="single-image"> <div class="shares"> <div class="share-button share"><span class="fa fa-share-square-o"></span></div> <div class="share-button facebook" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" data-original="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163101/JonathanGay2.jpg"><span class="fa fa-facebook"></span></div> <a target="_blank" href="https://twitter.com/intent/tweet?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" class="share-button twitter"><span class="fa fa-twitter"></span></a> <a target="_blank" href="http://pinterest.com/pin/create/button/?&media=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163101/JonathanGay2.jpg&description=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" class="share-button pinterest"><span class="fa fa-pinterest"></span></a> <a target="_blank" href="whatsapp://send?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"%20-%20http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" class="share-button whatsapp"><span class="fa fa-whatsapp"></span></a> <a target="_blank" href="https://telegram.me/share/url?url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA&text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"" class="share-button telegram"><span class="fa fa-paper-plane"></span></a> </div> <img id="O7QMD7FTTNCIJOVETW7KYJVVDA" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%23O7QMD7FTTNCIJOVETW7KYJVVDA" data-original="https://www.infobae.com/new-resizer/yS5kphJxw_CBn1mycqbcrMjoNmQ=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163101/JonathanGay2.jpg" alt="" height="422.32142857142856" width="750" class="image-lazy"> </div> <figcaption class=""> <span class="credit"></span> </figcaption> </figure> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Gastón Llopart, abogado de Sebastián, le detalló a <strong>Infobae</strong> que Jonathan está "próximo a recibir una intervención quirúrgica, ya que<strong> tuvo fractura en el hueso del pómulo derecho de su rostro. Sebastián llamó al 911 dos veces y no fueron.</strong> Me contaron que los agresores los siguieron hasta el sanatorio mientras los insultaban: la gente de seguridad tuvo que echarlos".</p> </div> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Llopart agregó que la patota, <strong>mientras lo golpeaban, le gritaba: "Te vamos a matar por puto"</strong>. La familia de Jonathan está en el sanatorio a la espera de la intervención quirúrgica. Llopart dijo que "harán la denuncia el lunes por la mañana, cuando existan mayores precisiones de lo ocurrido".</p> </div> </div> <div class="row"> <figure class="element element-image col-xs-12"> <div class="single-image"> <div class="shares"> <div class="share-button share"><span class="fa fa-share-square-o"></span></div> <div class="share-button facebook" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" data-original="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161927/Jonathan-Castellani-1920.jpg"><span class="fa fa-facebook"></span></div> <a target="_blank" href="https://twitter.com/intent/tweet?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" class="share-button twitter"><span class="fa fa-twitter"></span></a> <a target="_blank" href="http://pinterest.com/pin/create/button/?&media=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161927/Jonathan-Castellani-1920.jpg&description=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"&url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" class="share-button pinterest"><span class="fa fa-pinterest"></span></a> <a target="_blank" href="whatsapp://send?text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"%20-%20http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" class="share-button whatsapp"><span class="fa fa-whatsapp"></span></a> <a target="_blank" href="https://telegram.me/share/url?url=http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU&text=Una%20patota%20de%20varones%20atacó%20a%20un%20rugbier%20gay:%20"Te%20vamos%20a%20matar%20por%20puto"" class="share-button telegram"><span class="fa fa-paper-plane"></span></a> </div> <img id="7BCY2NEI6ZADBA3TRJGQC6R3BU" data-url="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/%237BCY2NEI6ZADBA3TRJGQC6R3BU" data-original="https://www.infobae.com/new-resizer/cFidtpanVMHP25zNoWF78I4qjMA=/600x0/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01161927/Jonathan-Castellani-1920.jpg" alt="" height="422.32142857142856" width="750" class="image-lazy"> </div> <figcaption class=""> <span class="credit"></span> </figcaption> </figure> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> Jonathan y Sebastián forman parte de Ciervos Pampas Rugby Club, un equipo que nació hace cinco años como el primer equipo de la Argentina por la diversidad sexual. Se trata de un combinado que no está integrado en un 100% por varones gays, pero en el que estos encuentran un lugar en el cual expresar libremente su orientación sexual, <strong>sin miedo a los prejuicios o a la discriminación.</strong> El club emitió un comunicado en su cuenta de Facebook, relatando los hechos y solidarizándose con Jonathan.</p> </div> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> <strong>LEA MÁS:</strong></p> </div> </div> <div class="row"> <div class="col-xs-12 col-print-12"> <p class="element element-paragraph"> <strong><em><a href="https://www.infobae.com/america/deportes/mundial-rusia-2018/2017/12/01/pese-a-la-ley-contra-la-propaganda-homosexual-vigente-rusia-permitira-banderas-gay-en-el-mundial/" target="_blank">Pese a la ley contra la propaganda homosexual vigente, Rusia permitirá banderas gays en el Mundial</a></em></strong></p> </div> </div> </div> </div> <div class="selectionSharer" id="selectionSharerPopover" data-selection="true"> <div id="selectionSharerPopover-inner"> <ul> <li id="popoverTwitter"><a class="action" href="" title="Share this selection on Twitter" target="_blank"><span id="twIcon" class="fa fa-twitter"></span>Tweet</a></li> </ul> </div> <div class="selectionSharerPopover-clip"><span class="selectionSharerPopover-arrow"></span></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f01GzrMEOu6IBq"> <div class="border-bottom-off"> <div class="no-skin flex-item flex-stack text-align-center equalize-height-target"> <div class="headline small normal-style "> <a href="https://app.infobae.com/" data-pb-field="headlines.basic" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> </a><a href="https://app.infobae.com/" target="_blank">⚡ ¿Probaste <img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/wapopartners.com/infobae-wp/wp-content/uploads/2016/03/29190548/infobae.png&mode=crop&h=24&q=75&token=bar" style="height:17px; margin-top:-5px"> en Alta Velocidad en tu smartphone?</a> </div> <div class="blurb normal-style" data-pb-field="description.basic" data-pb-field-type="text" data-pb-placeholder="Write blurb here."><span style="color: #000000; background-color:#FFFC41">Permite ver las noticias en menos de un segundo.</span></div> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-article-big-button-share" id="fXpds01EOu6IBq"> <div class="social-tools-wrapper-bottom full"> <ul class="social-tools-bottom inline"> <li data-sharetype="facebook" class="left facebook"> <a href="#" onclick="ga('send', 'event', 'Big Button Share Click', 'click', 'Facebook'); window.open('https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F','share_facebook','width=658,height=354,scrollbars=no'); return false;" tabindex="_tbidx_"> <span class="fa fa-facebook-square"> </span><span class="longname">Compartir en Facebook</span><span class="shortname">Compartir</span> </a> </li> <li data-sharetype="twitter" class="right twitter"> <a href="#" onclick="ga('send', 'event', 'Big Button Share Click', 'click', 'Twitter'); window.open('https://twitter.com/share?url=http%3A%2F%2Fwww.infobae.com%2Fsociedad%2F2017%2F12%2F01%2Funa-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto%2F&text=Una patota de varones atacó a un rugbier gay: "Te vamos a matar por puto"','share_twitter','width=550, height=350, scrollbars=no'); return false;" tabindex="_tbidx_"> <span class="fa fa-twitter"> </span> <span class="longname">Compartir en Twitter</span><span class="shortname">Tweet</span> </a> </li> </ul> <div class="clear"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fza3sq1EOu6IBq"> <div id="middle-1-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="middle-1-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("middle-1-300x250","/1058609/infobae/sociedad/nota/middle_1_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0h0bqdEOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f0b7WEoEOu6IBq"> <div class="border-bottom-off"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="http://www.infobae.com/ultimas-noticias/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_3119645" data-pb-field="custom.label" data-pb-placeholder="Label">ÚLTIMAS NOTICIAS</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-generic-results-list" id="f0dPEneEOu6IBq"> <div class="result-listing"> <div class="label-text"> <h2 class="header-label"></h2> </div> <div class="generic-results-list-main-wrapper" data-load-more="5175528"> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal first-item row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/america/mundo/2017/12/03/el-impactante-hundimiento-de-un-barco-surcoreano-en-el-mar-amarillo-al-menos-13-muertos/"> <h4 class="">El impactante hundimiento de un barco surcoreano en el Mar Amarillo: al menos 13 muertos</h4> <p><span class="excerpt">El navío, de más de 9 toneladas y con 22 personas a bordo, colisionó con un buque cisterna de más de 300 toneladas cerca de la isla de Yeongheung. Cuatro helicópteros y 14 barcos continúan su búsqueda por dos desaparecidos</span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/america/mundo/2017/12/03/el-impactante-hundimiento-de-un-barco-surcoreano-en-el-mar-amarillo-al-menos-13-muertos/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/cgUxNFQciDOFdUihSd9dgGf6b_Y=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03074750/Barco-pesquero-Corea-del-Sur-2.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/cgUxNFQciDOFdUihSd9dgGf6b_Y=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03074750/Barco-pesquero-Corea-del-Sur-2.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/politica/2017/12/03/g20-venezuela-y-la-busqueda-del-ara-san-juan-la-agenda-de-marcos-pena-en-su-visita-a-eeuu/"> <h4 class="">G20, Venezuela y la búsqueda del ARA San Juan, la agenda de Marcos Peña en su visita a EEUU</h4> <p><span class="excerpt"></span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/politica/2017/12/03/g20-venezuela-y-la-busqueda-del-ara-san-juan-la-agenda-de-marcos-pena-en-su-visita-a-eeuu/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/w1z7tobCQL3GZ9YhdYCC9UuUbC0=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02193822/Marcos-Pena-con-Ricky-Waddell-1920.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/w1z7tobCQL3GZ9YhdYCC9UuUbC0=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02193822/Marcos-Pena-con-Ricky-Waddell-1920.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/"> <h4 class="">El club inglés que es sensación en las redes sociales por su creatividad al anunciar los goles de su equipo</h4> <p><span class="excerpt">El community manager del Bristol City, de la segunda división de Inglaterra, empleó unos llamativos GIF's que se disparan cada vez que sus jugadores convierten</span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/fA7qBMo72SfnZmiZbZ9AiiSHPUY=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03080601/PARTIDA-BRISTOL-CITY-2.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/fA7qBMo72SfnZmiZbZ9AiiSHPUY=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03080601/PARTIDA-BRISTOL-CITY-2.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/sociedad/2017/12/03/cuanto-dinero-se-necesita-para-armar-el-arbolito-navideno/"> <h4 class="">¿Cuánto dinero se necesita para armar el arbolito navideño?</h4> <p><span class="excerpt">Decorar el hogar a la espera de las fiestas es parte de la tradición navideña. Los precios exponen una diferencia notable en relación a Chile y Estados Unidos </span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/sociedad/2017/12/03/cuanto-dinero-se-necesita-para-armar-el-arbolito-navideno/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/C-feFCQoaidN8MY0aVPIDhss3hw=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02193532/Navidad2.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/C-feFCQoaidN8MY0aVPIDhss3hw=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02193532/Navidad2.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/parati/estar-mejor/2017/12/03/la-tecnica-del-10-10-10-el-original-metodo-para-tomar-decisiones/"> <h4 class="">La técnica del 10-10-10: el original método para tomar decisiones</h4> <p><span class="excerpt">¿Horas, minutos... años? Elegir no es fácil: hay que pensar bien, elaborar alternativas e imaginar consecuencias, a corto y largo plazo. Pero, ¿cómo podemos saber y evaluar ese alcance? La norteamericana Suzy Welch, especialista en finanzas, propuso un técnica para encarar determinaciones, y fue un éxito instantáneo. </span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/parati/estar-mejor/2017/12/03/la-tecnica-del-10-10-10-el-original-metodo-para-tomar-decisiones/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/eyA2ZbzBOFgKK0YS7VjlKkV1BTc=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27174708/PARATI-IDEAS-APERTURA.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/eyA2ZbzBOFgKK0YS7VjlKkV1BTc=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27174708/PARATI-IDEAS-APERTURA.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> <div class="generic-results-list-item pwa_card" data-load-more="5175528"> <article class="result-item result-teaser result-teaser-normal last-item row"> <header> <div class="row"> <div class="col-sm-8"> <figure> <a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/"> <h4 class="">Afganistán: un terrorista hizo estallar su motocicleta y mató a seis personas en el norte del país</h4> <p><span class="excerpt">El hecho ocurrió en una zona donde opera el Estado Islámico, aunque ningún grupo se atribuyó aún el ataque. Se trata del último de una serie de atentados en el país que no vive tregua desde el fin de la misión de la OTAN en 2015</span></p> </a> </figure> </div> <div class="col-sm-4"> <a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/"> <div class="lazy-wrapper hover-media-overlay"> <img data-original="https://www.infobae.com/new-resizer/nsbMjcTGaowWVNWWetFTZuLTtxI=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03075442/Atentado-en-Jalalabad-Afganistan-2.jpg" alt="" class="image-lazy"> <noscript><img src="https://www.infobae.com/new-resizer/nsbMjcTGaowWVNWWetFTZuLTtxI=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03075442/Atentado-en-Jalalabad-Afganistan-2.jpg" alt=""></noscript> </div> </a> </div> </div> </header> </article> </div> </div> </div> <div class="button pb-loadmore clear generic-results-list-load-more" data-load-more-button-id="5175528" data-keys="Feed-Type,_jge,Feed-Parameter,Feed-Limit,Feed-Order,Feed-Offset" data-values="taxonomy.sites.path:("/politica" "/sociedad" "/economia" "/deportes-2" "/tecno" "/tendencias" "/salud" "/series-peliculas" "/autos" "/turismo" "/cultura" "/grandes-libros" "/vidriera" "/fotos" "/discapacidad" "/teleshow" "/gente" "/america/america-latina" "/america/mundo" "/america/eeuu" "/america/venezuela" "/america/mexico" "/america/colombia" "/america/entretenimiento" "/america/deportes" "/america/tecno" "/america/fotos" "/america/wapo" "/america/vice" "/parati" "/america/cultura-america" NOT "/deportes-2/diarios-deportivos" AND NOT "/gente/espacio-no-editorial-revista-gente" AND NOT "/gente/ediciones" AND NOT "/parati/ediciones-archivo" AND NOT "/parati/espacio-no-editorial-parati/") AND revision.published,content-feed,true,6,display_date:desc,0" data-custom-field-keys="formattingOption,enabledLoadMore,showSigline,dateType,offset,commentsCountCivil,commentsCountDisqus,numItems" data-custom-field-values="relative,true,false,displayOnly,0,false,false,7" data-href="/pb/api/v2/render/feature/global/generic-results-list" data-offset="0" data-number-items="6">Mas Noticias</div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0MkVHTEOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fHM8zB1EOu6IBq"> <div class="border-bottom-off"> <div class="no-skin flex-item flex-stack text-align-center equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="http://www.infobae.com/te-recomendamos/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_1052791" data-pb-field="custom.label" data-pb-placeholder="Label">TE RECOMENDAMOS</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-global-recommend col-lg-12 col-md-12 col-sm-12 col-xs-12" id="fE6dot1EOu6IBq"> <div id="recommendations-marker"></div> <div id="recommendations" style="display:none"> <div class="row result-listing"> <div class="label-text"> <h2 class="header-label"></h2> </div> <script data-template-id="recommendation" type="text/template"> + <article class="result-item result-teaser result-teaser-normal"> + <header class="row"> + <div class="row"> + <div class="col-sm-8"> + <figure> + <a data-href="{{url}}"> + <h4>{{headline}}</h4> + <p><span class="excerpt">{{summary}}</span></p> + </a> + </figure> + </div> + <div class="col-sm-4"> + <a data-href="{{url}}"> + <img data-src="{{picture}}"/> + </a> + </div> + </div> + </header> + </article> + </script> </div> </div> <script>(function(){function b(a){"loading"!=document.readyState?a():document.addEventListener("DOMContentLoaded",a)}window.XDomainRequest||b(function(){recommend({count:3,content:"5EPSP5OX6BDPPIKTHQ4JYUHSNI",element:"#recommendations",scrollMarker:"#recommendations-marker",endpoint:"https://recommendations.infobae.arcpublishing.com/hybrid/hybrid-filter",whenToRun:"smart",clientName:"recommend-arc",imageMaxWidth:300})})})();</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f8SMu52EOu6IBq"> <div class="border-bottom-kinda-tight"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fiV2kC1EOu6IBq"> <div id="middle-2-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="middle-2-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("middle-2-300x250","/1058609/infobae/sociedad/nota/middle_2_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fMfcTw1EOu6IBq"> <div class="border-bottom-tight"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-article-comments-facebook" id="f0Gcl69EOu6IBq"> <h2 class="header-label">Comentarios</h2> <div class="fb-comments" data-href="http://www.infobae.com/sociedad/2017/12/01/una-patota-de-varones-ataco-a-un-rugbier-gay-te-vamos-a-matar-por-puto/" data-numposts="3" data-colorscheme="light" data-order-by="reverse_time" data-width="700px"></div> <div class="clear"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0RsxmmEOu6IBq"> <div class="border-bottom-tight"></div> </div> </div> <div class="right-rail-chain col-md-4 col-sm-12 col-xs-12 pb-layout-item pb-chain pb-c-right-rail-chain" id="cPOkQK1EOu6IBq"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fLfroK1EOu6IBq"> <div id="right-1-300x600" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-1-300x600" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-1-300x600","/1058609/infobae/sociedad/nota/right_1_300x600",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fZpXBh1EOu6IBq"> <div id="right-2-300x600" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-2-300x600" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-2-300x600","/1058609/infobae/sociedad/nota/right_2_300x600",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fDpyZS1EOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix col-lg-12 col-md-12 pb-feature pb-layout-item pb-f-global-most-read col-sm-12 col-xs-12" id="f0JgBcJFOu6IBq"> <div class="row"> <h2 class="header-label label label-kicker most-read-wrapper"><a href="http://www.infobae.com/mas-leidas/">MÁS LEÍDAS</a></h2> <aside class="line-up most-read skin skin-card with-bottom-border col-lg-12 col-md-12 col-sm-12 col-xs-12 "> <article class="left"> <header> <div class="number left">1</div><h4 class="left"><a href="/sociedad/policiales/2017/12/03/exclusivo-habla-el-lider-de-la-temible-banda-del-millon-ibamos-a-ir-por-los-bolsos-que-lopez-tiro-en-el-convento/">Exclusivo, habla el líder de la temible Banda del Millón: “Íbamos a ir por los bolsos que López tiró en el convento”</a></h4> <a href="/sociedad/policiales/2017/12/03/exclusivo-habla-el-lider-de-la-temible-banda-del-millon-ibamos-a-ir-por-los-bolsos-que-lopez-tiro-en-el-convento/"> <img src="https://www.infobae.com/new-resizer/R1RvY0B8ow2txSDcg233vSkrhEs=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/29180028/leonardo-mercado-ympa-banda-del-millon-02.jpg" alt="" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">2</div><h4 class="left"><a href="/sociedad/policiales/2017/12/02/santiago-del-estero-asi-fue-el-pacto-satanico-para-descuartizar-a-un-chico-de-once-anos-2/">Santiago del Estero: así fue el pacto satánico para descuartizar a un chico de once años</a></h4> <a href="/sociedad/policiales/2017/12/02/santiago-del-estero-asi-fue-el-pacto-satanico-para-descuartizar-a-un-chico-de-once-anos-2/"> <img src="https://www.infobae.com/new-resizer/N_NvH9Omw_814ujN5txdgAG57D8=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/06/04180802/asesinato-Mario-Agust%C3%ADn-Salto-1920-4.jpg" alt="Marito fue violado antes de ser estrangulado con un cable." class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">3</div><h4 class="left"><a href="/sociedad/2017/12/03/sobrevivir-a-la-prostitucion-tuve-que-matar-a-la-puta-que-construyeron-dentro-de-mi/">Sobrevivir a la prostitución: "Tuve que matar a la puta que construyeron dentro de mí"</a></h4> <a href="/sociedad/2017/12/03/sobrevivir-a-la-prostitucion-tuve-que-matar-a-la-puta-que-construyeron-dentro-de-mi/"> <img src="https://www.infobae.com/new-resizer/9Ms00i-xfAU9gbJSgqTnoF9zFkA=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30160846/Sonia-Sanchez-8.jpg" alt="" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">4</div><h4 class="left"><a href="/noticias/2017/12/02/el-furioso-ataque-de-luciana-salazar-contra-martin-redrado/">El furioso ataque de Luciana Salazar contra Martín Redrado</a></h4> <a href="/noticias/2017/12/02/el-furioso-ataque-de-luciana-salazar-contra-martin-redrado/"> <img src="https://www.infobae.com/new-resizer/RUk9KmlnV9ross113tr-1jXTx5U=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/08/17135104/luli.jpg" alt="Martín Redrado y Luciana Salazar" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">5</div><h4 class="left"><a href="/politica/2017/12/03/un-grupo-mapuche-ya-recibio-del-estado-mas-de-100-millones/">Un grupo mapuche ya recibió del Estado más de 100 millones</a></h4> <a href="/politica/2017/12/03/un-grupo-mapuche-ya-recibio-del-estado-mas-de-100-millones/"> <img src="https://www.infobae.com/new-resizer/h3EUdxrpI48Hz9UOkeb3mxyE12I=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/09/19112338/NEUQUEN2.jpg" alt="" class="photo right small-img"> </a> </header> </article> </aside> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0dRBteFOu6IBq"> <div id="right-3-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-3-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-3-300x250","/1058609/infobae/sociedad/nota/right_3_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fKnhyt1FOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-list-card-column" id="fQuy4j2FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/deportes/"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/08/29170312/logo_deportes.png&mode=crop&h=24&q=75&token=bar" style="height:21px; margin-top:-10px"></a></h3></header> <div class="column-item"> <a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/fA7qBMo72SfnZmiZbZ9AiiSHPUY=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03080601/PARTIDA-BRISTOL-CITY-2.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/">El club inglés que es sensación en las redes sociales por su creatividad al anunciar los goles de su equipo</a></h4> </div> <div class="column-item"> <h4><a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-boca-vs-arsenal-hora-tv-arbitro-y-formaciones/">Boca buscará ante Arsenal un resultado que aleje los fantasmas: hora, TV, árbitro y formaciones</a></h4> </div> <div class="column-item"> <h4><a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-tigre-vs-san-lorenzo-hora-tv-arbitro-y-formaciones/">San Lorenzo visita a Tigre para superar a Boca y ser el nuevo líder: hora, TV, árbitro y formaciones</a></h4> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0xyZMPFOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0sFpkiFOu6IBq"> <div id="right-4-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-4-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-4-300x250","/1058609/infobae/sociedad/nota/right_4_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f07ZAViFOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-list-card-column" id="fKvqUn1FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="https://www.infobae.com/gente/"><strong>MÁS EN <img src="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/02173811/gente.png" style="height:24px; margin-top:-5px"></strong></a></h3></header> <div class="column-item"> <a href="/gente/lo-ultimo/2017/12/02/exclusivo-vimos-antes-que-nadie-13-minutos-de-star-wars-los-ultimos-jedi/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/4DMFMiuID1BL6lbiVzl-yl5NDoA=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27162306/GENTE-Starwars-Apertura-241117.jpg" alt="El productor Ram Bergman, la actriz Daisy Ridley, el director Rian Johnson y el actor Mark Hamill. Foto: gentileza Disney" class="image-lazy"> </div> </a> <h4 class="first"><a href="/gente/lo-ultimo/2017/12/02/exclusivo-vimos-antes-que-nadie-13-minutos-de-star-wars-los-ultimos-jedi/">Exclusivo: Vimos antes que nadie 13 minutos de Star Wars: Los últimos Jedi</a></h4> </div> <div class="column-item"> <h4><a href="/gente/lo-ultimo/2017/12/02/morla-el-abogado-de-maradona-diego-insiste-con-que-claudia-lo-quiere-ver-muerto/">Morla, el abogado de Maradona: "Diego insiste con que Claudia lo quiere ver muerto"</a></h4> </div> <div class="column-item"> <h4><a href="/gente/lo-ultimo/2017/12/02/toto-kirzner-debuta-en-los-unitarios-de-la-fundacion-huesped-y-dice-hay-prejuicios-y-discriminacion-sobre-el-sida/">Toto Kirzner debuta en los unitarios de la Fundación Huésped y dice: "Hay prejuicios y discriminación sobre el SIDA"</a></h4> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f02bKzyFOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fWuTM72FOu6IBq"> <div id="right-5-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-5-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-5-300x250","/1058609/infobae/sociedad/nota/right_5_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-list-card-column" id="f0IQUdnFOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/tecno"><strong>TECNO</strong></a></h3></header> <div class="column-item"> <a href="/america/tecno/2017/12/03/quien-fue-madame-x-la-mujer-que-revelo-los-codigos-secretos-de-japon-durante-la-segunda-guerra-mundial/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/tgPKJq7_YhCj19pbaMC8gxFQ7bQ=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27145850/AGNES-MAYER-DRISCOLL1.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/america/tecno/2017/12/03/quien-fue-madame-x-la-mujer-que-revelo-los-codigos-secretos-de-japon-durante-la-segunda-guerra-mundial/">Quién fue Madame X, la mujer que reveló los códigos secretos de Japón durante la Segunda Guerra Mundial</a></h4> </div> <div class="column-item"> <h4><a href="/tendencias/innovacion/2017/12/02/las-tres-tecnologias-que-cambiaran-nuestro-futuro/">Las tres tecnologías que cambiarán nuestro futuro</a></h4> </div> <div class="column-item"> <h4><a href="/tecno/2017/12/02/quien-controla-el-bitcoin/">¿Quién controla el Bitcoin?</a></h4> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fAKJEr1FOu6IBq"> <div class="border-bottom-airy"></div> </div> <div class="wrapper clearfix col-lg-12 col-md-12 pb-feature pb-layout-item pb-f-global-most-read col-sm-12 col-xs-12" id="f8owjl1FOu6IBq"> <div class="row"> <h2 class="header-label label label-kicker most-read-wrapper"><a href="http://www.infobae.com/america/">MÁS LEÍDAS <img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/09/27141508/america.png&mode=crop&h=24&q=75&token=bar" style="height:22px; margin-top:-6px"></a></h2> <aside class="line-up most-read skin skin-card with-bottom-border col-lg-12 col-md-12 col-sm-12 col-xs-12 "> <article class="left"> <header> <div class="number left">1</div><h4 class="left"><a href="/america/mundo/2017/12/03/la-horrenda-historia-de-la-condesa-hungara-que-asesino-a-mas-de-600-mujeres-para-lograr-la-belleza-eterna-con-su-sangre/">La horrenda historia de la condesa húngara que asesinó a más de 600 mujeres para lograr la belleza eterna con su sangre</a></h4> <a href="/america/mundo/2017/12/03/la-horrenda-historia-de-la-condesa-hungara-que-asesino-a-mas-de-600-mujeres-para-lograr-la-belleza-eterna-con-su-sangre/"> <img src="https://www.infobae.com/new-resizer/kUIgIYssfcsPB48GUiOIDg2AxuU=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30184950/Erzs%C3%A9bet-Isabel-Bathory.jpg" alt="" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">2</div><h4 class="left"><a href="/america/mundo/2017/12/02/como-es-albinen-el-pueblo-que-ofrece-usd-25-mil-a-quienes-quieran-mudarse/">Cómo es Albinen, el pueblo que ofrece USD 25 mil a quienes quieran mudarse</a></h4> <a href="/america/mundo/2017/12/02/como-es-albinen-el-pueblo-que-ofrece-usd-25-mil-a-quienes-quieran-mudarse/"> <img src="https://www.infobae.com/new-resizer/2QIoCOtACpHy-5EpMxIDP4pDzjY=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02094537/albinen-suiza-1920-4.jpg" alt="CZR23. ALBINEN (SUIZA), 30/11/2017.- Vista general del pueblo de Albinen hoy, jueves 30 de noviembre de 2017, durante la asamblea comunal de Albinen, en Albinen (Suiza). Los residentes de Albinen votarán una nueva regulación comunitaria que propone 25,000 francos suizos por cada persona que se establezca en la municipalidad por al menos 10 años. El subsidio en efectivo surge como una iniciativa para frenar el éxodo de residentes locales fuera de la aldea de Albinen y para atraer a nuevas familias. EFE/CYRIL ZINGARO" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">3</div><h4 class="left"><a href="/america/deportes/2017/12/02/medios-irlandeses-aseguraron-que-la-vida-de-conor-mcgregor-corre-un-grave-peligro/">Medios irlandeses aseguraron que la vida de Conor McGregor corre un "grave peligro"</a></h4> <a href="/america/deportes/2017/12/02/medios-irlandeses-aseguraron-que-la-vida-de-conor-mcgregor-corre-un-grave-peligro/"> <img src="https://www.infobae.com/new-resizer/V0Xe13tXim1KgOjta3O03N_WTD0=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/08/31084830/063_592638926.jpg" alt="(AFP)" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">4</div><h4 class="left"><a href="/america/entretenimiento/2017/12/03/los-curiosos-comienzos-como-extras-de-algunas-de-las-estrellas-mas-famosas-de-hollywood/">Los curiosos comienzos como extras de algunas de las estrellas más famosas de Hollywood</a></h4> <a href="/america/entretenimiento/2017/12/03/los-curiosos-comienzos-como-extras-de-algunas-de-las-estrellas-mas-famosas-de-hollywood/"> <img src="https://www.infobae.com/new-resizer/akM-LtOKQ5lEGQkcupgQSGBNDWQ=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30120001/pre-fama-famosos-partida-301117.jpg" alt="" class="photo right small-img"> </a> </header> </article> <article class="left"> <header> <div class="number left">5</div><h4 class="left"><a href="/america/mexico/2017/12/01/regreso-a-su-casa-y-encontro-a-siete-familiares-muertos-y-con-espuma-en-la-boca/">Regresó a su casa y encontró a siete familiares muertos y con espuma en la boca</a></h4> <a href="/america/mexico/2017/12/01/regreso-a-su-casa-y-encontro-a-siete-familiares-muertos-y-con-espuma-en-la-boca/"> <img src="https://www.infobae.com/new-resizer/2PT_ACjXRhuL5RpF8JEBizadhSI=/130x130/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01153823/Suicidio-familiar-Mexico-1.jpg" alt="Siete integrantes de una familia murieron dentro de su domicilio en Tizayuca, Hidalgo. (La prensa. Especial)" class="photo right small-img"> </a> </header> </article> </aside> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fz4KXK1FOu6IBq"> <div id="right-6-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-6-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-6-300x250","/1058609/infobae/sociedad/nota/right_6_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fzq1TV1FOu6IBq"> <div class="border-bottom-airy"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-list-card-column" id="f009HK2FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/tendencias/"><strong>Tendencias</strong></a></h3></header> <div class="column-item"> <a href="/tendencias/2017/12/02/julian-serrano-a-solas-con-infobae-los-jovenes-de-hoy-son-autodidactas-ambiciosos-y-emprendedores/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/0Gkd-hY3O-OurTrOQBCXGwjwDvw=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30145414/julian-serrano.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/tendencias/2017/12/02/julian-serrano-a-solas-con-infobae-los-jovenes-de-hoy-son-autodidactas-ambiciosos-y-emprendedores/">Julián Serrano, a solas con Infobae: "Los jóvenes de hoy son autodidactas, ambiciosos y emprendedores"</a></h4> </div> <div class="column-item"> <h4><a href="/mix5411/2017/12/02/la-casa-plegable-que-cuesta-menos-de-30-000-euros-y-se-arma-en-solo-6-horas/">La casa plegable que cuesta menos de 30.000 euros y se arma en solo 6 horas</a></h4> </div> <div class="column-item"> <h4><a href="/mix5411/2017/12/02/el-apasionado-beso-del-ken-humano-que-confirmo-su-verdadera-sexualidad/">El apasionado beso del “Ken humano” que confirmó su verdadera sexualidad</a></h4> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0PcYSlFOu6IBq"> <div class="border-bottom-airy"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0zJQibFOu6IBq"> <div id="right-7-300x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod ad-300X250" data-slot-name="right-7-300x250" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("right-7-300x250","/1058609/infobae/sociedad/nota/right_7_300x250",[[300,250],[300,600]],"");</script> </div> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-global-mailchimp-signup col-lg-12 col-md-12 col-sm-12 col-xs-12" id="f0kgs26FOu6IBq"> <div class=" col-xs-12 col-sm-10 col-sm-offset-1 col-md-10 col-md-offset-1"> <div class="form-wrapper row"> <div id="mc_embed_signup" style="width: 100%;"> <form action="//infobae.us13.list-manage.com/subscribe/post?u=4e953e7139f83467d8edcac2e&id=4ec30b39ed" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate> <div id="mc_embed_signup_scroll" style="height: 165px; border: 1px solid #e2e2e2; "> <h2 style="font-size: 20px; font-family: arial; font-weight: normal; margin-top: 0px; margin-bottom: 0px; padding-top: 15px; text-align: center; color: #f68e01;"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/09/22145201/closed-envelope.png&mode=crop&h=24&q=75&token=bar" width="40px" style="padding-right: 10px; vertical-align: middle;">Newsletter <img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/wapopartners.com/infobae-wp/wp-content/uploads/2016/03/29190548/infobae.png&mode=crop&h=24&q=75&token=bar" style="height:20px; margin-top:-8px"></h2> <p style="font-family: arial; font-size: 16px; color: #9e9e9e; margin-top: 5px; text-align: center;"> </p><div class="mc-field-group" style="text-align: center; "> <input type="email" id="mce-EMAIL" name="EMAIL" required placeholder="Tu email" style="width:100%; height: 34px; font-size: 14px; "> </div> <div id="mce-responses" class="clear"> <div class="response" id="mce-error-response" style="display:none"></div> <div class="response" id="mce-success-response" style="display:none"></div> </div> <div style="position: absolute; left: -5000px;" aria-hidden="true"> <input type="text" name="b_4e953e7139f83467d8edcac2e_4ec30b39ed" tabindex="-1" value=""> </div> <div class="clear"> <input type="submit" value="Suscribirse" name="subscribe" id="mc-embedded-subscribe" style=" background: #f68e01; color: white !important; font-weight: normal; display: block; margin-top: 5px; margin-bottom: 10px; border: 1px solid #f68e01; width: 80%; height: 36px; transition: background 0.3s; font-size: 19px; margin-left: 10%; margin-right: 10%;"> </div> </div> </form> </div> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fwnELc2FOu6IBq"> <div class="border-bottom-none"></div> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fC7J2j2FOu6IBq"> <div id="exp-push-2-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-2-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-2-970x250","/1058609/infobae/sociedad/nota/exp_push_2_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f3CSaU1FOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain full" id="c0G2Xa9FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fWDW661g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/teleshow/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_990267" data-pb-field="custom.label" data-pb-placeholder="Label">TELESHOW</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0N7qeTg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/infoshow/2017/12/03/quienes-son-yon-gonzalez-y-amaia-salamanca-los-actores-de-las-series-espanolas-que-hacen-furor-en-netflix/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Quiénes son Yon González y Amaia Salamanca, los actores de las series españolas que hacen furor en Netflix </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_3658" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/infoshow/2017/12/03/quienes-son-yon-gonzalez-y-amaia-salamanca-los-actores-de-las-series-espanolas-que-hacen-furor-en-netflix/"><img data-original="https://www.infobae.com/new-resizer/hxs4a_adg23D-1h7b2YDrBgQu3U=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/21200606/gran-hotel.jpg" class="image-lazy"></a></div> <style>#flex_3658.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_3658.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0uK44Dg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/infoshow/2017/12/03/la-ultima-moda-de-la-farandula-las-hijas-de-los-famosos-se-convierten-en-empresarias-y-lanzan-sus-propias-marcas/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La última moda de la farándula: las hijas de los famosos se convierten en empresarias y lanzan sus propias marcas </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6639" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/infoshow/2017/12/03/la-ultima-moda-de-la-farandula-las-hijas-de-los-famosos-se-convierten-en-empresarias-y-lanzan-sus-propias-marcas/"><img data-original="https://www.infobae.com/new-resizer/44VfN5GfgFdhha4Amz9eLstvf2s=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01123729/hijas-famosos-portada.jpg" class="image-lazy"></a></div> <style>#flex_6639.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6639.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="ffTE5O1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/infoshow/2017/12/03/a-25-anos-del-boom-de-la-pachanga-la-historia-jamas-contada-del-hit-de-vilma-palma-quien-era-el-pelado/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> A 25 años del boom de "La pachanga", la historia jamás contada del hit de Vilma Palma: ¿quién era "El Pelado"? </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_3727" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/infoshow/2017/12/03/a-25-anos-del-boom-de-la-pachanga-la-historia-jamas-contada-del-hit-de-vilma-palma-quien-era-el-pelado/"><img data-original="https://www.infobae.com/new-resizer/lf2elydCw7tq93Y0zafy17RLdjU=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01185417/Vilma-Palma-portada-1.jpg" class="image-lazy"></a></div> <style>#flex_3727.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_3727.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fD8D3i1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/entretenimiento/2017/12/03/los-curiosos-comienzos-como-extras-de-algunas-de-las-estrellas-mas-famosas-de-hollywood/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Los curiosos comienzos como extras de algunas de las estrellas más famosas de Hollywood </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6285" class="lazy-wrapper photo-wrapper"> <a href="/america/entretenimiento/2017/12/03/los-curiosos-comienzos-como-extras-de-algunas-de-las-estrellas-mas-famosas-de-hollywood/"><img data-original="https://www.infobae.com/new-resizer/GrSLk3FaBhPdtA-V0dJ3l4UWlTQ=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30120001/pre-fama-famosos-partida-301117.jpg" class="image-lazy"></a></div> <style>#flex_6285.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6285.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="pb-container"> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain col-lg-12 col-md-12 col-sm-12 col-xs-12" id="c0Mg8RVFOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f00OvHUg7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-center"> <a href="https://www.infobae.com/deportes/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_3341952" data-pb-field="custom.label" data-pb-placeholder="Label">DEPORTES</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0cCBJ1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> El club inglés que es sensación en las redes sociales por su creatividad al anunciar los goles de su equipo </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1241" class="lazy-wrapper photo-wrapper"> <a href="/america/deportes/2017/12/03/el-club-ingles-que-es-sensacion-en-las-redes-sociales-por-su-creatividad-al-anunciar-los-goles-de-su-equipo/"><img data-original="https://www.infobae.com/new-resizer/Hdy0B-KZrJ-ozGgG1oClQK8hohw=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03080601/PARTIDA-BRISTOL-CITY-2.jpg" class="image-lazy"></a></div> <style>#flex_1241.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_1241.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fAgG012g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-boca-vs-arsenal-hora-tv-arbitro-y-formaciones/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Boca buscará ante Arsenal un resultado que aleje los fantasmas: hora, TV, árbitro y formaciones </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_4998" class="lazy-wrapper photo-wrapper"> <a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-boca-vs-arsenal-hora-tv-arbitro-y-formaciones/"><img data-original="https://www.infobae.com/new-resizer/52xrGqaxiziwIEgP5uz0Sq3Ndm0=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/01184009/Boca-Juniors-vs-Chacarita-Juniors-1920-3.jpg" class="image-lazy"></a></div> <style>#flex_4998.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_4998.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f06nWvtg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-tigre-vs-san-lorenzo-hora-tv-arbitro-y-formaciones/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> San Lorenzo visita a Tigre para superar a Boca y ser el nuevo líder: hora, TV, árbitro y formaciones </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_3439" class="lazy-wrapper photo-wrapper"> <a href="/deportes-2/2017/12/03/superliga-argentina-20172018-fecha-11-tigre-vs-san-lorenzo-hora-tv-arbitro-y-formaciones/"><img data-original="https://www.infobae.com/new-resizer/bWfREjUA_H17Qy9fA01pcxu5_NM=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/04/02193748/Tigre-vs-San-Lorenzo-2017-1920-Telam.jpg" class="image-lazy"></a></div> <style>#flex_3439.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_3439.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0X2H9Zg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/deportes-2/2017/12/03/superliga-argentina-20162017-fecha-11-talleres-vs-estudiantes/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Talleres recibe a Estudiantes para acercarse a la cima: hora, TV y formaciones </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_856" class="lazy-wrapper photo-wrapper"> <a href="/deportes-2/2017/12/03/superliga-argentina-20162017-fecha-11-talleres-vs-estudiantes/"><img data-original="https://www.infobae.com/new-resizer/YRtH5ZxPVN7RX4moey6FvIjbGeQ=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03070044/talleres-vs-estudiantes-superliga-1920.jpg" class="image-lazy"></a></div> <style>#flex_856.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_856.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain" id="c0RxE6EFOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fodP881g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-center equalize-height-target"> <div class="label-wrapper text-align-center"> <a href="https://www.infobae.com/tendencias/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_9017760" data-pb-field="custom.label" data-pb-placeholder="Label">TENDENCIAS</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0WZbSpg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/discapacidad/2017/12/02/reflexion-conciencia-e-inclusion-los-3-objetivos-que-persigue-el-dia-internacional-de-las-personas-con-discapacidad/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Reflexión, conciencia e inclusión, los 3 objetivos que persigue el Día Internacional de las Personas con Discapacidad </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6203" class="lazy-wrapper photo-wrapper"> <a href="/discapacidad/2017/12/02/reflexion-conciencia-e-inclusion-los-3-objetivos-que-persigue-el-dia-internacional-de-las-personas-con-discapacidad/"><img data-original="https://www.infobae.com/new-resizer/OrVJ4FksGGi_EnTPTVvlh1NXPJw=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01151604/discapacidad.jpg" class="image-lazy"></a></div> <style>#flex_6203.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6203.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0kjckmg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/turismo/2017/12/02/turismo-instagrammer-los-10-rincones-mas-fotogenicos-de-jamaica/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Turismo instagrammer: los 10 rincones más "fotogénicos" de Jamaica </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1591" class="lazy-wrapper photo-wrapper"> <a href="/turismo/2017/12/02/turismo-instagrammer-los-10-rincones-mas-fotogenicos-de-jamaica/"><img data-original="https://www.infobae.com/new-resizer/4J_GegtAPRNosLKfU_eKCJNbuYo=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/26145521/jamaica-2.jpg" class="image-lazy"></a></div> <style>#flex_1591.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_1591.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fW0LGR1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/tendencias/2017/12/02/narda-lepes-uno-de-los-errores-mas-grandes-es-preguntarle-a-los-chicos-que-quieren-comer/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Narda Lepes: "Uno de los errores más grandes es preguntarle a los chicos qué quieren comer" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6979" class="lazy-wrapper photo-wrapper"> <a href="/tendencias/2017/12/02/narda-lepes-uno-de-los-errores-mas-grandes-es-preguntarle-a-los-chicos-que-quieren-comer/"><img data-original="https://www.infobae.com/new-resizer/C3VHqg20pdYUd-2c3xRsAvPlKdo=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30142733/narda-portada.jpg" class="image-lazy"></a></div> <style>#flex_6979.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6979.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0DyQLfg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/tendencias/2017/12/02/julian-serrano-a-solas-con-infobae-los-jovenes-de-hoy-son-autodidactas-ambiciosos-y-emprendedores/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Julián Serrano, a solas con Infobae: "Los jóvenes de hoy son autodidactas, ambiciosos y emprendedores" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6693" class="lazy-wrapper photo-wrapper"> <a href="/tendencias/2017/12/02/julian-serrano-a-solas-con-infobae-los-jovenes-de-hoy-son-autodidactas-ambiciosos-y-emprendedores/"><img data-original="https://www.infobae.com/new-resizer/bExHnE6e6ZQa7TyXcue8nsx3xc8=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30145414/julian-serrano.jpg" class="image-lazy"></a></div> <style>#flex_6693.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6693.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0jHQggFOu6IBq"> <div id="exp-push-3-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-3-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-3-970x250","/1058609/infobae/sociedad/nota/exp_push_3_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain full" id="cbqaIH1FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f3LWzd1f7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/gente/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_5384964" data-pb-field="custom.label" data-pb-placeholder="Label"><img src="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/02173813/gente-25.png" style="height:24px; margin-top:-5px"></div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0mmsI9f7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/gente/lo-ultimo/2017/12/02/toto-kirzner-debuta-en-los-unitarios-de-la-fundacion-huesped-y-dice-hay-prejuicios-y-discriminacion-sobre-el-sida/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Toto Kirzner debuta en los unitarios de la Fundación Huésped y dice: "Hay prejuicios y discriminación sobre el SIDA" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_5848" class="lazy-wrapper photo-wrapper"> <a href="/gente/lo-ultimo/2017/12/02/toto-kirzner-debuta-en-los-unitarios-de-la-fundacion-huesped-y-dice-hay-prejuicios-y-discriminacion-sobre-el-sida/"><img data-original="https://www.infobae.com/new-resizer/O9mKGdyH5B-Jv9YgcYks6rtyrwo=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27104906/GENTE-TOTO-Kirzner-AP-004-241117.jpg" class="image-lazy"></a></div> <style>#flex_5848.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_5848.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0pQnPsf7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/gente/personajes/2017/12/02/los-rituales-de-axel-antes-de-cada-show-piso-el-escenario-y-siento-una-explosion/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Los rituales de Axel antes de cada show: "Piso el escenario y siento una explosión" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_5996" class="lazy-wrapper photo-wrapper"> <a href="/gente/personajes/2017/12/02/los-rituales-de-axel-antes-de-cada-show-piso-el-escenario-y-siento-una-explosion/"><img data-original="https://www.infobae.com/new-resizer/s93U6tfFeCi6Ez_FadNzzfjZ0h4=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/27222707/GENTE-RECITAL-AXEL-AP-017-FOM-20171128.jpg" class="image-lazy"></a></div> <style>#flex_5996.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_5996.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fbt12L1f7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/gente/revista-gente-fotos/2017/12/02/las-fotos-mas-sensuales-de-barbie-velez-en-gente/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Las fotos más sensuales de Barbie Vélez en GENTE </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_9490" class="lazy-wrapper photo-wrapper"> <a href="/gente/revista-gente-fotos/2017/12/02/las-fotos-mas-sensuales-de-barbie-velez-en-gente/"><img data-original="https://www.infobae.com/new-resizer/DeNaRzPPQp4-Jcg2OKaGyYVH_y0=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01162803/GENTE-BarbieVelez-APERTURA2-011217-02.jpg" class="image-lazy"></a></div> <style>#flex_9490.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_9490.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fWjAv02f7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/gente/notas-de-tapa/2017/11/28/barbie-velez-despues-de-fede-bal-hay-muchos-lugares-que-evito-para-no-cruzarlo/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Barbie Vélez después de Fede Bal: "Hay muchos lugares que evito para no cruzarlo" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_3751" class="lazy-wrapper photo-wrapper"> <a href="/gente/notas-de-tapa/2017/11/28/barbie-velez-despues-de-fede-bal-hay-muchos-lugares-que-evito-para-no-cruzarlo/"><img data-original="https://www.infobae.com/new-resizer/erwd19H8nCdPPC8jM0ZESPNr1co=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/28094237/GENTE-BARBIE-VELEZ-002-2711171.jpg" class="image-lazy"></a></div> <style>#flex_3751.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_3751.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain full" id="cYJc9I1FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f0bbjBig7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-center equalize-height-target"> <div class="label-wrapper text-align-center"> <a href="https://www.infobae.com/salud/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_1123380" data-pb-field="custom.label" data-pb-placeholder="Label">SALUD</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fVKVnY1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/salud/fitness/2017/12/02/the-trip-el-entrenamiento-futurista-de-ciclismo-indoor-que-es-furor-en-europa/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> The Trip, el entrenamiento futurista de ciclismo indoor que es furor en Europa </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_2551" class="lazy-wrapper photo-wrapper"> <a href="/salud/fitness/2017/12/02/the-trip-el-entrenamiento-futurista-de-ciclismo-indoor-que-es-furor-en-europa/"><img data-original="https://www.infobae.com/new-resizer/tb6U33BQ6Abvukc1HwPIT1901x4=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/28191540/the-trip.jpg" class="image-lazy"></a></div> <style>#flex_2551.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_2551.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fyRyZX1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/salud/2017/12/01/vivir-con-hipertimesia-el-extrano-sindrome-de-los-que-recuerdan-con-exactitud-cada-detalle-de-su-vida/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Vivir con hipertimesia, el extraño síndrome de los que recuerdan con exactitud cada detalle de su vida </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_957" class="lazy-wrapper photo-wrapper"> <a href="/salud/2017/12/01/vivir-con-hipertimesia-el-extrano-sindrome-de-los-que-recuerdan-con-exactitud-cada-detalle-de-su-vida/"><img data-original="https://www.infobae.com/new-resizer/K4c5Gjdk6qy-whpvAUSPgxPbok4=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30134206/GettyImages-543174872.jpg" class="image-lazy"></a></div> <style>#flex_957.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_957.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0y3nImg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/salud/2017/12/01/el-spa-del-corazon-asi-funciona-la-ultima-tecnologia-para-el-tratamiento-de-angioplastias/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> El spa del corazón: así funciona la última tecnología para el tratamiento de angioplastias </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_3025" class="lazy-wrapper photo-wrapper"> <a href="/salud/2017/12/01/el-spa-del-corazon-asi-funciona-la-ultima-tecnologia-para-el-tratamiento-de-angioplastias/"><img data-original="https://www.infobae.com/new-resizer/vsC8urmO6AetNnMxPyqBDsIeDM4=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/08/29084700/cuidado-corazon-2.jpg" class="image-lazy"></a></div> <style>#flex_3025.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_3025.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0d4PGgg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/salud/fitness/2017/12/01/el-plan-fit-para-el-verano-la-rutina-ideal-para-afinar-la-silueta-antes-de-las-vacaciones/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> El plan fit para el verano: la rutina ideal para afinar la silueta antes de las vacaciones </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1794" class="lazy-wrapper photo-wrapper"> <a href="/salud/fitness/2017/12/01/el-plan-fit-para-el-verano-la-rutina-ideal-para-afinar-la-silueta-antes-de-las-vacaciones/"><img data-original="https://www.infobae.com/new-resizer/evSziA2xz-hO8Irc_vIr02N5o3g=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30162416/playa-entrenamiento.jpg" class="image-lazy"></a></div> <style>#flex_1794.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_1794.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="f0PYm6WFOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fYUikr1FOu6IBq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="http://www.infobae.com/america/fotos/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_355378" data-pb-field="custom.label" data-pb-placeholder="Label">FOTOS AL 100</div> </a> </div> </div> </div> </div> <div class="pb-container"> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain col-lg-12 col-md-12 col-sm-12 col-xs-12" id="cUETB72FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="f09Xaimg7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/vidriera/2017/12/03/40-fotos-del-124o-campeonato-argentino-abierto-de-polo-de-palermo/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> 40 fotos del 124º Campeonato Argentino Abierto de Polo de Palermo </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6596" class="lazy-wrapper photo-wrapper"> <a href="/vidriera/2017/12/03/40-fotos-del-124o-campeonato-argentino-abierto-de-polo-de-palermo/"><img data-original="https://www.infobae.com/new-resizer/UgWnm-sqKzNRVhG5xW2c7-MxP-8=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03051929/valeria-mazza1.jpg" class="image-lazy"></a></div> <style>#flex_6596.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_6596.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="fm1eng1g7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/fotos-teleshow/2017/12/03/un-fuego-las-fotos-mas-sexies-de-vicky-garay-la-cunada-de-pampita-en-la-intimidad-tengo-la-iniciativa/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> ¡Un fuego! Las fotos más sexies de Vicky Garay, la cuñada de Pampita: "En la intimidad tengo la iniciativa" </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6736" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/fotos-teleshow/2017/12/03/un-fuego-las-fotos-mas-sexies-de-vicky-garay-la-cunada-de-pampita-en-la-intimidad-tengo-la-iniciativa/"><img data-original="https://www.infobae.com/new-resizer/w5Vt8TMqiJmcFdCBZ0IZsQf4dd8=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30125820/Vicky-Garay-cunada-Pampita-8.jpg" class="image-lazy"></a></div> <style>#flex_6736.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_6736.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="f0q3bwig7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/gente/revista-gente-fotos/2017/12/02/las-fotos-mas-sensuales-de-barbie-velez-en-gente/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Las fotos más sensuales de Barbie Vélez en GENTE </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1752" class="lazy-wrapper photo-wrapper"> <a href="/gente/revista-gente-fotos/2017/12/02/las-fotos-mas-sensuales-de-barbie-velez-en-gente/"><img data-original="https://www.infobae.com/new-resizer/WY0dN2YIclfNe-8yHVrFMVP4gCk=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01162803/GENTE-BarbieVelez-APERTURA2-011217-02.jpg" class="image-lazy"></a></div> <style>#flex_1752.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_1752.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fOnNlj1g7DnoCq"> <div class="border-bottom-off"></div> </div> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="f0I1hnug7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/fotos-teleshow/2017/12/02/asi-lucian-los-actores-de-el-chavo-del-8-cuando-eran-ninos-en-la-vida-real/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Así lucían los actores de "El Chavo del 8" cuando eran niños en la vida real </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1473" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/fotos-teleshow/2017/12/02/asi-lucian-los-actores-de-el-chavo-del-8-cuando-eran-ninos-en-la-vida-real/"><img data-original="https://www.infobae.com/new-resizer/kRNFVofmqVaiOJME7eqI_Ry3I5s=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/06/18125550/1457985288-chavo-del-8-y-su-cancelacion.jpg" class="image-lazy"></a></div> <style>#flex_1473.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_1473.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="f0IRKNog7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/vidriera/2017/12/02/25-fotos-del-100-aniversario-de-la-residencia-britanica/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> 25 fotos del 100° aniversario de la Residencia Británica </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_8402" class="lazy-wrapper photo-wrapper"> <a href="/vidriera/2017/12/02/25-fotos-del-100-aniversario-de-la-residencia-britanica/"><img data-original="https://www.infobae.com/new-resizer/h0TF3u1_fPFYvReVzQE2pw_Q4rg=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01163839/Aniversario-Embajada-de-Reino-Unido-21.jpg" class="image-lazy"></a></div> <style>#flex_8402.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_8402.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-4 col-xs-12 col-md-4 pb-feature pb-layout-item pb-f-homepage-story-feed col-sm-4" id="f0BKb6eg7DnoCq"> <div class="border-bottom-tight flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/teleshow/fotos-teleshow/2017/12/02/la-semana-en-imagenes-el-suicidio-de-rocio-gancedo-el-polemico-noviazgo-de-barbie-velez-y-la-gala-de-gente/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La semana, en imágenes: el suicidio de Rocío Gancedo, el polémico noviazgo de Barbie Vélez y la gala de Gente </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_7735" class="lazy-wrapper photo-wrapper"> <a href="/teleshow/fotos-teleshow/2017/12/02/la-semana-en-imagenes-el-suicidio-de-rocio-gancedo-el-polemico-noviazgo-de-barbie-velez-y-la-gala-de-gente/"><img data-original="https://www.infobae.com/new-resizer/Fi1nrjjm8sXWDxhOQ0KxjdsdsG8=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/01132302/Semana-imagenes.jpg" class="image-lazy"></a></div> <style>#flex_7735.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_7735.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="fOsxDr1FOu6IBq"> <div id="exp-push-4-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-4-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-4-970x250","/1058609/infobae/sociedad/nota/exp_push_4_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fpYsDi2FOu6IBq"> <div class="border-bottom-none"></div> </div> <div class="pb-container"> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain" id="cDMwUv1FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fqgKgI1g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/series-peliculas/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_4556411" data-pb-field="custom.label" data-pb-placeholder="Label">SERIES Y PELÍCULAS</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0tn05Jg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/series-peliculas/2017/12/03/young-sheldon-un-spin-off-de-la-serie-la-teoria-del-big-bang/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> “Young Sheldon”: un spin-off de la serie “La teoría del Big Bang” </a> </div> <div class="blurb normal-style" data-pb-field="description.basic" data-pb-field-type="text" data-pb-placeholder="Write blurb here.">🍿🍿🍿 Buena</div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_1293" class="lazy-wrapper photo-wrapper"> <a href="/series-peliculas/2017/12/03/young-sheldon-un-spin-off-de-la-serie-la-teoria-del-big-bang/"><img data-original="https://www.infobae.com/new-resizer/0564aPlHib0y4AVwwnLw8WZNyoc=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/02174411/sheldon8.jpg" class="image-lazy"></a></div> <style>#flex_1293.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_1293.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f05Dv52g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/series-peliculas/2017/12/02/el-actor-jeremy-renner-protagoniza-la-cinta-policiaca-viento-salvaje/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> El policial “Viento salvaje”, con Jeremy Renner, llega al streaming vía iTunes </a> </div> <div class="blurb normal-style" data-pb-field="description.basic" data-pb-field-type="text" data-pb-placeholder="Write blurb here.">🍿🍿🍿🍿 Muy Buena</div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_8881" class="lazy-wrapper photo-wrapper"> <a href="/series-peliculas/2017/12/02/el-actor-jeremy-renner-protagoniza-la-cinta-policiaca-viento-salvaje/"><img data-original="https://www.infobae.com/new-resizer/cIhw1FZ0NLaN0UHeEkBDX4tPr64=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/30134716/wind5.jpg" class="image-lazy"></a></div> <style>#flex_8881.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_8881.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fhxzjT1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/series-peliculas/2017/12/02/la-querida-del-centauro-serie-netflix/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La segunda temporada de “La querida del Centauro” trae acción y venganza </a> </div> <div class="blurb normal-style" data-pb-field="description.basic" data-pb-field-type="text" data-pb-placeholder="Write blurb here.">🍿🍿🍿🍿🍿 Excelente</div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_4261" class="lazy-wrapper photo-wrapper"> <a href="/series-peliculas/2017/12/02/la-querida-del-centauro-serie-netflix/"><img data-original="https://www.infobae.com/new-resizer/AOfkpyAGNm7FB2FXy4eh4Q2zIt0=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/22094847/querida7.jpg" class="image-lazy"></a></div> <style>#flex_4261.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_4261.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fsQTMO1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="skin skin-card flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/series-peliculas/2017/12/01/32-pills-my-sisters-suicide-se-estrena-en-hbo/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> “32 Pills: My Sister’s Suicide”: un documental desgarrador en HBO </a> </div> <div class="blurb normal-style" data-pb-field="description.basic" data-pb-field-type="text" data-pb-placeholder="Write blurb here.">🍿🍿🍿 Buena</div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_7721" class="lazy-wrapper photo-wrapper"> <a href="/series-peliculas/2017/12/01/32-pills-my-sisters-suicide-se-estrena-en-hbo/"><img data-original="https://www.infobae.com/new-resizer/BXyYUEsoYXgq85VtBXHrOfcA_hc=/999x999/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/20171636/pills5.jpeg" class="image-lazy"></a></div> <style>#flex_7721.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:100.0%}#flex_7721.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain" id="c0r7MoKFOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="fxA1VN1g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/america/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_6602736" data-pb-field="custom.label" data-pb-placeholder="Label">INFOBAE AMÉRICA</div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0A4tzxg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/america/venezuela/2017/12/02/la-oposicion-venezolana-califico-de-relevante-el-dialogo-con-el-regimen-de-nicolas-maduro/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La oposición venezolana calificó de "relevante" el diálogo con el régimen de Nicolás Maduro </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_4728" class="lazy-wrapper photo-wrapper"> <a href="/america/venezuela/2017/12/02/la-oposicion-venezolana-califico-de-relevante-el-dialogo-con-el-regimen-de-nicolas-maduro/"><img data-original="https://www.infobae.com/new-resizer/AUFnC7lWvqDSXK7n9n5c2cLZlHY=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02230532/julio-borges.jpg" class="image-lazy"></a></div> <style>#flex_4728.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_4728.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fkZpIn1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/america/eeuu/2017/12/03/la-felicidad-de-una-perra-rescatada-de-la-calle-luego-de-recibir-un-corte-de-pelo-y-ser-adoptada/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La felicidad de una perra rescatada de la calle luego de recibir un corte de pelo y ser adoptada </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_9039" class="lazy-wrapper photo-wrapper"> <a href="/america/eeuu/2017/12/03/la-felicidad-de-una-perra-rescatada-de-la-calle-luego-de-recibir-un-corte-de-pelo-y-ser-adoptada/"><img data-original="https://www.infobae.com/new-resizer/82fqkJzLYSZ29x3SmW4iB3oI0GE=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03013054/perro-callejero-.jpg" class="image-lazy"></a></div> <style>#flex_9039.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_9039.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0c5XQVg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Afganistán: un terrorista hizo estallar su motocicleta y mató a seis personas en el norte del país </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_380" class="lazy-wrapper photo-wrapper"> <a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/"><img data-original="https://www.infobae.com/new-resizer/xjF9ninc_gb063jjrgzgdtMz8k4=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03075442/Atentado-en-Jalalabad-Afganistan-2.jpg" class="image-lazy"></a></div> <style>#flex_380.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_380.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0eAMdrg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline x-small normal-style "> <a href="/series-peliculas/2017/12/03/young-sheldon-un-spin-off-de-la-serie-la-teoria-del-big-bang/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> “Young Sheldon”: un spin-off de la serie “La teoría del Big Bang” </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_2485" class="lazy-wrapper photo-wrapper"> <a href="/series-peliculas/2017/12/03/young-sheldon-un-spin-off-de-la-serie-la-teoria-del-big-bang/"><img data-original="https://www.infobae.com/new-resizer/orok5NUpB9AvW-PM8Uu8f77qWE8=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/02174411/sheldon8.jpg" class="image-lazy"></a></div> <style>#flex_2485.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_2485.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f06IFjoFOu6IBq"> <div id="exp-push-5-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-5-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-5-970x250","/1058609/infobae/sociedad/nota/exp_push_5_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="pb-container"> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain" id="ckKFao1FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f3joKi2g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/america/wapo/"> <div style="color:#000000;background-color:#000000;" class="pb-font-smoothing label label-bar label-with-background class_5768958" data-pb-field="custom.label" data-pb-placeholder="Label"><img src="https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/05/22094331/the-washington-post_logo.png" style="height:28px; margin-top:-1px"></div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0pyzIrg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/wapo/2017/12/03/como-el-perro-parlante-de-alexander-graham-bell-ayudo-al-diseno-del-apple-iphone-x/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> De qué forma el perro parlante de Alexander Graham Bell ayudó al diseño del iPhone X </a> </div> <div class="art art-low art-x-small art-full-width text-align-left no-art-separator"> <div id="flex_3150" class="lazy-wrapper photo-wrapper"> <a href="/america/wapo/2017/12/03/como-el-perro-parlante-de-alexander-graham-bell-ayudo-al-diseno-del-apple-iphone-x/"><img data-original="https://www.infobae.com/new-resizer/P3xpBeKhzmpLzNStNJd5pDwTvaE=/999x751/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/21152830/iphone-tienda-apple.jpg" class="image-lazy"></a></div> <style>#flex_3150.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:75.18796992481202%}#flex_3150.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f1A6Gy1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/wapo/2017/12/03/mi-hermana-sigue-saliendo-con-hombres-mayores-acaso-es-por-culpa-de-nuestro-padre/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Mi hermana sigue saliendo con hombres mayores ¿Acaso es por culpa de nuestro padre? </a> </div> <div class="art art-low art-x-small art-full-width text-align-left no-art-separator"> <div id="flex_6333" class="lazy-wrapper photo-wrapper"> <a href="/america/wapo/2017/12/03/mi-hermana-sigue-saliendo-con-hombres-mayores-acaso-es-por-culpa-de-nuestro-padre/"><img data-original="https://www.infobae.com/new-resizer/v7mVgpICo2sJw3MhzWJlMWvI7l4=/999x751/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/30161427/PARATI-PAREJA-APERTURA-ESTARMEJOR-150917.jpg" class="image-lazy"></a></div> <style>#flex_6333.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:75.18796992481202%}#flex_6333.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0pA22yg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/wapo/2017/12/03/como-el-aspecto-humoristico-de-lo-burdo-puede-ayudar-a-los-ninos-a-entender-sus-cuerpos/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Cómo el aspecto humorístico de lo burdo puede ayudar a los niños a entender sus cuerpos </a> </div> <div class="art art-low art-x-small art-full-width text-align-left no-art-separator"> <div id="flex_3153" class="lazy-wrapper photo-wrapper"> <a href="/america/wapo/2017/12/03/como-el-aspecto-humoristico-de-lo-burdo-puede-ayudar-a-los-ninos-a-entender-sus-cuerpos/"><img data-original="https://www.infobae.com/new-resizer/46VTEtSQHJxGnI5KLhXnQQLauZ4=/999x751/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/08/18104012/iStock-665870928.jpg" class="image-lazy"></a></div> <style>#flex_3153.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:75.18796992481202%}#flex_3153.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0gXLurg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/wapo/2017/12/02/ondas-gravitacionales-estrellas-de-neutrones-y-kilonovas-que-significan-para-la-fisica/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Ondas gravitacionales, estrellas de neutrones y kilonovas ¿Qué significan para la física? </a> </div> <div class="art art-low art-x-small art-full-width text-align-left no-art-separator"> <div id="flex_4205" class="lazy-wrapper photo-wrapper"> <a href="/america/wapo/2017/12/02/ondas-gravitacionales-estrellas-de-neutrones-y-kilonovas-que-significan-para-la-fisica/"><img data-original="https://www.infobae.com/new-resizer/QZEca-Rj5yrdHsBE5H_ti5o3WPk=/999x751/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/10/11172746/GettyImages-472679632.jpg" class="image-lazy"></a></div> <style>#flex_4205.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:75.18796992481202%}#flex_4205.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="standard-chain in-chain border-bottom-none pb-layout-item pb-chain pb-c-standard-chain" id="c2DhVC1FOu6IBq"> <div class="chain-content no-skin"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f07hVJ1g7DnoCq"> <div class="border-bottom-kinda-tight"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="label-wrapper text-align-inherit"> <a href="https://www.infobae.com/america/vice/"> <div style="color:#000000;background-color:#DDDDDD;" class="pb-font-smoothing label label-bar label-with-background class_2335339" data-pb-field="custom.label" data-pb-placeholder="Label"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/09/14154721/logo_vice.png&mode=crop&h=24&q=75&token=bar" style="height:24px; margin-top:-5px"></div> </a> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fcp6Fa2g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/vice/2017/12/02/practique-el-mejor-sexo-de-mi-vida-estando-embarazada/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La experiencia de practicar el mejor sexo de tu vida estando embarazada </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6176" class="lazy-wrapper photo-wrapper"> <a href="/america/vice/2017/12/02/practique-el-mejor-sexo-de-mi-vida-estando-embarazada/"><img data-original="https://www.infobae.com/new-resizer/6Dq6FU-bJMy7S8cGTWb1tEMftvA=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30072118/embarazo-pareja.jpg" class="image-lazy"></a></div> <style>#flex_6176.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6176.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f47lg72g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/vice/2017/12/02/escuchar-musica-en-el-trabajo-puede-empeorar-tu-desempeno/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Escuchar música en el trabajo puede empeorar tu desempeño profesional </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_6445" class="lazy-wrapper photo-wrapper"> <a href="/america/vice/2017/12/02/escuchar-musica-en-el-trabajo-puede-empeorar-tu-desempeno/"><img data-original="https://www.infobae.com/new-resizer/wcE6Gmso_wlNnoZ0oeaPejwtXTM=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30205805/escuchar-musica-trabajando.jpg" class="image-lazy"></a></div> <style>#flex_6445.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_6445.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="fbDncF1g7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/vice/2017/12/02/todo-lo-que-me-hubiera-gustado-saber-antes-de-ir-a-la-universidad/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> Todo lo que me hubiera gustado saber antes de ir a la universidad </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_2107" class="lazy-wrapper photo-wrapper"> <a href="/america/vice/2017/12/02/todo-lo-que-me-hubiera-gustado-saber-antes-de-ir-a-la-universidad/"><img data-original="https://www.infobae.com/new-resizer/hGbzz9dscI1oPngO5JZxLh2vq8U=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/30035331/Vuelta-a-las-aulas.jpg" class="image-lazy"></a></div> <style>#flex_2107.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_2107.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-md-3 col-xs-12 col-sm-3 pb-feature pb-layout-item pb-f-homepage-story-feed" id="f0Gwq1lg7DnoCq"> <div class="border-bottom-hairline flex-feature-wrapper"> <div class="no-skin flex-item flex-stack text-align-left equalize-height-target"> <div class="headline small normal-style "> <a href="/america/vice/2017/12/01/la-alergia-a-la-comida-podria-afectar-la-salud-mental-de-los-ninos/" data-pb-field="headline" data-pb-url-field="canonical_url" data-pb-placeholder="Write headline here"> La alergia a la comida podría afectar la salud mental de los niños </a> </div> <div class="art art-low art-small art-full-width text-align-left no-art-separator"> <div id="flex_5946" class="lazy-wrapper photo-wrapper"> <a href="/america/vice/2017/12/01/la-alergia-a-la-comida-podria-afectar-la-salud-mental-de-los-ninos/"><img data-original="https://www.infobae.com/new-resizer/GvaK3yL2gIUkYUgRVOnY7_En5n8=/999x561/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/29223312/manies-cacahuates.jpg" class="image-lazy"></a></div> <style>#flex_5946.lazy-wrapper{position:relative;height:0;overflow:hidden;padding-bottom:56.17977528089888%}#flex_5946.lazy-wrapper img{position:absolute;top:0;left:0;width:100%;height:100%}</style> <div class="clear"></div> </div> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fLyh9K1FOu6IBq"> <div class="border-bottom-tight"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f08Jv41FOu6IBq"> <div id="exp-push-6-970x250" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod expandable ad-970X90 hide-mobile" data-slot-name="exp-push-6-970x250" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("exp-push-6-970x250","/1058609/infobae/sociedad/nota/exp_push_6_970x250",[[970,90],[970,250]],"expandable");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-single-line" id="fjwl7i1FOu6IBq"> <div class="border-bottom-tight"></div> </div> <div class="standard-chain in-chain border-bottom- pb-layout-item pb-chain pb-c-standard-chain full" id="cs1ZT22FOu6IBq"> <div class="chain-content equalize-heights no-skin"> <div class="wrapper clearfix col-lg-3 col-sm-6 col-md-3 col-xs-12 pb-feature pb-layout-item pb-f-list-card-column" id="fpCCIO1FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/ultimas-noticias"><strong>ÚLTIMAS NOTICIAS</strong></a></h3></header> <div class="column-item"> <a href="/politica/2017/12/03/g20-venezuela-y-la-busqueda-del-ara-san-juan-la-agenda-de-marcos-pena-en-su-visita-a-eeuu/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/w1z7tobCQL3GZ9YhdYCC9UuUbC0=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/02193822/Marcos-Pena-con-Ricky-Waddell-1920.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/politica/2017/12/03/g20-venezuela-y-la-busqueda-del-ara-san-juan-la-agenda-de-marcos-pena-en-su-visita-a-eeuu/">G20, Venezuela y la búsqueda del ARA San Juan, la agenda de Marcos Peña en su visita a EEUU</a></h4> </div> <div class="column-item"> <h4><a href="/sociedad/2017/12/03/cuanto-dinero-se-necesita-para-armar-el-arbolito-navideno/">¿Cuánto dinero se necesita para armar el arbolito navideño?</a></h4> </div> <div class="column-item"> <h4><a href="/sociedad/2017/12/03/un-taller-de-panes-dulces-donde-la-integracion-es-posible/">Un taller de panes dulces donde la integración es posible</a></h4> </div> <div class="column-item"> <h4><a href="/economia/2017/12/03/orlando-ferreres-en-2018-la-economia-va-a-crecer-menos-y-tambien-la-inflacion-sera-menor/">Orlando Ferreres: "En 2018 la economía va a crecer menos y también la inflación será menor"</a></h4> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-sm-6 col-md-3 col-xs-12 pb-feature pb-layout-item pb-f-list-card-column" id="fhTMuN1FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/america/"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/09/27141508/america.png&mode=crop&h=24&q=75&token=bar" style="height:22px; margin-top:-6px"></a></h3></header> <div class="column-item"> <a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/nsbMjcTGaowWVNWWetFTZuLTtxI=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03075442/Atentado-en-Jalalabad-Afganistan-2.jpg" alt="(AFP)" class="image-lazy"> </div> </a> <h4 class="first"><a href="/america/mundo/2017/12/03/afganistan-un-terrorista-hizo-estallar-su-motocicleta-y-mato-a-seis-personas-en-el-norte-del-pais/">Afganistán: un terrorista hizo estallar su motocicleta y mató a seis personas en el norte del país</a></h4> </div> <div class="column-item"> <h4><a href="/america/opinion/2017/12/03/la-falacia-de-los-robots-y-la-futura-falta-de-empleos/">La falacia de los robots y la futura falta de empleos</a></h4> </div> <div class="column-item"> <h4><a href="/america/cultura-america/2017/12/03/auguste-rodin-el-mal-alumno-al-que-sus-padres-enviaron-a-la-escuela-de-arte/">Auguste Rodin, el “mal alumno” al que sus padres enviaron a la escuela de arte</a></h4> </div> <div class="column-item"> <h4><a href="/america/mundo/2017/12/03/la-horrenda-historia-de-la-condesa-hungara-que-asesino-a-mas-de-600-mujeres-para-lograr-la-belleza-eterna-con-su-sangre/">La horrenda historia de la condesa húngara que asesinó a más de 600 mujeres para lograr la belleza eterna con su sangre</a></h4> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-sm-6 col-md-3 col-xs-12 pb-feature pb-layout-item pb-f-list-card-column" id="frLX6u1FOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/teleshow/"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/05/29175800/Logo_teleshow.png&mode=crop&h=24&q=75&token=bar" style="height:26px; margin-top:-7px"></a></h3></header> <div class="column-item"> <a href="/teleshow/infoshow/2017/12/03/quienes-son-yon-gonzalez-y-amaia-salamanca-los-actores-de-las-series-espanolas-que-hacen-furor-en-netflix/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/_mxs5x5gvgcmeLULs8iVkzwtCvI=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/11/21200606/gran-hotel.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/teleshow/infoshow/2017/12/03/quienes-son-yon-gonzalez-y-amaia-salamanca-los-actores-de-las-series-espanolas-que-hacen-furor-en-netflix/">Quiénes son Yon González y Amaia Salamanca, los actores de las series españolas que hacen furor en Netflix</a></h4> </div> <div class="column-item"> <h4><a href="/teleshow/infoshow/2017/12/03/la-ultima-moda-de-la-farandula-las-hijas-de-los-famosos-se-convierten-en-empresarias-y-lanzan-sus-propias-marcas/">La última moda de la farándula: las hijas de los famosos se convierten en empresarias y lanzan sus propias marcas</a></h4> </div> <div class="column-item"> <h4><a href="/teleshow/infoshow/2017/12/03/a-25-anos-del-boom-de-la-pachanga-la-historia-jamas-contada-del-hit-de-vilma-palma-quien-era-el-pelado/">A 25 años del boom de "La pachanga", la historia jamás contada del hit de Vilma Palma: ¿quién era "El Pelado"?</a></h4> </div> <div class="column-item"> <h4><a href="/america/entretenimiento/2017/12/03/los-curiosos-comienzos-como-extras-de-algunas-de-las-estrellas-mas-famosas-de-hollywood/">Los curiosos comienzos como extras de algunas de las estrellas más famosas de Hollywood</a></h4> </div> </div> </div> <div class="wrapper clearfix col-lg-3 col-sm-6 col-md-3 col-xs-12 pb-feature pb-layout-item pb-f-list-card-column" id="f03iXGIFOu6IBq"> <div class="col-sm-12 section-column"> <header><a href="/category/"></a><h3 class="header-label"><a href="/category/"></a><a href="http://www.infobae.com/deportes/"><img src="http://www.infobae.com/resizer/?op=resize&url=https://s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2016/08/29170312/logo_deportes.png&mode=crop&h=24&q=75&token=bar" style="height:21px; margin-top:-10px"></a></h3></header> <div class="column-item"> <a href="/deportes-2/2017/12/03/superliga-argentina-20162017-fecha-11-talleres-vs-estudiantes/"> <div class="lazy-wrapper"> <img data-original="https://www.infobae.com/new-resizer/sTkG8rPssqcsZ5tW3IocdSZMvsI=/600x400/filters:quality(100)/s3.amazonaws.com/arc-wordpress-client-uploads/infobae-wp/wp-content/uploads/2017/12/03070044/talleres-vs-estudiantes-superliga-1920.jpg" alt="" class="image-lazy"> </div> </a> <h4 class="first"><a href="/deportes-2/2017/12/03/superliga-argentina-20162017-fecha-11-talleres-vs-estudiantes/">Talleres recibe a Estudiantes para acercarse a la cima: hora, TV y formaciones</a></h4> </div> <div class="column-item"> <h4><a href="/deportes-2/2017/12/03/daniel-orsanic-a-un-ano-de-la-historica-davis-como-fue-que-el-joven-que-durmio-en-un-auto-se-transformo-en-el-capitan-campeon/">Daniel Orsanic, a un año de la histórica Davis: cómo fue que el joven que durmió en un auto se transformó en el capitán campeón</a></h4> </div> <div class="column-item"> <h4><a href="/deportes-2/2017/12/03/15-minutos-con-messi-en-el-fin-del-mundo-la-increible-historia-de-alejandro-ocampo/">15 minutos con Messi en el fin del mundo: la increíble historia de Alejandro Ocampo</a></h4> </div> <div class="column-item"> <h4><a href="/deportes-2/mundial-2018/2017/12/03/estamos-ante-el-mundial-mas-dificil-y-glorioso-de-la-historia/">Estamos ante el Mundial más difícil y glorioso de la historia</a></h4> </div> </div> </div> <div class="clear"></div> </div> <div class="clear"></div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-flyin" id="fIh1Tf1FOu6IBq"> <div class="flyin-pb flyin-pb-right"> <a onclick="ga('send', 'event', 'Flyin Button', 'click');" href="http://www.infobae.com/?noredirect"> <span class="full-pb-span"> <i class="fa fa-home"></i> </span> </a> <div class="close-btn-pb-flyin"> <i class="fa fa-times"></i> </div> </div> </div> <div class="pb-container"> </div></section> <section id="bottom" class=""> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-global-footer-colored" id="f0Pz041FOu6IBq"> <footer class="light"> <div class="footer-row-1 row"> <div class="homepage-footer-share-buttons"> <a href="https://www.facebook.com/Infobae/" target="_blank" class="homepage-footer-button"s> <i class="fa fa-facebook" aria-hidden="true"></i> </a> <a href="https://www.twitter.com/Infobae/" class="homepage-footer-button" target="_blank"> <i class="fa fa-twitter" aria-hidden="true"></i> </a> <a href="http://www.infobae.com/argentina-rss.xml" class="homepage-footer-button " target="_blank"> <i class="fa fa-rss" aria-hidden="true"></i> </a> <a href="https://www.instagram.com/Infobae/" class="homepage-footer-button" target="_blank"> <i class="fa fa-instagram" aria-hidden="true"></i> </a> <a href="https://www.youtube.com/c/infobae" class="homepage-footer-button " target="_blank"> <i class="fa fa-youtube-play" aria-hidden="true"></i> </a> <div class="clear"></div> </div> <aside class="header-label footer-nav-item logo-holder"> <img src="https://www.infobae.com/new-resizer/lL0I2ZL9bhnWNZ6yfu3ZDD8Ydho=/300x0/filters:quality(100)/s3.amazonaws.com/wapopartners.com/infobae-wp/wp-content/uploads/2016/03/29190548/infobae.png" class="footer-logo"/> </aside> <aside class="header-label footer-nav-item company-name"> Todos los derechos reservados © 2017 Infobae </aside> </div> <div class="footer-row-2 row"> <div class="footer-links col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="footer-nav has-sub col-sm-3 col-xs-12"> <a class="footer-nav-item header-label" href="http://www.infobae.com/">Infobae</a> <ul class="footer-sub-nav"> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/apps/">Apps</a> </li> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/ultimas-noticias/">Últimas noticias</a> </li> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/feeds/rss/">RSS</a> </li> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/sitemap.xml">Sitemap</a> </li> </ul> </div> <div class="footer-nav has-sub col-sm-3 col-xs-12"> <a class="footer-nav-item header-label" href="http://www.infobae.com/">Contáctenos</a> <ul class="footer-sub-nav"> <li class="footer-sub-nav-item header-label"> <a href="mailto:[email protected]">Contacto</a> </li> <li class="footer-sub-nav-item header-label"> <a href="mailto:[email protected]">Redacción</a> </li> <li class="footer-sub-nav-item header-label"> <a href="http://cdn01.ib.infobae.com/adjuntos/162/documentos/periodistas/index.html">Red de Periodistas</a> </li> <li class="footer-sub-nav-item header-label"> <a href="mailto:[email protected]">Comercial</a> </li> <li class="footer-sub-nav-item header-label"> <a href="http://mediakit.infobae.com">Media Kit</a> </li> </ul> </div> <div class="footer-nav has-sub col-sm-3 col-xs-12"> <a class="footer-nav-item header-label" href="http://www.infobae.com/">Redes Sociales</a> <ul class="footer-sub-nav"> <li class="footer-sub-nav-item header-label"> <a href="http://www.facebook.com/infobae">Facebook</a> </li> <li class="footer-sub-nav-item header-label"> <a href="http://www.twitter.com/infobae">Twitter</a> </li> <li class="footer-sub-nav-item header-label"> <a href="http://www.instagram.com/infobae">Instagram</a> </li> </ul> </div> <div class="footer-nav has-sub col-sm-3 col-xs-12"> <a class="footer-nav-item header-label" href="http://www.infobae.com/">legal</a> <ul class="footer-sub-nav"> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/terminos-y-condiciones/">Términos y Condiciones</a> </li> <li class="footer-sub-nav-item header-label"> <a href="https://www.infobae.com/politicas-de-privacidad/">Política de Privacidad</a> </li> </ul> </div> </div> <div class="footer-links col-lg-12 col-md-12 col-sm-12 col-xs-12"> </div> </div> </footer> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0daG6aFOu6IBq"> <div id="background-1x1" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod wallpaper ad-1900X1200 hide-mobile" data-slot-name="background-1x1" data-mobile-display="false" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none hide-mobile"></div> <script>window.dfpAdHelper.appendAd("background-1x1","/1058609/infobae/sociedad/nota/background_1x1",[1900,1200],"wallpaper");</script> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="finDRi2FOu6IBq"> <div id="zocalo-1x1" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod zocalo ad-940X80" data-slot-name="zocalo-1x1" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("zocalo-1x1","/1058609/infobae/sociedad/nota/zocalo_1x1",[[940,80],[320,50],[1,1]],"zocalo");</script> </div> <div class="pb-container"> <div class="wrapper clearfix pb-feature pb-layout-item pb-f-global-clavis" id="f0AHs12FOu6IBq"> <script>(function(){window.clavis={topics:[],keywords:[],auxiliaries:[],contentId:"5EPSP5OX6BDPPIKTHQ4JYUHSNI",targetingUrl:"https://targeting.infobae.arcpublishing.com/TargetingWebAPP/targeting"}})();</script> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-ads-dfp" id="f0e8Y9iFOu6IBq"> <div id="interstitial-800x600" class="dfp-ad-hidden pb-ad-container pb-ad pb-ad-prod interstitial ad-800X600" data-slot-name="interstitial-800x600" data-mobile-display="true" data-desktop-display="true"> </div> <div class="dfp-ad-hidden border-bottom-none"></div> <script>window.dfpAdHelper.appendAd("interstitial-800x600","/1058609/infobae/sociedad/nota/interstitial_800x600",[[800,600],[300,416],[518,690]],"interstitial");</script> </div> <div class="pb-container"> <div class="pb-layout-item pb-chain pb-c-default-chain full" id="ci7w7a2FOu6IBq"> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-homepage-story" id="f0o4uD8FOu6IBq"> </div> </div> </div> <div class="wrapper clearfix full pb-feature pb-layout-item pb-f-video-sticky-player" id="f0h0MCmFOu6IBq"> <div class="arc-sticky-player-video pb-font-smoothing wpv-hidden" data-video-background-image=""> <div class="arc-sticky-player-exit"> <i class="fa fa-times"></i> <span class="franklin-bold">Cerrar</span> </div> <div class="arc-sticky-player-wrapper" id="arc-sticky-player-wrapper"></div> <div class="arc-sticky-player-text wpv-hidden"> <div class="label label-normal">Now Playing</div> <div class="arc-sticky-player-caption pb-caption"></div> </div> </div> </div> <div class="pb-container"> </div></section> <div class="pb-container"> </div></div> <script>(function(){function g(a,d,c,e){var b=new XMLHttpRequest;b.open("GET",a);b.onreadystatechange=function(){if(4==b.readyState)if(200===b.status)try{var a=JSON.parse(b.responseText);d(a)}catch(e){c()}else c()};e&&(b.ontimeout=c,b.timeout=e);b.send()}function l(a){var d=Date.now()-p;g("https://bandito-events-prod.infobae.arcpublishing.com/api/save-perf?status\x3d"+a+"\x26time\x3d"+d,function(){},function(){})}function q(){for(var a in _variantFeatureIds)_variantFeatureIds.hasOwnProperty(a)&&(l("failure"), +k(_variantFeatureIds[a],!1))}function k(a,d){var c=document.getElementById(n[a]);m(a,a,c,d)}function t(a,d,c,e){var b=document.getElementById(a);g(_context+"/api/v2/render/feature/variant/"+c+"?rid\x3d"+_rid+"\x26uri\x3d"+_uri+"\x26outputType\x3d"+_outputType,function(a){var e=a.pageResources||{},f=b.parentNode,h=document.createElement("div");h.innerHTML=a.rendering;a=h.childNodes[0];f.replaceChild(a,b);f=Array.prototype.slice.call(a.getElementsByTagName("script"));for(h=0;h<f.length;h++)if(""!=f[h].src){var k= +document.createElement("script");k.setAttribute("src",f[h].src);document.body.appendChild(k)}else eval(f[h].innerHTML);for(var g in e)e.hasOwnProperty(g)&&g.endsWith(".js")&&(f=document.createElement("script"),f.setAttribute("src",e[g]),document.body.appendChild(f));l("success-variant");m(d,c,a,!0)},function(){l("failure-step2");m(d,d,b,!1)},e)}function m(a,d,c,e){r[a]||(r[a]=!0,c.style.visibility="visible",e&&(e=new XMLHttpRequest,e.open("POST","https://bandito-events-prod.infobae.arcpublishing.com/api/save-event", +!0),e.setRequestHeader("Content-Type","application/json"),e.send(JSON.stringify({event:"served",test_id:a,variant_id:d})),c.querySelectorAll("a").forEach(function(b){b.addEventListener("click",function(b){if(b&&b.target&&b.target.href){var c=new XMLHttpRequest;c.open("POST","https://bandito-events-prod.infobae.arcpublishing.com/api/save-event",!0);c.setRequestHeader("Content-Type","application/json");c.send(JSON.stringify({event:"clicked",test_id:a,variant_id:d}));0<b.button||b.ctrlKey||b.metaKey|| +b.shiftKey||(b.preventDefault(),setTimeout(function(){document.location=b.target.href},250))}})})))}function u(a){var d={};if(a&&a.length){for(var c=0;c<a.length;c++){var e=a[c].winner,b=a[c]._id,g=n[b];d[b]=!0;if(b==e)l("success-default"),k(b,!0);else{var m=1500-(Date.now()-p);50<m?t(g,b,e,m):(l("timeout-step1"),k(b,!1))}}for(var f in _variantFeatureIds)_variantFeatureIds.hasOwnProperty(f)&&(b=_variantFeatureIds[f],d[b]||(l("not-found"),k(b,!1)))}else q()}window.pageBuilder=window.pageBuilder||{}; +var n={},r={},p=Date.now();window.pageBuilder.showVariants=function(){var a=[],d;for(d in _variantFeatureIds)if(_variantFeatureIds.hasOwnProperty(d)){var c=_variantFeatureIds[d];n[c]=d;a.push(c)}a="/bandito/tests-pb/?q\x3d"+encodeURIComponent(JSON.stringify({_id:{$in:a}}));g(a,u,q)}})();</script> <script src="/pb/gr/c/default/rxO4LI1ihN8KCq/js/b4be7738ff.js?_=0365e"></script> <script src="/pb/gr/c/default/rxO4LI1ihN8KCq/footjs/b88498aec9.js?_=e49cb"></script> <script src="//www.youtube.com/iframe_api"></script> <script src="/pb/gr/c/default/rxO4LI1ihN8KCq/footjs/11f3bebf7c.js?_=e49cb"></script> <script src="https://d2ylgh2cnbot5i.cloudfront.net/v1/embed.js"></script> <script src="/pb/gr/c/default/rxO4LI1ihN8KCq/footjs/762e36a48c.js?_=e49cb"></script> <script src="/pb/gr/p/default/rxO4LI1ihN8KCq/render.js?_=c91be"></script> <script>jQuery(function(){jQuery.scrollDepth()});</script> <script>window.fbAsyncInit=function(){FB.init({appId:"303536999846097",xfbml:!0,version:"v2.6"})};(function(a,b,c){var d=a.getElementsByTagName(b)[0];a.getElementById(c)||(a=a.createElement(b),a.id=c,a.src="//connect.facebook.net/es_LA/sdk.js#xfbml\x3d1\x26version\x3dv2.6\x26appId\x3d303536999846097",d.parentNode.insertBefore(a,d))})(document,"script","facebook-jssdk");</script> <script>var _sf_async_config={uid:52562,domain:"infobae.com",useCanonical:!0,sections:"Sociedad",authors:"Mauricio Luna,Gisele Sousa Dias"};(function(){window._sf_endpt=(new Date).getTime();var a=document.createElement("script");a.setAttribute("language","javascript");a.setAttribute("type","text/javascript");a.setAttribute("src","//static.chartbeat.com/js/chartbeat.js");document.body.appendChild(a)})();</script> <script>dfpAdHelper.runAds();</script> </body> </html>
\ No newline at end of file diff --git a/test/test-pages/gmw/expected-metadata.json b/test/test-pages/gmw/expected-metadata.json index 77b24bf..2997886 100644 --- a/test/test-pages/gmw/expected-metadata.json +++ b/test/test-pages/gmw/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "宇航员在太空中喝酒会怎么样?后果很严重 _探索者 _光明网", - "byline": "肖春芳", - "dir": null, - "excerpt": "不幸的是,对于希望能喝上一杯的太空探险者,那些将他们送上太空的政府机构普遍禁止他们染指包括酒在内的含酒精饮料。", - "readerable": true + "Title": "宇航员在太空中喝酒会怎么样?后果很严重 _探索者 _光明网", + "Author": "肖春芳", + "Direction": null, + "Excerpt": "不幸的是,对于希望能喝上一杯的太空探险者,那些将他们送上太空的政府机构普遍禁止他们染指包括酒在内的含酒精饮料。" } diff --git a/test/test-pages/heise/expected-metadata.json b/test/test-pages/heise/expected-metadata.json index 48a5655..c723ccd 100644 --- a/test/test-pages/heise/expected-metadata.json +++ b/test/test-pages/heise/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "1Password für Mac generiert Einmal-Passwörter", - "byline": null, - "excerpt": "Das in der iOS-Version bereits enthaltene TOTP-Feature ist nun auch für OS X 10.10 verfügbar. Zudem gibt es neue Zusatzfelder in der Datenbank und weitere Verbesserungen.", - "readerable": true + "Title": "1Password für Mac generiert Einmal-Passwörter", + "Author": null, + "Excerpt": "Das in der iOS-Version bereits enthaltene TOTP-Feature ist nun auch für OS X 10.10 verfügbar. Zudem gibt es neue Zusatzfelder in der Datenbank und weitere Verbesserungen." } diff --git a/test/test-pages/herald-sun-1/expected-metadata.json b/test/test-pages/herald-sun-1/expected-metadata.json index 6c8b59b..4219464 100644 --- a/test/test-pages/herald-sun-1/expected-metadata.json +++ b/test/test-pages/herald-sun-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Angry media won’t buckle over new surveillance laws\n\t\t\t\t\t\t| Herald Sun", - "byline": "JOE HILDEBRAND", - "excerpt": "A HIGH-powered federal government team has been doing the rounds of media organisations in the past few days in an attempt to allay concerns about the impact of new surveillance legislation on press freedom. It failed.", - "readerable": true + "Title": "Angry media won’t buckle over new surveillance laws\n\t\t\t\t\t\t| Herald Sun", + "Author": "JOE HILDEBRAND", + "Excerpt": "A HIGH-powered federal government team has been doing the rounds of media organisations in the past few days in an attempt to allay concerns about the impact of new surveillance legislation on press freedom. It failed." } diff --git a/test/test-pages/iab-1/expected-metadata.json b/test/test-pages/iab-1/expected-metadata.json index 8c95f5e..8f651b4 100644 --- a/test/test-pages/iab-1/expected-metadata.json +++ b/test/test-pages/iab-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Getting LEAN with Digital Ad UX", - "byline": "By\n\t\t\tScott Cunningham", - "excerpt": "We messed up. As technologists, tasked with delivering content and services to users, we lost track of the user experience. Twenty years ago we saw an explosion of websites, built by developers around the world, providing all forms of content. This was the beginning of an age of enlightenment, the intersection of content and technology. … Continued", - "readerable": true + "Title": "Getting LEAN with Digital Ad UX", + "Author": "By\n\t\t\tScott Cunningham", + "Excerpt": "We messed up. As technologists, tasked with delivering content and services to users, we lost track of the user experience. Twenty years ago we saw an explosion of websites, built by developers around the world, providing all forms of content. This was the beginning of an age of enlightenment, the intersection of content and technology. … Continued" } diff --git a/test/test-pages/ietf-1/expected-metadata.json b/test/test-pages/ietf-1/expected-metadata.json index b8349d8..1431f27 100644 --- a/test/test-pages/ietf-1/expected-metadata.json +++ b/test/test-pages/ietf-1/expected-metadata.json @@ -1,5 +1,4 @@ { - "title": "draft-dejong-remotestorage-04 - remoteStorage", - "byline": "AUTHORING", - "readerable": true + "Title": "draft-dejong-remotestorage-04 - remoteStorage", + "Author": "AUTHORING" } diff --git a/test/test-pages/ietf-1/expected.html b/test/test-pages/ietf-1/expected.html index 525dad5..15aae73 100644 --- a/test/test-pages/ietf-1/expected.html +++ b/test/test-pages/ietf-1/expected.html @@ -1076,7 +1076,7 @@ charset=UTF-8","Content-Length":106}}} M. Jones, D. Hardt, "The OAuth 2.0 Authorization Framework: Bearer Token Usage", <a href="http://fakehost/test/rfc6750">RFC6750</a>, October 2012. - [<a id="ref-AUTHORING" name="ref-AUTHORING">AUTHORING</a>] + [] "Using remoteStorage for web authoring", reSite wiki, retrieved September 2014. <a href="https://github.com/michielbdejong/resite/wiki">https://github.com/michielbdejong/resite/wiki</a> /Using-remoteStorage-for-web-authoring diff --git a/test/test-pages/keep-images/expected-metadata.json b/test/test-pages/keep-images/expected-metadata.json index a62d0ab..3956602 100644 --- a/test/test-pages/keep-images/expected-metadata.json +++ b/test/test-pages/keep-images/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Inside the Deep Web Drug Lab — Backchannel — Medium", - "byline": "Joseph Cox", - "excerpt": "Welcome to DoctorX’s Barcelona lab, where the drugs you bought online are tested for safety and purity. No questions ask…", - "readerable": true + "Title": "Inside the Deep Web Drug Lab — Backchannel — Medium", + "Author": "Joseph Cox", + "Excerpt": "Welcome to DoctorX’s Barcelona lab, where the drugs you bought online are tested for safety and purity. No questions ask…" } diff --git a/test/test-pages/lemonde-1/expected-metadata.json b/test/test-pages/lemonde-1/expected-metadata.json index c32b2bb..3d8792a 100644 --- a/test/test-pages/lemonde-1/expected-metadata.json +++ b/test/test-pages/lemonde-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Le projet de loi sur le renseignement massivement approuvé à l'Assemblée", - "byline": null, - "excerpt": "Largement approuvé par les députés, le texte sera désormais examiné par le Sénat, puis le Conseil constitutionnel.", - "readerable": true + "Title": "Le projet de loi sur le renseignement massivement approuvé à l'Assemblée", + "Author": null, + "Excerpt": "Largement approuvé par les députés, le texte sera désormais examiné par le Sénat, puis le Conseil constitutionnel." } diff --git a/test/test-pages/liberation-1/expected-metadata.json b/test/test-pages/liberation-1/expected-metadata.json index 0f7e5c3..7040bd8 100644 --- a/test/test-pages/liberation-1/expected-metadata.json +++ b/test/test-pages/liberation-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Un troisième Français mort dans le séisme au Népal", - "byline": "AFP", - "excerpt": "Laurent Fabius a accueilli jeudi matin à Roissy un premier avion spécial ramenant des rescapés.", - "readerable": true + "Title": "Un troisième Français mort dans le séisme au Népal", + "Author": "AFP", + "Excerpt": "Laurent Fabius a accueilli jeudi matin à Roissy un premier avion spécial ramenant des rescapés." } diff --git a/test/test-pages/lifehacker-post-comment-load/expected-metadata.json b/test/test-pages/lifehacker-post-comment-load/expected-metadata.json index ead5dca..1c7f82b 100644 --- a/test/test-pages/lifehacker-post-comment-load/expected-metadata.json +++ b/test/test-pages/lifehacker-post-comment-load/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "How to Program Your Mind to Stop Buying Crap You Don’t Need", - "byline": "Patrick Allan", - "excerpt": "We all buy things from time to time that we don't really need. It's okay to appeal to your wants every once in a while, as long as you're in control. If you struggle with clutter, impulse buys, and buyer's remorse, here's how to put your mind in the right place before you even set foot in a store.", - "readerable": true + "Title": "How to Program Your Mind to Stop Buying Crap You Don’t Need", + "Author": "Patrick Allan", + "Excerpt": "We all buy things from time to time that we don't really need. It's okay to appeal to your wants every once in a while, as long as you're in control. If you struggle with clutter, impulse buys, and buyer's remorse, here's how to put your mind in the right place before you even set foot in a store." } diff --git a/test/test-pages/lifehacker-working/expected-metadata.json b/test/test-pages/lifehacker-working/expected-metadata.json index ead5dca..1c7f82b 100644 --- a/test/test-pages/lifehacker-working/expected-metadata.json +++ b/test/test-pages/lifehacker-working/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "How to Program Your Mind to Stop Buying Crap You Don’t Need", - "byline": "Patrick Allan", - "excerpt": "We all buy things from time to time that we don't really need. It's okay to appeal to your wants every once in a while, as long as you're in control. If you struggle with clutter, impulse buys, and buyer's remorse, here's how to put your mind in the right place before you even set foot in a store.", - "readerable": true + "Title": "How to Program Your Mind to Stop Buying Crap You Don’t Need", + "Author": "Patrick Allan", + "Excerpt": "We all buy things from time to time that we don't really need. It's okay to appeal to your wants every once in a while, as long as you're in control. If you struggle with clutter, impulse buys, and buyer's remorse, here's how to put your mind in the right place before you even set foot in a store." } diff --git a/test/test-pages/links-in-tables/expected-metadata.json b/test/test-pages/links-in-tables/expected-metadata.json index b1b58ff..6ff5704 100644 --- a/test/test-pages/links-in-tables/expected-metadata.json +++ b/test/test-pages/links-in-tables/expected-metadata.json @@ -1,7 +1,5 @@ { - "title": "Saving Data: Reducing the size of App Updates by 65%", - "byline": null, - "dir": "ltr", - "excerpt": "Posted by Andrew Hayden, Software Engineer on Google Play", - "readerable": true + "Title": "Saving Data: Reducing the size of App Updates by 65%", + "Author": null, + "Excerpt": "Posted by Andrew Hayden, Software Engineer on Google Play Android users are downloading tens of billions of apps and games on Google Pla..." } diff --git a/test/test-pages/lwn-1/config.json b/test/test-pages/lwn-1/config.json index 6441edf..0ac6816 100644 --- a/test/test-pages/lwn-1/config.json +++ b/test/test-pages/lwn-1/config.json @@ -1,3 +1,3 @@ { - "articleByLine": true + "ArticleByLine": true }
\ No newline at end of file diff --git a/test/test-pages/lwn-1/expected-metadata.json b/test/test-pages/lwn-1/expected-metadata.json index 0309a57..7a7ca1c 100644 --- a/test/test-pages/lwn-1/expected-metadata.json +++ b/test/test-pages/lwn-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "LWN.net Weekly Edition for March 26, 2015 [LWN.net]", - "byline": "By Nathan Willis\n March 25, 2015", - "excerpt": "The Arduino has been one of the biggest success stories of the open-hardware movement, but that success does not protect it from internal conflict. In recent months, two of the project's founders have come into conflict about the direction of future efforts—and that conflict has turned into a legal dispute about who owns the rights to the Arduino trademark.", - "readerable": true + "Title": "LWN.net Weekly Edition for March 26, 2015 [LWN.net]", + "Author": "By Nathan Willis\n March 25, 2015", + "Excerpt": "The Arduino has been one of the biggest success stories of the open-hardware movement, but that success does not protect it from internal conflict. In recent months, two of the project's founders have come into conflict about the direction of future efforts—and that conflict has turned into a legal dispute about who owns the rights to the Arduino trademark." } diff --git a/test/test-pages/medium-1/expected-metadata.json b/test/test-pages/medium-1/expected-metadata.json index 232a067..b27963a 100644 --- a/test/test-pages/medium-1/expected-metadata.json +++ b/test/test-pages/medium-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Better Student Journalism — Medium", - "byline": "Pippin Lee", - "excerpt": "We pushed out the first version of the Open Journalism site in January. Here’s what we’ve learned about student journali…", - "readerable": true + "Title": "Better Student Journalism — Medium", + "Author": "Pippin Lee", + "Excerpt": "We pushed out the first version of the Open Journalism site in January. Here’s what we’ve learned about student journali…" } diff --git a/test/test-pages/medium-2/expected-metadata.json b/test/test-pages/medium-2/expected-metadata.json index dade1f4..d451476 100644 --- a/test/test-pages/medium-2/expected-metadata.json +++ b/test/test-pages/medium-2/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "On Behalf of “Literally” — Medium", - "byline": "Courtney Kirchoff", - "excerpt": "In defense of the word “literally” and why you or someone you know should stop misusing the word, lest they drive us fig…", - "readerable": true + "Title": "On Behalf of “Literally” — Medium", + "Author": "Courtney Kirchoff", + "Excerpt": "In defense of the word “literally” and why you or someone you know should stop misusing the word, lest they drive us fig…" } diff --git a/test/test-pages/medium-3/expected-metadata.json b/test/test-pages/medium-3/expected-metadata.json index ec8dc2b..c4eaa56 100644 --- a/test/test-pages/medium-3/expected-metadata.json +++ b/test/test-pages/medium-3/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Samantha and The Great Big Lie – John C. Welch – Medium", - "byline": "John C. Welch", - "dir": null, - "excerpt": "(EDIT: removed the link to Samantha’s post, because the arments and the grubers and the rest of The Deck Clique got what they wanted: a non-proper person driven off the internet lightly capped with a…", - "readerable": true + "Title": "Samantha and The Great Big Lie – John C. Welch – Medium", + "Author": "John C. Welch", + "Direction": null, + "Excerpt": "(EDIT: removed the link to Samantha’s post, because the arments and the grubers and the rest of The Deck Clique got what they wanted: a non-proper person driven off the internet lightly capped with a…" } diff --git a/test/test-pages/missing-paragraphs/expected-metadata.json b/test/test-pages/missing-paragraphs/expected-metadata.json index 80c8500..ecd9fbc 100644 --- a/test/test-pages/missing-paragraphs/expected-metadata.json +++ b/test/test-pages/missing-paragraphs/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy\n eirmod tempor invidunt", - "byline": "Henri Sivonen", - "excerpt": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy\n eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet\n clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit\n amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam\n nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor\n sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed\n diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor\n sit amet.", - "readerable": true + "Title": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy\n eirmod tempor invidunt", + "Author": "Henri Sivonen", + "Excerpt": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy\n eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam\n voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet\n clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit\n amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam\n nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor\n sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed\n diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor\n sit amet." } diff --git a/test/test-pages/mozilla-1/expected-metadata.json b/test/test-pages/mozilla-1/expected-metadata.json index 63a3699..b6bac46 100644 --- a/test/test-pages/mozilla-1/expected-metadata.json +++ b/test/test-pages/mozilla-1/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Firefox — Customize and make it your own — The most flexible browser on\n the Web — Mozilla", - "byline": null, - "dir": "ltr", - "excerpt": "It’s easier than ever to personalize Firefox and make it work the way\n you do.\n No other browser gives you so much choice and flexibility.", - "readerable": true + "Title": "Firefox — Customize and make it your own — The most flexible browser on\n the Web — Mozilla", + "Author": null, + "Direction": "ltr", + "Excerpt": "It’s easier than ever to personalize Firefox and make it work the way\n you do.\n No other browser gives you so much choice and flexibility." } diff --git a/test/test-pages/mozilla-2/expected-metadata.json b/test/test-pages/mozilla-2/expected-metadata.json index d2126a6..de229d8 100644 --- a/test/test-pages/mozilla-2/expected-metadata.json +++ b/test/test-pages/mozilla-2/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Welcome to Firefox Developer Edition", - "byline": null, - "dir": "ltr", - "excerpt": "Get to know the features that make it the most complete browser for building the Web.", - "readerable": false + "Title": "Welcome to Firefox Developer Edition", + "Author": null, + "Direction": "ltr", + "Excerpt": "Built for those who build the Web. Introducing the only browser made for developers." } diff --git a/test/test-pages/msn/expected-metadata.json b/test/test-pages/msn/expected-metadata.json index 3923309..e4fff27 100644 --- a/test/test-pages/msn/expected-metadata.json +++ b/test/test-pages/msn/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Nintendo's first iPhone game will launch in December for $10", - "byline": "Alex Perry\n \n 1 day ago", - "excerpt": "Nintendo and Apple shocked the world earlier this year by announcing \"Super Mario Run,\" the legendary gaming company's first foray into mobile gaming. ", - "readerable": true + "Title": "Nintendo's first iPhone game will launch in December for $10", + "Author": "Alex Perry", + "Excerpt": "Nintendo and Apple shocked the world earlier this year by announcing \"Super Mario Run,\" the legendary gaming company's first foray into mobile gaming. " } diff --git a/test/test-pages/needs-entity-normalization/expected-metadata.json b/test/test-pages/needs-entity-normalization/expected-metadata.json index 3531939..aea0400 100644 --- a/test/test-pages/needs-entity-normalization/expected-metadata.json +++ b/test/test-pages/needs-entity-normalization/expected-metadata.json @@ -1,7 +1,5 @@ { - "title": "", - "byline": null, - "dir": "ltr", - "excerpt": "", - "readerable": false + "Title": "Daniele, a Mestre: \"En unos meses se va a borrar la sonrisa\"", + "Author": "Cadena 3 Argentina", + "Excerpt": "El titular del Suoem le dijo al intendente que va a pagar caro, esta infamia y canallada–por la publiación de sueldos–. Los municipales realizaron una ruidosa protesta en el Palacio 6 de Julio" } diff --git a/test/test-pages/nytimes-1/expected-metadata.json b/test/test-pages/nytimes-1/expected-metadata.json index d251218..c8b12aa 100644 --- a/test/test-pages/nytimes-1/expected-metadata.json +++ b/test/test-pages/nytimes-1/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "United States to Lift Sudan Sanctions", - "byline": "Jeffrey Gettleman", - "dir": null, - "excerpt": "For the first time since the 1990s, the country will be able to trade extensively with the United States.", - "readerable": true + "Title": "United States to Lift Sudan Sanctions", + "Author": "Jeffrey Gettleman", + "Direction": null, + "Excerpt": "For the first time since the 1990s, the country will be able to trade extensively with the United States." } diff --git a/test/test-pages/nytimes-2/expected-metadata.json b/test/test-pages/nytimes-2/expected-metadata.json index 3a0ca4e..d8c62b1 100644 --- a/test/test-pages/nytimes-2/expected-metadata.json +++ b/test/test-pages/nytimes-2/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Yahoo’s Sale to Verizon Leaves Shareholders With Little Say", - "byline": "Steven Davidoff Solomon", - "dir": null, - "excerpt": "The internet giant’s decision to sell its business is plagued with challenges that reveal how unusual deal structures can affect shareholders.", - "readerable": true + "Title": "Yahoo’s Sale to Verizon Leaves Shareholders With Little Say", + "Author": "Steven Davidoff Solomon", + "Direction": null, + "Excerpt": "The internet giant’s decision to sell its business is plagued with challenges that reveal how unusual deal structures can affect shareholders." } diff --git a/test/test-pages/pixnet/expected-metadata.json b/test/test-pages/pixnet/expected-metadata.json index 64fc194..97554c7 100644 --- a/test/test-pages/pixnet/expected-metadata.json +++ b/test/test-pages/pixnet/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "新竹尖石_美樹營地賞楓 (2) @ 史蒂文的家_藍天 :: 痞客邦 PIXNET ::", - "byline": "史蒂文的家_藍天 (stevenhgm)", - "dir": null, - "excerpt": "一波波接續性低溫寒流報到 已將新竹尖石鄉後山一帶層層山巒披上嫣紅的彩衣 玉峰道路一路上雲氣山嵐滯留山頭 順路下切蜿蜒道路後不久即抵達來到"玉峰國小" "美樹"美", - "readerable": true + "Title": "新竹尖石_美樹營地賞楓 (2) @ 史蒂文的家_藍天 :: 痞客邦 PIXNET ::", + "Author": "史蒂文的家_藍天 (stevenhgm)", + "Direction": null, + "Excerpt": "一波波接續性低溫寒流報到 已將新竹尖石鄉後山一帶層層山巒披上嫣紅的彩衣 玉峰道路一路上雲氣山嵐滯留山頭 順路下切蜿蜒道路後不久即抵達來到"玉峰國小" "美樹"美" } diff --git a/test/test-pages/remove-extra-brs/expected-metadata.json b/test/test-pages/remove-extra-brs/expected-metadata.json index 25e04b4..152d972 100644 --- a/test/test-pages/remove-extra-brs/expected-metadata.json +++ b/test/test-pages/remove-extra-brs/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Remove trailing brs test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua.", - "readerable": true + "Title": "Remove trailing brs test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua." } diff --git a/test/test-pages/remove-extra-paragraphs/expected-metadata.json b/test/test-pages/remove-extra-paragraphs/expected-metadata.json index 8e841af..4a21b9b 100644 --- a/test/test-pages/remove-extra-paragraphs/expected-metadata.json +++ b/test/test-pages/remove-extra-paragraphs/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Replace font tags test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua.", - "readerable": true + "Title": "Replace font tags test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua." } diff --git a/test/test-pages/remove-script-tags/expected-metadata.json b/test/test-pages/remove-script-tags/expected-metadata.json index 2ef0848..96ec024 100644 --- a/test/test-pages/remove-script-tags/expected-metadata.json +++ b/test/test-pages/remove-script-tags/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Remove script tags test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua.", - "readerable": true + "Title": "Remove script tags test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua." } diff --git a/test/test-pages/reordering-paragraphs/expected-metadata.json b/test/test-pages/reordering-paragraphs/expected-metadata.json index ca7653a..cae2da5 100644 --- a/test/test-pages/reordering-paragraphs/expected-metadata.json +++ b/test/test-pages/reordering-paragraphs/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "", - "byline": null, - "excerpt": "Regarding item# 11111, under sufficiently extreme conditions, quarks may\n become deconfined and exist as free particles. In the course of asymptotic\n freedom, the strong interaction becomes weaker at higher temperatures.\n Eventually, color confinement would be lost and an extremely hot plasma\n of freely moving quarks and gluons would be formed. This theoretical phase\n of matter is called quark-gluon plasma.[81] The exact conditions needed\n to give rise to this state are unknown and have been the subject of a great\n deal of speculation and experimentation.", - "readerable": true + "Title": "", + "Author": null, + "Excerpt": "Regarding item# 11111, under sufficiently extreme conditions, quarks may\n become deconfined and exist as free particles. In the course of asymptotic\n freedom, the strong interaction becomes weaker at higher temperatures.\n Eventually, color confinement would be lost and an extremely hot plasma\n of freely moving quarks and gluons would be formed. This theoretical phase\n of matter is called quark-gluon plasma.[81] The exact conditions needed\n to give rise to this state are unknown and have been the subject of a great\n deal of speculation and experimentation." } diff --git a/test/test-pages/replace-brs/expected-metadata.json b/test/test-pages/replace-brs/expected-metadata.json index 9654255..ae183f1 100644 --- a/test/test-pages/replace-brs/expected-metadata.json +++ b/test/test-pages/replace-brs/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Replace brs test", - "byline": null, - "excerpt": "Lorem ipsum", - "readerable": true + "Title": "Replace brs test", + "Author": null, + "Excerpt": "Lorem ipsum" } diff --git a/test/test-pages/replace-font-tags/expected-metadata.json b/test/test-pages/replace-font-tags/expected-metadata.json index 517ceea..c669818 100644 --- a/test/test-pages/replace-font-tags/expected-metadata.json +++ b/test/test-pages/replace-font-tags/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Replace font tags test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": false + "Title": "Replace font tags test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/rtl-1/expected-metadata.json b/test/test-pages/rtl-1/expected-metadata.json index 4f3b2e6..3c14748 100644 --- a/test/test-pages/rtl-1/expected-metadata.json +++ b/test/test-pages/rtl-1/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "RTL Test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet.", - "dir": "rtl", - "readerable": true + "Title": "RTL Test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet.", + "Direction": "rtl" } diff --git a/test/test-pages/rtl-2/expected-metadata.json b/test/test-pages/rtl-2/expected-metadata.json index 4f3b2e6..3c14748 100644 --- a/test/test-pages/rtl-2/expected-metadata.json +++ b/test/test-pages/rtl-2/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "RTL Test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet.", - "dir": "rtl", - "readerable": true + "Title": "RTL Test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet.", + "Direction": "rtl" } diff --git a/test/test-pages/rtl-3/expected-metadata.json b/test/test-pages/rtl-3/expected-metadata.json index 4f3b2e6..3c14748 100644 --- a/test/test-pages/rtl-3/expected-metadata.json +++ b/test/test-pages/rtl-3/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "RTL Test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet.", - "dir": "rtl", - "readerable": true + "Title": "RTL Test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet.", + "Direction": "rtl" } diff --git a/test/test-pages/rtl-4/expected-metadata.json b/test/test-pages/rtl-4/expected-metadata.json index 1d9581f..ee2b37a 100644 --- a/test/test-pages/rtl-4/expected-metadata.json +++ b/test/test-pages/rtl-4/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "RTL Test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet.", - "dir": null, - "readerable": true + "Title": "RTL Test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet.", + "Direction": null } diff --git a/test/test-pages/salon-1/expected-metadata.json b/test/test-pages/salon-1/expected-metadata.json index 02cb664..9c39de6 100644 --- a/test/test-pages/salon-1/expected-metadata.json +++ b/test/test-pages/salon-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "The sharing economy is a lie: Uber, Ayn Rand and the truth about tech\n and libertarians", - "byline": "Joanna Rothkopf", - "excerpt": "Disruptive companies talk a good game about sharing. Uber's really just an under-regulated company making riches", - "readerable": true + "Title": "The sharing economy is a lie: Uber, Ayn Rand and the truth about tech\n and libertarians", + "Author": "Joanna Rothkopf", + "Excerpt": "Disruptive companies talk a good game about sharing. Uber's really just an under-regulated company making riches" } diff --git a/test/test-pages/simplyfound-1/expected-metadata.json b/test/test-pages/simplyfound-1/expected-metadata.json index 1210bda..9d1a0ba 100644 --- a/test/test-pages/simplyfound-1/expected-metadata.json +++ b/test/test-pages/simplyfound-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Raspberry Pi 3 - The credit card sized PC that cost only $35 - All-time bestselling computer in UK", - "byline": null, - "excerpt": "The Raspberry Pi Foundation started by a handful of volunteers in 2012 when they released the original Raspberry Pi 256MB Model B without knowing what to expect. In a short four-year period they have grown to over sixty full-time employees and ha...", - "readerable": true + "Title": "Raspberry Pi 3 - The credit card sized PC that cost only $35 - All-time bestselling computer in UK", + "Author": null, + "Excerpt": "The Raspberry Pi Foundation started by a handful of volunteers in 2012 when they released the original Raspberry Pi 256MB Model B without knowing what to expect. In a short four-year period they have grown to over sixty full-time employees and ha..." } diff --git a/test/test-pages/social-buttons/expected-metadata.json b/test/test-pages/social-buttons/expected-metadata.json index 1a738af..50d7ac6 100644 --- a/test/test-pages/social-buttons/expected-metadata.json +++ b/test/test-pages/social-buttons/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Share buttons removal test", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": true + "Title": "Share buttons removal test", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/style-tags-removal/expected-metadata.json b/test/test-pages/style-tags-removal/expected-metadata.json index 8bd4dd2..e30a764 100644 --- a/test/test-pages/style-tags-removal/expected-metadata.json +++ b/test/test-pages/style-tags-removal/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Style tags removal", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": false + "Title": "Style tags removal", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/svg-parsing/expected-metadata.json b/test/test-pages/svg-parsing/expected-metadata.json index c8cbac6..2192d3b 100644 --- a/test/test-pages/svg-parsing/expected-metadata.json +++ b/test/test-pages/svg-parsing/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "SVG parsing", - "byline": null, - "excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - "readerable": true + "Title": "SVG parsing", + "Author": null, + "Excerpt": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/test/test-pages/table-style-attributes/expected-metadata.json b/test/test-pages/table-style-attributes/expected-metadata.json index b551087..3866f09 100644 --- a/test/test-pages/table-style-attributes/expected-metadata.json +++ b/test/test-pages/table-style-attributes/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "linux video", - "byline": null, - "dir": null, - "excerpt": "linux usability\n ...or, why do I bother. © 2002, 2003\n Jamie Zawinski", - "readerable": true + "Title": "linux video", + "Author": null, + "Direction": null, + "Excerpt": "linux usability\n ...or, why do I bother. © 2002, 2003\n Jamie Zawinski" } diff --git a/test/test-pages/telegraph/expected-metadata.json b/test/test-pages/telegraph/expected-metadata.json index d88303d..0664ae6 100644 --- a/test/test-pages/telegraph/expected-metadata.json +++ b/test/test-pages/telegraph/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Robert Mugabe and wife Grace 'insisting he finishes his term', as priest steps in to mediate", - "byline": null, - "dir": null, - "excerpt": "Zimbabwe President Robert Mugabe, his wife Grace and two key figures from her G40 political faction are under house arrest at Mugabe's "Blue House" compound in Harare and are insisting the 93 year-old finishes his presidential term, a source said.", - "readerable": true + "Title": "Zimbabwe coup: Robert Mugabe and wife Grace 'insisting he finishes his term', as priest steps in to mediate", + "Author": null, + "Direction": null, + "Excerpt": "Zimbabwe President Robert Mugabe, his wife Grace and two key figures from her G40 political faction are under house arrest at Mugabe's "Blue House" compound in Harare and are insisting the 93 year-old finishes his presidential term, a source said." } diff --git a/test/test-pages/tmz-1/expected-metadata.json b/test/test-pages/tmz-1/expected-metadata.json index 39a351a..994d596 100644 --- a/test/test-pages/tmz-1/expected-metadata.json +++ b/test/test-pages/tmz-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Lupita Nyong'o's $150K Pearl Oscar Dress -- STOLEN!!!", - "byline": null, - "excerpt": "Lupita Nyong'o's now-famous Oscar dress -- adorned in pearls -- was stolen right out of her hotel room ... TMZ has learned. Law enforcement sources tell…", - "readerable": true + "Title": "Lupita Nyong'o's $150K Pearl Oscar Dress -- STOLEN!!!", + "Author": null, + "Excerpt": "Lupita Nyong'o's now-famous Oscar dress -- adorned in pearls -- was stolen right out of her hotel room ... TMZ has learned. Law enforcement sources tell…" } diff --git a/test/test-pages/tumblr/expected-metadata.json b/test/test-pages/tumblr/expected-metadata.json index 6801046..09c83ac 100644 --- a/test/test-pages/tumblr/expected-metadata.json +++ b/test/test-pages/tumblr/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Minecraft 1.8 - The Bountiful Update - Minecraft 1.8 - The Bountiful Update", - "byline": null, - "dir": null, - "excerpt": "+ Added Granite, Andesite, and Diorite stone blocks, with smooth versions\n+ Added Slime Block\n+ Added Iron Trapdoor\n+ Added Prismarine and Sea Lantern blocks\n+ Added the Ocean Monument\n+ Added Red...", - "readerable": true + "Title": "Minecraft 1.8 - The Bountiful Update - Minecraft 1.8 - The Bountiful Update", + "Author": null, + "Direction": null, + "Excerpt": "+ Added Granite, Andesite, and Diorite stone blocks, with smooth versions\n+ Added Slime Block\n+ Added Iron Trapdoor\n+ Added Prismarine and Sea Lantern blocks\n+ Added the Ocean Monument\n+ Added Red..." } diff --git a/test/test-pages/wapo-1/expected-metadata.json b/test/test-pages/wapo-1/expected-metadata.json index 5195394..ac80bbb 100644 --- a/test/test-pages/wapo-1/expected-metadata.json +++ b/test/test-pages/wapo-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Attack stokes instability fears in North Africa", - "byline": "By Erin Cunningham", - "excerpt": "The assault on Tunisia’s most renowned museum, in which gunmen killed at least 19 people, could heighten tensions in a nation that has become deeply divided between pro- and anti-Islamist factions.", - "readerable": true + "Title": "Attack stokes instability fears in North Africa", + "Author": "By Erin Cunningham", + "Excerpt": "The assault on Tunisia’s most renowned museum, in which gunmen killed at least 19 people, could heighten tensions in a nation that has become deeply divided between pro- and anti-Islamist factions." } diff --git a/test/test-pages/wapo-2/expected-metadata.json b/test/test-pages/wapo-2/expected-metadata.json index bae11fb..bee9dd4 100644 --- a/test/test-pages/wapo-2/expected-metadata.json +++ b/test/test-pages/wapo-2/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Where do strained U.S.-Israeli relations go after Netanyahu’s victory?", - "byline": "By Steven Mufson", - "excerpt": "Few foreign leaders have so brazenly stood up to President Obama and the relationship could face its next test this month.", - "readerable": true + "Title": "Where do strained U.S.-Israeli relations go after Netanyahu’s victory?", + "Author": "By Steven Mufson", + "Excerpt": "Few foreign leaders have so brazenly stood up to President Obama and the relationship could face its next test this month." } diff --git a/test/test-pages/webmd-1/expected-metadata.json b/test/test-pages/webmd-1/expected-metadata.json index 4ceddcf..315ee82 100644 --- a/test/test-pages/webmd-1/expected-metadata.json +++ b/test/test-pages/webmd-1/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Babies Who Eat Peanuts Early May Avoid Allergy", - "byline": "By Brenda Goodman, MA\n WebMD Health News", - "excerpt": "Life-threatening peanut allergies have mysteriously been on the rise in the past decade, with little hope for a cure. But a groundbreaking new study may offer a way to stem that rise, while another may offer some hope for those who are already allergic.", - "readerable": true + "Title": "Babies Who Eat Peanuts Early May Avoid Allergy", + "Author": "By Brenda Goodman, MA\n WebMD Health News", + "Excerpt": "Life-threatening peanut allergies have mysteriously been on the rise in the past decade, with little hope for a cure. But a groundbreaking new study may offer a way to stem that rise, while another may offer some hope for those who are already allergic." } diff --git a/test/test-pages/webmd-2/expected-metadata.json b/test/test-pages/webmd-2/expected-metadata.json index a55dd94..3bbb5fd 100644 --- a/test/test-pages/webmd-2/expected-metadata.json +++ b/test/test-pages/webmd-2/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Superbugs: What They Are and How You Get Them", - "byline": "By Kelli Miller\n WebMD Health News", - "excerpt": "Drug-resistant bacteria, dubbed", - "readerable": true + "Title": "Superbugs: What They Are and How You Get Them", + "Author": "By Kelli Miller\n WebMD Health News", + "Excerpt": "Drug-resistant bacteria, dubbed" } diff --git a/test/test-pages/wikia/expected-metadata.json b/test/test-pages/wikia/expected-metadata.json index 4c0535d..3ad3235 100644 --- a/test/test-pages/wikia/expected-metadata.json +++ b/test/test-pages/wikia/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "'Star Wars' Original Cuts Might Get Released for 40th Anniversary", - "byline": "James Akinaka", - "dir": null, - "excerpt": "As a 40th birthday present to the Star Wars Saga and its fans, Lucasfilm could re-release the original versions of the original trilogy films.", - "readerable": true + "Title": "'Star Wars' Original Cuts Might Get Released for 40th Anniversary", + "Author": "James Akinaka", + "Direction": null, + "Excerpt": "As a 40th birthday present to the Star Wars Saga and its fans, Lucasfilm could re-release the original versions of the original trilogy films." } diff --git a/test/test-pages/wikipedia/expected-metadata.json b/test/test-pages/wikipedia/expected-metadata.json index ca08f7b..52b13ff 100644 --- a/test/test-pages/wikipedia/expected-metadata.json +++ b/test/test-pages/wikipedia/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Mozilla - Wikipedia", - "byline": null, - "dir": "ltr", - "excerpt": "Mozilla is a free-software community, created in 1998 by members of Netscape. The Mozilla community uses, develops, spreads and supports Mozilla products, thereby promoting exclusively free software and open standards, with only minor exceptions.[1] The community is supported institutionally by the Mozilla Foundation and its tax-paying subsidiary, the Mozilla Corporation.[2]", - "readerable": true + "Title": "Mozilla - Wikipedia", + "Author": null, + "Direction": "ltr", + "Excerpt": "Mozilla is a free-software community, created in 1998 by members of Netscape. The Mozilla community uses, develops, spreads and supports Mozilla products, thereby promoting exclusively free software and open standards, with only minor exceptions.[1] The community is supported institutionally by the Mozilla Foundation and its tax-paying subsidiary, the Mozilla Corporation.[2]" } diff --git a/test/test-pages/wordpress/expected-metadata.json b/test/test-pages/wordpress/expected-metadata.json index 2ff3a4f..3d860dc 100644 --- a/test/test-pages/wordpress/expected-metadata.json +++ b/test/test-pages/wordpress/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "Stack Overflow Jobs Data Shows ReactJS Skills in High Demand, WordPress Market Oversaturated with Developers – WordPress Tavern", - "byline": null, - "dir": null, - "excerpt": "Stack Overflow published its analysis of 2017 hiring trends based on the targeting options employers selected when posting to Stack Overflow Jobs. The report, which compares data from 200 companies…", - "readerable": true + "Title": "Stack Overflow Jobs Data Shows ReactJS Skills in High Demand, WordPress Market Oversaturated with Developers – WordPress Tavern", + "Author": null, + "Direction": null, + "Excerpt": "Stack Overflow published its analysis of 2017 hiring trends based on the targeting options employers selected when posting to Stack Overflow Jobs. The report, which compares data from 200 companies…" } diff --git a/test/test-pages/yahoo-1/expected-metadata.json b/test/test-pages/yahoo-1/expected-metadata.json index 9776065..e4bcca1 100644 --- a/test/test-pages/yahoo-1/expected-metadata.json +++ b/test/test-pages/yahoo-1/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "These are the 8 coolest PlayStation VR games", - "byline": "Ben Silverman", - "dir": null, - "excerpt": "To help you decide what’s what, I’ve put together this list of the 8 PSVR games worth considering. Beloved cult hit “Rez” gets the VR treatment to help launch the PSVR, and the results are terrific. Chaos, for sure, and also “Thumper.” Called a “violent rhythm game” by its creators, “Thumper” is, well", - "readerable": true + "Title": "These are the 8 coolest PlayStation VR games", + "Author": "Ben Silverman", + "Direction": null, + "Excerpt": "To help you decide what’s what, I’ve put together this list of the 8 PSVR games worth considering. Beloved cult hit “Rez” gets the VR treatment to help launch the PSVR, and the results are terrific. Chaos, for sure, and also “Thumper.” Called a “violent rhythm game” by its creators, “Thumper” is, well" } diff --git a/test/test-pages/yahoo-2/expected-metadata.json b/test/test-pages/yahoo-2/expected-metadata.json index 03810e5..562a72b 100644 --- a/test/test-pages/yahoo-2/expected-metadata.json +++ b/test/test-pages/yahoo-2/expected-metadata.json @@ -1,6 +1,5 @@ { - "title": "Russia: Space ship malfunctions, breaks up over Siberia", - "byline": "NATALIYA VASILYEVA", - "excerpt": "The latest news and headlines from Yahoo! News. Get breaking news stories and in-depth coverage with videos and photos.", - "readerable": true + "Title": "Russia: Space ship malfunctions, breaks up over Siberia", + "Author": "NATALIYA VASILYEVA", + "Excerpt": "The latest news and headlines from Yahoo! News. Get breaking news stories and in-depth coverage with videos and photos." } diff --git a/test/test-pages/yahoo-3/expected-metadata.json b/test/test-pages/yahoo-3/expected-metadata.json index b81ae3e..75d461d 100644 --- a/test/test-pages/yahoo-3/expected-metadata.json +++ b/test/test-pages/yahoo-3/expected-metadata.json @@ -1,7 +1,4 @@ { - "title": "Veteran Wraps Baby in American Flag, Photo Sparks Controversy", - "byline": "By GILLIAN MOHNEY\n March 11, 2015 3:46 PM", - "dir": "ltr", - "excerpt": "From Yahoo: A photographer and Navy veteran is fighting back after a photo she posted to Facebook started an online backlash. Vanessa Hicks said she had no idea her photo would be considered controversial. The photo, from a military family’s newborn photo shoot, showed a newborn infant wrapped in an American flag held by his father, who was in his military uniform. Hicks, a Navy veteran herself and the wife of an active-duty Navy member, said her intention was to honor the flag as well as her clients, who wanted to incorporate their military service in the photo shoot.", - "readerable": true + "Title": "Veteran Wraps Baby in American Flag, Photo Sparks Controversy", + "Excerpt": "From Yahoo: A photographer and Navy veteran is fighting back after a photo she posted to Facebook started an online backlash. Vanessa Hicks said she had no idea her photo would be considered controversial. The photo, from a military family’s newborn photo shoot, showed a newborn infant wrapped in an American flag held by his father, who was in his military uniform. Hicks, a Navy veteran herself and the wife of an active-duty Navy member, said her intention was to honor the flag as well as her clients, who wanted to incorporate their military service in the photo shoot." } diff --git a/test/test-pages/yahoo-4/expected-metadata.json b/test/test-pages/yahoo-4/expected-metadata.json index fbd8664..0dac267 100644 --- a/test/test-pages/yahoo-4/expected-metadata.json +++ b/test/test-pages/yahoo-4/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "トレンドマイクロ、公衆無線LANを安全に使うためのアプリ「フリーWi-Fiプロテクション」 (CNET Japan) - Yahoo!ニュース", - "byline": null, - "dir": null, - "excerpt": "トレンドマイクロは3月9日、Wi-Fi利用時の通信を暗号化し保護するスマホ・タブレッ", - "readerable": true + "Title": "トレンドマイクロ、公衆無線LANを安全に使うためのアプリ「フリーWi-Fiプロテクション」 (CNET Japan) - Yahoo!ニュース", + "Author": null, + "Direction": null, + "Excerpt": " トレンドマイクロは3月9日、Wi-Fi利用時の通信を暗号化し保護するスマホ・タブレッ" } diff --git a/test/test-pages/youth/expected-metadata.json b/test/test-pages/youth/expected-metadata.json index 8fc0b30..cf1afac 100644 --- a/test/test-pages/youth/expected-metadata.json +++ b/test/test-pages/youth/expected-metadata.json @@ -1,7 +1,6 @@ { - "title": "海外留学生看两会:出国前后关注点大不同_教育频道_中国青年网", - "byline": "青网校园崔宁宁", - "dir": null, - "excerpt": "图为马素湘在澳大利亚悉尼游玩时的近影。出国前后关注点大不同出国前:政治科目会出啥考题?出国后:国家未来将如何发展?在采访中,我们了解到不少学子在出国前就每年守在电脑前观看两会直播。但是,随着年龄和阅历的增长,学子对两会的关注点在出国前后发生了很大的变化。在法国里昂国立应用科学院留学的卢宇表示,他还是个中学生时,就开始关注两会了。“我高中毕业后就出国留学了。", - "readerable": true + "Title": "海外留学生看两会:出国前后关注点大不同_教育频道_中国青年网", + "Author": "青网校园崔宁宁", + "Direction": null, + "Excerpt": "图为马素湘在澳大利亚悉尼游玩时的近影。出国前后关注点大不同出国前:政治科目会出啥考题?出国后:国家未来将如何发展?在采访中,我们了解到不少学子在出国前就每年守在电脑前观看两会直播。但是,随着年龄和阅历的增长,学子对两会的关注点在出国前后发生了很大的变化。在法国里昂国立应用科学院留学的卢宇表示,他还是个中学生时,就开始关注两会了。“我高中毕业后就出国留学了。" } |