function MTConnect(targetUrl, title) {
    this.targetUrl = targetUrl;
    this.title = title || '';
    this.endpoint = 'http://mt.mspmag.com/mt/plugins/Connect/connect-endpoint.fcgi';
    this.commentCgiUrl = 'http://mt.mspmag.com/mt/mt-comments.cgi';
    this.communityCgiUrl = 'http://mt.mspmag.com/mt/mt-cp.cgi';
    this.utcOffset = '-0500';
    this.initialized = 0;
    this.loaded = 0;
    this.captchaVisible = false;
//    
    this.captchaContent = '<div class="label"><label for="captcha_code">Captcha:</label></div><div class="field"><input type="hidden" name="token" value="6XZjZ1v4ZI2yPgMptALPBtichlE1Zx0yf3gjhEIT" /><img src="http://mt.mspmag.com/mt/mt-comments.cgi/captcha/7/6XZjZ1v4ZI2yPgMptALPBtichlE1Zx0yf3gjhEIT" width="150" height="35" /><br /><input name="captcha_code" id="captcha_code" value="" autocomplete="off" /><p>Type the characters you see in the picture above.</p></div>';
//    
    this.attachEvent = function(eventName,func) {
        var onEventName = 'on' + eventName;
        var old = window[onEventName];
        if( typeof old != 'function' )
            window[onEventName] = func;
        else {
            window[onEventName] = function( evt ) {
                old( evt );
                return func( evt );
            };
        }
    };
    this.fireEvent = function(eventName, param) {
        var fn = window['on' + eventName];
        if (typeof fn == 'function') return fn(param);
        return;
    };
    this.attachEvent('load', function() { if ( typeof connect != 'undefined' ) { connect.loaded = 1; } });
    //    http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html
    this.JSONscriptRequest = function(fullUrl, separator) {
        if ( typeof separator == 'undef' ) {
            separator = '';
        }
        // REST request path
        this.fullUrl = fullUrl;
        // Keep IE from caching requests
        if ( separator == '?' ) {
            this.noCacheIE = '?noCacheIE=' + (new Date()).getTime();
        } else {
            this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
        }
        // Get the DOM location to put the script tag
        this.headLoc = document.getElementsByTagName("head").item(0);
        // Generate a unique script tag id
        this.scriptId = 'JscriptId' + this.scriptCounter++;
    };
    this.JSONscriptRequest.prototype.buildScriptTag = function () {
        // Create the script tag
        this.scriptObj = document.createElement("script");
        // Add script object attributes
        this.scriptObj.setAttribute("type", "text/javascript");
        this.scriptObj.setAttribute("charset", "utf-8");
        this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
        this.scriptObj.setAttribute("id", this.scriptId);
    };
    this.JSONscriptRequest.prototype.removeScriptTag = function () {
        // Destroy the script tag
        this.headLoc.removeChild(this.scriptObj);
    };
    this.JSONscriptRequest.prototype.addScriptTag = function () {
        // Create the script tag
        this.headLoc.appendChild(this.scriptObj);
    };
    this.fetchJSON = function( args, callback ) {
        if ( typeof args['mode'] == 'undefined' ) return;
        var request = this.commentCgiUrl + '?' + '__mode=' + args['mode'];
        if ( callback ) {
            request = request + '&jsonp=' + callback;
        }
        for ( key in args ) {
            if ( key != 'mode' && typeof args[key] != 'function' ) {
                request = request + '&' + key + '=' + args[key];
            }
        }
        var aObj = new this.JSONscriptRequest(request, '&');
        aObj.buildScriptTag();
        aObj.addScriptTag();
    };
    this.fetchEndpoint = function( request, callback, args ) {
        var request = this.endpoint + request;
        var separator = '?';
        if ( callback ) {
            request = request + '?callback=' + callback;
            separator = '&';
        }
        for ( key in args ) {
            if ( typeof args[key] != 'function' ) {
                request = request + separator + key + '=' + args[key];
                separator = '&';
            }
        }
        var aObj = new this.JSONscriptRequest(request, separator);
        aObj.buildScriptTag();
        aObj.addScriptTag();
    };
    this.setTargetUrl = function(newTargetUrl) {
        this.targetUrl = newTargetUrl;
    };

    this.setReturnToUrl = function(returnToUrl) {
        this.returnToUrl = returnToUrl;
    };

    this.setBlogId = function(newBlogId) {
        this.blogId = newBlogId;
    };

    this.setReflector = function(newReflector) {
        this.reflector = newReflector;
    };

    this.require = function(url) {
        // Load a new JS script
        var script = document.createElement('script');
        script.src = url;
        (document.getElementsByTagName('head'))[0].appendChild(script);
    };
    // John Resig's micro-templating function
    this.tmpl = function (str, data) {
        // Figure out if we're getting a template, or if we need to
        // load the template - and be sure to cache the result.
        data['reflector'] = this.reflector;
        var fn = !/\W/.test(str) ?
            this.tmplCache[str] = this.tmplCache[str] ||
                this.tmpl(document.getElementById(str).innerHTML) :

            // Generate a reusable function that will serve as a template
            // generator (and which will be cached).
            new Function("obj",
                "var p=[],print=function(){p.push.apply(p,arguments);};" +

                // Introduce the data as local variables using with(){}
                "with(obj){p.push('" +

                // Convert the template into pure JavaScript
                str
                    .replace(/[\r\t\n]/g, " ")
                    .split("<%").join("\t")
                    .replace(/((^|%>)[^\t]*)\'/g, "$1\r")
                    .replace(/\t=(.*?)%>/g, "',$1,'")
                    .split("\t").join("');")
                    .split("%>").join("p.push('")
                    .split("\r").join("\\'")
            + "');}return p.join('');");
        // Provide some basic currying to the user
        return data ? fn( data ) : fn;
    };
    this.redrawCommentsForm = function ( u, commentsOpen ) {
        if ( typeof commentsOpen == 'undefined' ) {
            commentsOpen = this.commentsOpen;
        }
        var connectF = document.getElementById( this.commentsDivId + '-form' );
        if ( commentsOpen ) {
            if ( typeof u != 'undefined' ) {
                if (u.is_anonymous) {
                    if ( this.permitAnonymousComment ) {
                        connectF.innerHTML = '';
                    } else {
                        connectF.innerHTML = this.tmpl(this.commentsFormTemplate,
                                {'divId': this.commentsDivId + '-form',
                                 'targetUrl': this.targetUrl,
                                 'blogId': this.blogId,
                                 'returnToUrl': this.returnToUrl});
                        var dataHead = document.getElementById( 'connect-form-data-head' );
                        dataHead.innerHTML = this.tmpl(this.commentsDataHeadNotLoggedIn,
                                                       {'divId': this.commentsDivId + '-form' });
                        this.maybeDrawCaptchaFields(true);
                    }
                } else {
                    connectF.innerHTML = this.tmpl(this.commentsFormTemplate,
                            {'divId': this.commentsDivId + '-form',
                             'blogId': this.blogId,
                             'targetUrl': this.targetUrl,
                             'returnToUrl': this.returnToUrl});
                    var dataHead = document.getElementById( 'connect-form-data-head' );
                    dataHead.innerHTML = this.tmpl(this.commentsDataHeadLoggedIn,
                            {'divId': this.commentsDivId + '-form',
                             'name': u.name,
                             'url': u.url,
                             'email': u.email });

                    // we dont' want to show the captcha stuff since they're
                    this.maybeDrawCaptchaFields(false);
                }
            }
            else {
                if ( ! this.permitAnonymousComment ) {
                    connectF.innerHTML = '';
                } else {
                    connectF.innerHTML = this.tmpl(this.commentsFormTemplate,
                            {'divId': this.commentsDivId + '-form',
                             'targetUrl': this.targetUrl,
                             'blogId': this.blogId,
                             'returnToUrl': this.returnToUrl});
                    var dataHead = document.getElementById( 'connect-form-data-head' );
                    dataHead.innerHTML = this.tmpl(
                        this.commentsDataHeadNotLoggedIn,
                        {'divId': this.commentsDivId + '-form' }
                    );
                    this.maybeDrawCaptchaFields(true);
                }
            }
        } // Close commentsOpen check
        else {
            connectF.innerHTML = '';
        }
    };
    this.maybeDrawCaptchaFields = function(flag) {
        var captchaDiv = document.getElementById(
            this.commentsDivId + '-form-captcha-container'
        );
        if (flag && this.captchaContent.length) {
            if (captchaDiv) {
                captchaDiv.innerHTML = this.captchaContent;
                this.captchaVisible = true;
            }
        }
        else {
            if (captchaDiv) {
                captchaDiv.style.display = 'none';
                this.captchaVisible = false;
            }
        }
    };
    this.initialize = function(args) {
        // Properties to set via args are: targetUrl, blogId, commentsLimit, reflector
        this.tmplCache = {};
        var fetchArgs = new Array();
        if ( typeof args != 'undefined' && args['reflector'] ) {
            this.reflector = args['reflector'];
        } else {
            this.reflector = 'connect';
        }
        if ( typeof args != 'undefined' && args['blogId'] ) {
            this.blogId = args['blogId'];
        } else {
            this.blogId = '7';
        }
        if ( typeof args != 'undefined' && args['commentsLimit'] ) {
            this.commentsLimit = args['commentsLimit'];
            fetchArgs['commentsLimit'] = args['commentsLimit'];
        } else {
            if ( typeof this.commentsLimit == 'undefined' ) {
                this.commentsLimit = '0';
            }
            else {
                fetchArgs['commentsLimit'] = this.commentsLimit;
            }
        }
        if ( typeof args != 'undefined' && args['staticSettingsFile'] ) {
            this.require(args['staticSettingsFile']);
        }
        var request = '/target/' + encodeURIComponent(encodeURIComponent(this.targetUrl)) + '/blog/' + this.blogId;

        if (this.title !== '') {
           request += '/title/' + encodeURIComponent(encodeURIComponent(this.title));
        }
        request += '/script/settings.js';

        this.fetchEndpoint(request, '', fetchArgs);
        this.scriptCounter = 1;
    };
}

// Init
MTConnect.prototype.initComments = function() {
    // Comments and form
    this.comments = new Array();
    if ( typeof this.commentsDivId == 'undefined' ) {
        this.commentsDivId = 'connect';
    }
    if ( typeof this.commentsLimit == 'undefined' ) {
        this.commentsLimit = 0;
    }
    if ( typeof this.commentsOffset == 'undefined' ) {
        this.commentsOffset = 0;
    }
    if ( typeof this.returnToUrl == 'undefined' ) {
        this.returnToUrl = this.targetUrl;
    }
    if ( typeof this.permitAnonymousComment == 'undefined' ) {
//        
        this.permitAnonymousComment = true;
//        
    }
    if ( typeof this.blogId == 'undefined' ) {
        this.blogId = '';
    }


    // Templates
    if ( typeof this.commentsHeader == 'undefined' ) {
        this.commentsHeader = '<h3>Comments</h3>';
    }
    if ( typeof this.commentsFormTemplate == 'undefined' ) {
        this.commentsFormTemplate = this.defaultCommentsFormTemplate;
    }
    if ( typeof this.commentTemplate == 'undefined' ) {
        this.commentTemplate = this.defaultCommentTemplate;
    }
    if ( typeof this.commentsDataHeadLoggedIn == 'undefined' ) {
        this.commentsDataHeadLoggedIn = this.defaultCommentsDataHeadLoggedIn;
    }
    if ( typeof this.commentsDataHeadNotLoggedIn == 'undefined' ) {
        this.commentsDataHeadNotLoggedIn = this.defaultCommentsDataHeadNotLoggedIn;
    }

    // Cookie related
    if ( typeof this.cookieTimeout == 'undefined' ) {
        this.cookieTimeout = 14400;
    }
    if ( typeof this.cookieName == 'undefined' ) {
            this.cookieName = 'mt_blog_user';
    }
    if ( typeof this.cookiePath == 'undefined' ) {
            this.cookiePath = '/';
    }
    if ( typeof this.cookieDomain == 'undefined' ) {
            this.cookieDomain = 'mspmag.com';
    }
    this.setupCommentsDiv = function () {
        connectDiv = document.getElementById( this.commentsDivId )
        if ( connectDiv == null ) {
            return;
        }
        var connectC = document.createElement('div');
        if ( typeof user == 'undefined' ) {
            var user;
        }
        this.commentsCommentsDiv = connectC;
        connectC.id = this.commentsDivId + "-comments";
        connectC.setAttribute('class', 'connect-comments');
        connectC.innerHTML = this.commentsHeader;
        connectDiv.appendChild(connectC);

        var connectGreeting = document.createElement('div');
        connectGreeting.id = this.commentsDivId + '-form-greeting';
        connectDiv.appendChild(connectGreeting);

        var connectF = document.createElement('form');
        connectDiv.appendChild(connectF);
        connectF.id = this.commentsDivId + '-form';
        connectF.setAttribute('name', 'connect-form');
        connectF.setAttribute('action', this.commentCgiUrl );
        connectF.setAttribute('method', 'post');
        connectF.innerHTML = '';
        this.commentsSetup = 1;
        this.fireEvent('connectCommentsSetup');
    }
    this.setupCommentsDiv();
}

// Comments-specific code

MTConnect.prototype.flowComments = function () {
    commentArea = document.getElementById( this.commentsDivId + '-comments');
    var page_txt;
    var commentText = '';
    for ( i = 0; i < this.comments.length; i++ ) {
        var comment = this.comments[i];
        if ( comment['body_html'] ) {
            var userpic = null;
            var isotime = comment['publication_time'];
            var tmp = isotime.match(/([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})Z$/);
            var offsetDate = new Date(Date.UTC(tmp[1],tmp[2]-1,tmp[3],tmp[4],tmp[5],tmp[6]));
            if ( this.utcOffset ) {
                var pos = this.utcOffset.substr(0, 1);
                var hour = this.utcOffset.substr(1, 2);
                var min = this.utcOffset.substr(3, 2);
                if ( pos == '+' ) {
                    offsetDate.setUTCHours( offsetDate.getUTCHours() + hour );
                    offsetDate.setUTCMinutes( offsetDate.getUTCMinutes() + min );
                }
                if ( pos == '-' ) {
                    offsetDate.setUTCHours( offsetDate.getUTCHours() - hour );
                    offsetDate.setUTCMinutes( offsetDate.getUTCMinutes() - min );
                }
                var commentYear = offsetDate.getUTCFullYear();
                var commentMonth = offsetDate.getUTCMonth() + 1;
                if (commentMonth.toString().length == 1) { commentMonth = '0' + commentMonth.toString(); }
                var commentDate = offsetDate.getUTCDate();
                if (commentDate.toString().length == 1) { commentDate = '0' + commentDate.toString(); }
                date = commentYear + '-' + commentMonth + '-' + commentDate;
                var commentHours = offsetDate.getUTCHours();
                if (commentHours.toString().length == 1) { commentHours = '0' + commentHours.toString(); }
                var commentMinutes = offsetDate.getUTCMinutes();
                if (commentMinutes.toString().length == 1) { commentMinutes = '0' + commentMinutes.toString(); }
                time = commentHours + ':' + commentMinutes;
            }
            var author = comment.author;
            if ( author && author.avatar && author.avatar.asset ) {
                userpic = author.avatar.asset.href;
            }
            var count = this.commentStart + i;
                   var commentClass = (count % 2) ? "connect-comment connect-odd" : "connect-comment connect-even";
            commentText = commentText + this.tmpl(this.commentTemplate,
                { 'commentClass':commentClass,'author':author.name,'date':date,'time':time,'fullDate':offsetDate,
                  'userpic':userpic,'count':count,'text':comment['body_html'],'email':author.email,'url':comment.comment_url.href,
                'profile_name': author.profile_name }
            );
        }
    }
    var navText = '';
    if ( this.commentsLimit && this.comments.length > 0 ) {
        navText = 'Comments ' + this.commentStart + ' to ' + this.commentEnd + ' of ' + this.commentTotal;
        if ( this.commentsOffset > 0 ) {
            var new_offset = Math.max(0, this.commentsOffset - this.commentsLimit);
            prev_link = "<a href=\"#\" onclick=\"" + this.reflector + ".retrieveComments( " + this.commentsLimit + ", " + new_offset + "); return false;\" >&#171;</a> ";
        } else {
            prev_link = "&nbsp; ";
        }
        if ( this.commentEnd < this.commentTotal ) {
            var new_offset = this.commentsOffset + this.commentsLimit;
            next_link = "<a href=\"#\" onclick=\"" + this.reflector + ".retrieveComments( " + this.commentsLimit + ", " + new_offset + "); return false;\" >&#187;</a> ";
        } else {
            next_link = " &nbsp;";
        }
        navText = "<span>" + prev_link + navText + next_link + "</span>";
    }
    commentArea.innerHTML = this.commentsHeader + commentText + navText;
    commentArea.style.display = 'block';
}

MTConnect.prototype.retrieveComments = function ( localLimit, localOffset ) {
    if ( typeof this.reflector == 'undefined' ) {
        return;
    }
    if ( typeof localLimit == 'number' ) {
        limit = localLimit;
    } else if ( typeof this.commentsLimit == 'undefined' ) {
        limit = 0;
    } else {
        limit = this.commentsLimit;
    }
    if ( typeof localOffset == 'number' ) {
        offset = localOffset;
    } else if ( typeof this.commentsOffset == 'undefined' ) {
        offset = 0;
    } else {
        offset = this.commentsOffset;
    }
    var args = new Array();
    args['max-results'] = limit;
    args['start-index'] = offset + 1;
    var request = '/target/' + encodeURIComponent(encodeURIComponent(this.targetUrl)) + '/blog/' + this.blogId + '/comments.js'
    var callback = this.reflector + '.retrieveCommentsCallback';
    this.fetchEndpoint(request, callback, args);
}


MTConnect.prototype.retrieveCommentsCallback = function( r ) {
    if ( r['error'] ) {
            alert(r['error']);
        return;
    }
    this.comments = r['comments'];
    this.commentsOffset = r.offset;
    this.commentsLimit = r.limit;
    this.commentStart = r.offset + 1;
    this.commentEnd = r.offset + this.comments.length;
    this.commentTotal = r.comment_count;
    this.flowComments();
};



MTConnect.prototype.createCommentClosure = function( item ) {
    return function(c, r) {
        var retrieved = Object.fromJSON(r);
        item.comments = retrieved['comments'];
        item.commentsOffset = retrieved.offset;
        item.commentsLimit = retrieved.limit;
        item.commentStart = retrieved.offset + 1;
        item.commentEnd = retrieved.offset + item.comments.length;
        item.commentTotal = retrieved.comment_count;
        item.flowComments();
        };
}

MTConnect.prototype.defaultCommentsDataHeadLoggedIn = '                         \
    <input id="connect-static" type="hidden" value="1" name="static"/>          \
    <input id="comment-bake-cookie" type="hidden" value="1" name="bakecookie"/> \
    <input id="connect-author" type="hidden" value="<%=name%>" name="name"/>    \
    <input id="connect-email" type="hidden" value="<%=email%>" name="email"/>   \
    <input id="connect-url" type="hidden" value="<%=url%>" name="url"/>         \
    <input id="connect-sid" type="hidden" value="xxxxx" name="sid"/>            \
';

MTConnect.prototype.defaultCommentsDataHeadNotLoggedIn = '         \
<div id="<%=divId%>-name">                                         \
    <label for="connect-author">Name</label>                       \
    <input id="connect-author" name="author" size="30" value="" /> \
</div>                                                             \
<div id="<%=divId%>-email">                                        \
    <label for="connect-email">Email Address</label>               \
    <input id="connect-email" name="email" size="30" value="" />   \
</div>                                                             \
<div id="<%=divId%>-url">                                          \
    <label for="connect-url">URL</label>                           \
    <input id="connect-url" name="url" size="30" value="" />       \
</div>                                                             \
                                     \
<div id="<%=divId%>-captcha-container">                            \
    <input id="connect-captcha" name="captcha" />                 \
</div>                                                             \
                                    \
';

// Takes targetUrl, returnToUrl, divId
MTConnect.prototype.defaultCommentsFormTemplate = '                                 \
    <input type="hidden" name="__mode" value="connect_comment_add" />               \
    <input type="hidden" name="target-url" value="<%=targetUrl%>" />                \
    <input type="hidden" name="returnToUrl" value="<%=returnToUrl%>" />             \
    <input type="hidden" name="blog_id" value="<%=blogId%>" />                      \
    <div id="<%=divId%>-data">                                                      \
        <div id="<%=divId%>-data-head">                                             \
        </div>                                                                      \
        <div id="<%=divId%>-text">                                                  \
            <label for="connect-text">                                              \
            Comments (You may use HTML tags for style)                              \
            </label><br />                                                          \
            <textarea id="connect-text" name="text" rows="15" cols="28"></textarea> \
        </div>                                                                      \
        <div id="<%=divId%>-footer">                                                \
            <input type="submit" accesskey="s" value="Submit" />                    \
        </div><p>Note: We do not moderate comments. However, mspmag.com will remove comments if they contain profanity, offensive content, and/or overt sales pitches.</p> \
    </div>                                                                          \
';

MTConnect.prototype.defaultCommentTemplate = '                      \
<div style="width: auto;" class="<%=commentClass%>">                \
<span class="connect-comment-count"><%=count%></span>               \
<span class="connect-comment-text">                                 \
<% if ( userpic ) { %>                                              \
    <img src="<%=userpic%>" alt="<%= author %>&#39;s userpic" />    \
<% } %>                                                             \
<%=text%><br />                                                     \
<span class="connect-comment-info">                                 \
Posted by <%=author%> on <%=date%> at <%=time%>                     \
</span>                                                             \
</span>                                                             \
</div>                                                              \
';

// RECOMMENDS

MTConnect.prototype.getPageRecommendScore = function() { // connectRecommendScore
    var args = new Array();
    args['type'] = 'recommend';
    var request = '/target/' + encodeURIComponent(encodeURIComponent(this.targetUrl)) + '/blog/' + this.blogId + '/score.js'
    var callback = this.reflector + '.postGetPageRecommendScore';
    this.fetchEndpoint(request, callback, args);
}

MTConnect.prototype.postGetPageRecommendScore = function(r, error) { // postGetScore( r )
    if ( error ) {
        // Handle error
    } else {
        if ( typeof r == 'undefined' ) {
            return;
        }
        var result = r['score'];
        var can_vote;
        var score = result['score'];
        var userscore;
        if ( this.recommendVoteCast ) {
            userscore = 1;
        } else {
            userscore = 0;
        }
        if ( typeof user != 'undefined' && ! user.is_anonymous ) {
            can_vote = 1;
        } else {
            can_vote = 0;
        }
        var scoreDiv = document.getElementById(this.recommendScoreDiv);
        scoreDiv.innerHTML = this.tmpl(this.recommendScoreDivTmpl, { 'score': score, 'votes': score });
        var postDiv = document.getElementById( this.recommendPostDiv );
        postDiv.innerHTML = this.tmpl(this.recommendPostDivTmpl, { 'canVote': can_vote, 'userscore': userscore });
    }
}

MTConnect.prototype.sendPageRecommendScore = function() { // connectVote
    var postDiv = document.getElementById( this.recommendPostDiv );
    postDiv.innerHTML = 'Voting...';
    args = Array();
    args['blog_id'] = this.blogId;
    args['url'] = encodeURIComponent(this.targetUrl);
    args['jsonp_callback'] = this.reflector + '.postGetPageRecommendScore'
    args['mode'] = 'connect_score_recommend_add';
    this.recommendVoteCast = 1;
    this.fetchJSON(args);
}

// RATINGS

MTConnect.prototype.getPageRatingScore = function() {
    var args = new Array();
    args['type'] = 'rating';
    var request = '/target/' + encodeURIComponent(encodeURIComponent(this.targetUrl)) + '/blog/' + this.blogId + '/score.js'
    var callback = this.reflector + '.postGetPageRatingScore';
    this.fetchEndpoint(request, callback, args);
}

MTConnect.prototype.postGetPageRatingScore = function(r, error) {
    if ( error ) {
        // Handle error
    } else {
        if ( typeof r == 'undefined' ) {
            return;
        }
        var result = r['score'];
        var can_vote;
        var score = result['score'];
        var votes = result['votes'];
        if ( typeof user != 'undefined' && ! user.is_anonymous ) {
            can_vote = 1;
        } else {
            can_vote = 0;
        }
        var scoreDiv = document.getElementById( this.ratingScoreDiv );
        scoreDiv.innerHTML = this.tmpl(this.ratingScoreDivTmpl, { 'score': score, 'votes': votes });
        var postDiv = document.getElementById( this.ratingPostDiv );
        postDiv.innerHTML = this.tmpl(this.ratingPostDivTmpl, { 'canVote': can_vote });
    }
}

MTConnect.prototype.sendPageRatingScore = function( score ) {
    var postDiv = document.getElementById( this.ratingPostDiv );
    postDiv.innerHTML = 'Voting...';
    args = Array();
    args['blog_id'] = this.blogId;
    args['url'] = encodeURIComponent(this.targetUrl);
    args['score'] = score;
    args['jsonp_callback'] = this.reflector + '.postGetPageRatingScore'
    args['mode'] = 'connect_score_rating_add';
    this.fetchJSON(args);
}

// REVIEWS

MTConnect.prototype.getPageReviewScore = function() {
    var args = new Array();
    args['type'] = 'review';
    var request = '/target/' + encodeURIComponent(encodeURIComponent(this.targetUrl)) + '/blog/' + this.blogId + '/score.js'
    var callback = this.reflector + '.postGetPageReviewScore';
    this.fetchEndpoint(request, callback, args);
}

MTConnect.prototype.postGetPageReviewScore = function(r, error) {
    if ( error ) {
        // Handle error
    } else {
        if ( typeof r == 'undefined' ) {
            return;
        }
        var result = r['score'];
        var can_vote;
        var score = result['score'];
        var votes = result['votes'];
        if ( typeof user != 'undefined' && ! user.is_anonymous ) {
            can_vote = 1;
        } else {
            can_vote = 0;
        }
        var scoreDiv = document.getElementById( this.reviewScoreDiv );
        scoreDiv.innerHTML = this.tmpl(this.reviewScoreDivTmpl, { 'score': score, 'votes': votes });
        var postDiv = document.getElementById( this.reviewPostDiv );
        postDiv.innerHTML = this.tmpl(this.reviewPostDivTmpl, { 'canVote': can_vote });
    }
}

MTConnect.prototype.sendPageReviewScore = function( score ) {
    var postDiv = document.getElementById( this.reviewPostDiv );
    postDiv.innerHTML = 'Voting...';
    args = Array();
    args['blog_id'] = this.blogId;
    args['url'] = encodeURIComponent(this.targetUrl);
    args['score'] = score;
    args['jsonp_callback'] = this.reflector + '.postGetPageReviewScore'
    args['mode'] = 'connect_score_review_add';
    this.fetchJSON(args);
}

MTConnect.prototype.defaultRecommendScoreDivTmpl = 'Recommended <%= score %> time<% if ( score != 1 ) { %>s<% } %>.';

MTConnect.prototype.defaultRecommendPostDivTmpl = '<% if ( userscore == 0 || userscore == null ) { %>\
<% if ( canVote ) { %>\
<a href="#" onClick="<%= reflector %>.sendPageRecommendScore(); return false;">Recommend it!</a>\
<% } else { %>\
Sign in to vote.\
<% } %>\
<% } %>';

MTConnect.prototype.defaultRatingScoreDivTmpl = '<% if ( votes > 0 ) { var fixed = score / ( 10 * votes ); %>\
This page has an average rating of <%= fixed.toFixed(2) %> from <%= votes %> users. \
<% } else { %>\
This page has not been rated. \
<% } %>';

MTConnect.prototype.defaultRatingPostDivTmpl = '<% if ( canVote ) { %>\
On a scale of one to ten, it&#39;s a <select id="comment-rating-post-score">\
    <option value="10">1</option>\
    <option value="20">2</option>\
    <option value="30">3</option>\
    <option value="40">4</option>\
    <option value="50">5</option>\
    <option value="60">6</option>\
    <option value="70">7</option>\
    <option value="80">8</option>\
    <option value="90">9</option>\
    <option value="100">10</option>\
    </select>\
    <button onClick="var s = document.getElementById(<%= "\'" %>comment-rating-post-score<%= "\'" %>); <%= reflector %>.sendPageRatingScore( s.options[s.selectedIndex].value); return false;">Vote!</button>\
<% } else { %>\
Sign in to vote.\
<% } %>';

MTConnect.prototype.defaultReviewScoreDivTmpl = '<% if ( votes > 0 ) { %>\
<%= votes %> users have given this page a net rating of <% if ( score == 0 ) { %>zero<% } else if ( score > 0 ) { %><%= "+" + score %><% } else { %><%= score %><% } %>. \
<% } else { %>\
This page has not been reviewed. \
<% } %>';

MTConnect.prototype.defaultReviewPostDivTmpl = '<% if ( canVote ) { %>\
Vote <a href="#" onClick="<%= reflector %>.sendPageReviewScore(1); return false;">thumbs up</a> or <a href="#" onClick="<%= reflector %>.sendPageReviewScore(-1); return false;">thumbs down</a>.\
<% } else { %>\
Sign in to vote.\
<% } %>';

MTConnect.prototype.commentsFormTemplate = '' +
'    <input type="hidden" name="__mode" value="connect_comment_add" />' +
'    <input type="hidden" name="target-url" value="<%=targetUrl%>" />' +
'    <input type="hidden" name="returnToUrl" value="<%=returnToUrl%>" />' +
'    <input type="hidden" name="blog_id" value="<%=blogId%>" />' +
'    <div id="<%=divId%>-data">' +
'        <div id="<%=divId%>-data-head">' +
'        </div>' +
'        <div id="<%=divId%>-text">' +
'            <label for="connect-text">' +
'            Comments (You may use HTML tags for style)' +
'            </label>' +
'            <textarea id="connect-text" name="text" rows="5" cols="55"></textarea>' +
'        </div>' +
'        <div id="<%=divId%>-footer">' +
'            <input type="submit" accesskey="s" value="Submit" />' +
'        </div><p><b>Note: We do not moderate comments. However, mspmag.com will remove comments if they contain profanity, offensive content, and/or overt sales pitches.</b></p>' +
'    </div>';



    
MTConnect.prototype.commentTemplate = '' +
'<div class="<%=commentClass%>">' +
'<table cellspacing="0" cellpadding="4">' +
'<tr>' +
'  <td width="75" valign="top" align="left">' +
'<% if ( userpic ) { %>' +
'    <img class="connect-userpic" src="<%=userpic%>" alt="<%= author %>&#39;s userpic" width="75" height="75"/>' +
'<% } else { %>' +
'    <img class="connect-userpic" src="http://mt.mspmag.com/mt-static/images/default-userpic-90.jpg" alt="<%= author %>&#39;s userpic" width="75" height="75"/>' +
'<% } %>' +
'  </td>' +
'  <td valign="top" align="left">' +
'   <span class="connect-comment-text">' +
'    <%=text%>' +
'   </span>' +
'   <span class="connect-comment-info">' +
'<% if ( profile_name ) { %>' +
'    By <a href="http://mt.mspmag.com/mt/mt-cp.cgi?username=<%=profile_name%>"><%=author%></a> at <%=time%>, <%=date%>' +
'<% } else if ( url ) { %>' + 
'    By <a href="<%=url%>" rel="nofollow"><%=author%></a> at <%=time%>, <%=date%>' +
'<% } else { %>' +
'    By <%=author%> at <%=time%>, <%=date%>' +
'<% } %>' +
'   </span>' +
'  </td>' +
'</tr>' +
'</table></div>';

MTConnect.prototype.commentsDataHeadNotLoggedIn = '' +
'<div id="<%=divId%>-name">' +
'    <label for="connect-author">Name</label>' +
'    <input id="connect-author" name="author" size="30" value="" />' +
'</div>' +
'<div id="<%=divId%>-email">' +
'    <label for="connect-email">E-mail Address</label>' +
'    <input id="connect-email" name="email" size="30" value="" />' +
'</div>' +
'<div id="<%=divId%>-url">' +
'    <label for="connect-url">URL</label>' +
'    <input id="connect-url" name="url" size="30" value="" />' +
'</div>' +
'<div id="<%=divId%>-captcha-container">' +
'    <input id="connect-captcha" name="captcha" />' +
'</div>';

MTConnect.prototype.sendPageRatingScore = function( score ) {
    var postDiv = document.getElementById( this.ratingPostDiv );
    postDiv.innerHTML = 'Rating...';
    args = Array();
    args['blog_id'] = this.blogId;
    args['url'] = encodeURIComponent(this.targetUrl);
    args['score'] = score;
    args['jsonp_callback'] = this.reflector + '.postGetPageRatingScore'
    args['mode'] = 'connect_score_rating_add';
    this.fetchJSON(args);
}

MTConnect.prototype.defaultRatingPostDivTmpl = '<% if ( canVote ) { %>\
<h2 style="font-size: 14px; font-weight: bold;">Your rating:</h2><br /> \
    <table cellpadding="0" cellspacing="0" border="0" bordercolor="#BFBFBF"><tr> \
	<td style="border:solid 1px #BFBFBF;margin:5px;padding:10px;font-family:Arial;"> \
	<div class="rateform"> \
	<form style="margin:0;padding:0;" name="form"><input type="hidden" id="comment-rating-post-score" name="rate1" value=""> \
	<input type="radio" name="ratethis" value="0" onClick="document.form.rate1.value=this.value">&nbsp;0 - Worthless<br /> \
    <input type="radio" name="ratethis" value="10" onClick="document.form.rate1.value=this.value">&nbsp;1 - Nearly Without Merit<br /> \
    <input type="radio" name="ratethis" value="20" onClick="document.form.rate1.value=this.value">&nbsp;2 - Poor<br /> \
    <input type="radio" name="ratethis" value="30" onClick="document.form.rate1.value=this.value">&nbsp;3 - Disappointing<br /> \
    <input type="radio" name="ratethis" value="40" onClick="document.form.rate1.value=this.value">&nbsp;4 - Low Average<br /> \
    <input type="radio" name="ratethis" value="50" onClick="document.form.rate1.value=this.value">&nbsp;5 - Average<br /> \
    <input type="radio" name="ratethis" value="60" onClick="document.form.rate1.value=this.value">&nbsp;6 - High Average<br /> \
    <input type="radio" name="ratethis" value="70" onClick="document.form.rate1.value=this.value">&nbsp;7 - Good, not Great<br /> \
    <input type="radio" name="ratethis" value="80" onClick="document.form.rate1.value=this.value">&nbsp;8 - Very Good<br /> \
    <input type="radio" name="ratethis" value="90" onClick="document.form.rate1.value=this.value">&nbsp;9 - Excellent<br /> \
    <input type="radio" name="ratethis" value="100" onClick="document.form.rate1.value=this.value">&nbsp;10 - Perfect, Without Peer<br /> \
	</form></div></td></tr></table><br /> \
	<input border="0" style="background:#b82d27 none repeat scroll 0 0;color:#FFFFFF;font-weight:bold;padding:5px 10px;font-family: Arial Bold, Arial;font-size:14px;border:solid 1px #BFBFBF;" type="submit" value="Rate" onClick="<%= reflector %>.sendPageRatingScore(document.form.rate1.value); return false;" /></div>\
<% } else { %>\
If you are a new user, please <a href="http://mt.mspmag.com/mt/mt-cp.cgi?__mode=register&blog_id=7&return_to=' + encodeURIComponent(document.URL) + '"><img style="display:inline;" src="/images/guides/ratings/createprofile_03.gif" title="Create a Profile" alt="Create a Profile" border="0" /></a> to rate a restaurant.<br /><br />Already registered? <a href="javas\cript:void(0)" onClick="return connectSignInOnClick()"><img style="display:inline;" src="/images/guides/ratings/signin_03.gif" title="Sign In" alt="Sign In" border="0" /></a> to rate it now.\
<% } %>';

MTConnect.prototype.defaultRatingScoreDivTmpl = '<% if ( votes > 0 ) { var fixed = score / ( 10 * votes ); %>\
To rate a restaurant, please <a href="javas\cript:void(0)" onClick="return connectSignInOnClick()">sign in</a> if you are already registered, or <a href="http://mt.mspmag.com/mt/mt-cp.cgi?__mode=register&blog_id=7&return_to=' + encodeURIComponent(document.URL) + '">create a profile</a>. Registered users can rate restaurants and post comments immediately. <br /><br /><h2 style="font-size: 14px; font-weight: bold;">Rate a Restaurant</h2><br /><table cellpadding="0" cellspacing="0" border="0"><tr><td><strong>Average User Rating:</strong></td><td><div id="connect-rating-preview" style="width:43px;height:36px;padding-top:7px;margin-left:5px;margin-right:5px;float:left;color:#FFFFFF;font-family:Arial;font-weight:bold;font-size:24px;text-align:center;background-repeat:no-repeat;background-position:top;background-image:url(/images/guides/ratings/rating_eater.gif);"><%= fixed.toFixed(1) %></div></td> <td style="font-family:arial;font-weight:bold;">(<%= votes %> eater<%= votes > 1 ? "s" : "" %> rated)</td></tr></table> <br />\
<% } else { %>\
To rate a restaurant, please <a href="javas\cript:void(0)" onClick="return connectSignInOnClick()">sign in</a> if you are already registered, or <a href="http://mt.mspmag.com/mt/mt-cp.cgi?__mode=register&blog_id=7&return_to=' + encodeURIComponent(document.URL) + '">create a profile</a>. Registered users can rate restaurants and post comments immediately. <br /><br /><h2 style="font-size: 14px; font-weight: bold;">Rate a Restaurant</h2><br />This restaurant has not been rated.<br /><br /> \
<% } %>';

MTConnect.prototype.postGetPageRatingScore = function(r, error) {
    if ( error ) {
        // Handle error
    } else {
        if ( typeof r == 'undefined' ) {
            return;
        }
        var result = r['score'];
        var can_vote;
        var score = result['score'];
        var votes = result['votes'];
        if ( typeof user != 'undefined' && ! user.is_anonymous ) {
            can_vote = 1;
        } else {
            can_vote = 0;
        }
        var scoreDiv = document.getElementById( this.ratingScoreDiv );
        scoreDiv.innerHTML = this.tmpl(this.ratingScoreDivTmpl, { 'score': score, 'votes': votes });
        var postDiv = document.getElementById( this.ratingPostDiv );
        postDiv.innerHTML = this.tmpl(this.ratingPostDivTmpl, { 'canVote': can_vote });

		if (this.ratingScorePreviewDiv) {
			var scorePreviewDiv = document.getElementById(this.ratingScorePreviewDiv);
			scorePreviewDiv.innerHTML = this.tmpl(this.ratingScorePreviewDivTmpl, { score: score, votes: votes });
		}
    }
}

MTConnect.prototype.ratingScorePreviewDivTmpl = '<% if ( votes > 0 ) { var fixed = score / ( 10 * votes ); %>\
<%= fixed.toFixed(1) %>\
<% } else { %>\
0\
<% } %>';

MTConnect.prototype.updatePageRatingScorePreview = function(r, error) {
    if ( error ) {
        // Handle error
    } else {
        if ( typeof r == 'undefined' ) {
            return;
        }
        var result = r['score'];
        var score = result['score'];
        var votes = result['votes'];
        var scorePreviewDiv = document.getElementById(this.ratingScorePreviewDiv);
        scorePreviewDiv.innerHTML = this.tmpl(this.ratingScorePreviewDivTmpl, { score: score, votes: votes });
    }
}


