Archive

Posts Tagged ‘linkedin’

M885 – Chapter 1: Introduction

May 20th, 2009 admin No comments

Iterative development illustration
Image via Wikipedia

Development models:

The text starts off with a description of the older style waterfall development model, quickly details its disadvantages (rigidity, unable to cope with changing requirements, assumes all design is nailed down from the start), and moves on to newer and much more useful models.

Incremental and iterative models are given as examples of more appropriate implementations. These models have the distinct advantage of being able to cope with changing requirements – in these models, feedback is provided constantly through the use of prototypes, whereby users can review the current work, alter their requirements to fit new criteria, and then proceed onwards with new ones.  It introduces the concept of risk management – if some of your biggest risks are changing requirements, then it makes sense to find a way to manage these, by reviewing and updating the requirements and expectations at frequent intervals.

There are various ways to implement these models – timeboxing (define a set time in which to complete a subset of requirements), prioritising (where requirements are prioritised and implemented in order), and others. For any project planner will need to decide which planning model is appropriate for their work.

The Unified Process is one of these. It advocates short time-boxed iterations – the advantage here is that a lot of functionality can be prioritised, implemented and reviewed in a short time, but it can also leave you open to time constraints if there are unforeseen difficulties with the work planned. A UP project has 4 phases – inception, elaboration, construction and transition. The correct use of these phases is what makes the UP a powerful tool.

Modelling and UML:

Next the problem needs to be modelled. The concepts of domain, specification and design modelling need to be discussed. Domain involves understanding the situation/problem we are trying to solve. Specification involves describing a system to solve the problem. Design is the low-level implementation of that system. One of the biggest advantages of modelling a system is the ability to use a defined language or process to lay out the design in precise notation. One such notation is UML. It allows a designer to specify the various levels of interaction within a system, such as classes, models, functions, etc… and all of the connections and dependencies between them.

Object-Oriented Development:

The concept of OO development was a natural outgrowth of the search for a better development model. On the surface it seems deceptively simple, create a system of interacting objects utilising tight cohesion and low coupling. It gives the developer an enormous amount of power though – you can use this simple idea to model alsmot anything you would come into contact with. Take the example of a car. A vehicle has X no. of wheels and an engine. It is your base object. A car then is an extension of this concept, being a more concrete example of a real world use case. A truck is another. Both of these inherit they’re base attributes from the base object. These objects have other attributes that they encapsulate, and can be interacted with, and can in turn interact with other objects.

This OO paradigm is the natural successor to functional programming. Functional programming would get the job done in most cases, but would not supply the power and simplicity required for large scale systems. For enterprise design this would have been essential. Extrapolating further from the concept of objects you now have whole hierarchy trees of branching, related objects, and looking a further level out you see that you can have networks of unrelated but still interacting objects. Communication across systems spanning various protocol levels are now much easier to envisage.

I won’t go into detail on the basics of how to explain, create and use samples of objects, other wiser heads have done a far better job than I could. Suffice it to say that by using this implementation you can achieve powerful results, particularly when aligned with object modelling, which can give you almost a 1-1 correlation from design to implementation, effectively speccing out the entire system from the very beginning.

Software Reuse:

Let’s say you’re tired of having to rewrite your software from scratch every time you need to use it. Perfectly understandable, nobody wants to do that. It has long been an unfulfilled promise of the software engineering discipline to provide frameworks of readily available software modules that can be clicked together in any configuration to build the required system. This has never really been delivered. A core ideal of software design is local reuse. This is great within the design of a single system, as it allows code reuse within a system to achieve a high degree, and encourages developers to correctly consider all of the design needs ahead of time.

But up until now this hasn’t really been applied from a larger scale perspective. Say you’ve designed this lovely system where not a single line of code is duplicated, nothing is unused, cohesion is high and coupling is low. Great. But it doesn’t click in as a module for larger products. Or you can’t break the constituents down easily into a bunch of plug and play components.. This is the long sought after reuse that has been promised but not delivered.  The idea of the product line comes in here – a set of base line objects that can be combined into any configuration such that the final system produced completely satisfies all of the user’s requirements. Hey presto, you have your Grail.

One way of achieving this reuse are design patterns – design patterns are open solutions to common problems: take for instance the Singleton pattern (there can be only one…) the Singleton is a pattern which defines a component such that there can only ever be one of it in existence at any time. This can be extremely useful for things like persisting system state and so on.. There are dozens of them out there, exceedingly powerful, and well worth consideration.

CASE Tools:

A CASE tool (Computer Assissted Software Engineering) is one created to assisst in the design of middle to large scale systems, or even small ones if you really feel the need. What it allows you to do is express your design in a modelling language in a structured way. There are a wide number of such tools available, some of them very expensive and useful, though the first does not neccessarily imply the second. Tools such as Rational Rose would be a good example of a CASE tool. Some of them allow for a creation of a model from first principles right through to the barebones implementation of the system itself, with just the code implementation details to be filled in after. However most of them are not quite that good yet, so some coding skills are still required :)

Reblog this post [with Zemanta]

Bit Masking – Chunk 78

May 18th, 2009 admin 1 comment

Visual description of this computing imaging t...
Image via Wikipedia

Following on from our discussion of bit shifting, we come now to the topic of bit masking. This is an area that has enjoyed many uses over the years, not the least of them to do with cryptography, communications, and graphics. In fact some of the more common uses may be known to you from everyday applications such as Photoshop, used to mask out a particular colour, etc.. In this section we will cover the theory behind a mask, the power inherent in it, plus processing speed implications and other items. Firstly, the name is a bit of a giveaway. A bit mask does exactly that – it masks. Masks are generally used in conjunction with bitwise operations, the set of operations containing AND, OR and NOT, as well as XOR and others… These are a distinct class of operations from bit-shifting, and it is important to remember this. So, a bit mask ‘masks’ the original value of a bit.. How? Take this for a sample: You have the 8 bit integer (or 1 byte) 00101110. You want to alter, say, every 2nd bit to be on, regardless of its current value. You need to perform some operation on the integer such that the outcome is 01111111. To do this you will need a suitable operation, OR in this case, as well as the correct mask value:

Input: 00101110

Mask: 01010101

Output: 01111111

As you can see, performing an OR operation using these bits resulted in any bits already at 0 being set to 1, if they were masked by a 1. Simplicity itself, yes? What if you were to use an AND? This operation comes in handy if you are looking to switch bits off rather than on. Lets take the same input and mask values, change the operation and observe our output…

Input: 00101110

Mask: 01010101

Output: 00000100

So as we can see, a wildly different output. Whereas an OR gave us 01111111 (127), AND gives us 00000100 (4). There are a whole host of other applications available to us for use with these versatile little masks, such as…


Masking to 0/1

Switching them all on or off is fairly simple using masks. Similar to what we saw, preforming an OR with a 1 will give us an output of 1, regardless of the state of the original bit. Extending this idea then means that if our entire mask is comprised of 1’s, and we perform an OR operation with this on  our input number, what we get out the far side is a stream of 1’s.

Input:   00101110

OR:         11111111

Output: 11111111

If instead we want all of the bits off (0), we perform an AND with our old buddy 0 – note that in this case the size of your actual mask number itself doesn’t matter – whether it has 8 bits or 8000, they will all be 0, so the value of your massive stream of 0’s will always be 0. Makes it a little easier than working with similar fluctuations in size that you might have with an all 1 mask. In that instance you could potentially have 8 1’s (255), or 32 (16,777,215).

Input:   00101110

AND:     00000000

Output: 11111111

Bit querying

What if you need to know what state your component bits are currently in? You could dream up various ways of accomplishing this, all of which would probably make your head hurt. Using a mask makes it much easier – This is a two step process. First we decide which bit it is that we are actually looking to query, lets say 8 of 15. We construct a mask where all bits are 0 except the one we wish to examine, giving us 000000010000000.  The second step then is to perform an AND with the input and the mask.The ANDing of all the other bits to 0 effectively shifts all of those bits to 0 also, leaving only the 8th bit with a possibly different value.

The result will be a bit stream containing an 8th bit set to 1 if the original bit was 1, and 0 if it was 0. We then evaluate this result to see if the integer evaluates to 0 – if it does then our query bit was off. It the output does not evaluate to 0 (remember, we do not care what the actual value is, just that it’s not 0.. this alone tells us the pertinent information), then this tells us that the input bit was on. See example for details:

Input:   0010111011111101

AND:     000000010000000

Output: 000000000000000


Bit toggling

Say you don’t care what the contents of that bit were, you just want it inverted. Inverting the complete bits of an image will allow you to do funky things like generate image negatives and so on, for relatively little effort. How would you go about this? Actually it’s quite simple. Using an XOR operation, you can alter the bit you are interested in, say the MSB in this case, so if your mask bit is 1, your output will always be the inverse of the original input. Simple, and extremely powerful and useful. So if you’re input is 0, and you XOR this with 1, you get an output of 1 – only one bit had to be set to give the desired output. On the other hand, performing an XOR using two 1’s gives a 0 – the reason is that an XOR will perform just like a normal OR operation, if, and only if, only bit is set to 1. If both are set to 1 then the operation fails, returning a 0. See the example for details:

Input:   00101110

XOR:     10000000

Output: 10000000



So, our basic operations are looking good… Now for some real world applications. One of the simplest ways to actually use a mask is a set of boolean flags. Think of it like this: Your binary integer is made up of an arbitrary number of 1s and os, lets say 8 in this case. To a computer, these are synonymous with TRUE and FALSE. So, conceptually, we now have one input object filled 8 boolean flags, each of which we can set on or off to our hearts content. This gives us the massive advantage of only needing to incur the expense of passing one parameter around, and only having to perform one operation/comparison to actually use it. Example time… you have an 8-bit integer. You fill it with 10010110. You pass this to your method and perform an operation on it to determine an output colour, lets say the overall level of green in a photo.. In pseudo code this looks something like..

unsigned int processUsingMask(unsigned int myMask)
{
  unsigned int currentValue = 00101101;
  unsigned int outputValue = currentValue & myMask;
  return outputValue;
}

Hey presto, your very own bit masker. Now obviously this is horribly oversimplified, but its just intended to give you an induction into the possibilities that this solution presents. Another massive area where masking is commonly employed is in network addressing. Ever wondered what the subnet mask related to your IP address is? Well go and find out, because it’s not currently the area we’re interested in, but there is a wealth of information available out there on it.

Several large and well known image editing packages will give you an implementation of a mask for image manipulation,  such as Photoshop. Anyone who is familiar with such packages will already know quite about this useful little tool and what you can accomplish with them. These masks can be tricky to use and can cause more than a few headaches. This is one particular area where Processing wins out.

The mask functionality implemented in Processing allows you to very simply load two images into memory and mask one with the other to alter the displayed output.  Say you have an image of a family photo, a favourite old snapshot from years before. You want to take this image and touch it up a little, because the sky is very bright and drowns out the rest of the image a little. How would you do this?

One of the simpler ways would be to import your original photo to Processing, and have created a gradient grayscale image (Processing seems to work best with grayscale for this type of application) that has the bits at the top of the image set to a low value (the darker the mask colour, the more it will cover up the original input pixel), and higher values up to 255 towards the bottom. In effect, what you will get out of this operation is your original image with the sky brightness toned down.

To accomplish something like this, we could use something similar to the following code snippet..

size(200, 200);
PImage inputImage = loadImage("Sample.jpg");
PImage maskImage = loadImage("MaskOfSample.jpg");
inputImage.mask(maskImage);
image(inputImage);

And thats it… in just 5 lines of code we have achieved the ability to imitate sophisticated image manipulation technology. One thing to bear in mind here is that both the input and mask images need to be of the same size in order for Processing to be able to mask them. You should also be aware of the fact that if you are using a mask image Processing will only make use of the blue channel while applying the mask, so a grayscale image is probably best for use as a mask.

However, what we are going to focus on here is the ability of Processing to create a pixel mask. What a pixel mask does is essentially create an image out of pixels (specified by the program to be anything at all, from something as simple as a plain black image, or something like a  shaded gradient ) and then apply this collection of pixels as a mask to the original input image.

Take a look at this sample code and see what it does..

PImage inputImage = loadImage("Sample.jpg");
background (100, 50, 50);
fill(255);
rect(random(width), random(height), 20, 20);
loadPixels();
inputImage.mask(pixels);
image(inputImage, 0, 0);

Lets break it down – the first line is simple enough, we load an image, nothing special there. Line 2 gives us something slightly new: background(100, 50, 50); What this does is dim the levels of the colours in our image. Line 4 then tells us that we are about to fill our object with 255, to make it completely opaque in other words. We then create a rectangle to which this applies, and spawn it somewhere randomly on the image. Then we build a pixel array of the screen, and call the mask method using our inputImage, and the newly created pixel array. The last step is to output this image to screen.

What would we expect from this code? Basically, a greyed out input image with one little rectangular window cut through it somewhere that fully displayed the image underneath. The reason for this is that, by creating our rectangle with a fill of 255, making it opaque, we have created a mask window through the background colours, or fog if you will, that displays your original image in all its glory. If you set the size of your rectangle to be the same as that of the image the you would see the entire image clearly, but there’s not a hell of a lot of point in doing that… for the extra processing effort all you really achieve is to get the same image back out. If however you were to spawn a few shapes off, on an otherwise dark background, it would appear as if just small segments of the image were showing through. Have a look at the following program and try to work out what it does before running it..

PImage inputImage;
void setup()
{
  size(200, 200);
  inputImage = loadImage("Sample.jpg");
  noStroke();
}
void draw()
{
  fill(255);
  ellipse(mouseX, mouseY, 45, 45);
  loadPixels();
  inputImage.mask(pixels);
  background(0);
  image(inputImage, 0, 0);
}

Got it yet? What we’ve got here is an input image that is completely blacked out by constantly redrawing the background to 0, and a circle that we create in the pixel array that is completely opaque, which we then mask over the original image. The position of this circle is then free floating, as determined by the mouseX and mouseY parameters for position. The effect is that of shining a torch on a  dark scene and only being able to see what is currently displayed by the narrow torch beam.

Using this code it is very easy to come up with variants on the end effect. For example, to create a “scratchcard” type effect, whereby the entire image is slowly revealed by moving your circle over all areas of the picture till it is clear, requires only one very small change – move the background(0); call from the draw method (where it is called continually) up to the setup  method where it is only called once: if the background is only set once, then the opaque circles will eventually override the darkness we have imposed. Blindingly simple, and creates a function much like old-style dungeon master games where the map had to be gradually exposed overtime by the players movements. Consider how you would go about altering the program to display an image, and use your circle to black it out?

As an exercise in understanding of the topic we have just discussed, try your hand at these three examples:

  1. Implement a “Catchphrase” style image revealer game based on random images – you might have a checkbox for multiple selection answers on one side, with the program revealing one new grid square every 5 seconds – the less squares uncovered the higher your points!!
  2. Create a James Bond style image mask – Have a circle track across the screen until it hits a certain point and gradually fills with red, or possibly explodes
  3. Create a game whereby the image mask functions similar to the program described here, but the underlying image is a maze. The player gets to uncover the maze bit by bit as they move the mouse over the screen, but if they go over the maze lines/boundaries, they lose, quite like one of those electric buzzer games, except in the dark….

As you can see, the possibilities for this small application are almost endless. You can accomplish a mountain of functionality with very little effort, so test it and see what you can do.

PImage inputImage;

void setup()
{
// Load image and correctly set the size of the display
size(340, 363);
inputImage = loadImage(“Beermotions.jpg”);
// Remove the borders from the images and shapes we will create
noStroke();
// Set the background opcaity to 0 – completely black
background(255);
}

void draw()
{
// Create an ellipse (a circle in this case)
// make the circle completely opaque using the fill command
fill(0);
ellipse(mouseX, mouseY, 45, 45);

// Build and load the pixel array with the circle we have created
loadPixels();
// Mask the input image with our pixel mask
inputImage.mask(pixels);

// Draw the entire image
image(inputImage, 0, 0);
}

Reblog this post [with Zemanta]

Bit Shifting – Chunk 77

May 3rd, 2009 admin No comments

Before exploring the advantages of bit shifting to graphical processing, we should first consider this question – What is bit shifting? Basically put, it does exactly what it says on the bit… It performs a shift operation, either left or right, on a particular input, resulting in a changed output.

They are not to be confused with bit-wise operations, or standard bit operations, such as NOT, AND and OR. These are a separate class of operations which we do not intend to cover in depth in this example. Instead we will focus  on the bit-shift operations, from a basic perspective all the way up to their use for graphical processing in the example that will follow.

As we know, a standard byte is made up of 8 bits. A standard integer is 4 bytes, so 32 bits. These bits are 1 or 0, and are then shunted back and forth between these states by means of the bit shift operations.  There are also two main classes of bit-shifting. These are:

  • Arithmetic shifts
  • Logical shifts

Before we continue, there are three important concepts to be aware of here:

  • Most Significant Bit
    • The term most significant bit refers to the bit having the highest value in your number. Generally considered to be the left-most bit in most languages and representations. The least significant bit then is the lowest value bit, or right most bit. So in our example (chopped down for brevity’s sake), we have “10 10 10″, where the red 1 is the most significant/left most bit (MSB), and the blue 0 is the least significant/right most bit (LSB).
  • The Sign of the binary number
    • The MSB of a binary number is frequently taken to be the sign of the number, so for example 1 for negative, 0 for positive. If we had an 8 bit integer, 10110010, the this number would be counted as a negative because of the rightmost bit being 1. However, it is also important to note that the an integer can be declared as unsigned, meaning that the MSB is regarded as a art of the number and nothing more.
  • The Carry Bit
    • The carry bit of a binary number does what you might think the name suggests – it carries over left over bits from operations. Lets say you have added two unsigned 8 bit integers (255 + 255) and gotten 510 as your result. Normally this would be represented as 1 11 11 11 10, but remember, we are 8 bit ints here… This means that in order to perserve our 8 bit interity, we have to drop the 9th bit from our normal representation and store it instead in a special bit, the carry bit. Our corrected output then becomes11 11 11 10 (254), and carry 1.

Arithmetic Shift

Let start with Arithmetic shift operations. As mentioned previously, one int is made up of 4 bytes, 32 individual bits.

A 32-bit integer represented in binary as :

00 00 00 00 00 00 00 00 00 00 00 00 00 10 10 10

Lets say we perform a left shift operation on this number, shifting it by two bits. This now gives us:

00 00 00 00 00 00 00 00 00 00 00 00 10 10 10 00

We can visualise the preceding operation from this illustration:

Right shifting by two bits would instead have given us:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 10

As you can see, performing a straight forward left bit-shift operation on our 42 has changed the representation. the two left-most bits have dropped off, to be removed by the register storing the information, and two new bits, both 0, have been added to the right of the integer. Right shifting moved all of the digits to the right, dropping the trailing 10 from the right, and adding 00 (assuming the carry bit has been set to 0) to the left hand side.

It is important to remember that while right shifting a bit, the sign of the number is always preserved, i.e. if the MSB is 0 or 1, this bit is preserved through all of the right shifting operations you can throw at it. The other implication to note is that the LSB is shifted rightward, into the carry bit. Each successive right shift operation will overwrite the carry bit with the current LSB.

Logical shifting

A logical shift is essentially the same as an arithmetic shift, with one very important difference – where the arithmetic shift uses the carry bit as the value to insert in right shift operations, the logical shift uses only 0s. What this means from a practical point of view is that a logical shift is the shift of choice for an unsigned int (no carry preserved), and an arithmetic shift is the choice for signed operations. See examples below:

Logical right shift of 1 bit on 0011010101 (carry bit: 1) – 0110101010

Arithmetic right shift of 1 bit on 0011010101 (carry bit: 1) – 0110101011


Next to consider are the areas of Rotate (no carry), and Rotate (carry through). Both of these operations perform a rotation on the bits, essentially behaving as if the integer was circular and you were just spinning them around on a big wheel. However there is an important difference to note, and that difference concerns the carry bit.


Rotate (no carry):

This form of the rotation behaves exactly as you would expect, all bits are preserved as they are rotated, no information is lost at any stage. A standard application of this type of bit shift would be in cryptography. Consider the age old Caeser Cipher and you’ll see what I mean.


Rotate (carry through)

This form is slightly different – Instead of preserving bit fidelity on each pass, there is a change affected. The operation behaves as if the carry bit is a separator between the two ends of the integer, so instead of shifting the MSB to the LSB, or vice versa, these values are instead shifted in and out of the carry bit. What this gives us, in effect, is a situation where you might have our old friend (42) 101010, with carry bit 1. A 1-bit left rotation will then give us 010101 with carry bit 1. See illustration below for clarification.

Bit-Shifting Applications

Finally, some real uses. There have been several major uses for bit-shifting over the years, all on semi-related themes – because bit-shifting is a very low-level operation, it became very useful for applications that needed to perform fast, and to work in close synch with the areas being acted upon, for example with device drivers, image processing, communications and so on. Think about it – instead of performing big fancy operations like multiplication and so on, which can incur an overhead (always an issue where these areas are concerned), would you prefer instead to be able to simply shift the bits right and left and come out with the same solution, just much faster?

So why does this interest us? Say you are developing a program in Processing and you have a colour in an image that you want to manipulate. You might come up with something like this..

PImage myImage = loadImage(“LotsOfColours.jpg”);

loadPixels();


for(int i = 0; i < (myImage.width * myImage.height); i++)

{

int greenValue = myImage.pixels[i] >> 8 & 0xFF;
int blueValue = myImage.pixels[i] & 0xFF;
int alphaValue = myImage.pixels[i] >> 24 & 0xFF;

// Recombine component colours
myImage.pixels[i] = (alphaValue << 24) | (greenValue << 8) | blueValue;

}

Lets examine this fragment and see what it does for us.. A we have seen previously, we can load an image into memory using the PImage and loadPixel comands. We have our array of pixels stored away. So far so good. But what if this was a particularly large image? We don’t want to expend a lot of time and processor effort in just shifting a particular shade or range of colours out of our way, so we do it on the cheap using a bit shift. Take a look at the first line inside the for loop:

int greenValue = myImage.pixels[i] >> 8 & 0xFF;

What we have happening here is quite simple and beautifully powerful – We take the current pixel, which evaluates to a 32 bit integer, and decide that since we know that range the green components of a colour live in the 8 bit range, we simply shift right by 8 bits and perform a bit-wise AND with 0xFF (an int consisting of all 1’s) which gives us our original pixel withonly the green components present. Simple, fast and effective!! And the beauty is it can be done for any colour or shade you might want.

Obviously this is not the end of the story. We have extracted the green, blue and alpha components of our current colour into outside variables. We now need to do something with them, namely re-combine them back into our original source colour leaving out the components we did not want. To do this we use the line at the bottom of the for loop:

myImage.pixels[i] = (alphaValue << 24) | (greenValue << 8) | blueValue;

This could be a little daunting for anyone not used to bit work, so lets step through it piecemeal and see what it does.

(alphaValue << 24) – Take our alpha component and shift it 24 bits to the right – Give us a 32 bit int with the alpha components in the correct position: 11111111000000000000000000000000

(greenValue << 8) – Take our green component and shift it 8 bits to the right – Give us a 32 bit int with the green components in the correct position: 0000000011011010000000000000000

blueValue – Take our blue component and don’t shift it at all (should already be in the correct position for blue):  0000000000000000000000011110001

Next we perform a bit-wise OR on all three of these integers…

11111111000000000000000000000000

|   0000000011011010000000000000000

|   0000000000000000000000011110001

=  11111111110110100000000011110001


And last,but most definitely not least, we take our newly modified and red free colour and assign back to the current pixel in our image. Tada!! Our loop then hops on to the next pixel in line and does the same thing again. Very shortly our whole image has been processed and we have a beautifully dull and colour constrained image. By now you should be getting a rough idea of just how powerful this small and seemingly insignificant low-level process is. With a little imagination, and a firm grasp of the fact that full manipulation of every facet of a pixel is now yours to command, you can accomplish whatever the hell you like.

Take for instance the example iven by Greenberg in his Processing book – that of contrast manipulation. What exactly is the contrast of our image? Basically it is the signal to noise ratio of the colour components in a given set of colour components. So if, for example, you were to take a green component that evaluated to the decimal number 120 and then applied a multiplier to it of 1.5, you would achieve a result of 180, meaning that your green is now 50% stronger in effect. So in code this would look like:

int contrastMultiplier= 1.5

for(int i = 0; i < (myImage.width * myImage.height); i++)

{

int greenValue = myImage.pixels[i] >> 8 & 0xFF;
int blueValue = myImage.pixels[i] & 0xFF;
int alphaValue = myImage.pixels[i] >> 24 & 0xFF;


greenValue = greenValue * contrastMultiplier;

// Recombine component colours
myImage.pixels[i] = (alphaValue << 24) | (greenValue << 8) | blueValue;

}

So now we have an image with no red at all, and a sharpened green component. In a grand total of five lines of image manipulation code. Not a bad return on investment.  The following program ties in all of the pieces we have demonstraated so far and produces a 4 image output…

float contrastMultiplier = 1.75;

void setup()
{
size (690, 726);
}

void draw()
{
PImage image1 = loadImage(“Beermotions.jpg”);

PImage image2 = createImage(image1.width, image1.height, RGB);
PImage image3 = createImage(image1.width, image1.height, RGB);
PImage image4 = createImage(image1.width, image1.height, RGB);

arraycopy(image1.pixels, image2.pixels);
arraycopy(image1.pixels, image3.pixels);
arraycopy(image1.pixels, image4.pixels);

loadPixels();

for (int i = 0; i < (image1.width * image1.height); i++)

{
int redValue = image1.pixels[i] >> 16 & 0xFF;
int greenValue = image1.pixels[i] >> 8 & 0xFF;
int blueValue = image1.pixels[i] & 0xFF;
int alphaValue = image1.pixels[i] >> 24 & 0xFF;

redValue = int(redValue * contrastMultiplier);
redValue = constrain(redValue, 0, 255);

greenValue = int(greenValue * contrastMultiplier);
greenValue = constrain(greenValue, 0, 255);

blueValue = int(blueValue * contrastMultiplier);
blueValue = constrain(blueValue, 0, 255);

alphaValue = int(alphaValue * contrastMultiplier);
alphaValue = constrain(alphaValue, 0, 255);

// Recombine component colours
image1.pixels[i] = (alphaValue << 24) | (redValue << 16) | (greenValue << 8) | blueValue;
}

for (int i = 0; i < (image1.width * image1.height); i++)
{
int greenValue = image2.pixels[i] >> 8 & 0xFF;
int blueValue = image2.pixels[i] & 0xFF;
int alphaValue = image2.pixels[i] >> 24 & 0xFF;

// Recombine component colours
image2.pixels[i] = (alphaValue << 24) | (greenValue << 8) | blueValue;
}

for (int i = 0; i < (image1.width * image1.height); i++)
{
int redValue = image3.pixels[i] >> 16 & 0xFF;
int blueValue = image3.pixels[i] & 0xFF;
int alphaValue = image3.pixels[i] >> 24 & 0xFF;

// Recombine component colours
image3.pixels[i] = (alphaValue << 24) | (redValue << 16) | blueValue;
}

for (int i = 0; i < (image1.width * image1.height); i++)
{
int redValue = image4.pixels[i] >> 16 & 0xFF;
int greenValue = image4.pixels[i] >> 8 & 0xFF;
int alphaValue = image4.pixels[i] >> 24 & 0xFF;

// Recombine component colours
image4.pixels[i] = (alphaValue << 24) | (redValue << 16) | (greenValue << 8);
}

// Draw all 4 images
image(image1, 0, 0);
image(image2, width/2, 0);
image(image3, 0, height/2);
image(image4, width/2, height/2);
}

This program functions as a standalone artifact which encompasses all of the concepts we have covered in this chapter. All of the code snippets, and the program we have produced should be easily understandable by this point. What our final program does, in essence, is:

Take an input image and create three copies.

Process image 1 such that all colours are present in the final output, and have each of the colour components processed so that the contrast level of each has been magnified.

Process image 2 such that the contrast stays the same, but the red components have been completely removed.

Process image 3 such that the contrast stays the same, but the green components have been completely removed.

Process image 4 such that the contrast stays the same, but the blue components have been completely removed.

Draw all 4 images in 2*2  grid

Hopefully Andy Warhol would have been proud of us.

All simple ideas, but when combined and utilised in a creative fashion you can come up with some truly bizzare and astonishing effects. As a test of your comprehension, see if you can create a program which takes an input image and redraws several times a second with the colours shifted by some random variable.  If your’re feeling particularly adventurous, apply a similar concept to a rotating sphere, or just go with whatever your imagination comes up with.

Reblog this post [with Zemanta]

M882 – Section 4: Ethics, Codes and Standards

April 22nd, 2009 admin No comments

1. Decisions concerning software need to be regulated in areas affecting people and the environment

This is true of any area, but is only being properly adopted now. The example given of the Therac radiation machine is good, and serves to drive the point home. As engineers we can, and do, create products that can ave lasting effects on peoples lives. Embedded software for pacemakers, flight control software, nuclear reactor control systems, all of these things have an immediate and lasting impact, so regulation would be no small thing. Would you want your doctor practising on you after 2 years tinkering on the family gerbils?

2. Situations should be analysed ethically from first principles of moral philosophy

This is a sightly tricky one – as the text mentions moral philosophy has been hotly debated as long as man could bang two rocks together, and no definitive answer has ever emerged, nor, I personally believe, will it ever. With changing society, etc.. , how can one set of moral codes define behaviour for all time?

Leaving that aside, first principle analysis using some system, whether it be utilitarian or deontological, does at least provide some reference or framework to go on. Work out the implications, cost/benefits, for the fair treatment of all parties.

3. Sets of rules can be applied instead whenever pre-analysed situations arise

Fairly intuitive statement here. Applies to damn near anything really… The ground they’re attempting to cover is that canned responses can be used to apply to certain situations, i.e what to do if a safety critical app develops a major bug or something similar. The idea is to get across the point that there will be some form of backup I think…

4. Professional societies provide  set of rules as codes of conduct

Essentially correct. Every professional body that has ever existed (might be stretching things a bit here..) has had some set of laws that determine their actions, for both their benefit and their clients. They serve to protect everyone involved in the transaction, much like a social contract, and members must perform to the standard of these rules to gain admission and to safeguard their clients, and them, in return from the clients also.

5. Professioal societies support software practices through events and activities that share d promulgate best practices

An emergent property of the professional body or society is the code of conduct. A set of rules grows to become a code of conduct, a set of instructions for the member and org to work by. This is a fantastic development as it lays down the expected conduct of the member by the organisation, but where a lot of places fall down is enforcement. A code of conduct is absolutely no use if it is not verified and proven to be in use at any given time. For doctors, lawyers, etc… they can and will be dismissed from the professional group for lack of adherement to these codes, but there is currently no such failsafe for software developers, and there will be definitely be a need for one in the very near future.

6. Standards for software provide extra guidance, with ISO being increasingly important

Harping back to the last point – this is a step along the right road but not really far enough. An organisation can lose its ISO certification for lack of adherence to practices and guidelines, but thats about it.. They can still trade away happily without it, and quite likely retain a lot of their customer base. Some form of negative reinforcement for non-adherence will be required.

7. Process standards can be bureaucratic, displaying their military origins

I’d probably argue the point here about military implying bureaucracy, but lets continue. Oriinally this would have been true, as a lot of standards work would have come out of the military, being an area where quality was important. However, with growth and emergence of new memes such as agile processes, the bureaucratic emphasis fall away to leave a more process-centric process, odd as that may sound.

8. Internationally approved technical standards should be consulted and used in procurement and

development work

This is really just an extension of what went before – the implication that professional bodies exist coupled with codes of conduct and standards means that these should now be adopted internationally also. Not doing so, considering the global status of many of todays major suppliers, is braindead.

9. Overall processes can be certified that they comply with the relevant standards

Once both the process and the standard are sufficiently then yes I’d agree with this. The problem is that there is potential for fluffiness, vague generality creeping in here and there, interpretation of meanings and so on, which will essentially render you standards and the ceritification related to it meaningless.

Reblog this post [with Zemanta]

M882 – Section 3: Economic and social context

April 7th, 2009 admin No comments

1. People are motivated by factors other than money, provided that they get enough money

This has always been true. People will always suffer through short wages and privation if they feel that the environment and conditions are worth the lack of monetary reward. This entire section is focused on what the organisation needs to not only further its staff, but itself as by-product, and as a standalone development item. give staff the respect and self-respect they are entitled to, and you will begin to see a cohesive community being built.

2. Important motivation comes from the need for personal self-actualisation and social contact

It could be argued that almost all motivation ultimately comes from this need. Ultimately all of the goals, achievements, etc.. will boil down to some form of personal gain, even if its just personal satisfaction at seeing their team, or group, or family profit directly through their efforts. Self-actualisation, coupled with a need for society are major drivers, just as all motivational needs can in some way be linked to each other.

3. Personal development can be partly achieved by training to meet the employers needs

Following on from my previous statement, this fits in nicely. However, I’m not entirely happy about the connotations of the sentence. It seems to suggest that a person’s personal development is dependent on the organisation they work for, when in reality it is up to the individual. I know that in the context of what I’m studying it makes sense, I just like to nitpick sometimes.

4. Training must be supplemented by learning from experience, and socially from others within communities of practice

Decent point, basically it states that individuals cannot learn by study alone, experience, expert systems, feedback, peer communities, etc… are all required for proper development. This is true, and in a lot of cases people will accept the less formal ‘on the job’ training rather than the more formal and abstracted method.

5. Organisations are also motivated by the need to survive and grow within some wider rational and international economy

This is a wider extrapolation of the previous point. think of an organisation as a large organism, constituted by the cells of staff beavering away, learning and working within. Whenever more information is acquired and applied by one cell, it benefits that department, or system if you will, leading to overall benefits for the organism. Fitness to survive is the key here, and being able to learn and adapt are integral to this.

6. Modern economies are based on free markets which are, in turn, based on the exchange of private goods between free agents

Personally I tend to view the current global markets as closed rather than free. There is only a finite amount of physical resources available to push around to consumers, and it will not last forever. However, the concept behind the free market is good. Goods and services find their own price levels, and hold steady based on what the market will value. Cartels and monopolies are therefore a bad thing, choking trade and causing scarcity.

7. Markets adjust themselves through the signals of prices, interest rates, profits and wages to achieve optimal use of limited resources

Again on the subject of monopolies, the system only works when all agents are free, equal, and benevolent. Otherwise you get situations where competitors are choked out of business, commodities being offered at ridiculous prices, etc… The market needs to be monitored and regulated in order to work.

8. Markets fail when agents external to the transactions are also affected, either positively or negatively

This harks back to the idea of agents not directly implicit within a trade, but explicit from the internal actions, whereby a large monopoly organisation acquiring a smaller competitor indirectly harms the market by causing competition to break down and prices to rise, even though the market was not directly involved in this transaction.

9. People and organisations may operate outside the normal market within the gratis economy of voluntary labour and free use of products and services

Hooray for people! The gratis economy is basically people, or agents, giving time, money, work, whatever, to some other agent of whatever form for no return whatsoever. The OSS community is a prime sample, Ubuntu for example, and there are a myriad others out there doing similar works, Red Cross, NGOs, etc.. These actions not only bring needed commodities to those who need them, they help to regulate the free market by essentially being a free alternative to the pay options. The system works surprisingly well in this case, and long may it continue.

Reblog this post [with Zemanta]

M882 – Section 2: The organisational and business context

April 6th, 2009 admin No comments

1. Organisationas and the work they do can modeled by diagrams and measurements

To  a point. Only after a lot of detailed examination of the organisation, the staff involved, and the knowledge and processes contained therein can any diagramming or measuring begin. Even after this point, there will still be a lot that cannot be diagrammed, or measured. This point works off the assumption that there are no unknowns and that all items can be analysed in such a manner. The information given in the previous section belies this, and as such the statement should be taken with a grain of salt.

2. These models are necessarily partial, and should not and cannot be taken to fully represent what happens in the organisation

Excellent, my work is done for me. This point is much better, and gives a better understanding of the process and the organisation. There is too much tacit/implicit knowledge and process happening within the organisation to ever fully nail it down to be a definitive model of the organisation.

3. The work of the organisations can be modeled as business processes, a sequence of interacting individual activities

In the text, as in various other industry studies performed over the years, the concept of business processes emerged, a process whereby environment (environment here meaning any interaction with external or internal demands or pressures) trigger a set of actions from the organisation and staff to perform some set list of tasks. Taken from a programming point of view this could almost be called the organisation’s business algorithm. Seems simple but it is an important concept to understand when dealing with such entities, and hasn’t been around all that long.

4. The activities in these processes can be modeled and can be made highly specialised to enhance efficiency by scientific management methods

Simple extension of previous comments. Defined as Taylorism or Fordism, these reworked processes can be applied to the organisation to provide major increases in productivity, while also bringing costs down if applied correctly. An application of modern thought to the industrial age production method of thinking, there are, however, major drawbacks to the way these methods were actually implemented.

5. These tayloristic processes lack flexibility and humanity

I’d argue with this one and say the examples given lack flexibility and humanity. A separation between the theory and the implementations are essential here, in that anything could have been produced as a new more efficient process and had the ‘taylorism’ tag applied, without being in line with the ideals of the theory. A more holistic approach would have stuck to the theory and produced better results, particularly from a worker point of view

6. An organisation contains computing systems and software embedded within it and they are inseparable from each other

Probably wouldn’t quite agree with this. Its true to a point, but it has to be remembered that while people are absolutely essential to an organisation, software is not as much of an essential item. The org can get by quite well using other software, or depending on the size, needs, etc, possibly without any at all. There will always be cases where they are inseparable, but it is important to note that it is a commodity, an asset, instead of the end of the world.

7. The software and the business processes that use software must necessarily be developed together, and though the software can be defined by a requirements document, the software cannot be understood in isolation

This is correct. Any organisation using software for a specific purpose, no matter how banal it may seem, needs to take into account the attributes and growth of the software, just as it must do for itself. Integration into business processes and practices must be fully understood before embarking on any sort of buy-in/development/etc.. of new software to facilitate some critical need.

8. Yet in order to acquire software and later evolve it we must be able to treat the software separately from other resources used in the business process

I don’t necessarily see these two points as mutually exclusive. Going back to my comment on point 6, the software is a separate yet integrated piece of infrastructure. Think of it as something modular. You fit lots of modules together to form a cohesive whole, but once thats done you can still take them back apart to form something else, leaving out entirely one of the ‘critical’ pieces.

9. The software systems embody some of the knowledge of the organisation, but cannot embody all of the the knowledge, some must remain tacit within the people involved

Absolutely true. A very large chunk of the knowledge of all groups, large or small, exists entirely in the heads of those who work there. Various methods and strategies have sprung up for the purpose of extracting and codifying this information. Situations like staff turnover, etc.., mean a lot of this knowledge is easily lost. One of the more effective methods for extraction and retention is the concept of the feedback loop, single and double. It enables an organisation to identify its tacit knowledge, and convert it into workable, teachable practices.

10. New systems are introduced either because of internal problems, or because of external business opportunities, or because of external demands

That list is not complete. It doesn’t take into account the internal opportunities and the external problems. Regardless, it is a reasonable list for detailing how changes would originate. An organisation will need to ingest a new system, revise processes, develop new practices, etc.. in response to any of these items. They cover both reactive and proactive solutions, things like introducing new features to become a market leader, or revisiting failing processes in the face of falling revenue. Any opportunity for positive change is always a good thing.

11. Rational decision making processes and return on investment calculations can only partially help justify the acquisition

This statement is something I’m not entirely comfortable with. I personally like to be able to quantify whatever comes my way, and stating that the benefits of acquiring a system can’t be fully expressed in ROI terms is something I don’t really like. However I can’t really argue with it either. The statement, according to current processes, metrics, etc.. is correct, because there are intangibles associated with such systems, and likely will be for some time. Until Skynet takes over anyway.

12. The process of introducing new systems can be viewed as a process of adaptation or learning, and the organisation does this as a learning organisation

I’m a little uneasy at the need to make a distinction here between the concept of a learning and a non learning organisation. A non learning organisation dies, simple as that. If it is not prepared to accept feedback and learn from its environment, then it is a net detractor from the business environment as a whole, and nature will take its course. The point above should be taken as the ground state for an organisation, not as something it should aspire to.

13. Organisational learning takes place in cycles as business processes are changed, knowledge is externalised, examined, restructured, consolidated and then re-internalised

This is true, but it would be nice if it wasn’t the whole story. If instead a constant cycle of information gathered, assimilated and integrated into practice then it would show that an organisation is proving its capacity to grow and outperform its competitors. For instance, in terms of a software house, developers and management need to be constantly on the lookout for new and expanded technologies and methodologies to keep them abreast of industry changes and up to speed with the latest state of the art. Cyclical BPR should be just the beginning.

14. The people in the organisation are critical in this process, and should be viewed as part of the assets of the organisation, the human capital

Dead right. People are massively important to any group, to the (obvious) point where it can’t work without them. No people, dissatisfied people, people who feel they are not being adequately rewarded by their job (rewards in terms of ‘hygienic’ needs, or Maslow’s hierarchy), make people happier and therefore more productive in their work. Treating them like machines on a factory belt will get you nowhere and is a quick and easy way to stall productivity and lose revenue. If people are viewed as assets, or better yet as stakeholders, then they are treated as people rather than cogs in the machine.

Reblog this post [with Zemanta]

Chunk the first – Bit masking

February 6th, 2009 admin No comments

Here we go at last! Finally getting down to some real work on this, I have some time to get it started and some ideas on what to do. Some sort of fancy dynamic random image reversal, have plenty more research to do into it. Darrell wants the first drafts (at least I hope its first drafts) in by the end of February, so that gives me about a week and a half per chunk. This should be plenty of time, unless I go doing monumentally stupid.

Will post back when ideas are a little more solid..

Information Retrieval Preferences

January 15th, 2009 admin 2 comments

How do people get their information? It occured to me recently that, while the internet is great and the ultimate resource for Life, The Universe and Everything, in general I prefer to get my information directly from other people.

Thinking about it, it seems to me that there could be a couple of possible reasons for this.

  1. Laziness – When the situation calls for it I will go and search the BeJaysus out of something until I’m satisifed with the answers, so that doesn’t seem to be it..
  2. Ease of access – there’s normally a better chance of getting information quickly from someone close by, particularly in a work context, but I will happily take my time and get specific items from specific people, and sometimes that can take a little time, so thats not it…
  3. Contextual/Added information – whereby the information gleaned from a particular person will have added relevance due to situational experience, etc.. Closer to a winner here…
  4. The personal touch – here we seem to have a winner. I like interacting with people. I’m a social beast, like most of the human race. I occasionally work from home and find the boredom to be stunning in the extreme, so I only do it when absolutely have to.

So it would seem that I like people. Todays instantly accessible information has given me direct access such as this, because in the past there wasn’t anywhere near as much generalised knowledge swirling around in both the aether and people’s head, so carefully lookup was needed to find information, meaning not as many did it.

The synopsis I draw from this (something other, much more clever people have figured out already ) is that the modern age with fingertip availability, social knowledge transfer, and the great swarm of data living in us all, is in fact yet another social enabler. People can interact even more now than ever before, and in new and interesting ways due to the magic of the tech and the evolution of society and societal memes.

Makes you happy to be knowledge foraging…

Interesting reading

Reblog this post [with Zemanta]

M882 – Section 6

January 15th, 2009 admin No comments

1. Legacy software is essential software that cannot be changed at the speed which the user organisation requires

From a management perspective this is true. From a developer perspective this is largely false. The developer will know that there are often times when you can develop system updates, new architectures, etc.. at a speed that will largely satisfy most people. The problem arises with the users/market. The market will not be ready for the latest and greatest a company has to offer in the beginning, and frequently this will continue until a certain software maturity has been reached. The cost and risk factors also play large roles here. Spending, when weighed up, contrasted with all of the relevant factors and so on, will usually fall back to “If it ain’t broke….”. It frequently just isn’t cost/risk effective to update to the cutting edge, when the investment for the dull hammer has already been made and still works just fine.

2. Unless work is applied to counteract the appearance of legacy symptoms, any business-critical software is likely to become a legacy system sooner or later

Basically this statement boils down to two items: it can be maintained, or it can be evolved. Maintenance will involve fixing little bits and pieces, keeping things ticking over. Evolution will take the existing processes, tacit or otherwise, and create a newer, leaner, meaner and keener beast out of it. Its the football equivalent of keeping a team chugging along with the same players because they get along ok, and nothings reeeeeeally broken… whereas evolving the tem with new players, new trining methods, new coach, etc… will make it a world class competitor.Wrapping legacy systems, acquiring FOSS, modular development; all of these things are good and will, but its down to corporate mentality as well.. willingness to change and evolve will be core here..

3. Wrapping legacy software and it’s integration with newer software should be considered when replacement is too risky or too expensive

I’d agree and disagree here. Yes, wrapping should be considered if absolutely necessary, but NOT at the risk of compromising the system – from my point of view this would mean not wrapping if there is a reasonable justification for re-engineering the system/process/whatever, extracting all of the lessons learned from the current implementation. There should be some sort of bias in the judging system towards a new implementation, obviously backward compatible with the old junk, but this should nearly always be the best option. Preserving the old stuff for the sake of it or for penny pinching, etc, is just wrong.

4. In COTS-based projects the requirements are limited, shaped and conditioned to what the COTS vendors can offer

5. Component-based development provides value through cost efficiencies and trhough the emergent properties of the integrated applications

6. There are still limitations to the wide use of components, including issues of reliability, risk, trust and lack of support for the future evolution of the component

7. Successful open source acquisition and deployment requires tapping into other diverse sources for support and this requires a more diverse approach than when depending on a single supplier

8. Acquisition of open source software can be primarily motivated by a cost reduction strategy and not by the availability of the source code

9. Outsourcing beefits from a number of economic and technical efficiencies. However, this option may lead to a client’s loss of control over the software

10. Advances in methods and process capability of software organisations expand the types of software activities that can offshored

11. Instead of owning or licensing the software to run on your machines, you can rent time using it at some service provider

12. Software acquisition as a service (e.g. web services) requires adequate resolution of issues of responsibility, trust, risk and security

13. Software provision does not end with the selection of a source and the acquisition of the software and its documentation

14. Software acqusition consequences go beyond the immediate decision: they may have far-reaching impact

M882 – Section 1: Software in the Information Society

January 14th, 2009 admin No comments

Summary Points – The itemised summary of Section 1 given in the course material. What I will do is list the summary points here and give a brief analysis, interpretation and example of same. I plan to do this for each section in the course, so a reasonable overview of the material will be produced.

1. Software may not have brought about the economic benefits nationally that we could have anticipated

One of the understatements of the century, no matter what perspective you look at it from. Software is generally touted as the all-singing all-dancing answer to all of life’s prayers, but frequently falls short of user/stakeholder expectations.  Coming from a developer’s point of view I can easily understand this. I know how my software works, the limitations and capabilities, technical caveats and so on, but a non technical person could have real trouble. “Why doesn’t it do this?”. “Because of XXXXXX”. “… Thats a bit rubbish isn’t it..?”.

An example given is of productivity vs investment in IT over time. Studies by Landauer and others show that there was a marked drop in productivity as more and more investment in IT rolled out, but doesn’t really give much more on it than that. One thing we can infer here is that if we can make the graph go the other way, i.e. productivity rising, then we can safely assume that correct methods of software design, production, and equally as importantly use, have set in.

2. Software can fail in service often with disastrous results

Also very true. In service here meaning any production environment. If software is not correctly designed, requirements not properly and systematically elicited, if production is sloppy, testing non-existant, and without input from all relevant stakeholders, then failure is assured.This is a no-brainer. It will happen, no ifs buts or maybes.

The example given is of the Therac Radiation machines, but I prefer this one: The great Zune fiasco of 2008. Whereby someone in Microsoft had coded a specialised calendar check into the Zune software, and basically forgot about the existence of such things as leap years. In this case I’m not (solely) blaming the coder, that snippet should have been reviewed ten ways form Sunday, especially considering there’s already a trolley load of date and time functions out there.

3. Software is important in the automation of clerical functions, justified by the saving of labour costs and the increased accuracy and reliability of results

No, really? Software is not important, its critical. Not just for the automation of tasks, but for the error checking that comes with this. One tired and bored clerical officer can do the same process for the same set of files 4/5 times and come out with different answers each time. Machines don’t have this problem. If the software is told how to do it right the first time, then it will do it right the first time, and the second, and the third…

Its not so much that the cost of is justified, more that is essential..

4. Software offers new opportunities for enterprises to deliver their services and products more effectively and more efficiently, and even create new products and services

This is true – in the modern world the average business or even home cottage industry type person can get themselves online and trading away with world wide exposure for about €100. And that includes the costs of the web hosting. Without the services built on software, they wouldn’t be of particular use, but them they are invaluable.

5. Stability cannot be relied upon – change is always with us, but has become more intense the advance of technology and the globalisation that accompanies it

This is a good thing rather than anything else – the more the market/industry/scene/whatever changes, the more we will see new and innovative ways of creating and using software, often in ways never dreamed of before. Software, automation, call it what you will, it has busted its way on to the scene and has now taken complete control. It is at the core of every business (or should be), and the world economy would collapse without it.

6. Rational and scientific approaches to developing software have their limits, limits that are matched in other areas of human activity and marked as postmodern

I consider this a bit of a contentious one – there is always a lot to be said for the human approach, etc, but at the end of the day it should still all boild down to a rational approach to your process. If your methods or results can’t be analysed in some way (and I’m including as yet uncovered methods of analysis here..) then I would think that it probably isn’t all that effective. I’m not a big believer in the “limited” idea.