07.06.06

Ruby Tutorials for TextMate hackers, part 2

Posted in TextMate, ruby/rails at 12:11 am by Haris

In the previous article from this series we learned some basic things about Ruby and how to use it to make TextMate do our bidding. In this post, we’ll see how to use some of TextMate’s Ruby libraries to do more stuff.

Snippeting Away

We’ll create a command similar to the one we talked about last time. This one will take as input the selected text or current line, and will wrap each line in html tags, with a different tab stop to fill each tag. In other words, each line should end up looking like <${1:p}>line text here</${1:p}>, with increasing snippet tab number on each line. Not a very useful command maybe, we’ll learn how to do things along the way.

The first thing to do is to set the output of our command to be “Insert as Snippet”. The command’s name might not say it, but this will in fact replace the text that was inputted to the command, just like the “Replace Selected Text” output option. The only difference is that the output is interpreted as if it were a snippet. So we could do what we need via a command like:

#!/usr/bin/env ruby
i = 1
for line in STDIN.read.split("\n") do
  puts "<${#{i}:p}>"+line+"</${#{i}:p}>"
  i += 1
end

We use split("\n") instead of readlines so that each line we process doesn’t have the trailing newline. Then the <${#{i}:p}> part becomes <${1:p}> the first time and so on, thus producing our desired snippet behavior.

All is not rosy with our command however. Try it on a line that contains something in backticks, or contains something like $1. What do you think just happened?

Correct, these things got interpreted by the snippet mechanism, as well they should! So, what do we do about it? We have to do what’s called “escaping”. This is often done by putting a backslash in front of the character we want to “escape”. This will cause the snippet mechanism to not interepret that character as something special. So if we manage to make all the backticks into a slash followed by a backtick, and all the dollar signs into \$, and all the backslashes into double backslashes (\\), we should be ok. This is where regular expressions come in. We can do this with this piece of code:

line.gsub(/[$`\\]/, "\\\\\\0")

Ok, so we’ve seen the first part before, we are doing a gsub. We’ve seen what the brackets do, they tell us to match any of the things in them. In our case, we want to match $, a backtick and a slash. But since slashes have special power in regexps (namely they are used for escaping characters), we need to escape them in the regexp, hence the two slashes. (Otherwise, if there was only one slash, the engine would want to interpret the \] part as desiring to match a right bracket).

Then we are telling the engine to replace each such occurrence with the proper thing. The replacement string looks very complicated, so let’s try to explain it. Remember that a slash followed by a number is replaced by the various grouped matches. What we did not see back then is that using 0 gives us back the entire match. Also backslashes are treated as special characters in strings, which means they need to be escaped. So what we are really seeing in the replacement string is two slashes followed by \0. This all happens before the gsub command gets to work with the replacing. The gsub command now takes this and replaces the two slashes with one, and the \0 with the match. So we end up with our match preceded with a slash.

Where is my Library?

If that last paragraph was too complicated, don’t worry because you don’t actually have to understand it, at least not until you decide to. This is where TextMate’s Ruby libraries come in handy. TextMate has a “Support” directory, which has a “lib” subdirectory. This contains some very useful pieces of code. We will be concerned with three files in there, escape.rb, exit_codes.rb and dialog.rb. Depending on whether you have checked this directory out via subversion or not, this directory has different location. Luckily for you, TextMate does the hard work of finding it for you and saving the information in the TM_SUPPORT_PATH variable. So this little program executed as a command will show you this path:

#!/usr/bin/env ruby
print ENV['TM_SUPPORT_PATH']

We haven’t talked about ENV yet, now is the time. When our program executes, there are a number of shell environment variables defined. Some are provided by the system, others, more of interest to us, by TextMate. ENV is Ruby’s way of accessing these variables. It is what is called a “Hash” in Ruby-speak. Think of it as a dictionary: You provide it with a key, like 'TM_SUPPORT_PATH', and it gives you back its value. See the manual section on environment variables for a list of all the various variables that TextMate provides for our enjoyment.

Ok, so now we know how to find the path. The next thing is to use ruby’s require command to load the escape.rb library. We want to load it because it has a command e_sn that will do the “snippet character escaping” we did manually above. In fact, the code we used above is exactly what the e_sn command does. Here is the command we want:

#!/usr/bin/env ruby
require ENV['TM_SUPPORT_PATH'] + "/lib/escape.rb"
i = 1
for line in STDIN.read.split("\n") do
  puts "<${#{i}:p}>"+e_sn(line)+"</${#{i}:p}>"
  i += 1
end

ENV['TM_SUPPORT_PATH'] returns to us the path to the support directory. We then append the path to the actual file we are after.

escape.rb contains a couple of other escaping functions, which you might want to look into if you are messing with other things, like passing parameters to shell commands, or producing links to be used with a URI scheme, like file://.... or txmt://...., but we won’t get into that in this tutorial.

Talk to me

It’s time to get our user to interact with us. for instance, instead of using p as the default tag, we’ll ask our user to provide us with a tag. The tools to do that are in the dialog.rb library. The library provides a number of methods, whose names basically tell us what they do:

  1. Dialog.request_string, for requesting a string from the user.
  2. Dialog.request_secure_string, for requesting a password from the user.
  3. Dialog.request_item, for requesting the user to pick from a list of items.
  4. Dialog.request_confirmation, for requesting the user to confirm an action.

As an example of how things work, we will now use all but the secure string one. We will first offer the user a list of html tags to pick from. If the user cancels, we will then request then to type in the tag they want. In any case, we will ask the user to confirm their decision. Here is the script:

#!/usr/bin/env ruby
require ENV['TM_SUPPORT_PATH'] + "/lib/escape.rb"
require ENV['TM_SUPPORT_PATH'] + "/lib/dialog.rb"
choices = ["p","h1", "h2", "h3", "a", "li"]
item = Dialog.request_item(:title => "Selecting tag", :prompt => "Please select a tag to use, or Cancel to manually type a tag", :items => choices)
if item.nil? then
  item = Dialog.request_string(:title => "Entering tag", :prompt => "Type in a tag:", :default => "p")
end
if item.nil? then
  exit
else
  confirmed = Dialog.request_confirmation(:title => "Confirming", :prompt => "You selected the tag \"#{item}\". Are you sure?")
end
unless confirmed then
  exit
end
i = 1
for line in STDIN.read.split("\n") do
  puts "<${#{i}:#{item}}>"+e_sn(line)+"</${#{i}:#{item}}>"
  i += 1
end

Pretty long, eh? And it introduced a lot of new things, so let’s take them one at a time. You already know what the first three lines do. The fourth line defines an array by listing its elements. That’s what the brackets there do. So this line sets the variable choices to hold a list of strings.

The next line calls the fourth library command. It needs to pass it a number of parameters, and the way it does it is through a hash (yes, that’s the same kind of hash as in the ENV case). The way to indentify a hash is through the “key-value” pairs key => value, separated by commas. Normally one needs to enclose the whole thing in braces ({), but because this is passed as an argument into the method, it doesn’t need to.

The thing that looks weird is probably the :title notation. It would perhaps make more sense to say "title" instead, right? What is the : for? This is one of the most misunderstood entities in Ruby. It is called a “symbol”, and you should think of it as a light-weight string. Symbols work well as keys to hashes, for reasons that have partly to do with memory management. But this will have to wait for another article. For now, just use them when you feel like it. Use them mainly for strings that might pop-up over and over, and that are “fixed”, like the words “title” and “prompt” in our example.

So we basically tell the Dialog object, to request an item from the user, providing the given title for the window, the given prompt, and the list of items provided by the choices array. The Dialog object then takes the responsibility of showing the appropriate window, interacting with the user, and finally giving us back an answer.

What is this answer? Well, if the user made a selection, then it is that selection. If the user did not make a selection, or pressed Cancel, then it is nil (Actually, all these commands have a particular behavior if we add a block to them, but we won’t get into that yet).

The next line starts an “if block”, which you are probably familiar with. An if block checks to see if the condition provided to it is true or not, and acts accordingly. Remember, that anything but nil and false is true. In our case, we ask item if it is nil, and act accordingly. Note the question mark at the end of the method name nil?. It is a convention in Ruby that all methods that return a true-false answer should end in a question mark. This line is essentially the same as:

if item == nil then

The next line tells us what happens when the item was indeed nil. We ask the user to type in a string. Since everything here is the same as the request_items case, we’ll just move on. Notice, that next we ask again if the item is nil, and if it is we exit the program. This is the case where the user pressed Cancel twice. The keyword exit is very important, and we’ll come back to it in the next section.

In the else part some interesting things happen. First, note the \" inside the string. Those of you who have been following along carefully will have figured out what it does. It places an actual double quote in the string. Since the double quotes were used to delimiter the string, we need to escape them if we want them to appear in the string. You might ask, why didn’t we use single quotes to delimit the string instead? Because inside single quotes, the #{} thingie does not do evaluation. Try it!

Let’s move to the next interesting line, the one with the unless. unless simply means “if not”. It just reads a bit better, that’s all. Ruby tries to go out of its way to read better, which is great for programmers using it, but a pain for anyone writing a parser for it. Anyway, the rest of the script should already be familiar to you.

Although the script is not that long, we’ll shorten it a bit using another Ruby idiom. Ruby allows you to replace:

if condition then
  dothings
end

with

dothings if condition

So with these changes our code can be rewritten as:

#!/usr/bin/env ruby
require ENV['TM_SUPPORT_PATH'] + "/lib/escape.rb"
require ENV['TM_SUPPORT_PATH'] + "/lib/dialog.rb"
choices = ["p","h1", "h2", "h3", "a", "li"]
item = Dialog.request_item(:title => "Selecting tag", :prompt => "Please select a tag to use, or Cancel to manually type a tag", :items => choices)
item = Dialog.request_string(:title => "Entering tag", :prompt => "Type in a tag:", :default => "p") if item.nil?
exit if item.nil?
confirmed = Dialog.request_confirmation(:title => "Confirming", :prompt => "You selected the tag \"#{item}\". Are you sure?")
exit unless confirmed
i = 1
for line in STDIN.read.split("\n") do
  puts "<${#{i}:#{item}}>"+e_sn(line)+"</${#{i}:#{item}}>"
  i += 1
end

What you use is up to you. Ruby is all about empowering the programmer.

Leaving with Grace

If you tested what happens when we Cancel our command, you will probably have witnessed an unfortunate behavior. Whatever selection we had is gone. Why did that happen?

Well, because we told our program to exit, but had not given it any output. So it sent no output to TextMate. But earlier we had told TextMate to replace the selected text with the output, and so it did! So what we need is a way to tell TextMate that we don’t want it to do that any more.

Luckily for us, TextMate does offer us this power. Our exit command above is allowed to take a number as an argument, like: exit 200 or exit 1 or anything like that. exit 0 means that the program exits normally, and it is the default. Any other number means that the program did not exit normally, and whoever ran the program might want to take that into account. TextMate uses this number to determine what to do, so we can guide its behavior this way. We want to tell it to discard the output. This turns out to be exit code 200. So if you replace all the exit commands above with exit 200, things should work much better.

Well, obviously we don’t want to have to remember these numbers. That’s where another library file comes in, this time called exit_codes.rb. It offers us convenience methods to call instead. They are:

exit_discard, exit_replace_text, exit_replace_document
exit_insert_text, exit_insert_snippet, exit_show_html
exit_show_tool_tip, exit_create_new_document

All but the first one take an optional argument, which is the string to be printed out. They will also take into account anything that your program has already printed. You call these methods by having the object TextMate call them. Here is our program using this:

#!/usr/bin/env ruby
require ENV['TM_SUPPORT_PATH'] + "/lib/escape.rb"
require ENV['TM_SUPPORT_PATH'] + "/lib/dialog.rb"
require ENV['TM_SUPPORT_PATH'] + "/lib/exit_codes.rb"
choices = ["p","h1", "h2", "h3", "a", "li"]
item = Dialog.request_item(:title => "Selecting tag", :prompt => "Please select a tag to use, or Cancel to manually type a tag", :items => choices)
item = Dialog.request_string(:title => "Entering tag", :prompt => "Type in a tag:", :default => "p") if item.nil?
TextMate.exit_discard if item.nil?
confirmed = Dialog.request_confirmation(:title => "Confirming", :prompt => "You selected the tag \"#{item}\". Are you sure?")
TextMate.exit_discard unless confirmed
i = 1
for line in STDIN.read.split("\n") do
  puts "<${#{i}:#{item}}>"+e_sn(line)+"</${#{i}:#{item}}>"
  i += 1
end

Until Next Time

Well, that’s it for now! Here are a couple of exercises to keep you going until next time. We’ll be able to do a lot more once we learn more about scanning strings and matching regular expressions against them.

  1. Change the command to do the following. It looks to see whether the environment variable 'TM_MYLIST' is defined. If it is not defined then it continues normally. If it is defined, it’s supposed to be a space-separated list of the various tags. Your command should process this string and set the variable choices to this list of words instead of the default one. Then it should continue with the requests normally.
  2. Create a command that takes as input the entire document, and then offers the user a list of all possible output options, and acts accordingly. Right now this will have to be a long if statement, but later on we might see a quick-and-dirty way to do it using a hash. (Basically, the value of the hash can actually be a method to be called at an appropriate time.)

Later

3 Comments »

  1. After thought » Ruby Tutorials for TextMate hackers, part 3 said,

    July 7, 2006 at 4:04 pm

    […] In the previous tutorial we saw how to load some basic libraries and interact with the user using those. That post was not so much about Ruby as it was about TextMate. In this post we return to talking about Ruby, in particular some of its methods for manipulating strings. Along the way, we’ll see how to use the txmt: scheme. […]

  2. Paul McCann said,

    July 10, 2006 at 9:11 pm

    Hi Haris,

    thanks from a “Nuby” (my perl’s fine, but my Ruby is somewhat embryonic). You probably want to correct a few occurrences of, ah, “smart” quotes that appear in the code examples. I was getting no output at all from the commands until I finally twigged that each example had

    puts ““+line+””

    listed in the bundle editor. Them be curlies in there!! Once they were converted to plain double quotes everything ran nicely.

    Cheers,
    Paul

  3. Haris said,

    July 10, 2006 at 10:04 pm

    Paul, thanks, I hadn’t realize it. I must be some problem with one of my plugins. It also had made a lot of code disappear.

Leave a Comment

macrobid more drug side effects buy neurontin fosamax lawsuits effects of fluoxetine order tamiflu buy meridia online effexor overdose minocycline hcl paxil overdose potatoes not prozac temazepam tablets adipex no rx side effects of lamisil drug elavil heroin chic metformin oral flomax erection butalbital apap impotence monopril flextra medicationflomax diazepam without a prescription generic aciphex meclizine drug what is flonase levaquin oral aldara side effects phentermine diet pill medroxyprogesterone acetate online pharmacy vaniqa fluconazole online macrobid oral fosamax generic propecia prices paxil side affects methamphetamine arrests fluconazole pregnancy naprosyn oral nexium more drug side effects cephalexin oxazepam drug information ramipril lawyer pantoprazole formulation aciphex rebate buy levitra antivert side effects ortho cyclen viagra no prescription generic for norvasc premarin alternatives buy remeron antibiotic penicillin altace side effects xanax for sale protonix side effects vicoprofen online allegra and aciphex interaction phentermine 375 mg drug aciphex fluconazole and dangerous nexium oral mescaline cactus shooting flexeril buy phendimetrazine online buying vicodin drug tamoxifen doxazosin buy vicodin what is seroquel buy proscar keppra to treat depression famvir dosage buy synthroid without prescription marion jones steroids serevent steroid prozac side effect ortho molecular products atenolol reviews no prescription needed adipex lavorazione hashish in marocco what is sertraline discount tenuate what is tricor vicoprofen without perscriptionvioxx generic propecia sertraline oral what is cephalexin keflex no prescription where to buy steroids buy oxycontin without a prescription tramadol hcl acetaminophen viagra price ditropan alternatives ambien withdrawl soma buy levitra price buy acyclovir drug crystal methamphetamine premarin generic oxycontin abuse buy lexapro online prescription soma triphasil tabs online meds fioricet fioricet oral generic plavix vioxx lawyer nexium alternative buy tamiflu online fulvicin price paroxetine suicidal pepcid buy buy levitra online tamiflu from canadatamoxifen seroquel oral levoxyl and weightloss celebrex 200mg cialis without prescription risedronate 35mg glyburide side effects actos diabetes sildenafil cheap generic valacyclovir online fioricet effects prozac weight gain lorcet without rx mircette birth control pills buy ambien without a prescription tenuate dospan watson generic zocor anabolic steroids buy what is metoprolol prilosec informationprinivil clonazepam overdose meridia order buy cyclessa buy fosamax methamphetamine recipe imitrex oral buy anabolic steroids protopic children mircette without a prescription from us pharmacy history of phencyclidine what is microzide used forminocycline xanax without a prescription online pharmacy fioricet buy xanax on line alternative to fulvicin cheap renova without a prescription temazepam 15 mg tobradex sales oxycodone addiction flexeril drug carisoprodol online pharmacy what is the price for prinivil xanax oral tamiflu medication antabuse online triphasil rohypnol drug alternative to metrogel buy ultracet without prescription what is macrobid used for vicodin cod altace ramipril antabuse side effects cialis comparison levitra elavil medicine vicodin high famvir pregnancy new dilantin didrex atlanta steroids and sports nardil online pharmacy best price viagra tadalafil coupon norvasc side effects ativan data synthroid more drug side effects buy didrex tadalafil online acetaminophen discovery of penicillin soma watson tylenol codeine plendil blood pressure medicine prednisone withdrawal synthroid oral macrobid doses sertraline hcl naprosyn side effects promethazine buy tazorac potency pravachol bontril aceon oxycodone side effects tamiflu buy drug valium phentermine cheap tamoxifen breast cancer compazine and side effects glyburide interaction zithromax pregnancy evista concerns cheap flonase hyzaar generic cyclobenzaprine effects nasacort aq nasal spray levothroid weight loss tadalafil overnightt finasteride cheap nifedipine xr buy rabeprazole buying sibutramine making mdma tadalafil price captopril side effects online pharmacy sibutramine buspar medicine valtrex side effects zovirax cost high testosterone meridia price lexapro dosage steroids side effects buy vicodin without a prescription online pharmacy no prescription proscar phentermine prescription online esgic genericesomeprazole meridia weight loss actos side effects oxycodone pills testosterone booster valtrex price generic prilosec lortab abuse buy adipex online order hydrocodone what is elocon dog pepcid ac or zantac ranitidine drug viagra cialis levitra propecia pharmacy phencyclidine picture generic sarafemselsun blue famvir vs valtrex snorting zoloft vaniqa medicine buy tenuate without a prescription generic vicoprofen phentermine prescription treating vicodin withdrawl cipro side effects in women ultracet online alternative celebrex generic xenical methylprednisolone tablets genarit norvasc prilosec 20mg vicodin pictures starting klonopin prilosec online ambien overnight delivery generic vicodin biaxin problem tadalafil 20mg steroids online is ultram a narcotic buy viagra alternative miacalcin more drug uses flomax caps side effectsflonase definition prozac vicodin buy online buy nasacort oxycontin addiction hyzaar medication buy ramipril on line without prescriptionranitidine biaxin nexium histex 10mg dilantin buy lorazepam keppra weight gain diclofenac buy xenical otc albuterol advair inhaler online pharmacy flonase fioricet tablets tricor generic mononitrate tylenol during pregnancy omeprazole oral buy detrol child taking lisinopril tylenol pregnancy ativan complication lortab cod cheap k-dur tamiflu relenza famvir oral paroxetine withdrawlpatanol nizoral hair loss buy fulvicin flovent inhaler nicotrol inhalers lortab side effects antabuse drug zyprexa withdrawal nordette levora tadalafil generic provigil more drug uses cheap generic viagra barry bonds steroids viagra samples buy hydrocodone online flexeril generic fluconazole overnight delivery buy diazepam without prescription buy evista propecia prescriptions antibiotic macrobid online pharmacy sildenafil generic lipitor ionamin pills prempro without a prescription buy valporicvaltrex order xanax online vaniqa buy what is rabeprazole sodium paxil stopping is naisads in motrin cefixime xenical no prescription toprol medication buy lorazepam online serevent discus viagra online uk premarin withdrawal aldara zocor generic tamiflu require prescription oxycontin side effects natural testosterone temovate buy ultravate drug omeprazole overdose lortab no prescription needed oxycodone pictures ibuprofen buyimitrex omeprazole generic ecstasy pills proscar propecia smoke flexeril premarin creme clomid buy veterinary fulvicin metrogel topical gel fioricet generic qualitest drug spironolactone amoxycillin evista side affectsevoxac adipex online prescription approved online tramadol pharmacy what is k dur tabletsk-dur order hydrocodone online bupropion cheap paxil hydrocodone picture dosage of pravachol trazodone and pregnancytretinoin prednisone dosage adderall metformin and weight loss proscar forum orlistat xenical serevent lawsuit order ultram order phentermine online sarafem 10mg temazepam cap prescription adderall xr increase effects of oxazepam vaniqa lowest price rabeprazole buy generic sildenafil cheapest sibutramine levitra and cialis and viagra free generic levitra morphine generation cheap valium gemfibrozil buyghb zoloft side effects nardil on line generic serevent tamsulosin hydrochloride evoxac more drug uses plavix medicine mdma for salemeclizine xenical without prescription serzone withdrawal side effects of clomid what is ic butalbital paroxetine 20 mg synthroid without a prescription amaryl diabetic medication hydrocodone cod what is toprol trimox picture valtrex cheap aricept side effects soma prescriptions diovan buy vicodin generic allegra prescription uses for temovate medicinetenuate lorazepam withdrawal clomid side effects famvir coupons rohypnol pictures zestril oral is ativan addictive seroquel abuse cheap zithromax online valium no prescription pictures of mescaline penicillin allergy online tramadol phentermine side effects dangers famvir medication pictures what is terazosin viagra generic lortab online isosorbide buy isosorbide mononitrate oral zithromax antibiotic norvasc overdose how does didrex work tamoxifen citrate free nicotrol inhalernifedipine pharmacy usa lipitorlisinopril nardil parnate premarin side effects testosterone gel nexium price k-dur transdermal patchkeflex alcohol and prozac avodart flomax lortab addiction tretinoin for genital warts how to make heroin adderall prices dovonex what is folic acid propecia reviews order norco online buy spironolactone no prescriptionsteroids buy preven buy xanax using paypal augmentin online pharmacy prempro trial cheapest phentermine prices what is pcp clonidine side effects cheap generic levitra onlinelevothroid clarinex compared to claritin rosiglitazone actions what is folic acid for buy soma online protonix more for patients prilosec coupons buy serzonesibutramine side effects when taking gemfibrozil effexor drug side effects stopping prozac vicodin sleepiness buy atorvastatin buy generic triphasil what is atenolol zithromax online aciphex costs buy ketamine online propecia testimonials buy injectable anabolic steroids xanax 2mg order tamiflu without prescription hydrocodone buy relafen drug kenalog shots wellbutrin withdrawal symptoms history of steroids buying valium online pravachol drug interactions buy fioricet w codeine side effects flomax sumatriptan from mexico cardura fabric esomeprazole magnesium uses of penicillin renova buy clonazepam fedex renova without prescription promethazine pill lotrel low pulse rate tadalafil cialis from india lortab without prescription side effects of diazepam buy adderall pills cyanocobalamin buy ultram withdrawal tamsulosin hcl propoxyphene apap serevent inhaler what does oxycodone look like sarafem canada flexeril online soma medication didrex side effects zyban buy provigil 200mg tab generic dovonex what is nexium buy valtrex alprazolam xr what is finasteride generic nasonex metformin dosage lasix without a prescriptionlescol diflucan adderall withdrawal generic premarin no prescription generic valtrex buy cheap generic nordette transderm pioglitazone hydrochloride accupril buy reactions to amoxycillin medication nexium protopic and vitiligo monopril side effects skelaxin side effect hydrocodone lortab generic zoloft proscar and pregnancy purchase xanax online order xenical seroquel buy fluconazole side effects about sertraline discount phentermine overnight fedex wellbutrin withdrawal proscar without prescription roxicet pill fosamax buyfulvicin valtrex girl oxazepam abuse carisoprodol online soma generic sibutramine adipex without prescription methylphenidate side effects ultram drug manufacturer of prinivil buy triamterene online glucophage and weight loss zovirax more drug uses vicodin withdrawlsvicoprofen relafen medication metrogel vaginal celebrex celecoxib phendimetrazine side effects adderall buy alprazolam online fedex mircette more drug side effects nasacort nasal spray order famvir ortho tri-cyclen side effects of keppra buy sibutramine meridia litigations minocycline without prescription generic xanax avandia drug alesse side effects cheap vermox online trazodone hcl tadalafil cod valium on line buy ketamine trazodone and clonazepam buy prinivilproctocort buspirone abuse accolate buy detrol and relief discovery penicillin tylenol with codeine canadaultracet xanax generic propoxyphene abuse lortab information buy zanaflex online buy depakote without a prescription antivert drug purchase phentermine online generic avapro lipitor muscle problems neurontin gabapentin miralax for children purchase fioricet online buy ultracet online no prescription patanol canada keflex oral celexa online pharmacy xanax no prescription clomid and pregnancy oxycontin for sale alternative viagra trazodone dosage buy tenuate dospan bontril no script kenalog lotion buy benicar avapro interactions buy macrobid without prescription metrogel side effects valium dosage what is flextra seroquel and alcohol what is levaquin generic for evista medicines what is famvir cardura buy generic ultram overdose roxicet erection viagra ibuprofen side effects what is nifedipine celecoxib alternative phencyclidine drugs low dose naltrexone prilosec nexium toprol information nifedipine cream order zithromax online what is supraxsymmetrel lorcet no prescription cyclobenzaprine 10mg side effects of lotrel prozac more drug uses side effects of ultram cipro no prescription purchase meridiamescaline yasmin buy no prescription ionamin lanoxin side effects sildenafil 100mg nasonex no rx what is trazodone valium online generic for altace overnight xanax online pharmacy tramadol propranolol hydrochloride cheap ultram online cheapest viagra online prescription tamiflu lotrisone more drug uses lipitor side effect lotensin dosage facts on ecstasy xanax xr estradiol levels cheap nasonex cyanocobalamin levoxyl and weight loss online prescription for adipex buy levaquin what is sibutramine zyban information buy tramadol side effects of propranolol purchase vicodin online phendimetrazine pills evista more drug interactions fioricet and pregnancy valtrex during pregnancy fioricet medication meridia side effects withdrawal symptoms of prednisone buy ambien buy naprosyn xanax valium buy proctocort alcon patanol nizoral pills toprol medicine valtrex and pregnancy nexium side effect cozaar cough vicodin addiction flomax tamsulosin canada order soma online mescaline dosage and effectsmetformin online pharmacy ceftin drug metoprololmetrogel what is plavix clopidogrel buy what is ritalin xanax abuse buy generic allegra fexofenadine cheap zithromaxzocor morphine sulphate didrex no prescription needed adipex review who discovered ionamin neurontin lawsuit ceftin side effects heroin overdose side effects of naprosyn adipex without rx zocor side affects ultram prescription gemfibrozil more drug uses adipex alternatives what is soma order phendimetrazine buy viagra on line promethazine codeine buspirone hydrochloride soma bicycles horse steroids pantoprazole label carton zanaflex dosage didrex drug discount zocorzoloft roxicet oral cialis levitra sale viagra side effects of ramipril ultram pain medication metformin more drug side effects side effects of miacalcin generic levoxyl purchase soma online elocon ointment adipex side effects brain purchase sildenafil citrate buy amoxil vioxx news norvasc side effect pravastatin side effects actonel buy ranitidine buyrelafen buy furosemide without a prescription miacalcin cause pancreatitis medication butalbital how to make mdma buy phentermine without prescription prevacid pregnancy prednisone tablets verapamil side effects serzone claims fluoxetine and pregnancy where to buy tramadol osteonecrosis and fosamax enalapril side effects buy zovirax without prescription how to use steroids lorazepam dosage prozac nation what is microzide fluconazole and natural medicine lamisil forums buy retin a online viagra for women what is azmacort tetracycline online lexapro more drug interactionslipitor buy generic sertraline buy wellbutrin premarin no prescription loratadine overdoselorazepam cheapest propecia discount xanax what is thiamine mononitratemonopril pantoprazole side effects what is zovirax bontril online pharmacy lexapro and weight gain medrol dosepack advair diprolene generic ramipril oral serzone increased energy premarin vaginal cream what is tobradextoprol tadalafil tablets skelaxin drug renova without a perscription what is risperdal patanol opht cozaar side effects buspirone hcl dangers of steroids nasonex nasal spray description triphasil acyclovir valacycovir on line phentermine tadalafil comprar retin a melanexmeridia what is estradiol plendil incontinence soma pharmacy buy sildenafil citrate cyclobenzaprine flexeril what is protonix steroids pictures cheap nexium tylenol biaxin reaction ritalin adhd nexium without prescriptionnicotine nordette and no prescription and thailand evista generic valium vicodin oral nexium pill phentermine pill imitrex coupons cheap celebrex online chemical name for suprax buy tussionex without prescription norco bike norco wolverine what is glyburide ritalin alternatives fluoxetine 20mg flonase nasal spray child paxil buy meridia on line buy zestrilziac risperdal overdoseritalin lotrisone lotion skelaxin medication purchase finasteride canadafioricet skelaxin dosage thiamine mononitrate formula tramadol on line side effects of flomax acyclovir aura soma furosemide prescription oxycodone overdose prozac information ketamine effects what is methylphenidatemethylprednisolone aciphex rabeprazole paxil lawsuit what is restoril buy prozac flexeril more drug side effects order tramadol online metrogel vaginal cream snorting zanaflex alabama psilocybin mexican steroids sertraline hydrochloride child overdose lisinopril what is oxycontin purchase tetracycline without prescriptiontiazac coreg tamsulosin hcl lanoxin digoxin thiamin mononitrate fioricet line purchase viagra online phentermine adipex temovate cream snorting flexeril propranolol side effects medicine fluconazole purchase acyclovir online tiazac diltiazem buy ambien overnight rabeprazole drug depression provigil tenuate tablet lexapro and pregnancy bontril diet pills buy eunlose lipitor interaction tadalafil cialis viagra prices increase testosterone buy hydrocodone cod generic tobradex history of anabolic steroids effects of prozac tenuate discount phendimetrazine 35mg flextra pregnancy lortab description smoking klonopin hydrochlorothiazide and pregnancy ultram cash on delivery buying vicodin online yellow xanax bars birth control nordette generic lamisil cheap soma glipizide side effects drug altace retin a wrinkles symmetrel abusesynalar phendimetrazine online paxil pregnancy transderm buy xenical side effects loratadine buy buy adderall without a prescription buy cheap fioricet ghb drug adderall online plavix news lexapro withdrawal symptoms symmetrel buy effexor side effects propranolol anxiety cozaar 50mg serevent law proscar side effects order sibutramine sumatriptan succinat information on tramadol tamiflu no prescription needed cream verapamil prilosec side affects what are steroids children motrin buy generic valium online cheap zyban fosamax warning zocor more drug side effects synalar nasal buy ziaczithromax terazosin drug buy tamiflu mexico rabeprazole sodium ultracet with aspirin triphasil without prescription lipitor prescription side effects valtrex online purchase steroids make ghb furosemide water pillsgemfibrozil esomeprazole magnesium in mexico mircette online cialis levitra vardenafil kidney infection macrobid zyban no prescription active ingredients in adipex fioricet prescription hives motrin allergy paxil quitting medrol side effects clonazepam cod medrol for dogs compazine drug tretinoin mexico athletes and steroids cheapest meridia xenical diet pill nizoral shampoo fosamax patent expiration what is norvasc vermox buy levaquin tablet phencyclidine impurities serevent buyseroquel propoxyphene darvocet order fioricet online buy ativan with overnight delivery effects of lipitor free singulair medicine nexium prescription hydrocodone side effects buy acyclovir hyzaar buy what is triamterene diclofenac 75mg soma online augmentin side effects buy zovirax buspar paxil ionamin phentermine macrobid pregnancy wellbutrin no prescription ultram online pharmacy intravenous pantoprazole guidelines buy mdma acyclovir dosage drug test vicodin atrovent nortriptyline for chronic pain avandia dosage pravachol side effects order vermox online protonix more drug interactions flonase during pregnancy aldactone withdrawal lorazepam alcohol withdrawal generic tamsulosin phenergan vomiting neurontin addiction buy generic propecia picture of valacyclovir levitra 20mg zovirax pills prednisone without a prescription actonel patient reviews minocycline hydrochloride synthroid lawsuittadalafil vicodin drug test protopic side effects biaxin breastfeeding terazosin oral diazepam overnight norco online valporic diltiazem buy norvasc problems diethylpropion 25mg kenalog in orabase diovan generic cialis lawyer columbus levaquin 500mg buy patanol buy flonase online premarin without a prescription lamisil cream buy relenza sumycin buy oxycodone buyoxycontin tramadol abuse adderall and pregnancy orlistat over the counter buy generic viagra temazepam more drug side effects nortriptyline side effects premarin buy online uk kenalog cream generic nexium xanax ambien hydrocodone buy bupropion side effects of tramadol lotrel generic pictures of hydrocodone flumadine prescribing information actonel generic pure mdma marijuana pics lasix oral side effects of sertraline norco bigfoot buy zithromax without prescription lipidos orlistat preven ca capsules buy orlistat furosemide buy side effects of flonase coreg 25mg buy amaryl prozac buy online levitra versus cialis no prescription lorazepam prevacid generic ethinyl estradiol what is spironolactone buy premarin online best price pioglitazone estradiol cream durg flomax viagra for woman information what is propoxyphene meclizine tablets what is premarin suprax cefixime isosorbide side effectspotassium k dur online avandia side effect ambien online without prescription vicodin effects order levitra buy roxicet no prescription needed flextra ds medication cialis tadalafil buy tamsulosin paxil side effects info on miacalcinmicrozide india generic tadalafil evista and breast cancer adipex tenuate paroxetine withdrawal symptoms hydrocodone bitartrate tobradex lawsuit actonel jaw bone buy xalatan on line pharmacy fioricet with codeine folic acid symptoms viagra sales skelaxin generic ultracet pain pill renova cream hydrocodone and pregnancyhyzaar discount xenical alprazolam tablets miacalcin side effects zestril without prescription description of lorazepam ultram oral morphine effects buy alphagan trazodone for sleep sildenafil citrate soft tabs sumatriptan mexico imitrex prilosec online coupon premarin estradiol alternatives to viagra baby motrin famvir 500mg terbinafine and pregnancy adipex no prescription ibuprofen and pregnancy spironolactone cream psilocybin spores acetaminophen overdose flomax medicine levoxyl more drug uses buy finasteride online relenza online alprazolam zoloft carisoprodol no prescription vicodin withdrawal symptoms drug side effects norvasc ketamine overdose buy renova without a prescription snorting clonazepam lanoxin buy tadalafil soft tabs phenergan side effects levitra with lotrel side effects of butalbital what is propranolol cyclobenzaprine used