Monday, June 21, 2010

Using jQuery and Templating to Pull and Display Your Twitter Updates

A while back, I wrote a blog post on how to pull in your last three twitter posts into your web page via jQuery and JSON. It's still today a very popular post.

A lot has happened since that post and I wanted to re-address it and show you an alternative way of pulling in your Twitter feed via jQuery and the new Templating plugin developed by Microsoft. On the right is a new Twitter widget I put together using the new jQuery templating plugin.

Microsoft's Templating Plugin

During MIX10, John Resig and Microsoft announced that Microsoft would be contributing code back to the jQuery Project. One of their first contributions was the Templating plugin. Microsoft created templates for jQuery so that JavaScript developers could use jQuery to easily display a set of data.

The source code for the plugin can be found in the jQuery-tmpl GitHub repository. The plugin requires jQuery 1.4.2 or higher.

Getting Setup

Before we start you'll need the following:

Create a html page, and include jQuery, the template plugin and the supporting_methods.js. Then include the style.css doc so that your code from the demo we do looks nice.

The HTML

Since each tweet will be listed as a list item in an unordered list the only required HTML we need is an empty ul:

		<ul id="renderTweets"></ul>
	

In our demo though we want to make it a complete widget. We need some extra layout html to be able to provide a heading and a link to take you to more tweets. Here is the full html we'll use:

		<div id="Tweets">
			<h3>@RedWolves Tweets</h3>
		  	<ul id="renderTweets"></ul>
			<div id="more">
				<a href="http://twitter.com/redwolves">More &gt;</a>
			</div>
		</div>
	

Make sure you replace my twitter name, RedWolves, with yours.

Making the Ajax request

Now let's get the data from Twitter. We'll use a JSONP ajax call to get back the JSON data of the last three tweets from Twitter. To get the JSON data we will use the user timeline of the Twitter API.

		$("document").ready(function(){
			var url = "http://api.twitter.com/1/statuses/user_timeline.json?id=RedWolves&count=3&callback=?"
			$.ajax({
				dataType: 'jsonp',
				url: url,
				jsonpCallback: "renderTweets" 
			});
		});
	

At the end of the Twitter API url that we declare we attach the user id of the user timeline we want to see, in this case mine, RedWolves, so make sure to update with the username you wish to see. We then declare the url and call the .ajax() method and provide it with the dataType 'jsonp' so that we can pull the data via cross-domain. We set the url and then tell it which function we will call after the data is loaded. After the data is loaded we will call the function 'renderTweets', defined below, which will run the data through the template.

Defining the Template

Now let's define the template that will display the data we get back from the Ajax request. We define the template in a script tag and we provide it with a type of "text/template" and a unique ID.

		<script type="text/template" id="twitterTemplate">
			<li>
					<img src="${ user['profile_image_url'] }" /> 
					${ text.linkify().atify() } 
					<span class="created_at">
						${ relative_time(created_at) } via ${ source }
					</span>
			</li>
		</script>
	

On each JSON item we will run it through the template and create an li element with the profile photo, tweet text, when it was created and what source the tweet came from (e.g. Twitter for iPhone, web, etc.).

We are using a couple of supporting methods to help us in formatting. .linkify which will make any link a hyper link, atify which will link up any @screenname to their twitter profile and relative_time which will turn the created time into Twitter style time. You can find these methods in the supporting_methods.js file.

Putting it all together

The last bit of jQuery code we need to do is to actually call the plugin and combine the template with the data and put it into the DOM. Here we will define the renderTweets callback function.

		function renderTweets(data) {
			$("#twitterTemplate")
				.render(data)
				.appendTo("#renderTweets");
		}
	

What we do is select our template, call the template plugin method, .render, which takes in the data from the Ajax call and renders the results against the template, and then append the results to the desired element in the HTML, the ul with id of renderTweets.

The whole HTML

		<!DOCTYPE html>
		<html>
			<head>
				<meta charset=utf-8 />
				<title>twitter</title>
				<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
				<script src="jquery.tmpl.js"></script>
				<script src="supporting_methods.js"></script>
				<link rel="stylesheet" href="style.css" type="text/css" media="screen" title="no title" charset="utf-8">
				<script type="text/template" id="twitterTemplate">
					<li>
							<img src="${ user['profile_image_url'] }" /> 
							${ text.linkify().atify() } 
							<span class="created_at">
								${ relative_time(created_at) } via ${ source }
							</span>
					</li>
				</script>
				<script type="text/javascript">
					$("document").ready(function(){
						var url = "http://api.twitter.com/1/statuses/user_timeline.json?id=RedWolves&count=3&callback=?"
						$.ajax({
							dataType: 'jsonp',
							url: url,
							jsonpCallback: "renderTweets" 
						});
					});

					function renderTweets(data) {
						$("#twitterTemplate")
							.render(data)
							.appendTo("#renderTweets");
					}
				</script>
			</head>
		<body>
		  <div id="Tweets">
			<h3>@RedWolves Tweets</h3>
		  	<ul id="renderTweets"></ul>
			<div id="more">
				<a href="http://twitter.com/redwolves">More ></a>
			</div>
		  </div>
		</body>
		</html>​
		
	



Source Code Demo

Friday, January 22, 2010

jQuery 1.4 Give Us a New Way to Zebra Stripe

In jQuery 1.4 all setter methods have been extended to take in a setter function.  Before only .attr() had the ability to use a function to return the value to set. Now you can pass a setter function to .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass(), and .toggleClass().

The setter function can take two arguments, the index position of the element in the set and the old value of the element.

.css( propertyName, function(index, value))

With setter functions now available we can use this in a new way to zebra stripe a set of elements.  In this example we'll stripe a unordered list:

HTML:

<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
</ul>
jQuery 1.4:

$(document).ready(function(){
$("li").css("background-color", function(i){
return (i % 2 === 0) ? "#cccccc": "#FFFFFF";
});
});

We select all the LIs and call the .css() setter method. We give it the property name we want to update, background-image and we pass a function that will return the value we want to set.

The function tests if the index that we passed in i is MOD 2 (simply is it even or odd), if even set the color to #cccccc else set it to #FFFFFF.

Demo: (jsbin)

Note: Obviously, this isn't the best way to do zebra stripping with jQuery but I like to explore different ways to do the same thing to learn the techniques.

Tuesday, August 04, 2009

PHP 101: Uploading a file

I am doing some freelance work with PHP and I am posting these for my future reference.  This is basic PHP 101 stuff here.

The HTML Form:

<form enctype="multipart/form-data" action="upload.php" method="post">     Please upload your file:     <div>         <input id="fileUpload" name="fileUpload" type="file">         <input id="submit" name="submit" value="Submit" type="submit">     </div> </form>

The key part to the form is enctype="multipart/form-data" which tells the server to expect a file on postback. 

The upload php file to process the file:

<?php     $target_path = "uploads/";
    $target_path = $target_path . basename( $_FILES['fileUpload']['name']);     if (isset($_FILES['fileUpload']))     {         if(move_uploaded_file($_FILES['fileUpload']['tmp_name'], $target_path)) {             echo "The file ".  basename( $_FILES['fileUpload']['name']).             " has been uploaded";               } else {                   echo "There was an error uploading the file, please try again!";               }         } ?>


First we test to see if fileUpload has a value if so it attempts to save the file to the target path.  If all goes well we get a message that the upload passed.  If not a message that there was a problem.

Monday, July 13, 2009

403 Permissions Denied on your users Site in OSX

I came into work today and turned on web sharing and got a 403 Permissions Denied error.

I followed the typical procedure to fix this, to no avail.

The fix was to set the user home directory permissions so everyone had read access.  It currently was set so everyone had no access.

Hope that helps someone someday.

Sunday, July 12, 2009

Apples Developer Connection Documentation is buggy

I was working this morning on setting up a LAMP environment in OSX.  I found this tutorial  from Apple's Developer Connection. As I haven't set up PHP on a Mac in quite a while i felt I needed a refresher.

It was going good till I got to the section "Enabling PHP in Apache."  They outline a script you need to run but to a new Mac user this isn't readily apparent how to do.  Obviously this is geared towards the advanced Mac Developer even though the topic is for a beginner.  I finally deduce from past experience that this needs to be run like a batch script on Windows.   I do a search on Google for "shell scripting in osx" and found that I needed to run "sh filename.sh" in the terminal window.  So I created a file and copy/pasted the script into the file, saved and switched to the terminal.  Here is the script I pasted, DO NOT RUN THIS:

set admin_email to (do shell script "defaults read AddressBookMe ExistingEmailAddress")
user_www=$HOME/Sites
filename=php-test
user_index=${user_www}/${filename}.php
user_db=${user_www}/${filename}-db.sqlite3
# NOTE: Having a writeable database in your home directory can be a security risk!

conf=`apachectl -V | awk -F= '/SERVER_CONFIG/ {print \$2}'| sed 's/"//g'`
conf_old=$conf.$$
conf_new=/tmp/php_conf.new

touch $user_db
chmod a+r $user_index
chmod a+w $user_db
chmod a+w $user_www

echo "Enabling PHP in $conf ..."
sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf | sed
"s^you@example.com^<b>\$admin_email</b>^" > $conf_new

echo "(Re)Starting Apache ..."
osascript <<EOF
do shell script "/bin/mv -f $conf $conf_old; /bin/mv $conf_new $conf;
/usr/sbin/apachectl restart" with administrator privileges

EOF
The first time I run it I am asked for the administrative password which I provide.  After I see that the script had a few errors.  But the instructions on the tutorial say I should be able to create phpinfo page and see the phpinfo data.  I create the file try to run it and the web server isn't running.

I do some troubleshooting and eventually figure out that httpd.conf has not no data in it anymore.  There is an older file with a version number attached but I can't copy or write to httpd.conf cause I don't have su priv on this computer.

I go back to the script file and try to figure out what happened. First I need to fix my apache.  I hack together a shell script to fix my httpd.conf and I come up with this:

osascript <<EOF

do shell script "/bin/mv -f /private/etc/apache2/httpd.conf.9002 /private/etc/apache2/httpd.conf" with administrator privileges

EOF

This restores the original httpd.conf that was made as a back up.  Retry to access a file in apache and it serves it.  Success!  At this point I want to make my own backup file of httpd.conf in case the script screws it up more. 

osascript <<EOF

do shell script "/bin/cp -f /private/etc/apache2/httpd.conf /private/etc/apache2/httpd.conf.bak" with administrator privileges

EOF

So why did httpd.conf have no data in it?  Looking over the script it seems that it is uncommenting the line for the PHP module and sending the output to conf_new.  But it seems the file specified in conf_new is never created in the script.  So when the final line is called to copy the new file over httpd.conf there is nothing to copy.  I solve this by adding another line: touch $conf_new

Now let's tackle the script, the first error I see is that a file doesn't exist: chmod: /Users/ralph/Sites/php-test.php: No such file or directory

The file doesn't exist apparently touch $user_index isn't included in the script.  Which is funny cause nothing else in the script requires the $user_index.  The script is basically just trying to create a php file.  I also add touch $user_index to the script.

Next error is: s^you@example.com^<b>$admin_email</b>^: No such file or directory

I wasn't quite sure what was causing this error and I couldn't solve fixing it but I determined that it was trying to replace the default admin e-mail with the one I specified earlier.  I took out that part of the command.  So the new line now looks like: sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf > $conf_new

The final script looks like this:

user_www=$HOME/Sites
filename=php-test
user_index=${user_www}/${filename}.php
user_db=${user_www}/${filename}-db.sqlite3
# NOTE: Having a writeable database in your home directory can be a security risk!

conf=`apachectl -V | awk -F= '/SERVER_CONFIG/ {print \$2}'| sed 's/"//g'`
conf_old=$conf.$$
conf_new=/tmp/php_conf.new

touch $user_index
touch $user_db
touch $conf_new
chmod a+r $user_index
chmod a+w $user_db
chmod a+w $user_www
chmod a+w $conf_new

echo "Enabling PHP in $conf ..."
sed '/#LoadModule php5_module/s/#LoadModule/LoadModule/' $conf > $conf_new

echo "(Re)Starting Apache ..."
osascript <<EOF
do shell script "/bin/mv -f $conf $conf_old; /bin/mv $conf_new $conf;
/usr/sbin/apachectl restart" with administrator privileges

EOF

I feel like the script written in the Developers Connection article was just written and not tested.  But what is really concerning is there is no way to provide feedback on the article on the page.  MSDN provides a way on every page asking if the tutorial was helpful and provides an area to comment. 

Needless to say I did not finish the tutorial. 


Monday, June 22, 2009

Transparent PNG's and IE 6

IE 6 doesn't have native support for the Alpha channel that make PNG's transparent.  This can make PNG's look very ugly in IE6 when they are transparent.

Asking around the office today, I got a cool solution that uses IE's proprietary behavior css attribute to call a Compiled HTML document that applies filters to the PNG to behave correctly.

It's pretty easy to install:

How To Use

Follow these simple steps to add this to your page:

  1. Copy and paste iepngfix.htc and blank.gif into your website folder.
  2. Copy and paste this into your website's CSS or HTML:
    <style type="text/css">
    img, div { behavior: url(iepngfix.htc) }
    </style>
    That CSS selector must include the tags/elements on which you want PNG support -- basically, give it a comma-separated list of tags you use. It must also include the correct path to the .HTC relative to the HTML document location (not relative to the CSS document!). For instance, yours may look like this:
    <style type="text/css">
    img, div, a, input { behavior: url(/css/resources/iepngfix.htc) }
    </style>
  3. If your site uses subfolders, open the .HTC file in a text editor like Windows Notepad and change the blankImg variable to include a correct path to blank.gif like so:
    var blankImg = '/images/blank.gif';
    Again the path is relative to the HTML file. Otherwise, you will see a "broken image" graphic!

Tuesday, June 16, 2009

Selecting the fastest selector for jQuery using Firebug Profile

Today I needed to select all the h3's within a div and set a margin-top property on all items in the returned set except the first.

I came up with a few ways to return the results I was looking for (here are some jQuery examples):

$("#div h3").slice(1);

$("#div h3:not(:first)");

$("#div h3:gt(0)");

I've been reading a lot about how your selection can be optimized based on how you structure your query. So I ran each query through Firebug Profile to see which selector query was the fastest. Load the page, click on the "Profile" button at the top, run your query in the console, click the "Profile" button again to stop the profile.  You'll get the time it took to execute that statement.  Here are the results for each:

$("#div h3").slice(1); 3.305ms

$("#div h3:not(:first)"); 0.705ms

$("#div h3:gt(0)"); 2.347ms

It's clear from my testing that the second query is 2-3 times faster then the rest for my page and my specific uses.  Your specific profile times may vary based on HTML structure and selector query. So it's always good practice to test the speed of your selector if there is more then one way to get your results so that you are using the most efficient selector for your situation. 

Sunday, June 07, 2009

Hidden C# Feature: Using Alias Directive

You can create an alias to a long namespace or a type like so:

using Project = SolutionName.Data.Project;

Then you use the Alias in place of the namespace:

Project p = new Project();

I wish I would of known about this last summer, probably could of shaved a month off my project just from not having to type in the long namespaces to our data layer.

Related Links:

using Directive (C# Reference)
Hidden Features of C#

Thursday, January 29, 2009

Building a jQuery-Powered Tag-Cloud with an ASP.NET MVC backend

NETTUTS had a great tutorial by Dan Wellman called "Building a jQuery-Powered Tag-Cloud" The problem for me was that the tutorial showed you how to connect to the database and pull tags and frequencies via PHP.

Because I am currently learning ASP.NET MVC I thought I would try to duplicate the results of the tutorial but with using ASP.NET MVC RC instread of PHP.  Here is how I did it.

I started by creating a Home Controller class.

HomeController.cs

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.Mvc;
   6:  using System.Web.Mvc.Ajax;
   7:   
   8:  namespace MvcApplication5.Controllers
   9:  {
  10:      public class HomeController : Controller
  11:      {
  12:          //
  13:          // GET: /Home/
  14:          public ActionResult TagCloud()
  15:          {
  16:              return View();
  17:          }
  18:   
  19:          public JsonResult JSON()
  20:          {
  21:              List<object> tagcloud = new List<object>
  22:              {
  23:                      new { tag = "jQuery", freq = "10" },
  24:                      new { tag = "asp.net", freq = "3"},
  25:                      new { tag = "programming", freq = "183"},
  26:                      new { tag = "code", freq = "34" },
  27:                      new { tag = "HTML", freq = "58"},
  28:                      new { tag = "javascript", freq = "23"},
  29:                      new { tag = "people", freq = "43" },
  30:                      new { tag = "Google", freq = "3"},
  31:                      new { tag = "Microsoft", freq = "1"},
  32:                      new { tag = "Apple", freq = "10" },
  33:                      new { tag = "iPhone", freq = "38"},
  34:                      new { tag = "MVC", freq = "1"}
  35:              };
  36:              return Json(tagcloud); 
  37:          }
  38:   
  39:      }
  40:  }

What's happening here is that we are making a action for the View we will create and I am calling it TagCloud.  This action isn't going to provide us any data so it's a stub action.  The next Action we create is to provide TagCloud the JSON data.  In here I am creating a static List to send back serialized as JSON.  You could also tie it to a model and use Linq to SQL to build the List.

Our URL for the .getJSON method will be: /Home/JSON

This will return JSON data that looks like this:



Notice the difference in the JSON I am bringing back and the one Dan was bringing back.  I don't have a tags: with the rest of the data nested under it.  We'll need to update a line in the jQuery to make this work now.

Let's create the View for TagCloud.


TagCloud.aspx

   1:  <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
   2:   
   3:      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
   4:      <html>  
   5:        <head>  
   6:          <link rel="stylesheet" type="text/css" href="/content/tagcloud.css" />  
   7:          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
   8:          <title>jQuery Tag Cloud</title>  
   9:        </head>  
  10:       <body>  
  11:         <div id="tagCloud">  
  12:           <h2>Tag Cloud</h2>  
  13:         </div>  
  14:         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>  
  15:         <script type="text/javascript">
  16:             $(function() {
  17:                 //get tag feed  
  18:                 $.getJSON("/Home/JSON",null, function(data) {
  19:                     //create list for tag links  
  20:                     $("<ul>").attr("id", "tagList").appendTo("#tagCloud");
  21:   
  22:                     //create tags  
  23:                     $.each(data, function(i, val) {
  24:   
  25:                         //create item  
  26:                         var li = $("<li>");
  27:   
  28:                         //create link  
  29:                         $("<a>").text(val.tag).attr({ title: "See all pages tagged with " + val.tag, href: "http://localhost/tags/" + val.tag + ".html" }).appendTo(li);
  30:   
  31:                         //add to list
  32:                         li.appendTo("#tagList");
  33:                         //set tag size  
  34:                         li.children().css("fontSize", (val.freq / 10 < 1) ? val.freq / 10 + 1 + "em" : (val.freq / 10 > 2) ? "2em" : val.freq / 10 + "em");  
  35:            
  36:                     });
  37:                 });
  38:             });  
  39:         </script>  
  40:       </body>  
  41:    </html>  

As we start to loop through the JSON data Dan was telling jQuery to start inside tags with data.tags, since we don't have tags we can just use the variable data like so: $.each(data, function(i, val) {

The rest of setting this up is the same as NETTUTS article.  All that remains is the css.




Download the Source

jQuery-TagCloud_source.zip (44.82 KB)



Tuesday, January 20, 2009

In Case you Missed it: #jQuery Twitter posts

My #jQuery related twitter posts for the week of January 13th - January 19th:

Follow me to see what I'll twitter next about jQuery.

Sunday, October 12, 2008

Database Mirroring with SQL Server 2005

    Database mirroring is a software solution, provided by SQL Server 2005, that gives you the ability to replicate your data in real-time.  Mirroring allows for increased database availability and data protection and works at the database level on databases that are set to full recovery mode.  You need two instances ofSQL Server to set up mirroring because it maintains separate copies of data of a single database across both servers.

    Let's look at a common scenario for database mirroring. Take a company that has their customer database in a data center in New York City.  They also have a backup data center in Houston. The database in NY is mirroring the data to the database in Houston.  Let's say the data center in NY loses power and they need to shut the server down.  With a "flip of a switch" they can move the database to Houston and continue as if nothing happened.  When the data center gets power again they can switch to the NY city database as soon as it's resynchronized.

Benefits

    One benefit of database mirroring is the increased data protection of your data.  As each transaction is being written to your principle database it is sending that exact transaction to the mirror database.  This provides complete or almost complete (depending on which mode you set up; I'll get into this later) data redundancy in real time.

    High-availability, this is a huge benefit for mission critical data.  Hardware failures happen and network issues arise, with a "flip of a switch' you can send the responsibility to the mirrored server to become the principled server at any time.  You can also set up automatic failover with the addition of a witness server to monitor the servers.

    Another benefit is that you have the flexibility to install updates on your server without data disruption.  Because you can manually failover to the mirror server at any time you can failover, install the updates and reboot if necessary. When you are done you can then have the new principle server failover again to restore the principle on to the primary server without any data loss or downtime and upgrade the mirror server.

    Finally, you can set up mirroring to sync in synchronous or asynchronous modes.  Synchronous or high-safety mode will write a transaction to the principle database and send that exact transaction to the mirror and then wait for it to finish committing that transaction before moving on. With high-safety you are assured that the data that is on the principle is on the mirror at the exact same time. In that you trade some latency waiting for the transaction for the true redundancy of the data.  Automatic and manualfailovers, explained more below, require the use of high-safety mode.

    Asynchronous or high-performance mode will send the stream of transactions at the mirror server and the mirror will try to keep up.  With high-performance there can be a gap where the mirror has a back log of transactions to complete that the principle already has completed.  This gap can become pretty big with heavy loads on the principle. 

Requirements

    Database mirroring requires two servers. With SQL Server 2005 you can set up mirroring with Standard or Enterprise editions.  It's very important that both servers are running the same edition.  It is also recommended that the hardware for both servers be near identical and have the ability to handle the same load.

Setting up a Database Mirror

    Let's start with some simple preparation:

  1. Make sure that you have the proper logins created on the mirror server.
  2. Create the mirror database by restoring with NORECOVERY a recent full backup of the principle database. The principle database must have been set-up with full recovery when the backup was created.
  3. You must also restore all log backups since the full backup was made. Create a backup of the transaction logs and restore on the mirror server.  You'll want to start the mirror session as soon as you can after taking the log backup.

    Configuring Database mirroring:

  1. Connect to the principle database. Select the database you wish to mirror.
  2. Right-click > Tasks > Mirror; this will bring you to the Mirror tab on the database properties pop-up.
  3. Select the Configure Security button to configure the mirror session through the Configure Database Mirroring Security Wizard (only in this wizard you can add or change the witness server instance).
  4. Upon completion of the security wizard and you are still connected to the principle server click on Start Mirroring.

Client Connections (Connection Strings)

    I am going to assume that you as the reader already know how to connect to a database in your application code in order to access it.  What I'll cover here are the required key strings needed in the connection string to handle connecting to both database servers in a mirror session depending on which one is acting as the principle at the moment.

    Just as you would with a normal connection string you need to provide a initial partner name.  This will be the principle server.  If you are usingTCP/IP then enter in the IP, if you are using named pipes then enter in the name of your server. Additionally, if your SQL Server is using a Instance Name then you will need to add that as well (example: 10.10.2.1\InstanceName.  Now we need to provide the failover partner.  This will be the mirror server.  Add this information similarly as you would for the initial partner name.

    The other item you will need to provide in your connection string is the network attribute.  This will specify the network protocol to be used and ensures that the proper network protocol persists between connections to different partners. ForTCP/IP use the following:

Network=dbmssocn;

    Named Pipes use:

Network=dbnmpntw;

    Putting it all together in a sample connection string, you can get more info on connection string keywords here:

Data Source = 10.10.2.10/InstanceName; Failover partner = 10.10.2.11\InstanceName; Initial Catalog = databaseName; User ID = sa; Password = 12345; Network = dbmssocn;

Failover

    There are three types of failover: automatic, manual and forced.  Automatic requires a witness server and the mirror set-up in high-safety mode.  Manual failover does not use a witness server and also requires the mirror set-up to be in high-safety mode. Forced is usually used because the principle server has been disconnected somehow.  Using forced service may result in data lose as all transactions may not have made it to the mirrored server.  Forced service is supported on high-availability and high-safety mirrored set-up modes.

Automatic Failover

    For automatic failover to occur the following conditions are required:

  • Mirroring sessions must be running high-safety mode and posses a witness server.
  • The mirror database must be synchronised.
  • The principle server has lost communication with the witness and mirror servers but the witness and mirror server are still online.  Note: If all servers lose connectivity but then the witness and mirror server comes online automatic failover does not occur.
  • The mirror server detects the loss of the principle server.

    How it works

  • If the principle server is still online and changes it's state to DISCONNECTED and disconnects all clients.
  • The mirror and witness server both register that the principle server is unavailable.
  • The mirror server waits for all logs to be written from the redo queue before rolling forward the mirror database.
  • The former mirror server now moves online to be the principle. Recovery will roll back any uncommitted transactions, locks isolate those transactions.
  • When the former principle server comes back online and sees that the mirror has moved to principle the former principle server will become the new mirror and start synchronising. Once synchronising is complete failover is possible again.

Manual Failover

    With manual failover it's possible to failover to the mirror server so that updates and upgrades can be performed on the principle server. Manual failover requires the mirror set-up to be in high-safety mode (transaction safety set to FULL). The partners need to be connected and synchronised.

    How it works:

  • Principle server disconnects, sends the last log message to the mirror and switches to be the mirror server.
  • The mirror server records the last log message as the failover log.
  • The mirror server waits for all logs to be written from the redo queue before rolling forward the mirror database.
  • The mirror server becomes the principle server and the principle becomes the new mirror.
  • The new mirror server quickly resynchronizes with the new principle server. Once complete failover is possible again.

    Initiate Manual failover:

  1. Connect to the principle server. Choose your database.
  2. Right-click > Tasks > Mirror; this will bring you to the Mirror tab on the database properties pop-up.
  3. Click Failover.  Confirm that you want to failover to the mirror server.

Note: The client will need to see that the connection to the primary has failed before it will try to connect to the failover partner.

Forced Service

    If the Principle server goes down due to hardware issues or is unreachable you can use forced service to bring the mirror to principle state.  Doing this may cause data loss as the mirror may not have received all of the transaction logs from the principle. Read this Microsoft TechNet article for more information on forced service.

    Initiate Forced Service

  1. Connect to the mirror server.
  2. Run the following T-SQL:
    ALTER DATABASE <database_name> SET PARTNER FORCE_SERVICE_ALLOW_DATA_LOSS

    The mirror will take over as principle and mirroring will be suspended.

Summary and Online Resources

    Database mirroring has many options and ways to be effective in maintaining a high-availability database.  This article is my collected research as I was learning how to set up mirroring. If you would like more information on setting up database mirroring please look at the following resources:


Wednesday, October 08, 2008

Gaining Exclusive Access to database in SQL Server 2005 via T-SQL

Usually, whenever I restore a backup of my database in SQL Server I am presented with the following error:

Msg 3101, Level 16, State 1, Line 1
Exclusive access could not be obtained because the database is in use.
Msg 3013, Level 16, State 1, Line 1
RESTORE DATABASE is terminating abnormally.

Usually, to get around this I just restart the server. This was fine when we were developing on our local server instance on our development machines. But we have a few programmers that need to make changes to the database and the logistics of having everyone script their changes and drop them into Subversion was becoming a nightmare. Regardless our simple solution was to put it on a shared server in the office and backup the server occasionally, in case someone screwed up the data.

Well I screwed up some data and needed to restore. Unfortunately, I have another co-worker in the office who is working on another project and is using the same database server (different database) for development. To be nice I'd want to restore without restarting the SQL Server and possibly disrupting his work.

What I need to do is find all the connection processes to the database and kill them:

Use Master
Go

Declare @dbname sysname

Set @dbname = 'databaseName'

Declare @spid int
Select @spid = min(spid) from master.dbo.sysprocesses
where dbid = db_id(@dbname)
While @spid Is Not Null
Begin
        Execute ('Kill ' + @spid)
        Select @spid = min(spid) from master.dbo.sysprocesses
        where dbid = db_id(@dbname) and spid > @spid
End

Now I can immediately restore:

USE Master
GO
RESTORE DATABASE [databaseName]
FROM  DISK = N'physical disk path to the backup file.bak' --example path: c:\program files\microsoft sql server\mssql\backup\databaseName.bak
WITH  FILE = 1,  NOUNLOADREPLACESTATS = 10
GO

This method works best in a development environment with minimum developer connections. In production/staging environments refer to your database administrator for best practices.


Related Links

How to Gain Exclusive Access to SQL Server 2005 DB to restore?

Tuesday, August 26, 2008

jQuery Plugin - Simple Shadow

UPDATE: Simple Shadow has been set up on Google Code.  You can get the latest here.

We've been researching and trying out javascript shadow solutions for quite sometime.  Our designers are really liking to add subtle dropshadows to elements in their designs.  jQuery UI had a shadow plugin and it looked promising.  I even submitted some bug reports to help it along.  But it's been officially removed from the project for the time being.

We've been using RUZEE.shadedborder to handle our shadow needs.  It works but adds a lot of undesired div tags to make the gradient color.  But the biggest problem was it was really slow and caused IE to crash when I had six items on a page RUZZEEIFIED.

I finally gave in and decided to write my own shadow plugin to handle my specific needs which were to display a shadow of 10px width on the right and bottom sides.  I needed it to be easy as well so it uses graphics to accomplish the shadow.

This will work on any element that has a width and height specified in css.  It requires three image files that are included in the complete zip file below. See demo.

Here is the code to make the shadow:

$(document).ready(function() {     $("div").shadow(); });

Download


UPDATE: Simple Shadow has been set up on Google Code.  You can get the latest here.

Monday, July 14, 2008

Adding link separators to a unordered list using jQuery

I figured out how to easily add a separator to a inline displayed unordered list of links using jQuery and so I'd thought I share.

So for a list like so:



I wanted it to display like this:

Ralph Whitbeck | jQuery | BrandEnsemble

Notice that the separator (|) is only between the links and not at either the beginning or end.  I should also note that when I was rendering the list it was coming from a dynamic source so I didn't have a set list to work from.

I wrote this jQuery:

$(document).ready(function(){
   $(".subnavigation li:lt(" + ($(".subnavigation li").length - 1) + ")").append(" | ");
});


So basically I used the :lt(index) selector to match against all the matches that were less then the index value.  I do that by figuring out the length of how many are selected and subtracting one.  Then finally I append my selector to all of my matches.


Update: John Resig (creator of jQuery) chimes in with an easier way to do the same thing in the comments.

$(document).ready(function(){
   $(".subnavigation li:not(:last-child)").append(" | ");
});

This works by selecting all the li's except the last child (or the last li) in the container. This will work with multiple containers on a page if there are more then one.  Thanks John for the tip.

Saturday, June 28, 2008

How to target="_blank" a link while keeping it XHTML compliant with jQuery

I had to make a bunch of links for a site I am working on for a client at work open in a new window.  It's not ideal but it was what was requested.

So I set up my links like such:

http://ralphwhitbeck.com

I run my page though a HTML validator and am quickly reminded that the target attibute is not allowed in the XHTML 1.0 Strict standard.  I do a quick Google Search and the first couple of results bring back the following function to make it compliant:

function externalLinks() {
 if (!document.getElementsByTagName) return;
 var anchors = document.getElementsByTagName("a");
 for (var i=0; i    var anchor = anchors[i];
   if (anchor.getAttribute("href") &&
       anchor.getAttribute("rel") == "external")
     anchor.target = "_blank";
 }
}
window.onload = externalLinks;

This function expects there to be a rel="external" attribute inside the links you want to open in a new window.

That function to me looks scary and ugly.  jQuery to the rescue.

$(document).ready(function(){
    $("a[rel='external']").attr("target","_blank");
});

I was able to shrink all that down to one line of jQuery.  And it's a lot easier to read and more importantly it now makes the document XHTML compliant.

Note: I did notice a huge argument/discussion on if this is really truely standards compliant.  As when you take the generated html code and run that through the validator you still get the same compliance error.  While others say that you are separating the action from the presentation and that satisfies the standard.  Thirdly others say that target was depricated and as such we should never use it because the standards people think we shouldn't open new windows on people.   I don't know whose right or whose wrong but I did find the discussion interesting.  Thoughts?

Monday, June 09, 2008

My first JSON Implementation

I wanted to share my first real use of JSON (JavaScript Object Notation) I created today at work.  The reason I find this exciting is cause I never really understood the use of JSON or how to create and use it.  I found a simple use when I wrote about pulling in twitter updated into my blog using jQuery and the Twitter API using the JSON data, but I didn't create the JSON and was just consumming it.

Well today I was tasked with creating a JavaScript array that could be easily updated by an administrator of a web site and the data would be used to populate a dropdown box.  Yes there are probably better solutions to populate a dropdown box but this was what I was tasked with. 

Now a year ago, I would have probably created an XML file to hold onto this data but a recent blog post from Jeff Atwood over at Coding Horror made me realize that XML is ugly.  From that article JSON seemed like a cleaner choice.

So basically my data needed to hold geographical regions of the US with sections or cities for each region.  Each region/city would have a url associated with it.  So in a separate js file I created this:

{ regions: [
                    {
                        text: "NorthEast",
                        value: "http://ralphwhitbeck.com/northeast",
                        sections: [
                                         {
                                            text: "New York",
                                            value: "http://ralphwhitbeck.com/newyork"
                                         },
                                        {
                                            text: "Boston",
                                            value: "http://ralphwhitbeck.com/boston"
                                         }
                                     ]
                   },
                    {
                        text: "South East",
                        value: "http://ralphwhitbeck.com/southeast",
                        sections: [
                                        {
                                            text: "Orlando",
                                            value: "http://ralphwhitbeck.com/southeast"
                                        }
                                      ]
                    }

                ]

}

So looking at this you can see that it's very clean and easy to read.  We can see that it's two levels deep and we can see which sections are related to which regions at a quick glance.

Now I needed to take this JSON data and consume it and populate a dropdown.  I turn to jQuery to help me out (which was very slow today due to the 1.5 release of the UI plugin).  Here is the code to consume display it:

$(document).ready(function(){
    $.getJSON("sections.js",function(json){
        $.each(json.regions, function(i,ritem){
            $("#select_dropdown").append("");
            $.each(ritem.sections, function(i,sitem){
                $("#select_dropdown").append("");
            });
        });
    });
});

This requires a select element on the page with an id of select_dropdown. 

Download the example code JSON_Example-DamnRalph.zip (1.24 KB)

Update: So an interesting problem came up at work today where we needed to validate the JSON because the data we entered had a syntax error (we figure this was the case cause it wasn't working as expected) and so we needed a validator to validate the JSON data.  Unfortunately the way we are consumming the JSON if it tries to parse it and it's not valid then the user doesn't get an error (is this the desired choice in jQuery's getJSON method?) so there is no feedback to what the sytax problem might be.  We found this online JSON Validator that worked to help us identify the syntax errors.

Thursday, May 29, 2008

Gary Vaynerchuk @ Tech Cocktail Chicago

TECH cocktail, a community building startup founded in May 2006 by Frank Gruber and Eric Olson, offers events and community-powered projects open to bloggers, technology enthusiasts, entrepreneurs & professionals interested in technology in under served technology communities.

Today, Loyola University hosted a bunch of speakers the one I was most interested in hearing was Gary Vaynerchuk of Wine Library TV.

I found a short summary of the talk from Tim Courtney:

Gary Vaynerchuk said definitively on community, “It’s irrelevant whether you’re a traditional business or a new media business, it’s all about the community. The community is the entire thing you should care about 24/7/365. What you need to become is a rat. Real, Authentic, and Transparent. Because you can’t hide anymore, everything you do is documented.” The core of his message is that people, marketers, companies, everyone — needs to be real with their audience or they will be exposed and leave open a vulnerability for smaller players who are authentic to come up and usurp your leadership position. My thoughts: Your character is who you are when no one is watching. Gary observes that the times when “no one is watching” are getting fewer and fewer as people adopt social tools. This doesn’t make character any more important, but your actions are becoming far more public so character flaws and inauthenticity is now more exposed.

But more importantly qik user bryanthatcher streamed it for us.  The sound quality is poor but you can still make out most of what he is saying.



(image from twitpic user timcourtney)

Monday, November 19, 2007

Pulling twitter updates with JSON and jQuery

I wrote a little script tonight to pull in my latest 3 tweets from twitter and display them on my blog.  You can see it in action on the right.

Here is how I did it.  I used the Twitter's API and called my timeline with a JSON call and comsummed it with jQuery and outputted it to a blank div.

       var url = "http://twitter.com/status/user_timeline/RedWolves.json?count=3&callback=?";        $.getJSON(url,         function(data){             $.each(data, function(i, item) {                 $("img#profile").attr("src", item.user["profile_image_url"]);                 $("#tweets ul").append("
  • "                       + item.text.linkify()                       + " "                       + relative_time(item.created_at)                       + " via "                       + item.source                       + "
  • ");             });         });

    Basically what this does is pulls in the data from twitter and makes them available as objects.  I then loop through each item and pull out the data I want and write it out to a unordered list. Update: make sure to look at the complete working example below as it has the two functions this code block is using (linkify and relative_time) to transform the JSON data into how I'd like it to look.

    Here is the HTML stub it's going to:

       

                   
         

      You can download a working example here: twitter-json-jquery.html (1.79 KB)

      Monday, November 05, 2007

      VS.NET IDE Issue - ASPX gets separated from codebehind

      Sometimes in VS.NET 2005 the codebehind for the aspx file show up in the solution explorer not connected.

      To Solve this problem:

      1. Close Visual Studio
      2. Open up the proj file with a text/XML editor.
      3. Scroll down till you find the <EmbeddedResource> section.
      4. Find around where you need to enter in a new resource in relation to the file you're having issues with.
      5. add this for each file except the aspx file:
          <EmbeddedResource Include="Admin\Author\MassUpload\upload.aspx.cs">
      <DependentUpon>upload.aspx</DependentUpon>
      </EmbeddedResource>
      <EmbeddedResource Include="Admin\Author\MassUpload\upload.aspx.resx">
      <DependentUpon>upload.aspx.cs</DependentUpon>
      </EmbeddedResource>

      Related Links

      Form & Designer File Becoming Separated


      Saturday, October 27, 2007

      Installing Rails on Ubuntu using VMWare Server

      I installed Ruby on Rails,I think ;), on a VMWare Server installation of Ubuntu 7.10 using the following tutorials.

      To install VMWare Server and Ubuntu: http://cmsproducer.com/Ubuntu-Linux-Windows-VMware-Server

      To install Ruby on Rails on Ubuntu: http://paulgoscicki.com/archives/2005/09/ruby-on-rails-on-ubuntu/

      Total installation time took me about two hours from the start of downloading Ubuntu to finishing the last step.

      Now let's see if I can figure out how to program Ruby on Rails.

      Thursday, October 11, 2007

      Click on your own Google Adsense links without breaking policy

      Laurent Kempé writes:

      If you are developing a site containing Google Adsense you might know that clicking on your own ad is not allowed.

      To be able to test and click on your own ad and still follow Google AdSense Program Policies, just add following to your pages:

      <script type="text/javascript">google_adtest = 'on';</script>

      Don't forget to remove it on your production server! ;)

      That's cool! The biggest worry of any Google Adsense participant is getting dropped from the program for clicking on your own links.

      Tuesday, July 10, 2007

      Uninstalling Cisco VPN client kills internet access

      Symptoms

      On starting the computer the computers internet access will work normally for a short period of time. Then access to normal websites will be down. Access to https sites, internet application such as instant messaging and e-mail are still accessible.

      Cause

      Uninstalling Cisco VPN 4.0 client doesn't fully uninstall hidden Zone Alarm Firewall which causes a block in port 80 on the computer.

      Resolution

      Cisco VPN client version 4.0 includes firewall functionality from Zone Labs Inc. It is possible that a failed Zone Labs uninstall left an incorrect value in the systems registry and must be changed. To resolve the problem follow these steps.

      Caution This procedure contains information about editing the registry. Before you edit the registry, make sure you understand how to restore it if a problem occurs.

      Step 1 Restart the computer and when your computer screen displays the startup message like "Starting Windows..." and a progress bar at the bottom of the screen, press the F8 key on the keyboard. This should display an advanced options screen.

      Step 2 At the advanced options screen select "Safe Mode" as a startup method.

      Step 3 If prompted, login to the PC once it is booted (you must have Administrator rights to login in Safe Mode).

      Step 4 Click Start > Run and type "regedit" in the Open: box (without the quotes) and click OK. This launches the Windows registry editor.

      Step 5 In the registry editor, browse to the following path: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\vsdatant and select the Start parameter in the right pane.

      Step 6 Right-click Start and select Modify. In the Value data: field enter the number 3.

      Step 7 Click OK and exit the registry editor.

      Step 8 Restart the computer and boot normally; the problem should be resolved.

      Related Links

      Release Notes for VPN Client, Release 4.0.1

      Author notes


      I spent a considerate amount of time looking for a resolution to this problem..I post it up here in hopes that it helps someone else a little easier.  If it helps you please post a comment to let me know.

      Sunday, May 27, 2007

      Brakes and Rotors

      My brakes started grinding this week so I needed to get that fixed...I bought the parts Brake pads and rotors and went over to my cousins house and he helped my put them on....I swear to god it was so easy...I am going to do it myself next time.

      I found instructions online for my type of brakes so I can do it next time.

      http://www.2carpros.com/how_to/how_to_replace_brakes.htm

      tools I'll need to get the job done:

      14 mm socket
      18 mm socket
      C-Clamp
      Mallet or hammer (in case the bolts are tight)
      Jack
      Brake pads
      Rotors (if worn)

      The Official jQuery Podcast

      with Ralph Whitbeck & Rey Bango

      You can subscribe to the show in iTunes or via the raw RSS feed

      My Twitter Updates

      View Twitter Page