text:
How to Travel to Munich, Germany From Barcelona, Spain
Can I Take a Bus From Barcelona to Marseille?
Cheapest Ways to Travel by Plane or Train From Budapest to Madrid, Spain
by Michael Roennevig
How Long Does it Take to Travel From Northern to Southern Italy?
How to Travel to Spain by Boat
How to Travel From Saigon to Cambodia
Traveling From Paris to Ireland
Hungary is not quite at the beating heart of Europe, so traveling between Budapest, its capital city, and Madrid isn't as simple as setting off from some of the continent's more visited destinations such as London or Berlin. Nevertheless, with a little shopping around, you should be able to find a reasonably priced flight or rail journey between the two cities.
Flight Broker
Check out flight broker services such as Skyscanner (skyscanner.net), Expedia U.K. (expedia.co.uk) and Momondo.co.uk. These sites will show you flights between Budapest and Madrid from major airlines. The services shown will typically involve at least one stopover, as few major carriers offer direct services between the two cities. Take a look at as many broker services as possible to help you find the best deals.
Rail Brokers
You can't book international rail travel through the website of MAV, Hungary's state train operator. Nor can you book travel between Budapest and Madrid through the websites of Europe's main train operators' umbrella groups Rail Europe (raileurope.com) and Deutsche Bahn (bahn.com). You can however get quotes for your journey from the latter two organizations by calling 1-800-622-8600 and +49-1805-996633, respectively.
Budget Carriers
Visit European budget carriers' websites that offer services between Budapest and Madrid. These typically don't show up in flight broker searches. Try Ryanair (ryanair.com), WizzAir (wizzair.com) and Brussels Airlines (brusselsairlines.com). Charges such as card processing fees and baggage costs could be added to the price of your flight when you check out. Run through the booking process on these sites to see how these fees will affect the overall price.
You can't book direct travel between Budapest and Madrid using Eurail's website, but can pick up a multicountry Global Pass that allows rail travel across 24 European countries, including Hungary and Spain, and all the countries you'll need to pass through to reach your final destination. This will be a great option if you want to see some other European countries en route, but could be a little pricier than a single rail journey or flight.
MAV: English Homepage
DB Bahn: Help and Services
Rail Europe: Contact Us
Ryanair: Budapest
WizzAir: Budapest
Brussels Airlines: Budapest
Eurail: Global Pass
Michael Roennevig has been a journalist since 2003. He has written on politics, the arts, travel and society for publications such as "The Big Issue" and "Which?" Roennevig holds a Bachelor of Arts in journalism from the Surrey Institute and a postgraduate diploma from the National Council for the Training of Journalists at City College, Brighton.
Ways to Travel From Rome to Venice
How Long Is the Flight to Ireland From the U.S.?
Travel Time Between Vienna & Venice
How to Travel From Madrid to Nice, France


text:
Stories of Hope for Rescued Pets Amidst the Tales of Devastation Caused by Recent Hurricanes
September 22, 2017 by Connie Newcomb
Hurricane season has wreaked havoc on several regions in the past month. There was Hurricane Harvey in Texas, Hurricane Irma in Florida, and now Hurricane Maria in Puerto Rico and the Bahamas. These natural disasters have killed dozens of people, destroyed thousands of homes and caused widespread flooding. And the tales of devastation and suffering have affected both humans as well as our beloved animals.
While much of the recent news has been tragic and downright depressing, there are also stories that help shine a little sunlight on the ongoing events. Here are a few of those that specifically spoke to the plight of our furry friends.
11 Hurricane Harvey Animal Rescues to Remind You That, Yes, Someone Went Back for the Cat
Sept. 1 | nymag.com
Heartwarming photos of both dogs and cats rescued in the aftermath of Hurricane Irma in Texas.
Miranda Lambert rescues trucks full of dogs displaced by Hurricane Harvey
Sept. 1 | nydailynews.com
In the wake of Hurricane Harvey, country singer Miranda Lambert' MuttNation Foundation helped bring over 70 puppies to safety. According to a Facebook post, they "went to Houston to rescue and relocate existing shelter animals in order to make room for the animals that were separated from their owners due to Harvey. This would allow animals to be reunited with their owners much quicker, while also giving the existing shelter animals a better chance for fostering or adoption."
Charleston Animal Society takes in 126 animals from Florida after Hurricane Irma
Sept. 15 | postandcourier.com
The Charleston Animal Society took in 126 animals from a Florida shelter Thursday night as part of ongoing Hurricane Irma relief efforts. In all, 54 cats and 72 dogs arrived at the North Charleston shelter from the Alachua County Humane Society in Gainesville, said Joe Elmore, the Animal Society's CEO. The Alachua County Humane Society is acting as a hub, taking in animals from Florida, Elmore said. From there, the animals come to Charleston, where they are kept before being turned over to rescue groups from North Carolina and Virginia.
Warriors and Heat help with Hurricane Irma animal rescue efforts
Sept. 16 | goldenstateofmind.com
More than a hundred shelter animals were shipped from Miami to Oakland on Friday with the hopes of finding new homes in the Bay Area. Assisted by Fed-Ex, these animals were moved to make room for more to be rescued in the wake of Hurricane Irma, which devastated Florida and surrounding states last weekend after causing catastrophic damage to islands in the Caribbean before that. Members of the NBA's Miami Heat and Golden State Warriors assisted in the efforts.
Dr. Jefferson on Hurricane Harvey Relief Efforts
Sept. 21 | austinpetsalive.org
Dr. Ellen Jefferson, Executive Director of Austin Pets Alive! recounts the efforts to relocate animals in local shelters to make space for new arrivals. Unfortunately, many shelters traditionally euthanize animals if they can't evacuate them in order to prevent further suffering when a shelter is demolished by a catastrophic event like Hurricane Harvey. APA took in more than 2000 pets in the two weeks following the initial impact. They set up an email helpline, used Google mapping and used an app called Zello to aid rescue effort in targeting stranded animals by boat. With the help of numerous volunteers and organizations like Best Friends Animal Society, they were able to set up temporary housing facilities outside the affected areas. " A huge number of shelter and owner-surrendered pets that came to APA! found new homes via transport to partner No Kill shelters across the country who were eager to help us with this huge influx of pets in need. Of those not transported to different locations, hundreds went to foster and hundreds more got adopted (around 700 dogs and nearly 600 cats!)."
Dogs, cats rescued during Hurricane Harvey brought to St Louis
Sept. 21 | fox2now.com
Humane Society teams from St. Louis and Atlanta joined forces to rescue more than 60 dogs and 20 cats from damaged by Hurricane Harvey. Since the end of August, 215 dogs and cats had been received by the Humane Society of Missouri.
Virginia Animal Rescuer Charters Last Minute Plane to Save 300 Caribbean Pets from Hurricane Maria
Sept. 22 | people.com
A Virginia Beach, Virginia, animal lover named Sali Gear, created a special rescue campaign or the dogs in the U.S. Virgin Islands caught in the aftermath of Hurricane Irma. What started out as a plan to fly groups of 20 animals at a time to the continental U.S. every day for a week morphed into a much larger venture. As Hurricane Maria appeared imminent, the need to get those animals out in a hurry became evident an a plan was chartered to get all 300 of the targeted animals out at once. After chartering a
Then Hurricane Maria appeared. As the second hurricane loomed closer to the Caribbean islands, Gear knew she needed to act fast. Instead of trying to save the pets piecemeal, Gear decided to charter a plane immediately and get all 300 of the animals she planned on rescuing, which included numerous dogs and several cats, out at once.
Katrina's Aftermath and the Pets Evacuation and Transportation Standards Act
It's been more than a decade since Hurricane Katrina devastated the Gulf Coast areas. According to The Washington Post's Karin Brulliard, "One 2006 poll found 44 percent of people who chose not to evacuate during Katrina did so because they did not want to abandon their pets." [source]
In that hurricane's aftermath,, the welfare of abandoned pets and other animals gained national attention. In response to public outcry as well as the efforts of organizations like the Humane Society and the American Society for the Prevention of Cruelty to Animals , the Pets Evacuation and Transportation Standards Act was enacted by Congress. It requires that response plans "account for the needs of individuals with household pets and service animals before, during and following a major disaster or emergency." See also https://www.congress.gov/109/plaws/publ308/PLAW-109publ308.pdf
◀Clear The Shelters - Adoption Fees Waived on Saturday
Dressing up our Pets at Halloween▶
Filed Under: Blog Tagged With: hurricanes, rescued pets

redpajama_set_name: RedPajamaCommonCrawl


text:
/**
 * \file TransistorFunction.h
 */

#ifndef ATK_PREAMPLIFIER_TRANSISTORFUNCTION_H
#define ATK_PREAMPLIFIER_TRANSISTORFUNCTION_H

namespace ATK
{
  template <typename DataType_>
  class TransistorFunction
  {
  protected:
    const DataType_ Is;
    const DataType_ Br;
    const DataType_ Bf;

  public:
    const DataType_ Vt;

    DataType_ Lb(const std::pair<DataType_, DataType_>& exp)
    {
      return Is * ((exp.first - 1) / Bf + (exp.second - 1) / Br);
    }

    DataType_ Lb_Vbe(const std::pair<DataType_, DataType_>& exp)
    {
      return Is / Vt * (exp.first / Bf);
    }

    DataType_ Lb_Vbc(const std::pair<DataType_, DataType_>& exp)
    {
      return Is / Vt * (exp.second / Br);
    }

    DataType_ Lc(const std::pair<DataType_, DataType_>& exp)
    {
      return Is * ((exp.first - exp.second) - (exp.second - 1) / Br);
    }

    DataType_ Lc_Vbe(const std::pair<DataType_, DataType_>& exp)
    {
      return Is / Vt * (exp.first);
    }

    DataType_ Lc_Vbc(const std::pair<DataType_, DataType_>& exp)
    {
      return -Is / Vt * (exp.second + exp.second / Br);
    }

    TransistorFunction(DataType_ Is, DataType_ Vt, DataType_ Br, DataType_ Bf)
      :Is(Is), Br(Br), Bf(Bf), Vt(Vt)
    {
    }

    /// Build a new transistor function for a filter
    static TransistorFunction build_standard_function(DataType_ Is=1e-12, DataType_ Vt=26e-3, DataType_ Br=1, DataType_ Bf=100)
    {
      return TransistorFunction(Is, Vt, Br, Bf);
    }
  };
}

#endif

redpajama_set_name: RedPajamaGithub


text:
The best blonde jokes
Three blondes are sitting by the side of a river holding fishing poles with the lines in the water. A Game Warden comes up behind them, taps them on the shoulder and says, "Excuse me, ladies, I'd like to see your fishing licenses." "We don't have any," replied the first blonde. "Well, if you're going to fish, you need fishing licenses," said the Game Warden. "But officer," replied the second blonde, "we aren't fishing. We all have magnets at the end of our lines and we're collecting debris off the bottom of the river." The Game Warden lifted up all the lines and, sure enough, there were horseshoe magnets tied on the end of each line. "Well, I know of no law against it," said the Game Warden. "Take all the debris you want." And with that, he left. As soon as the Game Warden was out of sight, the three blondes started laughing hysterically. "What a dumb Fish Cop," the second blonde said to the other two. "Doesn't he know that there are steelhead trout in this river?"
Joke has 74.20 % from 46 votes. More jokes about: blonde, cop, fish
A trucker stops at a red light and a blonde catches up to him. She knocks on the window and says, "Hi, my name is Heather and you are losing some of your load." The trucker just ignores her, the light changes, and he proceeds down the street. At the next light, the blonde again catches up and says, "Hi, my name is Heather, and you are losing some of your load." He ignores her again and continues down the street. At the next red light the blonde catches up, all out of breath, knocks on the window and says, "Hi, my name is Heather and you are losing some of your load." The trucker looks at her and finally, he says, "Hi, my name is Kevin, it's snowing, and I'm driving a salt truck."
Joke has 74.17 % from 65 votes. More jokes about: blonde, communication, driving, winter, work
The Sheriff in a small town walks out in the street and sees a blond cowboy coming down the walk with nothing on but his cowboy hat, gun, and his boots, so he arrests him for indecent exposure. As he is locking him up, he asks "Why in the world are you dressed like this?" The Cowboy says, "Well it's like this Sheriff… I was in the bar down the road and this pretty little red head asks me to go out to her motorhome with her. So I did. We go inside and she pulls off her top and asks me to pull off my shirt . so I did. Then she pulls off her skirt and asks me to pull off my pants…so I did. Then she pulls off her panties and asks me to pull off my shorts… so I did. Then she gets on the bed and looks at me kind of sexy and says, 'Now go to town, cowboy..' and here I am." Son of a Gun, Blond men do exist.
Joke has 74.15 % from 41 votes. More jokes about: blonde, cowboy
A brunette doing laundry asked her blonde friend to help her find a match for her sock. The blonde replied, "What for? Are you going to set it on fire!"
Joke has 74.14 % from 36 votes. More jokes about: blonde, communication, friendship, stupid
A redhead, a blonde and a brunette were stuck on an island and had to get back home from the island. The redhead swims half way and drowns. The brunette swims half way and drowns too. The blonde swims halfway gets tired and swims back.
Joke has 74.14 % from 36 votes. More jokes about: blonde, desert island, redneck, sport, stupid
My blonde girlfriend went to the doctors this morning and was told she had two weeks to live. She chose last week and this week.
Joke has 74.14 % from 36 votes. More jokes about: blonde, death, life, stupid, time
blonde asked someone what time it was, and the person told her it was 3:45. The blonde, with a puzzled look on her face replied, "You know, it's the weirdest thing, I have been asking that question all day, and each time I get a different answer."
Joke has 73.93 % from 55 votes. More jokes about: blonde, time
Q. Why does it take longer to build a blonde snowman? A. Cause you have to hollow out it's head!
Joke has 73.90 % from 96 votes. More jokes about: blonde
Two blond girls are discussing: "Yesterday during the blackout I got stuck in the elevator for three whole hours!" "Tell me about it! I got stuck too in the escalators."
A blonde who got a fishing rod for her birthday decided to go ice fishing to make good use of her gift. Early the next morning, she got all her gear together and headed out to the ice. When she reached her final destination, she cut a large hole in the ice and dipped the rod in. Then suddenly she heard a voice that said: "There are no fish in there". So she moves to another spot and cuts another hole, but then the same voice spoke again and told her there were no fish in there. So she moves again, and the voice tells her there are no fish in there. So she looks up and sees an irritated man staring down at her. "How do you know there are no fish there?" asks the blonde. So the man cooly says "Well first of all, this is a hockey rink, and second of all, you're going to have to pay for those holes."
Joke has 73.48 % from 54 votes. More jokes about: blonde, fish, sport
And get new jokes every day.


Configure your Universal Transceiver to work with nearly every vendor.
Growing database of supported vendor devices: Nearly 200 vendors are currently supported.
Save up to 10% - if you configure the transceivers yourself.
Check for potential problems in your fiber link … with no other optics than you use in the field.
Power Meter: Measure receive level.
DWDM tuner for everyone: Configure channels for tunable transceivers like XFP DWDM, SFP+ DWDM.
In combination with our microOTDR SFP you can measure the total length of attached fiber.
Why would we give you a FLEXBOX for free? What's the catch?
A) The FLEXBOX only works with UNIVERSAL FLEXOPTIX transceivers. To get your FLEXBOX for free, you need to add at least one transceiver to your shopping cart.
B) Once you discover the possibilities our FLEXBOX offers for transceiver deployments, you'll never want to miss it again.
Latest 2 weeks after you receive your free FLEXBOX, you will provide feedback (preferably to order@flexoptix.net).
If we do not receive feedback, we will charge you the normal price of the FLEXBOX as listed above.
Any questions left unanswered? Just contact us!
1By participating in the FREE FLEXBOX campaign and checking "I accept the conditions", you accept the following terms.
2FLEXOPTIX may or may not accept your request for participation in FREE FLEXBOX campaign.
You will send feedback in the form of text and optionally a photograph to order@flexoptix.net within two weeks after receiving the FLEXBOX. This feedback will be published on www.flexoptix.net. There is no right to publication. If you object to future publication, FLEXOPTIX reserves the right to reclaim the FLEXBOX or invoice the customer for it with the then current retail price.
4The campaign is limited to one FREE FLEXBOX per company or organization.
6You, respectively the customer, gives FLEXOPTIX the right to use your feedback text and photograph ("data" hereafter) indefinitely and worldwide for online publications. You, respectively the customer has to provide this unencumbered with third-party rights and guarantee FLEXOPTIX that you are the exclusive owner of all provided data or you are otherwise entitled (e.g. by written consent of the copyright holder) to publish the content on the website of FLEXOPTIX and to provide the usage and exploitation rights.
7You, respectively the customer, indemnifies FLEXOPTIX against all claims by third parties concerning possible infringements of exclusion or usage rights (particularly in regard to trademarks, tags, copyrights, personal rights and other rights) which result from the usage of data provided according to these regulations. The parties shall notify each other without undue delay if any claims are raised against either party.


text:
package com.kurtlaschinger.speedar.viewobj;

import com.kurtlaschinger.speedar.util.Vector3D;

/**
 * Interface for allowing ViewObj's to interact with phone movement.
 *
 * When using this interface, make sure to add it to the ViewObj
 */

public interface ScreenListener {

    /**
     * Called when the ViewObj leaves the phone screen
     */
    void onLeaveScreen();

    /**
     * Called when the ViewObj enters the phone screen
     */
    void onEnterScreen();

    /**
     * Called whenever the phone moves.
     *
     * @param newPos - Vector for the difference in between the last position and the new position.
     * @param timeDelta - Time difference between calls in milliseconds.  You can use this to determine a velocity
     *                  or other features.
     */
    void onMovePhone(Vector3D newPos, long timeDelta);

    /**
     * Called whenever the phone is rotated.
     *
     * @param pastRot - The past rotation of the phone.
     * @param newRot - The new rotation of the phone.
     * @param timeDelta - Time difference between calls in milliseconds
     */
    void onRotatePhone(Vector3D pastRot, Vector3D newRot, long timeDelta);
}


Men's padded parka from Italian outerwear brand, Herno. Forming part of the 'Legend' collection (a range reimagined on the banks of Lake Maggiore), the 'L'Impermeabile' jacket is cut from soft-feel nylon with a tubular quilted design, and is injected with ultra-light goose down for medium insulation. Mimicking a two-piece construction, the coat features a removable, internal zip placket insert to create the illusion of a zipped, high neck layer beneath.
Lightweight and practical, the parka features a pointed collar with hook and eye closure, a central button placket and two angled press stud pockets at the hips. Finished with contrast piping to the internal and three interior pockets: two zipped and one patch. The label's minimal branded tab sits at the nape.
Shell: 100% Nylon. Padding: 90% Goose Down, 10% Goose Feathers.
Model is 185cm/6'1" and wears a size M/IT 50.


text:
Q: how to revert to default video driver from nvidia driver? i downloaded the nvidia driver, and it seems to be messing things up. webcam programs dont work, blender isnt working. i need to revert to the default one.
Any help!?
this one doesnt make any since to me. How do I revert from the Nvidia driver to the unrestricted driver?

A: You should be able to disable it in System Settings > Addition Drivers
Otherwise you can do it on the command line like this:
sudo jockey-text -d xorg:nvidia_current

redpajama_set_name: RedPajamaStackExchange


text:
Seattle condos
U District
Construction begins on 244-unit 'U Place' condo project
Plans for U Place call for 244 units, ranging between 395 to 900 square feet.
By Sean Keeley@SeanKeeleyIsMe Sep 21, 2016, 1:00pm PDT
ZQH Investments has begun construction on their six-story, mixed-use project at 4603 Union Bay Place NE next to University Village called University Place (U Place for short).
Plans for U Place call for 244 units, ranging between 395 to 900 square feet. 80 percent of the units will be studios. Per a press release, they want those units to be for "young millennials who want to make the jump from renting to home ownership." Unit prices will not be determined until after construction begins.
The official amenity spaces are still being refined but they'll include two outdoor community decks (one on the second floor and a green roof deck with a lounge, barbecue area). Plans also call for 68 underground parking spaces and a bike gear & storage room.
The L-shaped design gives the eventual retail and restaurant properties a chance to work within a "food hall" concept that will include kiosks, small kitchens, pop-up vendors, and a "high-end, destination restaurant."
The residential building will replace a vacant old warehouse and small office building on the site. DLR Group will design the building and Chinn Construction will be the contractor.


This 70s inspired jumpsuit is from Boohoo and when I saw it online, I loved it! I ummed and arred over it for ages but decided to just be brave and go for it in the end! Its a flared leg, straight over the bust cut jumpsuit which is black but has quite thick stripes of white, orange, khaki green and burgundy colours over it. Sounds horrible when you describe it but it actually really works!
The jumpsuit is really fitted around the bust, body and thigh/bum area and then flairs over the legs. I styled it over a white long sleeved tee here, however it also looks really cool without the top underneath - I just was a bit too cold to wear it like that today! But in the summer, I'll definitely be wearing it on its own with a cool pair of platform sandals!
I also added my suede fitted biker jacket, however I think an oversized denim jacket would also look pretty cool with this jumpsuit!
Thanks to Peter for taking my photos! We are trying to be more artsy with my pictures! Hope you like them!
Also, I'm re-designing the layout of my blog! Its coming up to 3 years of juliettestephenson.co.uk and I feel like a change is needed! Keep a lookout - its going to be amazing!
Looks great! its quite bold but I do love it actually!


Wherever you are right now – pay attention. Close your eyes. Notice how your feet feel on the floor; move them around a little to get the full texture. Listen to the sound your feet are making as they move. What other parts of your body are touching your surroundings? Move ever so slightly to take in the sensation.
Listen. What do you hear? The whoosh of cars going by? Dishes clinked together while being washed? Someone typing on a computer? Music playing on the stereo?
Now take a deep breath. The air doesn't just carry the scent of your surroundings; it has a quality to it. It might be heavy with humidity, or thin and cold. But also pay attention to the smell. Scents are evocative; they can be powerful triggers of memory.
Finally look around and look closely. See the whole area from the large objects to one or two tiny details you may have never noticed. And really look at those details. If you look long enough it will be like seeing something for the first time because perhaps it is.
When you've captured your surroundings like this, in a mindful way, tell yourself you're saving this for later. I can't guarantee that everything you save will still be there, but you will find some of it again years from now. And when you find it, for a second you will be back in that space. And maybe, depending on how much time has elapsed between the initial imprint and the playback, that place won't really exist anywhere but in your memory. And it will feel like time travel.
I tell this to my children but I'm not sure they fully understand. When you're a child it can feel like your world is a rock, solid and unmovable. But as an adult you come to realize how quickly things can change. Something that seemed certain on one day is already gone the next and then you need to learn to let go of it. But if you weren't really paying attention in the first place you can get all messed up. You start making substitutions for what it is you thought you had. You imagine it bigger or smaller or more or less important than it actually was. You start having feelings for it that you didn't have at the time.
And so it's good to take a moment, wherever you are, to really look around to see what is it you have right now. Later, when it's gone, you can visit with it as it really was, or at least as close to what you perceived it to be, and you can be there again just for a moment before you let it go.


text:
Honest gaming news for all kinds of families.
Search for games, reviews & more
Taming Gaming is a Guidebook for Parents about Healthy Gaming
Posted by Eric Watson | May 18, 2018	| News, Tips for Parents | No Comments
Newspaper and broadcast journalist Andy Robertson has launched a new book project on crowdfunding publishing site Unbound. The book is called Taming Gaming. It's designed as a helpful guide for parents to navigate the daunting but ubiquitous world of video games. The 240-page book will be released in hardcover and digital ebook. Pre-orders are available now.
"Taming Gaming is an important and timely book," said Beth Lewis, Commissioning Editor at Unbound. "The gaming recipes offer parents an easy way to get involved in their child's hobby and start guiding them towards healthy habits."
The book is aimed at both gaming and non-gaming parents to provide healthy and positive avenues of gaming instead of simply limiting screen time. The second half of the book is organized into "family gaming recipes" that offer step-by-step examples on how to approach specific games.
"I appreciate parents' anxiety about this, but I'm also deeply grateful for what the skills and qualities that games have instilled in my children: curiosity, compassion, resilience, confidence, problem solving and patience," said Robertson. "I wrote Taming Gaming as a father wanting to air the real headaches of video games in the home, but also as a journalist offering parents an accessible way to solve this problem," said Robertson. "The 'family gaming recipes' do this perfectly."
Robertson is probably best known for his YouTube channel, FamilyGamerTV. FamilyGamerTV is Europe's largest family gaming channel, featuring insider looks, developer interviews, parental advice, and family-friendly gaming.
Unbound is a UK-based crowdfunding website that specializes in book publishing. Like Kickstarter and other crowdfunding sites, multiple higher pledges are available for this campaign, including signed books, YouTube guest appearances, and school visits.
andy robertsonF2familygamertvN2parentstaming gamingUnbound
About Eric Watson
Eric is a freelance writer who enjoys talking about video games, movies, books and Dallas-based sports teams. Every week he watches a random film from his collection of several hundred DVDs and live tweets about it @RogueWatson. He also makes a mean tuna quesadilla. He lives near Fort Worth, Texas with his wife and daughter, two dogs, two cats, two fish tanks, some hermit crabs and a bookshelf full of Transformers.
What is Pixelkin?
Follow Pixelkin
© 2020 Pixelkin.


text:
Digital Innovation Equipment and Innovation Treatments and Prevention
Paper: Clinical Signs Best Predictors of Mortality in Critically Ill Calves
US - Clinical signs such as gastrointestinal problems or septic arthritis may be better predictors of mortality in neonatal calves with diarrhea than blood pH levels and other laboratory findings, a new study suggests.
The research also may finally resolve a century-old debate among scientists about the blood pH levels needed to sustain life in humans and other mammals.
By analysing data in the medical records of more than 1,400 critically ill calves, scientists were able to ascertain which indicators were significant determinants of mortality. All of the calves in the study had diarrhea and other clinical signs, and were under 21 days old when they were admitted to the Clinic for Ruminants at Ludwig Maximilian University of Munich between April 2005 and October 2012.
Peter D. Constable, the dean of the College of Veterinary Medicine at the University of Illinois, co-wrote the paper with colleagues Florian M. Trefz and Annette Lorch, both of the Center of Veterinary Clinical Medicine at Ludwig Maximilian University of Munich; and Ingrid Lorenz, of the Bavarian Animal Health Service.
Published online in the scientific journal PLOS ONE, the study is believed to be the first retrospective data analysis involving a large population of critically ill animals, 22 per cent of which had blood pH levels below 7.0, Dr Constable said.
Critically ill calves with diarrhea typically exhibit dehydration, depression, loss of the suckling reflex and impaired ability to stand, according to the study.
Diarrhea also increases calves' risks for serious metabolic problems, including high levels of acid in the blood, a condition known as acidemia; and high concentrations of lactate in the blood, a strong predictor of mortality because it results from decreased blood flow and oxygen delivery to the tissues, Dr Constable said.
"We found that blood pH in itself is a predictor of mortality, but only when it is less than 6.85, which is profound acidemia," Dr Constable said. "Even then, it's not a really strong predictor. It appears that blood pH is a biomarker of the severity of other abnormalities, such as organ dysfunction."
One of the treatment goals for patients with severe diarrhea is to return their blood pH levels to normal limits using fluid therapy. Calves in the study were treated by administering electrolyte solutions orally or through IVs, along with antibiotics as needed. The mortality rate in the study population was 22 per cent.
Historically, veterinarians have relied on laboratory tests to predict treatment outcomes in neonatal calves. However, in analyzing the data associated with the animals in the current study, the researchers found that the top four predictors of mortality were clinical signs rather than laboratory findings.
Using a technique called classification tree analysis, the scientists found that signs of neurologic disease, gastrointestinal problems, orthopedic disorders such as septic arthritis, and cachexia - a condition commonly known as wasting syndrome - were better predictors of mortality than patients' blood pH levels.
Data on blood pH levels were not sensitive enough or specific enough to reliably predict mortality, the researchers found, except when these levels dropped below 6.85, indicating profound acidemia.
Normal serum pH level is 7.4, Dr Constable said, although there has been much debate among scientists as to what blood pH range is compatible with life. Fifty-four per cent of the calves in the study had blood pH levels below 7.2, indicating severe acidemia, with the lowest recorded pH level in the study population being 6.47.
"There's a lot of experimental data out there that says if blood pH falls below 7.2, patients tend to have many other comorbidities, but it's difficult to say whether those are caused by acidemia. If you're an Olympic rower, and you've just strenuously exerted yourself to cross the finish line and win the gold medal, your blood pH level could fall as low as 6.8. Yet, you're performing at a very high level," said Dr Constable, whose research interests include cardiovascular responses to endurance training.
"So it's a little uncertain whether blood pH by itself is really problematic and needs to be treated, or whether it's really an indicator of a whole lot of other serious abnormalities that need to be treated too," he said. "Our study would indicate that blood pH in itself, unless it's profoundly acidemic, is just a biomarker of these other abnormalities."
The study's findings also can help clinicians identify independent prognostic indicators in children with severe diarrhea, which causes 15 per cent of deaths worldwide in the population under age 5.
"There's an adage among experienced clinicians: Don't look at the data, look at the patient," Dr Constable said. "It's fine to look at laboratory data with these big data-mining exercises, but we can't lose sight of the fact that it's actually more valuable to look at the patient and see if we can identify and quantify physical signs and abnormalities, such as neurologic or abdominal disease, rather than saying that their serum sodium concentration is increased or decreased."
Find out more information on various cattle diseases by clicking here.


text:
Q: IE7 bug - span is covering up link The following code makes an entire div linkable to the  tag within with some cute css. It works for all browsers but IE7 (and probably 6). In IE7 the #go span seems to be covering up the link. The rest of the div is linked except for the span element, which acts like any normal part of the page. I've tried changing the z-indexes, and displaying the span as block (as you can see). A last resort would be wrapping the span with an additional  tag but that is just gross...does anybody have any better solutions?
.orangebutton {
    position: relative;
}
.orangebutton a {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
}

    Go

A: This is a bug of the IE ( Empty div hover event not firing in IE )
Solution would be to set a background for the a tag, but since you need it to be transparent, just add a transparent background image..
demo at http://jsfiddle.net/3m93n/1/
(transparent image hotlinked from the internet.. create a local version..)


text:
Home DAILY CURRENT AFFAIRS + PIB -23rd February 2020- IASbhai
DAILY CURRENT AFFAIRS + PIB -23rd February 2020- IASbhai
To be the best, you must be able to handle the worst.-Wilson Kanadi
PM-KISAN Scheme
International Judicial Conference
Kawal Tiger Reserve
Govt. eyes public-private fund
PM-KISAN Scheme completes one year on February 24, 2020
Over 8 crore 46 lakh farmers covered under Pradhan Mantri Kisan Samman Nidhi
Central Government transfers Rs.6,000 in three tranches every year to beneficiaries
SYLLABUS COVERED: GS 3:Scheme
For PRELIMS factual merit pointers are important in this scheme.
For MAINS pros and cons of this scheme have to be analysed.
24th February, 2020 is the 1st anniversary of starting of a new Central Sector Scheme, namely, the Pradhan Mantri Kisan Samman Nidhi (PM-KISAN).
MINISTRY? Ministry of Agriculture & Farmers Welfare
The scheme is effective from 1.12.2018.
The scheme was started with a view to augment the income of the farmers by providing income support to all landholding farmers' families across the country, to enable them to take care of expenses related to agriculture and allied activities as well as domestic needs.
The Scheme initially provided income support to all Small and Marginal Farmers' families across the country, holding cultivable land upto 2 hectares.
Under the Scheme an amount of Rs.6000/- per year is transferred in three 4-monthly installments of Rs.2000/- directly into the bank accounts of the farmers, subject to certain exclusion criteria relating to higher income status.
An exclusive web-portal www.pmkisan.gov.in has been launched for the Scheme.
The cut-off date for identification of beneficiaries with regard to their eligibility is 1.2.2019.
Affluent farmers have been excluded from the scheme such as Income Tax payers in last assessment year, professionals like Doctors, Engineers, Lawyers, Chartered Accountants etc and pensioners pensioners drawing at least Rs.10,000/- per month (excluding MTS/Class IV/Group D employees).
For enrollment, the farmer is required to approach the local patwari / revenue officer / Nodal Officer (PM-Kisan) nominated by the State Government.
Farmers can also do their self-registration through the Farmers Corner in the portal.
Farmers can also edit their names in PM-Kisan database as per their Aadhaar database / card through the Farmers Corner in the portal.
Farmers can also know the status of their payment through the Farmers Corner in the portal.
The entire responsibility of identification of beneficiaries rests with the State / UT Governments.
Its ambit was later expanded w.e.f. 01.06.2019 to cover all farmer families in the country irrespective of the size of their land holdings.
The Common Service Centres (CSCs) have also been authorized to do registration of the farmers for the Scheme upon payment of fees.
The above facilities on Farmers Corner are also available through CSCs. The total number of beneficiaries expected to be covered under the Scheme is 14 crore on the basis of the Agriculture Census, 2015-16.
Beneficiaries are entitled to their benefit from the 4-monthly period in which their name is registered by the State Nodal Officer (SNO) in the PM-Kisan Portal.
The Union Ministry of Agriculture & Farmers' Welfare has also launched a 24×7 automated IVRS(Interactive Voice Response System) based helpline for status verification.
Farmers can dial 1800-11-5526 or 155261 to know the status of their application.
Besides, farmers can now reach out to the PM KISAN team on email pmkisan-ict@gov.in.
State Governments are organizing camps periodically for the farmers to facilitate correction of application details.
The Central Government has already released more than Rs. 50850 crores till now.
Total number of beneficiaries to be covered under the scheme is about 14 crore.
As on 20.02.2020, on the basis of the data of beneficiaries uploaded on the PM-Kisan web portal by the State/UT Governments 8.46 crores farmer families have been given the benefits.
All installments falling due on or after 1st December, 2019 are being paid only on the basis of Aadhaar authenticated bank data of beneficiaries to ensure genuine beneficiaries.
PM addresses International Judicial Conference
Technology should help deliver speedy justice: PM
SYLLABUS COVERED: GS 2:Judiciary
For PRELIMS nothing much important here except the theme of this conference.
For MAINS there are some wonderful points which can be mentioned in Tech vs Judiciary .
Prime Minister Shri Narendra Modi addressed the International Judicial Conference in New Delhi. Distinguished Judges of the Supreme Court as well as various High Courts, Eminent lawyers and delegates from overseas also took part in the Conference.
KEY TAKEAWAYS FROM PM SPEECH
Changes are taking place in Social, Economic and Technological fields and that they should be based on logic, equitable justice. "Hence the topic of this conference, "Judiciary and The Changing World" is apt and significant".
India's philosophy is based on the paradigm that "Law is King of Kings, Law is Supreme".
The theme of this year's International Judicial Conference is "'Gender Just World'".
Dr B R Ambedkar said that "Constitution is not a mere lawyer's document, it is a vehicle of life, and its spirit is always a spirit of age'.
"Understanding each other's limitations, in the midst of all the challenges, many times the three Pillars of the Constitution have found the right path for the country.
The synergy of artificial intelligence and human conscience will also give further impetus to judicial processes in India
Prime Minister thanked the judiciary for its balance between development and environment.
SOURCES:PIB/DAILY CURRENT AFFAIRS for UPSC CSE Prelims & Mains
Adequate water in Kawal Tiger Reserve
No man-animal conflict foreseen on account of enough reserves, say officials
SYLLABUS COVERED: GS 3:Biodiversity
The worrisome man-animal conflict in the Kawal Tiger Reserve (KTR) on account of water seems to be a thing of the past.
No scarcity: Wild animals in Kawal Tiger Reserve will have enough water this summer.
There was no incident of wild animals straying into human habitations for water last year and it would hold good for the current season too as there is enough water for them to tide over the harsh summer in the Reserve, which is spread over 893 sq km of core area and 1,122 sq km of buffer.
Kawal Tiger Reserve is located at Jannaram mandal of Mancherial District (Old Adilabad district) in Telangana state of India.
Govt of India declared Kawal wildlife sanctuary as Tiger Reserve in 2012.
The reserve is the oldest sanctuary in the northern Telangana region of the state.
This sanctuary is catchment for the rivers Godavari and Kadam, which flow towards the south of the sanctuary.
Mammal species that have been sighted include tiger, leopard, gaur, cheetal, sambar, nilgai, barking deer, chowsingha, and sloth bear.
The sanctuary is one of the richest teak forests in the state, with dense pristine areas free of human disturbance.
The River Kadam flows through this area.
Dry deciduous teak forests mixed with bamboo, terminalia, pterocarpus, anogeisus and cassias.
Water will be available for a comparatively longer period in natural bodies, thanks to a prolonged monsoon and also the intensified efforts of the Reserve management in making it available through artificially created water holes.
Govt. eyes public-private fund to give R&D a shot in the arm
Target of ₹40 cr. is currently on the anvil
SYLLABUS COVERED: GS 3:SCI and TECH: Reasearch and Development
For PRELIMS the initiative of this bill is important as well as the ministry involved.
For MAINS find the issues related to funding in R&D projects.
In an effort to stimulate investment in research and development (R&D), the Department of Science and Technology is mooting a fund that will match the contributions made by private companies in R&D.
"The idea is to pool funds from a group of companies willing to invest in fundamental research, such as quantum computers or artificial intelligence, and whatever is invested government will match that.
A major beneficiary of such private sector funds could be the Indian Institutes of Technology.
FUNDING AND CO-ORDINATION
The scheme will be coordinated through the department's Science and Engineering Research Board, which funds a variety of basic science projects in several universities.
EXPENDITURE:
The total expenditure on R&D has tripled in the last decade in nominal (revenue sans inflation) terms — from ₹24,117 crore in 2004-05 to an estimated ₹1,04,864 crore in 2016-17.
Though India is among the top five countries in terms of its output of scientific publications, it doesn't match up in investments.
However as a fraction of GDP on R&D has been stagnant — between 0.6-0.7% of GDP — over the past two decades.
DAILY CURRENT AFFAIRS + PIB -22nd February 2020- IASbhai
DAILY CURRENT AFFAIRS + PIB -24th February 2020- IASbhai
IASbhai DAILY CURRENT AFFAIRS(THE HINDU+LIVEMINT+PIB) Page Contents: Section 144Department of Military AffairsReview of Net suspensionRelief to…
UPSC CURRENT AFFAIRS| PRELIMS & MAINS | 8th May 2020
13th Oct Current Affairs News Analysis | Prelims & Mains 2020-21
Page Contents: 13th Oct Current Affairs News Analysis | Prelims & Mains 2021Taro : Disappearing VegetableNo penal provision…
23rd Oct Current Affairs News Analysis | Prelims & Mains 2020
Page Contents: 23rd Oct Current Affairs News Analysis | Prelims & Mains 2021CPI-IW : Base year shifted to…
The most comprehensive DAILY CURRENT AFFAIRS of 28th FEBRUARY for UPSC PRELIMS and MAINS 2020 is here .Don't forget to solve the Quiz-2020.Subscribe NOW !


At the present moment the cheapest month to fly to Switzerland is currently November; with July being the most expensive. Prices will vary depending on multiple factors such as booking in advance, airline and departure airports and times.
Flying to Switzerland in November is usually considered the best time to fly. However, you will find other deals are always available year round. July tends to be the warmest period in Switzerland so if you are looking for sun or warmer climates then look to fly around this time. June is the wettest if you need to factor this in to your plans.
The price you pay for your flight to Switzerland may vary depending on when you book. For the best chance of a lower fare, look to book 60 days in advance of your trip. Fares are likely to increase a fortnight or so before your departure date.
The cheapest day to fly to Switzerland is usually Tuesday. At the moment, Friday is the most expensive.
To get the best value, try booking a flight in the afternoon when visiting Switzerland. Generally the prices will increase for flights at midday as these tend to have higher demand.


text:
Businesses can go to covid.gobusiness.gov.sg for more information regarding the temporary suspension of activities.
For more information on special travel arrangements that Singapore has implemented with other countries/regions, please go to https://safetravel.ica.gov.sg.
People at MTI
MTI Family
{{info.description}}
IMPROVING TRADE
Multilateral & Regional Forums
Digital Economy Agreements
International Investment Agreements
Other Collaborations
TRANSFORMING INDUSTRIES
Submit a Pro-Enterprise Suggestion
Submit a First Mover Idea
Apply for Business Grant
Apply for Business License
Future Economy
COVID-19 Updates For Businesses
Parliamentary Replies
Forum Letter Replies
Economic Survey of Singapore
Home / Newsroom / Speeches / 2020 / 11 / Speech by Minister Chan Chun Sing at Swee Choon Tim Sum Restaurant
Speech by Minister Chan Chun Sing at Swee Choon Tim Sum Rest...
Speech by Minister Chan Chun Sing at TravelRevive
Speech by MOS Alvin Tan at the 2nd Pacific Alliance Cooperat...
Speech by Minister Chan Chun Sing at the company visit to Se...
Speech by Minister Josephine Teo at the Opening Ceremony of ...
Delivered Remarks by Minister Chan Chun Sing at Release of T...
Speech by Minister Chan Chun Sing at Swee Choon Tim Sum Restaurant
1. The food services sector is an important industry that contributes to 1.1 per cent of Singapore's GDP and employs about 5.5 per cent of our workforce. We hope that with the 5.5 per cent workforce, we will be able to grow and value-add to the Singapore GDP much more than the current 1.1 per cent. Having said so, we want everyone to understand how we can achieve this.
2. Swee Choon is a very good example because it is an established historical brand. They have been working closely with ESG to see how we can scale up such a model going forward. Even before COVID-19, many of the trends that are affecting the food industry had already started. I am glad that some companies like Swee Choon have already begun to consider many of these trends.
3. What are some of these trends going forward? First, people like to have convenience when ordering their food. Many of us do not like to spend a lot of time at the queues nor wait a long time for our food. Of course, convenience comes with accessibility. How does a restaurant like Swee Choon serve the whole of the Singapore market when they previously did not have other outlets beyond the Jalan Besar restaurant? The second trend that has become very important since COVID-19 is how do we assure consumers of the safety and quality assurance when you can buy such food anywhere around Singapore or beyond. Thirdly, how do we use the digital medium to expand the market size for companies like Swee Choon and other smaller players in the market?
4.	Considering all these factors, the food industry needs to go through a transformation. COVID-19 has further accelerated digital adoption in the F&B sector. For instance, we have observed an accelerated adoption of online food delivery services by F&B operators and consumers. The percentage of online F&B sales out of total industry sales increased from 9.8 per cent in January 2020 to 44.6 per cent in May 2020, when the Circuit Breaker was in place. It now remains higher than pre-Circuit Breaker levels, at 20.4 per cent as of Sep 2020. This is unlikely to go back to the previous 10 per cent because the nature of the market has changed, the demand, as well as the consumption patterns, have all changed.
5.	This is why there is a lot of interest in the IT or the solutions under the Productivity Solutions Grants (PSG) within the F&B sector. The number of applications from January to October this year is more than four times the number of applications last year over the same period. We have supported over 2,700 PSG applications for IT solutions this year. There is a significant acceleration in the way companies are adopting the digital solutions to complement their conventional sales channels. Swee Choon is one of them.
6.	During the onset of the Circuit Breaker, Swee Choon's sales dropped by about 30 per cent, with profits falling about 40 per cent. Then, it quickly pivoted online to minimise the losses from the lack of dine-in sales and continued to serve customers via food delivery service. They ramped up their digital marketing, tapped on additional food delivery platforms such as FoodPanda, and Deliveroo. Enterprise Singapore (ESG) has also supported Swee Choon with its Food Delivery Booster Package to subsidise the delivery costs. To increase food delivery sales, Swee Choon also added new menu options in their delivery menus to make it easier for their customers to hit the minimum spend required for more affordable island-wide delivery.
7.	I must commend Swee Choon.Actually before COVID-19, they were already thinking along this line, and that is why they were ready to go into some of these new solutions. These efforts helped Swee Choon to increase their sales from food delivery significantly – from less than one per cent to around 60 per cent of their existing average monthly revenue during Circuit Breaker. While dine-in has resumed, food delivery sales continue to contribute to about 25 per cent to 30 per cent of their monthly revenue. Overall, Swee Choon's overall revenue has gone back to pre-COVID level, but the different segments' contribution has changed significantly. The most significant change is that digital platforms have allowed them to provide online delivery options around the island.
8.	Then, the question is, what else have they done, and what can we learn from this whole experience? For example, ESG launched the Food Delivery Booster Package during the Circuit Breaker period to support F&B businesses in onboarding to food delivery to diversify their revenues. To date, more than 13,000 establishments have benefited from this booster package.
9.	To help companies reach out to a wider group of customers, companies have been given Digital Marketing Support through the Enterprise Development Grant. They can also tap subsidised digital marketing courses to improve their digital marketing capabilities.
10.	However, to scale up beyond the digital platform, Swee Choon has started thinking about the next step because as the demand increased, they have to ask themselves, with the current shortage of manpower, how can Swee Choon deliver a higher volume to meet the customers' demand all around the island? To prepare for the next phase of growth, Swee Choon has set up a new central kitchen to ramp up its production volume. It has also opened a Cloud Kitchen in Tampines recently, which increases its ability to serve more customers in a capex light model and helps to reduce delivery costs for customers.
11.	One of the interesting things that Swee Choon has shared with me is that as they embarked on ecommerce, they are also able to gather data insights on the locations from which most of their orders are coming from. This allows Swee Choon to make a more informed decision on where they should open their next outlet or kitchen.
12.	It is the entire system – the data and a combination of cloud kitchen distribution and central kitchen that they have embraced to overcome the space and geographical constraints of serving their customers from their restaurant units in Jalan Besar. So today, even if you do not have time to come down to Jalan Besar, you can also enjoy Swee Choon dim sum through food delivery services or purchase it from one of the cloud kitchens around the island, which they intend to set up more in time to come.
13.	Another interesting idea that Swee Choon has is to expand its product range to frozen items, which are not so simple as it requires some tweaking of the recipe.
14.	Various initiatives have been rolled out to support our F&B players. For example, other companies, such as Le Rainbow, a catering company, are also partnering with the Food Innovation and Resource Centre (FIRC) to develop Ready-to-Eat products targeting dormitory workers and the elderly to increase revenue streams amid restrictions on buffet-style food services. Companies can also tap on FoodInnovate, a multi-agency initiative led by ESG, which provides resources to Singapore food companies to drive foodtech and innovations. There are still growth opportunities for F&B companies that are willing and able to adapt and transform.
15.	Next, I will go into the importance of investing in human capital capabilities. One of the big challenges for this sector is how to attract people to come into this sector to learn the trade and expand the business. As F&B companies digitalise and automate their processes further in their transformation process, there is an opportunity for them to embark on job redesign to increase the attractiveness of these roles to locals and reduce the sector's reliance on foreign manpower. This is a work-in-progress task, and it is not easy because there is a finite number of Singaporeans who are prepared to come into this line. However, we are exploring all the different ideas to see how we can attract more younger people to come in and learn the skills required and set up their business in time to come.
16.	Today, in this industry, it is not just about learning how to cook. If you look at the experience of Ernest Ting, the third generation owner of Swee Choon, it is also about managing the entire logistics chain, supply chain, and digital network so that we can expand the offerings beyond the limitations of a physical restaurant itself. These are actually exciting opportunities for many of our people if you are prepared to come in and learn the trade.
17.	Pastamania is another company that has re-examined its business structure and reskilled their workers during the downtime due to COVID-19. To support companies in the process of job redesign, as of mid-November 2020, more than 1,100 workers across more than 30 companies have undergone or are undergoing reskilling through WSG's Job Redesign Reskilling Programme for Food Services, which was rolled out in Apr 2020 to support the sector's transformation.
18.	To ensure businesses and workers are sufficiently supported to upgrade their skills, we will continue to support companies through schemes such as SSG's Enhanced Training Support Package for the Food services sector and increase the number of tracks relevant to Food Services sector under the Professional Conversion Programme (PCP).
19.	To conclude, let me pull together a few threads and summarise why we showcased Swee Choon as one of the examples. In the past few weekly sectoral updates, we have talked about many companies, and maybe people will think that many of our efforts are focused on helping big companies to grow. That is part of our effort, but there are also good prospects in the food manufacturing industry and even for smaller players like Swee Choon.
20.	The most fundamental issue is that you must have a good product. If you have a good product, we can think of ways to help the company or restaurant scale up. This will require us to have a bolder vision of where we want to be eventually. Like Swee Choon, they aspire to serve the whole of Singapore beyond Jalan Besar. Then, they start to dream bigger, do some R&D on the product mix, set up a central kitchen to increase production volume, redesign job roles to enhance productivity, set up a cloud kitchen to have more distribution points, and leverage digital platforms for people to access their food services beyond the confines of a physical restaurant. Once you have established a good base in Singapore, it will allow you to expand into other countries, like how Old Chang Kee, and other food establishments have successfully expanded overseas with a strong Singapore branding.
21.	I think we have every confidence that the trusted Singapore brand will put our food industry in good stead. To seize new growth opportunities, especially for a growing Asia market, we must ensure that we maintain the quality of our food products in Singapore. The Government will continue to support our companies to automate, redesign their jobs, and attract more talents to cater to the new generation of consumers and serve even more people.
22.	These are some of the initiatives we are committed to helping our small, medium, and micro-enterprises. Hopefully, amongst the many food establishments in Singapore, those with good branding and quality products will be able to scale up and serve customers in Singapore and beyond.
About Us About MTI
About Us People at MTI
About Us MTI Family
Pro-Enterprise Panel - Submit A Suggestion Future Economy Council Share your views @ Reach
Contact Us Feedback FAQs
Report Vulnerability Privacy Statement Terms of Use Rate this Service Sitemap Copyright © 2021 Ministry of Trade and Industry
Last Updated on 04 Jan 2021
add HOME ABOUT US


A easy four ingredient, popular traditional Bengali dessert, a delicious medley of mangoes and Yoghurt steamed to perfection.
Bake up this easy, festive and beautiful Christmas tree shaped,spicy Gingerbread flavoured brownies,cute and fun Christmas dessert your family will love!
A easy, gluten free, eggless, sugarfree,crispy, 3 ingredient Chocolate cookies with Ragi or Finger millet in Rosette shapes.
Here's a tasty Lasagna roll ups recipe filled with fresh Spinach, Cottage Cheese and Basil and baked in a homemade, quick Marinara sauce and a white Sauce.
Easy and best eggless Nankhatai recipe,made with a combo of flour and gram flour (besan),flavoured with Kesar and Pista,a melt in the mouth festive treat.
A vibrant, egg free, low calorie Saffron flavoured Mango Cake with Almonds, bursting with flavours making you crave for more.


Double bassist and sound artist, Hugo Blouin is interested in tradition, improvisation and experimentation. In 2016, he encounters the MAZ ship and crew at the junction of these currents and hops aboard.
Over the last ten years, his work has been heard and acknowledged in Quebec, in Canada and in francophone Europe. He led and contributed to many projects in relation to his eclectic practice, from chanson française to sound art, to jazz and folk music.
Among them : Brasser Brassens (chanson, with Sonia Painchaud), Jonathan Turgeon Trio (contemporary jazz), M'entends-tu? (poetry, with Véronique Bachand), Rose Vagabond (traditional/Cajun) and The Ossuary – a fire organ project (sound art, with Paul Grégoire).
Certified accompanist for slam and live poetry acts, Hugo Blouin is also active on the experimental and improvised music scenes. Trained in both classical and jazz traditions, he now pursues his autodidact studies in Living Music with the communities of musicians around which he revolves.


Our HSE 600 Watt fixture's integrated electronic ballast guarantees low energy consumption and a long life, offering you greater light intensities without adversely affecting your energy efficiency. Our HSE 600 provides more light with less energy.
We developed and perfected the electronic ballast devices integrated in this fixture. Each fixture moreover has a LED indicator enabling you to solve any problems at the source.
The unique design, with cooling fins and a heat shield, keeps the temperature in the fixture constant. The dust-repellent housing keeps the fixture clean, ensuring optimum output of light, while a membrane in the housing ensures ventilation and protects the fixture against the negative effects of moisture on the electronic components. One by one smart solutions to optimally protect all the electronic components against external influences.
The fixture's highly compact design minimises undesired shadows on the plants. And thanks to the special adapter, the lamp and reflector can be easily, quickly and safely installed.
Would you like to discuss the possibilities of the HSE 600 or one of Hortilux's other fixtures with us? We will gladly visit you free of obligations to discuss your specific requirements and offer suitable advice.


text:
package storage

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"

	alicred "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
	aliproviders "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials/providers"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/pingcap/errors"
	backuppb "github.com/pingcap/kvproto/pkg/brpb"
	"github.com/pingcap/log"
	berrors "github.com/pingcap/tidb/br/pkg/errors"
	"github.com/pingcap/tidb/br/pkg/logutil"
	"github.com/spf13/pflag"
	"go.uber.org/zap"
)

const (
	s3EndpointOption     = "s3.endpoint"
	s3RegionOption       = "s3.region"
	s3StorageClassOption = "s3.storage-class"
	s3SseOption          = "s3.sse"
	s3SseKmsKeyIDOption  = "s3.sse-kms-key-id"
	s3ACLOption          = "s3.acl"
	s3ProviderOption     = "s3.provider"
	notFound             = "NotFound"
	// number of retries to make of operations.
	maxRetries = 7
	// max number of retries when meets error
	maxErrorRetries = 3
	ec2MetaAddress  = "169.254.169.254"

	// the maximum number of byte to read for seek.
	maxSkipOffsetByRead = 1 << 16 // 64KB

	// TODO make this configurable, 5 mb is a good minimum size but on low latency/high bandwidth network you can go a lot bigger
	hardcodedS3ChunkSize = 5 * 1024 * 1024
	defaultRegion        = "us-east-1"
	// to check the cloud type by endpoint tag.
	domainAliyun = "aliyuncs.com"
)

var permissionCheckFn = map[Permission]func(*s3.S3, *backuppb.S3) error{
	AccessBuckets: checkS3Bucket,
	ListObjects:   listObjects,
	GetObject:     getObject,
}

// S3Storage info for s3 storage.
type S3Storage struct {
	session *session.Session
	svc     s3iface.S3API
	options *backuppb.S3
}

// S3Uploader does multi-part upload to s3.
type S3Uploader struct {
	svc           s3iface.S3API
	createOutput  *s3.CreateMultipartUploadOutput
	completeParts []*s3.CompletedPart
}

// UploadPart update partial data to s3, we should call CreateMultipartUpload to start it,
// and call CompleteMultipartUpload to finish it.
func (u *S3Uploader) Write(ctx context.Context, data []byte) (int, error) {
	partInput := &s3.UploadPartInput{
		Body:          bytes.NewReader(data),
		Bucket:        u.createOutput.Bucket,
		Key:           u.createOutput.Key,
		PartNumber:    aws.Int64(int64(len(u.completeParts) + 1)),
		UploadId:      u.createOutput.UploadId,
		ContentLength: aws.Int64(int64(len(data))),
	}

	uploadResult, err := u.svc.UploadPartWithContext(ctx, partInput)
	if err != nil {
		return 0, errors.Trace(err)
	}
	u.completeParts = append(u.completeParts, &s3.CompletedPart{
		ETag:       uploadResult.ETag,
		PartNumber: partInput.PartNumber,
	})
	return len(data), nil
}

// Close complete multi upload request.
func (u *S3Uploader) Close(ctx context.Context) error {
	completeInput := &s3.CompleteMultipartUploadInput{
		Bucket:   u.createOutput.Bucket,
		Key:      u.createOutput.Key,
		UploadId: u.createOutput.UploadId,
		MultipartUpload: &s3.CompletedMultipartUpload{
			Parts: u.completeParts,
		},
	}
	_, err := u.svc.CompleteMultipartUploadWithContext(ctx, completeInput)
	return errors.Trace(err)
}

// S3BackendOptions contains options for s3 storage.
type S3BackendOptions struct {
	Endpoint              string `json:"endpoint" toml:"endpoint"`
	Region                string `json:"region" toml:"region"`
	StorageClass          string `json:"storage-class" toml:"storage-class"`
	Sse                   string `json:"sse" toml:"sse"`
	SseKmsKeyID           string `json:"sse-kms-key-id" toml:"sse-kms-key-id"`
	ACL                   string `json:"acl" toml:"acl"`
	AccessKey             string `json:"access-key" toml:"access-key"`
	SecretAccessKey       string `json:"secret-access-key" toml:"secret-access-key"`
	Provider              string `json:"provider" toml:"provider"`
	ForcePathStyle        bool   `json:"force-path-style" toml:"force-path-style"`
	UseAccelerateEndpoint bool   `json:"use-accelerate-endpoint" toml:"use-accelerate-endpoint"`
}

// Apply apply s3 options on backuppb.S3.
func (options *S3BackendOptions) Apply(s3 *backuppb.S3) error {
	if options.Endpoint != "" {
		u, err := url.Parse(options.Endpoint)
		if err != nil {
			return errors.Trace(err)
		}
		if u.Scheme == "" {
			return errors.Annotate(berrors.ErrStorageInvalidConfig, "scheme not found in endpoint")
		}
		if u.Host == "" {
			return errors.Annotate(berrors.ErrStorageInvalidConfig, "host not found in endpoint")
		}
	}
	// In some cases, we need to set ForcePathStyle to false.
	// Refer to: https://rclone.org/s3/#s3-force-path-style
	if options.Provider == "alibaba" || options.Provider == "netease" ||
		options.UseAccelerateEndpoint {
		options.ForcePathStyle = false
	}
	if options.AccessKey == "" && options.SecretAccessKey != "" {
		return errors.Annotate(berrors.ErrStorageInvalidConfig, "access_key not found")
	}
	if options.AccessKey != "" && options.SecretAccessKey == "" {
		return errors.Annotate(berrors.ErrStorageInvalidConfig, "secret_access_key not found")
	}

	s3.Endpoint = strings.TrimSuffix(options.Endpoint, "/")
	s3.Region = options.Region
	// StorageClass, SSE and ACL are acceptable to be empty
	s3.StorageClass = options.StorageClass
	s3.Sse = options.Sse
	s3.SseKmsKeyId = options.SseKmsKeyID
	s3.Acl = options.ACL
	s3.AccessKey = options.AccessKey
	s3.SecretAccessKey = options.SecretAccessKey
	s3.ForcePathStyle = options.ForcePathStyle
	return nil
}

// defineS3Flags defines the command line flags for S3BackendOptions.
func defineS3Flags(flags *pflag.FlagSet) {
	// TODO: remove experimental tag if it's stable
	flags.String(s3EndpointOption, "",
		"(experimental) Set the S3 endpoint URL, please specify the http or https scheme explicitly")
	flags.String(s3RegionOption, "", "(experimental) Set the S3 region, e.g. us-east-1")
	flags.String(s3StorageClassOption, "", "(experimental) Set the S3 storage class, e.g. STANDARD")
	flags.String(s3SseOption, "", "Set S3 server-side encryption, e.g. aws:kms")
	flags.String(s3SseKmsKeyIDOption, "", "KMS CMK key id to use with S3 server-side encryption."+
		"Leave empty to use S3 owned key.")
	flags.String(s3ACLOption, "", "(experimental) Set the S3 canned ACLs, e.g. authenticated-read")
	flags.String(s3ProviderOption, "", "(experimental) Set the S3 provider, e.g. aws, alibaba, ceph")
}

// parseFromFlags parse S3BackendOptions from command line flags.
func (options *S3BackendOptions) parseFromFlags(flags *pflag.FlagSet) error {
	var err error
	options.Endpoint, err = flags.GetString(s3EndpointOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.Endpoint = strings.TrimSuffix(options.Endpoint, "/")
	options.Region, err = flags.GetString(s3RegionOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.Sse, err = flags.GetString(s3SseOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.SseKmsKeyID, err = flags.GetString(s3SseKmsKeyIDOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.ACL, err = flags.GetString(s3ACLOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.StorageClass, err = flags.GetString(s3StorageClassOption)
	if err != nil {
		return errors.Trace(err)
	}
	options.ForcePathStyle = true
	options.Provider, err = flags.GetString(s3ProviderOption)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// NewS3StorageForTest creates a new S3Storage for testing only.
func NewS3StorageForTest(svc s3iface.S3API, options *backuppb.S3) *S3Storage {
	return &S3Storage{
		session: nil,
		svc:     svc,
		options: options,
	}
}

// NewS3Storage initialize a new s3 storage for metadata.
//
// Deprecated: Create the storage via `New()` instead of using this.
func NewS3Storage( // revive:disable-line:flag-parameter
	backend *backuppb.S3,
	sendCredential bool,
) (*S3Storage, error) {
	return newS3Storage(backend, &ExternalStorageOptions{
		SendCredentials:  sendCredential,
		CheckPermissions: []Permission{AccessBuckets},
	})
}

// auto access without ak / sk.
func autoNewCred(qs *backuppb.S3) (cred *credentials.Credentials, err error) {
	if qs.AccessKey != "" && qs.SecretAccessKey != "" {
		return credentials.NewStaticCredentials(qs.AccessKey, qs.SecretAccessKey, ""), nil
	}
	endpoint := qs.Endpoint
	// if endpoint is empty,return no error and run default(aws) follow.
	if endpoint == "" {
		return nil, nil
	}
	// if it Contains 'aliyuncs', fetch the sts token.
	if strings.Contains(endpoint, domainAliyun) {
		return createOssRamCred()
	}
	// other case ,return no error and run default(aws) follow.
	return nil, nil
}

func createOssRamCred() (*credentials.Credentials, error) {
	cred, err := aliproviders.NewInstanceMetadataProvider().Retrieve()
	if err != nil {
		return nil, errors.Annotate(err, "Alibaba RAM Provider Retrieve")
	}
	ncred := cred.(*alicred.StsTokenCredential)
	return credentials.NewStaticCredentials(ncred.AccessKeyId, ncred.AccessKeySecret, ncred.AccessKeyStsToken), nil
}

func newS3Storage(backend *backuppb.S3, opts *ExternalStorageOptions) (obj *S3Storage, errRet error) {
	qs := *backend
	awsConfig := aws.NewConfig().
		WithS3ForcePathStyle(qs.ForcePathStyle)
	if qs.Region == "" {
		awsConfig.WithRegion(defaultRegion)
	} else {
		awsConfig.WithRegion(qs.Region)
	}
	request.WithRetryer(awsConfig, defaultS3Retryer())
	if qs.Endpoint != "" {
		awsConfig.WithEndpoint(qs.Endpoint)
	}
	if opts.HTTPClient != nil {
		awsConfig.WithHTTPClient(opts.HTTPClient)
	}
	cred, err := autoNewCred(&qs)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if cred != nil {
		awsConfig.WithCredentials(cred)
	}
	// awsConfig.WithLogLevel(aws.LogDebugWithSigning)
	awsSessionOpts := session.Options{
		Config: *awsConfig,
	}
	ses, err := session.NewSessionWithOptions(awsSessionOpts)
	if err != nil {
		return nil, errors.Trace(err)
	}

	if !opts.SendCredentials {
		// Clear the credentials if exists so that they will not be sent to TiKV
		backend.AccessKey = ""
		backend.SecretAccessKey = ""
	} else if ses.Config.Credentials != nil {
		if qs.AccessKey == "" || qs.SecretAccessKey == "" {
			v, cerr := ses.Config.Credentials.Get()
			if cerr != nil {
				return nil, errors.Trace(cerr)
			}
			backend.AccessKey = v.AccessKeyID
			backend.SecretAccessKey = v.SecretAccessKey
		}
	}

	c := s3.New(ses)
	// s3manager.GetBucketRegionWithClient will set credential anonymous, which works with s3.
	// we need reassign credential to be compatible with minio authentication.
	confCred := ses.Config.Credentials
	setCredOpt := func(req *request.Request) {
		if confCred != nil {
			req.Config.Credentials = confCred
		}
	}
	region, err := s3manager.GetBucketRegionWithClient(context.Background(), c, qs.Bucket, setCredOpt)
	if err != nil {
		return nil, errors.Annotatef(err, "failed to get region of bucket %s", qs.Bucket)
	}

	if qs.Region != region {
		if qs.Region != "" {
			return nil, errors.Trace(fmt.Errorf("s3 bucket and region are not matched, bucket=%s, input region=%s, real region=%s",
				qs.Bucket, qs.Region, region))
		}

		qs.Region = region
		if region != defaultRegion {
			awsConfig.WithRegion(region)
			c = s3.New(ses, awsConfig)
		}
	}
	log.Info("succeed to get bucket region from s3", zap.String("bucket region", region))

	if len(qs.Prefix) > 0 && !strings.HasSuffix(qs.Prefix, "/") {
		qs.Prefix += "/"
	}

	for _, p := range opts.CheckPermissions {
		err := permissionCheckFn[p](c, &qs)
		if err != nil {
			return nil, errors.Annotatef(berrors.ErrStorageInvalidPermission, "check permission %s failed due to %v", p, err)
		}
	}

	return &S3Storage{
		session: ses,
		svc:     c,
		options: &qs,
	}, nil
}

// checkBucket checks if a bucket exists.
func checkS3Bucket(svc *s3.S3, qs *backuppb.S3) error {
	input := &s3.HeadBucketInput{
		Bucket: aws.String(qs.Bucket),
	}
	_, err := svc.HeadBucket(input)
	return errors.Trace(err)
}

// listObjects checks the permission of listObjects
func listObjects(svc *s3.S3, qs *backuppb.S3) error {
	input := &s3.ListObjectsInput{
		Bucket:  aws.String(qs.Bucket),
		Prefix:  aws.String(qs.Prefix),
		MaxKeys: aws.Int64(1),
	}
	_, err := svc.ListObjects(input)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// getObject checks the permission of getObject
func getObject(svc *s3.S3, qs *backuppb.S3) error {
	input := &s3.GetObjectInput{
		Bucket: aws.String(qs.Bucket),
		Key:    aws.String("not-exists"),
	}
	_, err := svc.GetObject(input)
	if aerr, ok := err.(awserr.Error); ok {
		if aerr.Code() == "NoSuchKey" {
			// if key not exists and we reach this error, that
			// means we have the correct permission to GetObject
			// other we will get another error
			return nil
		}
		return errors.Trace(err)
	}
	return nil
}

// WriteFile writes data to a file to storage.
func (rs *S3Storage) WriteFile(ctx context.Context, file string, data []byte) error {
	input := &s3.PutObjectInput{
		Body:   aws.ReadSeekCloser(bytes.NewReader(data)),
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + file),
	}
	if rs.options.Acl != "" {
		input = input.SetACL(rs.options.Acl)
	}
	if rs.options.Sse != "" {
		input = input.SetServerSideEncryption(rs.options.Sse)
	}
	if rs.options.SseKmsKeyId != "" {
		input = input.SetSSEKMSKeyId(rs.options.SseKmsKeyId)
	}
	if rs.options.StorageClass != "" {
		input = input.SetStorageClass(rs.options.StorageClass)
	}

	_, err := rs.svc.PutObjectWithContext(ctx, input)
	if err != nil {
		return errors.Trace(err)
	}
	hinput := &s3.HeadObjectInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + file),
	}
	err = rs.svc.WaitUntilObjectExistsWithContext(ctx, hinput)
	return errors.Trace(err)
}

// ReadFile reads the file from the storage and returns the contents.
func (rs *S3Storage) ReadFile(ctx context.Context, file string) ([]byte, error) {
	input := &s3.GetObjectInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + file),
	}
	result, err := rs.svc.GetObjectWithContext(ctx, input)
	if err != nil {
		return nil, errors.Annotatef(err,
			"failed to read s3 file, file info: input.bucket='%s', input.key='%s'",
			*input.Bucket, *input.Key)
	}
	defer result.Body.Close()
	data, err := io.ReadAll(result.Body)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return data, nil
}

// DeleteFile delete the file in s3 storage
func (rs *S3Storage) DeleteFile(ctx context.Context, file string) error {
	input := &s3.DeleteObjectInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + file),
	}

	_, err := rs.svc.DeleteObjectWithContext(ctx, input)
	return errors.Trace(err)
}

// FileExists check if file exists on s3 storage.
func (rs *S3Storage) FileExists(ctx context.Context, file string) (bool, error) {
	input := &s3.HeadObjectInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + file),
	}

	_, err := rs.svc.HeadObjectWithContext(ctx, input)
	if err != nil {
		if aerr, ok := errors.Cause(err).(awserr.Error); ok { // nolint:errorlint
			switch aerr.Code() {
			case s3.ErrCodeNoSuchBucket, s3.ErrCodeNoSuchKey, notFound:
				return false, nil
			}
		}
		return false, errors.Trace(err)
	}
	return true, nil
}

// WalkDir traverse all the files in a dir.
//
// fn is the function called for each regular file visited by WalkDir.
// The first argument is the file path that can be used in `Open`
// function; the second argument is the size in byte of the file determined
// by path.
func (rs *S3Storage) WalkDir(ctx context.Context, opt *WalkOption, fn func(string, int64) error) error {
	if opt == nil {
		opt = &WalkOption{}
	}
	prefix := path.Join(rs.options.Prefix, opt.SubDir)
	if len(prefix) > 0 && !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	if len(opt.ObjPrefix) != 0 {
		prefix += opt.ObjPrefix
	}

	maxKeys := int64(1000)
	if opt.ListCount > 0 {
		maxKeys = opt.ListCount
	}
	req := &s3.ListObjectsInput{
		Bucket:  aws.String(rs.options.Bucket),
		Prefix:  aws.String(prefix),
		MaxKeys: aws.Int64(maxKeys),
	}

	for {
		// FIXME: We can't use ListObjectsV2, it is not universally supported.
		// (Ceph RGW supported ListObjectsV2 since v15.1.0, released 2020 Jan 30th)
		// (as of 2020, DigitalOcean Spaces still does not support V2 - https://developers.digitalocean.com/documentation/spaces/#list-bucket-contents)
		res, err := rs.svc.ListObjectsWithContext(ctx, req)
		if err != nil {
			return errors.Trace(err)
		}
		for _, r := range res.Contents {
			// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html#AmazonS3-ListObjects-response-NextMarker -
			//
			// `res.NextMarker` is populated only if we specify req.Delimiter.
			// Aliyun OSS and minio will populate NextMarker no matter what,
			// but this documented behavior does apply to AWS S3:
			//
			// "If response does not include the NextMarker and it is truncated,
			// you can use the value of the last Key in the response as the marker
			// in the subsequent request to get the next set of object keys."
			req.Marker = r.Key

			// when walk on specify directory, the result include storage.Prefix,
			// which can not be reuse in other API(Open/Read) directly.
			// so we use TrimPrefix to filter Prefix for next Open/Read.
			path := strings.TrimPrefix(*r.Key, rs.options.Prefix)
			// trim the prefix '/' to ensure that the path returned is consistent with the local storage
			path = strings.TrimPrefix(path, "/")
			itemSize := *r.Size

			// filter out s3's empty directory items
			if itemSize <= 0 && strings.HasSuffix(path, "/") {
				log.Info("this path is an empty directory and cannot be opened in S3.  Skip it", zap.String("path", path))
				continue
			}
			if err = fn(path, itemSize); err != nil {
				return errors.Trace(err)
			}

		}
		if !aws.BoolValue(res.IsTruncated) {
			break
		}
	}

	return nil
}

// URI returns s3://<base>/<prefix>.
func (rs *S3Storage) URI() string {
	return "s3://" + rs.options.Bucket + "/" + rs.options.Prefix
}

// Open a Reader by file path.
func (rs *S3Storage) Open(ctx context.Context, path string) (ExternalFileReader, error) {
	reader, r, err := rs.open(ctx, path, 0, 0)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &s3ObjectReader{
		storage:   rs,
		name:      path,
		reader:    reader,
		ctx:       ctx,
		rangeInfo: r,
	}, nil
}

// RangeInfo represents the an HTTP Content-Range header value
// of the form `bytes [Start]-[End]/[Size]`.
type RangeInfo struct {
	// Start is the absolute position of the first byte of the byte range,
	// starting from 0.
	Start int64
	// End is the absolute position of the last byte of the byte range. This end
	// offset is inclusive, e.g. if the Size is 1000, the maximum value of End
	// would be 999.
	End int64
	// Size is the total size of the original file.
	Size int64
}

// if endOffset > startOffset, should return reader for bytes in [startOffset, endOffset).
func (rs *S3Storage) open(
	ctx context.Context,
	path string,
	startOffset, endOffset int64,
) (io.ReadCloser, RangeInfo, error) {
	input := &s3.GetObjectInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + path),
	}

	// If we just open part of the object, we set `Range` in the request.
	// If we meant to open the whole object, not just a part of it,
	// we do not pass the range in the request,
	// so that even if the object is empty, we can still get the response without errors.
	// Then this behavior is similar to openning an empty file in local file system.
	isFullRangeRequest := false
	var rangeOffset *string
	switch {
	case endOffset > startOffset:
		// s3 endOffset is inclusive
		rangeOffset = aws.String(fmt.Sprintf("bytes=%d-%d", startOffset, endOffset-1))
	case startOffset == 0:
		// openning the whole object, no need to fill the `Range` field in the request
		isFullRangeRequest = true
	default:
		rangeOffset = aws.String(fmt.Sprintf("bytes=%d-", startOffset))
	}
	input.Range = rangeOffset
	result, err := rs.svc.GetObjectWithContext(ctx, input)
	if err != nil {
		return nil, RangeInfo{}, errors.Trace(err)
	}

	var r RangeInfo
	// Those requests without a `Range` will have no `ContentRange` in the response,
	// In this case, we'll parse the `ContentLength` field instead.
	if isFullRangeRequest {
		// We must ensure the `ContentLengh` has data even if for empty objects,
		// otherwise we have no places to get the object size
		if result.ContentLength == nil {
			return nil, RangeInfo{}, errors.Annotatef(berrors.ErrStorageUnknown, "open file '%s' failed. The S3 object has no content length", path)
		}
		objectSize := *(result.ContentLength)
		r = RangeInfo{
			Start: 0,
			End:   objectSize - 1,
			Size:  objectSize,
		}
	} else {
		r, err = ParseRangeInfo(result.ContentRange)
		if err != nil {
			return nil, RangeInfo{}, errors.Trace(err)
		}
	}

	if startOffset != r.Start || (endOffset != 0 && endOffset != r.End+1) {
		return nil, r, errors.Annotatef(berrors.ErrStorageUnknown, "open file '%s' failed, expected range: %s, got: %v",
			path, *rangeOffset, result.ContentRange)
	}

	return result.Body, r, nil
}

var contentRangeRegex = regexp.MustCompile(`bytes (\d+)-(\d+)/(\d+)$`)

// ParseRangeInfo parses the Content-Range header and returns the offsets.
func ParseRangeInfo(info *string) (ri RangeInfo, err error) {
	if info == nil || len(*info) == 0 {
		err = errors.Annotate(berrors.ErrStorageUnknown, "ContentRange is empty")
		return
	}
	subMatches := contentRangeRegex.FindStringSubmatch(*info)
	if len(subMatches) != 4 {
		err = errors.Annotatef(berrors.ErrStorageUnknown, "invalid content range: '%s'", *info)
		return
	}

	ri.Start, err = strconv.ParseInt(subMatches[1], 10, 64)
	if err != nil {
		err = errors.Annotatef(err, "invalid start offset value '%s' in ContentRange '%s'", subMatches[1], *info)
		return
	}
	ri.End, err = strconv.ParseInt(subMatches[2], 10, 64)
	if err != nil {
		err = errors.Annotatef(err, "invalid end offset value '%s' in ContentRange '%s'", subMatches[2], *info)
		return
	}
	ri.Size, err = strconv.ParseInt(subMatches[3], 10, 64)
	if err != nil {
		err = errors.Annotatef(err, "invalid size size value '%s' in ContentRange '%s'", subMatches[3], *info)
		return
	}
	return
}

// s3ObjectReader wrap GetObjectOutput.Body and add the `Seek` method.
type s3ObjectReader struct {
	storage   *S3Storage
	name      string
	reader    io.ReadCloser
	pos       int64
	rangeInfo RangeInfo
	// reader context used for implement `io.Seek`
	// currently, lightning depends on package `xitongsys/parquet-go` to read parquet file and it needs `io.Seeker`
	// See: https://github.com/xitongsys/parquet-go/blob/207a3cee75900b2b95213627409b7bac0f190bb3/source/source.go#L9-L10
	ctx      context.Context
	retryCnt int
}

// Read implement the io.Reader interface.
func (r *s3ObjectReader) Read(p []byte) (n int, err error) {
	maxCnt := r.rangeInfo.End + 1 - r.pos
	if maxCnt > int64(len(p)) {
		maxCnt = int64(len(p))
	}
	n, err = r.reader.Read(p[:maxCnt])
	// TODO: maybe we should use !errors.Is(err, io.EOF) here to avoid error lint, but currently, pingcap/errors
	// doesn't implement this method yet.
	if err != nil && errors.Cause(err) != io.EOF && r.retryCnt < maxErrorRetries { //nolint:errorlint
		// if can retry, reopen a new reader and try read again
		end := r.rangeInfo.End + 1
		if end == r.rangeInfo.Size {
			end = 0
		}
		_ = r.reader.Close()

		newReader, _, err1 := r.storage.open(r.ctx, r.name, r.pos, end)
		if err1 != nil {
			log.Warn("open new s3 reader failed", zap.String("file", r.name), zap.Error(err1))
			return
		}
		r.reader = newReader
		r.retryCnt++
		n, err = r.reader.Read(p[:maxCnt])
	}

	r.pos += int64(n)
	return
}

// Close implement the io.Closer interface.
func (r *s3ObjectReader) Close() error {
	return r.reader.Close()
}

// Seek implement the io.Seeker interface.
//
// Currently, tidb-lightning depends on this method to read parquet file for s3 storage.
func (r *s3ObjectReader) Seek(offset int64, whence int) (int64, error) {
	var realOffset int64
	switch whence {
	case io.SeekStart:
		realOffset = offset
	case io.SeekCurrent:
		realOffset = r.pos + offset
	case io.SeekEnd:
		realOffset = r.rangeInfo.Size + offset
	default:
		return 0, errors.Annotatef(berrors.ErrStorageUnknown, "Seek: invalid whence '%d'", whence)
	}
	if realOffset < 0 {
		return 0, errors.Annotatef(berrors.ErrStorageUnknown, "Seek in '%s': invalid offset to seek '%d'.", r.name, realOffset)
	}

	if realOffset == r.pos {
		return realOffset, nil
	} else if realOffset >= r.rangeInfo.Size {
		// See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
		// because s3's GetObject interface doesn't allow get a range that matches zero length data,
		// so if the position is out of range, we need to always return io.EOF after the seek operation.

		// close current read and open a new one which target offset
		if err := r.reader.Close(); err != nil {
			log.L().Warn("close s3 reader failed, will ignore this error", logutil.ShortError(err))
		}

		r.reader = io.NopCloser(bytes.NewReader(nil))
		r.pos = r.rangeInfo.Size
		return r.pos, nil
	}

	// if seek ahead no more than 64k, we discard these data
	if realOffset > r.pos && realOffset-r.pos <= maxSkipOffsetByRead {
		_, err := io.CopyN(io.Discard, r, realOffset-r.pos)
		if err != nil {
			return r.pos, errors.Trace(err)
		}
		return realOffset, nil
	}

	// close current read and open a new one which target offset
	err := r.reader.Close()
	if err != nil {
		return 0, errors.Trace(err)
	}

	newReader, info, err := r.storage.open(r.ctx, r.name, realOffset, 0)
	if err != nil {
		return 0, errors.Trace(err)
	}
	r.reader = newReader
	r.rangeInfo = info
	r.pos = realOffset
	return realOffset, nil
}

// CreateUploader create multi upload request.
func (rs *S3Storage) CreateUploader(ctx context.Context, name string) (ExternalFileWriter, error) {
	input := &s3.CreateMultipartUploadInput{
		Bucket: aws.String(rs.options.Bucket),
		Key:    aws.String(rs.options.Prefix + name),
	}
	if rs.options.Acl != "" {
		input = input.SetACL(rs.options.Acl)
	}
	if rs.options.Sse != "" {
		input = input.SetServerSideEncryption(rs.options.Sse)
	}
	if rs.options.SseKmsKeyId != "" {
		input = input.SetSSEKMSKeyId(rs.options.SseKmsKeyId)
	}
	if rs.options.StorageClass != "" {
		input = input.SetStorageClass(rs.options.StorageClass)
	}

	resp, err := rs.svc.CreateMultipartUploadWithContext(ctx, input)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &S3Uploader{
		svc:           rs.svc,
		createOutput:  resp,
		completeParts: make([]*s3.CompletedPart, 0, 128),
	}, nil
}

// Create creates multi upload request.
func (rs *S3Storage) Create(ctx context.Context, name string) (ExternalFileWriter, error) {
	uploader, err := rs.CreateUploader(ctx, name)
	if err != nil {
		return nil, err
	}
	uploaderWriter := newBufferedWriter(uploader, hardcodedS3ChunkSize, NoCompression)
	return uploaderWriter, nil
}

// Rename implements ExternalStorage interface.
func (rs *S3Storage) Rename(ctx context.Context, oldFileName, newFileName string) error {
	content, err := rs.ReadFile(ctx, oldFileName)
	if err != nil {
		return errors.Trace(err)
	}
	err = rs.WriteFile(ctx, newFileName, content)
	if err != nil {
		return errors.Trace(err)
	}
	if err = rs.DeleteFile(ctx, oldFileName); err != nil {
		return errors.Trace(err)
	}
	return nil
}

// retryerWithLog wrappes the client.DefaultRetryer, and logging when retry triggered.
type retryerWithLog struct {
	client.DefaultRetryer
}

func isDeadlineExceedError(err error) bool {
	// TODO find a better way.
	// Known challenges:
	//
	// If we want to unwrap the r.Error:
	// 1. the err should be an awserr.Error (let it be awsErr)
	// 2. awsErr.OrigErr() should be an *url.Error (let it be urlErr).
	// 3. urlErr.Err should be a http.httpError (which is private).
	//
	// If we want to reterive the error from the request context:
	// The error of context in the HTTPRequest (i.e. r.HTTPRequest.Context().Err() ) is nil.
	return strings.Contains(err.Error(), "context deadline exceeded")
}

func (rl retryerWithLog) ShouldRetry(r *request.Request) bool {
	if isDeadlineExceedError(r.Error) && r.HTTPRequest.URL.Host == ec2MetaAddress {
		// fast fail for unreachable linklocal address in EC2 containers.
		log.Warn("failed to get EC2 metadata. skipping.", logutil.ShortError(r.Error))
		return false
	}
	return rl.DefaultRetryer.ShouldRetry(r)
}

func (rl retryerWithLog) RetryRules(r *request.Request) time.Duration {
	backoffTime := rl.DefaultRetryer.RetryRules(r)
	if backoffTime > 0 {
		log.Warn("failed to request s3, retrying", zap.Error(r.Error), zap.Duration("backoff", backoffTime))
	}
	return backoffTime
}

func defaultS3Retryer() request.Retryer {
	return retryerWithLog{
		DefaultRetryer: client.DefaultRetryer{
			NumMaxRetries:    maxRetries,
			MinRetryDelay:    1 * time.Second,
			MinThrottleDelay: 2 * time.Second,
		},
	}
}


Anthony H. Cordesman's book, The Gulf War, was published in October 1994, and was the first comprehensive analysis of the strategic and military lessons of the Gulf War. Unlike previous studies, which concentrated primarily on the diplomatic and policy decisions affecting the war, or decisions at the high command level, Cordesman provides a detailed analysis of all of the military trends and actions that occurred during Desert Shield, a net assessment comparing Iraqi and each of the major Coalition military forces, and a detailed analysis of the history and lessons of each phase of Desert Storm.
Unlike books issued shortly after the war, or which focus largely on decisions at the high command level, Cordesman provides the first detailed analysis of the war that draws fully on the official histories and data bases the US government has issued in the years following the conflict. At the same time, he draws on his experience as ABC's military analyst during the Gulf War, tours of the battlefield shortly after the war, and extensive interviews with British, French, Saudi, and US officials and commanders.
The Gulf War is written as a reference book as well as an analysis and history. It draws largely on official data bases, many of which have never been fully published. It provides comprehensive tables, figures, and maps of the forces on each side, on the statistics and character of the fighting, and on the importance and effectiveness of key new weapons systems and tactics. The footnotes provide a research guide for further study in many areas, as well as citation that allow the reader to explore the additional material available in unpublished studies and data bases.
The Gulf War provides new data and insights into virtually every aspect of the war and the size and nature of the forces engaged. It examines each of the major new tactics and technologies that shaped the outcome the war. At the same time, Cordesman stresses the importance of human factors and the different levels of training and effectiveness of each major national contingent. His analysis not only examines the events of the Gulf War, but their implications for future conflict and the course of the "military revolution" that shaped much of the air campaign and air-land battle.
The Gulf War also provides a detailed and objective analysis of each of the major issues and debates affecting the war -- ranging from the problems intelligence analysts had in estimating the total size of total Iraqi forces to the debates over the effectiveness of the "Scud hunt" and the Patriot. New data are provided on the problems in the Coalition build-up, problems in tactical communications and intelligence, and on the true effectiveness of the F-117, Tomahawk, strategic bombing campaign, close air support, armored combat, heliborne assault forces, mine warfare systems, amphibious operations, friendly fire, reserve forces, and battle damage assessment efforts.
Separate chapters analyze command and control, intelligence, the battle for air supremacy, the offensive air campaign, the air-land battle, the key lessons of the land campaign, the war at sea, the battle against Iraq's Scud missiles and weapons of mass destruction, and the strategic and grand strategic lessons of the war. The book concludes with an analysis of the lessons of the war regarding deterrence, the use of decisive force, the role of coalition warfare and cooperative security, the importance of US and other Western power projection capabilities, the lessons of the war for counter-proliferation, and the implications of the war for regional warfare and countervailing strategy.