www.zeroonezero.com

Amy’s Blog

Altering all tables in the database

Thursday, May 15th, 2008

So today I was doing some thinking about my next project, and I decided that I should not be deleting records willy nilly and instead using a flag for deletion.  I know, I’m a little behind the times, this is certainly basic database management, but you know how things are.  We do what we do because we learned our bad habits from programmers before us.  The bigger picture is, experience and reading peer materials (best practices blogs and websites) teach us how to think differently, and how to correct some of our bad habits.  As one who is always interested in correcting those bad habits, I came across a nifty solution.

Using the mysql Show Tables syntax in a ColdFusion cfquery, I am able to pull down a query result set of all of the tables within the database that I am working on.  Using that query is very simple then to loop over and conduct a new query that alters the tables, adding on the new column that I wanted.

<CFQUERY NAME=”test” datasource=”#dsn#” username=”#dbuser#” password=”#dbpass#”>    
  show tables;
</CFQUERY>

The query will output with a column named TABLES_IN_xxxxx where xxxxx is the name of your database.   Using this as my new variable, I can loop over the results and use the alter table to add my little ‘deleted’ switch.

<cfoutput query=”test”>
 <CFQUERY NAME=”testUpd” datasource=”#dsn#” username=”#dbuser#” password=”#dbpass#”>    
  ALTER TABLE #test.tables_in_xxxxx#
  ADD Deleted TINYINT(1) UNSIGNED NOT NULL DEFAULT 0;
 </CFQUERY>
</cfoutput>

So there you have it.  A nice tidy way to make a mass update to all tables in the database.  This can be modified in all sorts of ways.  Say I wanted to change the datatype of one of my fields, and it has foreign key references all over the place.  Well, I can do the same thing with the CHANGE column syntax.  Of course, as always, be wary of housing this online anywhere where it could be accessible to those who would have some ill intent, having database permission to alter tables is a dangerous set of permissions to be floating around.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , , , ,

Posted in Amy, Programming

Social Engineering of Social Networking

Wednesday, May 14th, 2008

It would be difficult for me to say how many people I know have a Facebook or Myspace account (or both). Many do. I had a Myspace account for a while, but I got tired of it. My ego didn’t need to be fed any longer by strangers who wanted to read about what I was doing today. Most parents have probably seen hundreds of pictures of their daughter, and their daughter’s friends pursing their lips and holding up their fingers in what I refer to as the Myspace pose. So there are tons of people out there on these social network sites. And they all want to customize their page with stuff: OMG, LOL, check out what ur Scooby Doo name is! or various applications that are now available through third party installable programs. Not only are your future employers using these sites to check you out, but so are those with more malicious intent. They are diving into your account trying to persuade you to go to sites where you either reveal your personal information or download and agree to installing a piece of software that will do it for them. All by seemingly harmless postings on your page. They are starting to call them ‘drive by downloads’. One little link on a friend’s page, you trust them, so you get the link too. Anyone who clicks the link downloads something to their computer, and not thinking about the repercussions, click ‘ok’ because we’re so used to all the random safeguards on our modern computers.

Social engineering has long been the way ‘hackers’ (I use this term loosely) gain information to be used maliciously. Long before the days of the web 2.0 these people were gathering dial in numbers and usernames and passwords from pieces of paper left around, in the trash, or by phoning up an unsuspecting staff member. Then came spam, soliciting something fun, sending you to links that were riddled with virus programs. Today we’ve learned these tricks and how to stay ahead of them, to an extent, but the experts in social engineering will continue to find ways to get the information you’re not so willing to give. These days, social networking sites are all the more happy to just give out that information. Oh, but your account is private? Do you really know that person you just let be a friend? Did you install an application or put one of those quiz links on your page? How about a friend of yours? Each new application can be developed and in those applications user information can be garnished. Most programmers will not care about gathering information, but some do. Every link could be malicious, you really don’t know until you go there, and even then, do you really? Not every anti-virus or security suite catches everything. It may already be too late.

Does it bother you that every move you make is tracked by a company? It happens every day, whether it is simple user information about the website you’re visiting, or if it’s something more complex, like your email address dug up through that application that tells you who your best love match is. You can be as paranoid or not as you want to be, hoping that your anti-virus/Internet security system is more up-to-date than those trying to steal your information. I don’t have a foil hat, but I try to keep up to date with the goings on in the security world, even if it doesn’t directly relate to me, as anyone who uses the Internet should. As long as your computer is connected, it is vulnerable to attack. Whether or not you help it along is up to you.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , , , , , , ,

Posted in Amy, Programming

I have a fish

Tuesday, May 13th, 2008

I know the saying is “I have a beef” but having a fish seems more fun…. and then it also goes with ‘I have a bone to pick’ as well, because I always have bones in my fish. 

This weekend I was working on a project, programming in ColdFusion, using one of those discount hosting places that everyone seems to love unless they’re the actual programmers.  There are a lot of things that go in to getting a site set up for use with ColdFusion.  You have to not only create the code, but create the database and the datasource connection, and any time things go wrong, it can cause a spiral of issues that continue to compound.  After spending several hours getting everything set up, I finally got to coding only to find that things I’ve done in the past on our DDA servers were not as easy to do on this particular server, as certain things were unavailable due to security restrictions.  One of these was the ColdFusion createobject.  Eventually I found that the createobject had a decent substitute in cfinvoke.  So what I was thinking was, well, if they’re basically doing the same thing, why is one locked down and not the other?  I believe the answer coming from what I’ve researched on the web is that the instantiation of objects using cfinvoke is different from createobject.  Also, cfinvoke does not appear to be able to instantiate java objects, which I guess is what drives the lock down.  Now if you ask tech support, they’ll say there is no such lock down, that everything is fine and you’ve just improperly coded your scripts.  Never mind that within the 5 items in the entire ‘knowledgebase’ one of them clearly states that certain tags are not available.  So on to other things.  I finally get my coding in and I begin adding code to upload an image.  CFFILE is a great function, one I tend to use on every project for some thing or another.  Unfortunately what ColdFusion doesn’t tell you is that CFFILE actually uploads first to a temp directory, and then into the destination folder.  If you do not have access to that temp directory, gosh golly, you’ll not be able to get that file uploaded and accessible.  So what do you do?  Tech support.

Here’s my beef.  Tech support.  Now I know that 90% of the people out there that contact tech support are probably on the lower rungs of the technical savvy scale, but for those of us who are not, we like to be regarded as people who know what they’re talking about.  I don’t want a canned response for the first 5 times I contact support, as if my situation was not individually reviewed.  The other day I sent in a problem with some software that I own.  What I got back was a long response about turning off software that I am not running on the computer.  Every now and then I get an error message in another piece of operating system software.  It comes up with an error number and everything.  So then it says to click this link for more information, you know, to help troubleshoot.  So I click the error number and there’s a long list of all kinds of error numbers, but mine is not on the list.  It gets very frustrating.

So how do we avoid this at DDA?  Well for one, all of our clients at DDA are important to us.  Whether we have done custom programming or are hosting websites, we take every issue seriously and try to get to the bottom of every problem.  Sometimes due to conditions out of our control, we cannot solve an issue (usually cross browser incompatibility) but we take the time to provide the best support we can.  We have several people on staff with varying degrees of knowledge and experience, and we can rely on that entire set of knowledge when diagnosing issues and troubleshooting.  Our support will never be form letter sent, unless of course it’s something like setting up an email account on Outlook, where we have created a simple step by step process that we can direct users to.  But the fact that we would send that only after knowing what the real problem is, rather than using that as a first step, will set us apart from most other technical companies.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: ,

Posted in Amy, Programming

coldfusion can can

Monday, May 12th, 2008

Every so often, I am asked by a member of the DDA team to write up something along the lines of “What are our programming capabilities?”  I get a chuckle out of this question.  I always have to ask them to get a little more specific about what they’re looking for, or at the very least, if it is OK that I give them a list of things we’ve already done instead.  To me, our custom programming capabilities are pretty much endless, it’s just a matter of time and money and whether or not I think we can get it done in that amount of time and money.  We have been able to do an amazing amount of work for a little programming department, and we’re not stopping our momentum.  So what I like to do is ask in return, ‘How about asking about what we can’t do?”  I can start with ‘well, we can’t travel in hyperspace’ and ‘we probably cannot program your coffee maker to brew beer in 30 seconds’, things that might sound completely irrational, but it may be feasible some time in the future.  Our web programming services are limited only by imagination.

What we can do is work with ColdFusion to create advanced programming; programming which can do just about anything on the web.  If we have access to your database, we can integrate a website with your current inventory management system.  If you need things to float around and work like it’s in a desktop environment but on the web, we can do that too.  What about image processing?  Sure.  File transfers? No problem.  Can we give your dog a bath?  Well, I don’t know about how you’re going to get the shower to chase down your dog, but we could probably find a way to run robotic software to scrub him.  I’m not saying it would be easy. It would probably take years, but we could do it, and we could do it using ColdFusion.  Why?  Because I have faith in the abilities of our team.  We have a unique bunch of very intelligent programmers who can do some amazing programming work.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , , , , , ,

Posted in Amy, Programming

comments from the peanut gallery

Thursday, May 8th, 2008

Today we have another post from the programming blah-g.  I am excited though.  Rumor has it that the comments are being turned on for our blog.  I just hope there’s some sort of captcha (and not one of those stupid ones where real people can’t read the letters) to keep out the bots.  I’d love to hear from my fellow ColdFusion programmers, or even just the outside world in general.  Then again, my posts going back sometimes even feel incoherent to me, so, I’m not sure I should be excited.  The only thing I don’t want to hear about is how much better other programming languages are. Blah blah blah.  Yeah, I know, your light-saber is bigger than mine.    Go ask Yoda if size matters.  But anyway, on to the blog.

Yesterday I was working with PayPal and Google Checkout.  Now I haven’t gone in to the whole cart and payment gateway system, but I did set up a sandbox for each of them to play in, and added some ‘pay now’/'buy now’ forms/buttons to the system I’m working on.  What I was trying to accomplish was an easy way to grab a payment without having to construct a whole huge system behind it.  So within an hour, I had both sandboxes set up (for those of you who don’t know, the sandbox is basically a safe place to test out your program, in this case the payment gateway, so we can make payments without using real credit cards etc) and I had the buttons on a standard form with the purchase prices thrown in dynamically.  I really have to say that for ease of use, those two systems really have something going.  You don’t have to create this huge system to talk back and forth to the server under secure sockets if you don’t want.  If you just want a simple way for your users to purchase a few items, this is the way to go.  Most ecommerce packages come with several gateway connections already, so if you’re looking for a full out shopping cart, I wouldn’t go the individual form route, especially since you’ve already got the code to do the processing.  It would be a pain to create more than a handful of ‘buy now’ buttons one by one, nor is it best if you want to keep track of who’s purchasing what and whether or not it’s paid (unless you go manual), but it works for something simple and quick, where you’re going to be manually adding in the payments made.

So, that was my task yesterday.  Don’t get me wrong, we’ve implemented more than our share of ColdFusion and php based ecommerce sites, with varying payment gateways, but normally our clients are not looking for a PayPal solution, nor have they probably even heard of Google Checkout, so this was a fun change of pace.  I enjoy having a testbed to play with, where I can see payments actually being processed on the back end, rather than having very little feedback because your test request doesn’t actually go in to the system, it just validates and moves on.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , , , ,

Posted in Amy, Programming

jquery fun

Wednesday, May 7th, 2008

As I get more and more into jQuery, I learn a few more things.  The latest and greatest of things is .each().  The original premise is this: I have an Ajax based form, one that degrades sort of gracefully, but it shows and hides information based on what is submitted.  I got to the point where the form submits nicely if all the right information is put in, but then when I popped open the form, it still had my previous values in it.  Now this is fine if there’s an error, where we can correct it, but this doesn’t work so well when we want to submit something new.  In regular old javascript, we would need the name of the form, or the name of the objects in the form, and either clear them out one by one, or if we have the form, loop over the elements and set the value of the form element to “”.  Fine fine.  Of course, I have jQuery.  So I did a little searching and I found two nifty things.  First there was a selector that looked like it might work “:input” which is meant to give back an array of all the input elements on the page: var allInputs = $(”:input”);  I tried a few different ideas, not really understanding what the selector did, but I ran across “.each” in my hunts.  I thought this was brilliant because I could get my array of elements and loop over them with each and three lines of code, I’m done.  Well, that was if I could figure out how to only deal with the one form I wanted…

My first incarnation of trials was this:  (I always throw alerts in to make sure we are functioning, whether or not it was correct)

$(”:input”).each(function() {
   alert(’boo’);
     $(this).val(”);
    });

 And this did just as I expected, it looped over all 50 or so inputs on the page, including buttons, selects, checkboxes etc.  It might be useful in another situation but not this one.  So then I tried playing with the plain selector since I really didn’t understand the :input selector:

$(”#contactForm input”).each(function() {
   alert(’boo’);
     $(this).val(”);
    });

This turned out better, it was only clearing out the values in the specified form.  The only problem was, it was also clearing out the submit button, which I wasn’t looking for.  I went ahead and added one more thing, a filter:

$(”#contactForm input[@type=’text’]”).each(function() {
     $(this).val(”);
    });

This worked beautifully.  Maybe another day I’ll play with the “:input” selector, but until then, I found my solution, and I’m quite happy with it.  Now I just have to get the rest of the project done.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , ,

Posted in Amy, Programming

Programming and Training

Tuesday, May 6th, 2008

When I was working on my programming degree (or computer science, whatever), obviously I had to take quite a few programming classes.  Some of them focused on obscure programming languages that I’ll probably never again use (in fact most of them) and some of them were all about methodologies and databases that my 20 something mind thought I’d never need.  Alas, I now wished I’d put more effort into some of them.  It wasn’t exactly easy, trying to juggle a full-time job and full-time college, and still be a college kid, so I did have to cut my corners where I could.  There are quite a few things I probably would have learned from the wisdom of professors and former IT professionals, but I find that most of what I learned 10-15 years ago was a great foundation. So many things have changed that I use very little of the actual skills today.

Why is this?  Why did we teach antiquated languages to students in preparation for the real world?  When I was first going to college in the early 90’s, programming and computer science was still full of math geeks plugging away at big mainframes.  That didn’t change for much of the 90’s, especially since most trade schools were looking to fill Y2K positions (mmm COBOL).  It was the lucky few that actually got to learn useful programming languages that are widely used today.  With the popularity of the Internet, it seemed that programming changed direction again.  There are designers and there are programmers, usually with very little crossover, as there are at DDA today.  Designers are great at design, but not so great at programming, and I’m certainly no designer, I can barely make my projects look plain and nice.  So then, what of the web programmers that we so desperately needed.  They were off being taught actionscript and javascript and maybe a little about MySql, but again, nothing useful.

So, here we are then, left to our own devices because technology moves faster than education.  We learn on the job as our clients tell us ‘hey we want this custom system that looks this cool’.  We got our theories and methodologies and knowledge base from BASIC and PASCAL, but we stepped ahead into new technologies, took our hits and continued on.  This is why we’re not perfect as programmers, because we’re always learning as we work.  We are finding better ways to do things daily, and finding that even the things we programmed 3 months ago there’s already been a new development.  So if anyone ever says that we do not have time to learn on the job, those are people that don’t understand that as programmers in the modern world, that is the only way we can continue to be innovative.  We must continue learning all the new tools and apply them or we will not be able to provide our clients with the best possible custom programs.  So we do… and I think we’ve done one heck of a job coming up with some really cool stuff.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , ,

Posted in Amy, Programming

Cinco de Mayo

Monday, May 5th, 2008

The 5th of May.  Why is this so important to a 3rd generation American of Eastern European descent?  Just as the 4th of July reminds those of us in the USA of freedom, so should the 5th of May.  American freedom was won against one of the most feared military of the day, the military of the country that had control of most of the world.  The same went for the battle that commemorates the 5th of May.  Innovation and perseverance, two qualities we should always consider important, led a small band of soldiers to defeat an army twice its size one morning in 1862. 

So what does all of this have to do with programming at DDA?  Is it the cerveza and tacos?  A sombrero and margaritas?  How about a mariachi band?  Ok, well all of the aforementioned things would definitely help programming move along faster and make it more fun, but I’m talking about the bones of what happened that morning in Puebla.  Innovation.  Thinking outside the box. Problem solving solutions.  Those phrases and keywords that we hear from management across the nation.  The Mexicans had a problem, they had to take on the monumental task of defeating an army twice its size.  They did so by diverting the mounted army from the infantry, and using some interesting tactics of cattle stampede.   This is the sort of thing the programmers at DDA face daily.  We have the monumental tasks of taking on some of the most complex custom programming in a short amount of time in order for our clients to have the best possible software that meets their needs.  We cannot always meet every want, but with innovative thinking, we can usually accommodate all requests, limited only by the funding and time we have to do our work in.  We work efficiently on our projects with ColdFusion (it is after all a pretty rapid application development system) to create the most advanced system possible in the shortest amount of time.  This proves on every project that we are capable of amazing things under short time frames and low budgets.  Much like the Mexicans in 1862, we can take on tasks much larger than traditional wisdom thinks, and overcome the obstacles, proving that we can do anything.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: ,

Posted in Amy, Programming

Lines that blur

Thursday, May 1st, 2008

The thought of having to write another blog this morning was starting to wear on me.  It’s not that I don’t do a lot of stuff during the day to potentially write about, but to me it’s not noteworthy.  I’m sure that if someone were looking over my shoulder, there would be plenty of things they would see for me to write about, alas, I do not have someone standing over my shoulder (only a screen to show my work) and I haven’t had any feedback.  So what is left to write about?  My house.  Specifically how the work I do at my house has crept up into stuff I do at work, and vice versa.

Yesterday, David asked me to caulk the new sign (which looks fantastic).  Since we recycled the old sign by putting a new sign on top, David wanted to be sure that stuff wouldn’t get behind the attached section and get gross, causing the sign to deteriorate from within and all the great effort gone to waste.  I loved doing it since it gives me a mental break and I can work with my hands, which is, as I have previously mentioned, something that brings a little bit of grounding into my life.  What I found funny is that over the past few weeks while working on my house, most of what I have been doing is just that, caulking.  I try to re-use anything and everything from the house that was there before, not only because it’s cost effective, but because it is environmentally friendly, and it keeps the feel of the house intact.  The house was built in 1902, so I don’t want to get rid of any of the character of the house, just enhance it.  So when I pulled all the trim off the floor, it was to be replaced with the same trim unless the trim itself was in really bad shape.  Long story short, I needed a lot of caulk to make it look finished.  Years of paint and abuse, though taken care of the best I could, just sometimes couldn’t be erased, so I fixed with wood putty and caulk where I couldn’t.  Plus, I had to replace most of the quarter-round, and caulking the seams always makes that look nice.

This past weekend a little bit of work creeped in to the house.  When we first moved in to the new place here at DDA, I was one of the people that helped out with the networking - running wires, getting jacks set up so that all rooms had enough connections for those who would need them.  Not that I hadn’t done it before, but it was a refresher course in getting Cat-5 Ethernet jacks set up (and fun trying to figure out how to get the wires over and under the obstacles).  Over the weekend, I decided that my wireless connection was just not cutting it for me, so I ran down to the local Home Depot and got myself some wire, jacks and face-plates.  I found the perfect place for the first jack, traced out the space I needed to cut and started at it.  My mistake seemed to be the fact that I was using a crappy jigsaw to cut through the plaster and its supporting slats.   Not that I don’t have better tools, it was just that the jigsaw was right there, handy.  Three sides of the little cutout rectangle went really well, but then what started happening as I was making my last cut that the section around the cut was starting to shake and I couldn’t get through the wood that backs the plaster.  As I sat there pondering the situation, my vibrating jigsaw shook off a large chunk of plaster and splintered the final piece of wood.  So what would have taken me about 20 minutes had it been standard drywall, was now a weekend project.  The rest of the wall needed to be sanded and patched, it was all lumpy from handymen before who were not so handy, or just paid no attention to detail.  By Tuesday I could put a layer of primer on the wall, and last night I finally got the jack in and it actually looks great.  It was just a lot more work than I expected.  This weekend I get to tackle the same project in one of the rooms upstairs.  At least I already ran the cat-5 cable…..

Other than the obvious, how does this relate to programming at DDA?  The projects in my house seem to be like the custom programming we do here at DDA.  To our clients, and often those here at DDA who are not programmers, they see the project as simple, like I saw my Ethernet jack.  Cut a hole, install the jack and you’re done; 20 minutes tops.  Most of the time in our projects, what seems simple, like cutting the hole, is not so simple at all.  Many things go into the simple little hole, intense planning and precautions need to be taken to prevent that hole from getting too big or causing problems on the wall as a whole.  Sometimes we cannot predict what will happen, and we have to fix a lot of things after the fact.  In the end, though, it looks beautiful, smooth, and clean, unless you’re the one working it, you don’t know all the mess it took to complete. 

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , ,

Posted in Amy, Programming

To frame or not to frame

Wednesday, April 30th, 2008

There are a lot of catch phrases out there when dealing with ColdFusion programming, or any custom programming for that matter.  One of these is ‘frameworks’.  So what is a framework?  Well, it’s just what it says, a framework. Perhaps a better word would be skeleton.  The purpose of a framework is to have a program control flow pre-built in to a project, so in theory, it can be created with greater efficiency, from design to development to maintenance.   Over the years here at DDA, I’ve created a custom framework that I tend to use in all of our projects.  In comparison to frameworks such as Fusebox, Coldspring, ColdBox, Mach II, Model-Glue, (the list goes on) for ColdFusion programming, it may be small and custom, but it is comfortable.  In the world of getting projects done on time and on budget, it’s difficult to take on the task of first learning to use a pre-built framework, so the one I’ve created has evolved over time.

Now when I say that I’ve created a custom ColdFusion framework, I use the term loosely.  It contains wrappers and reusable elements, some touches of standard architecture, but it’s not very structured, like some of the more sophisticated frameworks are.  Since it has been an evolution, it tends to change with each new project, because each project is a custom program on its own, but the bones usually remain the same.  What I have tried to do is separate out some of the functionality from design and both containing great reusable parts by using CFCs to wrap up commonly used functions.  Someday maybe I’ll have a chance to work with a traditional ColdFusion framework - take the time and energy to go through the plethora of choices and pick one I like, and use it.  Maybe it’ll make my life easier.  Until then, my custom programmed framework will just have to do.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • e-mail
  • Reddit
  • StumbleUpon
Tags: , , , , ,

Posted in Amy, Programming

Search


type and hit 'enter'