#pragma once
#include <iostream>
#include <math.h>
#include <assert.h>
//enum of interpolator to create the right one
enum interpolatorType{
linear,
inQuad,
outQuad,
inOutQuad,
inSine,
inCube,
inExpo,
};
class IInterpolator{
protected:
IInterpolator(){};
public:
virtual ~IInterpolator(){};
};
template <class T>
class interpolator : public IInterpolator{
protected:
T &interpolant;
public:
interpolator(T &_interpolant) :
interpolant(_interpolant){};
virtual ~interpolator(){};
virtual void Interpolate() = 0;
virtual bool Done() = 0;
};
template <class T>
class nullInterpolator : public interpolator<T>{
private:
T value;
public:
nullInterpolator(T &_interpolant, T _value) : interpolator(_interpolant), value(_value){};
void Interpolate(){
interpolant = value;
}
bool Done(){ return true; }
~nullInterpolator(){};
};
//any class that requires this kind of structure can use IeasingInterpolator as the base class
//to simplify life :P most easing interpolators have the same structure
template <class T, class stepType = double>
class IeasingInterpolator : public interpolator<T>{
protected:
stepType currentTime;
const stepType deltaTime;
const stepType totalTime;
T begin, delta;
const double pi;
virtual void _Interpolate() = 0;
public:
IeasingInterpolator(T &_interpolant, T begin, T end, stepType _totalTime, stepType _deltaTime = 1)
: interpolator(_interpolant), pi(3.14159265), totalTime(_totalTime), deltaTime(_deltaTime){
this->currentTime = 0;
this->begin = begin;
this->delta = end - begin;
this->interpolant = begin;
};
void Interpolate(){
currentTime += deltaTime;
currentTime = ::std::max(::std::min(currentTime, totalTime), (stepType)0.0);
_Interpolate();
};
virtual bool Done(){
int x = 0;
return currentTime >= totalTime;
}
virtual ~IeasingInterpolator(){};
};
template <class T, class stepType = double>
class linearInterpolator : public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
interpolant = ((delta * currentTime) / totalTime) + begin;
}
public:
linearInterpolator(T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1)
: IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~linearInterpolator(){};
};
template <class T, class stepType = double>
class inQuadInterpolator : public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
//t /= d; return c*t*t + b;
T newTime = currentTime / totalTime;
interpolant = (delta * newTime * newTime) + begin;
}
public:
inQuadInterpolator(T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~inQuadInterpolator(){};
};
template <class T, class stepType = double>
class outQuadInterpolator : public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
//-c*t*t/(d*d) + 2*c*t/d + b;
interpolant = (-1 * delta * currentTime * currentTime / (totalTime * totalTime)) +
((2 * delta * currentTime) / totalTime) + begin ;
}
public:
outQuadInterpolator (T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~outQuadInterpolator(){};
};
template <class T, class stepType = double>
class inOutQuadInterpolator : public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
/*
if (t < d/2) return 2*c*t*t/(d*d) + b;
var ts = t - d/2;
return -2*c*ts*ts/(d*d) + 2*c*ts/d + c/2 + b;
*/
if(currentTime < (totalTime / 2.0)){
interpolant = (2 * delta * currentTime * currentTime /(totalTime * totalTime)) + begin;
}else{
stepType ts = currentTime - (totalTime / 2.0);
interpolant = (-2 * delta * ts * ts / (totalTime * totalTime)) +
(2 * delta * (ts / totalTime)) + begin;
}
}
public:
inOutQuadInterpolator (T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~inOutQuadInterpolator(){};
};
template <class T, class stepType = double>
class inSineInterpolator: public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
/*
return -c * Math.cos(t/d * Math.PI/2) + c + b;
*/
interpolant = (-delta * cos( (currentTime / totalTime) * (pi / 2.0))) + delta + begin;
}
public:
inSineInterpolator(T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~inSineInterpolator(){};
};
template <class T, class stepType = double>
class inCubeInterpolator: public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
/*
t /= d;
return c*t*t*t + b;
*/
T newT = currentTime / totalTime;
interpolant = delta * pow(newT, 3) + begin;
//interpolant = (delta * cos( (currentTime / totalTime) * (pi / 2.0))) + delta + begin;
}
public:
inCubeInterpolator(T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~inCubeInterpolator(){};
};
template <class T, class stepType = double>
class inExpoInterpolator: public IeasingInterpolator<T, stepType>{
protected:
void _Interpolate(){
// t: current time, b: beginning value, c: change in value, d: duration
/*
return c * Math.pow( 2, 10 * (t/d - 1) ) + b;
*/
interpolant = delta * pow(2, 10 * (currentTime / totalTime - 1)) + begin;
//interpolant = (delta * cos( (currentTime / totalTime) * (pi / 2.0))) + delta + begin;
}
public:
inExpoInterpolator(T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = 1) :
IeasingInterpolator(_interpolant, begin, end, totalTime, deltaTime){};
~inExpoInterpolator(){};
};
//helper functions--------------------------------------------------------------------------------------
template<typename T, typename stepType>
IeasingInterpolator<T, stepType>* createEasingInterpolator(interpolatorType type,
T &_interpolant, T begin, T end, stepType totalTime, stepType deltaTime = (double)1.0){
switch(type)
{
case linear:
return new linearInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case inQuad:
return new inQuadInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case outQuad:
return new outQuadInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case inOutQuad:
return new inOutQuadInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case inSine:
return new inSineInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case inCube:
return new inCubeInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
case inExpo:
return new inExpoInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
break;
default:
assert(false && "wrong interpolant type given to CreateInterpolator");
return new linearInterpolator<T, stepType>(_interpolant, begin, end, totalTime, deltaTime);
}
}
I3ByYWdtYSBvbmNlCiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPG1hdGguaD4KI2luY2x1ZGUgPGFzc2VydC5oPgoKCi8vZW51bSBvZiBpbnRlcnBvbGF0b3IgdG8gY3JlYXRlIHRoZSByaWdodCBvbmUKZW51bSBpbnRlcnBvbGF0b3JUeXBlewogICAgbGluZWFyLAoJaW5RdWFkLAoJb3V0UXVhZCwKCWluT3V0UXVhZCwKCWluU2luZSwKCWluQ3ViZSwKCWluRXhwbywKfTsKCgoKY2xhc3MgSUludGVycG9sYXRvcnsKcHJvdGVjdGVkOgoJCUlJbnRlcnBvbGF0b3IoKXt9OwpwdWJsaWM6CgoJdmlydHVhbCB+SUludGVycG9sYXRvcigpe307Cn07CgoKdGVtcGxhdGUgPGNsYXNzIFQ+CmNsYXNzIGludGVycG9sYXRvciA6IHB1YmxpYyBJSW50ZXJwb2xhdG9yewpwcm90ZWN0ZWQ6CglUICZpbnRlcnBvbGFudDsKcHVibGljOgoJaW50ZXJwb2xhdG9yKFQgJl9pbnRlcnBvbGFudCkgOiAKCSAgaW50ZXJwb2xhbnQoX2ludGVycG9sYW50KXt9OwoKCXZpcnR1YWwgfmludGVycG9sYXRvcigpe307CgoJdmlydHVhbCB2b2lkIEludGVycG9sYXRlKCkgPSAwOwoJdmlydHVhbCBib29sIERvbmUoKSA9IDA7Cn07CgoKdGVtcGxhdGUgPGNsYXNzIFQ+CmNsYXNzIG51bGxJbnRlcnBvbGF0b3IgOiBwdWJsaWMgaW50ZXJwb2xhdG9yPFQ+ewpwcml2YXRlOgoJVCB2YWx1ZTsKcHVibGljOgoJbnVsbEludGVycG9sYXRvcihUICZfaW50ZXJwb2xhbnQsIFQgX3ZhbHVlKSA6IGludGVycG9sYXRvcihfaW50ZXJwb2xhbnQpLCB2YWx1ZShfdmFsdWUpe307Cgl2b2lkIEludGVycG9sYXRlKCl7CgkJaW50ZXJwb2xhbnQgPSB2YWx1ZTsKCX0KCglib29sIERvbmUoKXsJcmV0dXJuIHRydWU7IH0KCgl+bnVsbEludGVycG9sYXRvcigpe307Cn07CgoKLy9hbnkgY2xhc3MgdGhhdCByZXF1aXJlcyB0aGlzIGtpbmQgb2Ygc3RydWN0dXJlIGNhbiB1c2UgSWVhc2luZ0ludGVycG9sYXRvciBhcyB0aGUgYmFzZSBjbGFzcyAKLy90byBzaW1wbGlmeSBsaWZlIDpQIG1vc3QgZWFzaW5nIGludGVycG9sYXRvcnMgaGF2ZSB0aGUgc2FtZSBzdHJ1Y3R1cmUKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBJZWFzaW5nSW50ZXJwb2xhdG9yIDogcHVibGljIGludGVycG9sYXRvcjxUPnsKcHJvdGVjdGVkOgoJc3RlcFR5cGUgY3VycmVudFRpbWU7Cgljb25zdCBzdGVwVHlwZSBkZWx0YVRpbWU7Cgljb25zdCBzdGVwVHlwZSB0b3RhbFRpbWU7CglUIGJlZ2luLCBkZWx0YTsKCWNvbnN0ICBkb3VibGUgcGk7CgoJdmlydHVhbCB2b2lkIF9JbnRlcnBvbGF0ZSgpID0gMDsKcHVibGljOgoJSWVhc2luZ0ludGVycG9sYXRvcihUICZfaW50ZXJwb2xhbnQsIFQgYmVnaW4sIFQgZW5kLCBzdGVwVHlwZSBfdG90YWxUaW1lLCBzdGVwVHlwZSBfZGVsdGFUaW1lID0gMSkKCQk6IGludGVycG9sYXRvcihfaW50ZXJwb2xhbnQpLCBwaSgzLjE0MTU5MjY1KSwgdG90YWxUaW1lKF90b3RhbFRpbWUpLCBkZWx0YVRpbWUoX2RlbHRhVGltZSl7CgkKCQkKCQl0aGlzLT5jdXJyZW50VGltZSA9IDA7CgkJdGhpcy0+YmVnaW4gPSBiZWdpbjsKCQl0aGlzLT5kZWx0YSA9IGVuZCAtIGJlZ2luOwoJCXRoaXMtPmludGVycG9sYW50ID0gYmVnaW47Cgl9OwoKCXZvaWQgSW50ZXJwb2xhdGUoKXsKCQljdXJyZW50VGltZSArPSBkZWx0YVRpbWU7CgkJY3VycmVudFRpbWUgPSA6OnN0ZDo6bWF4KDo6c3RkOjptaW4oY3VycmVudFRpbWUsIHRvdGFsVGltZSksIChzdGVwVHlwZSkwLjApOwoJCQoJCV9JbnRlcnBvbGF0ZSgpOwoJfTsKCgl2aXJ0dWFsIGJvb2wgRG9uZSgpeyAKCQlpbnQgeCA9IDA7CgkJcmV0dXJuIGN1cnJlbnRUaW1lID49CXRvdGFsVGltZTsKCX0KCgl2aXJ0dWFsIH5JZWFzaW5nSW50ZXJwb2xhdG9yKCl7fTsKfTsKCgoKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBsaW5lYXJJbnRlcnBvbGF0b3IgOiBwdWJsaWMgSWVhc2luZ0ludGVycG9sYXRvcjxULCBzdGVwVHlwZT57CnByb3RlY3RlZDoKCXZvaWQgX0ludGVycG9sYXRlKCl7CgkJaW50ZXJwb2xhbnQgPSAoKGRlbHRhICogY3VycmVudFRpbWUpIC8gdG90YWxUaW1lKSArIGJlZ2luOwkKCX0KCnB1YmxpYzoKCWxpbmVhckludGVycG9sYXRvcihUICZfaW50ZXJwb2xhbnQsIFQgYmVnaW4sIFQgZW5kLCBzdGVwVHlwZSB0b3RhbFRpbWUsIHN0ZXBUeXBlIGRlbHRhVGltZSA9IDEpCgkJOiAgSWVhc2luZ0ludGVycG9sYXRvcihfaW50ZXJwb2xhbnQsIGJlZ2luLCBlbmQsIHRvdGFsVGltZSwgZGVsdGFUaW1lKXt9OwoKCQoJfmxpbmVhckludGVycG9sYXRvcigpe307Cn07CgoKCnRlbXBsYXRlIDxjbGFzcyBULCBjbGFzcyBzdGVwVHlwZSA9IGRvdWJsZT4KY2xhc3MgaW5RdWFkSW50ZXJwb2xhdG9yIDogcHVibGljIEllYXNpbmdJbnRlcnBvbGF0b3I8VCwgc3RlcFR5cGU+ewpwcm90ZWN0ZWQ6Cgl2b2lkIF9JbnRlcnBvbGF0ZSgpewoJCS8vIHQ6IGN1cnJlbnQgdGltZSwgYjogYmVnaW5uaW5nIHZhbHVlLCBjOiBjaGFuZ2UgaW4gdmFsdWUsIGQ6IGR1cmF0aW9uCgkJLy90IC89IGQ7IHJldHVybiBjKnQqdCArIGI7CgkJVCBuZXdUaW1lID0gY3VycmVudFRpbWUgLyB0b3RhbFRpbWU7CgkJaW50ZXJwb2xhbnQgPSAoZGVsdGEgKiBuZXdUaW1lICogbmV3VGltZSkgKyBiZWdpbjsKCQkKCX0KcHVibGljOgoJaW5RdWFkSW50ZXJwb2xhdG9yKFQgJl9pbnRlcnBvbGFudCwgVCBiZWdpbiwgVCBlbmQsIHN0ZXBUeXBlIHRvdGFsVGltZSwgc3RlcFR5cGUgZGVsdGFUaW1lID0gMSkgOiAKCUllYXNpbmdJbnRlcnBvbGF0b3IoX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSl7fTsKCgl+aW5RdWFkSW50ZXJwb2xhdG9yKCl7fTsKCQp9OwoKCgp0ZW1wbGF0ZSA8Y2xhc3MgVCwgY2xhc3Mgc3RlcFR5cGUgPSBkb3VibGU+CmNsYXNzIG91dFF1YWRJbnRlcnBvbGF0b3IgOiBwdWJsaWMgSWVhc2luZ0ludGVycG9sYXRvcjxULCBzdGVwVHlwZT57CnByb3RlY3RlZDoKCXZvaWQgX0ludGVycG9sYXRlKCl7CgkJLy8gdDogY3VycmVudCB0aW1lLCBiOiBiZWdpbm5pbmcgdmFsdWUsIGM6IGNoYW5nZSBpbiB2YWx1ZSwgZDogZHVyYXRpb24KCQkvLy1jKnQqdC8oZCpkKSArIDIqYyp0L2QgKyBiOwoJCWludGVycG9sYW50ID0gKC0xICogZGVsdGEgKiBjdXJyZW50VGltZSAqIGN1cnJlbnRUaW1lIC8gKHRvdGFsVGltZSAqIHRvdGFsVGltZSkpICsgCgkJCSgoMiAqIGRlbHRhICogY3VycmVudFRpbWUpIC8gdG90YWxUaW1lKSArIGJlZ2luIDsKCQkKCX0KCnB1YmxpYzoKCW91dFF1YWRJbnRlcnBvbGF0b3IgKFQgJl9pbnRlcnBvbGFudCwgVCBiZWdpbiwgVCBlbmQsIHN0ZXBUeXBlIHRvdGFsVGltZSwgc3RlcFR5cGUgZGVsdGFUaW1lID0gMSkgOiAKCUllYXNpbmdJbnRlcnBvbGF0b3IoX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSl7fTsKCgl+b3V0UXVhZEludGVycG9sYXRvcigpe307Cn07CgoKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBpbk91dFF1YWRJbnRlcnBvbGF0b3IgOiBwdWJsaWMgSWVhc2luZ0ludGVycG9sYXRvcjxULCBzdGVwVHlwZT57CnByb3RlY3RlZDoKCXZvaWQgX0ludGVycG9sYXRlKCl7CgkJLy8gdDogY3VycmVudCB0aW1lLCBiOiBiZWdpbm5pbmcgdmFsdWUsIGM6IGNoYW5nZSBpbiB2YWx1ZSwgZDogZHVyYXRpb24KCgkJLyoKCQlpZiAodCA8IGQvMikgcmV0dXJuIDIqYyp0KnQvKGQqZCkgKyBiOwoJCXZhciB0cyA9IHQgLSBkLzI7CgkJcmV0dXJuIC0yKmMqdHMqdHMvKGQqZCkgKyAyKmMqdHMvZCArIGMvMiArIGI7CgkJKi8KCgkJaWYoY3VycmVudFRpbWUgPCAodG90YWxUaW1lIC8gMi4wKSl7CgkJCWludGVycG9sYW50ID0gKDIgKiBkZWx0YSAqIGN1cnJlbnRUaW1lICogY3VycmVudFRpbWUgLyh0b3RhbFRpbWUgKiB0b3RhbFRpbWUpKSArIGJlZ2luOwoJCX1lbHNlewoJCQlzdGVwVHlwZSB0cyA9IGN1cnJlbnRUaW1lIC0gKHRvdGFsVGltZSAvIDIuMCk7CgoJCQlpbnRlcnBvbGFudCA9ICgtMiAqIGRlbHRhICogdHMgKiB0cyAvICh0b3RhbFRpbWUgKiB0b3RhbFRpbWUpKSArIAoJCQkJKDIgKiBkZWx0YSAqICh0cyAvIHRvdGFsVGltZSkpICsgYmVnaW47CgkJCgkJfQoJfQpwdWJsaWM6Cglpbk91dFF1YWRJbnRlcnBvbGF0b3IgKFQgJl9pbnRlcnBvbGFudCwgVCBiZWdpbiwgVCBlbmQsIHN0ZXBUeXBlIHRvdGFsVGltZSwgc3RlcFR5cGUgZGVsdGFUaW1lID0gMSkgOiAKCUllYXNpbmdJbnRlcnBvbGF0b3IoX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSl7fTsKCgl+aW5PdXRRdWFkSW50ZXJwb2xhdG9yKCl7fTsKfTsKCgoKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBpblNpbmVJbnRlcnBvbGF0b3I6IHB1YmxpYyBJZWFzaW5nSW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPnsKcHJvdGVjdGVkOgoJdm9pZCBfSW50ZXJwb2xhdGUoKXsKCQkvLyB0OiBjdXJyZW50IHRpbWUsIGI6IGJlZ2lubmluZyB2YWx1ZSwgYzogY2hhbmdlIGluIHZhbHVlLCBkOiBkdXJhdGlvbgoKCQkvKgoJCXJldHVybiAtYyAqIE1hdGguY29zKHQvZCAqIE1hdGguUEkvMikgKyBjICsgYjsKCQkqLwoJCWludGVycG9sYW50ID0gKC1kZWx0YSAqIGNvcyggKGN1cnJlbnRUaW1lIC8gdG90YWxUaW1lKSAqIChwaSAvIDIuMCkpKSArIGRlbHRhICsgYmVnaW47IAoJfQpwdWJsaWM6CglpblNpbmVJbnRlcnBvbGF0b3IoVCAmX2ludGVycG9sYW50LCBUIGJlZ2luLCBUIGVuZCwgc3RlcFR5cGUgdG90YWxUaW1lLCBzdGVwVHlwZSBkZWx0YVRpbWUgPSAxKSA6IAoJSWVhc2luZ0ludGVycG9sYXRvcihfaW50ZXJwb2xhbnQsIGJlZ2luLCBlbmQsIHRvdGFsVGltZSwgZGVsdGFUaW1lKXt9OwoKCX5pblNpbmVJbnRlcnBvbGF0b3IoKXt9Owp9OwoKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBpbkN1YmVJbnRlcnBvbGF0b3I6IHB1YmxpYyBJZWFzaW5nSW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPnsKcHJvdGVjdGVkOgoJdm9pZCBfSW50ZXJwb2xhdGUoKXsKCQkvLyB0OiBjdXJyZW50IHRpbWUsIGI6IGJlZ2lubmluZyB2YWx1ZSwgYzogY2hhbmdlIGluIHZhbHVlLCBkOiBkdXJhdGlvbgoKCQkvKgoJCXQgLz0gZDsKCQkJcmV0dXJuIGMqdCp0KnQgKyBiOwoJCSovCgkJVCBuZXdUID0gY3VycmVudFRpbWUgLyB0b3RhbFRpbWU7CgoJCWludGVycG9sYW50ID0gZGVsdGEgKiBwb3cobmV3VCwgMykgKyBiZWdpbjsKCQkvL2ludGVycG9sYW50ID0gKGRlbHRhICogY29zKCAoY3VycmVudFRpbWUgLyB0b3RhbFRpbWUpICogKHBpIC8gMi4wKSkpICsgZGVsdGEgKyBiZWdpbjsgCgl9CnB1YmxpYzoKCWluQ3ViZUludGVycG9sYXRvcihUICZfaW50ZXJwb2xhbnQsIFQgYmVnaW4sIFQgZW5kLCBzdGVwVHlwZSB0b3RhbFRpbWUsIHN0ZXBUeXBlIGRlbHRhVGltZSA9IDEpIDogCglJZWFzaW5nSW50ZXJwb2xhdG9yKF9pbnRlcnBvbGFudCwgYmVnaW4sIGVuZCwgdG90YWxUaW1lLCBkZWx0YVRpbWUpe307CgoJfmluQ3ViZUludGVycG9sYXRvcigpe307Cn07CgoKdGVtcGxhdGUgPGNsYXNzIFQsIGNsYXNzIHN0ZXBUeXBlID0gZG91YmxlPgpjbGFzcyBpbkV4cG9JbnRlcnBvbGF0b3I6IHB1YmxpYyBJZWFzaW5nSW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPnsKcHJvdGVjdGVkOgoJdm9pZCBfSW50ZXJwb2xhdGUoKXsKCQkvLyB0OiBjdXJyZW50IHRpbWUsIGI6IGJlZ2lubmluZyB2YWx1ZSwgYzogY2hhbmdlIGluIHZhbHVlLCBkOiBkdXJhdGlvbgoKCQkvKgoJCXJldHVybiBjICogTWF0aC5wb3coIDIsIDEwICogKHQvZCAtIDEpICkgKyBiOwoJCSovCgkJaW50ZXJwb2xhbnQgPSBkZWx0YSAqIHBvdygyLCAxMCAqIChjdXJyZW50VGltZSAvIHRvdGFsVGltZSAtIDEpKSArIGJlZ2luOwoJCS8vaW50ZXJwb2xhbnQgPSAoZGVsdGEgKiBjb3MoIChjdXJyZW50VGltZSAvIHRvdGFsVGltZSkgKiAocGkgLyAyLjApKSkgKyBkZWx0YSArIGJlZ2luOyAKCX0KcHVibGljOgoJaW5FeHBvSW50ZXJwb2xhdG9yKFQgJl9pbnRlcnBvbGFudCwgVCBiZWdpbiwgVCBlbmQsIHN0ZXBUeXBlIHRvdGFsVGltZSwgc3RlcFR5cGUgZGVsdGFUaW1lID0gMSkgOiAKCUllYXNpbmdJbnRlcnBvbGF0b3IoX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSl7fTsKCgl+aW5FeHBvSW50ZXJwb2xhdG9yKCl7fTsKfTsKCgovL2hlbHBlciBmdW5jdGlvbnMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUgc3RlcFR5cGU+CkllYXNpbmdJbnRlcnBvbGF0b3I8VCwgc3RlcFR5cGU+KiBjcmVhdGVFYXNpbmdJbnRlcnBvbGF0b3IoaW50ZXJwb2xhdG9yVHlwZSB0eXBlLCAKCVQgJl9pbnRlcnBvbGFudCwgVCBiZWdpbiwgVCBlbmQsIHN0ZXBUeXBlIHRvdGFsVGltZSwgc3RlcFR5cGUgZGVsdGFUaW1lID0gKGRvdWJsZSkxLjApewoKCQlzd2l0Y2godHlwZSkKCQl7CgkJY2FzZSBsaW5lYXI6CgkJCXJldHVybiBuZXcgbGluZWFySW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPihfaW50ZXJwb2xhbnQsIGJlZ2luLCBlbmQsIHRvdGFsVGltZSwgZGVsdGFUaW1lKTsKCQkJYnJlYWs7CgoJCWNhc2UgaW5RdWFkOgoJCQlyZXR1cm4gbmV3IGluUXVhZEludGVycG9sYXRvcjxULCBzdGVwVHlwZT4oX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSk7CgkJCWJyZWFrOwoKCQljYXNlIG91dFF1YWQ6CgkJCXJldHVybiBuZXcgb3V0UXVhZEludGVycG9sYXRvcjxULCBzdGVwVHlwZT4oX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSk7CgkJCWJyZWFrOwoKCQljYXNlIGluT3V0UXVhZDoKCQkJcmV0dXJuIG5ldyBpbk91dFF1YWRJbnRlcnBvbGF0b3I8VCwgc3RlcFR5cGU+KF9pbnRlcnBvbGFudCwgYmVnaW4sIGVuZCwgdG90YWxUaW1lLCBkZWx0YVRpbWUpOwoJCQlicmVhazsKCQljYXNlIGluU2luZToKCQkJcmV0dXJuIG5ldyBpblNpbmVJbnRlcnBvbGF0b3I8VCwgc3RlcFR5cGU+KF9pbnRlcnBvbGFudCwgYmVnaW4sIGVuZCwgdG90YWxUaW1lLCBkZWx0YVRpbWUpOwoJCQlicmVhazsKCgkJY2FzZSBpbkN1YmU6CgkJCXJldHVybiBuZXcgaW5DdWJlSW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPihfaW50ZXJwb2xhbnQsIGJlZ2luLCBlbmQsIHRvdGFsVGltZSwgZGVsdGFUaW1lKTsKCQkJYnJlYWs7CgkJY2FzZSBpbkV4cG86CgkJCXJldHVybiBuZXcgaW5FeHBvSW50ZXJwb2xhdG9yPFQsIHN0ZXBUeXBlPihfaW50ZXJwb2xhbnQsIGJlZ2luLCBlbmQsIHRvdGFsVGltZSwgZGVsdGFUaW1lKTsKCQkJYnJlYWs7CgkJZGVmYXVsdDoKCQkJYXNzZXJ0KGZhbHNlICYmICJ3cm9uZyBpbnRlcnBvbGFudCB0eXBlIGdpdmVuIHRvIENyZWF0ZUludGVycG9sYXRvciIpOwoJCQlyZXR1cm4gbmV3IGxpbmVhckludGVycG9sYXRvcjxULCBzdGVwVHlwZT4oX2ludGVycG9sYW50LCBiZWdpbiwgZW5kLCB0b3RhbFRpbWUsIGRlbHRhVGltZSk7CgkJfQp9