XpsRollup Including Adding Blank Pages

XpxRollup is an example program from MSDN for combining multiple xps files. We use this at work for creating files that we can use to print runs of course materials. To use the XpsRollup file you’d do something like this.

xpsrollup.exe outputfile.xps file1.xps file2.xps file3.xps ...

The problem with this was that we wanted to each xps file to start on a new page when printed double sided. To overcome this we had to insert a blank.xps file between each section that required it. the difficulty was identifying where the blank files were required. This usually meant crating an xps file and then checking if the page breaks were correct.

To overcome this I decided to modify the XpsRollup source code. I simply introduced a page counter into the code and at the end of each document insertion I used the page count to find out if I needed to add a blank page in. If it was odd I needed a new blank page if it was even I didn’t.

I’ve attached the new file to this post with a blank.xps file to insert between pages. Xps Rollup Add Blank. Enjoy!

Business Analysis – RACI Matrices

An Introduction to Tools and  Techniques

I’ve recently been working as a Business Analysis trainer and in this position have had the opportunity to use and teach many interesting techniques. I though I’d share some of my thoughts on some of the techniques as they come to me!

The first technique/tool I wanted to talk about is RACI Matrices. These are becoming the way of working with stakeholders and allow you to identify how a stakeholder is involved with a specific activity or process.

A Case Study

As I go through this article I will be using an example business system to show how the tool fits in. The example I will use will be for a library. A traditional library that lends books (you know… these places that lend dead trees to people by scanning a card, stamping a book and getting them to return the item when they’ve finished with it).

What does RACI Stand for?

RACI is an acronym which stands for “Responsible”, “Accountable”, “Consulted” and “Informed”.  There are several variations to this but this is the most commonly used set so I will use this for the purpose of this article.

Now we know what the letters stand for lets consider what the categories mean and which stakeholders may fall into each within our library example.

Responsible

The stakeholders in this category are the ones who operate/run the area under investigation. In our library lets consider the function of “Lend Books”. The stakeholders we would consider responsible for the “Lend Books” function would be the librarians at the desk who take people’s library cards, scan the books and issue the loans to lenders.

Accountable

Accountable stakeholders are those at which “the buck stops”. The person with overall responsibility for the task at hand. Often a managerial role falls into the accountable area. In our library example it would be someone like the head of the librarians at the desk. This person is responsible for the accurate and complete completion of the “Lend Books” function.

Consulted

These stakeholders are people who need to be liaised with about the completion of the task. This implies a two way communication. In the library example if our lender has outstanding fines to pay for late return of items, an account administrator may be consulted as to the account status before a loan is permitted.

Informed

Informed stakeholders are those who are “kept in the loop” about goings on but do not have any input to the operation of the function. Due to the non-input nature of this relationship a single direction of communication is inferred here. In out library example, the overall library manager may wish for management information about the number of loans or other performance metrics of the process and would therefore be informed about the process.

RACI Roles

Now we have an idea of what each element of the RACI are lets lay out some rules for using a RACI Matrix (We’ll see soon why it’s called a matrix).

  • Responsible and Accountable positions are only assigned to one stakeholder role.
  • Often the role that is accountable for a task is also responsible for it. In this case only the Accountable role is added and the Responsible is assumed to be the same person
  • Except for the Responsible and Accountable roles, all other roles are mutually exclusive. For example, a stakeholder can not be both Responsible for a task as well as Informed about the task.
  • The role that is Responsible for a task obtains information required to complete the task from the Consulted role. This implies a two-way communication.
  • The Responsible role updates the Informed role about the task. This implies a one way channel of communication.
  • The Responsible role may delegate responsibilities to others in their team.

Why a Matrix?

Lets get an idea of why it’s called a RACI Matrix. Usually the roles/tasks/stakeholders are presented in tabular form. Let’s build a table for the library example presented in this article.

Librarian Lender Library Manager Finance Clerk County Council
Lend Book R C A C I
Return Book R C A C I
Set Targets I A I C
Register New Borrowers R C A I I

Based on the above lets look at the matrix. We have a county council linked with the library who oversee the operation of the library and want information about the number of items leant, the number of returns, late loans etc. They are not involved in the operation of the library but need information from it.

There are multiple roles that are consulted to complete certain tasks. For example, the lend books function relies on both the lender and the finance clerk to provide information to allow the function to be completed. Similarly with “Register New Borrowers” updates both the County Council and Finance Clerk about the output of registering new borrowers.

The “Set Targets” function does not have a Responsible task specified directly and therefore this falls under the Accountable task to complete, i.e. the Library Manager.

Summary

This technique is a very useful tool for business analysts and project managers to aid with stakeholder management. It provides useful information about the functions and processes being investigated and which stakeholders may be affected by any proposed changes.

Zend Framework Smarty Integration

I’ve been working with zend framework for some time and have been using the Smarty template engine for the views. Initially we were working well with the smarty integration but have just come across a problem. I’ve been using partials for Zend Navigation elements so I can create custom layouts.

The problem I was experiencing was that all my assigned variables were being cleared after the navigation partial has been called. The cause of this problem is that when partials are rendered the view object gets cloned to make sure that the partial is rendered in it’s own address space. With my previous integration the view object was not being cloned correctly and the current view object was being returned and then all the variables in the object was being cleared.

To fix this I found a new smarty integration on the internet based on the currently used view integration and adopted this into my object… I’ve included it below!

/**
* Smarty template engine integration into Zend Framework
* Some ideas borrowed from http://devzone.zend.com/article/120
*/
class ZendExt_View_Smarty extends Zend_View_Abstract
{
	/**
	 * Instance of Smarty
	 * @var Smarty
	 */
	protected $_smarty = null;
 
	/**
	 * Template explicitly set to render in this view
	 * @var string
	 */
	protected $_customTemplate = '';
 
	/**
	 * Smarty config
	 * @var array
	 */
	private $_config = null;
 
	/**
	 * Class definition and constructor
	 *
	 * Let's start with the class definition and the constructor part. My class Travello_View_Smarty is extending the Zend_View_Abstract class. In the constructor the parent constructor from Zend_View_Abstract is called first. After that a Smarty object is instantiated, configured and stored in a private attribute.
	 * Please note that I use a configuration object from the object store to get the configuration data for Smarty.
	 *
	 * @param array $smartyConfig
	 * @param array $config
	 */
	public function __construct($smartyConfig, $config = array())
	{
		$this->_config = $smartyConfig;
		parent::__construct($config);
		$this->_loadSmarty();
	}
 
	/**
	 * Return the template engine object
	 *
	 * @return Smarty
	 */
	public function getEngine()
	{
		return $this->_smarty;
	}
 
	/**
	 * Implement _run() method
	 *
	 * The method _run() is the only method that needs to be implemented in any subclass of Zend_View_Abstract. It is called automatically within the render() method. My implementation just uses the display() method from Smarty to generate and output the template.
	 *
	 * @param string $template
	 */
	protected function _run()
	{
		$file = func_num_args() > 0 && file_exists(func_get_arg(0)) ? func_get_arg(0) : '';
		if ($this->_customTemplate || $file) {
			$template = $this->_customTemplate;
			if (!$template) {
				$template = $file;
			}
 
			$this->_smarty->display($template);
		} else {
			throw new Zend_View_Exception('Cannot render view without any template being assigned or file does not exist');
		}
	}
 
	/**
	 * Overwrite assign() method
	 *
	 * The next part is an overwrite of the assign() method from Zend_View_Abstract, which works in a similar way. The big difference is that the values are assigned to the Smarty object and not to the $this->_vars variables array of Zend_View_Abstract.
	 *
	 * @param string|array $var
	 * @return Ext_View_Smarty
	 */
	public function assign($var, $value = null)
	{
		if (is_string($var)) {
			$this->_smarty->assign($var, $value);
		} elseif (is_array($var)) {
			foreach ($var as $key => $value) {
				$this->assign($key, $value);
			}
		} else {
			throw new Zend_View_Exception('assign() expects a string or array, got '.gettype($var));
		}
	}
 
	/**
	 * Overwrite escape() method
	 *
	 * The next part is an overwrite of the escape() method from Zend_View_Abstract. It works both for string and array values and also uses the escape() method from the Zend_View_Abstract. The advantage of this is that I don't have to care about each value of an array to get properly escaped.
	 *
	 * @param mixed $var
	 * @return mixed
	 */
	public function escape($var)
	{
		if (is_string($var)) {
			return parent::escape($var);
		} elseif (is_array($var)) {
			foreach ($var as $key => $val) {
				$var[$key] = $this->escape($val);
			}
		}
		return $var;
	}
 
	/**
	 * Print the output
	 *
	 * The next method output() is a wrapper on the render() method from Zend_View_Abstract. It just sets some headers before printing the output.
	 *
	 * @param <type> $name
	 */
	public function output($name)
	{
		header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
		header("Cache-Control: no-cache");
		header("Pragma: no-cache");
		header("Cache-Control: post-check=0, pre-check=0", false);
 
		print parent::render($name);
	}
 
	/**
	 * Use Smarty caching
	 *
	 * The last two methods were created to simply integrate the Smarty caching mechanism in the View class. With the first one you can check for cached template and with the second one you can set the caching on or of.
	 *
	 * @param string $template
	 * @return bool
	 */
	public function isCached($template)
	{
		return $this->_smarty->is_cached($template);
	}
 
	/**
	 * Enable/disable caching
	 *
	 * @param bool $caching
	 * @return Ext_View_Smarty
	 */
	public function setCaching($caching)
	{
		$this->_smarty->caching = $caching;
		return $this;
	}
 
	/**
	 * Template getter (return file path)
	 * @return string
	 */
	public function getTemplate()
	{
		return $this->_customTemplate;
	}
 
	/**
	 * Template filename setter
	 * @param string
	 * @return Ext_View_Smarty
	 */
	public function setTemplate($tpl)
	{
		$this->_customTemplate = $tpl;
		return $this;
	}
 
	/**
	 * Magic setter for Zend_View compatibility. Performs assign()
	 *
	 * @param string $key
	 * @param mixed $val
	 */
	public function __set($key, $val)
	{
		$this->assign($key, $val);
	}
 
 
	/**
	 * Magic getter for Zend_View compatibility. Retrieves template var
	 *
	 * @param string $key
	 * @return mixed
	 */
	public function __get($key)
	{
		return $this->_smarty->getTemplateVars($key);
	}
 
	/**
	 * Magic getter for Zend_View compatibility. Removes template var
	 *
	 * @see View/Zend_View_Abstract::__unset()
	 * @param string $key
	 */
	public function __unset($key)
	{
		$this->_smarty->clearAssign($key);
	}
 
	/**
	 * Allows testing with empty() and isset() to work
	 * Zend_View compatibility. Checks template var for existance
	 *
	 * @param string $key
	 * @return boolean
	 */
	public function __isset($key)
	{
		return (null !== $this->_smarty->getTemplateVars($key));
	}
 
	/**
	 * Zend_View compatibility. Retrieves all template vars
	 *
	 * @see Zend_View_Abstract::getVars()
	 * @return array
	 */
	public function getVars()
	{
		return $this->_smarty->getTemplateVars();
	}
 
	/**
	 * Updates Smarty's template_dir field with new value
	 *
	 * @param string $dir
	 * @return Ext_View_Smarty
	 */
	public function setTemplateDir($dir)
	{
		$this->_smarty->setTemplateDir($dir);
		return $this;
	}
 
	/**
	 * Adds another Smarty template_dir to scan for templates
	 *
	 * @param string $dir
	 * @return Ext_View_Smarty
	 */
	public function addTemplateDir($dir)
	{
		$this->_smarty->addTemplateDir($dir);
		return $this;
	}
 
	/**
	 * Adds another Smarty plugin directory to scan for plugins
	 *
	 * @param string $dir
	 * @return Ext_View_Smarty
	 */
	public function addPluginDir($dir)
	{
		$this->_smarty->addPluginsDir($dir);
		return $this;
	}
 
	/**
	 * Zend_View compatibility. Removes all template vars
	 *
	 * @see View/Zend_View_Abstract::clearVars()
	 * @return Ext_View_Smarty
	 */
	public function clearVars()
	{
		$this->_smarty->clearAllAssign();
		$this->assign('this', $this);
		return $this;
	}
 
	/**
	 * Zend_View compatibility. Add the templates dir
	 *
	 * @see View/Zend_View_Abstract::addBasePath()
	 * @return Ext_View_Smarty
	 */	public function addBasePath($path, $classPrefix = 'Zend_View')
	{
		parent::addBasePath($path, $classPrefix);
		$this->addScriptPath($path . '/templates');
		$this->addTemplateDir($path . '/templates/static');
		return $this;
	}
 
	/**
	 * Zend_View compatibility. Set the templates dir instead of scripts
	 *
	 * @see View/Zend_View_Abstract::setBasePath()
	 * @return Ext_View_Smarty
	 */
	public function setBasePath($path, $classPrefix = 'Zend_View')
	{
		parent::setBasePath($path, $classPrefix);
		$this->setScriptPath($path . '/templates');
		$this->addTemplateDir($path . '/templates/static');
		return $this;
	}
 
	/**
	 * Magic clone method, on clone create diferent smarty object
	 */
	public function __clone() {
		$this->_loadSmarty();
	}
 
	/**
	 * Initializes the smarty and populates config params
	 *
	 * @throws Zend_View_Exception
	 * @return void
	 */
	private function _loadSmarty()
	{
		if (!class_exists('Smarty', true)) {
			require_once 'Smarty/Smarty.class.php';
		}
 
		$this->_smarty = new Smarty();
 
		if ($this->_config === null) {
			throw new Zend_View_Exception("Could not locate Smarty config - node 'smarty' not found");
		}
 
		$this->_smarty->caching = $this->_config['smarty']['caching'];
		$this->_smarty->cache_lifetime = $this->_config['smarty']['cache_lifetime'];
		$this->_smarty->template_dir = $this->_config['smarty']['template_dir'];
		$this->_smarty->compile_dir = $this->_config['smarty']['compile_dir'];
		$this->_smarty->config_dir = $this->_config['smarty']['config_dir'];
		$this->_smarty->cache_dir = $this->_config['smarty']['cache_dir'];
		$this->_smarty->left_delimiter = $this->_config['smarty']['left_delimiter'];
		$this->_smarty->right_delimiter = $this->_config['smarty']['right_delimiter'];
 
		if(isset($this->_config['smarty']['plugins_dir']))
		{
			foreach($this->_config['smarty']['plugins_dir'] as $pluginDir)
			{
				$this->addPluginDir($pluginDir);
			}
		}
 
		$this->assign('this', $this);
	}
 
 
 
	public function addScriptPath($path)
	{
		if(!isset($this->_smarty->template_dir))
		{
			$this->_smarty->template_dir = $path;
		}
		else
		{
			if(!$this->checkScriptPathExists($path))
			{
				if(!is_array($this->_smarty->template_dir))
				{
					$this->_smarty->template_dir = array($this->_smarty->template_dir);
				}
 
				array_unshift($this->_smarty->template_dir, $path);
			}
		}
 
		parent::addScriptPath($path);
	}
 
	private function checkScriptPathExists($path)
	{
		$dirs = $this->_smarty->template_dir;
 
		if(is_array($dirs))
		{
			foreach($dirs as $dir)
			{
				if($dir == $path)
				{
					return true;
				}
			}
		}
		else
		{
			if($dirs == $path)
			{
				return true;
			}
		}
		return false;
	}
}

Zend Navigation’s isActive method

Again another Zend Framework issue. I’ve been trying to work out how to detect if a current page is active when using zend navigation. I have setup an XML document with the navigation structure I am after but was having problems detecting if a higher level node in the structure was the currently active branch.

Example:

Page 1
   Sub Page 1
   Sub Page 2 - Currently active page
   Sub Page 3
Page 2
Page 3

I was wanting to know when looking at the top level pages which one of Page 1, Page 2 or Page 3 was the current branch. I know the isActive() method exists for the current page but what I didn’t realise (and is not advertised on the send manual pages) is that passing the parameter “true” to the method makes is recursive.

By calling isActive(true) on the current node I was able to determine if the current branch I was looking at is the actual branch I require.

Comment Spam

I’m sorry to say that I’ve had to require registration before people are able to leave comments on this blog now. I’ve been getting a lot of comment spam so I’ve temporarily activated the requirement for registration before comments are allowed until I’ve managed to put some form of protection in place.

Zend_Auth_Adapter with multiple identity columns (username and email)

I’ve just started working with the Zend Framework and I must say it’s awesome. So powerful and so many helpers in place to make things easy to do. I’ve just been working with an authentication adapter. I wanted my users to be able to login using either their username or email address and a password. Zend_Auth_Adapter_DbTable does a brilliant job of using one field (email or username) but does not allow you to use both.

To do this I’ve written an auth adapter which has allowed me to use both. It’s a very simple class that adds an additional where clause option with the additional field. See below for the code…

 

class ZendExt_Auth_Adapter_MultiColumnDbTable 
              extends Zend_Auth_Adapter_DbTable
{
  protected $_alternativeIdentityColumn = null;
 
  protected function _authenticateCreateSelect()
  {
    $select = parent::_authenticateCreateSelect();
 
    if(isset($this->_alternativeIdentityColumn))
    {
      $select->orWhere($this->_zendDb->quoteIdentifier(
                      $this->_alternativeIdentityColumn, true) . ' = ?', 
                      $this->_identity);
    }
 
    return $select;
  }
 
  public function setAlternativeIdentityColumn($alternativeIdentityColumn)
  {
    $this->_alternativeIdentityColumn = $alternativeIdentityColumn;
    return $this;
  }
}

Pretty simple really. The important line is the “orWhere” bit which adds the additional column you want to use.
To use it you just have to do the following…

$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new ZendExt_Auth_Adapter_MultiColumnDbTable($dbAdapter);
$authAdapter->setTableName('user_user')
  ->setIdentityColumn('username')
  ->setAlternativeIdentityColumn('email')
  ->setCredentialColumn('password')
  ->setCredentialTreatment('MD5(?)');

Deleted items in outlook end up in the wrong deleted items folder

I’ve recently stared monitoring a mailbox for errors on a website. When an error occurs it sends an email to a Tech Support mail box. When I check through this box there are several emails that are from known sources and I like to clean the box down. When I do this however all the deleted items end up in my own mailboxes deleted items folder! This is not what I want to happen.

There is a solution to this however that requires a little bit of registry modification. If you set values as outlined below the deleted items will end up in the box of the person you deleted it from.

Key: HKEY_CURRENT_USER\Software\Microsoft\Office\xx.x\Outlook\Options\General
Value name: DelegateWastebasketStyle
Value Type: REG_DWORD
Value: 4

Note the xx.x should relate to the version of outlook you are using. For Outlook 2010 this is 14.0, for outlook 2007 this is 12.0

Credit for this goes to: http://www.msoutlook.info/question/130

UPDATE:

There is a similar fix for sent items. If you follow the instructions as listed in this MS KB article: http://support.microsoft.com/kb/972148

For outlook 2010 see: http://social.technet.microsoft.com/Forums/en/outlook/thread/4d38fdb9-e85b-4eac-b1b1-553e01bf168e

 

NASA Desktop Theme for Windows 7

Lots of people probably already know that it is possible for you to have a slide show as your desktop background. What a lot of people probably don’t know is that you can have an RSS feed as your desktop. For example, you can use something like the nasa daily theme.

I’ve just created a theme for with the help of this article. I’ve modified it slightly to use the nasa large image of the day at: http://www.nasa.gov/rss/lg_image_of_the_day.rss

If you want to use this theme. See here: NASA Theme. Simply download it, unzip it and double click on it. When asked, say you want to download the elements of the RSS theme. It may take some time to download the images so if you don’t get a background straight away try switching the theme and back again.

No Virtual Mahines were found on this server

Right… This has been driving me crazy today. Not really sure why it happened but I’ve managed to sort if out now and wanted to share!

Our hyper-v server hosting our domain controller and a couple of Linux machines decided today that it didn’t want to admit to having any machines hosted on it. When opening hte hyper-v management tools on my Win 7 laptop I was getting the message “No Virtual Mahines were found on this server”. That was quite a worry and made me reluctant to re-boot the host machine through fear of not being able to control the hosted machines any more.

My first hurdle was getting access to the Hyper-v R2 Event Log. For some reason the firewall was not configured to allow me to access this. This was a simple fix of opening the fiewall on the hyper-v server to allow WMI access. The alternative is to drop the fire wall for the duration of this fix (netsh firewall set opmode disable) and re-enable it after (netsh firewall set opmode enable).

Ok the real crux of the problem. For some reason the security permissions on the hyper-v configuration files had been lost or reset. It took me an age to fix this but finally managed to piece together enough information to fix it.

The Virtual Machine Management Service uses some configuration files from the directory %SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines\. The xml files in this directory are in fact symlinks and should be named the same as the xml configuration files for the virtual machines them selves.

We store our virtual machines in the directory v:\VMs. So for example our machine test-01 has it’s xml file stored as V:\VMs\test-01\Virtual Machines\<guid>.xml.

Each virtual machine on the host has a similar set up. To fix the permissions you need to recreate the symlinks in the directory %SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines\. To do that you need to execute the following commands for each machine.

mklink “%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines\<vm_guid>.xml” “V:\VMs\win2k8r2\Virtual Machines\<vm_guid>.xml”

icacls “%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Virtual Machines\<vm_guid>.xml” /grant “NT VIRTUAL MACHINE\<vm_guid>”:F /l

The one part that I missed initially was the “/l” on the end of the icacls command. This is very important and tells icacls to apply the security permission to the link rather than the destination file.

If any of your VM’s have snapshots you need to repeat a similar procedure for the snapshots directory.

mklink “%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Snapshots\<snapshot_guid>.xml” “V:\VMs\test-01\Snapshots\<snapshot_guid>.xml”

icacls “%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Hyper-V\Snapshots\<snapshot_guid>.xml” /grant “NT VIRTUAL MACHINE\<vm_guid>”:F /l

When you have repaired all the files in the directories simply restart the Virtual Machine Management Service” by using the following two commands:

net stop vmms

net start vmms

You should now be able to view the files in the Hyper-v management console.

SBS Migration – Part 2: Data Migration

As part of our setup we have a branch office server running Server 2008 R2. To ensure data was kept in sync between the two servers we setup some data replication namespaces and replication groups. This certainly makes replicating data to the new server a lot easier and allows a slightly more piecemeal approach to the migration.

To begin with I’ve setup the new server as another member of the replication group and replicating with the server it is replacing. I did it this way because both machines are virtual and are running on a Hyper-V host. Between the two servers in the virtual environment is a 10 Gigabit network (speedy!!). This will allow fast replication of the data between the two servers.

All users redirected data is accessed via a domain namespace. For example \\mydomain.local\Users\<username>. This again aids the transfer process. When we have low server usage one weekend I plan to re-structure the replication groups and namespaces. As all the data is kept in sync between the servers, when everything is sync’ed I can simply change the replication to replicate to the branch server from the new server as well and remove the old server from the list. This will then mean all users data and shares (again accessed by the namespace) will be being accessed from the new server.

1 very large step closer to the completion of the migration.