30 Mar 2007

I just read that Patrick Mineault thinks that SWX is a bad idea. Although I have the utmost respect for Patrick and I love and support his work, I respectfully disagree with him. SWX is a good idea and here's why.

(I started responding to Patrick's post in the comments on his blog but it got too long so I'm posting it here instead.)

The followering are the main points Patrick makes in his post, along with my counter-points:

Now my first point is that SWX reinvents the wheel, and for no good reason. Let's list out the various ways to do asynchronous data communication in Flash. We have LoadVars, XML, Remoting, JSON, SOAP, XML-RPC, and PHPObject. One solution seems more than enough for this very simple tasks; adding another one to these 7 seems like a complete waste of time.

I remember when Flash Remoting came out that, for a long time, people would make the same argument against it: Why do we need another way to exchange data? Why did they re-invent the wheel? And the answer is the same now as it was then: We need it because the existing methods do not meet the needs of certain people.

If we were to accept Patrick's argument at face value, there would be no reason to go beyond LoadVars and we could throw XML, Remoting, JSON, SOAP, XML-RPC and PHPObject away, labeling all of them as redundant. After all, as I mentioned in my talk at the LFPUG last night, the core concept at the heart of building data-driven applications is a glorified form of automated copy and paste. We are moving information around from one place to another. In place of trucks, we use pipes to move our data. But it's transportation, not rocket science. So anything you can do with Remoting you can do with XML and LoadVars. Based on this argument, Remoting, XML, JSON, SOAP etc. all re-invent the wheel. But that's not true. Each has its specific strengths, weaknesses and use-cases. As does SWX.

Of course, it wouldn't be if in fact SWX gave some mighty good advantages over all the other solutions. To my knowledge, however, the only positive advantage to using SWX is the ability to use getBytesLoaded and getBytesTotal, which isn't available, in, say, Remoting.

SWX does have several mighty good advantages over all of the other solutions, above and beyond giving you the ability to display a determinate progress indicator as mentioned by Patrick. (If that was the only advantage, as much as I like determinate progress bars, I surely would not have invested as much time and effort into creating this as I have!) :)

Here are just a few advantages I can think of off the top of my head that SWX has over other methods:

  • It's simpler to use.
  • Data is deserialized twice only as opposed to four times.
  • You don't have to learn a new API and can reuse your existing knowledge.
  • It is useful in mobile applications with limited processing power
  • The final downloadable bundles of SWX will contain everything you need to get up and running (you don't need to buy or download additional tools).

I want to elaborate on some of the above points, starting with the advantage of having two deserialization steps instead of four. To illustrate the point, I'll use the model that Patrick presents in his article on Clearing the FUD on amfphp’s speed versus JSON and XML (which is quite ironic since I'm clearing the FUD about SWX here!) In it, Patrick accurately states the following:

In most any RPC model, there are the following steps:

  • Serialization of the request on the client-side
  • Uploading of the message to the server
  • Deserialization of the request on the server-side
  • Dispatching on the server-side
  • Serialization of the response on the server-side
  • Downloading of the message to the client
  • Deserialization of the message on the client-side

In most any RPC model, that is, except SWX. Let's look at how the above list looks in SWX.

Steps in SWX:

  • Serialization of the request on the client-side
  • Uploading of the message to the server
  • Deserialization of the request on the server-side
  • Dispatching on the server-side
  • Serialization of the response on the server-side (i.e., assembly of the SWX SWF)
  • Downloading of the message (i.e., SWF) to the client
  • Deserialization of the message on the client-side

Straight off the bat, we remove the deserialization of the request on the server as the PHON object that is sent over is evaled, following security checks. The big advantage, however, is that we also remove the deserialization step on the client side because your Flash client is receiving a native SWF. There is no deserialization. The moment the SWF is loaded, it is ready for you to use. Just access the data structure and you're off.

Among other things, this means that there's no equivalent of the Flash Remoting Mystery Time. Once the SWF is loaded, the data structure is immediately available for you to use. Any sort of deserialization on the Flash client is going to use up processor cycles and SWX, by design, is the least processor intensive method possible since it is SWF bytecode and that's as native as you get in Flash.

Of course, time will tell how SWX compares with the other options in terms of performance, etc. but my gut tells me that a fully optimized SWX will compare very favorably indeed. It is, of course, not fair to compare it on these grounds currently as we are at a very early alpha release (think: one step removed from a proof of concept) and it is currently not optimized in any way. Most importantly, though, SWX is not in a pissing contest with other formats. It is one alternative, it is simple, and it has very valid use cases. In fact, one of the first things I am planning to do is to show people how SWX can be used alongside Amfphp and the single-package distributions of SWX will actually include Amfphp (I love Amfphp, Patrick, you know that!)

If you look at the sample code on the webpage . . . The first thing you'll notice is that dataHolder is a movie clip on Stage. That means that either you must place this empty movie clip on stage manually, or you have to use createEmptyMovieClip first. Of course, if you do the latter, you have to think about depths and whatnot. The second thing you'll notice is that there is an onEnterFrame. I thought the whole reason we dropped the use of onEnterFrame for polling a movie clip is that we had all sorts of crazy issues with that, including the difference between 0 and 4 loaded bytes.

I think Patrick is missing the point here. The key thing here is that Flash developers understand movie clips and know how to work with them. That sample code is purposefully simplistic. Of course, I will be releasing utility classes that abstract that away from you if you want to use a highler level API but the important design consideration here is that you *don't* have to learn a new API to use SWX. That's the beauty of it. You can use your existing Flash knowledge to easily create data-driven applications. And for those of you who *want* to have a higher-level interface, you'll have one. But it won't be forced on you.

Also, there is nothing wrong with using an enterFrame handler. The initial states (negative, etc.) tell you the various states that the load process is in and are actually very valuable for presenting accurate status information (is it waiting for data, receiving it, etc.) And, of course, you *can* display a determinate progress bar when you start loading the data. Apart from the usability advantages of doing so, it's just plain cool! :)

The third point is that the PHON serialization that is used relies on a prototype hack . . . So we hack toString in Array, Object and even (gasp!) String. I am not even to bother to expand as to the myriad ways in which I think this is a bad approach, but you can imagine the argument.

Ah, I just knew that people would get stuck at this point :)

Just to make it perfectly clear: The PHON serialization in SWX does *not* rely on a prototype hack. The current alpha of SWX happens to contain the automatic PHON serializer as the only option. I just didn't have the time to also release an alternative utility class that doesn't rely on extending the prototype object.

As I mentioned in my talk at the London Flash Platform User Group yesterday, this automatic workflow is very cool but you would be right to have concerns about object pollution if you use this method. Whether or not this will be a problem depends on your application. For simple apps, it should be fine. But if you're uncomfortable with it (or if you're using the toString() methods of the Object, Array or String classes for other purposes in your application), then you won't have to use the automatic PHON serialization method and you can use a manual method instead. That will involve one extra line of code:

org.swxformat.PHP.serialize(dataHolder.data);

To say that PHON serialization in SWX *relies* on a prototype hack is incorrect. The automatic PHON serialization workflow happens to be the only one I had time to implement in time for the initial launch. The manual method will follow very shortly (in fact, I think I'll get it into the next release.)

The fourth issue with this hack approach is that it is not going to work in AS3, either in Flex or in Flash 9. For one thing because you can't hack prototype, for another because the AS3 bytecode is different from the AS2 bytecode.

The current workaround to using SWX with AS3/Flex 2/Flash 9 is to use LocalConnection. In fact, this is what the SWX Analyzer (which is a Flex 2 application) does. However, this is far from ideal. I haven't even looked into how SWX may be implemented in AS3 at the moment but it is on the roadmap. Patrick is correct in that it will require a re-write of the PHP-based SWF assembler to use AS3 bytecode but there is nothing in it that is inherently impossible. And, as I outlined above, nothing in SWX relies on a "prototype hack".

SWX also had the disadvantage of being impossible to debug in Charles or ServiceCapture. Aral did a nice job with his Flex debugger, but why bother when you have native tools in your hands that do the job really really well.

I fail to see how having a free, built-in debugging tool can be perceived as a disadvantage. Surely, Patrick means that SWX has an *advantage* here! :)

When working with Flash Remoting, you need to purchase a separate tool to debug your application. Both Charles and ServiceCapture are commercial applications that you have to pay for and purchase separately.

Charles costs $50 for a single user license, and ServiceCapture costs $34.99.

SWX with the built-in SWX Analyzer, in contrast, costs $0.

(And it comes in the box so you get everything you need in one download.)

On a personal note, I found Charles to be highly annoying when I was evaluating it. Both the cumbersome interface and the constant "buy me now" nagging in the evaluation version. However, I do love ServiceCapture and I've bought multiple licenses for it over the years. It is far more than a remoting debugger (although it is wonderful for that purpose) and there is no reason why you cannot use ServiceCapture alongside SWX for its other features, such as the very useful network bandwidth throttling feature.

I could go on: SWX doesn't have anything for batched calls, or for typed objects, and I can hardly see how it could be put to use on a serious RIA.

It's true that SWX doesn't have batched calls, typed objects (yet) and that it may not be your first choice for a "serious RIA". But it's not for "serious RIAs". In fact, I'm fucking sick of "serious RIAs" and look forward to using SWX in fun projects that are in no way serious :)

You might argue that SWX is not meant to be used in RIAs, it's better for smaller projects, but that's why we have LoadVars and XML. Honestly I really don't see the point.

The whole idea behind SWX is that it is far easier to use than both LoadVars or XML that it is in a different class altogether when it comes to simplicity.

With LoadVars, you need to serialize your data into some custom format and then deserialize it yourself. This is a lot of useless plumbing code that no one should have to write. I had to write routines to deserialize complex arrays before but that was in Flash 5 when we had no other choice. Life is way too short for you to spend it writing this sort of useless code. All it does is bloat your application and take time away from actually creating your application and having fun with it.

XML. Where should I start? Have you ever worked with XML in Flash. It's not pretty is it? Until E4X in AS3, using XML in Flash was akin to pulling teeth without anesthetic. Another helping of firstChild, lastChild, bastardChild anyone? No, I didn't think so. Of course some people used helper classes that mixed in object-style look-up functionality to XML structures but how many people, really, even knew about these. In my experience, very few. Many people I see end up converting the XML structure into an object structure and then using that. Umm, but that's exactly what you get with SWX without doing any work whatsoever -- a native Flash object, as complex as you like, delivered to you piping hot in a tasty SWF shell! :)

SWX offers a huge advantage over both LoadVars and XML: simplicity. And the fact that you don't have to worry about serialization and deserialization.

In conclusion, I just want to state that SWX definitely has valid use cases: They're just not the same as those for Amfphp.

SWX, first and foremost, is built with an overriding focus on simplicity. It may be 2007 but, unfortunately, we still don't have an intuitively simple way to create data-driven apps in Flash. The closest thing we have is remoting (and I'd argue, Amfphp is the simplest one to get up and running with) but too many developers are still afraid to dive into the depths of even that. With SWX, you don't need to know anything new to get the advantages of Remoting without the extra hassle.

If you're building a mashup, or a FlashLite 2 application, take a look at SWX. If you want to have fun with Flash and create data-driven applications without the hassle of learning new APIs and downloading extra classes and all that unnecessary stuff, then SWX may be the right choice for you.

Like anything new technology, it will take a little time for it to mature. As I've mentioned in several places, it is currently not optimized in any way so this really isn't the time to be running benchmarks on it with other, mature technologies that have been around for ages.

SWX is growing and changing daily and I hope you will be part of its story. Pretty soon it will be up and running and getting up to all sorts of mischief and then we'll really start having some fun! :)

Don't forget that SWX is a tiny, new-born baby right now. It just opened its eyes to the world yesterday. Let's give it a chance instead of trying to strangle it in its cradle.

Creative Commons LicenseThe SWX: A good idea article by Aral Balkan, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial 2.0 UK: England License.

Add Your Comment

Spam Protection by WP-SpamFree

SWX: A good idea

  1. [...] I just posted a reply to Patrick Mineault’s post, explaining why SWX is a good idea. [...]

    SWX: A good idea at SWX: SWF Data Exchange Format
  2. Aral,
    So sorry I couldn’t make the talk. Just could not get away from work. I guess I’ve been soo busy SWX went underneath my radar. A bloody brilliant idea. I’ve got a few new projects that no doubt will need such a data exchange vehicle.
    More bounce to the pounce Compadre

    a

    aYo
  3. Nice read! Thanks!

    aSH
  4. Hi there,

    The weak point i see to SWX is that right now it just works against a server. Working with XML (and XPath to make your life easier), lets you easily create applications to work both on and off line. You just need a URL, Flash doesn’t care if it’s a server or a local file. Of course, this only applies to applications that are going to be used BOTH on and off line.

    Really good work, though. And thanks for sharing!

    Cheers,

    Juan

    Zarate
  5. I think its an interesting concept and i’ll defo have a play with it.

    Tink
  6. [...] Dicho esto, el rendimiento de SWX puede que sea mejor, (te ahorras un par de serializacion/deserializacion, pero echadle un ojo al propio post de Aral, que lo explica mejor), así que en dispositivos móviles puede que sí tenga su campo. [...]

    Dando la chapa » SWX una nueva forma de obtener datos en Flash
  7. Every single Open Source project is a good idea.

    Some of them might be better suited for certain purposes, but simplicity is always a very important feature, allowing people to access technology they couldn’t use before.

    Well done, Aral. Sorry I couldn’t make it to the talk -I was busy with my own leaving do :)

    C4RL05
  8. It seems like a good idea Aral I will also give it a play.

    Darren
  9. [...] So what the hell is this SWX: SWF Data Exchange Format, well its the brain child of Aral Balkan to get data into flash Faster and better that the current loadvars and XML ways, I am going to give it a try for sure, I will keep you posted. [...]

    SWX? » Flash Experiment
  10. You rock Aral, I’m very pleased to checkout your share!!! It looks very impressive. I’ve been an amfphp junkie.

    LEE
  11. even if it was the worst idea ever, you can do whatever you want :)

    I have respect for both you and patrick, but com’on
    to tell someone else to just not do something
    because it’s reinventing or a bad idead or whatever is going a little too far…

    the more choice the better!

    and to come back to the main suject: SWX,
    humm well I wish you all the best but I will not use it

    one single reason: binary format.

    for me that means: no security, no way to encrypt the data, hard to debug, not that faster over plain/text format, loading from different domain sandbox security problem, bound to a server (you can not use it localy without a server), hard to port to different environment etc..

    note also that amfphp fall in the same bag :).

    zwetan
  12. On the point of reinvention, such wonders as Linux, Php and Ruby wouldnt exist today if folks had accepted that objection….

    ktec
  13. [...] So what the hell is this SWX: SWF Data Exchange Format, well its the brain child of Aral Balkan to get data into flash Faster and better that the current loadvars and XML ways, I am going to give it a try for sure, I will keep you posted. [...]

    SWX? » Darren Richardson
  14. Hi Aral,
    I like your reply – logical, respectful. I think both you and Patrick have made some good observations, and keeping in mind the earliness of the release is important, as you’ve pointed out.
    Perhaps some of the concern comes from having yet another format to learn. Yes, I understand that it is a familliar format (movieclip) and simple, but by now people who do dynamic sites have often developed reliable strategies. At a time when we are stretched to learn AS3, FlexIDE, Apollo, and soon CS3, along with everything else, understandably some will want to say ‘thanks, I’ll stick with what I know already in this regard’.
    Don’t get me wrong, like your work, enjoy your enthusiasm, think you’re a genius. :)
    -tim.

    timbot
  15. The first thing I thought when I saw your example code was ” oh thats easy”.

    Working at a firm with multiple skill levels of flash developers. I can see the advantage of SWX. Anything that takes advantage of familiar items (read, movieclips) will make this a much more approachable form of remoting for many people.

    Dustin Senos
  16. [...] SWX is still in alpha, and already it’s been fascinating to listen in on the conversation about its potential and its role among the other data exchange options. We think it’s reassuring that, even while Flash continues its evolution into a serious RIA platform, attention is still being spared to develop user-friendly solutions for “right brain” Flash users who want to play with mashups etc. without a big learning curve. [...]

    Flashforward Blog » Blog Archive » Aral’s Spring Surprise: SWX
  17. Personally this debate about passing objects this way or that is a moot point. If my app needs to make a call to receive data, I’m pretty happy with the new XML support in AS3. Yes XML has its weakness, but its a lot better and easier to work with. If my app needs something more, like real time, push/pull, data binding…you’re gonna need something else anyway, ie. Flex Data Services, Assemblers, RTMP, and ultimately Java or Cold Fusion.

    Seth
  18. Good post.

    I think the ability to have progress reported on a service call like this is a meritable feature in itself. How about some benchmarks for large amounts of data?

    Ash
  19. [...] Some more comments on the SWX controversy, after Aral’s rebuttal of my previous post. First off, just to be absolutely clear, I am not bashing Aral, or anybody working on SWX itself. Aral and I have have collaborated on amfphp, and are coauthors (among several other very talented people) on a new open-source Flash book, and we get along quite well, thanks ;) I’m also not saying that SWX is a stupid idea; in fact the idea behind SWX is quite clever, but the implementation is not going to yield any net benefits for the community (more on this later). As for my statement that SWX is a hack, I stand by that, and I think other people agree. But of course, you could argue that once a hack is sufficiently abstracted away in classes, it doesn’t have the disadvantages normally associated with hacks, and that makes it a valid solution. Unless I am misunderstanding Aral’s argument, I think that’s his point. [...]

    5 1/2 blog » SWX: still a bad idea
  20. [...] Patrick Mineault maintains, after my post SWX: A good idea that SWX is still a bad idea. I still disagree. This is going to be my last post on the subject because it appears that we are just going to have to agree to disagree on this one and I would rather spend my time improving SWX and doing fun stuff with Flash rather than justifying the existence of my latest open source project. [...]

    SWX: Still a good idea at Aral Balkan
  21. This is an interesting topic. I work in the mobile market and in one product, recently moved the processing of xml files from the remote clients flash layer over to the server in the search of performance gains.

    Like swx, the server now does the leg work, generating the parsed data structures (in a format i dictate) and sending me the generated swfs. There was a noticeable amount of processing time saved on the client as the all i do is load the swf and I’m away, no more heavy xml interrogation.

    This also removed a bunch of logic from my code as all the actions which used to perform the conversion from xml dom to ui friendly data structures, are gone in place of a single generic action which passes back these data structures directly.

    So drawing some parallels with swx, i can say this benefit alone is worth consideration by others.

    Cool project, look forward to seeing how it develops.

    Mike Stead
  22. Thanks, Mike — it looks like mobile apps will be a big use-case for SWX.

    aral
  23. [...] My previous post about my thoughts on the current Flash climate was apparently just a small slice of this somewhat larger growing sentiment. The Flash community is definitely changing. These posts here and here seem to prove it to me. Lots of negativity for what should be a positive thing: A member of the community making something unlike what was already out there and sharing it with anyone who wanted to try it. These types of efforts make things simpler for users by providing options. Flexibility is one of the major draws for many starting Flash designers in my experience. I teach and work with beginning students building their first timelines and parsing their first XML. I know that the multitudes of options can sometimes get a bit confusing, but do provide ways to ease users into achieving their goals using a method they feel comfortable with. [...]

    Getting Data into Your Flash Files - A Million Ways Can’t Be Wrong? | Visualrinse | Design and Development by Chad Udell
  24. I think one of the cooler things about SWX is that it represents data as files on the hard drive. Coming from Rails (and WebOrb) this means that I can now cache my data as .swf files on the hard drive and avoid hitting my app servers on every data call from Flash. Also, since the SWF files are just standard files sitting on the HD, all of Rails helpful Cache Sweeping mechanisms should still apply. Sure, this could be accomplished with XML files, but you’ve already outlined the advantages that SWX has over XML (and the others). Very cool. Perhaps I’ll start considering a Ruby/Rails implementation.

    Meekish
  25. Obviously, the caching would only be applicable to service methods that didn’t accept any arguments, but I still see some major potential here.

    Aral: Could you contact me at the email address I left? I would to chat with you about a Ruby port. Thanks!

    Meekish
  26. Great concept, great implementation, and a great way to be more accessible for mobile devices. I am developing content that needs to perform amazingly well on high-end computers and have the same performance on mobile devices. This is just the solution needed for getting a heavy data app to perform well on mobile devices. I am very excited to see the future of it.

    As far as the argument that no one should reinvent the wheel – Tell the pioneers that the wheels and wagons they pushed across the plains are just fine and the cars and tires we have today wouldn’t help them in any way. Progress is progress and this fits a very specific need. As far as I understand it this is perfect for mobile devices. I can’t wait to use it. The other huge upside is that if the data is being carried into the master swf using another swf then that data is accessible later in the local cache even if the users internet connection is not intact. What a great tool that fills a very specific need.

    Aral, I would love to see in your to-do list – more focus around mobile devices, also it would be fantastic if you could explore further the concept of persitent data using Shared objects etc… so that we can access the data even while disconnected without the browser dictating how.

    SWX is a great idea. Let me know how I can help.

    Curtis J. Morley
  27. [...] SWX – A Great Idea Aral Balkan has come up with a new way to get server side data from the server and into Flash. This is a very unique method that has great application. You are probably wondering why we need another format to do Flash and server side communication. We have LoadVars(gotta love the .txt files), XML, Remoting(Macromedia Flash Remoting, AMFPHP, WebORB, etc…), JSON, SOAP, XML-RPC, Flash Media Server, Red5, and PHPObject. Some have asked this same question. When I look at Aral’s latest project two reasons come to mind of why this is not only a good idea but a great idea. [...]

    curtismorley.com » Blog Archive » SWX - A Great Idea
  28. I am very excited about this and wish I could be there for your FITC presentation. I got so excited I had to blog about it.
    http://curtismorley.com/2007/04/05/swx-a-great-idea/

    Curtis J. Morley
  29. After reading Aral posts and Patrick’s I would agree that the SWX format is very valid and can be applied to use cases which are not currently being addressed. I echo Curtis’s enthusiasm about the technology and look forward to helping where possible.

    Keep rockin Aral. You have a great open mind.

    Jonathan

    Jonathan
  30. I’m extremely enthusiastic about this technology. In some cases, it will allow for less talented Flash developers to do things they aren’t currently capable of.

    Aral, you make a pretty clear case for the technology, but for most developers who already use technologies that are perhaps more robust than SWX, is it going to be worth it to learn? I use mostly XML, and although not perfect, it works very well for most of my needs. I probably won’t use SWX, but several of my employees will probably get a chance to use it.

    Joe
  31. Hi Joe,

    So glad to hear that you’re excited about SWX! :)

    For developers currently working with other technologies, I can only say, give it a try and see where SWX makes sense and where it doesn’t. For mobile applications, for example, XML just is not a very feasible option due to the processor overhead on the client. SWX works great there!

    Also, you do get some neat things for free in SWX like queued requests (using the Full API) and a timeout handler (easy enough to implement but usually overlooked).

    Looking forward to hearing about how you get on with SWX.

    aral
  32. Hi Aral!

    I think you’ve convinced me. I have a small group of Flash developers working for me that are going to learn the technology. After researching SWX, I think it’s going to work great with a couple of the things we do.

    Thanks for the great blog!

    Joe
  33. I don’t think having more options is a bad idea… but what i think every new option should incorporate is enterprise level integration in this day and age. Example for small applications only php support is ok, but for real world usage I would hope there are java and .net integration points as well

    Very interesting idea
    Nik

    Nik Khilnani
  34. Really a great concept. Like you say it is a baby right now, but I am looking forward to how this affects mobile.

    Bruce Swedal
  35. Umm.. Very good idea. Thanks for great ideas.

    ruud

    ruud
  36. SWX is something new for me but this article convinced me to learn more about it. Thank you for the valuable article!

    Best regards,
    Zoltan Sebestyen

    Respiro Media
  37. We are doing quite a lot of data intensive commercial Flash Lite projects, we are very excited to showcase SWX as the preferred data transfer medium, I will post an example as soon as it’s done! SWX really is a godsend for mobile developers, have you seen what XML parsing does to the performance of a mobile application? I do agree though that it is a bit of a slowdown having to work of a running web server all the time, but that is really becoming less and less of a problem.

    Stefan Wessels
  38. i belive its not reinvent of the wheal… ideas are not purely new it has tobe some inspiration and starting point. so keep up the good work.

    Rizwan
  39. [...] Craig was the perfect follow-up to Michelle Yaiser. He started his talk by saying, “This is not about Flash, this talk is not about Flex, and this talk is definitely not about Flex. He also said the he writes awful code. I get the feeling that he follows Aral Balkans philosophy that you don’t have to have double doctorate in Computer Science and create perfect code with extended polymorphism to creat amazing things. And let me say Craig Swann, at Crash Media creates amazing kick-butt things. [...]

    curtismorley.com » Flash Forward Boston 2007 - Craig Swann
  40. dating agencys
    new dating relationships
    dating chat line
    uk no loan debt consolidation
    pros and cons of debt consolidation

    Exjji