14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifndef COMPONENTS_DOM_DISTILLER_CORE_DISTILLER_H_ 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#define COMPONENTS_DOM_DISTILLER_CORE_DISTILLER_H_ 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <map> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/callback.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/containers/hash_tables.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/ref_counted.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_vector.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/weak_ptr.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/dom_distiller/core/article_distillation_update.h" 18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "components/dom_distiller/core/distiller_page.h" 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/dom_distiller/core/distiller_url_fetcher.h" 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/dom_distiller/core/proto/distilled_article.pb.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h" 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "url/gurl.h" 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace dom_distiller { 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class DistillerImpl; 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class Distiller { 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) typedef base::Callback<void(scoped_ptr<DistilledArticleProto>)> 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DistillationFinishedCallback; 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef base::Callback<void(const ArticleDistillationUpdate&)> 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DistillationUpdateCallback; 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~Distiller() {} 364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Distills a page, and asynchronously returns the article HTML to the 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // supplied |finished_cb| callback. |update_cb| is invoked whenever article 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // under distillation is updated with more data. 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // E.g. when distilling a 2 page article, |update_cb| may be invoked each time 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // a distilled page is added and |finished_cb| will be invoked once 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // distillation is completed. 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual void DistillPage(const GURL& url, 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<DistillerPage> distiller_page, 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const DistillationFinishedCallback& finished_cb, 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const DistillationUpdateCallback& update_cb) = 0; 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class DistillerFactory { 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual scoped_ptr<Distiller> CreateDistiller() = 0; 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~DistillerFactory() {} 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Factory for creating a Distiller. 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class DistillerFactoryImpl : public DistillerFactory { 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DistillerFactoryImpl( 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory, 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const dom_distiller::proto::DomDistillerOptions& dom_distiller_options); 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~DistillerFactoryImpl(); 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual scoped_ptr<Distiller> CreateDistiller() OVERRIDE; 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory_; 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) dom_distiller::proto::DomDistillerOptions dom_distiller_options_; 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Distills a article from a page and associated pages. 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class DistillerImpl : public Distiller { 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DistillerImpl( 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const DistillerURLFetcherFactory& distiller_url_fetcher_factory, 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const dom_distiller::proto::DomDistillerOptions& dom_distiller_options); 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~DistillerImpl(); 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu virtual void DistillPage( 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const GURL& url, 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu scoped_ptr<DistillerPage> distiller_page, 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const DistillationFinishedCallback& finished_cb, 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const DistillationUpdateCallback& update_cb) OVERRIDE; 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void SetMaxNumPagesInArticle(size_t max_num_pages); 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // In case of multiple pages, the Distiller maintains state of multiple pages 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // as page numbers relative to the page number where distillation started. 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // E.g. if distillation starts at page 2 for a 3 page article. The relative 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // page numbers assigned to pages will be [-1,0,1]. 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Class representing the state of a page under distillation. 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) struct DistilledPageData { 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DistilledPageData(); 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual ~DistilledPageData(); 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Relative page number of the page. 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int page_num; 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedVector<DistillerURLFetcher> image_fetchers_; 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<base::RefCountedData<DistilledPageProto> > 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) distilled_page_proto; 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private: 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DistilledPageData); 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void OnFetchImageDone(int page_num, 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DistillerURLFetcher* url_fetcher, 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& id, 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& response); 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void OnPageDistillationFinished( 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int page_num, 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GURL& page_url, 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scoped_ptr<proto::DomDistillerResult> distilled_page, 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool distillation_successful); 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void FetchImage(int page_num, 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& image_id, 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& item); 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Distills the next page. 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void DistillNextPage(); 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Adds the |url| to |pages_to_be_distilled| if |page_num| is a valid relative 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // page number and |url| is valid. Ignores duplicate pages and urls. 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void AddToDistillationQueue(int page_num, const GURL& url); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check if |page_num| is a valid relative page number, i.e. page with 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // |page_num| is either under distillation or has already completed 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // distillation. 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool IsPageNumberInUse(int page_num) const; 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool AreAllPagesFinished() const; 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Total number of pages in the article that the distiller knows of, this 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // includes pages that are pending distillation. 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t TotalPageCount() const; 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Runs |finished_cb_| if all distillation callbacks and image fetches are 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // complete. 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void RunDistillerCallbackIfDone(); 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Checks if page |distilled_page_data| has finished distillation, including 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // all image fetches. 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void AddPageIfDone(int page_num); 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DistilledPageData* GetPageAtIndex(size_t index) const; 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Create an ArticleDistillationUpdate for the current distillation 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // state. 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const ArticleDistillationUpdate CreateDistillationUpdate() const; 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const DistillerURLFetcherFactory& distiller_url_fetcher_factory_; 153a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scoped_ptr<DistillerPage> distiller_page_; 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) dom_distiller::proto::DomDistillerOptions dom_distiller_options_; 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DistillationFinishedCallback finished_cb_; 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DistillationUpdateCallback update_cb_; 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Set of pages that are under distillation or have finished distillation. 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // |started_pages_index_| and |finished_pages_index_| maintains the mapping 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // from page number to the indices in |pages_|. 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedVector<DistilledPageData> pages_; 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Maps page numbers of finished pages to the indices in |pages_|. 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::map<int, size_t> finished_pages_index_; 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Maps page numbers of pages under distillation to the indices in |pages_|. 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If a page is |started_pages_| that means it is still waiting for an action 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // (distillation or image fetch) to finish. 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::hash_map<int, size_t> started_pages_index_; 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The list of pages that are still waiting for distillation to start. 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This is a map, to make distiller prefer distilling lower page numbers 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // first. 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::map<int, GURL> waiting_pages_; 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Set to keep track of which urls are already seen by the distiller. Used to 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // prevent distiller from distilling the same url twice. 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::hash_set<std::string> seen_urls_; 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t max_pages_in_article_; 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool destruction_allowed_; 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::WeakPtrFactory<DistillerImpl> weak_factory_; 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DistillerImpl); 1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace dom_distiller 1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif // COMPONENTS_DOM_DISTILLER_CORE_DISTILLER_H_ 193