text:
25iq
My views on the market, tech, and everything else
Featured Individuals & Topics
Business Lessons from Katrina Lake of Stitch Fix
November 25, 2017 ∞
Katrina Lake is the founder and CEO of Stitch Fix. The magnitude of what she accomplished in building this business is highly underappreciated: She took a clothing retailer public in November 2017. This is a remarkable accomplishment given the financial state of retail in the United States and the challenges facing Nordstrom, Macy's and others. Lake did so by finding sustainable competitive advantage using some of the most advanced technology in the retail industry.
Stich Fix investor and board member Bill Gurley has said this about what she has accomplished: "One of the unique things about Stitch Fix relative to all the unicorns in Silicon Valley is they've run a very disciplined and profitable approach. They've been profitable for several years. The reason that you never heard of them as a unicorn is that they never raised money over a billion because they didn't need to raise money."
Here are seven lessons to learn from her success.
"In business school, one of the areas that interested me was hunting and fishing. [But] I was not super passionate about the category. I can't imagine devoting my whole life to it."
Lake did not decide to create a biotech, blockchain, e-sports or enterprise security business because it would have been fashionable. She is passionate about fashion and retail.
Missionaries are far more likely to be successful business founders than mercenaries because their desire to solve a real customer problem enables them to persevere when things inevitably get tough. Mercenaries are motivated by money. Missionaries are driven by a cause.
It is a terrible idea to start a business because it is a hot sector or because people currently think it is glamorous.
"I would buy clothes at boutiques around Boston, then bring them to people's houses. I'd watch them try on the clothes, ask them questions, and have them fill out a survey, gathering as much data as I could."
Too many businesses fail to prove a value hypothesis before trying to prove a growth hypothesis. If you don't have a product that customers are willing to buy, nothing else matters. Spending cash on growth before product market or fit is discovered is a proven way to destroy shareholder value.
Lake cleverly used a classic viable product (MVP) approach to prove her value hypothesis. She intentionally did some things that she knew would not scale as part of this MVP. For example, she acquired inventory knowing that she could return products people did not buy but that would generate data that would allow her to raise funds to build her business.
"It was hard to raise money. We always treated every dollar very preciously and focused early on profitability. There are companies out there that may have failed because they had too much money and never had to think about the economics of their business."
Failure to understand the unit economics of a business is inevitably a fatal mistake. Every business has a cost to acquire a customer, a cost to serve a customer, a cost of goods sold, a revenue per customer and an opportunity cost of capital. Lake knows the only unforgivable sin in business is to run out of cash. For example, she lived through a period in which Stitch Fix had only eight weeks of cash remaining and lived to tell that tale.
Stitch Fix now has $120 million from the IPO. Criticizing the IPO for not resulting in a stock-price "pop," which benefits investment banks rather than shareholders, is rubbish. Improving the reputation of the investment bank for building future IPO order books represents zero justification for selling Stitch Fix shares at below market value.
"I'm not valuation-focused, so we weren't going to raise money if we didn't need it."
More businesses die from indigestion than starvation. Business that raise too much money often resolve problems with money that could be fixed with innovation and a stronger company culture. Too much money also tends to cause business to start off on the growth hypothesis far too early. People can lose discipline about expenses. Frugality is a part of a sound company culture.
"We collect information from you, what we know from inventory, what we know from other people, and all of that helps to inform the data and algorithm side, which generates recommendations for the stylists." "Fundamentally what we're offering is personalization. Our data can say, for example, this client has a 50% chance of keeping this denim."
Without some barrier to entry, the price of a product inevitably drops to a point where financial returns don't exceed the opportunity cost of capital. In other words, every business needs a moat, which limits supply to some extent, so they can generate a profit. Stitch Fix has had to find ways to thrive financially in a retail environment inhabited by businesses like Amazon. It is smartly focused on providing a differentiated personalized experience for its customers. Many people would be shocked by how many data scientists work at Stitch Fix and the sophistication of their technical stack.
"There's going to be a day when everything is amazing and another day when everything is terrible. It's an emotional roller coaster when you're the founder, especially in those early days."
It is thrilling to start a new business and even more thrilling if you eventually create a great financial success. But in between those two end points is a grueling period which inevitably involves struggle and gyrating emotional states. Entrepreneur, author and investor Scott Belsky (who wrote the forward my new book) has said that it is in the "messy middle" between founding a company and an event like an IPO that reputations get made via execution, optimization and endurance.
Venture capitalist Megan Quinn adds: "Katrina built an incredible business with grit and discipline. She shunned the Silicon Valley mantra of valuation at all costs in favor of sustainable unit economics and profitability. She is the real Valley success story — one founded in fundamentals and sincere dedication to solving a customer problem."
"I met more than 100 entrepreneurs and realized that all these entrepreneurs were just as unqualified as I was."
There is no magic formula for creating a successful business. Best practices do exist which you can learn on your own, in a job or in business school. But every successful business breaks at least one rule, which the root cause of innovation.
Lake has blazed a new trail in the retail industry by applying "money ball"-style analytics to retail fashion. Stitch Fix's use of machine learning and big data is unprecedented. Her story is inspirational.
http://www.mercurynews.com/2014/03/14/qa-stitch-fix-founder-katrina-lake-on-melding-fashion-and-technology/
https://www.axios.com/stitch-fix-files-for-ipo-2498638481.html
https://www.bloomberg.com/gadfly/articles/2017-10-20/stitch-fix-ipo-the-anti-uber-silicon-valley-startup
http://www.latimes.com/business/la-fi-himi-katrina-lake-stitch-fix-20170609-htmlstory.html
http://www.cosmopolitan.com/career/a59033/katrina-lake-stitch-fix-get-that-life/
https://www.recode.net/2017/11/17/16668888/stitch-fix-ipo-katrina-lake-women-tech-female-founders
https://www.recode.net/2016/10/31/13462112/stitch-fix-cto-cathy-polinsky-salesforce
https://architecht.io/stitch-fix-cto-talks-data-science-modern-architectures-and-moving-up-the-engineering-ladder-de4c8d7b5152
https://blog.stitchfix.com/inside-stitchfix/women-who-redefine-the-rules-cathy-polinsky/
https://www.infoq.com/podcasts/randy-shoup
https://www.cnbc.com/2017/11/17/bill-gurley-unicorns-need-to-grow-up.html
http://multithreaded.stitchfix.com/blog/2016/03/31/data-science-at-stitch-fix/
https://www.glassdoor.com/Interview/Stitch-Fix-Data-Scientist-Interview-Questions-EI_IE783817.0,10_KO11,25.htm
http://www.businesswire.com/news/home/20131017005317/en/Stitch-Fix-Raises-12-Million-Series-Funding
https://www.kdnuggets.com/2015/03/interview-brad-klingenberg-stitchfix-machine-learning.html
https://blog.stitchfix.com/inside-stitchfix/meet-lisa-bougie/
Business Lessons from Ben Thompson of Stratechery
Investing Lessons from the Dude. "Or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing."
Subscribe to 25IQ
Subscribe to receive notifications of new 25IQ posts by email.
@TrenGriffin on Twitter
My neighbor's dog stopped by to ask if value investing involves butts. He said his experience in that area is nothi… twitter.com/i/web/status/1… 19 hours ago
Follow @TrenGriffin
Peloton: The "SaaS Plus a Box" Business case
The Dot-Com Boom and Bust
Lessons from Chance the Rapper (Value Chains and Profit Pools)
A Dozen Lessons about Business, Investing and Money from Lil Wayne (Weezy)
25IQ RSS


text:
'What I'm watching' — Gm5 Vs. Dal: Canes continue measuring stick tour versus Dallas Stars
by Matt Karash | Jan 30, 2021 | Morning Skate
After a feel-good win after a COVID-induced layoff in the home opener against the defending Stanley Cup Champions on Thursday, the Canes continue to test against the best. Next up is a quick two-game set against the Dallas Stars. The Stars were the other Stanley Cup finalist only four months ago and are among the best teams in the NHL right now with a 4-0 start that includes a couple of lopsided wins courtesy of two seven-goal outbursts. The Stars feature a blue line that is among the best in the NHL, and somewhere along the way an offense that was struggling through much of the 2019-20 season found the ignition switch.
The season still has a long way to go obviously and the Hurricanes are still playing with less than a maximum lineup, but the game still represents a good early season benchmark for how the Canes stack up against other good teams.
My watch points for tonight's match up follow.
'What I'm watching' for the Carolina Hurricanes versus the Dallas Stars
1) Matching up top to bottom
One of the things that jumps out about the Stars is the team's depth. As noted above, the Stars' blue line is among the best in the NHL including both top pairing talent but also solid depth 1 through 6. The team also boasts enough offensive fire power to build a bona fide first scoring ling and power play unit but also depth through the forward ranks. One of the Achilles' heels of the past two Canes playoff teams is that the forward group has been a bit top-heavy offensively. With Vincent Trocheck off to a good start, there are indications that the Hurricanes might be on the way to finding more depth and balance scoring-wise. Against a team that has good players from top to bottom, I will be watching to see what the Hurricanes can generate across three if not four lines offensively.
2) Sebastian Aho and Andrei Svechnikov
The game will also be a good measure for how the Hurricanes best offensively (minus Teravainen) fare in a game where there are not really any favorable match ups to tilt the ice favorably. Winning in the playoffs against good teams requires a team's top scorers to be able to produce even when the match ups are tough. Aho and Svechnikov are both off to good starts. They also played well and had chances against the Lightning but did not crack the score sheet. This two-game set offers another chance to see what they can do against strong competition. In addition, I suggested recently that an interesting move to consider could be reuniting Aho and Svechnikov and moving Teravainen to another line hopefully to serve as a playmaker. With Teravainen out on Saturday, the game also represents another chance to assess how the duo looks minus Teravainen.
3) The auditions
It is reported that the Canes COVID crew was back on the ice Saturday for practice before the game group. They will not play Saturday but should be back soon. That makes Saturday an important game for players like Jake Bean and Steven Lorentz to stake a claim to additional NHL ice time even when the team has its full roster back. Steven Lorentz jumped straight into a middle six role on Jordan Staal's line. He did not light things up offensively a la March 2020 Morgan Geekie, but he was competent defensively and did not look out of place. Similarly, Jake Bean played a solid game on Thursday. Saturday represents a chance for these players to build trust and be considered for more ice time going forward.
4) The measuring stick
With groups of seven or eight teams quarantined within their own divisions, it is difficult to rank teams league-wide, but Dallas' fast star coming off their 2020 NHL Playoff run has to put them somewhere near the top. I will be watching to see how the Canes match up against one of the best right now.
The puck drops at 7pm on Fox Sports Carolinas (or did they change the name already?) with Tripp, Mike, Abby and Shane.

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Perl throws an error message about syntax So, building off a question about string matching (this thread), I am working on implementing that info in solution 3 into a working solution to the problem I am working on.
However, I am getting errors, specifically about this line of the below function:
next if @$args->{search_in} !~ /@$cur[1]/;

syntax error at ./db_index.pl line 16, near "next "

My question as a perl newbie is what am I doing wrong here?
sub search_for_key
{
    my ($args) = @_;

    foreach $row(@{$args->{search_ary}}){
        print "@$row[0] : @$row[1]\n";
    }

    my $thiskey = NULL;
    foreach $cur (@{$args->{search_ary}}){
        print "\n" . @$cur[1] . "\n"
        next if @$args->{search_in} !~ /@$cur[1]/;
        $thiskey = @$cur[0];
        last;
    }
    return $thiskey;
}

A: You left off the semicolon at the end of the previous line.  That's what caused the syntax error, anyway.  I think you're also misusing $args, but it's hard to be sure about that without knowing how you're calling this function.

A: There are several issues here.

*

*Are you adding use strict; and use warnings; at the top of your script before you do anything else? You only posted the sub, but it is clear that you are not using these.

*What is NULL? (strict will not let you use bare-words...) Be sure to read What is Truth in Perl? The more Perly way is to deal with "truth" or "false" is defined / undef or exists or specifically test for a value chosen as a convention.

*Missing ; after print "\n" . @$cur[1] . "\n"

*Your data structures seem way too complicated. From what I can tell, you are passing a reference to a hash of arrays, true? Why your data structures get really obscure, back up and look at what you are trying to do...

*Perl gives you plenty of way to shoot yourself in the foot. It is not strictly typed and you will do yourself (and your readers) a favor by naming references as a derivative of what they refer to. So instead of $args use $ref2HoArefs for example.

A: Side note, are you sure you can't just use a hash for what you're doing? It seems awfully complicated do do something so simple:
my %hash = (
     key1 => 'value1',
     key2 => 'value2',
);

exists $hash{$search_in};   # true/false.
my $result = $hash{$search_in}; # returns 'value1' when $search_in is 'key1'

Or if you need to search by value:
my %flip = reverse %hash;
$result = $flip{$search_in};

And if you really need a regex key ( or value ) lookup:
 sub string_match {
        my ($lookup_hash, $key ) = @_;
        for my $hash_key ( %{ $lookup_hash } ){
            return $hash_key if $key =~ $lookup_hash->{$hash_key};
        }
        return; # not found.
 }
 my $k = string_match({
           'whitespace at end' =>  qr/\s+$/,
           'whitespace at start' => qr/^\s+/,
 }, "Some Garbage string     ");  # k == whitespace at end

redpajama_set_name: RedPajamaStackExchange


text:
Home / About STU / Administration / Human Resources / Employment / Adjunct Faculty – History
Adjunct Faculty – History
St. Thomas University in Miami Gardens, FL, is seeking applications from qualified individuals to lecture undergraduate courses in History for our on-ground programs. The candidate must display evidence of teaching excellence, a commitment to undergraduate education, and ability to work with diverse populations.
St. Thomas University is a Catholic university with rich cultural and international diversity committed to the academic and professional success of its students who become ethical leaders in our global community. We are a designated Hispanic Serving Institution and the only Catholic Archdiocesan sponsored university in the State of Florida.
Minimum qualifications: Master's degree or higher in History, or closely related field. History areas of interest include Western Civilization, Modern American, African-American, Hispanic-American, Cuban-American, Caribbean, Women's, Urban, or Catholic history.
Application Process: For consideration, please send résumé and copies of post-secondary degree transcripts to
lfernandez-torres@stu.edu
MS Word or PDF attachments only.
St. Thomas University is an E-Verify® Equal Opportunity Employer.
All employees must pass a criminal background check prior to commencement of employment and official degree transcripts will be required upon hire.
Applicants must be legally authorized to work in the U.S.


Detective John Muller died as the result of cancer that he developed following his assignment to the search and recovery efforts at the World Trade Center site following the 9/11 Terrorist Attacks.
Detective Muller had served with the NYPD for 20 years. He was survived by his wife.


The streets of D.C. were filled with marchers on Saturday.
Marchers make their views known.
John Styer, Nancy Styer and Susan Belford at the march.
Alex Wigmore, Polly Bomstein, and Eleanor Bomstein.
There was also a March at Maplewood in Bethesda. These seniors supported the rally.
The youth came to Washington D.C. on Saturday, March 24, to express their rage and need for change. They spoke with passion and determination, focusing on thoughtful solutions to gun violence — changes they want to be immediately addressed by Congress. The teens delivered first-hand stories of bloodshed and heartbreak, tales of lost siblings, friends and classmates.
The students from Marjory Stoneman Douglas High School organized a rally of hundreds of thousands of people in Washington D.C. They encouraged their peers to register to vote in the 2018 mid-term elections and to work to bring about an adjustment in the attitudes of legislators. Their message was one of hope that stricter gun-control laws can end the two decades of shootings which have taken place across the US — in schools, concerts, movie theatres and on the streets. They are seeking to unseat elected officials who receive campaign contributions from the NRA. They want an end to student nightmares of a shooting taking place while she or he is in class. They do not want to arm teachers; instead they want a safe environment in which to learn and safety on the streets as students travel back and forth to school.
In New York City, Meghan Bonner, a Marjory Stoneman Douglas High School student, said "The adults failed us, and now 17 people are dead." These students are taking the matter into their own hands – and encouraging common sense gun laws. "We are not looking for band-aid solutions," said one teen.
David Hogg, survivor of the Marjory Stoneman Douglas High School shooting, made it clear that politicians in the pocket of the National Rifle Association wouldn't be around much longer. "To those politicians supported by the NRA and who allow the continued slaughter of our children and our future, I say: Get your resumes ready," Hogg said.


As the creeping destruction wrought by climate change escalates and political antagonism and public apathy deepen, finding the right story to catalyze change is more urgent than ever. Join ASU's Imagination and Climate Futures Initiative for a talk with New York Times-bestselling author Kim Stanley Robinson, "The Comedy of Coping: Alarm and Resolve in Climate Fiction" on Wednesday, September 20, 2017 at the Phoenix Art Museum at 7:00 pm. After the talk, Robinson will take questions from the audience and sign books. This event is open to the public and free.
In the talk, Robinson will trace the threads of story and science that he wove together to create his latest novel, New York 2140, a scientifically-grounded exploration of climate chaos, its long aftermath, and the enduring forces of culture and community. He will also argue that we need to renounce apocalyptic thinking, even when it feels most irresistible. What can stories do in the face of impending calamity? How can fiction authors balance their urges to unsettle and inspire? How can literature be part of an affirmative response to existential risk?
Parking: Free parking is available in the shared lot between the Phoenix Art Museum and the Phoenix Theater, with additional parking on surrounding side-streets.


text:
Since June 2003, Namaste Community Foundation-Nepal (Formerly: Namaste Children's House) has always been a place of opportunity and hope for the many poor, orphaned children and desperate people of Nepal. For my team and me, nothing could be more fulfilling than to see the happiness on our children's faces; to watch them grow, inquire and explore; to shuttle them off to school each day for a quality education; to witness the joy and wonder of their sweet smiling faces. Through the various projects that we run, it is incredible to see the difference that all of our joint efforts make in the lives of many underprivileged children, women, and people of Nepal.
At NCF-Nepal, we take responsibility for ourselves and for each other; for the ideas we embrace and for the future we share. We celebrate selflessness and value those across the world who step forward and make unprecedented contributions to the well-being of humanity in a very friendly, transparent, professional and mutual understanding way. The outpouring of kindness and generosity from various charities and people from Nepal and around the world reflects the spirit of compassion and reminds each of us of the profound impact we can have on many lives when we join together to achieve common goals.
As we mark this important milestone, my team and I from Nepal, look forward to continuing to work with existing networks and many new individuals in the years ahead in order to positively change the lives of many more children and people of Nepal. I'd especially like to thank all the NCF team, including the well-wishers from Nepal and abroad for your ongoing support and concern toward our work. You are also one who makes this NCF-Nepal a very successful organization.
Our dream is to grow to serve more people of Nepal, which is only possible with your involvement in the Namaste global family. Feel free to contact me through e-mail: [email protected]
Visma Raj Paudel
Founder and Executive Director
History of Visma Raj Paudel
Mr. Visma Raj Poudel (Founder/Director, NCF-Nepal)was born and raised till the age of 13, in Meghauli, near the beautiful Chitwan National Park. He was from the middle class family therefore he had everything that he needed for his childhood. It was not the case with his many friends who were living in the same and neighboring villages. Some of his friends were beaten in the school as they didn't have proper uniforms and stationary. This sort of incidents used to upset him quite frequently. Although he was small, he had realized and decided to do something in the future for these people once he grew up. When he was a child, one day while playing in the bank of the river near his house with his friends, he was swept away by the current of the river. His horrified friends were watching from the other side as he was tumbled over the rocks, and dragged beneath the water. Suddenly a stranger swam in and rescued him to the shore.
This experience has led him throughout his life to remember. He is here for a purpose, and always tries to make the kind of choices that could lead him in a direction to make a positive difference in other children's lives. After this near death experience, he changed from a child with little care in the world, to one who felt that he was here for a purpose. He would go out of his way to help those in his village who were less fortunate than him. He applied himself in a serious manner, at a young age, to his studies and soon began to excel.
It seems like fate was working in many aspects of his life before he was even aware of it, leading him on a path that would one day allow him to compassionately care for and protect children from very poor circumstances.
When he was 20 years old, Mr. Poudel was offered a chance to work for an organization here in Pokhara that was dedicated to the welfare of Nepalese children. Mr. Poudel spent his almost 8 years with the organization and the time with the organization changed his life forever, leaving him even more devoted to this work. He has been involved in various kind of projects like school construction, building a large school for 600 pupils, and working as the treasurer of a local road committee. He has helped to establish a children village for 75 children, worked as an adviser for different clubs as well as for local non-governmental organizations and carried out various other functions.
His dream continued to be working for as many children and people in Nepal as possible, and in the midst of this work, his dream began to come true when he established Namaste Children's House in 2003 (Current: Namaste Community Foundation).He and his team now works closely with the local communities, people, social organizations, government bodies, many individual foreigners, volunteers and charity aboard etc to run entire organization successfully. He is also the part of other organizations and clubs like:International Tal Barahi Lions Club-Pokhara-Nepal(Charter President), Network of Children's Home (Founder and past chairperson), and is also working as the advisory member of some social clubs and business firms etc.
Now he is gaining a lot of pleasure and found it an incredibly rewarding feeling to work for all these children besides his own family and businesses with his brother. It is his life dream to help more children and women in the future in very sustainable and effective way. However, this position of care also brings a huge burden of responsibility with it. Although financial worries often weigh heavily on him, the team Namaste and his work to manage the orphanage and other projects and ensure the safety of the children, women whose lives are already in their care.
Mr. Paudel is very thankful with the generosity and financial support of the people and various organizations throughout the World to run NCF-Nepal as successful project but is also expecting bigger global involvement and long term genuine partnership to serve his people, society and nation in bigger and sustainable way.
His main focus since the beginning of his social involvement is to run such development projects in a very transparent, professional, need base and cost effective way (with minimum cost). He strongly believes that local people's involvement and their empowerment should be the first priority in any development project to create future in-dependency and prosperity of each individual and any society. He loves to work on the basis of evidence and suggests people to carry out any work related to social development accordingly. He believes that any work conducted without any research only with an aim of fulfilling personal ego and hidden desire,would only damage the societies and leave negative impacts globally and paralyze the ultimate beneficiaries from their well-being.
If you want to contact Mr. Paudel to learn more about his work and future project then please write him on : [email protected] or private e-mail : [email protected]
Visma Raj Poudel


text:
Happyness - Write in | FESTIVALPHOTO
Happyness - Write in
London band Happyness released their debut EP just over three years ago, and followed that up later in 2014 with their debut album "Weird little birthdays". Now they're back with their second album, "Write in". They've not let the success of the first album go to their heads though and recorded this album on a shoestring budget.
It's an interesting album with a good mix of sounds showing their willingness to experiment. On "Uptrend/Style raids" for example, the slightly unusual vocal sound comes from using an old supermarket announcement microphone they found at a Paris flea market - not the first thing you'd imagine a band using but effective in giving the song a slightly different feel.
While they are still willing to take risks and experiment and definitely embrace a wide range of sounds, there's a more focussed feel to this album as well as a more positive feel.
Is it the sort of album I'd normally listen to? No it's not, but there's something about it that draws you in and makes you want to listen to it a bit more. It's not your typical album - it's far more interesting than that, and that can only be a good thing.
1. Falling down
2. The reel starts again (Man as Ostrich)
3. Anytime
4. Through windows
5. Uptrend/Style raids
6. Bigger glass less full
7. Victor Lazarro's heart
8. Anna, Lisa calls
9. The C is A B A G
10. Tunnel vision on your part
Skribent: Anthony May


text:
The NHS across North West London is today launching a new mum and baby app – a personal guide for pregnancy, birth and beyond.
The app was developed by mums, midwives and doctors in North West London and charity CW+ to provide women with a single source of trusted NHS information for all their maternity needs.
From the start of pregnancy to early parenthood, this app will support women and their families with:
Choice on where in North West London they would like to give birth and how they would like their birth to go
access to essential information every step of the way from being pregnant, to giving birth and looking after a new baby
personalised plans for their care during pregnancy, birth and beyond.
Leo Mead who lives in Ealing and is expecting her first baby in December said:
"I really like the app, the fact that all the information provided is from the NHS makes it feel very comforting. I never knew there was so much to know and this app helps to keep it all in one place. Being able to note my thoughts, questions and feelings also means it's easier to remember things I want to discuss when I have appointments with my midwife."
The app aims to improve women's experiences of maternity care and ensures that the information they receive is consistent no matter where they choose to give birth in the local area.
Professor Jacqueline Dunkley-Bent, Head of Maternity, Children and Young People for NHS England, said: "This new app shows what is possible when we embrace modern technology. It now also means that we are able to offer personal care to women and their families in North West London by ensuring they can access information quickly and easily which will help give women and clinicians their valuable time back'.
Baroness Julia Cumberlege, Chair of the National Maternity Review, 'Better Births', said:"The mum & baby app shows how we can harness digital technology to deliver innovation in the NHS. This maternity app supports women and families to understand their choices, especially around choosing their place of birth, which pregnant women have told us how important this is to them."
"The NHS in North West London have shown the potential of 'digital' to enhance services which deliver choice and personalisation to women, and empowers women to make shared decisions and manage their own care throughout their pregnancy, birth and beyond."
Doctor Sunita Sharma, Consultant Obstetrician from Chelsea and Westminster Hospital NHS Foundation Trust said: "The North West London mum and baby app represents an innovative way in which these local maternity services have come together to provide women and their families with consistent NHS information on how to look after themselves and their babies in an easily accessible format. I think this is great step forward for our maternity services."
This helpful new app is available for download on both Apple and Android just go to your app store and search 'mum and baby'.
As short video with details on the apps features can be found here.
If there is anything you are unsure about or you have a question that you haven't been able to ask your midwife, ask us!
Join us on Twitter on Thursday 15 November 2018, 7.30pm to 8.30pm for a chat, where we will have a midwife on hand to answer your burning questions. Just post your question on Twitter with #askthemidwifenwl, you can also find us @Healthiernwl.
For media enquiries please contact Ayesha Baker, Communications Manager at ayesha.baker@nhs.net or 0773 348 4891.
[ENDS]
Maternity care in North West London is provided through: Chelsea and Westminster, Hillingdon, Northwick Park, Queen Charlotte's and Chelsea, St Mary and West Middlesex hospitals. The app was developed in partnership with clinical staff from these hospitals, women who have used these maternity services and the North West London Collaboration of Clinical Commissioning Groups.
A previous version of the mum and baby app was originally created by the Doctor Sunita Sharma and the maternity team at Chelsea and Westminster Hospital NHS Foundation Trust, in partnership with their charity CW+ as a postnatal information tool. The app has now been expanded for use across North West London to now include information on maternity care, pregnancy, labour and birth. More information on CW+ and their work can be found here: https://www.cwplus.org.uk/
CCG Press Office
nwlccgs.media@nhs.net


text:
using System;
using XafDelta.Localization;

namespace XafDelta.Exceptions
{
    /// <summary>
    /// Invalid replication node id exception
    /// </summary>
    [Serializable]
    public class InvalidReplicationNodeIdException : ApplicationException
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InvalidReplicationNodeIdException"/> class.
        /// </summary>
        public InvalidReplicationNodeIdException()
            : base(string.Format(Localizer.NodeIdAllNodes, ReplicationNode.AllNodes))
        {

        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
Anna Maria Hong: Related Content
Hong to Judge Mount Holyoke Glascock Poetry Competition
Faculty member Anna Maria Hong will serve as a judge for the 96th annual Kathryn Irene Glascock '22 Intercollegiate Poetry Competition at Mount Holyoke College.
A Year in Books
A dystopian metropolis plagued by dragons. A disillusioned detective back on the beat. An exploration of what it means to be black, feminist, and female in America. A deep dive into the new science of psychedelics. Across millions of words and myriad perspectives, one constant is clear: 2018 was a big year for Bennington writers.
Entropy Magazine Selects Hong's Books as Best of 2018
Faculty member Anna Maria Hong's novella H&G and debut poetry collection Age of Glass have been selected for Entropy Magazine's 2018 "Best Fiction Books" and "Best Poetry Books & Poetry Collections" lists.
Age of Glass Garners Publishers Weekly Starred Review
Faculty member Anna Maria Hong's debut poetry collection Age of Glass, winner of the Cleveland State University Poetry Center's 2017 First Book Poetry Competition, has garnered a starred review from Publishers Weekly.
Opening Up Experimental Fiction
The Guardian highlighted faculty member Anna Maria Hong's H&G as leading the way for a new avant garde in literature.


It's that time of year again! The Family Homemade Regatta Race is Saturday, July 7 at 11 a.m. Try your shipbuilding skills out at the Hope Valley Farms Family Regatta.
We will have a hodgepodge of shipbuilding supplies for you and your family to sail across the pool, or come prepared with a homemade vessel and test the fierce deep water. Each team will race from one end of the pool and back. The ship must stay afloat with all of its crew members on board.
Saturday, July 7 from 11 a.m. - 12:30 p.m.
If you are interested in participating please contact Kelly Johnson or Molly McCabe.


NINA SIMON has been described as a "museum visionary" by Smithsonian Magazine for her audience-centered approach to design. She is the Executive Director of the Santa Cruz Museum of Art & History (MAH), where she led an institutional turnaround based on grassroots community participation. She has consulted with hundreds of international museums, parks, libraries, theaters, historic sites, art and cultural centers on issues of relevance and community participation. Nina began her career at the International Spy Museum in Washington, D.C. Her work has been shared in the Wall Street Journal, New York Times, NPR, and TEDx. She was named Santa Cruz County Woman of the Year in 2017 for her community leadership at the MAH. Nina lives off the grid in the Santa Cruz mountains with twenty people, twenty-three chickens, five dogs, and one zipline.


text:
Comic Con 2016: Saturday schedule
In this image released by CBS, Melissa Benoist appears in a scene from "Supergirl." The CW said Thursday, May 12, 2016, that it's picking up the series from CBS, where it debuted last year. (Darren Michaels/Warner Bros. Entertainment Inc. via AP)
Expect plenty of surprises on the third day of Comic-Con International as both Marvel Studios and Warner Bros. (producer of DC Comics movies) are holding court in Hall H. Neither studio announced what casts would be there, but it is a good bet you'll see the stars of upcoming films "Dr. Strange," "Guardians of the Galaxy Vol. 2," and "Suicide Squad."
What is a sure thing is the CW's slate of superhero shows with the stars of "Arrow," "The Flash," "Supergirl," and "Legends of Tomorrow" confirmed. Also, plenty of well-known people will be on hand including Kevin Smith, Will Forte, Lucy Lawless, James Cameron, Neil deGrasse Tyson, Bill Paxton, William Shatner and Sigourney Weaver.
Here are some highlights, with official descriptions courtesy of the folks at Comic-Con.
For the complete Saturday schedule, go here.
Comic-Con 2016 schedule
Comic-Con 2016: Thursday schedule
Comic-Con 2016: Friday schedule
Comic-Con 2016: Sunday schedule
Even after 75 plus years of stories, the family of Batman comics couldn't be any hotter! The DC Rebirth talent behind your favorite Dark Knight tales present an exclusive look at what's in store for the World's Greatest Detective! With Julie and Shawna Benson (Batgirl and the Birds of Prey), Tom King (Batman), Scott Snyder (All-Star Batman), James Tynion IV (Detective Comics), and others, this is the best time to explore Gotham City. Room 6DE, 11:15 a.m.-12:15 p.m.
Neil deGrasse Tyson: Creating Universes
Dr. Neil deGrasse Tyson (Cosmos, Star Talk) hosts an A-List panel of creators, including Len Wein (co-creator of Swamp Thing and Wolverine), who will discuss how universes are formed with the imagination and with science. Renowned artist Rob Prior (Game of Thrones, Star Wars) will provide a live painting exhibition during the panel. Horton Grand Theatre, 11:30 a.m.-12:30 p.m.
A sneak peek at upcoming releases. Hall H, 11:30 a.m.-1:30 p.m.
The Simpsons is heading into its 600th episode. Creator Matt Groening, executive producers Al Jean and Matt Selman, supervising director Mike B. Anderson, Oscar-nominated director of The Simpsons Movie David Silverman, and voice of Bart Simpson Nancy Cartwright offer some juicy tidbits on the 28th season and beyond! Ballroom 20, 12 p.m. - 12:45 p.m.
Sullivan Stapleton and Jaimie Alexander star in this one-hour action thriller from Berlanti Productions and Quinn's House, Inc. in association with Warner Bros. Television. Stapleton is hardened FBI agent Kurt Weller, who is drawn into a complex conspiracy when a mysterious woman, with no memories of her past, is found in Times Square, her body completely covered in intricate cryptic tattoos. As Weller and his teammates at the FBI-Edgar Reade (Rob Brown), Tasha Zapata (Audrey Esparza), and the tech-savvy Patterson (Ashley Johnson)-begin to investigate the veritable roadmap of Jane Doe's tattoos, they are drawn into a high-stakes underworld that twists and turns through a labyrinth of secrets and revelations-with the information exposing a larger conspiracy of crime, while bringing her closer to discovering the truth about her identity. See a special video presentation followed by a panel with series stars Sullivan Stapleton, Jaimie Alexander, Rob Brown, Audrey Esparza, Ashley Johnson, and writer/executive producer Martin Gero. Blindspot returns for its second season on NBC September 14 in a new time period, Wednesdays at 8/7c. Indigo Ballroom, Hilton San Diego Bayfront, 12 p.m.-12:50 p.m.
DC Comics publishers
DC's co-publishers are back in San Diego and better than ever! Jim Lee and Dan DiDio are the driving forces behind DC Rebirth, Vertigo, MAD, DC's Young Animal, and much more. This up-close-and-personal panel gives you unique access to the leaders of your favorite comic book line! Room 6DE,, 12:30 p.m.-1:30 p.m.
Marvel Animation
Join Marvel Animation for an eye-popping, toe-tapping, heart-stopping panel celebrating Marvel's acclaimed animated series Marvel's Ultimate Spider-Man vs. The Sinister Six, Marvel's Avengers: Ultron Revolution, and Marvel's Guardians of the Galaxy. Hosted by "Cantankerin" Cort Lane (SVP, animation and family entertainment),"Evil-Eyed" Eric Randomski (SVP, production and creative director, Marvel Animation), and "Stephen" Wacker (VP, current series & development, Marvel Animation), this jamboree will feature exclusive sneak peeks from upcoming episodes and scoop on exciting new projects in development. Plus: special guests who have already secretly RSVP'ed. Room 6A, 12:30 p.m.-1:30 p.m.
The cast ( Alex Borstein, Mike Henry) and executive producers (Rich Appel, Alec Sulkin, Steve Callaghan) present a special preview of next season's hilarity and hi-jinx from FOX's hit animated comedy. Ballroom 20, 1 p.m.-1:35 p.m.
Spotlight on Stan Lee
'Nuff said. Room 6A, 1:45 p.m.-2:45 p.m.
September 8, 2016 marks the 50th anniversary of Star Trek's first broadcast. What began as a TV show became a window into the future and a reflection of our greatest hopes and dreams. By envisioning a world where technology and science improve the human condition, and where peace and unity transcend conflict and separation, Star Trek has inspired children, parents, engineers, scientists, entrepreneurs, and viewers around the world. It's also spurred countless real-world innovations and "firsts," giving name to a Space Shuttle (the Enterprise), launching one of the first and most passionate worldwide fandoms, and featuring the first interracial kiss on American network television. Join William Shatner, Scott Bakula, Michael Dorn, Jeri Ryan, and Brent Spiner for a conversation moderated by Bryan Fuller, executive producer of the new Star Trek television series coming to CBS All Access, following its network premiere in 2017. Hall H, 2 p.m.-3 p.m.
Supervillains are continuing to push Gotham City toward the brink, and while Jim Gordon remains at the forefront of the fight against crime in this dangerously corrupt city, how far will he go to save Gotham? Throughout season 2, Gordon's moral compass wavered more than ever, creating both personal and professional dilemmas in his life as villains emerged from the city's darkest places, including Arkham Asylum's secret experimental lab, Indian Hill. Bruce Wayne also began to unravel some of Gotham City's, and his family's, deepest secrets, leading him to discover that Wayne Enterprises could be behind some very dangerous schemes poised to tear the city apart. Be among the first to see what's in store for season 3 with a special video presentation, followed by a discussion with series stars and producers. From Warner Bros. Television, Gotham returns September 19 with all-new episodes, Mondays at 8/7c on FOX. Indigo Ballroom, 2:10 p.m.-3 p.m.
Vice Principals, the new HBO comedy series starring Danny McBride and Walton Goggins, makes its Comic-Con debut. Moderated by The Nerdist Podcast's Matt Mira, with McBride, Goggins, and executive producer Jody Hill. Created by McBride and Hill, who also created HBO's Eastbound & Down, Vice Principals is a dark comedy series that tells the story of a high school and the two people who almost run it: the vice principals. McBride and Goggins star as the rival administrators who are in an epic power struggle, vying for the top spot: to be school principal. The half-hour show airs on Sundays at 10:30, beginning on July 17. Horton Grand Theatre, 2:30 p.m.-3:30 p.m.
Joe Quesada
Here is your chance for a Q&A with Marvel's chief creative officer Joe Quesada and a no-holds-barred panel on everything Marvel. Got a question about a favorite hero? Want to hear the latest developments on Marvel's Star Wars or Marvel NOW! titles? This panel has you covered! Featuring VP of international development C. B. Cebulski and director of content & character development Sana Amanat, along with Jason Aaron (Star Wars, Doctor Strange), Kieron Gillen (Darth Vader), and other Mighty Marvel guests. Room 6A, 3 p.m.-4p.m.
Aliens: 30th Anniversary
Writer/director James Cameron (Avatar) and producer Gale Anne Hurd (The Walking Dead) join cast members Sigourney Weaver (Avatar), Bill Paxton (True Lies), Lance Henriksen (Millennium), Michael Biehn (The Terminator), and Paul Reiser (Red Oaks) for a look back at the iconic science fiction classic in honor of the film's 30th anniversary. Hall H, 3:15 p.m.-4:15 p.m.
Supergirl will be returning for more supercharged adventures in the show's new home on The CW this fall! Wondering who's in that pod, or what will be bringing Superman to National City? Join the series' cast and creative team for a special video presentation, followed by a discussion of these season 2 hot topics and more! From Berlanti Productions in association with Warner Bros. Television, Supergirl's second season will premiere Mondays at 8/7c this fall on The CW. Ballroom 20, 3:30 p.m.-4:15 p.m.
Syfy's The Magicians
The acclaimed breakout hit makes its San Diego Comic-Con debut. The cast and executive producers tease the anticipated second season of the Syfy series based on author Lev Grossman's bestselling fantasy trilogy. Indigo Ballroom, Hilton San Diego Bayfront, 4 p.m.-5 p.m.
After saving the world-and all of time-from the immortal madman Vandal Savage, then bidding farewell to two of their fellow comrades, Hawkman and Hawkgirl, the Legends received an unexpected visit from a mysterious new ally, Rex Tyler, who gives the team a brand new mission. What that mission is, how the Justice Society of America will factor in, and who will be aboard the Waverider when The CW's Super Hero team-up series returns for its second season are questions that the cast and creative team will seek to answer when they descend on San Diego for their second visit to Comic-Con. From Berlanti Productions in association with Warner Bros. Television, DC's Legends of Tomorrow airs Thursdays at 8/7c on The CW. Ballroom 20, 4:15 p.m.-5p.m.
Parallel universes and doppelgangers and man-sharks, oh my! The second season of The CW's highest-rated series had more than its fair share of twists and turns, but none compared to Barry Allen's jaw-dropping decision to go back in time and save his mother from his arch-nemesis, Reverse-Flash, a decision that called the entire timeline into question. But fear not fans, you won't have to wait until the fall to start getting answers to some of your most pressing questions, as the cast and creative team behind the show will be giving fans insight into the show's highly anticipated third season. From Bonanza Productions Inc. in association with Berlanti Productions and Warner Bros. Television, The Flash airs Tuesdays at 8/7c on The CW. Ballroom 20, 5 p.m.-5:40 p.m.
Marvel Studios president and producer Kevin Feige and special guests provide an inside look at the ever expanding Marvel Cinematic Universe. Hall H, 5:30 p.m.-6:45 p.m.
In the face of worldwide nuclear destruction at the hands of the maniacal mystic known as Damien Darhk, Oliver Queen (a.k.a Green Arrow) united Star City with a message of hope that allowed him to vanquish the season 4 Big Bad once and for all. However, our heroes' triumph came at a cost, and the future of Team Arrow was left hanging in the balance. Now, as the show takes aim on season 5, Oliver will set out to save his city from a new threat-one that he personally created-as both the newly appointed mayor of Star City and as the Green Arrow. The cast and creators of the hit CW series will be on-hand for a lively conversation surrounding the upcoming season. From Bonanza Productions Inc. in association with Berlanti Productions and Warner Bros. Television, Arrow airs Wednesdays at 8/7c on The CW. Ballroom 20, 5:45 p.m.-6:30 p.m.
The stars from FOX's Emmy-nominated hit comedy The Last Man on Earth-Will Forte, Kristen Schaal, January Jones, Mel Rodriguez, Mary Steenburgen, and Cleopatra Coleman-discuss the evolution and surprising twist and turns from the first two shocking seasons as well as tease the upcoming third season. Moderated by Henry Goldblatt. Indigo Ballroom, Hilton San Diego Bayfront, 10:30 p.m.-11:30 p.m.
Starz's Ash vs. Evil Dead
Sam Raimi (executive producer), Rob Tapert (executive producer), Bruce Campbell (executive producer/Ash), Lucy Lawless (Ruby), Ray Santiago (Pablo), Dana DeLorenzo (Dana), Lee Majors (Brock Williams), and Ted Raimi (Chet Kaminski) discuss the hit series and preview what's to come in season 2. Room 6A, 6:45 p.m.-7:45 p.m.
What if you had a panel and the audience didn't show up? Kevin Smith can tell you what it's like: Last year, the clown prince of Comic-Con saw thousands of people abandon his annua Hall H talk for a once-in-a-lifetime outdoor Star Wars concert. But the plucky, portly director and podcaster is back to tell silly stories and talk about his new movie Yoga Hosers, his AMC Network shows Comic Book Men and Geeking Out, directing an episode of The Flash for The CW, his forthcoming Buckaroo Banzai adaptation, and the Mallrats sequel that's gonna be a TV series! You can't miss this perennial Hall H highlight (unless there's something way better going on at the same time, like a Star Wars concert). Hall H, 7 p.m.-8:30 p.m.
Darwyn Cooke Tribute
Celebrate the life and art of award-winning cartoonist Darwyn Cooke (The New Frontier, Parker) with moderator Jimmy Palmiotti and some of the biggest names in comics and animation, including Mike Allred, Scott Dunbier, Cully Hamner, Frank Tieri, and Bruce Timm. Room 25ABC, 8-9 p.m.


text:
package com.conveyal.r5.profile;

import com.conveyal.r5.analyst.fare.FareBounds;
import com.conveyal.r5.analyst.fare.InRoutingFareCalculator;
import com.conveyal.r5.api.util.LegMode;
import com.conveyal.r5.api.util.TransitModes;
import com.conveyal.r5.streets.StreetRouter;
import com.conveyal.r5.transit.RouteInfo;
import com.conveyal.r5.transit.TransitLayer;
import com.conveyal.r5.transit.TransportNetwork;
import com.conveyal.r5.transit.TripFlag;
import com.conveyal.r5.transit.TripPattern;
import com.conveyal.r5.transit.TripSchedule;
import gnu.trove.list.TIntList;
import gnu.trove.map.TIntIntMap;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import org.apache.commons.math3.random.MersenneTwister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.IntFunction;
import java.util.function.Supplier;

/**
 * A profile routing implementation which uses McRAPTOR to store bags of arrival times and paths per
 * vertex, so we can find suboptimal paths. We're not using range-RAPTOR here, yet, as the obvious implementation
 * produces some very strange paths for reasons I do not fully understand.
 *
 * @author mattwigway
 */
public class McRaptorSuboptimalPathProfileRouter {

    private static final Logger LOG = LoggerFactory.getLogger(McRaptorSuboptimalPathProfileRouter.class);

    public static final int BOARD_SLACK = 60;

    public static final int[] EMPTY_INT_ARRAY = new int[0];

    private final boolean DUMP_STOPS = false;

    /** Use a list for the iterations since we aren't sure how many there will be (we're using random sampling over the departure minutes) */
    public List<int[]> timesAtStopsEachIteration = new ArrayList<>();

    private TransportNetwork network;
    private ProfileRequest request;
    private Map<LegMode, TIntIntMap> accessTimes;
    private Map<LegMode, TIntIntMap> egressTimes = null;
    private InRoutingFareCalculator.Collater collapseParetoSurfaceToTime;

    private FrequencyRandomOffsets offsets;

    private TIntObjectMap<McRaptorStateBag> bestStates = new TIntObjectHashMap<>();

    private int round = 0;
    private int departureTime;

    private BitSet touchedStops;
    private BitSet touchedPatterns;
    private BitSet patternsNearDestination;
    private BitSet servicesActive;
    // Used in creating the McRaptorStateBag; the type of list supplied determines the domination rules. Receives the departure time as an argument.
    private IntFunction<DominatingList> listSupplier;
    private MersenneTwister mersenneTwister;

    /** In order to properly do target pruning we store the best times at each target _by access mode_, so car trips don't quash walk trips */
    private TObjectIntMap<LegMode> bestTimesAtTargetByAccessMode = new TObjectIntHashMap<>(4, 0.95f, Integer.MAX_VALUE);

    /** if saveFinalStates is true, contains the final states for every departure time */
    public TIntObjectMap<Collection<McRaptorState>> finalStatesByDepartureTime = null;

    public final boolean saveFinalStates;

    /** backwards compatibility */
    public McRaptorSuboptimalPathProfileRouter (TransportNetwork network, ProfileRequest req, Map<LegMode,
            TIntIntMap> accessTimes, Map<LegMode, TIntIntMap> egressTimes, IntFunction<DominatingList> listSupplier,
                                                InRoutingFareCalculator.Collater collapseParetoSurfaceToTime) {
        this(network, req, accessTimes, egressTimes, listSupplier, collapseParetoSurfaceToTime, false);
    }

    /**
     *
     * @param network
     * @param req
     * @param accessTimes
     * @param egressTimes
     * @param listSupplier
     * @param collapseParetoSurfaceToTime
     * @param saveFinalStates if true, save the best states by departure time in the field finalStatesByDepartureTime.
     *                        egressTimes must not be null in this case.
     */
    public McRaptorSuboptimalPathProfileRouter (TransportNetwork network, ProfileRequest req, Map<LegMode,
            TIntIntMap> accessTimes, Map<LegMode, TIntIntMap> egressTimes, IntFunction<DominatingList> listSupplier,
                                                InRoutingFareCalculator.Collater collapseParetoSurfaceToTime,
                                                boolean saveFinalStates) {
        this.network = network;
        this.request = req;
        this.accessTimes = accessTimes;
        this.egressTimes = egressTimes;
        this.listSupplier = listSupplier;
        this.collapseParetoSurfaceToTime = collapseParetoSurfaceToTime;
        this.touchedStops = new BitSet(network.transitLayer.getStopCount());
        this.touchedPatterns = new BitSet(network.transitLayer.tripPatterns.size());
        this.patternsNearDestination = new BitSet(network.transitLayer.tripPatterns.size());
        this.servicesActive = network.transitLayer.getActiveServicesForDate(req.date);
        this.offsets = new FrequencyRandomOffsets(network.transitLayer);
        this.saveFinalStates = saveFinalStates;
        if (saveFinalStates) this.finalStatesByDepartureTime = new TIntObjectHashMap<>();

        // To make results repeatable from one run to the next, seed with some characteristic of the request itself,
        // e.g. (int) (request.fromLat * 1e9).  Leaving out an argument will make it use a combination of time and
        // the instance's identity hash code, which makes it truly random for all practical purposes.
        this.mersenneTwister = new MersenneTwister((int) (request.fromLat * 1e9));
    }

    /** Get a McRAPTOR state bag for every departure minute */
    public Collection<McRaptorState> route () {

        // Modeify does its own pre-computation of accessTimes, but Analysis does not
        // TODO MWC - I think this can be removed now, I believe analysis now does pre-compute access times.
        if (accessTimes == null) computeAccessTimes();

        long startTime = System.currentTimeMillis();

        // Optimization for modeify (PointToPointQuery): find patterns near destination
        // on the final round of the search we only explore these patterns
        if (this.egressTimes != null) {
            this.egressTimes.values().forEach(times -> times.forEachKey(s -> {
                network.transitLayer.patternsForStop.get(s).forEach(p -> {
                    patternsNearDestination.set(p);
                    return true;
                });
                return true;
            }));

            LOG.info("{} patterns found near the destination", patternsNearDestination.cardinality());
        }

        List<McRaptorState> codominatingStatesToBeReturned = new ArrayList<>();

        // We start at end of time window and work backwards (which is what range-RAPTOR does, in case we
        // re-implement that here). We use a constrained random walk to choose which departure minutes to sample as we
        // work backward through the time window.  According to others (Owen and Jiang?), this is a good way to reduce
        // the number of samples without causing an issue with variance in results.  This value is the constraint
        // (upper limit) on the walk.
        // multiply by two because E[random] = 1/2 * max.
        if (request.monteCarloDraws == 200) {
            // 200 draws will take a really long time and is probably not what is desired. It is more likely the user simply
            // forgot to change the number of draws in the
            throw new IllegalArgumentException("Monte Carlo draws set to UI default, this is probably not what you want, exiting. " +
                    "Each draw in the fare-based router can be quite slow, so you probably want a smaller number. " +
                    "If you _really_ want 200 draws, maybe you'd be happy with 199 or 201, which will prevent " +
                    "this error?");
        }

        ArrayList<Integer> departureTimes = new ArrayList<>();

        while(departureTimes.size() != request.monteCarloDraws){
            departureTimes = generateDepartureTimesToSample(request);
        }

        for (int n = 0; n < departureTimes.size(); n++) {
            departureTime = departureTimes.get(n);

            // we're not using range-raptor so it's safe to change the schedule on each search
            offsets.randomize();

            bestStates.clear();
            touchedPatterns.clear();
            touchedStops.clear();
            // Round 0 is in essence non-transit access.
            round = 0;
            // final to allow use in the lambda function below
            final int finalDepartureTime = departureTime;

            // enqueue/relax access times, which are seconds of travel time (not clock time) by mode from the origin
            // to nearby stops
            accessTimes.forEach((mode, times) -> times.forEachEntry((stop, accessTime) -> {
                if (addState(stop, -1, -1, finalDepartureTime + accessTime, -1, -1, -1, null, mode))
                    touchedStops.set(stop);

                return true;
            }));

            markPatterns();

            round++;

            // NB the walk search is an initial round, so MAX_ROUNDS + 1
            while (doOneRound() && round < request.maxRides + 1);

            // TODO this means we wind up with some duplicated states.
            if (egressTimes != null) {
                // In a PointToPointQuery (for Modeify), egressTimes will already be computed
                Collection<McRaptorState> states = doPropagationToDestination(finalDepartureTime);
                codominatingStatesToBeReturned.addAll(states);
                if (saveFinalStates) finalStatesByDepartureTime.put(departureTime, states);
            }

            if (collapseParetoSurfaceToTime != null) {
                collateTravelTimes(departureTime);
            }

            LOG.info("minute {} / {}", n + 1, request.monteCarloDraws);
        }

        LOG.info("McRAPTOR took {}ms", System.currentTimeMillis() - startTime);

        // will be empty unless this is for a PointToPointQuery.
        return codominatingStatesToBeReturned;
    }

    /** compute access times based on the profile request. NB this does not do a search-per-mode */
    private void computeAccessTimes() {
        StreetRouter streetRouter = new StreetRouter(network.streetLayer);

        EnumSet<LegMode> modes = request.accessModes;
        LegMode mode;
        if (modes.contains(LegMode.CAR)) {
            streetRouter.streetMode = StreetMode.CAR;
            mode = LegMode.CAR;
        } else if (modes.contains(LegMode.BICYCLE)) {
            streetRouter.streetMode = StreetMode.BICYCLE;
            mode = LegMode.BICYCLE;
        } else {
            streetRouter.streetMode = StreetMode.WALK;
            mode = LegMode.WALK;
        }

        streetRouter.profileRequest = request;

        // TODO add time and distance limits to routing, not just weight.
        // TODO apply walk and bike speeds and maxBike time.
        streetRouter.distanceLimitMeters = TransitLayer.WALK_DISTANCE_LIMIT_METERS; // FIXME arbitrary, and account for bike or car access mode
        streetRouter.setOrigin(request.fromLat, request.fromLon);
        streetRouter.route();
        streetRouter.quantityToMinimize = StreetRouter.State.RoutingVariable.DURATION_SECONDS;
        accessTimes = new HashMap<>();
        accessTimes.put(mode, streetRouter.getReachedStops());
    }

    /** dump out all stop names, for debugging */
    public String dumpStops (TIntIntMap stops) {
        if (DUMP_STOPS) {
            StringBuilder sb = new StringBuilder();

            stops.forEachEntry((stop, time) -> {
                String stopName = network.transitLayer.stopNames.get(stop);
                sb.append(String.format("%s (%d) at %sm %ss\n", stopName, stop, time / 60, time % 60));
                return true;
            });

            return sb.toString();
        } else {
            return "";
        }
    }

    /** Perform a McRAPTOR search and extract paths */
    public Collection<PathWithTimes> getPaths () {
        Collection<McRaptorState> states = route();

        // A map to keep track of the best path among each group of paths using the same sequence of patterns.
        // We will often find multiple paths that board or transfer to the same patterns at different locations.
        // We only want to retain the best set of boarding, transfer, and alighting stops for a particular pattern sequence.
        // FIXME we are using a map here with unorthodox definitions of hashcode and equals to make them serve as map keys.
        // We should instead wrap PathWithTimes or copy the relevant fields into a PatternSequenceKey class.
        Map<PathWithTimes, PathWithTimes> paths = new HashMap<>();

        states.forEach(s -> {
            PathWithTimes pwt = new PathWithTimes(s, network, request, accessTimes.get(s.accessMode), egressTimes.get(s.egressMode));

            if (!paths.containsKey(pwt) || paths.get(pwt).stats.avg > pwt.stats.avg)
                paths.put(pwt, pwt);
        });
        //states.forEach(s -> LOG.info("{}", s.dump(network)));

        LOG.info("{} states led to {} paths", states.size(), paths.size());

        paths.values().forEach(p -> LOG.info("{}", p.dump(network)));

        return new ArrayList<>(paths.values());
    }

    /** perform one round of the McRAPTOR search. Returns true if anything changed */
    private boolean doOneRound () {
        // make a protective copy of bestStates so we're not reading from the same structure we're writing to
        // Otherwise the router can ride multiple transit vehicles in a single round, if it explores the pattern of the first
        // before the pattern of the second
        TIntObjectMap<Collection<McRaptorState>> bestStatesBeforeRound = new TIntObjectHashMap<>();
        TIntObjectMap<Collection<McRaptorState>> bestNonTransferStatesBeforeRound = new TIntObjectHashMap<>();
        bestStates.forEachEntry((stop, bag) -> {
            bestStatesBeforeRound.put(stop, new ArrayList<>(bag.getBestStates()));
            bestNonTransferStatesBeforeRound.put(stop, new ArrayList<>(bag.getNonTransferStates()));
            return true; // continue iteration
        });

        // optimization: on the last round, only explore patterns near the destination in a point to point search
        if (round == request.maxRides && egressTimes != null)
            touchedPatterns.and(patternsNearDestination);

        for (int patIdx = touchedPatterns.nextSetBit(0); patIdx >= 0; patIdx = touchedPatterns.nextSetBit(patIdx + 1)) {
            // All states that have been propagated
            List<McRaptorState> states = new ArrayList<>();

            // The board stop position in the pattern for each state (not the R5 or GTFS stop ID)
            TObjectIntMap<McRaptorState> boardStopPositionInPattern = new TObjectIntHashMap<>();

            // The board time, for frequency trips
            TObjectIntMap<McRaptorState> boardTimeForFrequencyTrips = new TObjectIntHashMap<>();

            // The trip index in the pattern (not GTFS Trip ID) that produced each state
            TObjectIntMap<McRaptorState> tripIndicesInPattern = new TObjectIntHashMap<>();

            TripPattern pattern = network.transitLayer.tripPatterns.get(patIdx);
            RouteInfo routeInfo = network.transitLayer.routes.get(pattern.routeIndex);
            TransitModes mode = TransitLayer.getTransitModes(routeInfo.route_type);
            // skips trip patterns with trips which don't run on wanted date
            if (!pattern.servicesActive.intersects(servicesActive) ||
                // skips pattern with Transit mode which isn't wanted by profileRequest
                !request.transitModes.contains(mode)) {
                continue;
            }

            // ride along the entire pattern, picking up states as we go
            for (int stopPositionInPattern = 0; stopPositionInPattern < pattern.stops.length; stopPositionInPattern++) {
                int stop = pattern.stops[stopPositionInPattern];
                // Skips stops that don't allow wheelchair users if this is wanted in request
                if (request.wheelchair) {
                    if (!network.transitLayer.stopsWheelchair.get(stop)) {
                        continue;
                    }
                }

                // Perform this check here so we don't needlessly loop over states at a stop that are only created by
                // getting off this pattern. This optimization may limit the usefulness of R5 for a strict Class B
                // (touch all stations) Subway Challenge attempt (http://www.gricer.com/anysrc/anysrc.html).
                boolean stopReachedViaDifferentPattern = bestStatesBeforeRound.containsKey(stop);

                // get off the bus, if we can
                for (McRaptorState state : states) {
                    int tripIndexInPattern = tripIndicesInPattern.get(state);
                    TripSchedule sched = pattern.tripSchedules.get(tripIndexInPattern);
                    int boardStopPosition = boardStopPositionInPattern.get(state);
                    int arrival, boardTime;

                    // we know we have no mixed schedule/frequency patterns, see check on boarding
                    if (sched.headwaySeconds != null) {
                        int travelTimeToStop = sched.arrivals[stopPositionInPattern] - sched.departures[boardStopPosition];
                        boardTime = boardTimeForFrequencyTrips.get(state);
                        arrival = boardTime + travelTimeToStop;
                    } else {
                        arrival = sched.arrivals[stopPositionInPattern];
                        boardTime = sched.departures[boardStopPosition];
                    }

                    if (addState(stop, boardStopPosition, stopPositionInPattern, arrival, boardTime, patIdx,
                            tripIndexInPattern, state))
                        touchedStops.set(stop);
                }

                // get on the bus, if we can
                if (stopReachedViaDifferentPattern) {
                    STATES: for (McRaptorState state : bestStatesBeforeRound.get(stop)) {
                        if (state.round != round - 1) continue; // don't continually reexplore states

                        // don't reexplore patterns.
                        // NB checking and preventing reboarding any pattern that's been boarded in a previous
                        // round doesn't save a significant amount of search time (anecdotally), and forbids some rare
                        // but possible optimal routes that use the same pattern twice (e.g. transfering in Singapore
                        // from Downtown Line westbound at Jalan Besar to Rochor; see also Line 1 in Naples, or LU
                        // Circle Line in the vicinity of Paddington).
                        // if (prevPattern == patIdx) continue;

                        if (pattern.hasFrequencies && pattern.hasSchedules) {
                            throw new IllegalStateException("McRAPTOR router does not support frequencies and schedules in the same trip pattern!");
                        }

                        // find a trip, if we can
                        int currentTrip = -1; // first increment lands at zero

                        if (pattern.hasSchedules) {
                            for (TripSchedule tripSchedule : pattern.tripSchedules) {
                                currentTrip++;
                                //Skips trips which don't run on wanted date
                                if (!servicesActive.get(tripSchedule.serviceCode) ||
                                    //Skip trips that can't be used with wheelchairs when wheelchair trip is requested
                                    (request.wheelchair && !tripSchedule.getFlag(TripFlag.WHEELCHAIR))) {
                                    continue;
                                }
                                // clock time for trip departing a stop
                                int departure = tripSchedule.departures[stopPositionInPattern];
                                if (departure > state.time + BOARD_SLACK) {
                                    // boarding is possible here
                                    states.add(state);
                                    tripIndicesInPattern.put(state, currentTrip);
                                    boardStopPositionInPattern.put(state, stopPositionInPattern);

                                    // we found the best trip we can board at this stop based on travel time (we know this because trips
                                    // are sorted by departure time from first stop), break loop regardless of whether
                                    // we decided to board it or continue on a trip coming from a previous stop.

                                    // NB there is an assumption here that a user will take the first vehicle that comes
                                    // on the desired pattern. It is possible to imagine a situation in which this is not
                                    // completely correct. If there are peak and off-peak fares, it may make sense to arrive
                                    // at a transfer point and allow a on-peak vehicle to pass in order to get on the next vehicle
                                    // which just so happens to arrive after peak. I do not doubt that someone, somewhere, does this.
                                    // There are reasons to do this at a transfer point. Suppose that there are peak and off-peak
                                    // fares for a rail system but not a connecting bus system (e.g., WMATA in DC). Suppose that the bus only
                                    // comes every hour. If you take the 8:30 AM (hourly) bus, you arrive at the rail station at 8:50 - still in peak time.
                                    // However, if you allow the 8:55 on-peak train to pass and take the off-peak 9:01, you stand to save some money.
                                    // You can't leave your house later, because the feeder bus isn't coming again until 9:30.
                                    // This isn't a problem for the almost certainly more common situation of people delaying
                                    // their trips to save money, as that should be accounted for by the time window (and if you
                                    // wanted to consider a trip that nominally departed at 8:30 but involved waiting to depart until 9:00
                                    // to get the best fare, you could achieve that through post-processing.
                                    break;
                                }
                            }
                        } else if (pattern.hasFrequencies) {
                            for (TripSchedule tripSchedule : pattern.tripSchedules) {
                                currentTrip++;
                                if (!servicesActive.get(tripSchedule.serviceCode) ||
                                    //Skip trips that can't be used with wheelchairs when wheelchair trip is requested
                                    (request.wheelchair && !tripSchedule.getFlag(TripFlag.WHEELCHAIR))) {
                                    continue;
                                }

                                int earliestPossibleBoardTime = state.time + BOARD_SLACK;

                                // find a departure on this trip
                                for (int frequencyEntry = 0; frequencyEntry < tripSchedule.startTimes.length; frequencyEntry++) {
                                    // we have to check all trips and frequency entries because, unlike
                                    // schedule-based trips, these are not sorted
                                    int departure = tripSchedule.startTimes[frequencyEntry] +
                                            offsets.getOffsetSeconds(tripSchedule, frequencyEntry) +
                                            tripSchedule.departures[stopPositionInPattern];

                                    int latestDeparture = tripSchedule.endTimes[frequencyEntry] +
                                            tripSchedule.departures[stopPositionInPattern];

                                    if (earliestPossibleBoardTime > latestDeparture) continue; // we're outside the time window

                                    while (departure < earliestPossibleBoardTime) departure += tripSchedule.headwaySeconds[frequencyEntry];

                                    // check again, because depending on the offset, the latest possible departure based
                                    // on end time may not actually occur
                                    if (departure > latestDeparture) continue;

                                    states.add(state);
                                    tripIndicesInPattern.put(state, currentTrip);
                                    boardTimeForFrequencyTrips.put(state, departure);
                                    boardStopPositionInPattern.put(state, stopPositionInPattern);
                                }
                            }
                        }
                    }
                }
            }
        }

        doTransfers();
        markPatterns();

        round++;

        return !touchedPatterns.isEmpty();
    }

    /** Perform transfers */
    private void doTransfers () {
        BitSet stopsTouchedByTransfer = new BitSet(network.transitLayer.getStopCount());
        double walkSpeedMillimetersPerSecond = request.walkSpeed * 1000;
        for (int stop = touchedStops.nextSetBit(0); stop >= 0; stop = touchedStops.nextSetBit(stop + 1)) {
            TIntList transfers = network.transitLayer.transfersForStop.get(stop);

            // okay to use bestStates directly here, it doesn't allow the router to ride two transit vehicles in one round.
            // because doTransfers only creates transfer states, it does not affect nonTransfer states.
            for (McRaptorState state : bestStates.get(stop).getNonTransferStates()) {
                for (int transfer = 0; transfer < transfers.size(); transfer += 2) {
                    int toStop = transfers.get(transfer);
                    int distanceMillimeters = transfers.get(transfer + 1);
                    int walkTimeSeconds = (int)(distanceMillimeters / walkSpeedMillimetersPerSecond);
                    if (addState(toStop, -1, -1, state.time + walkTimeSeconds, -1, -1, -1, state)) {
                        String to = network.transitLayer.stopNames.get(transfers.get(transfer));
                        //LOG.info("Transfer from {} to {} is optimal", from, to);

                        stopsTouchedByTransfer.set(toStop);
                    }
                }
            }
        }

        // copy all stops touched by transfers into the touched stops bitset.
        touchedStops.or(stopsTouchedByTransfer);
    }

    /** propagate states to the destination in a point-to-point search */
    private Collection<McRaptorState> doPropagationToDestination(int departureTime) {
        McRaptorStateBag bag = createStateBag(departureTime);

        egressTimes.forEach((mode, times) -> times.forEachEntry((stop, egressTime) -> {
            McRaptorStateBag bagAtStop = bestStates.get(stop);
            if (bagAtStop == null) return true;

            for (McRaptorState state : bagAtStop.getNonTransferStates()) {
                McRaptorState stateAtDest = new McRaptorState();
                stateAtDest.back = state;
                // walk to destination is transfer
                stateAtDest.pattern = -1;
                stateAtDest.trip = -1;
                stateAtDest.stop = -1;
                stateAtDest.accessMode = state.accessMode;
                stateAtDest.egressMode = mode;
                stateAtDest.time = state.time + egressTime;
                bag.add(stateAtDest);
            }

           return true;
        }));

        return bag.getBestStates();
    }

    private ArrayList<Integer> generateDepartureTimesToSample (ProfileRequest request) {
        // See Owen and Jiang 2016 (unfortunately no longer available online), add between f / 2 and
        // f + f / 2, where f is the mean step.
        int randomWalkStepMean = (request.toTime - request.fromTime) / request.monteCarloDraws;
        int randomWalkStepWidthOneSided = randomWalkStepMean / 2;

        ArrayList<Integer> departureTimes = new ArrayList<>();

        for (int departureTime = request.fromTime + mersenneTwister.nextInt(randomWalkStepMean);
             departureTime < request.toTime;
             departureTime += mersenneTwister.nextInt(randomWalkStepMean) + randomWalkStepWidthOneSided) {
            departureTimes.add(departureTime);
        }

        return departureTimes;

    }

    private void collateTravelTimes(int departureTime) {
        int[] timesAtStopsThisIteration = new int[network.transitLayer.getStopCount()];
        Arrays.fill(timesAtStopsThisIteration, FastRaptorWorker.UNREACHED);

        for (int stop = 0; stop < network.transitLayer.getStopCount(); stop++) {
            // find the best state at the stop
            McRaptorStateBag bag = bestStates.get(stop);

            if (bag == null) continue;
            int bestClockTimeGivenConstraint = collapseParetoSurfaceToTime.collate(bag.getNonTransferStates(),
                            departureTime + request.maxTripDurationMinutes * 60);
            if (bestClockTimeGivenConstraint < timesAtStopsThisIteration[stop]){
                timesAtStopsThisIteration[stop] = bestClockTimeGivenConstraint;
            }
        }

        for (int i = 0; i < timesAtStopsThisIteration.length; i++) {
            if (timesAtStopsThisIteration[i] != FastRaptorWorker.UNREACHED) timesAtStopsThisIteration[i] -= departureTime;
        }

        timesAtStopsEachIteration.add(timesAtStopsThisIteration);
    }

    public int[][] getBestTimes() {
        return timesAtStopsEachIteration.toArray(new int[timesAtStopsEachIteration.size()][]);
    }

    /** Mark patterns at touched stops, to be explored in a subsequent round */
    private void markPatterns () {
        this.touchedPatterns.clear();

        for (int stop = touchedStops.nextSetBit(0); stop >= 0; stop = touchedStops.nextSetBit(stop + 1)) {
            network.transitLayer.patternsForStop.get(stop).forEach(pat -> {
                this.touchedPatterns.set(pat);
                return true;
            });
        }

        this.touchedStops.clear();
    }

    private boolean addState (int stop, int boardStopPosition, int alightStopPosition, int time, int boardTime, int
            pattern, int trip, McRaptorState back) {
        return addState(stop, boardStopPosition, alightStopPosition, time, boardTime, pattern, trip, back, back
                .accessMode);
    }

        /** Add a state */
    private boolean addState (int stop, int boardStopPosition, int alightStopPosition, int time, int boardTime, int
            pattern, int trip, McRaptorState back, LegMode accessMode) {
        /**
         * local pruning, and cutting off of excessively long searches
         * NB need to have cutoff be relative to toTime because otherwise when we do range-RAPTOR we'll have left over states
         * that are past the cutoff.
         */
        // cut off excessively long searches
        if (time > request.toTime + request.maxTripDurationMinutes * 60) return false;

        // local pruning iff in suboptimal point-to-point (Modeify) mode
        if (request.maxFare < 0 && time - request.suboptimalMinutes * 60 > bestTimesAtTargetByAccessMode.get(accessMode)) {
            return false;
        }

        if (back != null && back.time > time)
            throw new IllegalStateException("Attempt to decrement time in state!");

        McRaptorState state = new McRaptorState();
        state.stop = stop;
        state.boardStopPosition = boardStopPosition;
        state.alightStopPosition = alightStopPosition;
        state.time = time;
        state.boardTime = boardTime;
        state.pattern = pattern;
        state.trip = trip;
        state.back = back;
        state.round = round;
        state.accessMode = accessMode;

        // sanity check (anecdotally, this has no noticeable effect on speed)
        if (boardStopPosition >= 0) {
            TripPattern patt = network.transitLayer.tripPatterns.get(pattern);
            int boardStop = patt.stops[boardStopPosition];

            if (boardStop != back.stop) {
                LOG.error("Board stop position does not match board stop!");
            }

            if (stop != patt.stops[alightStopPosition]) {
                LOG.error("Alight stop position does not match alight stop!");
            }
        }

        if (!bestStates.containsKey(stop)) bestStates.put(stop, createStateBag(departureTime));

        McRaptorStateBag bag = bestStates.get(stop);
        boolean optimal = bag.add(state);

        // target pruning: keep track of best time at destination
        if (egressTimes != null && optimal && pattern != -1) {
            // Save the worst egress time by any egress mode and use this for target pruning
            // we don't know what egress mode will be used when we do target pruning, above, so we just store the
            // best time for each access mode and the slowest egress mode
            int[] egressTimeWithSlowestEgressMode = new int[] { -1 };
            egressTimes.forEach((mode, times) -> {
                if (!times.containsKey(stop)) return;
                int timeAtDest = time + times.get(stop);
                egressTimeWithSlowestEgressMode[0] = Math.max(egressTimeWithSlowestEgressMode[0], timeAtDest);
            });

            if (egressTimeWithSlowestEgressMode[0] != -1 &&
                    egressTimeWithSlowestEgressMode[0] < bestTimesAtTargetByAccessMode.get(accessMode)) {
                bestTimesAtTargetByAccessMode.put(accessMode, egressTimeWithSlowestEgressMode[0]);
            }
        }

        return optimal;
    }

    /** Create a new McRaptorStateBag with properly-configured dominance */
    public McRaptorStateBag createStateBag (int departureTime) {
        return new McRaptorStateBag(() -> listSupplier.apply(departureTime));
    }

    /**
     * This is the McRAPTOR state, which stores a way to get to a stop in a round. It is an object,
     * so there is a certain level of indirection, but note that all of its members are primitives so the entire object
     * can be packed.
     */
    public static class McRaptorState {
        /** what is the previous state? */
        public McRaptorState back;

        /** What is the clock time of this state (seconds since midnight) */
        public int time;

        /** Board time of ride used to reach this stop */
        public int boardTime;

        /** On what pattern did we reach this stop (-1 indicates this is the result of a transfer) */
        public int pattern;

        /** What trip of that pattern did we arrive on */
        public int trip;

        /** the round on which this state was discovered */
        public int round;

        /** What stop are we at */
        public int stop;

        /**
         * What stop position are we at in the pattern?
         *
         * This is needed because the same stop can appear twice in a pattern, see #116.
         */
        public int boardStopPosition;

        /**
         * What stop position in this pattern did we board at?
         */
        public int alightStopPosition;

        /** The mode used to access transit at the start of the trip implied by this state */
        public LegMode accessMode;
        public LegMode egressMode;

        /**
         * The fare to get to this state. Ideally, this wouldn't be here, as it only applies to fare-based routing, not
         * other McRaptor DominatingLists, but this is the easiest place to put it so that it isn't being recalculated
         * all the time (which can be slow if there are table lookups involved).
         */
        public FareBounds fare;

        public String dump(TransportNetwork network) {
            StringBuilder sb = new StringBuilder();
            sb.append("BEGIN PATH DUMP (reverse chronological order, read up)\n");
            McRaptorState state = this;
            while (state != null) {
                String toStop = state.stop == -1 ? "destination" : network.transitLayer.stopNames.get(state.stop);

                if (state.pattern != -1) {
                    RouteInfo ri = network.transitLayer.routes.get(network.transitLayer.tripPatterns.get(state.pattern).routeIndex);
                    sb.append(String.format("%s %s to %s, p%st%s end at %d:%02d\n", ri.route_short_name, ri.route_long_name,
                            toStop, state.pattern, state.trip, state.time / 3600, state.time % 3600 / 60));
                }
                else {
                    sb.append(String.format("transfer via street to %s, end at %d:%02d\n", toStop, state.time / 3600, state.time % 3600 / 60));
                }

                state = state.back;
            }

            sb.append("END PATH DUMP");

            return sb.toString();
        }
    }

    /** A bag of states which maintains dominance, and also keeps transfer and non-transfer states separately. */
    public static class McRaptorStateBag {
        /** best states at stops */
        private DominatingList best;

        /** best states for which the preceding step was not a transfer via the street network. States in this list
         * could be reached by multiple transfers farther back in the itinerary, but we need a separate list for
         * stops reached by a direct egress from a transit vehicle without intervening walking along the street
         * network.  This is to avoid circumventing the egress walk limit. */
        private DominatingList nonTransfer;

        public McRaptorStateBag(Supplier<DominatingList> factory) {
            this.best = factory.get();
            this.nonTransfer = factory.get();
        }

        /** try adding state to the best DominatingList, and to the nonTransfer dominating list if the last step in
         * this state was not a transfer */
        public boolean add (McRaptorState state) {
            boolean ret = best.add(state);

            // state.pattern == -1 implies this is a transfer
            if (state.pattern != -1) {
                if (nonTransfer.add(state)) ret = true;
            }

            return ret;
        }

        public Collection<McRaptorState> getBestStates () {
            return best.getNonDominatedStates();
        }

        public Collection<McRaptorState> getNonTransferStates () {
            return nonTransfer.getNonDominatedStates();
        }
    }
}