Code Project: monitor /proc with Python and Clutter
If you already read our beginner's guide to the Clutter toolkit and wished it were available in something other than C, then good news: we're putting together a tutorial series covering PyClutter, the Python binding to Clutter, which merges all the power and beauty of the Clutter toolkit with the simplicity and brevity of Python.
So, let's start with a simple project to get things going: you're going to produce a network monitor that monitors data transfer and displays it all on the screen using Clutter. It's nice and easy, but we're going to be adding more involved PyClutter tutorials in the coming months, so you should get started while the learning curve is shallow!
The first thing you need to get to grips with in Clutter is the basic terminology. Unlike other GUI toolkits, which usually define objects like windows or panel, Clutter refers to the visual area as a 'stage'. To continue the analogy, objects that appear on (or actually, in, but it sounds weird to say it) the stage are called 'actors'. It makes more sense when you start coding it, and the names don't seem so strange after a while. The thing about the actors is that they have more properties than a standard widget because they actually exist in a 3D environment, rather than a 2D one.
What should I care about Clutter?
Clutter is a GPL graphics and GUI library that was originally developed by the OpenedHand team. It was later sold to Intel, which is committed to further development and deployment.
The great thing about Clutter is that it's a simple, fast and powerful way to deliver 3D or 2D graphics on a number of platforms. The back-end is essentially OpenGL, but by using the Clutter library developers can take advantage of a fast, efficient and friendly way to develop graphically rich apps without messing around with more technical aspects of the OpenGL libraries.
Clutter also forms an integral part of Moblin, the latest attempt to deliver a lightweight but powerful graphical version of Linux to run on mobile devices. Moblin is primarily aimed at Intel Atom based devices, although it will run on other hardware.
A note about versions
The Clutter library, and consequently the Python module that uses the Clutter library, has been updated recently to version 1.0. Normally updates may cause a few inconsistencies between old versions and new versions of software, but in this case there are fundamental differences between the code of versions before and after 0.9. The PyClutter module and the Clutter library should be available in your distro's repository, but when you install it, make sure you have a version 0.9 (preferably 1.0) or above, otherwise I can guarantee you that none of the code in this tutorial will work. If you think that's a faff, you ought to try writing a tutorial and then discovering the whole library changes...
All the world's a stage
Anyway, enough hyperbabble - it will make more sense when we write some code. Open up your standard Python environment (mine is a Bash shell, but you can use some of those fancy ones if you like), and let's create our very first Clutter script...
>>> import clutter >>> stage = clutter.Stage() >>> stage.set_size(500,300) >>> red=clutter.Color(255,0,0,255) >>> black=clutter.Color(0,0,0,255) >>> stage.set_color(black) >>> stage.show_all()
When you're done, click in the Close gadget on the window that opened. I know it didn't do anything amazing, but it does have the potential to! Let's take a look at what just happened. The first line obviously loaded the Clutter module. In turn, Clutter opens a few more modules itself - back-end stuff that links into display libraries to be able to put things on the screen. Next up we created a stage object. the stage is like a viewport - an area where your actor objects can play.
It's a bit dark in here... could be the promising start of a 3D adventure game, perhaps. Or your first Clutter effort!
Setting the attributes is as simple as calling some methods for the stage class, in this case a size and a colour. The parameters for the size method are x and y dimensions, and the colour is taken from the clutter.Color object (which takes values for RGB and alpha). As with other GUI toolkits, we should cause the object to be shown before any of it is drawn on the screen, which is what the final command does.
But what of our actors, the objects that we want to show on the screen? Let's add some text objects:
>>> a=clutter.Text()
>>> a.set_font_name("Sans 30")
>>> a.set_color(red)
>>> a.set_text ("Hello World!")
>>> a.set_position(130,100)
>>> stage.add(a)
Now we've added a text object, our first actor. Hopefully it will be fairly clear what the methods are doing - picking a font, a colour, setting the text string and positioning it on the stage. The final call in the code example adds the actor to the stage, and until this point, you won't be able to see it. Now that it's there though, you can continue to play around with it - try setting it to a different position or adding new colours.
As I mentioned earlier, the PyClutter documentation is scanty, but we can gain some solace in the fact that Python has good introspection. Try typing in dir (a) at this point to see the methods and attributes available for this object.
The traditional first app, though rather daringly we have left out the comma.
Our next step is to build a running script, but there's something we haven't covered yet: for all the Clutter magic to work properly, we should turn control of the application over to the clutter.main() function, but we don't want to do that without some way to exit the program. In such situations, Python will catch Ctrl+C interrupts, so we will have no way of quitting. The answer is to provide some keyboard events.
When the stage window is active, Clutter will receive signals for keypresses. All we need to do is provide a callback function that will process that event, and if the correct key has been pressed, quit out of the main loop. You could also assign other actions to some keys, like changing the colour of the stage for example.
>>> def parseKeyPress(self, event):
... if event.keyval == clutter.keysyms.q:
... clutter.main_quit()
... elif event.keyval == clutter.keysyms.r:
... self.set_color(red)
...
>>> stage.connect('key-press-event', parseKeyPress)
>>> clutter.main()
When run in the interactive Python shell, the quit function will not quit Python itself, or even destroy the application; it will just return control to the Python shell. In the case of a running script though, calling the clutter.main_quit() method will effectively end the application, or at least the Clutter part of it.
Messing around in the interactive shell is a quick, safe way to find out about Clutter objects and methods.
Time to monitor something
Right, now we have the interface sorted out, how are we going to build an amazing bandwidth monitor? We first need to find out the speed of the network traffic. Whenever I am confronted with a question about some piece of system statistics, I always go and ask my old friend, proc. Yes, the /proc pseudo filesystem is the repository of everything you ever needed to know about a running Linux box. proc is a huge sprawling mess of files, but the one we want is /proc/net/dev. This lists all the network devices, and reading the file will give you statistics on bytes in and out, packets, dropped packets, errors and so on.
The only thing we are interested in are the bytes sent and the bytes received. I know that the number there is a total, and we wanted a speed, but behold the power of proc - just open the file again and the magic numbers will have changed. Now, I hope I am not going too fast for you, but simple arithmetic should not be beyond us. If we poll the file every second and subtract the old number from the new number, everything should be fine.
All we really have to do is build a little function that will read in the file, parse it for the information we want, and compute the deltas. Before we leave we will save the old number so we can subtract it next time. Here's how the function should look, more or less:
devfile=open('/proc/net/dev','r')
for line in devfile.readlines():
line=line.strip()
if (line[:4] == 'eth0'):
line=line[5:].split()
print line[0], line[8]
Hopefully, this will make some sense to you without me needing to draw diagrams. We read in the file and iterate through the lines, looking for the one that begins eth0: - it is necessary to strip the line before searching because the output is padded by an amount to make the tables line up. When we have the correct line, we take of the interface part and split the string up, so we have each of the numbers as part of a list. The counts for bytes in and out happen to be at the 0 and 8 positions in this list. Here we have just printed them out - you can type in the code and see what it gives you. All that needs to be added to that is to convert the strings to integers and store them so we can keep a track of what's going on.
Maths is your friend
The more detail-oriented of you might question whether we take into account the length of time it takes this snippet of code to run. If you want to time this code, go ahead - on my development system it takes 0.0001 seconds to run. In case you're interested, a complete command line app would look something like this:
import time
lasttime=1
lastin=0
lastout=0
def getspeed():
x=open('/proc/net/dev','r')
for line in x.readlines():
line=line.strip()
if (line[:4] == 'eth0'):
line=line[5:].split()
bin=int(line[0])
bout=int(line[8])
return (bin, bout)
while True :
z= getspeed()
timedelta=time.time()-lasttime
lasttime=time.time()
sin=(float(z[0]-lastin))/(1024*timedelta)
sout=(float(z[1]-lastout))/(1024*timedelta)
print sin, sout
lastin=z[0]
lastout=z[1]
time.sleep(5)
This incorporates a timing function to more accurately calculate the speeds, but bear in mind that we're only talking about a couple of milliseconds, so it doesn't make a lot of difference. It is useful however, if we ever want to alter the timing period elsewhere in the software.
Now what we have to do is to incorporate this functionality into our Clutter application. We could just stick the loop at the end of our program and fail to ever call the main Clutter loop. We can still update the actor objects whenever we like, but this would be a Bad Thing. The nicer way to do it is to give liberty, autonomy and freedom back to the actors, but make use of an animation timeline to control their text.
Timelines are covered in slightly more detail in the box below, but to give you a brief summary, a timeline is just a timer that counts to some value and then emits the programmatic equivalent of a beep - a signal. The signal can be caught and fed to a callback, and as well as itself, you can supply other parameters to the call. For our purposes, we can make the timer call a function that will test the network speed and update our two actors.
It's all about timing
The Clutter library uses objects called timelines to do practically everything that needs to be done while an application is running. The timeline is the heartbeat of your script, and makes sure that everything at least makes a good attempt at running together.
Timelines are used extensively for controlling animations and effects within Clutter, but you can also use them as your own interrupts to call routines every so often. It does this by emitting signals for events such as started, next-frame, completed and so on. Each of these signals can be bound to a callback function to control something else.
Here is a short example you can type into a Python shell:
>>> import clutter
>>> t=clutter.Timeline()
>>> t.set_duration(2000)
>>> t.set_loop(True)
>>> def ping(caller):
... print caller
...
>>> t.connect('completed',ping)
9L
>>> t.start()
>>> <clutter.Timeline object at 0xb779639c (ClutterTimeline at 0x95b9860)>
Hopefully the methods of the timeline object should be easy to follow. The duration is set as a number of milliseconds. The timeline is then set to loop. Here we have created a simple function called ping, which just prints out the parameter it was called with. next, we connect the completed emitted signal to the ping function and start the timeline running. Without any further interaction, the ping function will now be called every two seconds, as the timeline completes, until you kill the Python shell.
You can get more documentation from the official homepage, clutter-project.org, but it's mostly for C programmers.
The timeline is an object unto itself, but when we execute the connection between the timeline and the callback function, we can pass along our text actor objects too, so the callback function will be able to change them directly. Note that if you're going for more complicated behaviours, this doesn't preclude you from having other timers too - you could set one up to change the colour of the objects every second if you wanted, and it needn't interfere with the timeline we have already created. Timelines can be used like threads in a multithreaded app - they aren't quite as flexible, but they are easier to manage and they it easier to deal with animated objects, because you can separate the business of animating the object from the other interactions it has.
import clutter
import time
lasttime=1
lastbin=0
lastbout=0
black = clutter.Color(0,0,0,255)
red = clutter.Color(255, 0, 0, 255)
green = clutter.Color(0,255,0,255)
blue = clutter.Color(0,0,255,255)
def updatespeed(t, a, b):
global lasttime, lastbin, lastbout
f=open('/proc/net/dev','r')
for line in f.readlines():
line=line.strip()
if (line[:4] == 'eth0'):
line=line[5:].split()
bin=int(line[0])
bout=int(line[8])
timedelta=time.time()-lasttime
lasttime=time.time()
speedin=round((bin-lastbin)/(1024*timedelta), 2)
speedout=round((bout-lastbout)/(1024*timedelta), 2)
lastbin, lastbout = bin, bout
a.set_text(str(speedin)+'KB/s')
xx, yy=a.get_size()
a.set_position(int((300-xx)/2),int((100-yy)/2) )
b.set_text(str(speedout)+'KB/s')
xx, yy=b.get_size()
b.set_position(int((300-xx)/2),int((100-yy)/2)+100 )
def parseKeyPress(self, event):
# Parses the keyboard
#As this is called by the stage object
if event.keyval == clutter.keysyms.q:
#if the user pressed "q" quit the test
clutter.main_quit()
elif event.keyval == clutter.keysyms.r:
#if the user pressed "r" make the object red
self.set_color(red)
elif event.keyval == clutter.keysyms.g:
#if the user pressed "g" make the object green
self.set_color(green)
elif event.keyval == clutter.keysyms.b:
#if the user pressed "b" make the object blue
self.set_color(blue)
elif event.keyval == clutter.keysyms.Up:
#up-arrow = make the object black
self.set_color(black)
print 'event processed', event.keyval
stage = clutter.Stage()
stage.set_size(300,200)
stage.set_color(blue)
stage.connect('key-press-event', parseKeyPress)
intext=clutter.Text()
intext.set_font_name("Sans 30")
intext.set_color(green)
stage.add(intext)
outtext=clutter.Text()
outtext.set_font_name("Sans 30")
outtext.set_color(red)
stage.add(outtext)
stage.show_all()
t=clutter.Timeline()
t.set_duration(5000)
t.set_loop(True)
t.connect('completed', updatespeed, intext, outtext)
t.start()
clutter.main()
Here we've brought together all the elements we have explored in this tutorial. We have created a stage, populated it with actors, and then used the timeline objects in Clutter to make them update themselves at our whim. But so far we have only scratched the surface of Clutter's graphical capabilities. We haven't even learned about behaviours or animations yet, never mind the alpha channel effects. Please trust us that we will be including these in our next project.
Numbers. Coloured numbers. That change. And monitor things. We call this a pretty good start!
First published in Linux Format magazine
You should follow us on Identi.ca or Twitter



Copyright 2010 Future Publishing Limited (company
registered number 2008885), a company registered
in England and Wales whose registered office is at
Beauford Court, 30 Monmouth Street, Bath, BA1 2BW, UK
Your comments
Python IDEs
Mark Johnson (not verified) - February 12, 2010 @ 5:34pm
Looking forward to having a crack at this tutorial.
Out of curiosity, what is Nick/everyone's preferred IDE for their Python projects?
RE: Python IDEs
Evil Nick (not verified) - February 12, 2010 @ 11:10pm
It really depends on what you are making. For the small apps in these tutorials, I mostly use Kate and the commandline. I found it incredibly useful to probe around Clutter in interactive mode, and every so often copy and paste everything into a text editor like Kate, so I could reproduce my environment if I did something wrong and PyClutter segfaulted (which is naughty, but does happen).
In general, Eclipse, WingIDE and Eric all have their relative strengths. Eric has some quirks, but is a good all round and pretty fast. Eclipse is solid and highly configurable, but slows me down a bit to much - it just seems so cumbersome, but I imagine some of its features would be very welcome if I were developing some massive cross-platform app.
Typo
Myers (not verified) - February 14, 2010 @ 9:14am
Just a hint:
In the article there is codeline "a.set_colour(red)". This has to be "a.set_color(red)"
My distro offers
davey (not verified) - February 14, 2010 @ 9:08pm
My distro offers python-clutter and python-clutter development files. Also the clutter library and dev files. Are the dev files needed to make these tutorials work?
You shouldn't need the dev
Anonymous Penguin (not verified) - February 15, 2010 @ 12:49am
You shouldn't need the dev files to make this work, though I am a bit curious as to what has been split out into PyClutter-dev
There is no "set_colour" in this listing - if one appeared in the mag it is the result of an overactive spell-checker, although I confess that gotcha does catch me out all the time
IDEs and early days
Anonymous Penguin (not verified) - February 17, 2010 @ 10:50pm
early days: Don't like clutter for some reason, coming from pyglet which also wraps OpenGL and is device independent there seems to be what feels like more polish, defined colours, function calls that have American color and rest-of-the-world colour versions, something about all the hyphens in the naming convention for built-in events irks me. In the demo window size of 500,300 does not work on my linux system. Its way to small on the horizontal axis and the text is truncated. Having to clean up everything and set up everything in the environment yourself seems like all these little annoyances make for a larger distaste. I'll still give some more clutter a go but I am still preferring how pyglet takes care of the little annoyances and seems to do the same thing.
IDEs:
If I feel like a light IDE and still free I go with Editra which I install from subversion in the command line to get the latest and greatest.
If I feel like a big full feature large projects IDE and still free I go with Eric4 or I hear Eric5 is out there for Python 3.x series.
If I am making small scripts I just do it in the shell editor on the command line as its just quick and easy and I don't need anything in an IDE to get the job done, IDE just gets in the way.
Clutter-WARNING **: Unable to create a new stage: the glx backen
Simon (not verified) - October 11, 2010 @ 2:24am
I'm getting this error on Ubuntu 9 GNOME (running over VNC):
/usr/lib/pymodules/python2.6/clutter/__init__.py:66: Warning: g_set_prgname() called multiple times
_clutter.init()
Xlib: extension "GLX" missing on display ":1.0".
(speedtest.py:4159): Clutter-WARNING **: Unable to create a new stage: the glx backend does not support multiple stages.
Traceback (most recent call last):
File "speedtest.py", line 54, in <module>
stage = clutter.Stage()
RuntimeError: could not create a clutter.Stage
Anyone else having this problem?
With gi.repository
Anonymous Penguins (not verified) - May 6, 2011 @ 3:23am
When using gir version, other than from gi.repository import Clutter, you have to do a
Clutter.init(sys.argv)
before anything clutter-wise.
steelers jerseys
Steelers Jerseys (not verified) - December 10, 2011 @ 1:11pm
<a href="http://www.packersmall.com/green-bay-packers-jerseys/aaron-rodgers-jersey">Aaron Rodgers Jersey</a>
<a href="http://www.packersmall.com/green-bay-packers-jerseys/charles-woodson-jersey">Charles Woodson Jersey</a>
<a href="http://www.packersmall.com/green-bay-packers-jerseys/clay-matthews-jersey">Clay Matthews Jersey</a>
<a href="http://www.steelers-jersey-shop.com/pittsburgh-steelers-jerseys/troy-polamalu-jersey">Troy Polamalu Jersey</a>
<a href="http://www.steelers-jersey-shop.com/pittsburgh-steelers-jerseys/james-harrison-jersey">James Harrison Jersey</a>
<a href="http://www.steelers-jersey-shop.com/pittsburgh-steelers-jerseys/ben-roethlisberger-jersey">Ben Roethlisberger Jersey</a>
<a href="http://www.shoppatriotsjersey.com/new-england-patriots-jerseys/tom-brady-jersey">Tom Brady Jersey</a>
<a href="http://www.shopbearsjersey.com/chicago-bears-jerseys/matt-forte-jersey">Matt Forte Jersey</a>
<a href="http://www.shopbearsjersey.com/chicago-bears-jerseys/devin-hester-jersey">Devin Hester Jersey</a>
<a href="http://www.shopbearsjersey.com/chicago-bears-jerseys/brian-urlacher-jersey">Brian Urlacher Jersey</a>
<a href="http://www.shopbearsjersey.com/chicago-bears-jerseys/julius-peppers-jersey">Julius Peppers Jersey</a>
jerseys
steelers JerseysMLB Jerseys (not verified) - December 10, 2011 @ 1:12pm
Thank you for your post.I like very much!
jordan shoes,jordan spizike,factory online
jordan jordan shoes,jordan spizike,factory onlineshoes,jorda (not verified) - December 22, 2011 @ 10:27am
I watched and listened to about two-thirds of Neil Selwyn’s <a href="http://www.jordanshoessold.com" title="new jordan,jordan release dates,jordan shoes for sale"><b>jordan shoes</b></a>,<a href="http://www.jordanshoessold.com" title="jordan shoes for women,shoes,jordan shoes cheap"><b>jordan shoes for sale</b></a>,<a href="http://www.jordanshoessold.com" title="joran shoes cheap,the new jordan shoes,joran shoes "><b>jordan shoes for women </b></a>,<a href="http://www.jordanshoessold.com" title="retro 1 jordan,jordan flight,jordan i"><b>jordan shoes cheap</b></a>,<a href="http://www.jordanshoessold.com" title="jordan flight 45,jordan sale,jordan s"><b>jordan 3</b></a>,<a href="http://www.jordanshoessold.com" title="jordan grown low,jordan v5 grown low,jordan retro 1"><b>shoes jordan</b>,<a href="http://www.jordanshoessold.com" title="sell jordan,all jordan shoes,new jordan shoes"><b>retro jordan</b></a>session from earlier today before I lost the sound on my Macbook
wholeslae tresor paris
tress (not verified) - December 29, 2011 @ 9:20am
<a href=http://www.tresorparisjewellery.org>wholeslae tresor paris</a>
Wholesale Tresor Paris jewellery offers bracelets,necklaces and packings-Tresor Paris
jewellery all by hand-made with a variety of precious gemstones crystals magnetite balls and fabrics.
Hip Hop Jewelry
Stuart Geel (not verified) - December 29, 2011 @ 9:33am
<a href=http://www.cheaphiphopjewelry.org>Hip Hop Jewelry</a>
Cheap Hip Hop Jewelry is mainly for sale in fashion Hip Hop Chains,and Hip Hop Pendant
and Disco Ball Chain as well,with brass, cubic zirconia stones and nylon string all by hand-made.
Buy Jordan Shoes
Felipe Contreraz (not verified) - December 29, 2011 @ 9:43am
<a href=http://www.buyjordanshoes.org/Jordan-Shoes/>Buy Jordan Shoes</a>
Buy Jordan Shoes and Buy Jordan Shoes at china supply! Free Gift at china supply! Jordan Shoes
Nike Shoes,China Nike Shoes,Wholesale Nike shoes Cheap Price and Top quality
jordan heels,jordan high heels,air jordan high heels
cheapjordanheel (not verified) - January 11, 2012 @ 7:34am
http://www.cheapjordanheel.com
http://www.airgriffeymax2.com
http://www.airyeezycheap.com
http://www.dunkhighheelslow.com
http://www.airjordanheelboots.com
http://www.jordanheels.biz
49ers Red Jersey
Alex Smith Jersey (not verified) - January 12, 2012 @ 11:21am
<a href="http://www.nfl49ersjerseys.com/">49ers Red Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/alex-smith-jersey">Alex Smith Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/frank-gore-jersey">Frank Gore Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/anthony-davis-jersey">Anthony Davis Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/michael-crabtree-jersey">Michael Crabtree Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/vernon-davis-jersey">Vernon Davis Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/patrick-willis-jersey">Patrick Willis Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/deion-sanders-jersey">Deion Sanders Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/brian-westbrook-jersey">Brian Westbrook Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/isaac-sopoaga-jersey">Isaac Sopoaga Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/jerry-rice-jersey">Jerry Rice Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/joe-montana-jersey">Joe Montana Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/mike-iupati-jersey">Mike Iupati Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/nate-clements-jersey">Nate Clements Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/nate-davis-jersey">Nate Davis Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/roger-craig-jersey">Roger Craig Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/ronnie-lott-jersey">Ronnie Lott Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/steve-young-jersey">Steve Young Jersey</a>
<a href="http://www.nfl49ersjerseys.com/san-francisco-49ers-jerseys/taylor-mays-jersey">Taylor Mays Jersey</a>
http://www.3gtabletpc.org
Best Tablet PC Android (not verified) - January 14, 2012 @ 5:31am
Most of our products have no minimum order requirements, <a href=http://http://www.3gtabletpc.org/>Tablet PC Android</a>Tablet PC Android so you can shop retail products at wholesale prices! Wholesalers can shop big and get even larger discounts! Browse our huge range of products now and see for yourself.
http://www.agenttaobao.org/
taobao agent (not verified) - February 9, 2012 @ 3:02am
Cheap michael jordan shoes,True Religion Jeans,Provide Discount nike air max,<a href=http://www.agenttaobao.org/>taobao agent</a>Designed with comfort and protection for running,100% quality and return policy guarantee. We offer Top Quality Products,Reasonable factory Price,Fast and Safe Shipping,24/7 customer service, also you can get a great selection of fashion and latest styles Michael Jordan shoes,True Religion Jeans,Nike Air Max on www.ChinaWholesaleNike.com/nike paypal, credit card, western union, money gram accepted. Buy now!.
http://www.1973shop.com
basketball jerseys (not verified) - February 9, 2012 @ 3:02am
We are a reliable and professional <a href=http://www.1973shop.com/>basketball jerseys</a>
, more orders to get more discounts. basketball jerseys we have a large amount of "stocklist", dont hesitate to mail us
http://www.nfljerseysfactory.com
NFL jerseys wholesaler (not verified) - February 9, 2012 @ 3:03am
We are a reliable and professional <a href=http://www.nfljerseysfactory.com>NFL jerseys wholesaler</a>
, more orders to get more discounts. Wholesale NFL Jerseys
we have a large amount of "stocklist", dont hesitate to mail us
http://www.nfljerseysfactory.com
NFL jerseys wholesaler (not verified) - February 9, 2012 @ 3:03am
We are a reliable and professional <a href=http://www.nfljerseysfactory.com>NFL jerseys wholesaler</a>
, more orders to get more discounts. Wholesale NFL Jerseys
we have a large amount of "stocklist", dont hesitate to mail us
http://www.3gtabletpc.org
Best Tablet PC Android (not verified) - February 9, 2012 @ 3:03am
Most of our products have no minimum order requirements, <a href=http://http://www.3gtabletpc.org/>Tablet PC Android</a>Tablet PC Android so you can shop retail products at wholesale prices! Wholesalers can shop big and get even larger discounts! Browse our huge range of products now and see for yourself.
Post new comment