Chris Oliver's Weblog
- All
- F3
- JavaFX
- Programming
- Research
Key-Frame Animation
It's unfortunate that OpenJFX currently isn't a real open-source project. As such, it gives the appearance that progress isn't being made with JavaFX Script. Nevertheless, evolution has occurred, albeit internally.
I've worked on replacing the animation framework in JavaFX with something more complete and consistent. This was always intended to happen. The presently available animation mechanism (the "dur" operator) was a temporary solution added to F3 more than a year ago, was never thought to be an adequate solution, and clearly isn't to anyone who has ever actually tried to use it.
The supported animation idiom is now that of "Key Frame" animation, as in traditional animation and visual design tools. My view (after significant research) is that this same idiom is also the most effective technique for describing animations programmatically. The concept is that you describe the animated state transitions of your "scene" by declaring start and end "snapshots" of state at certain points in time, and declare interpolation functions to calculate the in-between states.
Given this input the system can automatically perform the animation, stop it, pause it, resume it, reverse it, or repeat it when requested. Thus it is a "declarative" animation technique.
Programmatically such "snapshots" consist of specifying the values for JavaFX variables - local variables and instance variables.
Here are some examples:
- Simple A very simple example, which demonstrates simultaneous animation of the rotation, scale, and fill color of a rectangle. Ball Consists of three concurrent repeating animations: one for the x coordinate of the ball, one which animates the y coordinate, and the one which animates the scale to create a "bounce" effect. See line 65 for the animations.
- Motomaxxve Consists of only one keyframe animation whose "position" is bound to a Slider, such that you can manually "play" it by moving the slider. Left-click on the content will play it forward, Right-click will reverse it. One interesting point is that the text animations are dynamically generated.
- EG Consists of several animations (fade, slide): one of which is a kind of ticker-tape view of the presenters at the 2007 "Entertainment Gathering" at the Getty Museum. The others support a slide show view.
- Poker Video poker game. Consists of two animations: 1 for the deal, and 1 for the draw, each of which animates the bet, turning over the cards, and scoring (if you have a winning hand).
You'll want to take a look at the examples for reference as you read the below, I think.
Time Literals
Since time is fundamental to animation, I've added time "literals" to the language. These are instances of the following primitive class:
public class Time extends java.lang.Comparable {
public attribute millis: Integer;
public attribute seconds: Number;
public attribute minutes: Number;
public attribute hours: Number;
public operation toMillis():Integer;
public operation add(other:Time):Time;
public operation subtract(other:Time):Time;
public operation multiplyBy(n:Number):Time;
public operation divideBy(n:Number):Time;
public operation equals(other): Boolean;
}
Numeric Literals with one of the suffixes (h, m, s, ms) are interpreted as Time literals, e.g:
2s == Time {seconds: 2}; // true
Relational operators and arithmetic operators other than % are overloaded for Time types:
2.5s < 5000ms; // true
2.5s * 3 == 7.5s; // true
Timelines
A KeyFrame describes a set of end states of various properties of objects at a certain time instant relative to the start of the animation, together with interpolation specifications to calculate the in-between values relative to the previous frame. Lack of an interpolation specification indicates a "discrete" animation, meaning the value of the property instantaneously transitions to the value given in the key frame at the time instant of the key frame. A Timeline is an object that contains a list of key frames, together with operations to control the overall animation, to start it, stop it. repeat it, etc.
Timelines are instances of the following class:
public class Timeline {
public attribute keyFrames: KeyFrame*;
public attribute repeatCount: Number;
public attribute autoReverse: Boolean;
public operation start();
public operation stop();
public operation pause();
public operation resume();
public operation reverseNow();
public attribute position: Number?; // unit time interval
}
where KeyFrame is:
public class KeyFrame {
public attribute time: Time;
public attribute keyValues: InterpolatedLValue*;
public attribute action: function()?;
public attribute timelines: TimeLine*; // included timelines
}
InterpolatedLValue has the following definition:
public class InterpolatedValue {
public attribute value: Object;
public attribute interpolate: function(values:Object*, unitTimeInterval:Number):Object?;
}
public class InterpolatedLValue extends InterpolatedValue {
public attribute target: &Object;
}
InterpolatedValue describes a pair (<value>, <interpolation_function>).
InterpolatedLValue describes a triple (<target property>, <value>, <interpolation function>).
Properties
Specification of the target property required adding "pointers" to the JavaFX script language. Pointer types are declared with the "&" symbol (as in the target attribute above), and pointer instances are obtained with the unary "&" operator and dereferenced with the unary "*" operator, as in C, e.g:
var x = 2;
var px = &x;
*px == 2; // true
*px = 3;
x == 3; // true
Properties in JavaFX are pointers to local variables or object attributes. In cases where these are "sequences" a pointer to an element of such a sequence is also a valid property.
Syntax
Although KeyFrame animations are normal JavaFX objects, special syntax is provided to make it easier to express than is possible with the standard object-literal syntax.
The "tween" operator is a a literal constructor for InterpolatedValue.
100 tween LINEAR;
is equivalent to
InterpolatedValue { value: 100, interpolate: LINEAR:Number }
The "=>" operator provides a literal constructor for a list of InterpolatedLValues:
var x = 2;
x => 100 tween LINEAR;
is equivalent to the following
var x = 2;
InterpolatedLValue {target: &x, value: 100, interpolate: LINEAR:Number};
However, you can also apply "=>" to a whole set of object properties using an object-literal like notation rather than just single property or variable, for example like this:
var rect = Rect {};
rect => {height: 400 tween EASEBOTH, width: 500, fill: blue tween LINEAR, clip: { shape: Rect => {height: 500, width: 600} };
The second line above is equivalent to this:
[InterpolatedLValue {
target: &rect.height
value: 500
interpolate: EASEBOTH:Number
},
InterpolatedLValue {
target: &rect.width
value: 500
interpolate: null
},
InterpolatedLValue {
target &rect.fill
value: blue:Color
interpolate: LINEAR:Color
},
InterpolatedLValue {
target: &((Rect)rect.clip.shape).height
value: 500
interpolate: null
},
InterpolatedLValue {
target: &((Rect)rect.clip.shape).width
value: 600
interpolate: null
}]
Finally, the "at" and "after" operators are literal constructors of KeyFrame objects:
var x = 2;
var rect = Rect {...};
at (2s) {
x => 2 tween LINEAR;
rect => {width: 400 tween EASEBOTH, fill: red tween EASEBOTH};
trigger {
println("at 2 seconds...");
}
}
after (5s) {
x => 100 tween EASEBOTH;
}
The "trigger" clause allows you to associate an arbitrary callback with the key frame.
The time specified by "at" is relative to the start of the Timeline. The time specified by "after" is relative to the previous key frame.
The first example above is equivalent to:
KeyFrame {
time: 2s
action: operation() { println("at 2 seconds..."); }
keyValues:
[InterpolatedLValue {
target &x
value: 2
interpolate: LINEAR:Number
},
InterpolatedLValue {
target: &rect.width
value: 400
interpolate: EASEBOTH:Number
},
InterpolatedLValue {
target: &rect.fill
value: red:Color
interpolate: EASEBOTH:Color
}]
}
Timelines and KeyFrames may be composed hierarchically - a KeyFrame may use the "include" operator to include any number of Timelines, in which case the key frames that make up the included timelines are merged into the containing timeline at the time instant of the key frame. The above "Ball" example demonstrates this, reproduced here:
var ax = Timeline {
// x
keyFrames:
[at (0s) {
x => 0;
},
at (10s) {
x => 700 tween LINEAR;
}]
autoReverse: true
repeatCount: INFINITY
}
var ay = Timeline {
// y
repeatCount: INFINITY
keyFrames:
[at (0s) {
y => 0;
},
at (2.2s) {
y => 375 tween SPLINE(0, 0, .5, 0);
},
at (2.25s) {
y => 375;
},
at (4.5s) {
y => 0 tween SPLINE(0, 0, 0, 0.5);
}]
}
var sxy = Timeline {
// scale x y
repeatCount: INFINITY
keyFrames:
[at (2.15s) {
sx => 1;
sy => 1;
},
at (2.25s) {
sx => 1.2 tween LINEAR;
sy => .7 tween LINEAR;
},
at (2.5s) {
sy => 1 tween LINEAR;
sx => 1 tween LINEAR;
},
at (4.5s) {
sx => 1;
sy => 1;
}]
}
var clip = Timeline {
repeatCount: INFINITY
keyFrames:
at (0s) {
include ax, ay, sxy;
}
}
In the above example, the "clip" timeline combines the other three animations. Playing "clip" will play all the animations simultaneously (yet still taking into account each ones individual repeat behavior).
Posted at 10:22AM Dec 20, 2007 by Christopher Oliver in JavaFX | Comments[103]
the "dur" operator was simple and clean that was it's beauty. Dont understand me wrong i like the Flash keyFrames i like the Flash as a tool for creating animations ( flex is good microsoft silverlight has a nice solution too ) and all they are keyframe oriented i like them but i like love the dur operator :) one line and u have it and it work ! :) so .. if you ask me ok make them keyFrame oriented if there is nice design tool but leave the "dur" too .. I like coding by hand.
Posted by JOKe on December 20, 2007 at 12:00 PM PST #
I'm not convinced by this approach. Too complicated to be productively usable, and the code itself is not very readable. And pointers - you gotta be kidding me! Is this still supposed to be a productive and easy to use language? You guys can do better then that!
Posted by Snowflake on December 20, 2007 at 01:34 PM PST #
Snowflake,
Pointers are not visible to the user - if you look at the examples.
It's a necessary implementation detail, however.
The examples given weren't necessarily designed to demonstrate the simplicity of the animation syntax, but rather the generality and credibility of it.
I've added an even simpler example, which shows an expression of a reversing, simultaneous scale, rotation, and color animation.
I personally, don't see how to make it easier than that. If you do, please let me know.
Try clicking on the rectangle while the animation is running.
Posted by Chris Oliver on December 20, 2007 at 03:17 PM PST #
It's good for you to admit you're not doing open source. The question is WHY???
You're pretty much undermining Sun overall open source effort by now doing this on a highly visible, yet far-from-baked project. I'm pretty sure it's actually hurting other open source projects at Sun.
Posted by John Doe on December 21, 2007 at 12:17 AM PST #
@John Doe
If you think I'm personally responsible for the fact that OpenJFX hasn't become a true open-source project, you're mistaken. That's the opposite of my personal recommendation.
On the plus side, the openjfx compiler project is a true open-source project, as is the new Java scene-graph project.
Hopefully, in the near future these will replace the current open-jfx binary code base.
Posted by Chris Oliver on December 21, 2007 at 11:25 AM PST #
@Patrick,
You can use variables in place of time literals:
var t1 = 0s;
var t2 = 1s
var t3 = 2s;
at (t1) {...}
at (t2) {...}
at (t3) {...}
Or any expression:
after (t3-t2) {...}
Posted by Chris Oliver on December 21, 2007 at 11:30 AM PST #
One recommendation from the peanut gallery: call them something other than pointers and use different symbols. People will mock the language for having "pointers" even though they're a different beast than their C counterparts.
Posted by 76.21.13.66 on December 21, 2007 at 09:48 PM PST #
Oncely your site is looks so nice for guests and have informations much more than the other blogs. I want to meet or conversation you
with msn, gtalk etc.
I think I have take so many informations from you.
Posted by youtube lig tv on August 25, 2008 at 04:06 AM PDT #
Dear Chris Oliver, please do not use pointers but use an "affect" keyword as the exact inverse of "bind". "bind" and "affect" with the optional "birectional" keyword (currently "with inverse") would be the complete and logical JavaFX replacement for references and pointers in e.g. C++. That is unless you want to scrap binding altogether in JavaFX.
Posted by Navigateur on September 09, 2008 at 02:13 AM PDT #
Let me revise that. Even better would be to make "bind" bidirectional by default, and use "affect" and "take" as the unidirectional binds in each direction. That would prevent any redundancy and/or confusion. Regards, N
Posted by Navigateur on September 10, 2008 at 01:02 AM PDT #
http://www.batterylaptoppower.com/toshiba/satellite-1900.htm toshiba satellite 1900 battery,
http://www.batterylaptoppower.com/toshiba/satellite-1905.htm toshiba satellite 1905 battery,
http://www.batterylaptoppower.com/toshiba/pa3383u-1brs.htm toshiba pa3383u-1brs battery,
http://www.batterylaptoppower.com/toshiba/pa3383u.htm toshiba pa3383u battery,
http://www.batterylaptoppower.com/toshiba/satellite-a70.htm toshiba satellite a70 battery,
http://www.batterylaptoppower.com/toshiba/satellite-p30.htm toshiba satellite p30 battery,
http://www.batterylaptoppower.com/toshiba/satellite-p35.htm toshiba satellite p35 battery,
http://www.batterylaptoppower.com/toshiba/pa3382u-1bas.htm toshiba pa3382u-1bas battery,
http://www.batterylaptoppower.com/toshiba/pa3384u-1bas.htm toshiba pa3384u-1bas battery,
Posted by ANITA BANULIS on November 07, 2008 at 11:39 PM PST #
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
http://www.yayinakisi.com/dizi.php
Posted by dizi izle on December 01, 2008 at 07:39 PM PST #
<a href="http://www.yayinakisi.com/dizi.php" title="dizi izle">dizi izle</a>
thanks
Posted by dizi izle on December 01, 2008 at 07:40 PM PST #
thanks you..
Posted by dizi izle on December 25, 2008 at 02:55 PM PST #
thanks..
Posted by backlink sorgu on December 25, 2008 at 02:56 PM PST #
Bir KeyFrame, canlandırmanın başlangıcına göreli olarak kesin bir zaman anında nesnelerin çeşitli mallarının son durumlarının bir takımını tanımlar, arada içini hesaplamak için araya koyma tanımlamalarıyla beraber, önceki yapıya göreli olarak değer biçer. Bir araya koyma tanımlaması eksikliği, bir "Ayrı" canlandırmasını gösterir, aniden anahtar yapıda o zaman anahtar yapının anı verilen değere geçişlerin olduğu malın değerini ifade etmek. Bir zaman çizgisi, anahtar yapıların bir listesini içeren bir nesnedir, o başlamak, toplam canlandırmayı kontrol etmek için çalışmalarla beraber, onu durdurur. Onu tekrarla, vb.
Posted by dış cephe on December 25, 2008 at 02:59 PM PST #
türkçe açtığınız için teçekürler konuyu..
Posted by evden eve nakliyat on December 25, 2008 at 03:00 PM PST #
Daha zeytine ait sevgili Chris, lütfen göstergeleri kullanmaz, ama "Kızgınlık"'ın tam tersi olarak bir "Etkile" anahtar sözcüğünü kullanır. Seçmeli "Birectional"'la anahtar sözcük "Kızgınlık" ve "Etkile" (Güncel olarak "Tersle"), referanslar için tam ve mantıklı JavaFX değiştirmesi ve mesela C'de göstergeler ++ olacaktı. Odur, eğer sen, JavaFX'da neticede bağlamayı hurdaya çıkarmayı istemezsen.
Posted by bariyer on December 25, 2008 at 03:02 PM PST #
thanks..
Posted by izmir evden eve on January 01, 2009 at 08:26 AM PST #
paylaşım için teşekkürler..
Posted by evden eve on January 01, 2009 at 08:27 AM PST #
Thanks..
Posted by backlink sorgu on January 11, 2009 at 10:57 AM PST #
Thanks..
Posted by izmir evden eve on February 01, 2009 at 11:42 AM PST #
thanks you..
Posted by korkuluk on February 02, 2009 at 06:08 AM PST #
thanks you..
Posted by kanal açma on February 02, 2009 at 11:19 AM PST #
Dear Chris Oliver, please do not use pointers but use an "affect" keyword as the exact inverse of "bind". "bind" and "affect" with the optional "birectional" keyword (currently "with inverse") would be the complete and logical JavaFX replacement for references and pointers in e.g. C++. That is unless you want to scrap binding altogether in JavaFX.
Posted by Manavgat, side on February 08, 2009 at 05:01 AM PST #
thanks you..
Posted by boğaz turları on February 09, 2009 at 11:42 PM PST #
thansk you..
Posted by bursa evden eve nakliyat on February 12, 2009 at 03:22 AM PST #
paylaşım için teşekür ederim..
Posted by bursa evden eve nakliyat on February 18, 2009 at 03:53 AM PST #
paylaşım için teşekür ederim.
Posted by izmir evden eve on February 20, 2009 at 01:38 PM PST #
thanks you..
Posted by parça kontör on February 22, 2009 at 01:04 PM PST #
Thank You..
Posted by izmirde evden eve on March 23, 2009 at 04:58 AM PDT #
Thank You..
Posted by firma rehberi on April 05, 2009 at 11:18 PM PDT #
thanksss
Posted by alem on April 08, 2009 at 10:23 AM PDT #
thanksss
Posted by izmir on April 08, 2009 at 10:24 AM PDT #
thanksss
Posted by forum on April 08, 2009 at 10:24 AM PDT #
thankssss
Posted by izmir evden eve on April 15, 2009 at 12:30 PM PDT #
Thank You..
Posted by cam balkon on April 23, 2009 at 12:25 PM PDT #
Thank You..
Posted by erken rezervasyon on April 24, 2009 at 01:42 PM PDT #
Thank You..
Posted by erken rezervasyon on April 26, 2009 at 10:57 AM PDT #
Thank You..
Posted by bursa evden eve on April 28, 2009 at 09:38 AM PDT #
nice text, thanks for all
Posted by lig tv izle on April 29, 2009 at 10:03 AM PDT #
thankssss
Posted by izmir forumu on April 29, 2009 at 12:32 PM PDT #
thank you
Posted by worldkontor on May 01, 2009 at 01:43 AM PDT #
thank you..
Posted by beyaz eşya on May 04, 2009 at 11:22 PM PDT #
Thank You..
Posted by atv safari on May 08, 2009 at 01:16 PM PDT #
Thank You..
Posted by arama motoru on May 09, 2009 at 12:43 PM PDT #
Thank You..
Posted by karel on May 11, 2009 at 05:35 AM PDT #
Thank You..
Posted by otogaz on May 13, 2009 at 08:06 AM PDT #
Thank You..
Posted by bursa evden eve on May 17, 2009 at 03:21 AM PDT #
thanks admin
Posted by müzik dinle on May 20, 2009 at 07:52 AM PDT #
thank you
Posted by parça kontör on May 20, 2009 at 12:55 PM PDT #
thank you
Posted by canlıdivx on May 20, 2009 at 12:55 PM PDT #
thanks admin
Posted by network marketing on May 21, 2009 at 01:48 AM PDT #
thanks admin
Posted by parça kontör on May 24, 2009 at 05:43 PM PDT #
Thanks, really great
Posted by parça kontör on May 24, 2009 at 05:47 PM PDT #
thank
Posted by Bursa Evden Eve Nakliyat on May 24, 2009 at 09:18 PM PDT #
Thanks..
Posted by izmir evden eve on May 25, 2009 at 05:38 AM PDT #
biz bu cam balkon işi yapıyoruz adımızda tosun:)
Posted by cam balkon on May 25, 2009 at 11:20 AM PDT #
The o till I either make my mind up or someone invents an affordable cloning machine, I’ll just focus on my main blog.oky.
Posted by müzik dinle on May 29, 2009 at 07:09 AM PDT #
thank you very much
Posted by Müzik Dinle on June 11, 2009 at 09:38 AM PDT #
Thank you very much admin
Posted by Sikis on June 11, 2009 at 09:41 AM PDT #
Konuya tacizde bulunulmuş resmen (:
Posted by rehber on June 12, 2009 at 12:52 AM PDT #
thank you very much
Posted by DJ Remixleri on June 12, 2009 at 04:53 PM PDT #
asdad
Posted by DJ Remixleri on June 12, 2009 at 04:54 PM PDT #
thank you very much
Posted by DJS Productions on June 12, 2009 at 04:55 PM PDT #
thank you very much
Posted by Jinglesiz Türkçe Remixler on June 12, 2009 at 04:56 PM PDT #
[url=http://www.mixsound.net/forum/index.php]DJS Productions[/url]
Posted by Jinglesiz Türkçe Remixler on June 12, 2009 at 07:59 PM PDT #
<a href="http://www.mixsound.net/forum/index.php">Tribal</a>
Posted by Jinglesiz Türkçe Remixler on June 12, 2009 at 08:00 PM PDT #
thanks a lot =)
Posted by izmir parça kontör on June 13, 2009 at 02:28 AM PDT #
saldırımı var ne iş len burda ne oluyor :D
Posted by gencsite on June 13, 2009 at 04:46 AM PDT #
thanks admin.
Posted by beşiktaş marşları dinle on June 13, 2009 at 06:34 AM PDT #
thanks adminn
Posted by çet on June 14, 2009 at 06:56 AM PDT #
thanks
<a href="http://vestelbekoservisimiz.blogspot.com" rel="nofollow">vestel beko siemens arçelik bosch servisi ebys</a><br />
<a href="http://www.hackarena.net" rel="nofollow">trojan</a><br />
<a href="http://www.attackerz.com" rel="nofollow">attackerz</a><br />
Posted by vestelbeko on June 14, 2009 at 09:11 AM PDT #
teşekkürler.
Posted by klip izle on June 15, 2009 at 12:03 PM PDT #
Igor Stravinsky
Posted by Igor Stravinsky on June 16, 2009 at 05:35 PM PDT #
dation from the peanut gallery: call them something other than pointers and use different symbols. People will mock the language for having
Posted by sohbet99 on June 18, 2009 at 12:45 PM PDT #
Notify me by email of new comments
Posted by sohbet99 on June 19, 2009 at 12:17 AM PDT #
a href="http://vestelbekoservisimiz.blogspot.com" rel="nofollow">vestel beko siemens arçelik bosch servisi ebys</a><br />
Posted by sohbet99 on June 19, 2009 at 12:18 AM PDT #
<a href="http://www.smsmatbaa.com" title="matbaa">matbaa</a>
http://www.smsmatbaa.com
Posted by matbaa on June 22, 2009 at 09:48 AM PDT #
Thank you so much for content, you would track;)
http://lidaal-zayiflama.klipci.org
Posted by lida on June 26, 2009 at 05:30 AM PDT #
thanks
Posted by müzik dinle on June 26, 2009 at 03:01 PM PDT #
thnx so much
Posted by oyun indir on June 27, 2009 at 05:27 AM PDT #
thnx so much
Posted by remix programı on June 30, 2009 at 09:57 AM PDT #
The o till I either make my mind up or someone invents an affordable cloning machine, I’ll just focus on my main blog.oky.
Posted by nick oluşturucusu on July 01, 2009 at 03:06 PM PDT #
affordable cloning machine, I’ll just focus on my main blog.oky.
Posted by pagerank sorgulama on July 01, 2009 at 03:07 PM PDT #
estel beko siemens arçelik bosch servisi ebys
Posted by 2009 temmuz hitleri on July 01, 2009 at 03:09 PM PDT #
way be ne diyim
thanks admin
Posted by tavla oyna on July 02, 2009 at 06:48 PM PDT #
tahnk u
Posted by Tavla İndir on July 02, 2009 at 06:49 PM PDT #
good post
http://www.erozyon.info
:)
Posted by erozyon on July 02, 2009 at 06:50 PM PDT #
wow good post
Posted by otomobil on July 02, 2009 at 06:50 PM PDT #
thank u
allah razı olsun
Posted by kumarcı on July 02, 2009 at 06:52 PM PDT #
thanks of
Posted by konya chat on November 05, 2009 at 07:09 AM PST #
good site
Posted by hürriyet ilan on November 08, 2009 at 06:00 AM PST #
thank you ..
Posted by betsson on November 09, 2009 at 06:41 AM PST #
1977 yılından beri hizmet vermekte olan reklam ajansımız Hürriyet gazatesi ilanlarında size en uygun ve en ekonomik çözümleri sumaktadır.
Posted by hürriyet ilan on November 12, 2009 at 04:25 AM PST #
thank you
Posted by travesti on November 12, 2009 at 08:48 AM PST #
site and current site is too bilnçli track you ediorum
Posted by haber on November 15, 2009 at 03:40 AM PST #
thanks admin
Posted by Konya chat on November 17, 2009 at 08:01 AM PST #
very good sharing thanks
Posted by web tasarım on November 17, 2009 at 11:39 AM PST #
işimi çok yararlı olacaktır. çok teşekkür ederim
Posted by firma rehberi on November 19, 2009 at 01:46 AM PST #
will be very useful to my job. thank you very much
Posted by alo firma on November 19, 2009 at 01:46 AM PST #
işimi çok yararlı olacaktır. çok teşekkür ederim
Posted by muzikdinle on November 19, 2009 at 08:17 AM PST #
teşekkür ederim sagolun
Posted by komik on November 21, 2009 at 03:27 PM PST #