Ok – after much delay, here is the highly anticipated first release:
<?php/*** The ps_suregate class, containing the payment processing code* for transactions with Suregate.net** @version $Id: ps_suregate.php 2010-25-12* @package VirtueMart* @subpackage payment* @copyright Copyright (C) 2009 created by: Soeren - All rights reserved.* Modified for Suregate.net by TheWebDoctor.us* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php* VirtueMart is free software. This version may have been modified pursuant* to the GNU General Public License, and as distributed it includes or* is derivative of works licensed under the GNU General Public License or* other free or open source software licenses.* See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.** http://virtuemart.net*/if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );class ps_suregate {var $payment_code = "AN";/** Show all configuration parameters for this payment method* @returns boolean False when the Payment method has no configration*/function show_configuration() {global $VM_LANG, $sess;$db = new ps_DB;$payment_method_id = vmGet( $_REQUEST, 'payment_method_id', null );/** Read current Configuration ***/require_once(CLASSPATH ."payment/".__CLASS__.".cfg.php");?><table class="adminform"><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_ENABLE_AUTORIZENET_TESTMODE') ?></td><td><select name="AN_TEST_REQUEST" class="inputbox" ><option <?php if (AN_TEST_REQUEST == 'TRUE') echo "selected=\"selected\""; ?> value="TRUE"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_TEST_REQUEST == 'FALSE') echo "selected=\"selected\""; ?> value="FALSE"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_ENABLE_AUTORIZENET_TESTMODE_EXPLAIN') ?></td></tr><tr class="row1"><td class="labelcell">Suregate.net Server Hostname</td><td><input type="text" name="AN_HOSTNAME" value="<?php echo defined('AN_HOSTNAME') ? AN_HOSTNAME : 'https://secure.suregate.net:443/smartPayments/transact.asmx/ProcessCreditCard?' ?>" /></td><td>Name of the Suregate.net Server, the requests are sent to. Default Value: <strong>https://secure.suregate.net:443/smartPayments/transact.asmx/ProcessCreditCard?</strong><br /></td></tr><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_USERNAME') ?></td><td><input type="text" name="AN_LOGIN" class="inputbox" value="<?php echo AN_LOGIN ?>" /></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_USERNAME_EXPLAIN') ?></td></tr><tr class="row1"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_KEY') ?></td><td><a class="button" id="changekey" href="<?php $sess->purl($_SERVER['PHP_SELF']."?page=store.payment_method_keychange&pshop_mode=admin&payment_method_id=$payment_method_id") ?>" ><?php echo $VM_LANG->_('PHPSHOP_CHANGE_TRANSACTION_KEY') ?><a/></td><td> </td></tr><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_PAYMENT_CVV2') ?></td><td><select name="AN_CHECK_CARD_CODE" class="inputbox"><option <?php if (AN_CHECK_CARD_CODE == 'YES') echo "selected=\"selected\""; ?> value="YES"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_CHECK_CARD_CODE == 'NO') echo "selected=\"selected\""; ?> value="NO"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_PAYMENT_CVV2_TOOLTIP') ?></td></tr><tr class="row1"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_PAYMENT_AN_RECURRING') ?></td><td><select name="AN_RECURRING" class="inputbox"><option <?php if (AN_RECURRING == 'YES') echo "selected=\"selected\""; ?> value="YES"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_RECURRING == 'NO') echo "selected=\"selected\""; ?> value="NO"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_PAYMENT_AN_RECURRING_TOOLTIP') ?></td></tr><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_AUTENTICATIONTYPE') ?></td><td><select name="AN_TYPE" class="inputbox"><option <?php if (AN_TYPE == 'AUTH_CAPTURE') echo "selected=\"selected\""; ?> value="AUTH_CAPTURE">AUTH_CAPTURE</option><option <?php if (AN_TYPE == 'AUTH_ONLY') echo "selected=\"selected\""; ?> value="AUTH_ONLY">AUTH_ONLY</option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_AUTENTICATIONTYPE_EXPLAIN') ?></td></tr><tr><td colspan="3"><hr/></td></tr><tr class="row1"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_PAYMENT_ORDERSTATUS_SUCC') ?></td><td><select name="AN_VERIFIED_STATUS" class="inputbox" ><?php$q = "SELECT order_status_name,order_status_code FROM #__{vm}_order_status ORDER BY list_order";$db->query($q);$order_status_code = Array();$order_status_name = Array();while ($db->next_record()) {$order_status_code[] = $db->f("order_status_code");$order_status_name[] = $db->f("order_status_name");}for ($i = 0; $i < sizeof($order_status_code); $i++) {echo "<option value=\"" . $order_status_code[$i];if (AN_VERIFIED_STATUS == $order_status_code[$i])echo "\" selected=\"selected\">";elseecho "\">";echo $order_status_name[$i] . "</option>\n";}?></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_PAYMENT_ORDERSTATUS_SUCC_EXPLAIN') ?></td></tr><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_PAYMENT_ORDERSTATUS_FAIL') ?></td><td><select name="AN_INVALID_STATUS" class="inputbox" ><?phpfor ($i = 0; $i < sizeof($order_status_code); $i++) {echo "<option value=\"" . $order_status_code[$i];if (AN_INVALID_STATUS == $order_status_code[$i])echo "\" selected=\"selected\">";elseecho "\">";echo $order_status_name[$i] . "</option>\n";} ?></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_PAYMENT_ORDERSTATUS_FAIL_EXPLAIN') ?></td></tr><tr class="row1"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_RESPCODES') ?></td><td><select name="AN_SHOW_ERROR_CODE" class="inputbox"><option <?php if (AN_SHOW_ERROR_CODE == 'YES') echo "selected=\"selected\""; ?> value="YES"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_SHOW_ERROR_CODE == 'NO') echo "selected=\"selected\""; ?> value="NO"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_RESPCODES_EXPLAIN') ?></td></tr><tr class="row0"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_EMAIL_MERCHANT') ?></td><td><select name="AN_EMAIL_MERCHANT" class="inputbox"><option <?php if (AN_EMAIL_MERCHANT == 'YES') echo "selected=\"selected\""; ?> value="YES"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_EMAIL_MERCHANT == 'NO') echo "selected=\"selected\""; ?> value="NO"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_EMAIL_MERCHANT_EXPLAIN') ?></td></tr><tr class="row1"><td class="labelcell"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_EMAIL_CUSTOMER') ?></td><td><select name="AN_EMAIL_CUSTOMER" class="inputbox"><option <?php if (AN_EMAIL_CUSTOMER == 'YES') echo "selected=\"selected\""; ?> value="YES"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_YES') ?></option><option <?php if (AN_EMAIL_CUSTOMER == 'NO') echo "selected=\"selected\""; ?> value="NO"><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_NO') ?></option></select></td><td><?php echo $VM_LANG->_('PHPSHOP_ADMIN_CFG_AUTORIZENET_EMAIL_CUSTOMER_EXPLAIN') ?></td></tr></table><?php// return false if there's no configurationreturn true;}function has_configuration() {// return false if there's no configurationreturn true;}/*** Returns the "is_writeable" status of the configuration file* @param void* @returns boolean True when the configuration file is writeable, false when not*/function configfile_writeable() {return is_writeable( CLASSPATH."payment/".__CLASS__.".cfg.php" );}/*** Returns the "is_readable" status of the configuration file* @param void* @returns boolean True when the configuration file is writeable, false when not*/function configfile_readable() {return is_readable( CLASSPATH."payment/".__CLASS__.".cfg.php" );}/*** Writes the configuration file for this payment method* @param array An array of objects* @returns boolean True when writing was successful*/function write_configuration( &$d ) {$my_config_array = array("AN_TEST_REQUEST" => $d['AN_TEST_REQUEST'],"AN_LOGIN" => $d['AN_LOGIN'],"AN_HOSTNAME" => $d['AN_HOSTNAME'],"AN_TYPE" => $d['AN_TYPE'],"AN_CHECK_CARD_CODE" => $d['AN_CHECK_CARD_CODE'],"AN_VERIFIED_STATUS" => $d['AN_VERIFIED_STATUS'],"AN_INVALID_STATUS" => $d['AN_INVALID_STATUS'],"AN_RECURRING" => $d['AN_RECURRING'],"AN_EMAIL_MERCHANT" => $d['AN_EMAIL_MERCHANT'],"AN_EMAIL_CUSTOMER" => $d['AN_EMAIL_CUSTOMER'],"AN_SHOW_ERROR_CODE" => $d['AN_SHOW_ERROR_CODE']);$config = "<?php\n";$config .= "if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' ); \n\n";foreach( $my_config_array as $key => $value ) {$config .= "define ('$key', '$value');\n";}$config .= "?>";if ($fp = fopen(CLASSPATH ."payment/".__CLASS__.".cfg.php", "w")) {fputs($fp, $config, strlen($config));fclose ($fp);return true;}else {return false;}}/**************************************************************************** name: process_payment()** created by: Soeren** description: process transaction with Suregate.net** parameters: $order_number, the number of the order, we're processing here** $order_total, the total $ of the order** returns:***************************************************************************/function process_payment($order_number, $order_total, &$d) {global $vendor_mail, $vendor_currency, $VM_LANG, $vmLogger;$database = new ps_DB;$ps_vendor_id = $_SESSION["ps_vendor_id"];$auth = $_SESSION['auth'];$ps_checkout = new ps_checkout;// Get the Configuration File for authorize.netrequire_once(CLASSPATH ."payment/".__CLASS__.".cfg.php");// connector classrequire_once(CLASSPATH ."connectionTools.class.php");// Get the Transaction Key securely from the database$database->query( "SELECT ".VM_DECRYPT_FUNCTION."(payment_passkey,'".ENCODE_KEY."') as passkey FROM #__{vm}_payment_methodWHERE payment_class='".__CLASS__."'AND payment_enabled = 'Y'" );$transaction = $database->record[0];if( empty($transaction->passkey)) {$vmLogger->err( $VM_LANG->_('PHPSHOP_PAYMENT_ERROR',false).'. Technical Note: The required transaction key is empty! The payment method settings must bereviewed.' );return false;}// Get user billing information$dbbt = new ps_DB;$qt = "SELECT * FROM #__{vm}_user_info WHERE user_id=".$auth["user_id"]." AND address_type='BT'";$dbbt->query($qt);$dbbt->next_record();$user_info_id = $dbbt->f("user_info_id");if( $user_info_id != $d["ship_to_info_id"]) {// Get user billing information$dbst = new ps_DB;$qt = "SELECT * FROM #__{vm}_user_info WHERE user_info_id='".$d["ship_to_info_id"]."' AND address_type='ST'";$dbst->query($qt);$dbst->next_record();}else {$dbst = $dbbt;}// Option to send email to merchant from gatewayif (AN_EMAIL_MERCHANT == 'NO') {$vendor_mail = "";}if (AN_EMAIL_CUSTOMER == 'YES') {$email_customer = "TRUE";} else {$email_customer = "FALSE";}//Authnet vars to send$formdata = array ('UserName' => AN_LOGIN,'Password' => $transaction->passkey,'TransType'=> 'Sale','CardNum' => $_SESSION['ccdata']['order_payment_number'],'ExpDate' => ($_SESSION['ccdata']['order_payment_expire_month']) . substr ($_SESSION['ccdata']['order_payment_expire_year'],2),'Amount' => $order_total,'MagData' => '','NameOnCard' => $_SESSION['ccdata']['order_payment_name'],'InvNum' => substr($order_number, 0, 20),'PNRef' => '','Zip' => substr($dbbt->f("zip"), 0, 20),'Street' => substr($dbbt->f("address_1"), 0, 60),'CVNum' => '','ExtData' => '',);//build the post string$poststring = '';foreach($formdata AS $key => $val){$poststring .= urlencode($key) . "=" . urlencode($val) . "&";}// strip off trailing ampersand$poststring = substr($poststring, 0, -1);if (defined('AN_HOSTNAME')) {$host = AN_HOSTNAME;} else {$host = 'https://secure.suregate.net:443/smartPayments/transact.asmx/ProcessCreditCard?';}$result = vmConnector::handleCommunication( "https://secure.suregate.net:443/smartPayments/transact.asmx/ProcessCreditCard?", $poststring );if( !$result ) {$vmLogger->err('The transaction could not be completed.' );$vmLogger->notice( var_export($result,true) );return false;}$response=new SimpleXMLElement($result);// Approved - Success!if ($response->Result=='0') {$d["order_payment_log"] = $VM_LANG->_('PHPSHOP_PAYMENT_TRANSACTION_SUCCESS').": ";$vmLogger->debug( $d['order_payment_log']);return True;}// Payment Declinedelseif ($response->Result='12') {if (AN_SHOW_ERROR_CODE == 'YES') {$vmLogger->notice( var_export($result,true) );}$d["order_payment_log"] = $response;return False;}}}
I dunno, it came up a few times a work today and I considered being unconventional in all instances. Actually ended up being conventional and un equally and they all came out well. So far anyways. Hey check in with my man Craig Byrne (No, not like John Byrne) on this page:
Heck, I just figured conventional practicality is what everyone else expects – especially in business. The competition likes to talk about their competition going down in flames while suddenly discovering the holy grail of twitter and facebook. And by holy grail I mean your online office post it note and wadded paper wastebasket. Anyways, Keep It Simple Stupid.
In other news, have you noticed all the people driving in from out of town? ‘GSP Arena Tops 750K’ Coming soon…
Man I do love Greenville – especially disc golf in Greenville. I wanna put Timmons up for a while, and so does my average
One of the most important and very first things we do for our clients is GET THEM ON GOOGLE MAPS! And now that they have the new QR codes this is more important than ever! First let’s take a look at what exactly a QR code is and how it will benefit business of the future…
So as you can imagine, the QR system is going to blow a whole through the interactive barriers of personalized marketing! To insure our clients were ready to go with this new technology we immediately upgraded one of our most dedicated, Keowee Falls RV Park with their very own personalized QR code from Google and published it immediately to their website. Check it out – isn’t that cool!
In the coming weeks we will be adding this feature to all our existing and new clients, we’d love to hear your response. How would you use a QR code on your website?
Link your Blog up to Facebook, or call us to do it for you! Every time you post a new article it will also publish a link to your feed (that your friends can see in their Home page) that intros your article with the first couple of sentences and one of any pictures you included. Here’s the kicker though – you’ll realistically need 200 friends for every single person to subscribe to your blog. OR, 1 person with 1000 friends that likes your article enough to share it with his friends – who are all BLOG MANIACS that will comment on your blogs, share them with their friends who will in turn call the 5 o’clock news screaming about, “OMG DID YOU READ THAT FREAKING BAWD AZZ BLAWG???!?!?”. In the event you ever find yourself in the latter situation I’m gonna assume you are writing about Twilight movies or Canadian Hockey or something.
If you are writing about Sheet Metal Fabrication or MLM Network Marketing Recruiting then you will more than likely be writing for a finite audience that you could possibly even calculate the size and make-up of. Think about this when you are writing your blog, “Who wants to read this?” and you will then discover enhanced motivation and purpose.
Finally, read your own blog and ask yourself – would I read this? If not, fun it up a bit! Get your stick out of the mud and join us this weekend at FunBlogTacular.GoodTimes! Seriously, make it fun and it will be fun every time. Remember you are building a library of articles for current AND Future Subscribers so making them fun also makes them durable.
Alright, have a good time!
A blog is most like a magazine. You would pick up a magazine and read the articles and look at the pictures. You would look at a blog website and read the articles and look at the pictures. If you like the articles, you would subscribe to the magazine so that you get the new articles in your mailbox every month. With a blog you would subscribe to get the new articles emailed to you as soon as they are written. You would give a magazine to a friend to look at an article you liked. You would share an article on a blog by clicking a “share this” link to post the link to the article on your facebook wall, or you would copy and paste the link in an email to your friends.
The one thing a blog does that a magazine does not is let you leave comments on the articles. So you might read a blog article and all the comments below the article one day – then go back the next day to read new comments or to respond to comments about your comment.
Here is about the best video on what about a Blog is:
For some strange reason I woke up around 5:30 this morning, rolled over and checked the news on my laptop. BANG – an 8.8 magnitude earthquake hits Chile causing a massive Pacific Tidal Wave Warning that we could easily be watching the aftermath of on the news for the next few days…if God forbid one does hit.
In the event this quake causes major damage or loss of life, we always recommend donating to the Red Cross for relief effort.
As a service to your visitors it could be worthwhile to offer a live rss feed of any current news. This not only gives patrons to your web page information they would have otherwise gone elsewhere else to find, but also gives them other reasons to refer your site to friends in their social sphere! In Joomla you would first go to Twitter Search to get the rss, then create a custom feed module to syndicate that content.
Here is a quick alternative example using the rss feed widget from feedzilla and the search results for Chile.
We are very proud to introduce our Help Ticket System, our Online Help Desk today to most effectively provide IT Support and Web Design services to Greenville SC!
Register on our Trouble Ticket Page and Submit a New Ticket. We will contact you within 24 hours to submit our affordable proposal, after which The Web Doctor will go to work immediately to resolve your Small Business Computer or Website Issue!
I don’t read many paper backs since the explosion of online information – but Mike’s book “90 Recruits In 90 Days” has all the key elements towards motivating my decision to absorb it in play! First – Mikes book HAS LARGE PRINT SO I DON’T HAVE TO SQUINT. Secondly it was short enough to spare several moments of my time, yet simultaneously full of enough great information that indulging in it more than justifies the dedication. I also want you the reader to be aware that the dedication I previously spoke of was spent effortlessly as 90 Recruits In 90 Days indeed achieves the third of my criteria – it was fun to read!
90 Recruits In 90 Days will give you the GAME PLAN to achieve 90 Recruits In 90 Days OR DOUBLE YOUR MONEY BACK GUARANTEED! As we are all aware any profession requires a library of knowledge in the relentless struggle towards capturing success. Mike’s book 90 Recruits In 90 Days is one of the books you would want in your library if your JOB DEPENDS ON ACHIEVING A QUOTA OF RECRUITS. Mike guarantees that if you read this book and follow the plan you will not only keep your job, but have much greater success with your career!
We’ve been delivering great web pages to clients of The Web Doctor for several years now with Joomla. Along the way I’ve discovered many solutions to providing features requested on a custom web site with this software. Most recently we were approached by Tech Gen X with the task of building a custom payout reporting system that would not only track the earned commissions of an associate, but also track the pay out of the recruits under that associate for five generations! After looking over all the mlm downline software packages we decided it could be best case scenario if we could build our own solution from the ground up using Joomla components and open source ingenuity.
First of course we started with a standard 1.5 install. I will have to take a moment here and suggest that if you want a real website quick that scales nice you will want to go with Joomla. It’s kind of like the Linux of CMS in the sense that it’s free and has a large repository of add ons available at your dispense. Being the source code is open, available and based on consortium web standards you will find that Joomla is flexible to modify to your needs.
Next we needed to add people, phone numbers, addresses etc… To make Joomla socially capable you have no shortage of package options, but we use Community Builder for this operation. CB is like the Linux of Social Community Joomla add ons with all the upgrade modules to get excited about. So with this CB we could have an associate register and define what information we needed from that individual. We could also associate that person with their sponsor via ID. CB allows you to query the registering associate with custom defined variables like, “Sponsor ID”. The Sponsor ID is the recruiting associates ID number so if my ID is 3 and I recruit an associate, that associates Sponsor ID is 3. Now if that associate I recruited goes out and recruits someone else, if my recruits ID is 4 then that will be the Sponsor ID of whoever they recruit. So with CB and these custom fields we have achieved a tracking system.
Next we need to define commissions. In this case the company is selling Clear 4g Wimax Super Fast Mobile Internet Service and other products. Each sale nets a defined commission for the associate so we need a way for the associate to enter that sale. For this I looked at the sales reporting process much like a reverse purchase. The associate would pick out what product they sold, enter the mac ID on the equipment and check out with their “order”. For this I went to VirtueMart. VM is like the Linux of shopping cart addons for Joomla. Starting to see a benefit of this Joomla yet? So in the shopping cart – which was HEAVILY MODIFIED – we were able to link each associate with an order id that included a commission amount. Now we are able to track associates, track the sales they made…but what about a payout commission for the five generations of recruits?
On an average sale the associate would make a $150 commission, and the person that directly recruited that associate would make $100. The next five generations of sponsors would each make $20. With our system already tracking who sold what and who sponsored who we just needed to tie it all together into a system that reported that commission. Long to short we went with SQL2EXCEL. s2E is like the Macintosh computer of database reporting. This amazing software component for Joomla can run sql queries against any table in your database and report them in a downloadable excel spreadsheet or, what we liked the most, in a rendered web page. Before I tell you what we did let me mention that S2E is a pay for component that cost us around $35. Very well worth it! First we created a query that reports to the logged in associate who their recruits are and who has been recruited by their recruits through six generations. This was achieved with lots of caffeine and table join trial and error. Fortunately their are very helpful people and resources at http://forums.mysql.com/. Next we crafted a query that took the previous query as a base, then took the order IDs for that associate and their six generations and calculated the earned commission of both direct sales and generational commissions.
In summary we used Joomla, Community Builder, SQL2EXCEL and VirtueMart all heavily modified to achieve the commission payout software for Tech Gen X. If you are in need of a similar software solution for your startup, feel free to contact The Web Doctor for a free consultation.