text:
Chinese Ship Locks Radar on Japanese Ship, Netizen Reactions
by Polly on Thursday, February 7, 2013 85 comments comments
Japanese Defence Minister Onodera Itsunori speaks to journalists at the Ministry of Defence on February 5.
On January 30 a Chinese ship locked what is assumed to be a fire-control radar onto a Japanese ship in the East China sea in the vicinity of the disputed Senkaku Islands. This week, the move has been strongly condemned by the Japanese government, who have confirmed that the Chinese ship directed a radar onto the Japanese warship "Yudachi" which could possibly have been used to guide weapons to the target.
Unsurprisingly given the continuous tension between the two nations, the story has been widely reported in the international press. Below, we bring you netizen reactions to this latest incident.
From Yahoo! Japan:
Chinese Ship Locks Target onto Japanese Vessel in East China Sea – Assertion of China's Claim to Senkaku Islands Through Intimidation?
On January 30, a Chinese Navy warship locked onto a Japanese Maritime Self Defence Force vessel with its weapon targeting radar in the East China Sea, the Ministry of Defence reported on February 5. It is believed that the radar targeted and followed the Japanese ship's movements, with the intent to be threatening to those on board.
Onodera Itsunori, the Minister of Defence, is reported as saying on February 5: "It is an extremely alarming situation where one wrong move could have resulted in a very dangerous situation." Territorial violations by Chinese patrol ships and aircraft have been frequent since the Japanese government's nationalisation of the Senkaku Islands; however, this latest incident is thought it be a step up from previous menacing behaviour by the Chinese Navy.
The Japanese defence vessel JS Yuudachi, DD-103.
According to the Ministry of Defence, at approximately 10 a.m. on January 30 in the East China Sea, the Chinese frigate Shanwei [Jiangwei] (Grade II) locked onto the Japanese patrol ship Yuudachi (based at the Sasebo military base, Nagasaki prefecture.)
Yuudachi and the Chinese ship were reported to have been 3 kilometres apart, and the Minister of Defence, Onodera said, "They were continually locked onto the Japanese ship for some time."
Comments from Yahoo! Japan:
zgh*bfg*f(zgh…)さん:
… They treat us with contempt, like always. We need to act fast to increase the defence budget and reform the law.
tou_rikugi(tou…)さん:
Please stop the welfare payments to foreigners.
I can't understand why we're giving money to people who come from our enemy's country. To the politicians and bureaucrats, please stop giving welfare payments to foreigners. Why are the politicians and bureaucrats giving our precious taxes to people of our enemies, Korea and China? Even though the taxes are rising for the Japanese people?
北斗のもの(hok…)さん:
We need to stop all assistance and aid to the chinks immediately.
tsu**shil*ck(tsu…)さん:
This is the same as a declaration of war!
It's a huge problem!
自称邦楽バカ(pin…)さん:
If you've got enough money to be using it for something like that, how about doing something about that air pollution?
Or how about fixing some of those bridges? (笑)
ゆうゆう(sky…)さん:
China's saying that Japan is eager for a war, but the truth is it's you guys! This is seriously irresponsible!
dfjdkfjd(djf…)さん:
Who gives a shit~! Sink the fuckers! The Japanese people won't mind.
ハワイ島(amk…)さん:
Stop screwing us around!
トワイライト(kas…)さん:
Don't you dare pay even one more yen towards the ODA [Official Development Assistance programme].
国憂未来模索(vic…)さん
China isn't an ally anymore so just retaliate already!
Show them the strength of Japan!
殿リーマン(tak…)さん:
These people are fucking nutjobs.
1984_The Natural(roy…)さん:
I feel sorry for the members of the Self Defence Forces and the coastal guard who are risking their lives for us.
We need to at least make provisions for war, and sooner rather than later.
3son*ck8*18(son…)さん:
If they locked onto us first, it's only fair that we do it back!
They're taking the piss because it's Japan. They would never do this kind of thing to America, because America would defend itself first.
They're lighting the smouldering embers of war…
pat*i*_tin(pat…)さん:
I hope the Self Defence Forces set up a permanent residence on the Senkaku Islands soon. It's obvious that the Chinese are going to attack at some point, regardless of what it'll do to their relationship with Japan.
ikimono(iki…)さん:
This is scary…
So they really do want to go to war with Japan…
大和魂(k_h…)さん:
They're really taking the piss now! If you back down now, you'll have serious questions to answer! Don't brush it off!
94Rothmans(rot…)さん:
This kind of threat is really overboard.
not*ro5*(not…)さん:
It's the proclamation of war from the idiot country that thinks too highly of itself.
グスク(gus…)さん:
Well, what are you going to do now? Abe administration.
You can't back out, so what will you do?
pea*h*511*55(pea…)さん
I wonder what would have happened if they had changed the flag from the Japanese one to the American one the moment they got targeted.
Japan Considering Release Of Chinese 'Radar Lock' Evidence
Chinese Military Instructed to 'Prepare For War' With Japan
Chinese Residents Urged To Leave Japan By Anxious Relatives
«Salaryman Lifestyle Blamed For Failing Japanese Companies
Teacher Loses Student's Passport For Trip, Netizens Outraged »


In the spring of 1999 I found myself washed up in the city of Montreal after drifting around the world for months with just a backpack, a journal and my appetite. I had no job, no prospects, save a flicker of romance with a 20-year-old engineering student.
I knew that I loved food, and wanted to work with it in some capacity, and I knew I needed to stay in Montreal.
Money was tight, and I enjoyed as many dinners as I could at my future mother-in-laws' table without wearing out my welcome. Still I always splurged (such as it was, back then) on the latest Saveur magazine.
Saveur understood my appetite for stories and recipes of food in all its contexts. It was a read that celebrated food culture and cuisine all around the world, and one that I cherished.
The love of travel never quite leaves your blood, and I would escape the tiny humdrum kitchens that I was trapped in by remembering the places I had visited in my recent journeys. The June '99 issue featured Paris, and while reading the article I recalled how the metro had smelled of croissants in the morning and the simple joys of strolling Rue du Montparnasse with a warm crêpe in hand.
Saveur magazine stroked the embers of those memories of traveling with each issue editor Colman Andrews released. Oh, and that stuff about no prospects? It all worked out in the long run.
Fast-forward fourteen years and you will find me still savoring a world of authentic cuisine on Saveur.com. There is no time to languish in the bath with a magazine anymore – no, not with three children under seven – and so I have to get my culinary travel fix in bits and bytes from the Saveur Instagram and Twitter feeds.
Come to think of it, that is how I catch up with pretty much everything in the world, on my iPhone screen, while nursing the baby or waiting in the car at school pick-up. That is just my simple life right now and that is okay.
Except for the part about flying to Vegas. To wine and dine with the Saveur editors. To accept a 2013 Best Food Blog Award. For Best Kids' Cooking Blog.
Let's backtrack a little first, shall we? Here -kindasorta- is how it played out.
The categories for Best Food Blog had changed from last year. Instead of Best Humor Food Blog or Best Celebrity Food Blog, Saveur now had Best New Blog and Best Kids' Cooking Blog.
Obviously Best Kids' Cooking category was of interest to me, as the definition stated that they were looking for "a blog that is written by or for kids, or that covers cooking for families or matters related to cooking for families".
I was also very aware of the stiff competition I had. Friendly competition, of course. My daily reads include some of the best kid's cooking blogs out there: Food for My Family. Shutterbean. The Naptime Chef. One Hungry Mama. Family Bites. Dine & Dish, and so. many. more.
Which is precisely why it didn't even occur to me to check the Saveur finalists. Not one bit. I was deep in preparation for the Food Bloggers of Canada conference when I received a congratulatory tweet from Michael. Thanks, man.
Astonishingly, Simple Bites was shortlisted by Saveur editors for a Best Food Blog Award, along with an absolutely amazing group of fellow 'mom bloggers'. Wow. That in itself was one of the biggest honors I have ever received.
Really. I was so happy that cooking for -and with- kids was getting some recognition. It's such an important message to bring to modern families.
Then there was a week or so of waiting – and hoping that people were voting. And being keenly aware that I didn't have anything specific to 'kids in the kitchen' on my site all week, but heck, that was the content that was scheduled, and so be it.
On Tuesday, in the middle of making supper with Clara at my feet and reviewing spelling words with Noah, a tweet came through. Impossibly. But there it was.
A shriek, followed by a very literal spatula-waving, apron-flapping dance in the kitchen. I may have tossed Clara into the air about 20 times. I hugged my kids so hard. Then we jumped on the bed.
My iPhone began dinging with texts. My twitter stream picked up the pace with words from so many kind people. I stammered something out on Facebook and dear friends and family who voted for me shared the news.
It was completely surreal. Danny arrived home with fresh tulips and mixed us a Gin & Tonic (which chased the margarita I had already finished, in all honesty). The kids didn't fully understand what we were celebrating, but it was an opportunity to have ice cream after dinner, so that was winning in their books.
To say this award is an honor sounds like a cliché, but I mean it from the bottom of my heart. It was an honor to be included with my fellow finalists, and it is a privilege to share the top honors with the winners from the other categories. My gosh, what. a. group.
This is turning out to be very lengthy indeed and I fear the orchestra is going to play me out soon, but before I go, if anyone is still reading, I need to say a few thank you's.
To Danny and the children, who inspire me daily, who eat every crumb of what I cook, and who are my every reason for breathing.
To Tsh. Who handed me this platform and set me free, to be creative, to experiment, to make it my blog. She's an incredible support and one heck of a mentor. And she's my date for the fête in Vegas.
To my contributors, who submit such stellar content, and bring their wisdom to this space every Wednesday.
To you, the readers. I'm going to risk one more cliché and say that if it wasn't for you, this blog would amount to a big old pile of beans. So, thank you for reading – and for voting.
Oh, and thank you SAVEUR! I suppose loyalty is rewarded in the end. It is in the end of this story, anyway.
Congratulations! I registered with Saveur Magazine just to vote for your great blog! I'm so glad that you won.
Wow! I so appreciate your vote! Thank you.
I'm so excited for you! Thank you for the kind mention, and please know that I'm thrilled to be one of your contributors. And Las Vegas? I had no idea, but I think you and Tsh are going to have a fabulous time!
Heck, even those of us who don't have kids love to read this site – your heartfelt posts have universal appeal, and it's a well-deserved honor. CONGRATS and have a great time in Vegas!
That's cool, Casey! Many thanks.
Congrats Aimee! I know you inspire me to cook real food for my kids, even if it doesn't specifically read kid's meal. Thanks for all the wonderful recipes and stories.
That is all I aspire to do. Thank you, Emily.
Congrats! This is so exciting! You should be so proud of yourself!! You deserve it!
And I'm going to check out those other blogs, too. Thanks for sharing them–I need to diversify Baguette's meals.
You will love them! And thanks.
Congrats Aimee!! I'm so happy that you won. Thanks for this wonderful space you have created!!!
Congratulations! Nothing motivates more than the success!
I voted in Saveur for your blog. Although I did not have much time to contribute in the comment sections of your post, I read your blog on regular basis and tested the small and big recipes. I must confide; most of the time the ideas were big hits in my family!
Thank you so much for being part of my life!!!
I trully believe you deserve this achievement.
I really appreciate your vote, so thanks! I know commenting takes time. I'm just happy that you are cooking. Honest.
Wonderful news, Aimee! I appreciate this blog—it's classy, and it has integrity. So proud!
Congrats – and like many other readers, no kids (mine are all grown and gone) but love your recipes but mostly your STYLE! BTW, I'm jealous of the way you started out. Many of us wish we had taken to time early to travel and flesh out our interests. It doesn't sound like you have any regrets – but then, you shouldn't!
Congratulations Aimee – you deserve the recognition, and I hope you enjoy dining at Le Cirque – it's amazing!! Just remember to ask for 3 extra boxes of their custom packaged complimentary chocolates for your kids – Jesse still plays with his beautiful box 2 years after I brought it home for him!
That is the most awesome tip ever. Thank you so much, Lisa!! Now I am soooo excited for Le Cirque. Whoa.
Congratulations! You really do a great job and deserve the recognition.
Congrats on this wonderful award! You've got my vote everyday! Have fun in LV!
I too signed up just to Vote! You have helped change my outlook on food and how easy it is to make it healthy for my family while having FUN!
Congratulations a millon times over! So awesome now you get to put the HUGE banner on your site that YOU ARE THE WINNER!!!
Thanks for your vote!!! Yes, the banner is huge. 😉 We're scaling it back soon.
I adore this post. The history, the way you write, and CONGRATS on the award!
Wow, congratulations! That's totally awesome!
I loved the backstory! =) I love the family celebration and a trip to Vegas, that sounds awesome!
Thanks for creating a lovely space that inspires me with my littles and also in my everyday to see the beauty.
Thanks for stopping by, Kelsey, and for your kind words. That means a lot!
I also love Saveur!! What a great place to win an award from!
Congratulations, you deserve it!!! Simple Bites is my favourite food blog!
Thank you, Lisa! That is amazing.
Congratulations, Aimee! You are so, so worthy of every mention you receive!
Thank you so much, Georgia. You're too kind.
congratulations! That shot of your kids is too fun.
Congratulations Aimee! I follow quite a few blogs, but I must say yours is one of my favorites! Revel in the glory, you deserve it.
Thank you, Carol! That is so sweet of you. Thank you for reading.
I'm so happy for you Aimée! You deserve this award every little bit. Your hard work and brilliance in the kitchen has paid off! I look up to you as a blogger, food lover and friend. Enjoy your time in Vegas with Tsh!
Congrats, Aimee! This is a well-deserved award! Keep up the beautiful work.
Joyful for you Aimee! It's a pleasure to be part of this little community (even just as a reader) – an honor well deserved.
Hooray! I'm a very regular reader. It was fun to vote for a blogger I feel I "know". I really appreciate all of the work and love you put into this space. Congratulations!
Congrats, Aimee! (And on the redesign, too—look at how gorgeous this place looks!!!) So well deserved. You're an inspiration to me and so many other moms with your gorgeous family, beautiful pictures, honest musings and, of course, delicious food.
Congratulations Aimee 🙂 you deserve it! Your kids are so adorable!
Awesome!! Congratulations and keep up the wonderful blogging.
I literally got chills reading this and could feel my heart beating harder with excitement for you. Huge congrats! You do amazing work and I always love reading what you have to say! Thank you so much for sharing your lives with us, and doing it so beautifully in the process.
Congratulations, and thank you for sharing the excitement of learning of your win! What an honour … enjoy!
Thank you, Liz!! I still can't believe it sometimes.


text:
Q: In SQL Server, how do I select IDs where value is in list, then insert matching IDs into join table? I am trying to connect a select and an insert in Query Manager
How can the two queries be tied together so that the insert happens for each match?
How can we call the results to verify that matching record IDs were inserted, and non-matching list items were not?
SELECT table1.ID
FROM    table1
WHERE table1.Name IN  ('Anne', 'Bob', 'Carol', 'Dave')

INSERT INTO joinTable
    (joinTable.table1_fk, joinTable.table2_fk)
VALUES (table1.ID,1)

A: The basic idea is to use insert . . . select.
INSERT INTO joinTable(table1_fk, table2_fk)
    SELECT table1.ID, 1
    FROM    table1
    WHERE table1.Name IN  ('Anne', 'Bob', 'Carol', 'Dave')

A: Q. How can the two queries be tied together so that the insert happens for each match?
A. To move data into an existing table as a result of a query, an INSERT INTO statement does the trick.
INSERT INTO joinTable ('table1_fk', 'table2_fk')
SELECT ID, 1
FROM table1
WHERE Name IN ('Anne', 'Bob', 'Carol', 'Dave')

http://www.w3schools.com/sql/sql_insert_into_select.asp
Q. How can we call the results to verify that matching record ids were inserted, and non-matching list items were not?
A. This is a single table SQL query...only those records that match the WHERE clause can be inserted.

redpajama_set_name: RedPajamaStackExchange


text:
#import "CPTXYPlotSpace.h"

#import "CPTAnimation.h"
#import "CPTAnimationOperation.h"
#import "CPTAnimationPeriod.h"
#import "CPTAxisSet.h"
#import "CPTExceptions.h"
#import "CPTGraph.h"
#import "CPTGraphHostingView.h"
#import "CPTMutablePlotRange.h"
#import "CPTPlot.h"
#import "CPTPlotArea.h"
#import "CPTPlotAreaFrame.h"
#import "CPTUtilities.h"
#import "NSCoderExtensions.h"
#import <tgmath.h>

/// @cond
@interface CPTXYPlotSpace()

-(CGFloat)viewCoordinateForViewLength:(NSDecimal)viewLength linearPlotRange:(CPTPlotRange *)range plotCoordinateValue:(NSDecimal)plotCoord;
-(CGFloat)viewCoordinateForViewLength:(CGFloat)viewLength linearPlotRange:(CPTPlotRange *)range doublePrecisionPlotCoordinateValue:(double)plotCoord;

-(CGFloat)viewCoordinateForViewLength:(CGFloat)viewLength logPlotRange:(CPTPlotRange *)range doublePrecisionPlotCoordinateValue:(double)plotCoord;

-(NSDecimal)plotCoordinateForViewLength:(NSDecimal)viewLength linearPlotRange:(CPTPlotRange *)range boundsLength:(NSDecimal)boundsLength;
-(double)doublePrecisionPlotCoordinateForViewLength:(CGFloat)viewLength linearPlotRange:(CPTPlotRange *)range boundsLength:(CGFloat)boundsLength;

-(double)doublePrecisionPlotCoordinateForViewLength:(CGFloat)viewLength logPlotRange:(CPTPlotRange *)range boundsLength:(CGFloat)boundsLength;

-(CPTPlotRange *)constrainRange:(CPTPlotRange *)existingRange toGlobalRange:(CPTPlotRange *)globalRange;
-(void)animateRangeForCoordinate:(CPTCoordinate)coordinate shift:(NSDecimal)shift momentumTime:(CGFloat)momentumTime speed:(CGFloat)speed acceleration:(CGFloat)acceleration;
-(CPTPlotRange *)shiftRange:(CPTPlotRange *)oldRange by:(NSDecimal)shift usingMomentum:(BOOL)momentum inGlobalRange:(CPTPlotRange *)globalRange withDisplacement:(CGFloat *)displacement;

-(CGFloat)viewCoordinateForRange:(CPTPlotRange *)range coordinate:(CPTCoordinate)coordinate direction:(BOOL)direction;

CGFloat firstPositiveRoot(CGFloat a, CGFloat b, CGFloat c);

@property (nonatomic, readwrite) BOOL isDragging;
@property (nonatomic, readwrite) CGPoint lastDragPoint;
@property (nonatomic, readwrite) CGPoint lastDisplacement;
@property (nonatomic, readwrite) NSTimeInterval lastDragTime;
@property (nonatomic, readwrite) NSTimeInterval lastDeltaTime;
@property (nonatomic, readwrite, retain) NSMutableArray *animations;

@end

/// @endcond

#pragma mark -

/**
 *  @brief A plot space using a two-dimensional cartesian coordinate system.
 *
 *  The @ref xRange and @ref yRange determine the mapping between data coordinates
 *  and the screen coordinates in the plot area. The @quote{end} of a range is
 *  the location plus its length. Note that the length of a plot range can be negative, so
 *  the end point can have a lesser value than the starting location.
 *
 *  The global ranges constrain the values of the @ref xRange and @ref yRange.
 *  Whenever the global range is set (non-@nil), the corresponding plot
 *  range will be adjusted so that it fits in the global range. When a new
 *  range is set to the plot range, it will be adjusted as needed to fit
 *  in the global range. This is useful for constraining scrolling, for
 *  instance.
 **/
@implementation CPTXYPlotSpace

/** @property CPTPlotRange *xRange
 *  @brief The range of the x coordinate. Defaults to a range with @link CPTPlotRange::location location @endlink zero (@num{0})
 *  and a @link CPTPlotRange::length length @endlink of one (@num{1}).
 *
 *  The @link CPTPlotRange::location location @endlink of the @ref xRange
 *  defines the data coordinate associated with the left edge of the plot area.
 *  Similarly, the @link CPTPlotRange::end end @endlink of the @ref xRange
 *  defines the data coordinate associated with the right edge of the plot area.
 **/
@synthesize xRange;

/** @property CPTPlotRange *yRange
 *  @brief The range of the y coordinate. Defaults to a range with @link CPTPlotRange::location location @endlink zero (@num{0})
 *  and a @link CPTPlotRange::length length @endlink of one (@num{1}).
 *
 *  The @link CPTPlotRange::location location @endlink of the @ref yRange
 *  defines the data coordinate associated with the bottom edge of the plot area.
 *  Similarly, the @link CPTPlotRange::end end @endlink of the @ref yRange
 *  defines the data coordinate associated with the top edge of the plot area.
 **/
@synthesize yRange;

/** @property CPTPlotRange *globalXRange
 *  @brief The global range of the x coordinate to which the @ref xRange is constrained.
 *
 *  If non-@nil, the @ref xRange and any changes to it will
 *  be adjusted so that it always fits within the @ref globalXRange.
 *  If @nil (the default), there is no constraint on x.
 **/
@synthesize globalXRange;

/** @property CPTPlotRange *globalYRange
 *  @brief The global range of the y coordinate to which the @ref yRange is constrained.
 *
 *  If non-@nil, the @ref yRange and any changes to it will
 *  be adjusted so that it always fits within the @ref globalYRange.
 *  If @nil (the default), there is no constraint on y.
 **/
@synthesize globalYRange;

/** @property CPTScaleType xScaleType
 *  @brief The scale type of the x coordinate. Defaults to #CPTScaleTypeLinear.
 **/
@synthesize xScaleType;

/** @property CPTScaleType yScaleType
 *  @brief The scale type of the y coordinate. Defaults to #CPTScaleTypeLinear.
 **/
@synthesize yScaleType;

/** @property BOOL allowsMomentum
 *  @brief If @YES, plot space scrolling in any direction slows down gradually rather than stopping abruptly. Defaults to @NO.
 **/
@dynamic allowsMomentum;

/** @property BOOL allowsMomentumX
 *  @brief If @YES, plot space scrolling in the x-direction slows down gradually rather than stopping abruptly. Defaults to @NO.
 **/
@synthesize allowsMomentumX;

/** @property BOOL allowsMomentumY
 *  @brief If @YES, plot space scrolling in the y-direction slows down gradually rather than stopping abruptly. Defaults to @NO.
 **/
@synthesize allowsMomentumY;

/** @property CPTAnimationCurve momentumAnimationCurve
 *  @brief The animation curve used to stop the motion of the plot ranges when scrolling with momentum. Defaults to #CPTAnimationCurveQuadraticOut.
 **/
@synthesize momentumAnimationCurve;

/** @property CPTAnimationCurve bounceAnimationCurve
 *  @brief The animation curve used to return the plot range back to the global range after scrolling. Defaults to #CPTAnimationCurveQuadraticOut.
 **/
@synthesize bounceAnimationCurve;

/** @property CGFloat momentumAcceleration
 *  @brief Deceleration in pixels/second^2 for momentum scrolling. Defaults to @num{2000.0}.
 **/
@synthesize momentumAcceleration;

/** @property CGFloat bounceAcceleration
 *  @brief Bounce-back acceleration in pixels/second^2 when scrolled past the global range. Defaults to @num{3000.0}.
 **/
@synthesize bounceAcceleration;

/** @property CGFloat minimumDisplacementToDrag
 *  @brief The minimum distance the interaction point must move before the event is considered a drag. Defaults to @num{2.0}.
 **/
@synthesize minimumDisplacementToDrag;

@dynamic isDragging;
@synthesize lastDragPoint;
@synthesize lastDisplacement;
@synthesize lastDragTime;
@synthesize lastDeltaTime;
@synthesize animations;

#pragma mark -
#pragma mark Init/Dealloc

/// @name Initialization
/// @{

/** @brief Initializes a newly allocated CPTXYPlotSpace object.
 *
 *  The initialized object will have the following properties:
 *  - @ref xRange = [@num{0}, @num{1}]
 *  - @ref yRange = [@num{0}, @num{1}]
 *  - @ref globalXRange = @nil
 *  - @ref globalYRange = @nil
 *  - @ref xScaleType = #CPTScaleTypeLinear
 *  - @ref yScaleType = #CPTScaleTypeLinear
 *  - @ref allowsMomentum = @NO
 *  - @ref allowsMomentumX = @NO
 *  - @ref allowsMomentumY = @NO
 *  - @ref momentumAnimationCurve = #CPTAnimationCurveQuadraticOut
 *  - @ref bounceAnimationCurve = #CPTAnimationCurveQuadraticOut
 *  - @ref momentumAcceleration = @num{2000.0}
 *  - @ref bounceAcceleration = @num{3000.0}
 *  - @ref minimumDisplacementToDrag = @num{2.0}
 *
 *  @return The initialized object.
 **/
-(instancetype)init
{
    if ( (self = [super init]) ) {
        xRange           = [[CPTPlotRange alloc] initWithLocation:CPTDecimalFromInteger(0) length:CPTDecimalFromInteger(1)];
        yRange           = [[CPTPlotRange alloc] initWithLocation:CPTDecimalFromInteger(0) length:CPTDecimalFromInteger(1)];
        globalXRange     = nil;
        globalYRange     = nil;
        xScaleType       = CPTScaleTypeLinear;
        yScaleType       = CPTScaleTypeLinear;
        lastDragPoint    = CGPointZero;
        lastDisplacement = CGPointZero;
        lastDragTime     = 0.0;
        lastDeltaTime    = 0.0;
        animations       = [[NSMutableArray alloc] init];

        allowsMomentumX           = NO;
        allowsMomentumY           = NO;
        momentumAnimationCurve    = CPTAnimationCurveQuadraticOut;
        bounceAnimationCurve      = CPTAnimationCurveQuadraticOut;
        momentumAcceleration      = 2000.0;
        bounceAcceleration        = 3000.0;
        minimumDisplacementToDrag = 2.0;
    }
    return self;
}

/// @}

#pragma mark -
#pragma mark NSCoding Methods

/// @cond

-(void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];

    [coder encodeObject:self.xRange forKey:@"CPTXYPlotSpace.xRange"];
    [coder encodeObject:self.yRange forKey:@"CPTXYPlotSpace.yRange"];
    [coder encodeObject:self.globalXRange forKey:@"CPTXYPlotSpace.globalXRange"];
    [coder encodeObject:self.globalYRange forKey:@"CPTXYPlotSpace.globalYRange"];
    [coder encodeInteger:self.xScaleType forKey:@"CPTXYPlotSpace.xScaleType"];
    [coder encodeInteger:self.yScaleType forKey:@"CPTXYPlotSpace.yScaleType"];
    [coder encodeBool:self.allowsMomentumX forKey:@"CPTXYPlotSpace.allowsMomentumX"];
    [coder encodeBool:self.allowsMomentumY forKey:@"CPTXYPlotSpace.allowsMomentumY"];
    [coder encodeInt:self.momentumAnimationCurve forKey:@"CPTXYPlotSpace.momentumAnimationCurve"];
    [coder encodeInt:self.bounceAnimationCurve forKey:@"CPTXYPlotSpace.bounceAnimationCurve"];
    [coder encodeCGFloat:self.momentumAcceleration forKey:@"CPTXYPlotSpace.momentumAcceleration"];
    [coder encodeCGFloat:self.bounceAcceleration forKey:@"CPTXYPlotSpace.bounceAcceleration"];
    [coder encodeCGFloat:self.minimumDisplacementToDrag forKey:@"CPTXYPlotSpace.minimumDisplacementToDrag"];

    // No need to archive these properties:
    // lastDragPoint
    // lastDisplacement
    // lastDragTime
    // lastDeltaTime
    // animations
}

-(instancetype)initWithCoder:(NSCoder *)coder
{
    if ( (self = [super initWithCoder:coder]) ) {
        xRange       = [[coder decodeObjectForKey:@"CPTXYPlotSpace.xRange"] copy];
        yRange       = [[coder decodeObjectForKey:@"CPTXYPlotSpace.yRange"] copy];
        globalXRange = [[coder decodeObjectForKey:@"CPTXYPlotSpace.globalXRange"] copy];
        globalYRange = [[coder decodeObjectForKey:@"CPTXYPlotSpace.globalYRange"] copy];
        xScaleType   = (CPTScaleType)[coder decodeIntegerForKey : @"CPTXYPlotSpace.xScaleType"];
        yScaleType   = (CPTScaleType)[coder decodeIntegerForKey : @"CPTXYPlotSpace.yScaleType"];

        if ( [coder containsValueForKey:@"CPTXYPlotSpace.allowsMomentum"] ) {
            self.allowsMomentum = [coder decodeBoolForKey:@"CPTXYPlotSpace.allowsMomentum"];
        }
        else {
            allowsMomentumX = [coder decodeBoolForKey:@"CPTXYPlotSpace.allowsMomentumX"];
            allowsMomentumY = [coder decodeBoolForKey:@"CPTXYPlotSpace.allowsMomentumY"];
        }
        momentumAnimationCurve    = (CPTAnimationCurve)[coder decodeIntForKey : @"CPTXYPlotSpace.momentumAnimationCurve"];
        bounceAnimationCurve      = (CPTAnimationCurve)[coder decodeIntForKey : @"CPTXYPlotSpace.bounceAnimationCurve"];
        momentumAcceleration      = [coder decodeCGFloatForKey:@"CPTXYPlotSpace.momentumAcceleration"];
        bounceAcceleration        = [coder decodeCGFloatForKey:@"CPTXYPlotSpace.bounceAcceleration"];
        minimumDisplacementToDrag = [coder decodeCGFloatForKey:@"CPTXYPlotSpace.minimumDisplacementToDrag"];

        lastDragPoint    = CGPointZero;
        lastDisplacement = CGPointZero;
        lastDragTime     = 0.0;
        lastDeltaTime    = 0.0;
        animations       = [[NSMutableArray alloc] init];
    }
    return self;
}

/// @endcond

#pragma mark -
#pragma mark Ranges

/// @cond

-(void)setPlotRange:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate
{
    switch ( coordinate ) {
        case CPTCoordinateX:
            self.xRange = newRange;
            break;

        case CPTCoordinateY:
            self.yRange = newRange;
            break;

        default:
            // invalid coordinate--do nothing
            break;
    }
}

-(CPTPlotRange *)plotRangeForCoordinate:(CPTCoordinate)coordinate
{
    CPTPlotRange *theRange = nil;

    switch ( coordinate ) {
        case CPTCoordinateX:
            theRange = self.xRange;
            break;

        case CPTCoordinateY:
            theRange = self.yRange;
            break;

        default:
            // invalid coordinate
            break;
    }

    return theRange;
}

-(void)setScaleType:(CPTScaleType)newType forCoordinate:(CPTCoordinate)coordinate
{
    switch ( coordinate ) {
        case CPTCoordinateX:
            self.xScaleType = newType;
            break;

        case CPTCoordinateY:
            self.yScaleType = newType;
            break;

        default:
            // invalid coordinate--do nothing
            break;
    }
}

-(CPTScaleType)scaleTypeForCoordinate:(CPTCoordinate)coordinate
{
    CPTScaleType theScaleType = CPTScaleTypeLinear;

    switch ( coordinate ) {
        case CPTCoordinateX:
            theScaleType = self.xScaleType;
            break;

        case CPTCoordinateY:
            theScaleType = self.yScaleType;
            break;

        default:
            // invalid coordinate
            break;
    }

    return theScaleType;
}

-(void)setXRange:(CPTPlotRange *)range
{
    NSParameterAssert(range);

    if ( ![range isEqualToRange:xRange] ) {
        CPTPlotRange *constrainedRange;

        if ( self.allowsMomentumX ) {
            constrainedRange = range;
        }
        else {
            constrainedRange = [self constrainRange:range toGlobalRange:self.globalXRange];
        }

        id<CPTPlotSpaceDelegate> theDelegate = self.delegate;
        if ( [theDelegate respondsToSelector:@selector(plotSpace:willChangePlotRangeTo:forCoordinate:)] ) {
            constrainedRange = [theDelegate plotSpace:self willChangePlotRangeTo:constrainedRange forCoordinate:CPTCoordinateX];
        }

        if ( ![constrainedRange isEqualToRange:xRange] ) {
            CGFloat displacement = self.lastDisplacement.x;
            BOOL isScrolling     = NO;

            if ( xRange && constrainedRange ) {
                isScrolling = !CPTDecimalEquals(constrainedRange.location, xRange.location) && CPTDecimalEquals(constrainedRange.length, xRange.length);

                if ( isScrolling && ( displacement == CPTFloat(0.0) ) ) {
                    CPTGraph *theGraph    = self.graph;
                    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

                    if ( plotArea ) {
                        NSDecimal rangeLength = constrainedRange.length;

                        if ( !CPTDecimalEquals( rangeLength, CPTDecimalFromInteger(0) ) ) {
                            NSDecimal diff = CPTDecimalDivide(CPTDecimalSubtract(constrainedRange.location, xRange.location), rangeLength);

                            displacement = plotArea.bounds.size.width * CPTDecimalCGFloatValue(diff);
                        }
                    }
                }
            }

            xRange = [constrainedRange copy];

            [[NSNotificationCenter defaultCenter] postNotificationName:CPTPlotSpaceCoordinateMappingDidChangeNotification
                                                                object:self
                                                              userInfo:@{ CPTPlotSpaceCoordinateKey: @(CPTCoordinateX),
                                                                          CPTPlotSpaceScrollingKey: @(isScrolling),
                                                                          CPTPlotSpaceDisplacementKey: @(displacement) }
            ];

            if ( [theDelegate respondsToSelector:@selector(plotSpace:didChangePlotRangeForCoordinate:)] ) {
                [theDelegate plotSpace:self didChangePlotRangeForCoordinate:CPTCoordinateX];
            }

            CPTGraph *theGraph = self.graph;
            if ( theGraph ) {
                [[NSNotificationCenter defaultCenter] postNotificationName:CPTGraphNeedsRedrawNotification
                                                                    object:theGraph];
            }
        }
    }
}

-(void)setYRange:(CPTPlotRange *)range
{
    NSParameterAssert(range);

    if ( ![range isEqualToRange:yRange] ) {
        CPTPlotRange *constrainedRange;

        if ( self.allowsMomentumY ) {
            constrainedRange = range;
        }
        else {
            constrainedRange = [self constrainRange:range toGlobalRange:self.globalYRange];
        }

        id<CPTPlotSpaceDelegate> theDelegate = self.delegate;
        if ( [theDelegate respondsToSelector:@selector(plotSpace:willChangePlotRangeTo:forCoordinate:)] ) {
            constrainedRange = [theDelegate plotSpace:self willChangePlotRangeTo:constrainedRange forCoordinate:CPTCoordinateY];
        }

        if ( ![constrainedRange isEqualToRange:yRange] ) {
            CGFloat displacement = self.lastDisplacement.y;
            BOOL isScrolling     = NO;

            if ( yRange && constrainedRange ) {
                isScrolling = !CPTDecimalEquals(constrainedRange.location, yRange.location) && CPTDecimalEquals(constrainedRange.length, yRange.length);

                if ( isScrolling && ( displacement == CPTFloat(0.0) ) ) {
                    CPTGraph *theGraph    = self.graph;
                    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

                    if ( plotArea ) {
                        NSDecimal rangeLength = constrainedRange.length;

                        if ( !CPTDecimalEquals( rangeLength, CPTDecimalFromInteger(0) ) ) {
                            NSDecimal diff = CPTDecimalDivide(CPTDecimalSubtract(constrainedRange.location, yRange.location), rangeLength);

                            displacement = plotArea.bounds.size.height * CPTDecimalCGFloatValue(diff);
                        }
                    }
                }
            }

            yRange = [constrainedRange copy];

            [[NSNotificationCenter defaultCenter] postNotificationName:CPTPlotSpaceCoordinateMappingDidChangeNotification
                                                                object:self
                                                              userInfo:@{ CPTPlotSpaceCoordinateKey: @(CPTCoordinateY),
                                                                          CPTPlotSpaceScrollingKey: @(isScrolling),
                                                                          CPTPlotSpaceDisplacementKey: @(displacement) }
            ];

            if ( [theDelegate respondsToSelector:@selector(plotSpace:didChangePlotRangeForCoordinate:)] ) {
                [theDelegate plotSpace:self didChangePlotRangeForCoordinate:CPTCoordinateY];
            }

            CPTGraph *theGraph = self.graph;
            if ( theGraph ) {
                [[NSNotificationCenter defaultCenter] postNotificationName:CPTGraphNeedsRedrawNotification
                                                                    object:theGraph];
            }
        }
    }
}

-(CPTPlotRange *)constrainRange:(CPTPlotRange *)existingRange toGlobalRange:(CPTPlotRange *)globalRange
{
    if ( !globalRange ) {
        return existingRange;
    }
    if ( !existingRange ) {
        return nil;
    }

    if ( CPTDecimalGreaterThanOrEqualTo(existingRange.length, globalRange.length) ) {
        return [globalRange copy];
    }
    else {
        CPTMutablePlotRange *newRange = [existingRange mutableCopy];
        [newRange shiftEndToFitInRange:globalRange];
        [newRange shiftLocationToFitInRange:globalRange];
        return newRange;
    }
}

-(void)animateRangeForCoordinate:(CPTCoordinate)coordinate shift:(NSDecimal)shift momentumTime:(CGFloat)momentumTime speed:(CGFloat)speed acceleration:(CGFloat)acceleration
{
    NSMutableArray *animationArray = self.animations;
    CPTAnimationOperation *op;

    NSString *property        = nil;
    CPTPlotRange *oldRange    = nil;
    CPTPlotRange *globalRange = nil;

    switch ( coordinate ) {
        case CPTCoordinateX:
            property    = @"xRange";
            oldRange    = self.xRange;
            globalRange = self.globalXRange;
            break;

        case CPTCoordinateY:
            property    = @"yRange";
            oldRange    = self.yRange;
            globalRange = self.globalYRange;
            break;

        default:
            break;
    }

    CPTMutablePlotRange *newRange = [oldRange mutableCopy];

    CGFloat bounceDelay = CPTFloat(0.0);
    NSDecimal zero      = CPTDecimalFromInteger(0);
    BOOL hasShift       = !CPTDecimalEquals(shift, zero);

    if ( hasShift ) {
        newRange.location = CPTDecimalAdd(newRange.location, shift);

        op = [CPTAnimation animate:self
                          property:property
                     fromPlotRange:oldRange
                       toPlotRange:newRange
                          duration:momentumTime
                    animationCurve:self.momentumAnimationCurve
                          delegate:self];
        [animationArray addObject:op];

        bounceDelay = momentumTime;
    }

    if ( globalRange ) {
        CPTPlotRange *constrainedRange = [self constrainRange:newRange toGlobalRange:globalRange];

        if ( ![newRange isEqualToRange:constrainedRange] && ![globalRange containsRange:newRange] ) {
            BOOL direction = ( CPTDecimalGreaterThan(shift, zero) && CPTDecimalGreaterThan(oldRange.length, zero) ) ||
                             ( CPTDecimalLessThan(shift, zero) && CPTDecimalLessThan(oldRange.length, zero) );

            // decelerate at the global range
            if ( hasShift ) {
                CGFloat brakingDelay = CPTFloat(NAN);

                if ( [globalRange containsRange:oldRange] ) {
                    // momentum started inside the global range; coast until we hit the global range
                    CGFloat globalPoint = [self viewCoordinateForRange:globalRange coordinate:coordinate direction:direction];
                    CGFloat oldPoint    = [self viewCoordinateForRange:oldRange coordinate:coordinate direction:direction];

                    CGFloat brakingOffset = globalPoint - oldPoint;
                    brakingDelay = firstPositiveRoot(acceleration, speed, brakingOffset);

                    if ( !isnan(brakingDelay) ) {
                        speed -= brakingDelay * acceleration;

                        // slow down quickly
                        while ( momentumTime > CPTFloat(0.1) ) {
                            acceleration *= CPTFloat(2.0);
                            momentumTime  = speed / (CPTFloat(2.0) * acceleration);
                        }

                        CGFloat distanceTraveled = speed * momentumTime - CPTFloat(0.5) * acceleration * momentumTime * momentumTime;
                        CGFloat brakingLength    = globalPoint - distanceTraveled;

                        CGPoint brakingPoint = CGPointZero;
                        switch ( coordinate ) {
                            case CPTCoordinateX:
                                brakingPoint = CPTPointMake(brakingLength, 0.0);
                                break;

                            case CPTCoordinateY:
                                brakingPoint = CPTPointMake(0.0, brakingLength);
                                break;

                            default:
                                break;
                        }

                        NSDecimal newPoint[2];
                        [self plotPoint:newPoint numberOfCoordinates:2 forPlotAreaViewPoint:brakingPoint];

                        NSDecimal brakingShift = CPTDecimalSubtract(newPoint[coordinate], direction ? globalRange.end : globalRange.location);

                        [newRange shiftEndToFitInRange:globalRange];
                        [newRange shiftLocationToFitInRange:globalRange];
                        newRange.location = CPTDecimalAdd(newRange.location, brakingShift);
                    }
                }
                else {
                    // momentum started outside the global range
                    brakingDelay = CPTFloat(0.0);

                    // slow down quickly
                    while ( momentumTime > CPTFloat(0.1) ) {
                        momentumTime *= CPTFloat(0.5);

                        shift = CPTDecimalDivide( shift, CPTDecimalFromInteger(2) );
                    }

                    newRange = [oldRange mutableCopy];

                    newRange.location = CPTDecimalAdd(newRange.location, shift);
                }

                if ( !isnan(brakingDelay) ) {
                    op = [CPTAnimation animate:self
                                      property:property
                                 fromPlotRange:constrainedRange
                                   toPlotRange:newRange
                                      duration:momentumTime
                                     withDelay:brakingDelay
                                animationCurve:self.momentumAnimationCurve
                                      delegate:self];
                    [animationArray addObject:op];

                    bounceDelay = momentumTime + brakingDelay;
                }
            }

            // bounce back to the global range
            CGFloat newPoint         = [self viewCoordinateForRange:newRange coordinate:coordinate direction:!direction];
            CGFloat constrainedPoint = [self viewCoordinateForRange:constrainedRange coordinate:coordinate direction:!direction];

            CGFloat offset = constrainedPoint - newPoint;

            CGFloat bounceTime = sqrt(ABS(offset) / self.bounceAcceleration);

            op = [CPTAnimation animate:self
                              property:property
                         fromPlotRange:newRange
                           toPlotRange:constrainedRange
                              duration:bounceTime
                             withDelay:bounceDelay
                        animationCurve:self.bounceAnimationCurve
                              delegate:self];
            [animationArray addObject:op];
        }
    }
}

-(CGFloat)viewCoordinateForRange:(CPTPlotRange *)range coordinate:(CPTCoordinate)coordinate direction:(BOOL)direction
{
    CPTCoordinate orthogonalCoordinate = CPTOrthogonalCoordinate(coordinate);

    NSDecimal point[2];

    point[coordinate]           = (direction ? range.maxLimit : range.minLimit);
    point[orthogonalCoordinate] = CPTDecimalFromInteger(1);

    CGPoint viewPoint       = [self plotAreaViewPointForPlotPoint:point numberOfCoordinates:2];
    CGFloat pointCoordinate = CPTFloat(NAN);

    switch ( coordinate ) {
        case CPTCoordinateX:
            pointCoordinate = viewPoint.x;
            break;

        case CPTCoordinateY:
            pointCoordinate = viewPoint.y;
            break;

        default:
            break;
    }

    return pointCoordinate;
}

// return NAN if no positive roots
CGFloat firstPositiveRoot(CGFloat a, CGFloat b, CGFloat c)
{
    CGFloat root = CPTFloat(NAN);

    CGFloat discriminant = sqrt(b * b - CPTFloat(4.0) * a * c);

    CGFloat root1 = (-b + discriminant) / (CPTFloat(2.0) * a);
    CGFloat root2 = (-b - discriminant) / (CPTFloat(2.0) * a);

    if ( !isnan(root1) && !isnan(root2) ) {
        if ( root1 >= CPTFloat(0.0) ) {
            root = root1;
        }
        if ( ( root2 >= CPTFloat(0.0) ) && ( isnan(root) || (root2 < root) ) ) {
            root = root2;
        }
    }

    return root;
}

-(void)setGlobalXRange:(CPTPlotRange *)newRange
{
    if ( ![newRange isEqualToRange:globalXRange] ) {
        globalXRange = [newRange copy];
        self.xRange  = [self constrainRange:self.xRange toGlobalRange:globalXRange];
    }
}

-(void)setGlobalYRange:(CPTPlotRange *)newRange
{
    if ( ![newRange isEqualToRange:globalYRange] ) {
        globalYRange = [newRange copy];
        self.yRange  = [self constrainRange:self.yRange toGlobalRange:globalYRange];
    }
}

-(void)scaleToFitPlots:(NSArray *)plots
{
    if ( plots.count == 0 ) {
        return;
    }

    // Determine union of ranges
    CPTMutablePlotRange *unionXRange = nil;
    CPTMutablePlotRange *unionYRange = nil;
    for ( CPTPlot *plot in plots ) {
        CPTPlotRange *currentXRange = [plot plotRangeForCoordinate:CPTCoordinateX];
        CPTPlotRange *currentYRange = [plot plotRangeForCoordinate:CPTCoordinateY];
        if ( !unionXRange ) {
            unionXRange = [currentXRange mutableCopy];
        }
        if ( !unionYRange ) {
            unionYRange = [currentYRange mutableCopy];
        }
        [unionXRange unionPlotRange:currentXRange];
        [unionYRange unionPlotRange:currentYRange];
    }

    // Set range
    NSDecimal zero = CPTDecimalFromInteger(0);
    if ( unionXRange ) {
        if ( CPTDecimalEquals(unionXRange.length, zero) ) {
            [unionXRange unionPlotRange:self.xRange];
        }
        self.xRange = unionXRange;
    }
    if ( unionYRange ) {
        if ( CPTDecimalEquals(unionYRange.length, zero) ) {
            [unionYRange unionPlotRange:self.yRange];
        }
        self.yRange = unionYRange;
    }
}

-(void)setXScaleType:(CPTScaleType)newScaleType
{
    if ( newScaleType != xScaleType ) {
        xScaleType = newScaleType;

        [[NSNotificationCenter defaultCenter] postNotificationName:CPTPlotSpaceCoordinateMappingDidChangeNotification
                                                            object:self
                                                          userInfo:@{ CPTPlotSpaceCoordinateKey: @(CPTCoordinateX) }
        ];

        CPTGraph *theGraph = self.graph;
        if ( theGraph ) {
            [[NSNotificationCenter defaultCenter] postNotificationName:CPTGraphNeedsRedrawNotification
                                                                object:theGraph];
        }
    }
}

-(void)setYScaleType:(CPTScaleType)newScaleType
{
    if ( newScaleType != yScaleType ) {
        yScaleType = newScaleType;

        [[NSNotificationCenter defaultCenter] postNotificationName:CPTPlotSpaceCoordinateMappingDidChangeNotification
                                                            object:self
                                                          userInfo:@{ CPTPlotSpaceCoordinateKey: @(CPTCoordinateY) }
        ];

        CPTGraph *theGraph = self.graph;
        if ( theGraph ) {
            [[NSNotificationCenter defaultCenter] postNotificationName:CPTGraphNeedsRedrawNotification
                                                                object:theGraph];
        }
    }
}

/// @endcond

#pragma mark -
#pragma mark Point Conversion (private utilities)

/// @cond

// Linear
-(CGFloat)viewCoordinateForViewLength:(NSDecimal)viewLength linearPlotRange:(CPTPlotRange *)range plotCoordinateValue:(NSDecimal)plotCoord
{
    if ( !range ) {
        return CPTFloat(0.0);
    }

    NSDecimal factor = CPTDecimalDivide(CPTDecimalSubtract(plotCoord, range.location), range.length);
    if ( NSDecimalIsNotANumber(&factor) ) {
        factor = CPTDecimalFromInteger(0);
    }

    NSDecimal viewCoordinate = CPTDecimalMultiply(viewLength, factor);

    return CPTDecimalCGFloatValue(viewCoordinate);
}

-(CGFloat)viewCoordinateForViewLength:(CGFloat)viewLength linearPlotRange:(CPTPlotRange *)range doublePrecisionPlotCoordinateValue:(double)plotCoord
{
    if ( !range || (range.lengthDouble == 0.0) ) {
        return CPTFloat(0.0);
    }
    return viewLength * (CGFloat)( (plotCoord - range.locationDouble) / range.lengthDouble );
}

-(NSDecimal)plotCoordinateForViewLength:(NSDecimal)viewLength linearPlotRange:(CPTPlotRange *)range boundsLength:(NSDecimal)boundsLength
{
    const NSDecimal zero = CPTDecimalFromInteger(0);

    if ( CPTDecimalEquals(boundsLength, zero) ) {
        return zero;
    }

    NSDecimal location = range.location;
    NSDecimal length   = range.length;

    NSDecimal coordinate;
    NSDecimalDivide(&coordinate, &viewLength, &boundsLength, NSRoundPlain);
    NSDecimalMultiply(&coordinate, &coordinate, &length, NSRoundPlain);
    NSDecimalAdd(&coordinate, &coordinate, &location, NSRoundPlain);

    return coordinate;
}

-(double)doublePrecisionPlotCoordinateForViewLength:(CGFloat)viewLength linearPlotRange:(CPTPlotRange *)range boundsLength:(CGFloat)boundsLength
{
    if ( boundsLength == 0.0 ) {
        return 0.0;
    }

    double coordinate = viewLength / boundsLength;
    coordinate *= range.lengthDouble;
    coordinate += range.locationDouble;

    return coordinate;
}

// Log (only one version since there are no transcendental functions for NSDecimal)
-(CGFloat)viewCoordinateForViewLength:(CGFloat)viewLength logPlotRange:(CPTPlotRange *)range doublePrecisionPlotCoordinateValue:(double)plotCoord
{
    if ( (range.minLimitDouble <= 0.0) || (range.maxLimitDouble <= 0.0) || (plotCoord <= 0.0) ) {
        return CPTFloat(0.0);
    }

    double logLoc   = log10(range.locationDouble);
    double logCoord = log10(plotCoord);
    double logEnd   = log10(range.endDouble);

    return viewLength * (CGFloat)( (logCoord - logLoc) / (logEnd - logLoc) );
}

-(double)doublePrecisionPlotCoordinateForViewLength:(CGFloat)viewLength logPlotRange:(CPTPlotRange *)range boundsLength:(CGFloat)boundsLength
{
    if ( boundsLength == 0.0 ) {
        return 0.0;
    }

    double logLoc = log10(range.locationDouble);
    double logEnd = log10(range.endDouble);

    double coordinate = viewLength * (logEnd - logLoc) / boundsLength + logLoc;

    return pow(10.0, coordinate);
}

/// @endcond

#pragma mark -
#pragma mark Point Conversion

/// @cond

-(NSUInteger)numberOfCoordinates
{
    return 2;
}

// Plot area view point for plot point
-(CGPoint)plotAreaViewPointForPlotPoint:(NSDecimal *)plotPoint numberOfCoordinates:(NSUInteger)count
{
    CGPoint viewPoint = [super plotAreaViewPointForPlotPoint:plotPoint numberOfCoordinates:count];

    CGSize layerSize;
    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

    if ( plotArea ) {
        layerSize = plotArea.bounds.size;
    }
    else {
        return viewPoint;
    }

    switch ( self.xScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            viewPoint.x = [self viewCoordinateForViewLength:plotArea.widthDecimal linearPlotRange:self.xRange plotCoordinateValue:plotPoint[CPTCoordinateX]];
            break;

        case CPTScaleTypeLog:
        {
            double x = CPTDecimalDoubleValue(plotPoint[CPTCoordinateX]);
            viewPoint.x = [self viewCoordinateForViewLength:layerSize.width logPlotRange:self.xRange doublePrecisionPlotCoordinateValue:x];
        }
        break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    switch ( self.yScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            viewPoint.y = [self viewCoordinateForViewLength:plotArea.heightDecimal linearPlotRange:self.yRange plotCoordinateValue:plotPoint[CPTCoordinateY]];
            break;

        case CPTScaleTypeLog:
        {
            double y = CPTDecimalDoubleValue(plotPoint[CPTCoordinateY]);
            viewPoint.y = [self viewCoordinateForViewLength:layerSize.height logPlotRange:self.yRange doublePrecisionPlotCoordinateValue:y];
        }
        break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    return viewPoint;
}

-(CGPoint)plotAreaViewPointForDoublePrecisionPlotPoint:(double *)plotPoint numberOfCoordinates:(NSUInteger)count
{
    CGPoint viewPoint = [super plotAreaViewPointForDoublePrecisionPlotPoint:plotPoint numberOfCoordinates:count];

    CGSize layerSize;
    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

    if ( plotArea ) {
        layerSize = plotArea.bounds.size;
    }
    else {
        return viewPoint;
    }

    switch ( self.xScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            viewPoint.x = [self viewCoordinateForViewLength:layerSize.width linearPlotRange:self.xRange doublePrecisionPlotCoordinateValue:plotPoint[CPTCoordinateX]];
            break;

        case CPTScaleTypeLog:
            viewPoint.x = [self viewCoordinateForViewLength:layerSize.width logPlotRange:self.xRange doublePrecisionPlotCoordinateValue:plotPoint[CPTCoordinateX]];
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    switch ( self.yScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            viewPoint.y = [self viewCoordinateForViewLength:layerSize.height linearPlotRange:self.yRange doublePrecisionPlotCoordinateValue:plotPoint[CPTCoordinateY]];
            break;

        case CPTScaleTypeLog:
            viewPoint.y = [self viewCoordinateForViewLength:layerSize.height logPlotRange:self.yRange doublePrecisionPlotCoordinateValue:plotPoint[CPTCoordinateY]];
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    return viewPoint;
}

// Plot point for view point
-(void)plotPoint:(NSDecimal *)plotPoint numberOfCoordinates:(NSUInteger)count forPlotAreaViewPoint:(CGPoint)point
{
    [super plotPoint:plotPoint numberOfCoordinates:count forPlotAreaViewPoint:point];

    CGSize boundsSize;
    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

    if ( plotArea ) {
        boundsSize = plotArea.bounds.size;
    }
    else {
        NSDecimal zero = CPTDecimalFromInteger(0);
        plotPoint[CPTCoordinateX] = zero;
        plotPoint[CPTCoordinateY] = zero;
        return;
    }

    switch ( self.xScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            plotPoint[CPTCoordinateX] = [self plotCoordinateForViewLength:CPTDecimalFromCGFloat(point.x) linearPlotRange:self.xRange boundsLength:plotArea.widthDecimal];
            break;

        case CPTScaleTypeLog:
            plotPoint[CPTCoordinateX] = CPTDecimalFromDouble([self doublePrecisionPlotCoordinateForViewLength:point.x logPlotRange:self.xRange boundsLength:boundsSize.width]);
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    switch ( self.yScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            plotPoint[CPTCoordinateY] = [self plotCoordinateForViewLength:CPTDecimalFromCGFloat(point.y) linearPlotRange:self.yRange boundsLength:plotArea.heightDecimal];
            break;

        case CPTScaleTypeLog:
            plotPoint[CPTCoordinateY] = CPTDecimalFromDouble([self doublePrecisionPlotCoordinateForViewLength:point.y logPlotRange:self.yRange boundsLength:boundsSize.height]);
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }
}

-(void)doublePrecisionPlotPoint:(double *)plotPoint numberOfCoordinates:(NSUInteger)count forPlotAreaViewPoint:(CGPoint)point
{
    [super doublePrecisionPlotPoint:plotPoint numberOfCoordinates:count forPlotAreaViewPoint:point];

    CGSize boundsSize;
    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

    if ( plotArea ) {
        boundsSize = plotArea.bounds.size;
    }
    else {
        plotPoint[CPTCoordinateX] = 0.0;
        plotPoint[CPTCoordinateY] = 0.0;
        return;
    }

    switch ( self.xScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            plotPoint[CPTCoordinateX] = [self doublePrecisionPlotCoordinateForViewLength:point.x linearPlotRange:self.xRange boundsLength:boundsSize.width];
            break;

        case CPTScaleTypeLog:
            plotPoint[CPTCoordinateX] = [self doublePrecisionPlotCoordinateForViewLength:point.x logPlotRange:self.xRange boundsLength:boundsSize.width];
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }

    switch ( self.yScaleType ) {
        case CPTScaleTypeLinear:
        case CPTScaleTypeCategory:
            plotPoint[CPTCoordinateY] = [self doublePrecisionPlotCoordinateForViewLength:point.y linearPlotRange:self.yRange boundsLength:boundsSize.height];
            break;

        case CPTScaleTypeLog:
            plotPoint[CPTCoordinateY] = [self doublePrecisionPlotCoordinateForViewLength:point.y logPlotRange:self.yRange boundsLength:boundsSize.height];
            break;

        default:
            [NSException raise:CPTException format:@"Scale type not supported in CPTXYPlotSpace"];
    }
}

// Plot area view point for event
-(CGPoint)plotAreaViewPointForEvent:(CPTNativeEvent *)event
{
    CGPoint plotAreaViewPoint = CGPointZero;

    CPTGraph *theGraph                  = self.graph;
    CPTGraphHostingView *theHostingView = theGraph.hostingView;
    CPTPlotArea *thePlotArea            = theGraph.plotAreaFrame.plotArea;

    if ( theHostingView && thePlotArea ) {
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        CGPoint interactionPoint = [[[event touchesForView:theHostingView] anyObject] locationInView:theHostingView];
        if ( theHostingView.collapsesLayers ) {
            interactionPoint.y = theHostingView.frame.size.height - interactionPoint.y;
            plotAreaViewPoint  = [theGraph convertPoint:interactionPoint toLayer:thePlotArea];
        }
        else {
            plotAreaViewPoint = [theHostingView.layer convertPoint:interactionPoint toLayer:thePlotArea];
        }
#else
        CGPoint interactionPoint = NSPointToCGPoint([theHostingView convertPoint:[event locationInWindow] fromView:nil]);
        plotAreaViewPoint = [theHostingView.layer convertPoint:interactionPoint toLayer:thePlotArea];
#endif
    }

    return plotAreaViewPoint;
}

// Plot point for event
-(void)plotPoint:(NSDecimal *)plotPoint numberOfCoordinates:(NSUInteger)count forEvent:(CPTNativeEvent *)event
{
    [self plotPoint:plotPoint numberOfCoordinates:count forPlotAreaViewPoint:[self plotAreaViewPointForEvent:event]];
}

-(void)doublePrecisionPlotPoint:(double *)plotPoint numberOfCoordinates:(NSUInteger)count forEvent:(CPTNativeEvent *)event
{
    [self doublePrecisionPlotPoint:plotPoint numberOfCoordinates:count forPlotAreaViewPoint:[self plotAreaViewPointForEvent:event]];
}

/// @endcond

#pragma mark -
#pragma mark Scaling

/// @cond

-(void)scaleBy:(CGFloat)interactionScale aboutPoint:(CGPoint)plotAreaPoint
{
    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;

    if ( !plotArea || (interactionScale <= 1.e-6) ) {
        return;
    }
    if ( ![plotArea containsPoint:plotAreaPoint] ) {
        return;
    }

    // Ask the delegate if it is OK
    id<CPTPlotSpaceDelegate> theDelegate = self.delegate;

    BOOL shouldScale = YES;
    if ( [theDelegate respondsToSelector:@selector(plotSpace:shouldScaleBy:aboutPoint:)] ) {
        shouldScale = [theDelegate plotSpace:self shouldScaleBy:interactionScale aboutPoint:plotAreaPoint];
    }
    if ( !shouldScale ) {
        return;
    }

    // Determine point in plot coordinates
    NSDecimal const decimalScale = CPTDecimalFromCGFloat(interactionScale);
    NSDecimal plotInteractionPoint[2];
    [self plotPoint:plotInteractionPoint numberOfCoordinates:2 forPlotAreaViewPoint:plotAreaPoint];

    // Cache old ranges
    CPTPlotRange *oldRangeX = self.xRange;
    CPTPlotRange *oldRangeY = self.yRange;

    // Lengths are scaled by the pinch gesture inverse proportional
    NSDecimal newLengthX = CPTDecimalDivide(oldRangeX.length, decimalScale);
    NSDecimal newLengthY = CPTDecimalDivide(oldRangeY.length, decimalScale);

    // New locations
    NSDecimal newLocationX;
    if ( CPTDecimalGreaterThanOrEqualTo( oldRangeX.length, CPTDecimalFromInteger(0) ) ) {
        NSDecimal oldFirstLengthX = CPTDecimalSubtract(plotInteractionPoint[CPTCoordinateX], oldRangeX.minLimit); // x - minX
        NSDecimal newFirstLengthX = CPTDecimalDivide(oldFirstLengthX, decimalScale);                              // (x - minX) / scale
        newLocationX = CPTDecimalSubtract(plotInteractionPoint[CPTCoordinateX], newFirstLengthX);
    }
    else {
        NSDecimal oldSecondLengthX = CPTDecimalSubtract(oldRangeX.maxLimit, plotInteractionPoint[0]); // maxX - x
        NSDecimal newSecondLengthX = CPTDecimalDivide(oldSecondLengthX, decimalScale);                // (maxX - x) / scale
        newLocationX = CPTDecimalAdd(plotInteractionPoint[CPTCoordinateX], newSecondLengthX);
    }

    NSDecimal newLocationY;
    if ( CPTDecimalGreaterThanOrEqualTo( oldRangeY.length, CPTDecimalFromInteger(0) ) ) {
        NSDecimal oldFirstLengthY = CPTDecimalSubtract(plotInteractionPoint[CPTCoordinateY], oldRangeY.minLimit); // y - minY
        NSDecimal newFirstLengthY = CPTDecimalDivide(oldFirstLengthY, decimalScale);                              // (y - minY) / scale
        newLocationY = CPTDecimalSubtract(plotInteractionPoint[CPTCoordinateY], newFirstLengthY);
    }
    else {
        NSDecimal oldSecondLengthY = CPTDecimalSubtract(oldRangeY.maxLimit, plotInteractionPoint[1]); // maxY - y
        NSDecimal newSecondLengthY = CPTDecimalDivide(oldSecondLengthY, decimalScale);                // (maxY - y) / scale
        newLocationY = CPTDecimalAdd(plotInteractionPoint[CPTCoordinateY], newSecondLengthY);
    }

    // New ranges
    CPTPlotRange *newRangeX = [[CPTPlotRange alloc] initWithLocation:newLocationX length:newLengthX];
    CPTPlotRange *newRangeY = [[CPTPlotRange alloc] initWithLocation:newLocationY length:newLengthY];

    BOOL oldMomentum = self.allowsMomentumX;
    self.allowsMomentumX = NO;
    self.xRange          = newRangeX;
    self.allowsMomentumX = oldMomentum;

    oldMomentum          = self.allowsMomentumY;
    self.allowsMomentumY = NO;
    self.yRange          = newRangeY;
    self.allowsMomentumY = oldMomentum;
}

/// @endcond

#pragma mark -
#pragma mark Interaction

/// @name User Interaction
/// @{

/**
 *  @brief Informs the receiver that the user has
 *  @if MacOnly pressed the mouse button. @endif
 *  @if iOSOnly touched the screen. @endif
 *
 *
 *  If the receiver has a @ref delegate and the delegate handles the event,
 *  this method always returns @YES.
 *  If @ref allowsUserInteraction is @NO
 *  or the graph does not have a @link CPTPlotAreaFrame::plotArea plotArea @endlink layer,
 *  this method always returns @NO.
 *  Otherwise, if the @par{interactionPoint} is within the bounds of the
 *  @link CPTPlotAreaFrame::plotArea plotArea @endlink, a drag operation starts and
 *  this method returns @YES.
 *
 *  @param event The OS event.
 *  @param interactionPoint The coordinates of the interaction.
 *  @return Whether the event was handled or not.
 **/
-(BOOL)pointingDeviceDownEvent:(CPTNativeEvent *)event atPoint:(CGPoint)interactionPoint
{
    self.isDragging = NO;

    BOOL handledByDelegate = [super pointingDeviceDownEvent:event atPoint:interactionPoint];
    if ( handledByDelegate ) {
        return YES;
    }

    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;
    if ( !self.allowsUserInteraction || !plotArea ) {
        return NO;
    }

    CGPoint pointInPlotArea = [theGraph convertPoint:interactionPoint toLayer:plotArea];
    if ( [plotArea containsPoint:pointInPlotArea] ) {
        // Handle event
        self.lastDragPoint    = pointInPlotArea;
        self.lastDisplacement = CGPointZero;
        self.lastDragTime     = event.timestamp;
        self.lastDeltaTime    = 0.0;

        // Clear any previous animations
        NSMutableArray *animationArray = self.animations;
        for ( CPTAnimationOperation *op in animationArray ) {
            [[CPTAnimation sharedInstance] removeAnimationOperation:op];
        }
        [animationArray removeAllObjects];

        return YES;
    }

    return NO;
}

/**
 *  @brief Informs the receiver that the user has
 *  @if MacOnly released the mouse button. @endif
 *  @if iOSOnly lifted their finger off the screen. @endif
 *
 *
 *  If the receiver has a @ref delegate and the delegate handles the event,
 *  this method always returns @YES.
 *  If @ref allowsUserInteraction is @NO
 *  or the graph does not have a @link CPTPlotAreaFrame::plotArea plotArea @endlink layer,
 *  this method always returns @NO.
 *  Otherwise, if a drag operation is in progress, it ends and
 *  this method returns @YES.
 *
 *  @param event The OS event.
 *  @param interactionPoint The coordinates of the interaction.
 *  @return Whether the event was handled or not.
 **/
-(BOOL)pointingDeviceUpEvent:(CPTNativeEvent *)event atPoint:(CGPoint)interactionPoint
{
    BOOL handledByDelegate = [super pointingDeviceUpEvent:event atPoint:interactionPoint];

    if ( handledByDelegate ) {
        return YES;
    }

    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;
    if ( !self.allowsUserInteraction || !plotArea ) {
        return NO;
    }

    if ( self.isDragging ) {
        self.isDragging = NO;

        CGFloat acceleration = CPTFloat(0.0);
        CGFloat speed        = CPTFloat(0.0);
        CGFloat momentumTime = CPTFloat(0.0);

        NSDecimal shiftX = CPTDecimalFromInteger(0);
        NSDecimal shiftY = CPTDecimalFromInteger(0);

        CGFloat scaleX = CPTFloat(0.0);
        CGFloat scaleY = CPTFloat(0.0);

        if ( self.allowsMomentum ) {
            NSTimeInterval deltaT     = event.timestamp - self.lastDragTime;
            NSTimeInterval lastDeltaT = self.lastDeltaTime;

            if ( (deltaT > 0.0) && (deltaT < 0.05) && (lastDeltaT > 0.0) ) {
                CGPoint pointInPlotArea = [theGraph convertPoint:interactionPoint toLayer:plotArea];
                CGPoint displacement    = self.lastDisplacement;

                acceleration = self.momentumAcceleration;
                speed        = sqrt(displacement.x * displacement.x + displacement.y * displacement.y) / CPTFloat(lastDeltaT);
                momentumTime = speed / (CPTFloat(2.0) * acceleration);
                CGFloat distanceTraveled = speed * momentumTime - CPTFloat(0.5) * acceleration * momentumTime * momentumTime;
                distanceTraveled = MAX( distanceTraveled, CPTFloat(0.0) );

                CGFloat theta = atan2(displacement.y, displacement.x);
                scaleX = cos(theta);
                scaleY = sin(theta);

                NSDecimal lastPoint[2], newPoint[2];
                [self plotPoint:lastPoint numberOfCoordinates:2 forPlotAreaViewPoint:pointInPlotArea];
                [self plotPoint:newPoint numberOfCoordinates:2 forPlotAreaViewPoint:CGPointMake(pointInPlotArea.x + distanceTraveled * scaleX,
                                                                                pointInPlotArea.y + distanceTraveled * scaleY)];

                if ( self.allowsMomentumX ) {
                    shiftX = CPTDecimalSubtract(lastPoint[CPTCoordinateX], newPoint[CPTCoordinateX]);
                }
                if ( self.allowsMomentumY ) {
                    shiftY = CPTDecimalSubtract(lastPoint[CPTCoordinateY], newPoint[CPTCoordinateY]);
                }
            }
        }

        // X range
        [self animateRangeForCoordinate:CPTCoordinateX
                                  shift:shiftX
                           momentumTime:momentumTime
                                  speed:speed * scaleX
                           acceleration:acceleration * scaleX];

        // Y range
        [self animateRangeForCoordinate:CPTCoordinateY
                                  shift:shiftY
                           momentumTime:momentumTime
                                  speed:speed * scaleY
                           acceleration:acceleration * scaleY];

        return YES;
    }

    return NO;
}

/**
 *  @brief Informs the receiver that the user has moved
 *  @if MacOnly the mouse with the button pressed. @endif
 *  @if iOSOnly their finger while touching the screen. @endif
 *
 *
 *  If the receiver has a @ref delegate and the delegate handles the event,
 *  this method always returns @YES.
 *  If @ref allowsUserInteraction is @NO
 *  or the graph does not have a @link CPTPlotAreaFrame::plotArea plotArea @endlink layer,
 *  this method always returns @NO.
 *  Otherwise, if a drag operation commences or is in progress, the @ref xRange
 *  and @ref yRange are shifted to follow the drag and
 *  this method returns @YES.
 *
 *  @param event The OS event.
 *  @param interactionPoint The coordinates of the interaction.
 *  @return Whether the event was handled or not.
 **/
-(BOOL)pointingDeviceDraggedEvent:(CPTNativeEvent *)event atPoint:(CGPoint)interactionPoint
{
    BOOL handledByDelegate = [super pointingDeviceDraggedEvent:event atPoint:interactionPoint];

    if ( handledByDelegate ) {
        return YES;
    }

    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;
    if ( !self.allowsUserInteraction || !plotArea ) {
        return NO;
    }

    CGPoint lastDraggedPoint = self.lastDragPoint;
    CGPoint pointInPlotArea  = [theGraph convertPoint:interactionPoint toLayer:plotArea];
    CGPoint displacement     = CPTPointMake(pointInPlotArea.x - lastDraggedPoint.x, pointInPlotArea.y - lastDraggedPoint.y);

    if ( !self.isDragging ) {
        // Have we started dragging, i.e., has the interactionPoint moved sufficiently to indicate a drag has started?
        CGFloat displacedBy = sqrt(displacement.x * displacement.x + displacement.y * displacement.y);
        self.isDragging = (displacedBy > self.minimumDisplacementToDrag);
    }

    if ( self.isDragging ) {
        CGPoint pointToUse = pointInPlotArea;

        id<CPTPlotSpaceDelegate> theDelegate = self.delegate;

        // Allow delegate to override
        if ( [theDelegate respondsToSelector:@selector(plotSpace:willDisplaceBy:)] ) {
            displacement = [theDelegate plotSpace:self willDisplaceBy:displacement];
            pointToUse   = CPTPointMake(lastDraggedPoint.x + displacement.x, lastDraggedPoint.y + displacement.y);
        }

        NSDecimal lastPoint[2], newPoint[2];
        [self plotPoint:lastPoint numberOfCoordinates:2 forPlotAreaViewPoint:lastDraggedPoint];
        [self plotPoint:newPoint numberOfCoordinates:2 forPlotAreaViewPoint:pointToUse];

        // X range
        NSDecimal shiftX        = CPTDecimalSubtract(lastPoint[CPTCoordinateX], newPoint[CPTCoordinateX]);
        CPTPlotRange *newRangeX = [self shiftRange:self.xRange
                                                 by:shiftX
                                      usingMomentum:self.allowsMomentumX
                                      inGlobalRange:self.globalXRange
                                   withDisplacement:&displacement.x];

        // Y range
        NSDecimal shiftY        = CPTDecimalSubtract(lastPoint[CPTCoordinateY], newPoint[CPTCoordinateY]);
        CPTPlotRange *newRangeY = [self shiftRange:self.yRange
                                                 by:shiftY
                                      usingMomentum:self.allowsMomentumY
                                      inGlobalRange:self.globalYRange
                                   withDisplacement:&displacement.y];

        self.lastDragPoint    = pointInPlotArea;
        self.lastDisplacement = displacement;

        NSTimeInterval currentTime = event.timestamp;
        self.lastDeltaTime = currentTime - self.lastDragTime;
        self.lastDragTime  = currentTime;

        self.xRange = newRangeX;
        self.yRange = newRangeY;

        return YES;
    }

    return NO;
}

-(CPTPlotRange *)shiftRange:(CPTPlotRange *)oldRange by:(NSDecimal)shift usingMomentum:(BOOL)momentum inGlobalRange:(CPTPlotRange *)globalRange withDisplacement:(CGFloat *)displacement
{
    CPTMutablePlotRange *newRange = [oldRange mutableCopy];

    newRange.location = CPTDecimalAdd(newRange.location, shift);

    if ( globalRange ) {
        CPTPlotRange *constrainedRange = [self constrainRange:newRange toGlobalRange:globalRange];

        if ( momentum ) {
            if ( ![newRange isEqualToRange:constrainedRange] ) {
                // reduce the shift as we get farther outside the global range
                NSDecimal rangeLength = newRange.length;

                if ( !CPTDecimalEquals( rangeLength, CPTDecimalFromInteger(0) ) ) {
                    NSDecimal diff = CPTDecimalDivide(CPTDecimalSubtract(constrainedRange.location, newRange.location), rangeLength);
                    diff = CPTDecimalMax( CPTDecimalMin( CPTDecimalMultiply( diff, CPTDecimalFromDouble(2.5) ), CPTDecimalFromInteger(1) ), CPTDecimalFromInteger(-1) );

                    newRange.location = CPTDecimalSubtract( newRange.location, CPTDecimalMultiply( shift, CPTDecimalAbs(diff) ) );

                    *displacement = *displacement * ( CPTFloat(1.0) - ABS( CPTDecimalCGFloatValue(diff) ) );
                }
            }
        }
        else {
            newRange = (CPTMutablePlotRange *)constrainedRange;
        }
    }

    return newRange;
}

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
#else

/**
 *  @brief Informs the receiver that the user has moved the scroll wheel.
 *
 *
 *  If the receiver does not have a @ref delegate,
 *  this method always returns @NO. Otherwise, the
 *  @link CPTPlotSpaceDelegate::plotSpace:shouldHandleScrollWheelEvent:fromPoint:toPoint: -plotSpace:shouldHandleScrollWheelEvent:fromPoint:toPoint: @endlink
 *  delegate method is called. If it returns @NO, this method returns @YES
 *  to indicate that the event has been handled and no further processing should occur.
 *
 *  @param event The OS event.
 *  @param fromPoint The starting coordinates of the interaction.
 *  @param toPoint The ending coordinates of the interaction.
 *  @return Whether the event was handled or not.
 **/
-(BOOL)scrollWheelEvent:(CPTNativeEvent *)event fromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint
{
    BOOL handledByDelegate = [super scrollWheelEvent:event fromPoint:fromPoint toPoint:toPoint];

    if ( handledByDelegate ) {
        return YES;
    }

    CPTGraph *theGraph    = self.graph;
    CPTPlotArea *plotArea = theGraph.plotAreaFrame.plotArea;
    if ( !self.allowsUserInteraction || !plotArea ) {
        return NO;
    }

    CGPoint fromPointInPlotArea = [theGraph convertPoint:fromPoint toLayer:plotArea];
    CGPoint toPointInPlotArea   = [theGraph convertPoint:toPoint toLayer:plotArea];
    CGPoint displacement        = CPTPointMake(toPointInPlotArea.x - fromPointInPlotArea.x, toPointInPlotArea.y - fromPointInPlotArea.y);
    CGPoint pointToUse          = toPointInPlotArea;

    id<CPTPlotSpaceDelegate> theDelegate = self.delegate;

    // Allow delegate to override
    if ( [theDelegate respondsToSelector:@selector(plotSpace:willDisplaceBy:)] ) {
        displacement = [theDelegate plotSpace:self willDisplaceBy:displacement];
        pointToUse   = CPTPointMake(fromPointInPlotArea.x + displacement.x, fromPointInPlotArea.y + displacement.y);
    }

    NSDecimal lastPoint[2], newPoint[2];
    [self plotPoint:lastPoint numberOfCoordinates:2 forPlotAreaViewPoint:fromPointInPlotArea];
    [self plotPoint:newPoint numberOfCoordinates:2 forPlotAreaViewPoint:pointToUse];

    // X range
    NSDecimal shiftX        = CPTDecimalSubtract(lastPoint[CPTCoordinateX], newPoint[CPTCoordinateX]);
    CPTPlotRange *newRangeX = [self shiftRange:self.xRange
                                             by:shiftX
                                  usingMomentum:NO
                                  inGlobalRange:self.globalXRange
                               withDisplacement:&displacement.x];

    // Y range
    NSDecimal shiftY        = CPTDecimalSubtract(lastPoint[CPTCoordinateY], newPoint[CPTCoordinateY]);
    CPTPlotRange *newRangeY = [self shiftRange:self.yRange
                                             by:shiftY
                                  usingMomentum:NO
                                  inGlobalRange:self.globalYRange
                               withDisplacement:&displacement.y];

    self.xRange = newRangeX;
    self.yRange = newRangeY;

    return YES;
}
#endif

/**
 *  @brief Reset the dragging state and cancel any active animations.
 **/
-(void)cancelAnimations
{
    self.isDragging = NO;
    for ( CPTAnimationOperation *op in self.animations ) {
        [[CPTAnimation sharedInstance] removeAnimationOperation:op];
    }
}

/// @}

#pragma mark -
#pragma mark Accessors

/// @cond

-(void)setAllowsMomentum:(BOOL)newMomentum
{
    self.allowsMomentumX = newMomentum;
    self.allowsMomentumY = newMomentum;
}

-(BOOL)allowsMomentum
{
    return self.allowsMomentumX || self.allowsMomentumY;
}

/// @endcond

#pragma mark -
#pragma mark Animation Delegate

/// @cond

-(void)animationDidFinish:(CPTAnimationOperation *)operation
{
    [self.animations removeObjectIdenticalTo:operation];
}

/// @endcond

@end

redpajama_set_name: RedPajamaGithub


1. Are the prices listed on line the same if I place my order by phone or fax?
No, there is a 5% up-charge, since it is more efficient to enter your order on line. Additionally, you have a hard copy of your order.
2. How long will it take before my order is shipped?
We make every effort to ship orders as soon as possible. However, an order may be delayed because it is and/or its components maybe out-of-stock, which is indicated on your printed order. On the day your order ships, you will be notified with a UPS generated e-mail, which includes your tracking number(s).
3. Is my credit card charged on line?
No, credit cards are only processed when your order ships. However before custom work is started, we pre-approve the credit card.
4. With so many cables to choose from, which one(s) is the correct product for my application?
5. I am looking for products not shown on line can you still help me.
Perhaps, so please direct your inquiries to quotations. Please note minimums may apply.
6. Do you have a return policy?
Yes, for stock parts only. Please see Return Policy for details.
All information, images, and documents on this website are the sole property of Cable X-Perts, Inc. Any reuse or redistribution of the contents of this website are strictly prohibited without authorization from Cable X-Perts, Inc.


 Mal Fletcher: Social Comment http://2020plus.net/Editorial.aspx en-gb Mal Fletcher Mal Fletcher's Social Comment is a short and concise editorial comment on a hot issue or event confronting society today Thu, 18 Apr 2019 20:25:54 GMT Thu, 18 Apr 2019 20:25:54 GMT 20 Should Social Media Carry Health Warnings? http://2020plus.net/Editorial-400-Mal-Fletcher-Should-Social-Media-Carry-Health-Warnings.aspx http://2020plus.net/Editorial-400-Mal-Fletcher-Should-Social-Media-Carry-Health-Warnings.aspx The social media juggernaut Facebook has reportedly acknowledged, albeit perhaps reluctantly, that engagement with its platform may potentially affect cognition or emotional wellbeing.
Faced with mounting international research revealing harmful side-effects, including addiction and depression, some social media groups have arguably acted as tobacco companies once did when they were confronted with claims about addiction and cancer. They have shrugged off the criticism with the notion that the evidence is inconclusive.
Now, in Facebook's case, a former executive has robustly touted the dangers. The company has offered a novel response. It says that while there is potential for unhealthy effects, the answer is yet more engagement online.
To overcome any potential negative effects, it suggests, one must spend even more time engaging on its platform, particularly with good friends, exchanging positive messages.
In the opinion of this writer, such a response shows a disregard for the already sizeable body of research into the dopamine-inducing impact of social media engagement.
Facebook is by no means alone in this. Though some of the research has often focused on Facebook, because it is the world's largest social media company, the results have been shown to be relevant to other social media platforms.
The research shows that social media activity releases small doses of dopamine, a chemical which is associated with alertness and feelings of pleasure, into the user's brain.
A little shot of this chemical, taken in isolation, may be fine but many small doses taken over time may provide the same cumulative impact as relatively large ones. This may lead to a problematic dependency and even addiction.
Another well documented potential by-product of social media use is feelings of depression and anxiety.
Few people will post their worst performances online for all the world to see. People tend to post what makes them and their situation present well to an audience - even if the audience is just one or two people.
Watching a constant stream of best-moments-or-ideas from multiple senders, whether they're personal friends or not, will slowly erode the confidence of even the most robust ego - perhaps with the exception of the clinically narcissistic or psychopathic ego.
It's high time social media operators fessed up to the impact their creations are potentially having on cognitive processes.
Technology in itself is not the problem. We are not a product of the technologies we use, but of how we choose the use them.
However, those who make money trading in personal data have a concomitant responsibility to their data providers. At the very least, they are ethically duty-bound to be honest and accountable about the potential impacts of their product.
We would be horrified if a drug company was allowed to amass a fortune by selling a product known to encourage any form of addiction or depression, without (at the very least) being required to announce the same on its packaging.
We'd be even more disturbed if the same drug provider offered a remedy that said, "Take more of our drug and you'll be fine."
We should be no less disturbed if social media platforms refuse to appropriately address these same side effects. Perhaps it is time such groups were treated as drug companies and required to carry health warnings.
Instead of offering remedies built on people doing more-of-the-same, Facebook - and arguably other social media companies - should be offering concise, accurate and consistent guidelines about keeping the useage habit in check and in the process protecting relationships and mindsets.
In many ways, these platforms offer a helpful, informative and entertaining service. However, they should be required to acknowledge and mitigate the dangers.
Perhaps social media platforms should feature a caution loosely based on one used by gaambling companies: "BEFORE the fun stops, stop!"


How will I know that you have shipped my order?
When your Keezel has been shipped, you will receive a notification to the email address you used to place your pre-order.
Will I be able to track the package once you've sent out my pre-order?
Yes, when your order has been shipped, you will receive an email with tracking information to the address you used to place the order.
How long will it take for the package to arrive once it's been shipped?
Depending on couriers and your delivery address, once it has begun shipment, it may take up to 2 weeks for your pre-order to arrive.
The shipping cost is calculated based on your delivery country during the checkout process and it will be added to your pre-order cost after you fill in your shipping information. Depending on your country, you may have to pay for additional levies, taxes or duties upon receiving.
What shipping options are available to me (standard, express, overnight etc)?
We currently only offer Standard shipping, but we are looking into adding more options in the near future.
Can I pick up my order at your office in Amsterdam?
No, the Keezels are all being sent out from our warehouses.
Yes, the Keezel ships internationally. Depending on your country, you may have to pay for additional levies, taxes or duties upon receiving.
Orders are currently being shipped from our warehouse in Hong Kong.


text:
CHRI - Commonwealth Human Rights Initiative calls for urgent independent inquiry into Rwandan gospel singer's death.
La Tribune Franco-Rwandaise — 19 Février 2020 — #Diplomatie, #Droits de l'homme, #Justice, #Rwanda, #Politique
CHRI calls for urgent independent inquiry into Rwandan gospel singer's death
February 19, 2020 The Commonwealth Human Rights Initiative (CHRI) today called for an assurance from Rwandan authorities of an independent inquiry into the death of Kizito Mihigo, a popular Rwandan
https://www.humanrightsinitiative.org/press-releases/chri-calls-for-urgent-independent-inquiry-into-rwandan-gospel-singers-death
The Commonwealth Human Rights Initiative (CHRI) today called for an assurance from Rwandan authorities of an independent inquiry into the death of Kizito Mihigo, a popular Rwandan gospel singer and government critic, who was found dead in police custody on Monday.
"An impartial and independent inquiry is needed in accordance with procedure established by law," said Alison Duxbury, Chairperson of CHRI's International Advisory Commission, pointing to Rwanda's obligations under Articles 9 and 14 of the International Covenant on Civil and Political Rights (ICCPR).
While noting that the Rwandan government is awaiting the conclusion of a post-mortem before confirming its initial reports of suicide, CHRI called for the conduct of a full and independent inquiry into the circumstances leading to his death. "Time is of the essence so that valuable evidence is not lost and that the investigation meets the ends of substantive justice", said Sanjoy Hazarika, International Director of CHRI.
Last week, the Rwanda Investigation Bureau tweeted that the security services had handed over Mr. Mihigo who was charged with "attempting to illegally cross into Burundi" in breach of the terms of his release from prison in 2018 "to join terrorist groups", as well as corruption, for attempting to bribe people living near the border according to Rwandan authorities.
In 2014, Mr. Mihigo was arrested for releasing a prohibited gospel song in which he prayed for victims of the genocide and victims of other violence. The following year, he was sentenced to 10 years in prison after being found guilty of conspiracy to murder or harm Rwandan President Paul Kagame and other senior government figures. He was also convicted of complicity to overthrow the government and conspiracy to form alliances with groups trying to destabilise the country. He was pardoned by Kagame in 2018 along with the opposition leader Victoire Ingabire Umuhoza.
Kigali is set to host the forthcoming Commonwealth Heads of Government Meeting in June.
Headquartered in New Delhi, with offices in London and Accra, CHRI is an independent, non-government, international, non-profit organisation committed to protecting and promoting human rights in Commonwealth nations. CHRI works towards strengthening access to justice (through prison and police reforms) and building a culture of transparent governance (through the Right to Information). CHRI also monitors human rights-related trends and developments across the Commonwealth and makes formal submissions to treaty bodies and inter-governmental agencies, including the United Nations Human Rights Council.
CHRI's International Board consists of Prof. Alison Duxbury of Australia, Mr. Wajahat Habibullah of India, Ms. Joanna Ewart-James of the UK, Mr. Sam Okudzeto of Ghana and Mr. Sanjoy Hazarika.
Sanjoy Hazarika, International Director,
RUCUNSHU KWA MUSEVENI. NI IBICIKA HAGATI YA JENERALI MUHOOZI NA SE.
DÉCLARATION DE SOUTIEN DU CADRE DE CONCERTATION DES BÂTISSEURS DU PONT INTER-RWANDAIS, RWANDA BRIDGE BUILDERS (RBB), AU PEUPLE CONGOLAIS FACE À LA GUERRE D'OCCUPATION IMPOSÉE PAR LE RÉGIME DE PAUL KAGAME
FOUR KEY NOTORIOUS ASSASSINS IN THE ARREST, INCARCERATION, PSYCHOLOGICAL TORTURE, INTERROGATION AND ELIMINATION OF GOSPEL SINGER KIZITO MIHIGO.
Rwanda : assassinat politique de l'artiste Kizito Mihigo.

redpajama_set_name: RedPajamaCommonCrawl


Professor Oliver Stoll from Leipzig is one of the most famous German sport psychologists. Furthermore the 52-year old is a passionate endurance athlete and in 2014 finisher of the "100 kilometers of Biel". With this running classic the idea was born which has now been published: "Once I have been to Biel – A declaration of love to running, to love and to life". Oliver tries to create an interconnection between science, sport psychology and the running everyday of hundreds of thousands of recreational athletes. We have talked to Oliver, who has been a guest lecturer at the LG Mauerweg e.V. before, about his new book and the Wall Race.
Oliver, you have already written some books. Why now this declaration of love to running?
Up to now I have written only textbooks and specialist books, thus books with a more or less academic focus. With the project of "Einmal war ich in Biel" (Once I have been to Biel) I wanted to try something completely new together with Frauke and Mathias Liebing, the editor. I don't know whether I succeeded, but it is an attempt to reveal sport-psychologic know-how in a rather non-academic way, but in a precise individual case, meaning my own running life. This is complemented by Frauke's point of view and my actions. Besides all this the form of publication (online – embedded in an own homepage) offers many advantages. The content is dynamic, although the core text will stay unchanged. But additional material can be exchanged and extended anytime. Finally this book is an hommage to my great passion of running and to Werner Sonntag who has inspired me a lot.
What is the value of benefit for the ambitious recreational athlete when reading your book?
That is up to the person reading. Of course, I can imagine a recreational athlete learning from my experiences in Biel (and my life before). But the book is not meant for consuming only, but also for reflection. A further value of benefit are of course the precise hints which I have illustrated in the additional material, i.e. how I have trained, what to take on the track, what self-developed mental tricks I have used to handle the inevitable pain and how to involve the social support of a partner for such a project realization.
The Wall Race is coming up. Is there the one special hint by the sport psychologist to pass to the participants on track?
Yes, 1) to be concerned with the course helps. One can develop a kind of mental script which then – if trained prior to the race – might help to arrange and structure the own thoughts when it is getting tough. 2) Always helpful is the right portion of easygoingness at the start. 160km is a long way. This might be disturbing if imagined at a stretch. One could divide the complete course into sections which are then worked off one at a time. 3) Don't forget the power of social support. One could invite friends and family to Berlin to meet them at the strategic important locations on the track.
Everyone has had this feeling of "I don't want to go any further" or the popular question for the meaning of it all on such a long course. What does the sport psychologist reply to those negative thoughts?
That is part of the book. Exhaustion and pain will definitely occur at one time or another. Then it is important to have the right thoughts handy in the form of self-talk. This can be developed and trained prior to the race, for example during long training runs when such experiences emerge to some extent.
After the 100km of Biel, have you ever thought about running the 100Meilen of Berlin?
🙂 In the Biel book I am very clear about this – and I say no, probably not again such a long track. But you know how it is. At the finish line you say "Never again", two weeks later "Well, maybe" and one month later the passionate runner is looking for the next challenge. At the moment I am off form and don't have the time for this, but I don't dare to exclude the chance. The Wall Race is clearly not only an athletic challenge, but has a cultural and historic dimension for us Germans. Considering this, I will definitely keep this run in mind.


text:
package jp.fieldnotes.hatunatu.dao.exception;

import jp.fieldnotes.hatunatu.util.exception.SRuntimeException;

public class NotFoundModifiedPropertiesRuntimeException extends
        SRuntimeException {

    private String beanClassName;

    public NotFoundModifiedPropertiesRuntimeException(
            final String beanClassName, final String propertyName) {
        super("EDAO0021", new Object[] { beanClassName, propertyName });
        this.beanClassName = beanClassName;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

}


text:
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCatego<caret>
</PreferenceScreen>