Friday, May 31, 2013

Python Game: Blackjack

This week's game is Blackjack. Go play it here

# Blackjack
__author__ = 'RK'
import simplegui
import random

CARD_SIZE = (73, 98)
CARD_CENTER = (36.5, 49)
card_images = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/cards.jfitz.png")

CARD_BACK_SIZE = (71, 96)
CARD_BACK_CENTER = (35.5, 48)
card_back = simplegui.load_image("https://www.dropbox.com/s/75fcadgeewharzg/joker.jpg?dl=1")

# initialize some useful global variables
in_play = False
outcome = ""
score = 0

# define globals for cards
SUITS = ('C', 'S', 'H', 'D')
RANKS = ('A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K')
VALUES = {'A':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':10, 'Q':10, 'K':10}


# define card class
class Card:
    def __init__(self, suit, rank):
        if (suit in SUITS) and (rank in RANKS):
            self.suit = suit
            self.rank = rank
        else:
            self.suit = None
            self.rank = None
            print "Invalid card: ", suit, rank

    def __str__(self):
        return self.suit + self.rank

    def get_suit(self):
        return self.suit

    def get_rank(self):
        return self.rank

    def draw(self, canvas, pos):
        card_loc = (CARD_CENTER[0] + CARD_SIZE[0] * RANKS.index(self.rank),
                    CARD_CENTER[1] + CARD_SIZE[1] * SUITS.index(self.suit))
        canvas.draw_image(card_images, card_loc, CARD_SIZE, [pos[0] + CARD_CENTER[0], pos[1] + CARD_CENTER[1]], CARD_SIZE)

# define hand class
class Hand:
    def __init__(self):
        self.hand = []

    def __str__(self):
        s = ''
        for c in self.hand:
            s += str(c)
            s += " "
        return s

    def add_card(self, card):
        self.hand.append(card)

    def hit(self,deck):
        self.add_card(deck.deal_card())
        player.get_value()
        dealer.get_value()

    def get_value(self):
        """ count aces as 1, if the hand has an ace, then add 10 to hand value if it doesn't bust"""
        global in_play, message, score
        self.value = 0
        A = 0
        for card in self.hand:
            if card[1] == 'A':
                A += 1
            self.value += VALUES[card[1]]
        if A > 0 and self.value < 12:
            self.value += 10
        if self.value > 21:
            if in_play and (player.value > 21):
                message = "You lose! The computer wins!"
                score -= 1
            in_play = False
        return self.value


    def draw(self, canvas, pos):
        """draw a hand on the canvas, use the draw method for cards"""
        x = 0
        for card in self.hand:
            card = Card(self.hand[x][0], self.hand[x][1])
            card.draw(canvas, [x * 90 + 50, pos * 200])
            x += 1


# define deck class
class Deck:
    def __init__(self):
        self.deck = [(suit, rank) for suit in SUITS for rank in RANKS]
        self.shuffle()

    def shuffle(self):
        random.shuffle(self.deck)

    def deal_card(self):
        return self.deck.pop()


#define event handlers for buttons
def deal():
    global outcome, in_play,deck, hand, dealer, hand_total, player, message, score
    message = "Do you choose to Hit or Stand?"
    if in_play:
        score -= 1
        message = "That's cheating!"
    hand_total = 0
    deck = Deck()
    player = Hand()
    dealer = Hand()
    player.hit(deck)
    player.hit(deck)
    dealer.hit(deck)
    dealer.hit(deck)
    in_play = True


def hit():
    global player, in_play, message
    """if the hand is in play, hit the player"""
    player.get_value()
    if (player.value <= 21) and in_play:
        player.hit(deck)
        if player.value < 21:
            message = "OK. Do you want to Hit again or Stand?"
            """if busted, assign a message to outcome, update in_play and score"""
    else:
        message = "STOP. CLICKING. THAT."


def stand():
    global value, message, in_play, score
    if in_play == False:
        message = "STOP. CLICKING. THAT."
    else:
        player.value
        message = "Please wait! Computer is making its move..."
        timer.start()
    in_play = False

def dealercard():
    global score, message
    if dealer.value < 17:
        dealer.hit(deck)
    elif (player.value > dealer.value) or (dealer.value > 21):
        message = "You win. Congrats! Deal again?"
        score += 1
        timer.stop()
    else:
        message = "Computer Wins. Deal again?"
        score -= 1
        timer.stop()

# draw handler
def draw(canvas):
    global dealer, player, message, in_play, score
    scorestring = "Your points are: "
    scorestring += str(score)
    dealer.draw(canvas, 1)
    player.draw(canvas, 2)
    canvas.draw_text(message, [50, 185], 18, "Black")
    canvas.draw_text(scorestring, [480, 555], 14, "Yellow")
    canvas.draw_text("BlackJack Game", [480, 585], 18, "Black")
    if in_play:
        canvas.draw_image(card_back, CARD_BACK_CENTER, CARD_BACK_SIZE, (88, 249), (70, 94))

# initialization frame
frame = simplegui.create_frame("Blackjack", 600, 600)
frame.set_canvas_background("Gray")
timer = simplegui.create_timer(1000, dealercard)

#create buttons and canvas callback
frame.add_button("Deal", deal, 200)
frame.add_button("Hit",  hit, 200)
frame.add_button("Stand", stand, 200)
frame.set_draw_handler(draw)

# get things rolling
frame.start()
deck = Deck()
player = Hand()
dealer = Hand()
message = "BlackJack Game.                       Please hit Deal"

Thursday, May 30, 2013

A simple list manipulation - Computing primes using Sieve of Eratosthenes process

I am incredibly dumb that I had to wrestle with this problem for a long time before being able to solve it. But the experience has been invaluable.

The Problem:

Initialize n to be 1000. Initialize numbers to be a list of numbers from 2 to n, but not including n. With results starting as the empty list, repeat the following as long as numbers contains any numbers.
1. Add the first number in numbers to the end of results.
2. Remove every number in numbers that is evenly divisible by (has no remainder when divided by) the number that you
had just added to results.

How long is results?

The Solution (It is ugly!)

n  = 1000 
numbers = range(2, n)
results = []
while numbers:
    i = numbers[0]
    results.append(i)
    for number in numbers:
        if number % i == 0:
            numbers.remove(number)

print numbers
print len(results)


It looks like this computes the primes less than n, by a process known as Sieve of Eratosthenes. Below is another, more elegant and pythonic way to do it.

n = 1000
numbers = range(2, n)
results = []

while numbers != []:
    results.append(numbers[0])
    numbers = [n for n in numbers if n % numbers[0] != 0]

print len(results)

I was stuck with infinite loops with my original program before I stumbled upon pythontutor.org and saw the execution step by step. Below is the visualized execution of my program.



SQL Server: Storage internals, recovery model and log behavior

This is not a comprehensive post on SQL Server storage and internals, but we recently ran into an interesting issue. We were doing PCI scans on some of our servers for PCI compliance. There is a tool that scans each bit and byte inside the database and server and return a list of possible violations. Our developers identified data that needs to be removed in some legacy systems and they cleaned up the data by updating offending fields with blank values, deleting some tables altogether etc. But the scan tool would often find violations even after truncating/deleting data. Some of those databases were on simple and some were in FULL recovery mode and I had to explain how log backups, recovery and checkpoint affect the databases and I came up with this small tutorial.

Lets create a database to play with. Lets set that database in FULL recovery mode and create some data and see whats in the log.
CREATE DATABASE storagefun;
GO

ALTER DATABASE storagefun SET RECOVERY FULL
GO

A database with no data in it is no good. Lets create a table and see. I am going to define DEFAULTS just to save some time and effort while inserting records into that table. I'm just lazy:

USE storagefun
GO
 
CREATE TABLE CreditInfo 
(
id int identity,
name nvarchar(30) DEFAULT 'SQL Server is fun!',
ccnumber nvarchar(40) DEFAULT '1234-4567-7891-1023'
)

A full backup initiates an LSN chain, so lets do a FULL backup.
BACKUP DATABASE storagefun TO DISK = 'D:\SQLData\Backups\Storagefun.bak'

Lets check and try to find more details about our transaction log. There is a very useful DBCC command, LOGINFO which allows us to do that. Here is Paul Randal demonstrating the circular nature of the log using DBCC LOGINFO.

DBCC LOGINFO
GO

You should see some thing similar to the below image.



So there are a couple of VLFs (Virtual Log Files) and on one of them, the status is 2, which means 'Active'. Can we find more information? What is in those log files? Yes we can, using the undocumented function fn_dblog

SELECT
 [Previous LSN] ,
 [Current LSN] ,
 [Transaction ID] ,
 [Operation],
 [CONTEXT],
 [AllocUnitName] ,
 [Page ID],
 [Slot ID],
 [Offset in Row] ,
 [Transaction Name] ,
 [Begin Time],
 [End Time],
 [Number of Locks] ,
 [Lock Information] ,
 [RowLog Contents 0] ,
 [RowLog Contents 1] ,
 [RowLog Contents 2] ,
 [RowLog Contents 3] ,
 [RowLog Contents 4] ,
 [Log Record],
 [Log Record Fixed Length] ,
 [Log Record Length]
FROM fn_dblog (null,null)
GO

This will return a lot of data which may not make much sense to you at first. That's ok. We just created a table and there is no data in it. Let us insert some data and see how the log behaves.

INSERT INTO CreditInfo VALUES ( DEFAULT, DEFAULT);
GO 200

How does out VLF files look now?

DBCC LOGINFO
GO


Our VLF count has increased and now two VLFs are marked as Active. Let us insert some more records and see what happens to the log

INSERT INTO CreditInfo VALUES ( DEFAULT, DEFAULT);
GO 5000

DBCC LOGINFO
GO

Since we seem to have a lot of data, may be try and read the log and see if we can make sense of the output from fn_dlog function output. Lets use the query we used above, but only this time, we know we only ever dealt with the CreditInfo table. So lets narrow the scope of the results based on this.

SELECT
 [Previous LSN] ,
 [Current LSN] ,
 [Transaction ID] ,
 [Operation],
 [CONTEXT],
 [AllocUnitName] ,
 [Page ID],
 [Slot ID],
 [Offset in Row] ,
 [Transaction Name] ,
 [Begin Time],
 [End Time],
 [Number of Locks] ,
 [Lock Information] ,
 [RowLog Contents 0] ,
 [RowLog Contents 1] ,
 [RowLog Contents 2] ,
 [RowLog Contents 3] ,
 [RowLog Contents 4] ,
 [Log Record],
 [Log Record Fixed Length] ,
 [Log Record Length]
FROM fn_dblog (null,null)WHERE AllocUnitName LIKE '%CreditInfo%'

You'll notice the details of the operation we performed, LOP_INSERT_ROWS. So is that the actual data? Yes and no. Its not actual data in the sense of data in a data file. It is knowledge about what happened to that data for SQL Server's use. I had to demonstrate this to our devs because they were claiming that there is credit card info in the log files as per the scanning tool.



Coming back to log, observe how the log file grows and how most of the VLFs are in Active mode. This means they are currently being used and are not marked for reuse yet. We obviously dont want our log file to grow indefinitely. It needs to be cleared, right? So what clears a transaction log file when the database is in Full Recovery Mode? Two things- First, When a checkpoint has occurs since the last full backup AND a transaction log backup. Lets issue a manual CHECKPOINT and do a log backup and see what happens to our log.

CHECKPOINT
GO

BACKUP LOG storagefun TO DISK = 'D:\SQLData\storagefun_log.trn'
GO

What happened? All the VLFs are still there, but the log backup has cleared the transaction log and the existing virtual log files are marked as inactive. So they can be used again for any transactions in future. Now, try to read the log again and limit your scope to CreditInfo table.

SELECT
 [Previous LSN] ,
 [Current LSN] ,
 [Transaction ID] ,
 [Operation],
 [CONTEXT],
 [AllocUnitName] ,
 [Page ID],
 [Slot ID],
 [Offset in Row] ,
 [Transaction Name] ,
 [Begin Time],
 [End Time],
 [Number of Locks] ,
 [Lock Information] ,
 [RowLog Contents 0] ,
 [RowLog Contents 1] ,
 [RowLog Contents 2] ,
 [RowLog Contents 3] ,
 [RowLog Contents 4] ,
 [Log Record],
 [Log Record Fixed Length] ,
 [Log Record Length]
FROM fn_dblog (null,null) WHERE AllocUnitName LIKE '%CreditInfo%'
GO

Boom! there is nothing related to CreditInfo object. Didn't I tell you that the log backup cleared the transaction log?

But you can see that data in the data file. Use a simple select.

Ok, this is credit card data and one internet kitten will die for each row you keep in your database. Its vile. So lets get rid of it. After you truncate the table, will you find any information about it in the log file? Yes, you will. You'll see LOP_MODIFY_ROW operation.

TRUNCATE TABLE CreditInfo;

SELECT
 [Previous LSN] ,
 [Current LSN] ,
 [Transaction ID] ,
 [Operation],
 [CONTEXT],
 [AllocUnitName] ,
 [Page ID],
 [Slot ID],
 [Offset in Row] ,
 [Transaction Name] ,
 [Begin Time],
 [End Time],
 [Number of Locks] ,
 [Lock Information] ,
 [RowLog Contents 0] ,
 [RowLog Contents 1] ,
 [RowLog Contents 2] ,
 [RowLog Contents 3] ,
 [RowLog Contents 4] ,
 [Log Record],
 [Log Record Fixed Length] ,
 [Log Record Length]
FROM fn_dblog (null,null) WHERE AllocUnitName LIKE '%CreditInfo%'

The credit card scan utility still sees the data, we just truncated the table and still. Ok, lets do a log backup.

BACKUP LOG storagefun TO DISK  = 'D:\SQLData\storagefun_lon1.trn'

Read the log again

SELECT
 [Previous LSN] ,
 [Current LSN] ,
 [Transaction ID] ,
 [Operation],
 [CONTEXT],
 [AllocUnitName] ,
 [Page ID],
 [Slot ID],
 [Offset in Row] ,
 [Transaction Name] ,
 [Begin Time],
 [End Time],
 [Number of Locks] ,
 [Lock Information] ,
 [RowLog Contents 0] ,
 [RowLog Contents 1] ,
 [RowLog Contents 2] ,
 [RowLog Contents 3] ,
 [RowLog Contents 4] ,
 [Log Record],
 [Log Record Fixed Length] ,
 [Log Record Length]
FROM fn_dblog (null,null) WHERE AllocUnitName LIKE '%CreditInfo%'

Still see the records? How about a checkpoint

CHECKPOINT
GO

At this point, if you try to read again, you wont see any records related to CreditInfo and its completely gone. I was able to explain about FULL Recovery mode, nature of log using this example to our devs and I hope you find it useful too.

Wednesday, May 29, 2013

Python Classes and Objects

It took me 4 hours to figure out whats going on with classes and objects in Python and I am not even sure if I understand them completely yet. Yeah, I am dumb. Anyways - I was able to complete this 'Hello World' kind of program for calculating account balance and fees.

__author__ = 'RK Kuppala'

class BankAccount:
    def __init__(self, balance):
        """Creates an account with the given balance."""
        self.balance = balance
        self.counter = 0

    def withdraw(self, amount):
        """
        Withdraws the amount from the account.  Each withdrawal resulting in a
        negative balance also deducts a penalty fee of 5 dollars from the balance.
        """
        if self.balance - amount < 0:
            self.balance -= amount+5
            self.counter += 5
        else:
            self.balance -= amount

    def deposit(self, amount):
        """Deposits the amount into the account."""
        self.balance += amount

    def get_balance(self):
        """Returns the current balance in the account."""
        return self.balance

    def get_fees(self):
        """Returns the total fees ever deducted from the account."""
        return self.counter

#lets test if it works
my_account = BankAccount(5)
my_account.withdraw(15)
my_account.deposit(20)
my_account.withdraw(60)
my_account.deposit(20)
my_account.withdraw(60)

print my_account.get_balance(), my_account.get_fees()

Friday, May 24, 2013

Another simple Python game: Memory

This week's assignment is a simple and straight forward Memory game. You play with a set of cards facedown and you are allowed to flip and view two cards in one turn and if they both match, they remain opened. If they don't they go back to facedown mode and you use your memory to match the cards. You can play it here:

UPDATE: I was doing peer evaluation for this and I found one implementation which is better than mine. It uses classes. Check it here:

__author__ = 'RK Kuppala'
# implementation of card game - Memory
import simplegui
import random

num_list = []
exposed = []
state = 0
first_pick = 0
second_pick = 0
moves = 0

# helper function to initialize globals
def init():
    global num_list, exposed, moves
    moves = 0
    num_list = [i%8 for i in range(16)]
    random.shuffle(num_list)
    exposed = [False for i in range(16)]
    pass


# define event handlers
def mouseclick(pos):
    global state, first_pick, second_pick, moves
    this_pick = int(pos[0] / 50)
    if state == 0:
        first_pick = this_pick
        exposed[first_pick] = True
        state = 1
        moves += 1
    elif state == 1:
        if not exposed[this_pick]:
            second_pick = int(pos[0] / 50)
            exposed[second_pick] = True
            state = 2
            moves += 1
    elif state == 2:
        if not exposed[this_pick]:
            if num_list[first_pick] == num_list[second_pick]:
                pass
            else:
                exposed[first_pick] = False
                exposed[second_pick] = False
            first_pick = this_pick
            exposed[first_pick] = True
            state = 1
            moves += 1
    l.set_text("Moves = " + str(moves))
    pass


# cards are logically 50x100 pixels in size
def draw(canvas):
    offset = 50
    hor_pos = -25
    for i in range(len(num_list)):
        hor_pos += offset
        canvas.draw_text(str(num_list[i]), [hor_pos, 50], 30, "White")
    exposed_pos = -50
    for i in exposed:
        exposed_pos += offset
        if not i:
            canvas.draw_polygon([(exposed_pos, 0), (exposed_pos + 50, 0), (exposed_pos + 50, 100), (exposed_pos + 0, 100)], 10, "White", "Orange")

# create frame and add a button and labels
frame = simplegui.create_frame("Memory", 800, 100)
frame.add_button("Restart", init)
l=frame.add_label("Moves = 0")

# initialize global variables
init()

# register event handlers
frame.set_mouseclick_handler(mouseclick)
frame.set_draw_handler(draw)

# get things rolling
frame.start()

Saturday, May 18, 2013

Simple Python Game: Pong

Here goes this week's game. The classic Pong game. You can play this game on your browser here (don't try this on IE). Its a two player game. Player 1 can use 'w' and 's' keys and Player 2 can use ↑ and ↓. I would like to make this game working locally on Windows using tkinter. Let see

# Author: RK

import simplegui
import random

# initialize globals - pos and vel encode vertical info for paddles
WIDTH = 600
HEIGHT = 400       
BALL_RADIUS = 20
PAD_WIDTH = 8
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2

ball_pos = [WIDTH/2, HEIGHT/2]
ball_vel = [-random.randrange(60, 180) / 60, random.randrange(120, 240) / 60]
paddle1_pos = HEIGHT/2
paddle2_pos = HEIGHT/2

# helper function that spawns a ball by updating the 
# ball's position vector and velocity vector
# if right is True, the ball's velocity is upper right, else upper left
def ball_init(right):
    global ball_pos, ball_vel # these are vectors stored as lists
    ball_pos = [WIDTH/2,HEIGHT/2]
    ball_vel[1] = -random.randrange(60, 180)/60
    if right == True:
        ball_vel[0] = random.randrange(120, 240)/60
    else:
        ball_vel[0] = -random.randrange(120, 240)/60
    pass

def new_game():
    global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel
    global score1, score2
    paddle1_pos = HEIGHT/2
    paddle2_pos = HEIGHT/2
    paddle1_vel = 0
    paddle2_vel = 0
    score1 = 0
    score2 = 0
    ball_init(0 == random.randrange(0, 11) % 2)
    pass 

# define event handlers


def draw(c):
    global score1, score2, paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel, ball_pos, ball_vel
    # update paddle's vertical position, keep paddle on the screen
    if paddle1_pos < (HALF_PAD_HEIGHT) and paddle1_vel < 0:
        paddle_vel = 0
    if paddle2_pos < (HALF_PAD_HEIGHT) and paddle2_vel < 0:
        paddle2_vel = 0
    if paddle1_pos > (HEIGHT - (HALF_PAD_HEIGHT)) and paddle1_vel >0:
        paddle2_vel = 0
    if paddle2_pos > (HEIGHT - (HALF_PAD_HEIGHT)) and paddle2_vel > 0:
        paddle2_vel = 0
    paddle1_pos += paddle1_vel
    paddle2_pos += paddle2_vel
    # draw mid line and gutters
    c.draw_line([WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1, "White")
    c.draw_line([PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1, "White")
    c.draw_line([WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1, "White")
    # draw paddles
    c.draw_polygon([(0, paddle1_pos-HALF_PAD_HEIGHT), (0, paddle1_pos+HALF_PAD_HEIGHT), (PAD_WIDTH-2, paddle1_pos+HALF_PAD_HEIGHT),(PAD_WIDTH-2,paddle1_pos-HALF_PAD_HEIGHT)], PAD_WIDTH-1, "White","White")
    c.draw_polygon([(WIDTH, paddle2_pos-HALF_PAD_HEIGHT), (WIDTH, paddle2_pos+HALF_PAD_HEIGHT), (WIDTH-PAD_WIDTH+2, paddle2_pos+HALF_PAD_HEIGHT),(WIDTH-PAD_WIDTH+2,paddle2_pos-HALF_PAD_HEIGHT)], PAD_WIDTH-1, "White","White") 
    # update ball
    ball_pos[0] += ball_vel[0]
    ball_pos[1] += ball_vel[1]
    if ball_pos[1] >= (HEIGHT - BALL_RADIUS) or ball_pos[1] <= (BALL_RADIUS):
        ball_vel[1] = -ball_vel[1]
    if ball_pos[0] <= (PAD_WIDTH + BALL_RADIUS):
        if ball_pos[1] < (paddle1_pos - HALF_PAD_HEIGHT) or ball_pos[1] > (paddle1_pos + HALF_PAD_HEIGHT):
            ball_init(True)
            score2 += 1
        else:
            ball_vel[0] = -ball_vel[0] * 1.1
            
    if  ball_pos[0] >= (WIDTH - PAD_WIDTH - BALL_RADIUS):
        if ball_pos[1] < (paddle2_pos - HALF_PAD_HEIGHT) or ball_pos[1] > (paddle2_pos + HALF_PAD_HEIGHT):
            ball_init(False)
            score1 += 1
        else:
            ball_vel[0] = -ball_vel[0] * 1.1        
    # draw ball and scores
    c.draw_circle(ball_pos, BALL_RADIUS, 2, "Yellow", "White")
    c.draw_text(str(score1), (170, 50), 36, "Yellow")
    c.draw_text(str(score2), (400, 50), 36, "Yellow")
    
def keydown(key):
    global paddle1_vel, paddle2_vel
    if key == simplegui.KEY_MAP['w']:
        paddle1_vel = -4
    elif key == simplegui.KEY_MAP['s']:
        paddle1_vel = 4
    elif key == simplegui.KEY_MAP['up']:
        paddle2_vel = -4
    elif key == simplegui.KEY_MAP['down']:
        paddle2_vel = 4
        
def keyup(key):
    global paddle1_vel, paddle2_vel
    if key == simplegui.KEY_MAP['w']:
        paddle1_vel = 0
    elif key == simplegui.KEY_MAP['s']:
        paddle1_vel = 0
    elif key == simplegui.KEY_MAP['up']:
        paddle2_vel = 0
    elif key == simplegui.KEY_MAP['down']:
        paddle2_vel = 0

# create frame
frame = simplegui.create_frame("Pong", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)

# start frame
frame.start()
new_game()

Thursday, May 16, 2013

Step By Step: SQL Server 2012 AlwaysOn Availability Groups Lab Setup Using VirtualBox

I was inspired to write this post by the super awesome DBA, Jonathan Kehayias of sqlskills. He has a great series of articles on setting up a home lab using virtualbox and evaluation software from Microsoft available as free downloads. Check out his articles on sqlskills.

If you are on this page and reading this, chances are that you already know what AlwaysOn is so I am not going to explain it again.For a quick overview of this new High availability/disaster recovery solution, go read this article. Now lets get started with building our lab.

What do you need?

In order to follow this tutorial, you need the following

The latest version of VirtualBox
Windows server 2008 R2 with sp1, evaluation edition
SQL Server 2012 Evaluation edition

Coming to the hardware, you need a decent laptop/desktop with 8 GB RAM and a good processor (may be core i5). You can try with lesser RAM too, but things will be a little slow. You need at least 4 VMs to test a basic setup of AlwaysOn. The server that acts as a domain controller can not be a part of availability groups. Don't worry about storage for all these VMs, because we are going to use linked clones that make use of resources from a base VM.

Saturday, May 11, 2013

A not so exciting game in Python: Stop Watch

Another week and another assignment. The game itself is not very exciting. You can start and stop the timer, every start is an attempt and every stop exactly at 0 is a win.

Thursday, May 9, 2013

Visual Fox Pro Hell: fpt file missing or invalid (memo file corruption)

I know, its 2013 and nobody should be dealing with Visual Fox Pro 6.0 databases, but one of the clients I support has a legacy system that uses foxpro databases. We have an SSIS job that pulls data everyday from `foxpro` and it recently started failing with the error, `person.fpt is missing or invalid`, I initially thought it was a network issue but the frequency of the failure increased and one fine day it stopped working at all. Lesson - don't wait for it to break completely. Because some day it will. So I naturally started googling and that was a time travel back to the ancient kingdoms of the internet. Microsoft's resources didn't help much, and I had to deal with shareware, freeware software that promise `.dbf` and `.fpt` repair as soon as you pay, help forums with no answers and annoying browser addons etc. After trying a lot of demo software I thought may be its just the `.fpt` file that needs rebuilding. So going though the documentation I thought I'd make a copy of this database and see if it rebuilds `.fpt` file and fortunately, it worked!

Wednesday, May 1, 2013

Game: Guess the number!

I have recently started learning Python from an online course and we had this course assignment to program this game. I am avoiding the name of the course and the name of the online resource on purpose because I don't want this show up on Google results. I'm just childishly happy that I wrote something and I wanted to save it here. This code may not work as is, because it uses some modules that are not part of standard python installations. After writing it in Python, I tried to do it on Powershell too and it kind of worked.