For implementation of your investment project in the territory of Minsk free economic zone there are available premises for rent and sale.
Follow links on the map.
Plot №7 is located in Molodechno and has the size of 7, 36 hectares, the territory of "Veles-MIT" LLC.
Plot №8 is located near the village of Selivonovka, Molodechno district and has the size of 21, 96 hectares.
Plot №13 is located near the village of Peresady, Borisov district and has the size of 122, 25 hectares.
Sector 1 of Plot №12 is located in Borisov, the territory of "Borisov Plant Automotive and Tractor Electrical Equipment" JSC, - managing company of the Holding "Automotive components" has the size of 11, 1 hectares.
Plot№11 is located in Borisov and has t he size of 26, 86 hectares.
Sector 2 of Plot №12 is located in Borisov on the territory of "Borisov Plant "Avtogydrousilitel", JSC and has the size of 29, 93 hectares.
Plot №5 is located near the village of Mostishe, Smolevichi district and has the size of 110,84 hectares.
Sector 1 of Plot №4 is located in Oktyabrsky district of Minsk city in the area of airport complex National Airport "Minsk" and has the size of 54, 04 hectares.
Sector 2 of Plot №4 is located in the area of Minsk and Smolevichi districts, near National Airport "Minsk" and has the size of 198, 77 hectares.
Plot № 15 is located in Frunzenski district of Minsk city and has the size of 8,82 hectares, the territory of "Sukno" JSC.
Plot № 17 is located in Tsentralny district of Minsk city and has the size of 0, 3497 hectares, the territory of "Sukno" JSC.
Plot № 16 is located in Moskovsky district of Minsk city and has the size of 6, 78 hectares, the territory of "Sukno" JSC.
Plot № 19 is located in Zavodskoy district of Minsk city and has the size of 27, 59 hectares, the territory of "MOTOVELO" JSC.
Plot № 21 is located in Partizansky district of Minsk city and has the size of 10, 1055 hectares, the territory of "Belkommunmash" JSC.
Plot №6 is located in Moskovsky district of Minsk city and has the size of 19, 95 hectares, the territory of "Holding Management company" Horizont" LSC.
Plot № 14 is located in Leninski district of Minsk city and has the size of 18, 6 hectares, the territory of "Kamvol'"JSC.
Plot №9 is located in Oktyabrsky district of Minsk city and has the size of 46, 91 hectares, the territory of "Integral "JSC.
Plot № 20 is located in Oktyabrsky district of Minsk city and has the size of 3, 0448 hectares, the territory of "Belryba" JSC.
Sector 1 of Plot №1 is located in Zavodskoy district of Minsk city in the industrial area "11th kilometer of Mogilev highway" and has the size of 290, 0 hectares.
Sector 2 of Plot №1 is located in the southeastern part of Minsk and near the sewage disposal plant in Minsk region and has the size of 298, 0 hectares.
Sector 4 of Plot №1 is located near the village of El'nitsa, Minsk district and has the size of 7, 37 hectares.
Sector 1 of Plot №2 is located near the village of Obchak, Minsk district and has the size of 73, 37 hectares.
Sector 2 of PLot №2 is located near the village of Priles'e, Minsk district and has the size of 122, 64 hectares.
Sector 4 of Plot №2 is located near the transport interchanges М1/Е30 – М4, Minsk district and has the size of 7,15 hectares.
Sector 3 Of Plot №2 is located near the village of Privolny, Minsk district and has the size of 54,17 hectares.
Plot №10 is located in Fanipol' and in Dzerzhinsk district and has the size of 604, 4 hectares.
Plot №3 is located in Zavodskoy district of Minsk city near the village of Sosny and has the size of 41,42 hectares.
Plot № 18 is located in the village of Novi Sverzhen', Stolbtsy district and has the size of 13, 0 hectares.


This section contains some of the FUQs that I have struggled to understand and which I later to my surprise discovered that others also had the same doubts.
Some of the things that I have compiled in this section can also be found in other places on the internet, but I have tried to add my insight into the topics and presented it here.
Most of these topics that I have put here comprise of the basics of what I feel is needed from a person who wants to walk the talk on Quality.
There is no particular order that these needs to be read. But I would recommend WWWWWH to be read first.


The Coffee & Tea Festival NYC is celebrating its 10th anniversary. This year, the festival will take place Saturday, March 21st and Sunday, March 22nd at the Brooklyn Expo Center at 79 Franklin St. There will be over 60 exhibitors and more than 100 tastings. Discover and sample a wide variety of coffee, tea, and things related. There will also be seminars, workshops, and more.
Discounted tickets are currently available on Amazon Local. General admission tickets are $13. Choose one of the event days. Event is 11:30am to 5pm each day.


text:
Five-year-old girl sets up lemonade stand on the 4th of July to help raise money for wounded veterans
FOX 8 Cleveland - 2019-07-04T22:07:31.000Z
NORTH CANTON, Ohio — Five-year-old Cassidy Cecil has been planning for this day for months. She set up a lemonade stand in front of her home on the 4th of July, prepared to serve 19 gallons of freshly squeezed lemonade to benefit wounded veterans. Dozens of people including bikers, North Canton fire fighters and veterans lined up to support her. Her father said she got the idea following an impromptu lemonade stand last Independence Day. But this time, she wanted [
Read this story at FOX 8 Cleveland , FOX 8 Cleveland ,
5-year-old Ohio girl raises $3,660 for wounded veterans with 4th of July lemonade stand
Michigan 13-year-old aims to raise $5,000 for veterans with lemonade stand
Alleged 4th of July shooters are father, uncle of injured 8-year-old girl
CapFed Best News: 9-year-old raises $14K from lemonade-stand sales, donates to Topeka organization
12-Year-Old Girl Runs Free Library In Kerala's Kochi With Over 2,500 Books. A deep love for books and reading has prompted the girl to set up a library in this Kerala city and lay claim possibly to the title of the 'youngest librarian' in the country.
A 26-year-old man accused of pretending to be a teenager to groom a 13-year-old girl online
2-year-old girl, 6-year-old boy among victims of E. 63rd Street deaths
Young brothers' lemonade stand has 'made a lot of money' to help migrant kids
Alaska hits 90 degrees on July 4th, breaking 50-year-old record
by Daily Kos
21-Year-Old American Reilly Opelka Upsets Wawrinka In Five Sets at Wimbledon
by Sports Illustrated
Chick-Fil-A employee helps change 96-year-old WWII veteran's tire.
Missouri man drives into 4th of July crowd, runs over 5-year-old's leg
From FOX 8 Cleveland
north canton news
girl sets up lemonade stand to raise money for vets

redpajama_set_name: RedPajamaCommonCrawl


mounds of thinly sliced bourbon tri-tip covered in our original roadhouse grill bbq sauce and served on 4 freshly baked rolls. served with our spicy lassos.
tons of thinly sliced rings of onion, hand breaded and deep-fried. served with a side of spicy ranch dressing.
a tasty treat from the far eastfar east texas that is. cream cheese and chopped jalapeno cocooned in a skin of wonton. deep-fried with a helping of jalapeno jelly for dipping.
black beans, corn, red peppers, cilantro and diced chicken. served with spicy ranch dipping sauce.
smoked salmon, cream cheese, parmesan and red peppers. served with a tangy lemon dill dipping sauce.
a dip with just the right amount of kick. a mound of chips done original roadhouse style, celery sticks and ciabatta bread. served with a 3-cheese jalapeno artichoke dip and topped with green onions and diced tomatoes.
tender pieces of boneless fried chicken breast. served with celery sticks and bleu cheese dip. choose bourbon, bbq, spicy hot or our new teriyaki bbq sauce.
potato lovers, theres nothin better. get either bacon or shredded chicken, each covered with two kinds of cheese and slathered with bbq sauce.
a tender steak, marinated in a blend of red wine, soy sauce, garlic and other seasonings, grilled to your liking and then thinly-sliced.
a hearty steak marinated in our bourbon glaze and slow-roasted overnight to tender perfection. served medium, medium-well and well-done.
tender and meaty, grilled and basted with bbq sauce.
a tender, all natural chicken breast, grilled with your choice of peppercorn parmesan, cajun seasoning, bbq or spicy honey teriyaki sauces. served on a bed of rice.
fire-grilled to perfection mesquite salmon filet.
All Salads Come With Freshly Baked Rolls With Honey Butter. Add Extra Cheese Or Bacon To Any Salad For 50 Each.
mixed greens topped with tomatoes, jack and cheddar cheeses, bacon and red onions.
Original Roadhouse Grill features an authentic roadhouse menu and a down-home, fun lovin' atmosphere. You'll find people wearing blue jeans, peanuts served in buckets and peanut shells on the floor. You'll hear a blend of country music, classic rock and blues on the jukebox. You may even witness line dance performances by employees. We are an American Family Steakhouse. Bring in the whole family and crew for a fun, hearty delicious meal. One whiff from the open-air grill or our freshly made signature rolls will get your mouth watering.


JamFactory supports and promotes outstanding design and craftsmanship through its widely acclaimed studios, galleries and shops. A unique not-for-profit organisation located in the Adelaide city centre and its regional facility at Seppeltsfield in the Barossa Valley (opening late 2013), JamFactory is supported by the South Australian Government and recognised nationally and internationally as a centre for excellence for craft and design.
For 40 years JamFactory has been presenting outstanding exhibitions and public programs and nurturing the careers of talented artists, craftspeople and designers.
CUSP will be presented across our two facilities JamFactory, Adelaide and JamFactory at Seppeltsfield.
Architect and CEO of the Committee for Adelaide Tim Horton discusses what CUSP means to the Adelaide and South Australian region.


text:
HomeEthan Hawke
Zeros and Ones
January 25, 2022Addison Wylie0 Comments
Zeros and Ones begins with an enthusiastic vlog from Ethan Hawke, who eagerly tells the audience that he'll be playing a dual role in the movie that we're about to watch. He also speaks highly of the film's writer/director Abel Ferrara (Ms. 45, Bad Lieutenant, 4:44 Last Day on Earth), and how the filmmaker has made a truly special movie that speaks "to this moment" and that it's "Abel's hit on what we've been going through…
September 25, 2020Mark Barber0 Comments
Tesla, written and directed by Michael Almereyda (Hamlet [2000], Majorie Prime), explores the famous Serbian inventor with an ostensible inventiveness in both narrative and form. While the experimentation is welcome and even appropriate, its application is uneven and questionable, and leads to an uncertain overall thesis.
June 28, 2019Addison Wylie0 Comments
From my experience, audiences usually like when a movie shifts into high gear right off the hop; especially if it's an action movie. The Kid does just that. Using a pair of young fugitives as a vessel for the audience, the film essentially starts in the middle of a power struggle between Pat Garrett (Ethan Hawke) and Billy 'The Kid' Bonney (Dane DeHaan).
December 13, 2018Wylie Writes Staff0 Comments
By: Trevor Chartrand Director Ethan Hawke's country music biopic Blaze leaves a lot to be desired – with a lot of atmosphere and not much narrative, this film is meandering and weak. To some, the film could perhaps be considered an abstract poem, akin to the music stylings of the late Blaze Foley, which I suppose should be commendable. However, given the more obscure nature of this film's subject, the storytelling gaps will leave audiences…
July 14, 2018Addison Wylie1 Comment
Eugene Jarecki takes to the road in Elvis Presley's 1963 Rolls Royce in The King. The documentary's narrative itself is like Jarecki's luggage – crammed-full and seeping out of the zippers. However, this stuffed film is interesting in ways thought-provoking open discussions can be.
May 31, 2018Addison Wylie1 Comment
In First Reformed, writer/director Paul Schrader tells a story about characters living in excruciating personal turmoil. He then gradually develops his movie to be more visceral, so the audience can experience similar pain. You would think keeping movie goers in a state of compelling discomfort would be a tricky balancing act for Schrader, but he succeeds with ease; almost as if this area of emotional discomfort is a particular wheelhouse for the Taxi Driver screenwriter.
July 20, 2017Shannon Page0 Comments
Valerian and the City of a Thousand Planets is an astonishing film. Visually, it could even be described as a masterpiece. Unfortunately, a formulaic third act and a lack of chemistry between the two leads sink one of the most promising films of the year.
Toronto After Dark 2016: 'As the Gods Will' and 'In a Valley of Violence'
October 20, 2016Shahbaz Khayambashi0 Comments
As the Gods Will (DIR. Takashi Miike) Takashi Miike has two modes of filmmaking: a deadly serious style that's evident in films like Audition, and a goofy, over-the-top style visible in films like Ichi the Killer. In As the Gods Will, it takes the viewer mere minutes to figure out which category Miike's latest falls into (for me, it was the moment when a student gets decapitated and bleeds red marbles).
March 9, 2016Shannon Page1 Comment
Ethan Hawke (Before Sunrise, Boyhood) stars as east-coast jazz legend Chet Baker in Robert Budreau's biographical drama Born to Be Blue, which focuses on the musician's comeback during the 1960s and his struggle with addiction. The film, which was written, directed and produced by Budreau, chooses to examine a specific period of Baker's career rather than the entirety of his career – a decision that results in a more intimate experience than one might expect…
August 19, 2014Addison Wylie4 Comments
By: Addison Wylie It's been about a week since I've seen Richard Linklater's much anticipated Boyhood. I don't usually give myself that amount of time to conceive a write-up. Boyhood's different though. Boyhood's an ambitious project that had Linklater shooting scenes over a 12 year period capturing his young lead Mason (played by Ellar Coltrane) mature into a strong-willed individual. He, along with his cast, crafted a story around that filmmaking method and then –…


text:
De Haan (fr. Le Coq) – miejscowość i gmina w Belgii, w prowincji Flandria Zachodnia. W 2018 roku liczyło 12 635 mieszkańców.

Miejscowości we Flandrii Zachodniej
Gminy w prowincji Flandria Zachodnia

redpajama_set_name: RedPajamaWikipedia


Let's Get Talking – The Future of Word Of Mouth Marketing!
When it comes to generating new leads, you know there's nothing better than word of mouth. A happy customer has always been the best form of marketing & advertising. The way customers share their opinions in today's uber-connected world however has changed drastically.
So, what's the future going to look like? Well, before we look ahead, let's look back and appreciate how far word of mouth has evolved into a wider approach; one that goes beyond a friend's recommendation. It started with small internet communities that brought a phase of consumer centric review platforms.
Soon, e-commerce companies such as Amazon & Flipkart quickly offered more trustworthy review sections of their own. So, buyers knew they weren't reading a paid or fake review. There are of course close-knit digital communities like Team-BHP, TripAdvisor and Lonely Planet which will continue to influence consumers as long as they stay honest & trustworthy.
In the broader scheme of things, leveraging opinion and advice will need a far more technology-based approach. The strength of word of mouth has always been the impact influence has on potential consumers. While we still find ourselves being influenced by many whom we trust, there's a circle outside our family, friends and acquaintances whom we tend to trust and follow.
These are influencer who know how to create trust, authenticity, a sense of friendship and simplify access to information. The first wave of these influencers was made up of Bloggers, Celebrities and Actors. The next wave and the one that exists even today is the world of social media influencers - YouTube stars and Instagram Celebrities. These modern-day influencers are the new faces of word of mouth opinion makers.
Most consumers are influenced by recommendations from such power individuals. The only downside to this however is that some of these individuals or the organizations that employ them make false claims and share mis-information in exchange of money. This is when such individuals lost trust and authenticity. Luckily, "Word Of Mouth" always finds a way! Being an entrepreneur myself, I can relate to the opportunities that have come our way through word of mouth marketing. While there are several celebrity influencers one can employ –some such people have lost credibility. This is a combination of buying fake followers or doing too many unauthentic paid promotions. Which is why the future of word of mouth marketing lies with Key Opinion Leaders and Micro-influencers.
These people are loyal and in turn earn the trust of their followers and fans. People relate to them almost like friends and these influencers are also fiercely protective of their viewers. At CashKaro we work with a lot of these influencers through Qapper – our influencer marketing division focused on this.
In my personal experience these influencers have strengthened CashKaro' customer base. From working with external micro-influencers to creating an in-house team of our own fashion and lifestyle influencer channel – MenSwag, CashKaro has climbed up the ladder. We noticed that over 80% people who learn about a product or service through trusted influencers – tend to make a purchase decision.
Today word of mouth has spurred the growth of Social Commerce players such as Meesho, Wooplr and EarnKaro – which is CashKaro's social deal commerce platform. Such platforms help users earn money when they recommend/share/sell a product. So, there is an incentive for everyone to spread information through a digital version of word of mouth – using WhatsApp, Messenger and other social channels.
The future of word of mouth marketing will likely be ruled by Amazon and Google. These giants have done a brilliant job of keeping the consumer at the heart of their approach. A recent example of this is Neighbourly by Google, an app that works for the people on the basis of anonymous community reviews.
So, while you and I contribute to Google or Amazon by sharing reviews and images – their products share this credible, useful and unbiased information with its users. What's great is that all these tech giants are- taking the words out of our mouths and turning them into a trustworthy, free-flowing information bank.
While 2018 was all about understanding and knowing how to create positive word of mouth for your business, 2019 will be all about implementing what we've learnt. Encourage happy customers to talk about your brand and engage with them on every conceivable platform.
As it becomes easier for people to put their opinions and experiences out there, the genuine sentiment that surrounds your brand will make more noise than any form or marketing or advertising can. The future is word of mouth is consumer driven. Potential buyers will have access to easy to use technology driven platforms that offer a real-time reflection of aggregated existing-consumer sentiment.
Swati Bhargava is the Co-founder of CashKaro.com- India's largest Cashback & Coupons website. A girl from the small town of Ambala, Swati knew knowledge and education were her tickets to success. Stepping out of LSE, Swati worked her way up the corporate ladder at Goldman Sachs, London. After 5 enlightening years at Goldman Sachs, Swati decided to venture into the world of business. She started a UK based Cashback business - Pouring Pounds along with her husband & Co-Founder, Rohan Bhargava.
Swati also Co-Chairs H2 India- a Global leadership network for the digital industry. Honoured as one of the top 10 women entrepreneurs in the E-commerce industry, Swati has represented India at the coveted Blackbox Connect – Female Founders Edition - powered by Google in Silicon Valley, California.
Why gender-based stereotypes continue to plague marketing strategies?


" The discovery of a stable center is the same thing as creating the world. Its repetition."
The symposium among approximately 30 international artists is held on the grounds of the monastery in Plasy. The exhibition, results in part from the works made on-site by the symposium participants and is complemented with installations, drawings, paintings and objects by 20 other artists addressing the given theme. The exhibition opens on August 30th with a two-day program of concerts and performances. A collection of texts and catalogue of the works will accompany the exhibition. Accommodations for the symposium and exhibition participants is provided at the monastery.
It is beginning to appear as though many aesthetic, ethical, and physical structures, which have been considered invariable and objectively given, are rather the formations of our perception and senses. We nonetheless still continue to search for some kind of central germ, a firm framework, a life line that gives the world its shape and meaning. Is there a common center where we could all meet? The Near the Beginning project seeks to explore a broad range of approaches to and interpretations of this given theme. In doing so, it could help to clarify the contemporary perception of this problem.
Center for Metamedia-Plasy is an international, interdisciplinary artist residency program and project center established in 1992 on the grounds of the former monastery in Plasy, west Bohemia (a national monument). Over 400 artists from many parts of the world have participated in the Center's programs, which range from independent study or project-based residencies for visual and performing artists, scholars, curators, and students; exhibitions; performances; symposia; workshops; and other meetings. The Center's archive and library are open to the public. Catalogues are published by the Center for each symposia since 1992, in some cases supplemented by music recordings.


text:
Monty Python and the Holy Grail (1974)
And now! At Last! Another film completely different from some of the other films which aren't quite the same as this one
$1.8 mil
Genre(s): Adventure, Comedy, Fantasy
Graham Chapman
Eric Idle
Michael Palin
Connie Booth
Carol Cleveland
Bee Duffell
Mark Forstater
Michael White
This cult classic manages to make fun of the Arthurian legend as the motley crew portraying the Knights of the Round Table manage to make a silly mess of things as they set out in search of the Holy Grail, the vessel allegedly used by Christ during the Last Supper. The pilgrims encounter numerous difficulties on their journey, including killer rabbits, a town filled with bodies dead from plague, and military officers from France who continually taunt them with such threats as farting.
Release Date March 6, 2012
Release Date October 3, 2006
imdb: 8.5 G
Brotherhood of the Wolf


text:
New head of operations East of England
Meet the new guy: New head of gas operations for East region
Apr 6 2017 corporate
Chris Rison takes over as National Grid Gas Distribution's Head of Operations in its East region
Predecessor James Harrison has left to head up National Grid Gas Distribution's London Gas Network
The vast East region includes urban, rural and coastal locations
A new head of operations has taken over National Grid's fast paced East region where he will work to ensure over four million customers keep on enjoying safe and reliable gas supplies.
This week Chris Rison, CEng. MSc. MIMechE*, took over the East network after predecessor James Harrison moved on to helm National Grid Gas Distribution's London network.
Chris' new job involves managing Emergency Response and Repair Operations which deals with reports of gas escapes across National Grid's East region. The network includes East Anglia, and the East Midlands along with Northamptonshire, Bedfordshire and Hertfordshire. A vast and varied patch the network supplies over four million customers in an area covering nearly fifteen thousand square miles which includes industrial towns and cities, seaside towns and national parks.
Chartered Engineer Chris was previously Network Manager, Emergency for London, where he covered National Grid's Gas Distribution patch in the capital, serving a network of over two million customers and covering landmark locations such as Westminster Abbey, Buckingham Palace, the Houses of Parliament, Wembley and Canary Wharf.
Chris, 32, joined National Grid Gas Distribution as a Graduate Trainee back in 2009. He has held many roles in Gas Distribution and in London Operations where he has gained extensive operational and leadership experience.
He said: "I'm very happy to lead the team in East who deliver gas safely to such a huge part of the country. Gas is such an important thing in our lives, enabling us to enjoy warm houses and hot dinners. Gas matters and so our work matters.
"I've got a great team of engineers and support staff to work with and I'm excited to join East Network."
Outside of work Chris enjoys days out with his young family, keeping active, the cinema and music.
This press release relates to Cadent work. It does not have Cadent branding on it, due to this press release being published prior to 1st May 2017, when this gas distribution business was part of National Grid's group of businesses.


Since 2013, MassCAN has played an important leadership role, along with many other passionate advocates and partners, in promoting equitable opportunities for all Massachusetts students to have access to quality K–12 computer science education.
A complicated array of public and private funding challenges have prevented MassCAN from reaching its full potential to foster and support a broad collaborative effort to expand computer science education in the state. Thus, MassCAN suspended operations as of August 31, 2018. This suspension will give the program and government leaders time to seek a more viable funding model and to explore ways to best take the foundation MassCAN has built to the next level.
Given its broad and deep expertise in K–12 computer science education, Education Development Center, Inc. (EDC), remains eager to help the state promote equitable opportunities for all Massachusetts students to access quality K–12 computer science education. Should a viable and sustainable funding model emerge to support this work, EDC would welcome the opportunity to continue a partnership to advance MassCAN's goals.
Additionally, Anne DeMallie, Digital Literacy and Computer Science Content Support Lead and Computer Science and STEM Integration Specialist at the Massachusetts Department of Elementary and Secondary Education, is deeply knowledgeable about the state's K–12 computer science activities. Requests for information can be addressed to Anne via phone (781-338-3527) or email (ademallie@doe.mass.edu).
Note: Jim Stanton, MassCAN co-founder and Executive Director, retired from MassCAN effective August 31, 2018, but remains a Senior Project Director at EDC on a part-time basis through early 2019.


Did the aussies have any of thier own AC in WW2?
If you don't mind flying British aircraft, I'm reasonably confident you might well get RAAF Spitfires in this one. I don't know much beyond that. I guess the good old P-40 in Aussie markings is a fair possibility too, both aircraft are included from what I've read, and Ubisoft seem very good about supporting allied countries other than the usual USN/USMC/USAAF. If not you can fly one of ours over Singapore - you are welcome to join the RAF like many of your brave countryman really did!


Leaders in machinery for mining, quarrying, earthmoving, civil, agriculture & forestry, since 2002.
We stock a range of machinery, can import to order, offer you sound advice and guarantee unrivalled service. Browse our range online.
Enjoy great rates on excavators, dozers, loaders, scrapers, graders and compactors – for short-term or long-term projects. Get in touch today to find out more about hiring.
Trackgear, undercarriage parts, filters, belts, batteries and more – get in touch to ensure you get the right part for the job.
Protect your costly machine components so you get the longest life possible from them – get in touch to book your next service.
Trackworks Machinery Limited was established in 2002 as a family-owned business. We're experts in machinery for the mining, quarrying, earthmoving, civil, agriculture and forestry industries.
Operating from Pukekohe, we're actively involved in buying, selling, refurbishment and hire of machinery within New Zealand and globally.


text:
using base::FilePath;
using content::AsyncFileTestHelper;
using net::DrainableIOBuffer;
using net::IOBuffer;
using FileCreationInfo = storage::BlobMemoryController::FileCreationInfo;

namespace storage {
namespace {

const int kTestDiskCacheStreamIndex = 0;
const int kTestDiskCacheSideStreamIndex = 1;

void SaveBlobStatusAndFiles(BlobStatus* status_ptr,
                            std::vector<FileCreationInfo>* files_ptr,
                            BlobStatus status,
                            std::vector<FileCreationInfo> files) {
  *status_ptr = status;
  for (FileCreationInfo& info : files) {
    files_ptr->push_back(std::move(info));
  }
}

// Our disk cache tests don't need a real data handle since the tests themselves
// scope the disk cache and entries.
class EmptyDataHandle : public storage::BlobDataBuilder::DataHandle {
 private:
  ~EmptyDataHandle() override {}
};

// A disk_cache::Entry that arbitrarily delays the completion of a read
// operation to allow testing some races without flake. This is particularly
// relevant in this unit test, which uses the always-synchronous MEMORY_CACHE.
class DelayedReadEntry : public disk_cache::Entry {
 public:
  explicit DelayedReadEntry(disk_cache::ScopedEntryPtr entry)
      : entry_(std::move(entry)) {}
  ~DelayedReadEntry() override { EXPECT_FALSE(HasPendingReadCallbacks()); }

  bool HasPendingReadCallbacks() { return !pending_read_callbacks_.empty(); }

  void RunPendingReadCallbacks() {
    std::vector<base::Callback<void(void)>> callbacks;
    pending_read_callbacks_.swap(callbacks);
    for (const auto& callback : callbacks)
      callback.Run();
  }

  // From disk_cache::Entry:
  void Doom() override { entry_->Doom(); }

  void Close() override { delete this; }  // Note this is required by the API.

  std::string GetKey() const override { return entry_->GetKey(); }

  base::Time GetLastUsed() const override { return entry_->GetLastUsed(); }

  base::Time GetLastModified() const override {
    return entry_->GetLastModified();
  }

  int32_t GetDataSize(int index) const override {
    return entry_->GetDataSize(index);
  }

  int ReadData(int index,
               int offset,
               IOBuffer* buf,
               int buf_len,
               const CompletionCallback& original_callback) override {
    net::TestCompletionCallback callback;
    int rv = entry_->ReadData(index, offset, buf, buf_len, callback.callback());
    DCHECK_NE(rv, net::ERR_IO_PENDING)
        << "Test expects to use a MEMORY_CACHE instance, which is synchronous.";
    pending_read_callbacks_.push_back(base::Bind(original_callback, rv));
    return net::ERR_IO_PENDING;
  }

  int WriteData(int index,
                int offset,
                IOBuffer* buf,
                int buf_len,
                const CompletionCallback& callback,
                bool truncate) override {
    return entry_->WriteData(index, offset, buf, buf_len, callback, truncate);
  }

  int ReadSparseData(int64_t offset,
                     IOBuffer* buf,
                     int buf_len,
                     const CompletionCallback& callback) override {
    return entry_->ReadSparseData(offset, buf, buf_len, callback);
  }

  int WriteSparseData(int64_t offset,
                      IOBuffer* buf,
                      int buf_len,
                      const CompletionCallback& callback) override {
    return entry_->WriteSparseData(offset, buf, buf_len, callback);
  }

  int GetAvailableRange(int64_t offset,
                        int len,
                        int64_t* start,
                        const CompletionCallback& callback) override {
    return entry_->GetAvailableRange(offset, len, start, callback);
  }

  bool CouldBeSparse() const override { return entry_->CouldBeSparse(); }

  void CancelSparseIO() override { entry_->CancelSparseIO(); }

  int ReadyForSparseIO(const CompletionCallback& callback) override {
    return entry_->ReadyForSparseIO(callback);
  }

 private:
  disk_cache::ScopedEntryPtr entry_;
  std::vector<base::Callback<void(void)>> pending_read_callbacks_;
};

std::unique_ptr<disk_cache::Backend> CreateInMemoryDiskCache(
    const scoped_refptr<base::SingleThreadTaskRunner>& thread) {
  std::unique_ptr<disk_cache::Backend> cache;
  net::TestCompletionCallback callback;
  int rv = disk_cache::CreateCacheBackend(
      net::MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, FilePath(), 0, false,
      thread, nullptr, &cache, callback.callback());
  EXPECT_EQ(net::OK, callback.GetResult(rv));

  return cache;
}

disk_cache::ScopedEntryPtr CreateDiskCacheEntry(disk_cache::Backend* cache,
                                                const char* key,
                                                const std::string& data) {
  disk_cache::Entry* temp_entry = nullptr;
  net::TestCompletionCallback callback;
  int rv = cache->CreateEntry(key, &temp_entry, callback.callback());
  if (callback.GetResult(rv) != net::OK)
    return nullptr;
  disk_cache::ScopedEntryPtr entry(temp_entry);

  scoped_refptr<net::StringIOBuffer> iobuffer = new net::StringIOBuffer(data);
  rv = entry->WriteData(kTestDiskCacheStreamIndex, 0, iobuffer.get(),
                        iobuffer->size(), callback.callback(), false);
  EXPECT_EQ(static_cast<int>(data.size()), callback.GetResult(rv));
  return entry;
}

disk_cache::ScopedEntryPtr CreateDiskCacheEntryWithSideData(
    disk_cache::Backend* cache,
    const char* key,
    const std::string& data,
    const std::string& side_data) {
  disk_cache::ScopedEntryPtr entry = CreateDiskCacheEntry(cache, key, data);
  scoped_refptr<net::StringIOBuffer> iobuffer =
      new net::StringIOBuffer(side_data);
  net::TestCompletionCallback callback;
  int rv = entry->WriteData(kTestDiskCacheSideStreamIndex, 0, iobuffer.get(),
                            iobuffer->size(), callback.callback(), false);
  EXPECT_EQ(static_cast<int>(side_data.size()), callback.GetResult(rv));
  return entry;
}

template <typename T>
void SetValue(T* address, T value) {
  *address = value;
}

class FakeFileStreamReader : public FileStreamReader {
 public:
  explicit FakeFileStreamReader(const std::string& contents)
      : buffer_(new DrainableIOBuffer(
            new net::StringIOBuffer(
                std::unique_ptr<std::string>(new std::string(contents))),
            contents.size())),
        net_error_(net::OK),
        size_(contents.size()) {}
  FakeFileStreamReader(const std::string& contents, uint64_t size)
      : buffer_(new DrainableIOBuffer(
            new net::StringIOBuffer(
                std::unique_ptr<std::string>(new std::string(contents))),
            contents.size())),
        net_error_(net::OK),
        size_(size) {}

  ~FakeFileStreamReader() override {}

  void SetReturnError(int net_error) { net_error_ = net_error; }

  void SetAsyncRunner(base::SingleThreadTaskRunner* runner) {
    async_task_runner_ = runner;
  }

  int Read(net::IOBuffer* buf,
           int buf_length,
           const net::CompletionCallback& done) override {
    DCHECK(buf);
    // When async_task_runner_ is not set, return synchronously.
    if (!async_task_runner_.get()) {
      if (net_error_ == net::OK) {
        return ReadImpl(buf, buf_length, net::CompletionCallback());
      } else {
        return net_error_;
      }
    }

    // Otherwise always return asynchronously.
    if (net_error_ == net::OK) {
      async_task_runner_->PostTask(
          FROM_HERE,
          base::Bind(base::IgnoreResult(&FakeFileStreamReader::ReadImpl),
                     base::Unretained(this), make_scoped_refptr(buf),
                     buf_length, done));
    } else {
      async_task_runner_->PostTask(FROM_HERE, base::Bind(done, net_error_));
    }
    return net::ERR_IO_PENDING;
  }

  int64_t GetLength(
      const net::Int64CompletionCallback& size_callback) override {
    // When async_task_runner_ is not set, return synchronously.
    if (!async_task_runner_.get()) {
      if (net_error_ == net::OK) {
        return size_;
      } else {
        return net_error_;
      }
    }
    if (net_error_ == net::OK) {
      async_task_runner_->PostTask(FROM_HERE, base::Bind(size_callback, size_));
    } else {
      async_task_runner_->PostTask(
          FROM_HERE,
          base::Bind(size_callback, static_cast<int64_t>(net_error_)));
    }
    return net::ERR_IO_PENDING;
  }

 private:
  int ReadImpl(scoped_refptr<net::IOBuffer> buf,
               int buf_length,
               const net::CompletionCallback& done) {
    CHECK_GE(buf_length, 0);
    int length = std::min(buf_length, buffer_->BytesRemaining());
    memcpy(buf->data(), buffer_->data(), length);
    buffer_->DidConsume(length);
    if (done.is_null()) {
      return length;
    }
    done.Run(length);
    return net::ERR_IO_PENDING;
  }

  scoped_refptr<net::DrainableIOBuffer> buffer_;
  scoped_refptr<base::SingleThreadTaskRunner> async_task_runner_;
  int net_error_;
  uint64_t size_;

  DISALLOW_COPY_AND_ASSIGN(FakeFileStreamReader);
};

class MockFileStreamReaderProvider
    : public BlobReader::FileStreamReaderProvider {
 public:
  ~MockFileStreamReaderProvider() override {}

  MOCK_METHOD4(CreateForLocalFileMock,
               FileStreamReader*(base::TaskRunner* task_runner,
                                 const FilePath& file_path,
                                 int64_t initial_offset,
                                 const base::Time& expected_modification_time));
  MOCK_METHOD4(CreateFileStreamReaderMock,
               FileStreamReader*(const GURL& filesystem_url,
                                 int64_t offset,
                                 int64_t max_bytes_to_read,
                                 const base::Time& expected_modification_time));
  // Since we're returning a move-only type, we have to do some delegation for
  // gmock.
  std::unique_ptr<FileStreamReader> CreateForLocalFile(
      base::TaskRunner* task_runner,
      const base::FilePath& file_path,
      int64_t initial_offset,
      const base::Time& expected_modification_time) override {
    return base::WrapUnique(CreateForLocalFileMock(
        task_runner, file_path, initial_offset, expected_modification_time));
  }

  std::unique_ptr<FileStreamReader> CreateFileStreamReader(
      const GURL& filesystem_url,
      int64_t offset,
      int64_t max_bytes_to_read,
      const base::Time& expected_modification_time) override {
    return base::WrapUnique(CreateFileStreamReaderMock(
        filesystem_url, offset, max_bytes_to_read, expected_modification_time));
  }
};

}  // namespace

class BlobReaderTest : public ::testing::Test {
 public:
  BlobReaderTest() {}
  ~BlobReaderTest() override {}

  void TearDown() override {
    reader_.reset();
    blob_handle_.reset();
    base::RunLoop().RunUntilIdle();
    base::RunLoop().RunUntilIdle();
  }

 protected:
  void InitializeReader(BlobDataBuilder* builder) {
    blob_handle_ = builder ? context_.AddFinishedBlob(builder) : nullptr;
    provider_ = new MockFileStreamReaderProvider();
    reader_.reset(new BlobReader(blob_handle_.get(),
                                 base::WrapUnique(provider_),
                                 message_loop_.task_runner().get()));
  }

  // Takes ownership of the file reader (the blob reader takes ownership).
  void ExpectLocalFileCall(const FilePath& file_path,
                           base::Time modification_time,
                           uint64_t initial_offset,
                           FakeFileStreamReader* reader) {
    EXPECT_CALL(*provider_, CreateForLocalFileMock(
                                message_loop_.task_runner().get(), file_path,
                                initial_offset, modification_time))
        .WillOnce(testing::Return(reader));
  }

  // Takes ownership of the file reader (the blob reader takes ownership).
  void ExpectFileSystemCall(const GURL& filesystem_url,
                            int64_t offset,
                            int64_t max_bytes_to_read,
                            base::Time expected_modification_time,
                            FakeFileStreamReader* reader) {
    EXPECT_CALL(*provider_, CreateFileStreamReaderMock(
                                filesystem_url, offset, max_bytes_to_read,
                                expected_modification_time))
        .WillOnce(testing::Return(reader));
  }

  void CheckSizeCalculatedSynchronously(size_t expected_size, int async_size) {
    EXPECT_EQ(-1, async_size);
    EXPECT_EQ(net::OK, reader_->net_error());
    EXPECT_EQ(expected_size, reader_->total_size());
    EXPECT_TRUE(reader_->total_size_calculated());
  }

  void CheckSizeNotCalculatedYet(int async_size) {
    EXPECT_EQ(-1, async_size);
    EXPECT_EQ(net::OK, reader_->net_error());
    EXPECT_FALSE(reader_->total_size_calculated());
  }

  void CheckSizeCalculatedAsynchronously(size_t expected_size,
                                         int async_result) {
    EXPECT_EQ(net::OK, async_result);
    EXPECT_EQ(net::OK, reader_->net_error());
    EXPECT_EQ(expected_size, reader_->total_size());
    EXPECT_TRUE(reader_->total_size_calculated());
  }

  scoped_refptr<net::IOBuffer> CreateBuffer(uint64_t size) {
    return scoped_refptr<net::IOBuffer>(
        new net::IOBuffer(static_cast<size_t>(size)));
  }

  bool IsReaderTotalSizeCalculated() {
    return reader_->total_size_calculated();
  }

  BlobStorageContext context_;
  std::unique_ptr<BlobDataHandle> blob_handle_;
  MockFileStreamReaderProvider* provider_ = nullptr;
  base::MessageLoop message_loop_;
  std::unique_ptr<BlobReader> reader_;

 private:
  DISALLOW_COPY_AND_ASSIGN(BlobReaderTest);
};

TEST_F(BlobReaderTest, BasicMemory) {
  BlobDataBuilder b("uuid");
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  b.AppendData(kData);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_TRUE(reader_->IsInMemory());
  CheckSizeCalculatedSynchronously(kDataSize, size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kDataSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
}

TEST_F(BlobReaderTest, BasicFile) {
  BlobDataBuilder b("uuid");
  const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();
  b.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&b);

  // Non-async reader.
  ExpectLocalFileCall(kPath, kTime, 0, new FakeFileStreamReader(kData));

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_FALSE(reader_->IsInMemory());
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
}

TEST_F(BlobReaderTest, BasicFileSystem) {
  BlobDataBuilder b("uuid");
  const GURL kURL("file://test_file/here.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();
  b.AppendFileSystemFile(kURL, 0, kData.size(), kTime);
  this->InitializeReader(&b);
  // Non-async reader.
  ExpectFileSystemCall(kURL, 0, kData.size(), kTime,
                       new FakeFileStreamReader(kData));

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_FALSE(reader_->IsInMemory());

  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
}

TEST_F(BlobReaderTest, BasicDiskCache) {
  std::unique_ptr<disk_cache::Backend> cache =
      CreateInMemoryDiskCache(message_loop_.task_runner());
  ASSERT_TRUE(cache);

  BlobDataBuilder b("uuid");
  const std::string kData = "Test Blob Data";
  scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
      new EmptyDataHandle();
  disk_cache::ScopedEntryPtr entry =
      CreateDiskCacheEntry(cache.get(), "test entry", kData);
  b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  EXPECT_FALSE(reader_->has_side_data());

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size()));
}

TEST_F(BlobReaderTest, DiskCacheWithSideData) {
  std::unique_ptr<disk_cache::Backend> cache =
      CreateInMemoryDiskCache(message_loop_.task_runner());
  ASSERT_TRUE(cache);

  BlobDataBuilder b("uuid");
  const std::string kData = "Test Blob Data";
  const std::string kSideData = "Test side data";
  scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
      new EmptyDataHandle();
  disk_cache::ScopedEntryPtr entry = CreateDiskCacheEntryWithSideData(
      cache.get(), "test entry", kData, kSideData);
  b.AppendDiskCacheEntryWithSideData(data_handle, entry.get(),
                                     kTestDiskCacheStreamIndex,
                                     kTestDiskCacheSideStreamIndex);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  EXPECT_TRUE(reader_->has_side_data());
  BlobReader::Status status = BlobReader::Status::DONE;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->ReadSideData(
                base::Bind(&SetValue<BlobReader::Status>, &status)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_TRUE(reader_->side_data());
  std::string result(reader_->side_data()->data(),
                     reader_->side_data()->size());
  EXPECT_EQ(kSideData, result);
}

TEST_F(BlobReaderTest, BufferLargerThanMemory) {
  BlobDataBuilder b("uuid");
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  const size_t kBufferSize = 10ul;
  b.AppendData(kData);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kBufferSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
}

TEST_F(BlobReaderTest, MemoryRange) {
  BlobDataBuilder b("uuid");
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  const size_t kSeekOffset = 2ul;
  const uint64_t kReadLength = 4ull;
  b.AppendData(kData);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);

  reader_->SetReadRange(kSeekOffset, kReadLength);
  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kDataSize - kSeekOffset, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength));
}

TEST_F(BlobReaderTest, BufferSmallerThanMemory) {
  BlobDataBuilder b("uuid");
  const std::string kData("Hello!!!");
  const size_t kBufferSize = 4ul;
  b.AppendData(kData);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kBufferSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize));

  bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kBufferSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize));
}

TEST_F(BlobReaderTest, SegmentedBufferAndMemory) {
  BlobDataBuilder b("uuid");
  const size_t kNumItems = 10;
  const size_t kItemSize = 6;
  const size_t kBufferSize = 10;
  const size_t kTotalSize = kNumItems * kItemSize;
  char current_value = 0;
  for (size_t i = 0; i < kNumItems; i++) {
    char buf[kItemSize];
    for (size_t j = 0; j < kItemSize; j++) {
      buf[j] = current_value++;
    }
    b.AppendData(buf, kItemSize);
  }
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kTotalSize, size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));

  current_value = 0;
  for (size_t i = 0; i < kTotalSize / kBufferSize; i++) {
    int bytes_read = 0;
    int async_bytes_read = 0;
    EXPECT_EQ(BlobReader::Status::DONE,
              reader_->Read(buffer.get(), kBufferSize, &bytes_read,
                            base::Bind(&SetValue<int>, &async_bytes_read)));
    EXPECT_EQ(net::OK, reader_->net_error());
    EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
    EXPECT_EQ(0, async_bytes_read);
    for (size_t j = 0; j < kBufferSize; j++) {
      EXPECT_EQ(current_value, buffer->data()[j]);
      current_value++;
    }
  }
}

TEST_F(BlobReaderTest, FileAsync) {
  BlobDataBuilder b("uuid");
  const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();
  b.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&b);

  std::unique_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
  reader->SetAsyncRunner(message_loop_.task_runner().get());

  ExpectLocalFileCall(kPath, kTime, 0, reader.release());

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_FALSE(reader_->IsInMemory());
  CheckSizeNotCalculatedYet(size_result);
  base::RunLoop().RunUntilIdle();
  CheckSizeCalculatedAsynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
  EXPECT_EQ(0, bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
}

TEST_F(BlobReaderTest, FileSystemAsync) {
  BlobDataBuilder b("uuid");
  const GURL kURL("file://test_file/here.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();
  b.AppendFileSystemFile(kURL, 0, kData.size(), kTime);
  this->InitializeReader(&b);

  std::unique_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
  reader->SetAsyncRunner(message_loop_.task_runner().get());

  ExpectFileSystemCall(kURL, 0, kData.size(), kTime, reader.release());

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeNotCalculatedYet(size_result);
  EXPECT_FALSE(reader_->IsInMemory());
  base::RunLoop().RunUntilIdle();
  CheckSizeCalculatedAsynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
  EXPECT_EQ(0, bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
}

TEST_F(BlobReaderTest, DiskCacheAsync) {
  std::unique_ptr<disk_cache::Backend> cache =
      CreateInMemoryDiskCache(message_loop_.task_runner());
  ASSERT_TRUE(cache);

  BlobDataBuilder b("uuid");
  const std::string kData = "Test Blob Data";
  scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
      new EmptyDataHandle();
  std::unique_ptr<DelayedReadEntry> delayed_read_entry(new DelayedReadEntry(
      CreateDiskCacheEntry(cache.get(), "test entry", kData)));
  b.AppendDiskCacheEntry(data_handle, delayed_read_entry.get(),
                         kTestDiskCacheStreamIndex);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeCalculatedSynchronously(kData.size(), size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_TRUE(delayed_read_entry->HasPendingReadCallbacks());
  delayed_read_entry->RunPendingReadCallbacks();
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(0, bytes_read);
  EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
  EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size()));
}

TEST_F(BlobReaderTest, FileRange) {
  BlobDataBuilder b("uuid");
  const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
  // We check the offset in the ExpectLocalFileCall mock.
  const std::string kRangeData = "leD";
  const std::string kData = "FileData!!!";
  const uint64_t kOffset = 2;
  const uint64_t kReadLength = 3;
  const base::Time kTime = base::Time::Now();
  b.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&b);

  std::unique_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(kData));
  reader->SetAsyncRunner(message_loop_.task_runner().get());
  ExpectLocalFileCall(kPath, kTime, 0, reader.release());

  // We create the reader again with the offset after the seek.
  reader.reset(new FakeFileStreamReader(kRangeData));
  reader->SetAsyncRunner(message_loop_.task_runner().get());
  ExpectLocalFileCall(kPath, kTime, kOffset, reader.release());

  int size_result = -1;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  base::RunLoop().RunUntilIdle();

  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->SetReadRange(kOffset, kReadLength));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kReadLength, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kReadLength, static_cast<size_t>(async_bytes_read));
  EXPECT_EQ(0, bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength));
}

TEST_F(BlobReaderTest, DiskCacheRange) {
  std::unique_ptr<disk_cache::Backend> cache =
      CreateInMemoryDiskCache(message_loop_.task_runner());
  ASSERT_TRUE(cache);

  BlobDataBuilder b("uuid");
  const std::string kData = "Test Blob Data";
  const uint64_t kOffset = 2;
  const uint64_t kReadLength = 3;
  scoped_refptr<BlobDataBuilder::DataHandle> data_handle =
      new EmptyDataHandle();
  disk_cache::ScopedEntryPtr entry =
      CreateDiskCacheEntry(cache.get(), "test entry", kData);
  b.AppendDiskCacheEntry(data_handle, entry.get(), kTestDiskCacheStreamIndex);
  this->InitializeReader(&b);

  int size_result = -1;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));

  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kReadLength);
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->SetReadRange(kOffset, kReadLength));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kReadLength, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength));
}

TEST_F(BlobReaderTest, FileSomeAsyncSegmentedOffsetsUnknownSizes) {
  // This tests includes:
  // * Unknown file sizes (item length of uint64_t::max) for every other item.
  // * Offsets for every 3rd file item.
  // * Non-async reader for every 4th file item.
  BlobDataBuilder b("uuid");
  const FilePath kPathBase = FilePath::FromUTF8Unsafe("/fake/file.txt");
  const base::Time kTime = base::Time::Now();
  const size_t kNumItems = 10;
  const size_t kItemSize = 6;
  const size_t kBufferSize = 10;
  const size_t kTotalSize = kNumItems * kItemSize;
  char current_value = 0;
  // Create blob and reader.
  for (size_t i = 0; i < kNumItems; i++) {
    current_value += kItemSize;
    FilePath path = kPathBase.Append(
        FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value)));
    uint64_t offset = i % 3 == 0 ? 1 : 0;
    uint64_t size = kItemSize;
    b.AppendFile(path, offset, size, kTime);
  }
  this->InitializeReader(&b);

  // Set expectations.
  current_value = 0;
  for (size_t i = 0; i < kNumItems; i++) {
    uint64_t offset = i % 3 == 0 ? 1 : 0;
    std::unique_ptr<char[]> buf(new char[kItemSize + offset]);
    if (offset > 0) {
      memset(buf.get(), 7, offset);
    }
    for (size_t j = 0; j < kItemSize; j++) {
      buf.get()[j + offset] = current_value++;
    }
    std::unique_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(
        std::string(buf.get() + offset, kItemSize), kItemSize + offset));
    if (i % 4 != 0) {
      reader->SetAsyncRunner(message_loop_.task_runner().get());
    }
    FilePath path = kPathBase.Append(
        FilePath::FromUTF8Unsafe(base::StringPrintf("%d", current_value)));
    ExpectLocalFileCall(path, kTime, offset, reader.release());
  }

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeNotCalculatedYet(size_result);
  base::RunLoop().RunUntilIdle();
  CheckSizeCalculatedAsynchronously(kTotalSize, size_result);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));

  current_value = 0;
  for (size_t i = 0; i < kTotalSize / kBufferSize; i++) {
    int bytes_read = 0;
    int async_bytes_read = 0;
    EXPECT_EQ(BlobReader::Status::IO_PENDING,
              reader_->Read(buffer.get(), kBufferSize, &bytes_read,
                            base::Bind(&SetValue<int>, &async_bytes_read)));
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(net::OK, reader_->net_error());
    EXPECT_EQ(0, bytes_read);
    EXPECT_EQ(kBufferSize, static_cast<size_t>(async_bytes_read));
    for (size_t j = 0; j < kBufferSize; j++) {
      EXPECT_EQ(current_value, buffer->data()[j]);
      current_value++;
    }
  }
}

TEST_F(BlobReaderTest, MixedContent) {
  // Includes data, a file, and a disk cache entry.
  std::unique_ptr<disk_cache::Backend> cache =
      CreateInMemoryDiskCache(message_loop_.task_runner());
  ASSERT_TRUE(cache);

  BlobDataBuilder b("uuid");
  const std::string kData1("Hello ");
  const std::string kData2("there. ");
  const std::string kData3("This ");
  const std::string kData4("is multi-content.");
  const uint64_t kDataSize = 35;

  const base::Time kTime = base::Time::Now();
  const FilePath kData1Path = FilePath::FromUTF8Unsafe("/fake/file.txt");

  disk_cache::ScopedEntryPtr entry3 =
      CreateDiskCacheEntry(cache.get(), "test entry", kData3);

  b.AppendFile(kData1Path, 0, kData1.size(), kTime);
  b.AppendData(kData2);
  b.AppendDiskCacheEntry(
      scoped_refptr<BlobDataBuilder::DataHandle>(new EmptyDataHandle()),
      entry3.get(), kTestDiskCacheStreamIndex);
  b.AppendData(kData4);

  this->InitializeReader(&b);

  std::unique_ptr<FakeFileStreamReader> reader(
      new FakeFileStreamReader(kData1));
  reader->SetAsyncRunner(message_loop_.task_runner().get());
  ExpectLocalFileCall(kData1Path, kTime, 0, reader.release());

  int size_result = -1;
  EXPECT_FALSE(IsReaderTotalSizeCalculated());
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  CheckSizeNotCalculatedYet(size_result);
  base::RunLoop().RunUntilIdle();
  CheckSizeCalculatedAsynchronously(kDataSize, size_result);

  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize);

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kDataSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(0, async_bytes_read);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(0, bytes_read);
  EXPECT_EQ(kDataSize, static_cast<size_t>(async_bytes_read));
  EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.",
                      kDataSize));
}

TEST_F(BlobReaderTest, StateErrors) {
  // Test common variables
  int bytes_read = -1;
  int async_bytes_read = -1;
  int size_result = -1;
  const std::string kData("Hello!!!");

  // Case: Blob handle is a nullptr.
  InitializeReader(nullptr);
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
  EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(10);
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->Read(buffer.get(), 10, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());

  // Case: Not calling CalculateSize before SetReadRange.
  BlobDataBuilder builder1("uuid1");
  builder1.AppendData(kData);
  InitializeReader(&builder1);
  EXPECT_EQ(BlobReader::Status::NET_ERROR, reader_->SetReadRange(0, 10));
  EXPECT_EQ(net::ERR_FAILED, reader_->net_error());
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->Read(buffer.get(), 10, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));

  // Case: Not calling CalculateSize before Read.
  BlobDataBuilder builder2("uuid2");
  builder2.AppendData(kData);
  InitializeReader(&builder2);
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->Read(buffer.get(), 10, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
}

TEST_F(BlobReaderTest, FileErrorsSync) {
  int size_result = -1;
  const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();

  // Case: Error on length query.
  BlobDataBuilder builder1("uuid1");
  builder1.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&builder1);
  FakeFileStreamReader* reader = new FakeFileStreamReader(kData);
  reader->SetReturnError(net::ERR_FILE_NOT_FOUND);
  ExpectLocalFileCall(kPath, kTime, 0, reader);

  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());

  // Case: Error on read.
  BlobDataBuilder builder2("uuid2");
  builder2.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&builder2);
  reader = new FakeFileStreamReader(kData);
  ExpectLocalFileCall(kPath, kTime, 0, reader);
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  reader->SetReturnError(net::ERR_FILE_NOT_FOUND);

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
}

TEST_F(BlobReaderTest, FileErrorsAsync) {
  int size_result = -1;
  const FilePath kPath = FilePath::FromUTF8Unsafe("/fake/file.txt");
  const std::string kData = "FileData!!!";
  const base::Time kTime = base::Time::Now();

  // Case: Error on length query.
  BlobDataBuilder builder1("uuid1");
  builder1.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&builder1);
  FakeFileStreamReader* reader = new FakeFileStreamReader(kData);
  reader->SetAsyncRunner(message_loop_.task_runner().get());
  reader->SetReturnError(net::ERR_FILE_NOT_FOUND);
  ExpectLocalFileCall(kPath, kTime, 0, reader);

  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_EQ(net::OK, reader_->net_error());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, size_result);
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());

  // Case: Error on read.
  BlobDataBuilder builder2("uuid2");
  builder2.AppendFile(kPath, 0, kData.size(), kTime);
  this->InitializeReader(&builder2);
  reader = new FakeFileStreamReader(kData);
  ExpectLocalFileCall(kPath, kTime, 0, reader);
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  reader->SetReturnError(net::ERR_FILE_NOT_FOUND);
  reader->SetAsyncRunner(message_loop_.task_runner().get());

  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kData.size()));
  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->Read(buffer.get(), kData.size(), &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, async_bytes_read);
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
}

TEST_F(BlobReaderTest, RangeError) {
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  const uint64_t kReadLength = 4ull;

  // Case: offset too high.
  BlobDataBuilder b("uuid1");
  b.AppendData(kData);
  this->InitializeReader(&b);
  int size_result = -1;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  scoped_refptr<net::IOBuffer> buffer = CreateBuffer(kDataSize);
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->SetReadRange(kDataSize + 1, kReadLength));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());

  // Case: length too long.
  BlobDataBuilder b2("uuid2");
  b2.AppendData(kData);
  this->InitializeReader(&b2);
  size_result = -1;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  buffer = CreateBuffer(kDataSize + 1);
  EXPECT_EQ(BlobReader::Status::NET_ERROR,
            reader_->SetReadRange(0, kDataSize + 1));
  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, reader_->net_error());
}

TEST_F(BlobReaderTest, HandleBeforeAsyncCancel) {
  const std::string kUuid("uuid1");
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  std::vector<FileCreationInfo> files;

  BlobDataBuilder b(kUuid);
  b.AppendFutureData(kDataSize);
  BlobStatus can_populate_status =
      BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
  blob_handle_ = context_.BuildBlob(
      b, base::Bind(&SaveBlobStatusAndFiles, &can_populate_status, &files));
  EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, can_populate_status);
  provider_ = new MockFileStreamReaderProvider();
  reader_.reset(new BlobReader(blob_handle_.get(), base::WrapUnique(provider_),
                               message_loop_.task_runner().get()));
  int size_result = -1;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_FALSE(reader_->IsInMemory());
  context_.CancelBuildingBlob(kUuid,
                              BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::ERR_FAILED, size_result);
}

TEST_F(BlobReaderTest, ReadFromIncompleteBlob) {
  const std::string kUuid("uuid1");
  const std::string kData("Hello!!!");
  const size_t kDataSize = 8ul;
  std::vector<FileCreationInfo> files;

  BlobDataBuilder b(kUuid);
  b.AppendFutureData(kDataSize);
  BlobStatus can_populate_status =
      BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
  blob_handle_ = context_.BuildBlob(
      b, base::Bind(&SaveBlobStatusAndFiles, &can_populate_status, &files));
  EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, can_populate_status);
  provider_ = new MockFileStreamReaderProvider();
  reader_.reset(new BlobReader(blob_handle_.get(), base::WrapUnique(provider_),
                               message_loop_.task_runner().get()));
  int size_result = -1;
  EXPECT_EQ(BlobReader::Status::IO_PENDING,
            reader_->CalculateSize(base::Bind(&SetValue<int>, &size_result)));
  EXPECT_FALSE(reader_->IsInMemory());
  b.PopulateFutureData(0, kData.data(), 0, kDataSize);
  context_.NotifyTransportComplete(kUuid);
  base::RunLoop().RunUntilIdle();
  CheckSizeCalculatedAsynchronously(kDataSize, size_result);
  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kDataSize));

  int bytes_read = 0;
  int async_bytes_read = 0;
  EXPECT_EQ(BlobReader::Status::DONE,
            reader_->Read(buffer.get(), kDataSize, &bytes_read,
                          base::Bind(&SetValue<int>, &async_bytes_read)));
  EXPECT_EQ(net::OK, reader_->net_error());
  EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
  EXPECT_EQ(0, async_bytes_read);
  EXPECT_EQ(kData, std::string(buffer->data(), kDataSize));
  EXPECT_EQ(net::OK, size_result);
}

}  // namespace storage

redpajama_set_name: RedPajamaGithub


Breathe deep, stand back and take in the view of a vibrant painting, each brush stroke thoughtfully placed. Look up at an awe-inspiring whale skeleton, suspended from the ceiling and filling up an entire room. Brush your hand across a soft and satisfyingly textured fabric, created by a master weaver.
Museums and art galleries are great places to admire beautiful, interesting and historic things, but research suggests they can also help people experiencing depression, chronic pain, anxiety and stress to reduce their symptoms, as part of a holistic treatment plan.
People who have been diagnosed with these conditions can benefit from therapies and medications, but healthcare providers are supplementing these conventional approaches by recommending social activities that involve getting out into the community, connecting with others, and engaging in light physical exercise. These activities can lead to an increase in serotonin (the "happy chemical"), which promotes feelings of well-being. After successful trials in the UK and Montreal, more doctors and social workers are adding visits to museums and art galleries to their patients' prescriptions.
While this particular project is currently restricted to the ROM, public library users can also access free passes to a range of cultural institutions across the GTA. So if you feel like a social visit would do you good, here are some museums and galleries worth the visit—no prescription required.


We loved the Transformers Choose Your Fate books as kids, and even wrote a text adventure in their style for an old version of Transformers At The Moon. Here you can find images from these puzzle-books, both UK and US versions.
Page Rendering Time: 0.6665 seconds.


text:
Marvel Madness in Florida
Jeanne found some info about Universal Studios, Florida's plans for the Marvel Universe on the USF website. It reads in part:
Spider-Man, the X-Men, The Incredible Hulk and other Marvel Comics Super Heroes will be permanent residents of Universal's Islands of Adventure®. These super champions and super villains, which remain the most popular comic book characters of all time, will achieve new heights of popularity as they are brought to life through the application of never-before-seen technologies incorporated into incomparable rides and spellbinding offerings.
Also, Florida's Universal Studio's is planning on a "CityWalk" for their site as well, although their version of it looks less like a mall and more like an entertainment center. They plan on having a "Marvel Mania" restaurant there. Here's what they say about it:
Marvel Mania -- A unique and thrilling new Marvel comic-book themed restaurant, Marvel Mania, brings to life a world-famous cast of comic book heroes and villains in a truly marvelous multi-media experience. Spider-Man, The X-Men, The Fantastic Four and others will leap out of the pages of the world's number one selling comic books to inspire a superhero menu and decor. Families will be transported into the fictional "Marvel Universe," populated by nearly 4,000 comic book characters.
4,000 characters, eh? Sounds like it might be pretty well packed?
Prev: Junk Food - Marvel Style
Next: Mighty Marvel Mailer
Item: Marvel Madness in Florida


The Boon Docs is a comic about practicing medicine in a small town. It's about raising chickens and having sheep instead of a lawnmower. It's about being nice to your neighbours (or else). But don't be fooled: it is not always simple or idyllic. There are hungry bears and peckish raccoons out there. Rumors get around faster than the ambulance, and the store often runs out of milk.


text:
Rhode Island joins 36 states in adding financial literacy education in schools
European private debt in 2018 and the year ahead
Thoma Bravo closes second Discover fund at $2.4 billion hard cap
A closed sign hanging in a shop window
Thoma Bravo announced on Thursday it closed its a lower-middle-market fund, Thoma Bravo Discover Fund II, at its hard cap of $2.4 billion, confirmed spokesman Matthew Gorton.
Like its predecessor, the fund will focus on middle-market investments in the software industry. It will be deployed using Thoma Bravo's "buy-and-build" investment strategy, according to a news release. Capital has not been deployed yet, Mr. Gorton said. The fund will target investments in application, infrastructure, and security software and technology-enabled services.
The prior fund, Thoma Bravo Discover Fund, closed in February at $1.07 billion, also reaching its hard cap.
"The Discover Fund has demonstrated that Thoma Bravo's approach of partnering with current management teams to implement our operating practices and metrics, investing in organic growth through product development and more effective distribution, and making accretive acquisitions is a model that works across size, stage and scale," said A.J. Rohde, a partner at Thoma Bravo, in the release.
Investors in the fund include the Florida State Board of Administration, which oversees the $167 billion Florida Retirement System, Tallahassee; $118.9 billion New York State Teachers' Retirement System, Albany; $72 billion Massachusetts Pension Reserves Investment Management Board, Boston; and the $16.1 billion Arkansas Teacher Retirement System, Little Rock.
Arkansas Teachers assigns $180 million to alternatives
New York State Teachers sets $1 billion in private equity commitments
Florida State Board of Administration allocates $1.75 billion


We are a tiny artisan microbrewery in Kensington that prides itself in handcrafting exquisite beers and ales using the finest ingredients, a lot of passion, and even more hard work.
All our beers are brewed personally by us on "Blue Billy the Rainmaker". Blue Billy is a sophisticated 100L three vessel, single tier pilot system that we engineered and built from scratch, piece-by-piece over several years in Phil's backyard. We take the quality of our beers very seriously and pride ourselves in being one of the very few independent bricks-and-mortar craft breweries in inner-city Melbourne.
Henry Street Brewhouse was set up in 2015. For years prior to this, Phil could be found brewing away in his backyard on Henry Street, rain or shine - or hail – with the family dog running laps around them and babies crying in the background. The operation got a bit out-of-control when it out-grew Phil's garage. When we started ordering grain by the half-tonne we knew we had a problem and decided it was time to start a professional brewery.


Bradford, Maine. Population for Bradford from the last gathering is 1186. You can view Bradford venues that host many Bradford ME events every year.
You can find a ton of properties for sale if you search the Bradford page on Zillow. Currently Bradford has an average listing price for homes for sale on the market of $196,780. More real estate facts about Bradford: The number of properties currently for sale in Bradford is 1,173. The median homes for sale listing price is $158,033. This is broken down with the number of three bedroom houses in Bradford consisting of 543 with an average listing price for these house of $187,065. Out of the 245 houses that are four bedroom the average listing price for Bradford is $226,483. Interest rates for Bradford are at historic lows as well.