Home – PullMonkey Blog http://pullmonkey.com Tue, 29 Nov 2011 03:53:36 +0000 en-US hourly 1 https://wordpress.org/?v=5.6 USB drive disconnecting and reconnecting randomly http://pullmonkey.com/2011/01/05/usb-drive-disconnecting-and-reconnecting-randomly/ Wed, 05 Jan 2011 00:27:26 +0000 http://pullmonkey.com/?p=57559 It was very strange, I got a new 2 TB external USB drive for Christmas and I noticed a number of windows (nautilus windows) opening up throughout the night.  So I would wake up to find 20 - 30 windows opened to the media mount directory (/media).  Overtime and watching the logs, I noticed that the new USB drive was disconnecting itself and then reconnecting.  As it would reconnect and mount, the new mount point /media/<some long character string> would pop open in a  nautilus window.  When the drive would eventually disconnect, the opened nautilus window would no longer have access to the data and would display contents from one directory up (/media).  After a couple days I finally found the answer and tried it and it worked as advertised.

For those having the same problem, this is where I found the solution you see below.

$ sudo sdparm --clear STANDBY -6 /dev/sdb
# note that your device could be something else, for example - /dev/sd<something>

And if you get an error, something like this:

change_mode_page: failed fetching page: Power condition

Then you should be able to use hdparm instead, like this:

sudo hdparm -S 0 /dev/sdb
]]>
Open Flash Chart II – fully automated http://pullmonkey.com/2009/04/30/open-flash-chart-ii-fully-automated/ http://pullmonkey.com/2009/04/30/open-flash-chart-ii-fully-automated/#comments Thu, 30 Apr 2009 16:33:00 +0000 /2009/04/30/open-flash-chart-ii-fully-automated Just as an attention grabber - we are going after this example in this article:

Keeping up

Ok, seeing that the php versions of open flash chart and open flash chart swf files continually change along with with the API (not saying this is a bad thing), I wanted to come up with an even more abstract solution. The goal is to not have to worry when the swf file is released with the latest set of graphs or changes its API. I simply don't want to worry about this method or that method, or this class or that class.

Feedback

This article will sort of act as a tutorial for those interested in metaprogramming and as a set of instructions for those looking to experiment with the latest version of the OFC II Rails Plugin that I am currently toying with. I would like to hear feedback, but just remember that phase 1 of this release will be very basic, meaning none of the ajaxy stuff. It will come, just not yet.

Let's see what we can get away with

I am already using method_missing() for pretty much everything in the OFC II Rails Plugin that is being used now. But every time new classes are added, I have to sit down and basically convert the php class to ruby - just plain tedious, not really what I had planned when I started all this. Ok, so method_missing() was great, but let me introduce (or possibly reintroduce) you to const_missing(), basically method_missing() but instead of methods, we can create classes or modules or other objects on the fly. This will definitely help when the php version gets a new class. Instead of getting hounded to update the rails version to be 100% like the php version, everything will just work, no updates to code required. Well, we hope ! So check this out:

Here is what we did with method_missing():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

module OFC
  class Base
    def method_missing(method_name, *args, &blk)
      case method_name.to_s
      when /(.*)=/   # i.e., if it is something x_legend=
        # if the user wants to set an instance variable then let them
        # the other args (args[0]) are ignored since it is a set method
        self.instance_variable_set("@#{$1}", args[0])
      when /^set_(.*)/
        # backwards compatible ... the user can still use the same set_y_legend methods if they want
        self.instance_variable_set("@#{$1}", args[0])
      else
          if inst = self.instance_variable_get("@#{method_name}")
            inst
          else
            # if the method/attribute is missing and it is not a set method then hmmmm better let the user know
            super
          end
      end
    end
  end
end

This just basically allows me to do this:

1
2
3
4
5
6
7
8
9
10
11
12
13

  class Foo < OFC::Base
  end

  foo = Foo.new

  foo.some_random_attribute = "Hello"  #=> "Hello"
  foo.some_random_attribute  #=> "Hello"
  foo.some_random_undefined_attribute  #=> Method Missing error (calls super)

  # too be like php, for easier conversion
  foo.set_some_random_attribute("Good Bye")  #=> "Good Bye"
  foo.some_random_attribute  #=> "Good Bye"

Along the same lines, I have created an initialize method that takes any argument hash of variable/value pairs and calls variable=() which is handled by method missing as we saw above:

1
2
3
4
5
6
7
8

  class Foo < OFC::Base
  end

  foo = Foo.new(:x_axis => 5, :min => 10, :max => 90, :steps => 5, :elements => ["one", "two"])
  
  foo.x_axis #=> 5
  foo.min #=> 10

Ok, so on to const_missing() and what we can do with that:

1
2
3
4
5
6

  def OFC.const_missing(const)
    klass = Class.new OFC::Base
    Object.const_set const, klass
    return klass
  end

This says that any undefined (missing) constant of OFC should be defined as a new class that inherits from OFC::Base.

So when we say OFC::Foo, that has not been defined, so we will get back class OFC::Foo < OFC::Base;end; which will give us the initialize() method and method_missing() method from above. Let's see how this works:

1
2
3
4
5
6
7
8
9
10
11

  line = OFC::Line.new(:values => [1,2,3,nil,nil,5,6,7])
  line.values #=> [1,2,3,nil,nil,5,6,7]
  line.some_random_variable = "Hello" #=> "Hello"
  line.some_random_variable #=> "Hello"

  stacked_bar_chart = OFC::BarStack.new
  stacked_bar_chart.values = []
  stacked_bar_chart.values << [2,3,4]
  stacked_bar_chart.values << [5, {"val" => 5, "colour" => "#ff0000"}]
  stacked_bar_chart.keys = [{ "colour" => "#C4D318", "text" => "Kiting", "font-size" => 13 } ...]

So it all sort of came together right there. I've shown you all the code that comes with the Rails Open Flash Chart plugin now. No more definining idividual classes, no more trying to keep up with the never ending php version, and no more late nights converting php to ruby (!). About dang time.

Ok, but this is just the beginning, nothing has been set in stone, so like I said, give me your feedback, what works for you and what does not. And, hopefully, I will have solutions for you or you for me.

Example with new version (test version)

I am using rails 2.3.2, but I don't think it will matter what version you are using.

Create your new rails project

1
2
3
4
5

# create a new rails project 
> pullmonkey$ rails testing_it
#<Bunch of stuff is created ....>
> pullmonkey$ cd testing_it/

Install the plugin from the test branch

Note the -r test in this next step. The new version (test version) I am playing with is under the test branch and -r says what branch to pull from.

Also, you can use git:// instead of http:// below, but depending on your firewall restrictions http:// will probably work out best for you.

1
2
3

> pullmonkey$ ./script/plugin install http://github.com/pullmonkey/open_flash_chart.git -r test
# <Bunch more stuff ...>

Create a controller to play in

1
2
3

> pullmonkey$ ./script/generate controller test_it
# <And more stuff >

Get our assets

1
2
3
4
5
6
7

# first we will get swfobject.js
> pullmonkey$ cp vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js public/javascripts/
# next the open flash chart swf (GET whatever is the latest version), right now that is here: http://teethgrinder.co.uk/open-flash-chart-2/open-flash-chart.swf
> pullmonkey$ cd public/
> pullmonkey$ wget http://teethgrinder.co.uk/open-flash-chart-2/open-flash-chart.swf
> pullmonkey$ cd ..

Edit our controller

Notice here that I just include one of the many examples from the plugin's examples directory. Definitely more to follow.

One thing you will notice about the examples, is that the php code is in the comments, so you can see how I would convert from the php examples to ruby. Please feel free to add your own examples, just fork the project.

1
2
3
4
5
6
7
8
9
10

> pullmonkey$ vi app/controllers/test_it_controller.rb
# mine looks like this:
class TestItController < ApplicationController
  include OFC::Examples::AreaHollow

  def index
    @graph = open_flash_chart_object(600,300, "/test_it/area_hollow")
  end
end

Edit our view

1
2
3
4
5

> pullmonkey$ vi app/views/test_it/index.html.erb
# mine looks like this:
<%= javascript_include_tag 'swfobject' %>
<%= @graph %>

Start 'er up

1
2
3
4
5

> pullmonkey$ ./script/server

# browse to the test_it index
http://localhost:3000/test_it

Our example

]]>
http://pullmonkey.com/2009/04/30/open-flash-chart-ii-fully-automated/feed/ 8
Spreadsheet Gem – data may have been lost http://pullmonkey.com/2009/04/30/spreadsheet-gem-data-may-have-been-lost/ http://pullmonkey.com/2009/04/30/spreadsheet-gem-data-may-have-been-lost/#comments Thu, 30 Apr 2009 14:48:00 +0000 /2009/04/30/spreadsheet-gem-data-may-have-been-lost I've been using the spreadsheet gem lately for a couple projects I am working on to modify existing spreadsheets. I have quite often stumbled upon this error when opening modified spreadsheets in excel:

File error: data may have been lost

Like most microsoft errors, it was useless and the spreadsheet came up just fine. But that error was just so annoying, other spreadsheet applications (open office, excel on mac) opened without any problems. So after quite a bit of hacking and digging around, I finally tried setting the encoding, which defaults to UTF-8. Well it just so happens that the spreadsheet being modified was encoded with UTF-16LE.

So part one of my solution became this:

1
2

Spreadsheet.client_encoding = 'UTF-16LE'

Then doing a little more digging I decided that this would be a better long-term solution:

1
2
3

book = Spreadsheet.open spreadsheet_file
Spreadsheet.client_encoding = book.encoding

Well, hopefully it wasn't just me and someone will be able to save a bit of time with this.

]]>
http://pullmonkey.com/2009/04/30/spreadsheet-gem-data-may-have-been-lost/feed/ 1
Can you read this? http://pullmonkey.com/2009/04/17/can-you-read-this/ Fri, 17 Apr 2009 01:41:00 +0000 /2009/04/17/can-you-read-this Got an email today, I have seen it before and I am sure it has been going around for years. This time, I thought that I would do an exercise and create a plugin that duplicates what I found in this email. See for yourself.

Here is the email I got:

What I gathered was that the only important letters are the first and last letter of each word, those have to be in the right order. So the rest of the letters can be in any random order. That is what I did - I created a plugin and put it out on github. You can install it like this:


./script/plugin install http://github.com/pullmonkey/can_you_read_this.git

And use it like this:


#in your views
<%= can_you_read_this("hello, can you read this?") %>

Have fun.

]]>
ECE231 – Spring 2009 – Programming Assignment 4 http://pullmonkey.com/2009/04/14/ece231-spring-2009-programming-assignment-4/ Tue, 14 Apr 2009 00:02:00 +0000 /2009/04/14/ece231-spring-2009-programming-assignment-4 This is a step-by-step tutorial for this assignment and an explanation of the basics of how it works for those that are having a difficult time understanding or just are stuck somewhere. To view the assignment click here.

So for this assignment we are only going to be doing input and output. So the only header file we need is the iostream library.

1
2
3
4

#include <iostream>
using namespace std;

Defining the Node Class

For the node class we need 5 private variables: type, value, node1, node2, next, a constructor, 5 member functions, and a friend class.

Because most of the functions only return a single variable it would be a waste to have the functions outside the class so I put them all inside the class.

So here is what your class should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

class node
{
  protected:
    int type;     // type of component
    double value; // value of the component
    int node1;    // first node of the component
    int node2;    // second node of the component
    node *next;   // pointer to the next node in list
  public:
    node(int a, double b, int c, int d)
    {
      type  = a;
      value = b;
      node1 = c;
      node2 = d;
    }

    int getType() { return type; }
    double getValue() { return value; }
    int getNode1() { return node1; }
    int getNode2() { return node2; }
    node *getNext() { return next; }

    friend class circuit;
};

Defining the Circuit Class

For the circuit class we need 2 private variables: first and last, a constructor, a copy constructor, 6 member functions, and a friend function.

For these I will put most of the functions on the outside of the class.

So here is what your class should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

class circuit
{
  protected:
    node *first; // pointer to first node in list
    node *last;  // pointer to last node in list
    node *getNode(int & , double & , int & , int & );
  public:
    circuit();
    circuit(const circuit & );
    ~circuit();

    void insert(int , double , int , int );
    void insertInFront(node * );
    void insertInBack(node * , node * );
    void insertInMiddle(node * , node * , node * );
    bool remove(int , int );
    bool isEmpty();

    friend ostream & operator << (ostream & , circuit );
};

Writing the Actual Functions for the Circuit Class

First, we have the private function getNode. This function creates a new member of the node class and returns the address to it.

1
2
3
4
5
6
7
8

node* circuit::getNode(int &t, double &v, int &n1, int &n2)
{
  node *temp = new node(t, v, n1, n2);
  assert( temp != 0 );
  return temp;
}

Second, we have the a constructor, a copy constructor, and a class destructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

circuit::circuit()
{
  first = last = 0;
}
circuit::circuit(const circuit &c)
{
  first = last = 0;
  node *nc = c.first;
  while(nc != 0)
  {
    insert(nc->type, nc->value, nc->node1, nc->node2);
    nc = nc->next;
  }
}
circuit::~circuit()
{
  if( !isEmpty() )
  {
    node *nc = first;
    node *temp;
    while(nc != 0)
    {
      temp = nc;
      nc = nc->next;
      delete temp;
    }
  }
}

Next, we have the 6 member functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

void circuit::insert(int t, double v, int n1, int n2)
{
  node *newNode = getNode(t, v, n1, n2);
  node *nc = first;
  node *nc_next = first;
  if(isEmpty())
  {
    first = last = newNode;
    newNode->next = 0;
  }
  else if(first == last)
  {
    if(newNode->node1 < first->node1)
      insertInFront(newNode);
    else if(newNode->node1 > first->node1)
      insertInBack(newNode, first);
    else // if newNode->node1 == first->node1
    {
      if(newNode->node2 < first->node2)
        insertInFront(newNode);
      else
        insertInBack(newNode, first);
    }
  }
  else
  {
    while(nc->next != 0)
    {
      if(newNode->node1 < nc_next->node1)
      {
        if(nc_next == first)
          insertInFront(newNode);
        else
          insertInMiddle(newNode, nc, nc_next);
        break;
      }
      if(newNode->node1 == nc_next->node1)
      {
        if(newNode->node2 <= nc_next->node2)
        {
          if(nc_next == first)
            insertInFront(newNode);
          else
            insertInMiddle(newNode, nc, nc_next);
          break;
        }
      }
      if(newNode->node1 >= nc_next->node1 and nc_next == last)
      {
        insertInBack(newNode, nc_next);
        break;
      }
      nc = nc_next;
      nc_next = nc->next;
    }
  }
}
void circuit::insertInFront(node *n)
{
  n->next = first;
  first = n;
}
void circuit::insertInBack(node *n, node *p)
{
  p->next = last = n;
  n->next = 0;
}
void circuit::insertInMiddle(node *cn, node *p , node *n)
{
  p->next = cn;
  cn->next = n;
}
bool circuit::remove(int n1, int n2)
{
  node *nc = first;
  node *nc_next = first;
  node *temp;
  if( isEmpty() )
    return false;
  while (nc_next != 0)
  {
    if(nc_next != 0 and nc_next->node1 == n1 and nc_next->node2 == n2)
    {
      temp = nc_next;
      nc->next = nc_next->next;
      if(first == last)
        first = last = 0;
      if(nc_next == first)
        first = temp->next;
      if (nc_next == last)
        last = nc;
      delete nc_next;
      return true;
    }
    nc = nc_next;
    nc_next = nc->next;
  }
  return false;
}
bool circuit::isEmpty()
{
  return ( first == 0 and last == 0 );
}

Last, we have a friend function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

ostream & operator << (ostream &os, circuit c)
{
  node *nc = c.first; // node count variable used for looping through list
  int lcv = 1; // loop control variable
  cout << "First: " << c.first << "  Last: " << c.last << endl;
  while (nc != 0)
  {
    os << lcv << ". "
       << "node1: "   << nc->getNode1() 
       << "  node2: " << nc->getNode2()
       << "  type: "  << nc->getType() 
       << "  value: " << nc->getValue() 
       << "  next: "  << nc->getNext() 
       << endl;
    nc = nc->getNext();
    lcv++;
  }
  if(c.first == 0)
    os << "List is empty" << endl;
  return os;
}

Testing your program

Our teacher gave us a test program, however I expanded it a little bit to test a bit more fully.

So here is my test program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

#include <iostream>
#include "yourprogramname.h"
using namespace std;

const int M=7;
const int R=2;

int main()
{
  circuit c, c2, c3;
  int d[M*3] = {1,1,4, 1,1,3, 2,2,3, 1,1,2, 1,5,6, 1,2,5, 3,1,3};
  double v[M] = {10.5, 30.7, 100.4, 20.6, 35.5, 45.9, 60.8};
  int d1[R*8] = {1,2, 5,6, 3,6, 1,4, 1,3, 2,5, 2,3, 1,3};
  int i, j;

  for( i=0,j=0; i<M; i++,j=j+3 )
  {
    cout << i+1 << endl;
    cout << "Inserting new node into list with:" << endl;
    cout << "node1: "   << d[j+1]
         << "  node2: " << d[j+2]
         << "  type: "  << d[j]
         << "  value: " << v[i]
         << endl;
    c.insert( d[j], v[i], d[j+1], d[j+2] );
    cout << "List: " << endl;
    cout << c << endl << endl;
  }
  for( i=0; i<R*8; i=i+2 )
  {
    cout << "Removing node with:" << endl;
    cout << "node1: "   << d1[i]
         << "  node2: " << d1[i+1]
         << endl;
    if( c.remove( d1[i], d1[i+1] ) == false )
      cout << "Node not found" << endl;
    cout << "List: " << endl;
    cout << c << endl << endl;
  }

  cout << "nnMaking List #2:" << endl;
  int d2[M*3] = {2,2,4, 1,1,3, 2,2,3, 1,1,2, 1,5,6, 1,2,5, 3,1,3};
  for( i=0,j=0; i<M; i++,j=j+3 )
  {
    cout << i+1 << endl;
    cout << "Inserting new node into list with:" << endl;
    cout << "node1: "   << d2[j+1]
         << "  node2: " << d2[j+2]
         << "  type: "  << d2[j]
         << "  value: " << v[i]
         << endl;
    c2.insert( d2[j], v[i], d2[j+1], d2[j+2] );
    cout << "List: " << endl;
    cout << c2 << endl << endl;
  }

  cout << "nnMaking List #3:" << endl;
  int d3[M*3] = {2,2,4, 3,3,3, 2,2,3, 1,1,2, 1,5,6, 1,2,5, 3,1,3};
  for( i=0,j=0; i<M; i++,j=j+3 )
  {
    cout << i+1 << endl;
    cout << "Inserting new node into list with:" << endl;
    cout << "node1: "   << d3[j+1]
         << "  node2: " << d3[j+2]
         << "  type: "  << d3[j]
         << "  value: " << v[i]
         << endl;
    c3.insert( d3[j], v[i], d3[j+1], d3[j+2] );
    cout << "List: " << endl;
    cout << c3 << endl << endl;
  }

  return 0;
}

]]>
ECE231 – Spring 2009 – Programming Assignment 3 http://pullmonkey.com/2009/03/26/ece231-spring-2009-programming-assignment-3/ http://pullmonkey.com/2009/03/26/ece231-spring-2009-programming-assignment-3/#comments Thu, 26 Mar 2009 18:05:00 +0000 /2009/03/26/ece231-spring-2009-programming-assignment-3 This is a step-by-step tutorial for this assignment and an explanation of the basics of how it works for those that are having a difficult time understanding or just are stuck somewhere. To view the assignment click here.

So for this assignment we are going to be doing a lot of math calculations so we are going to need the include the both the iostream and the cmath libraries. We will also need the value of pi.

1
2
3
4
5
6
7
8
9

#include <iostream>
#include <cmath>
using namespace std;

#define PI 3.141592654
or
const double PI = 3.141592654;

Defining the Complexn Class

For the complexn class we need 2 private variables r and i, 3 constructors, a copy constructor, 4 member functions, 9 overloaded opperators, and 2 friend functions.

Like the previous program we will define everything with in the class and have the actual functions at the bottom.

So here is what your class should look like (keep in mind that this all goes at the top before the main function):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

class complexn
{
  private:
    double r; // real part of the complex number
    double i; // imaginary part of the complex number
  public:
    complexn();
    complexn(double );
    complexn(double , double );
    complexn(const complexn & );

    double complexabs();
    double complexangle();
    complexn complexconj();
    double distance(const complexn & );

    complexn operator + (const complexn & );
    complexn operator - (const complexn & );
    complexn operator * (const complexn & );
    complexn operator / (const complexn & );
    complexn operator = (const complexn & );

    complexn operator ++ ();
    complexn operator ++ (int );
    complexn operator -- ();
    complexn operator -- (int );

    friend ostream & operator << (ostream & , const complexn & );
    friend istream & operator >> (istream & , complexn & );
};

Writing the Actual Functions for the Complexn Class

First we have the 3 constructors and the copy constructor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

// takes no arguments and sets r and i to 0.0
complexn::complexn()
{
  r = i = 0.0;
}
// takes 1 argument and sets r to the argument and i to 0.0
complexn::complexn(double real)
{
  r = real;
  i = 0.0;
}
// takes 2 arguments and sets r to the first and i to the second
complexn::complexn(double real, double imag)
{
  r = real;
  i = imag;
}
// this is a copy constructor that dereferences the complexn variable if it is referenced
complexn::complexn(const complexn &c)
{
  r = c.r;
  i = c.i;
}

Next, we have the 3 member functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// takes no arguments and returns the distance from the 0 as a double
double complexn::complexabs()
{
  return sqrt(pow(r,2.0) + pow(i,2.0));
}
// takes no arguments and returns the angle of the complex point as a double in radians
double complexn::complexangle()
{
  double angle; // angle of coordinate from positive x axis
  angle = atan(r / i);
  if(r < 0 and i >= 0)
    return PI - abs(angle);
  if(r < 0 and i < 0)
    return -(PI - abs(angle));
  return angle;
}
// takes no arguments and returns the conjugate of the complex number as a complexn class
complexn complexn::complexconj()
{
  complexn temp = *this; // complex number used for calculations
  temp.i *= -1;
  return temp;
}
// takes one complexn type argument and returns the distance between the argument and the current instance
double complexn::distance(const complexn &temp)
{
  return sqrt(pow(temp.r -r, 2.0) + pow(temp.i - i, 2.0));
}

Next, we have the 9 overloaded operators:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

complexn complexn::operator + (const complexn &temp)
{
  complexn cn; // complex number used for calculations
  cn.r = r + temp.r;
  cn.i = i + temp.i;
  return cn;
}
complexn complexn::operator - (const complexn &temp)
{
  complexn cn; // complex number used for calculations
  cn.r = r - temp.r;
  cn.i = i - temp.i;
  return cn;
}
complexn complexn::operator * (const complexn &temp)
{
  complexn cn; // complex number used for calculations
  cn.r = r * temp.r - i * temp.i;
  cn.i = r * temp.i + i * temp.r;
  return cn;
}
complexn complexn::operator / (const complexn &temp)
{
  complexn cn; // complex number used for calculations
  cn.r = (r * temp.r + i * temp.i) / (pow(temp.r, 2.0) + pow(temp.i, 2.0));
  cn.i = (i * temp.r - r * temp.i) / (pow(temp.r, 2.0) + pow(temp.i, 2.0));
  return cn;
}
complexn complexn::operator = (const complexn &temp)
{
  r = temp.r;
  i = temp.i;
  return *this;
}
complexn complexn::operator ++ ()
{
  r += 1;
  return *this;
}
complexn complexn::operator ++ (int x)
{
  complexn temp = *this;
  r += 1;
  return temp;
}
complexn complexn::operator -- ()
{
  r -= 1;
  return *this;
}
complexn complexn::operator -- (int x)
{
  complexn temp = *this;
  r -= 1;
  return temp;
}

Last, we have the 2 friend functions:

1
2
3
4
5
6
7
8
9
10
11
12

ostream & operator << (ostream &os, const complexn &temp)
{
  os << temp.r << " + " << temp.i << "i";
  return os;
}
istream & operator >> (istream &is, complexn &temp)
{
  is >> temp.r >> temp.i;
  return is;
}

Testing Your program

I wrote a fairly good program for testing this complexn class.

To test your program copy your program to [name].h file and in the main.cpp file change the header file at the top to match your file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

#include <iostream>
#include "yourprogram.h" // the name of your comlexn header file goes here

using namespace std;

int main()
{
  complexn c1;
  complexn c2(1);
  complexn c3(3, -5);
  complexn c4, c5, c6;

  cout << "Complex Numbers: " << endl;
  cout << "  C1: " << c1 << endl;
  cout << "  C2: " << c2 << endl;
  cout << "  C3: " << c3 << endl;

  cout << "nEnter values for C1: ";
  cin >> c1;
  cout << "  You enetered: " << c1 << endl;
  cout << "Enter values for C2: ";
  cin >> c2;
  cout << "  You enetered: " << c2 << endl;
  cout << "Enter values for C3: ";
  cin >> c3;
  cout << "  You enetered: " << c3 << endl;

  cout << "nDistances from origin: " << endl;
  cout << "  C1(" << c1 << "): " << c1.complexabs() << endl;
  cout << "  C2(" << c2 << "): " << c2.complexabs() << endl;
  cout << "  C3(" << c3 << "): " << c3.complexabs() << endl;

  cout << "nConjugates:" << endl;
  cout << "  C1(" << c1 << "): " << c1.complexconj() << endl;
  cout << "  C2(" << c2 << "): " << c2.complexconj() << endl;
  cout << "  C3(" << c3 << "): " << c3.complexconj() << endl;

  cout << "nDistances between:" << endl;
  cout << "  C1(" << c1 << ") and C2(" << c2 << "): " << c1.distance(c2) << endl;
  cout << "  C1(" << c1 << ") and C3(" << c3 << "): " << c1.distance(c3) << endl;
  cout << "  C2(" << c2 << ") and C3(" << c3 << "): " << c2.distance(c3) << endl;

  cout << "nAddition:" << endl;
  cout << "  C1(" << c1 << ") + C2(" << c2 << "): " << c1 + c2 << endl;
  cout << "  C1(" << c1 << ") + C3(" << c3 << "): " << c1 + c3 << endl;
  cout << "  C2(" << c2 << ") + C3(" << c3 << "): " << c2 + c3 << endl;

  cout << "nSubtraction:" << endl;
  cout << "  C1(" << c1 << ") - C2(" << c2 << "): " << c1 - c2 << endl;
  cout << "  C1(" << c1 << ") - C3(" << c3 << "): " << c1 - c3 << endl;
  cout << "  C2(" << c2 << ") - C3(" << c3 << "): " << c2 - c3 << endl;

  cout << "nMultiplication:" << endl;
  cout << "  C1(" << c1 << ") * C2(" << c2 << "): " << c1 * c2 << endl;
  cout << "  C1(" << c1 << ") * C3(" << c3 << "): " << c1 * c3 << endl;
  cout << "  C2(" << c2 << ") * C3(" << c3 << "): " << c2 * c3 << endl;

  cout << "nDivision:" << endl;
  cout << "  C1(" << c1 << ") / C2(" << c2 << "): " << c1 / c2 << endl;
  cout << "  C1(" << c1 << ") / C3(" << c3 << "): " << c1 / c3 << endl;
  cout << "  C2(" << c2 << ") / C3(" << c3 << "): " << c2 / c3 << endl;

  cout << "nIncrementing:" << endl;
  cout << "  C1 =  " << c1   << endl;
  cout << "  C1++: " << c1++ << endl;
  cout << "  C1 =  " << c1   << endl;
  cout << "  ++C1: " << ++c1 << endl;
  cout << "  C1 =  " << c1   << endl;

  cout << "  C2 =  " << c2   << endl;
  cout << "  C2++: " << c2++ << endl;
  cout << "  C2 =  " << c2   << endl;
  cout << "  ++C2: " << ++c2 << endl;
  cout << "  C2 =  " << c2   << endl;

  cout << "  C3 =  " << c3   << endl;
  cout << "  C3++: " << c3++ << endl;
  cout << "  C3 =  " << c3   << endl;
  cout << "  ++C3: " << ++c3 << endl;
  cout << "  C3 =  " << c3   << endl;

  cout << "nDecrementing:" << endl;
  cout << "  C1 =  " << c1   << endl;
  cout << "  C1--: " << c1-- << endl;
  cout << "  C1 =  " << c1   << endl;
  cout << "  --C1: " << --c1 << endl;
  cout << "  C1 =  " << c1   << endl;

  cout << "  C2 =  " << c2   << endl;
  cout << "  C2--: " << c2-- << endl;
  cout << "  C2 =  " << c2   << endl;
  cout << "  --C2: " << --c2 << endl;
  cout << "  C2 =  " << c2   << endl;

  cout << "  C3 =  " << c3   << endl;
  cout << "  C3--: " << c3-- << endl;
  cout << "  C3 =  " << c3   << endl;
  cout << "  --C3: " << --c3 << endl;
  cout << "  C3 =  " << c3   << endl;

  c4 = c1;
  c5 = c2;
  c6 = c3;

  cout << "nEquals:" << endl;
  cout << "  C4 = C1(" << c1 << "): " << c4 << endl;
  cout << "  C5 = C2(" << c2 << "): " << c5 << endl;
  cout << "  C6 = C3(" << c3 << "): " << c6 << endl;

  c1 = complexn ( 1, 1);
  c2 = complexn (-1, 1);
  c3 = complexn (-1,-1);
  c4 = complexn ( 1,-1);
  c5 = complexn ( 0, 1);
  c6 = complexn (-1, 0);
  cout << "nAngles:" << endl;
  cout << "  C1(" << c1 << "): " << c1.complexangle() << endl;
  cout << "  C2(" << c2 << "): " << c2.complexangle() << endl;
  cout << "  C3(" << c3 << "): " << c3.complexangle() << endl;
  cout << "  C4(" << c4 << "): " << c4.complexangle() << endl;
  cout << "  C5(" << c5 << "): " << c5.complexangle() << endl;
  cout << "  C6(" << c6 << "): " << c6.complexangle() << endl;

  return 0;
}

]]>
http://pullmonkey.com/2009/03/26/ece231-spring-2009-programming-assignment-3/feed/ 2
Compilation failed: this version of PCRE is not compiled with PCRE_UTF8 support http://pullmonkey.com/2009/03/10/compilation-failed-this-version-of-pcre-is-not-compiled-with-pcre_utf8-support/ http://pullmonkey.com/2009/03/10/compilation-failed-this-version-of-pcre-is-not-compiled-with-pcre_utf8-support/#comments Tue, 10 Mar 2009 06:26:00 +0000 /2009/03/10/compilation-failed-this-version-of-pcre-is-not-compiled-with-pcre_utf8-support I don't do too much with php these days, and really haven't since I found rails many years ago. But I figured I would give magento a try, just for fun. Most of it worked, but I continually came across this PCRE error - the full error that I go was:


Warning: preg_match_all() [function.preg-match-all]: Compilation failed: this version of PCRE is not compiled with PCRE_UTF8 support at offset 0  ...

Ok, loads and loads of research led no where, or at least no where that I was willing to go. I tried so hard to find a solution that didn't require me recompiling apache ... well no such luck. I am using slicehost's ubuntu 8.04, so I took the dpkg approach to help make things simple.

Well, I am sure you have found out by now that apache comes with its own version of pcre built in (version 5). This version does not come with UTF-8 support. The trick is to tell apache to use an external system package of pcre. This requires the slightest bit of reconfiguring of apache.
Initially, my pcre looked like this (notice the version of 5.0...):

As mentioned earlier this is a pretty good indicator that your pcre is the built-in apache version. This is not good.

Ok, the solution is not too bad. Compared to this article, which I learned a few things from, it is much simpler. One thing, you will note in the article is the use of --with-pcre=/usr - this is quite different than the --with-pcre=yes that apache2 comes configured with from gusty.
So the solution is to make that change by doing this:
1) Get the source code:

1
2
3
mkdir apache_src
cd apache_src/
apt-get source apache2

2) Modify the configuration (specifically the AP2_COMMON_CONFARGS in debian/rules)
Once the source is downloaded you should have several files and a directory. Edit the debian/rules files from within the apache directory. The only change that is needed is to find the line that says --with-pcre=yes and change it to say --with-pcre=/usr.
This, of course, assumes that you installed pcre and it lives in /usr/(bin,lib ...):

1
2
vi apache2-2.2.4/debian/rules # make those changes
./apache2-2.2.4/debian/rules

3) Install build dependencies for apache:


sudo apt-get build-dep apache2

4) Now build the package:

1
2
3
4
cd apache2-2.2.4/
# you may need to install fakeroot for this:
sudo apt-get install fakeroot 
dpkg-buildpackage -rfakeroot -uc -b

5) Install the new apache package:

1
2
cd ..
sudo dpkg -i apache2_2.2.4-3ubuntu0.1_all.deb

Voila, now look what I have:

That should be it.

Good luck.

]]>
http://pullmonkey.com/2009/03/10/compilation-failed-this-version-of-pcre-is-not-compiled-with-pcre_utf8-support/feed/ 3
ECE231 – Spring 2009 – Programming Assignment 2 http://pullmonkey.com/2009/02/23/ece231-spring-2009-programming-assignment-2/ Mon, 23 Feb 2009 04:13:00 +0000 /2009/03/01/ece231-spring-2009-programming-assignment-2 This is a step-by-step tutorial for this assignment and an explanation of the basics of how it works for those that are having a difficult time understanding or just are stuck somewhere. To view the assignment click here.

So for this assignment we are going to be doing a lot of math calculations so we are going to need the include the both the iostream and the cmath libraries. We will also need the value of pi.

1
2
3
4
5
6
7
8

#include <iostream>
#include <cmath>

#define PI 3.14159
or
const double PI = 3.14159;

Defining the Coordinate Class

For the coordinate class we need 2 private variables x and y, 3 constructors, and 11 member functions.

The way you do the constructors and member functions can be done 2 different ways. You can either do them inside the class, or you can define them inside the class, like you do prototypes, and then have the actual functions at the bottom of your code. I like to define them and then put the functions at the bottom, making the code a little bit easier to read so that is the way that I'll show you, but if you want to do it the other way then just do it how you normally would with a regular function.

So here is what your class should look like (keep in mind that this all goes at the top before the main function):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

class coordinate
{
  private:
    double x;  // x value of the coordinate point
    double y;  // y value of the coordinate point
  public:
    coordinate(); // 1st constructor requiring that no arguments are passed
    coordinate(double ); // 2nd constructor requiring that only 1 argument is passed
    coordinate(double , double ); // 3rd constructor requiring that 2 arguments are passed

    void set(double , double ); // sets both values and requires 2 arguments to be passed
    void setx(double ); // sets x value and requires 1 argument to be passed
    void sety(double ); // sets y value and requires 1 argument to be passed
    void read(); // allows user to input both x and y values 
    void print(); // prints out the coordinate point in "(x, y)" form
    double distancezero(); // calculates distance of point from zero and returns the value
    double distancetwo(coordinate ); // calculates distance between 2 points (current instance and coordinate value passed) and returns the value
    double ranglezero(); // calculates the angle of the coordinate in radians and returns the value
    double danglezero(); // calculates the angle of the coordinate in degrees and returns the value
    int quadrant(); // find what quadrant the coordinate is in and returns the value
    void midpoint(coordinate ); // calculates the midpoint between 2 points (current instance and coordinate value passed) and prints the value as a coordinate
};

Writing the Actual Functions for the Coordinate Class

Since we are not actually writing the functions in the same place we are doing the class we will write them at the bottom after the main function. However, to do this we will need a little more than what we would with regular functions. For member functions we have to define what class the function is actually a member of. To do this we have to do coordinate::[function]().

For example, here are the 3 constructors for the coordinate class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// takes no arguments and sets x and y to 0
coordinate::coordinate()
{
  x = y = 0;
} 
// takes 1 argument and sets x and y to that value
coordinate::coordinate(double a)
{
  x = y = a;
} 
// takes 2 arguments and sets the corresponding x and y to those values
coordinate::coordinate(double a, double b)
{
  x = a;
  y = b;
}

Next, we have the member functions. The first 3 are the set functions. These allow the user to set the values of either the x or the y or both together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// take 2 arguments and sets the corresponding x and y to those values
void coordinate::set(double a, double b)
{
  x = a;
  y = b;
}
// takes 1 argument and sets the x to that value
void coordinate::setx(double a)
{
  x = a;
}
// takes 1 argument and sets the y to that value
void coordinate::sety(double b)
{
  y = b;
}

Next, is the read and print functions. All we want the read to do is to do a cin of the 2 values (x and y). The print is just the opposite. All it does is do a cout of the x and y values in the (x, y) format.

1
2
3
4
5
6
7
8
9
10
11
12

// takes no arguments and reads in the x and y values from the screen
void coordinate::read()
{
  cin >> x >> y;
}
// takes no arguments and prints the x and y values in (x, y) format
void coordinate::print()
{
  cout << "(" << x << ", " << y << ")";
}

Next, we have the distance functions. distanczero calculates the distance of the current instance coordinate from 0. distancetwo calculates the distance between 2 points (the current instance and the coordinate passed in).

1
2
3
4
5
6
7
8
9
10
11
12

// takes no arguments and returns the distance of the current instance from zero
double coordinate::distancezero()
{
  return sqrt(x * x + y * y);
}
// take 1 argument and calculates the distance between them
double coordinate::distancetwo(coordinate pt)
{
  return sqrt(pow(x - pt.x, 2.0) + pow(y - pt.y, 2.0));
}

Next, we have the angle functions. ranglezero uses the function in the math library atan()(arc tangent) to find the angle in radians from the positive x axis. danglezero does the same thing but converts the value from radians to degrees. To convert from radians to degrees you multiply the value by 180 / pi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

// takes no arguments and returns the angle of the coordinate from the positive x axis in radians
double coordinate::ranglezero()
{
  double angle; // angle of coordinate from positive x axis
  if(x == 0) // if x == 0 then you will get a domain error so compute angle manually
  {
    if(y > 0) return PI / 2;
    if(y < 0) return -PI / 2;
    if(y == 0) return 0;
  }
  angle = atan(y / x);
  if(x < 0 and y >= 0)
    return PI - abs(angle);
  if(x < 0 and y < 0)
    return -(PI - abs(angle));
  return angle;
}
// takes no arguments and returns the angle of the coordinate from the positive x axis in degrees
double coordinate::danglezero()
{
  double angle; // angle of coordinate from positive x axis
  if(x == 0) // if x == 0 then you will get a domain error so compute angle manually
  {
    if(y > 0) return 90;
    if(y < 0) return -90;
    if(y == 0) return 0;
  }
  angle = atan(y / x) * 180 / PI;
  if(x < 0 and y >= 0)
    return 180 - abs(angle);
  if(x < 0 and y < 0)
    return -(180 - abs(angle));
  return angle;
}

Next, we have the quadrant function. This looks at whether the x and y values are positive or negative to determine which quadrant the coordinate is in. It will return the number of the quadrant as an integer 1-4 and 0 if the coordinate is (0, 0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14

int coordinate::quadrant()
{
  if(x > 0 && y >= 0)
    return 1; // return quadrant 1
  if(x <= 0 && y > 0)
    return 2; // return quadrant 2
  if(x < 0 && y <= 0)
    return 3; // return quadrant 3
  if(x >= 0 && y < 0)
    return 4; // return quadrant 4
  return 0;   // return 0 if point is (0, 0)
}

Last, we have the midpoint function. you will need to pass this function a coordinate instance and it will calculate the midpoint between the current instance and the passed instance and print the coordinate instance.

1
2
3
4
5
6
7
8
9

void coordinate::midpoint(coordinate pt)
{
  coordinate np; // new coordinate point
  np.x = (x + pt.x) / 2.0;
  np.y = (y + pt.y) / 2.0;
  np.print();
}

Now all you have to do is test each constructor and member function to make sure that everything is working properly.

]]>
Blog plugin tutorial for Ruby on Rails http://pullmonkey.com/2009/02/11/blog-plugin-tutorial-for-ruby-on-rails/ http://pullmonkey.com/2009/02/11/blog-plugin-tutorial-for-ruby-on-rails/#comments Wed, 11 Feb 2009 20:27:00 +0000 /2009/04/02/blog-plugin-tutorial-for-ruby-on-rails Update: Bloggity does not require the Engines plugin to run if you are using Rails 2.3 or above (where the Engines plugin is baked in). -- Noted below by Bill.

Update: Added the plugin to github - simple_blog. It is not production ready or really all that usable quite yet.

Ok, so this a rant and I am sorry for that - but as simple as it is, I have been looking for a blog plugin lately. The problem with the plugins I find is that I don't want to have to deal with the engines plugin or have the controllers, models, views, etc ... all extracted into my applications code. I want it all external (hence a plugin) but let it be minimally configurable.

So in my recent search for a blog plugin for rails, I came across two that look very useful, but each with their flaws:
1) bloget - Everything is extracted to my code space. Why? Yes, I realize that it is most likely because I will want to override things, but get out of my space and keep to yourself! 🙂
Provide me a way to override things that I would need to (there really shouldn't be too many), after all it is ruby.
2) bloggity - Uses the engines plugin! I have nothing against the engines plugin (I think it is well written and documented) but for a freaking blog plugin?!? Why?

Is there a third option?
Glad you asked - yes, there is a third option - I hate to say it, but do it right! There's your third option.
Ok, but really, if there is a third option (a third plugin), I would love to hear about it.

Ok, so all that to lead up to a little plugin tutorial? Well, it got your attention didn't it?

Starting from scratch

Ok, I guess I will start from scratch. So let's get started.

Creating a plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pullmonkey$ ./script/generate plugin simple_blog
      create  vendor/plugins/simple_blog/lib
      create  vendor/plugins/simple_blog/tasks
      create  vendor/plugins/simple_blog/test
      create  vendor/plugins/simple_blog/README
      create  vendor/plugins/simple_blog/MIT-LICENSE
      create  vendor/plugins/simple_blog/Rakefile
      create  vendor/plugins/simple_blog/init.rb
      create  vendor/plugins/simple_blog/install.rb
      create  vendor/plugins/simple_blog/uninstall.rb
      create  vendor/plugins/simple_blog/lib/simple_blog.rb
      create  vendor/plugins/simple_blog/tasks/simple_blog_tasks.rake
      create  vendor/plugins/simple_blog/test/simple_blog_test.rb
      create  vendor/plugins/simple_blog/test/test_helper.rb

Create the app directories for your plugin

1
2
3
4
5
6
7
8
9
10
pullmonkey$ cd vendor/plugins/simple_blog/  # pretty important
pullmonkey$ ls
init.rb  install.rb  lib  MIT-LICENSE  Rakefile  README  tasks  test  uninstall.rb
pullmonkey$ mkdir app
pullmonkey$ mkdir -p app/models
pullmonkey$ mkdir -p app/controllers
pullmonkey$ mkdir -p app/views
pullmonkey$ mkdir -p app/helpers
pullmonkey$ ls app/
controllers  helpers  models  views

Well that was easy, so let's move on.

Models, Views, Controllers and Helpers - Living as one in my plugin

Models

Ok, so we have a clear path for where our models, controllers, views, and helpers should live, right?
For simplicity, let's just have a post and comment model - you have all seen this a billion times.

Models: vendor/plugins/simple_blog/app/models/post.rb

1
2
3
class Post < ActiveRecord::Base
  has_many :comments
end

Models: vendor/plugins/simple_blog/app/models/comment.rb

1
2
3
class Comment < ActiveRecord::Base
  belongs_to :post
end

And there you have it.
So what do you do to tell your rails application about your models?
Simple - inside vendor/plugins/simple_blog/init.rb - add these lines

1
2
3
model_path = File.join(directory, 'app', 'models')
$LOAD_PATH << model_path
ActiveSupport::Dependencies.load_paths << model_path

Ok, so let's test it out.

Step 1 - we will need some default migrations for the model to use.
Post migration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pullmonkey$ ./script/generate migration post
# This is what mine looks like
class Post < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :subject
      t.text   :body
      t.timestamps
    end
  end

  def self.down
    drop_table :posts
  end
end

And then the comment migration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pullmonkey$ ./script/generate migration comment
# This is what mine looks like
  def self.up
    create_table :comments do |t|
      t.string :username
      t.text   :body
      t.references :post
      t.timestamps
    end
  end

  def self.down
    drop_table :comments
  end

Run the migrations:


pullmonkey$ rake db:migrate

That was all just setup - now for the actual testing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
pullmonkey$ ./script/console
Loading development environment (Rails 2.2.2)
>> Comment.new
=> #<Comment id: nil, username: nil, body: nil, post_id: nil, created_at: nil, updated_at: nil>
>> Post.new
=> #<Post id: nil, subject: nil, body: nil, created_at: nil, updated_at: nil>
>> p = Post.create(:subject => "Test 1", :body => "My Body")
=> #<Post id: 1, subject: "Test 1", body: "My Body", created_at: "2009-02-11 19:09:25", updated_at: "2009-02-11 19:09:25">
>> p.body
=> "My Body"
>> p.subject
=> "Test 1"
>> p.new_record?
=> false
>> p.comments
=> []
>> c = Comment.create(:username => 'pullmonkey', :body => "this is simple")
=> #<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: nil, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:01">
>> p.comments << c
=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]
>> p.comments
=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]
>> Post.first.comments
=> [#<Comment id: 1, username: "pullmonkey", body: "this is simple", post_id: 1, created_at: "2009-02-11 19:10:01", updated_at: "2009-02-11 19:10:06">]

That's probably good enough. We have a working model and relationships. The best part is that all the code is still in the plugin.
What does my code space contain?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pullmonkey$ ls -l app/**
app/controllers:
total 4
-rw-rw-r--  1 pullmonkey pullmonkey 720 Feb 11 11:00 application.rb

app/helpers:
total 4
-rw-rw-r--  1 pullmonkey pullmonkey 115 Feb 11 11:00 application_helper.rb

app/models:
total 0

app/views:
total 4
drwxrwxr-x  2 pullmonkey pullmonkey 4096 Feb 11 11:00 layouts

Just the defaults - neat 🙂

Controllers

In much the same way as models, we can easily use controllers from our plugin. No extracting, no engines plugin.

Controllers: vendor/plugins/simple_blog/app/controllers/posts_controller.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

  def show
    @post = Post.find(params[:id])
  end

  def new
    @post = Post.new
  end

  def create
    if @post = Post.create(params[:post])
      flash[:notice] = "Post Created"
      redirect_to :action => 'index'
    else
      flash[:error] = "Post Not Created"
      render :action => 'new'
    end
  end
  #.... more code
end

Controllers: vendor/plugins/simple_blog/app/controllers/comments_controller.rb

1
2
3
4
5
6
class CommentsController < ApplicationController
  def index
    @comments = Comment.find_all_by_post_id(params[:post_id])
  end
  #.... more code
end

Now, to register the controllers, add the following to vendor/plugins/simple_blog/init.rb:

1
2
3
4
controller_path = File.join(directory, 'app', 'controllers')
$LOAD_PATH << controller_path
ActiveSupport::Dependencies.load_paths << controller_path
config.controller_paths << controller_path

Ok, before we can really test this we will need to do the views, so keep going.

Views

Create your view directories:

1
2
pullmonkey$ mkdir -p app/views/posts
pullmonkey$ mkdir -p app/views/comments

Create your views:
For this example, I will just create one, then we will test it.

Views: vendor/plugins/simple_blog/app/views/posts/index.html.erb

1
2
3
4
5
6
7
8
9
10
11
<h1>Posts</h1>
<% @posts.each do |post| -%>
  <h2><%= h post.subject %></h2>
  <%= post.body %>
  <h3>Comments</h3>
  <% post.comments.each do |comment| -%>
    <b>by <%= comment.username %></b><br/>
    <%= comment.body %><br/>
    <br/>
  <% end -%>
<% end -%>

Append your view paths:

If you don't do this next step, you will very likely see an error message like this:
Missing template posts/index.erb in view path /home/pullmonkey/rails_projects/simple_blog/app/views:

So let's add it.
There are at least two ways to do this. 1) Added to your controllers individually or 2) Add to application controller globally.
I prefer the less obtrusive, so let's go with number 1.
For this test, we will just work with the posts controller, so open it up again and add this line:


self.append_view_path(File.join(File.dirname(__FILE__), '..', 'views'))

So your file should look like this now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class PostsController < ApplicationController
  self.append_view_path(File.join(File.dirname(__FILE__), '..', 'views'))

  def index
    @posts = Post.all
  end

  def show
    @post = Post.find(params[:id])
  end

  def new
    @post = Post.new
  end

  def create
    if @post = Post.create(params[:post])
      flash[:notice] = "Post Created"
      redirect_to :action => 'index'
    else
      flash[:error] = "Post Not Created"
      render :action => 'new'
    end
  end
end

Time to test

Start your web server - ./script/server
Browse to http://localhost:3000/posts
You should see the post we created up above via Post.create(...) and its associated comment that we also created above.

Note:Feel free to overwrite any of the views. This can be done simply for the posts index view by creating the same file under RAILS_ROOT/app/views/posts/index.html.erb and doing what you'd like.

That's it for part 1

Ok, so that's part 1. The goal was to keep everything external and I think we succeeded (aside from migrations).
No offense to those that use engines or extract files into one's application's space, we all have our ways - the above is what I prefer.

Part 2 will consist mainly of filling this out a bit more and further discussion on adding helpers, routes and migrations to your plugin without interfering in the application's code space.

As always, have fun and good luck!

]]>
http://pullmonkey.com/2009/02/11/blog-plugin-tutorial-for-ruby-on-rails/feed/ 11
ECE231 – Spring 2009 – Programming Assignment 1 http://pullmonkey.com/2009/02/05/ece231-spring-2009-programming-assignment-1/ Thu, 05 Feb 2009 19:45:00 +0000 /2009/02/23/ece231-spring-2009-programming-assignment-1 This is a step-by-step tutorial for this assignment and an explanation of the basics of how it works for those that are having a difficult time understanding or just are stuck somewhere. To view the assignment click here.

Part A

1. Create a structure (called point) that includes a time and y value (both doubles).

This is very simple using the typedef struct and listing your variables.

1
2
3
4
5
6
7

typedef struct
{
  double time;
  double y;
} point;

2. Create a main program that has an array of 40 points (or structures), keeps track of the number of values in the array and has variables for each of the values needed to calculate above.

In the main program we will need an array of points p, an integer with the total number of points values, and 4 double variables, one for each of the functions (I used vert_shift, amp, freq, and phase_shift).

Then you will need to call each function and for testing I printed each value out to make sure everything was coming in right. It is short, simple, and to the point like all programming should be. Your main should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

int main()
{
  point p[40];          // array of points
  int values = 0;       // total number of values in the points array
  double vert_shift=0;  // vertical shift
  double amp=0;         // amplitude
  double freq=0;        // frequency
  double phase_shift=0; // phase shift

  values = read_data(p);
  cout << "Values: " << endl;
  for(lcv=0; lcv < values; lcv++)
    cout << "  " <<  p[lcv].time << "  " << p[lcv].y << endl;
  cout << "nTotal Number of values = " << values << endl;
  vert_shift = vertical(p, values);
  cout << "nVertical shift = " << vert_shift << endl;
  amp = amplitude(p, values);
  cout << "nAmplitude = " << amp << endl;
  freq = frequency(p, values);
  cout << "nFrequency = " << freq << endl;
  phase_shift = pshift(p, values);
  cout << "nPhase Shift = " << phase_shift << endl;
  return 0;
}

3. The main program should then call the read_data function. This function will have one argument (the array of points - or structures - which will be passed as a pointer to the function) and will return the number of values in the array. It should read the data from the data file using a pointer and the arrow (->) operator.

First, we are going to be reading from a file in this function so we are going to need to include the fstream library.

1
2
3

#inlcude <fstream> // reading from file

Next, we need to create the prototype for this function called read_data. This will go above the main. The read_data function will need the array of points and will return the total number of points as an integer. So it should look like this:

1
2
3

int read_data(point *);

Now below the main we can create our function and lets call the array of points a. In this function we will need 2 more variables, an integer (total) for counting the number of points that we read from the file and an ifstream variable (f) for opening and closing the file.

First, we need to try to open the file using f.open("sp09prog1.txt"). Next, we need to test to make sure the file was opened and that we can read from it and if not then print out error message and exit. If the file was opened then we need to read in the values into the point array and count the number of points using the total integer variable. We do this until we read the end of the file and we find out if we are at the end of the file with f.eof(). Finally, we will want to return the total. It should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int read_data(point *a)
{
  ifstream f;  // file streaming variable
  int total=0; // counts the total number of points in file

  f.open("sp09prog1.txt");

  if(f.fail())
  {
    cout << "ERROR: File could not be opened" << endl;
    exit(1);
  }

  while(!f.eof())
  {
    f >> a->time >> a->y;
    total++;
    a++;
  }
  return total - 1;
}

Notice that we return total - 1. This is because we increment total and then we find out it is the end of the file. So we incremented one too many times so we need to subtract 1 before returning it.

4. Main should then call the vertical function to calculate the vertical shift. This function has two arguments (the array of points - passed as a pointer - and the number of values in the array). It will calculate the vertical shift by finding the average of the maximum and minimum y-values. You will need to search through the array of points to find these max and min values.
5. Next, main will call the amplitude function to calculate the amplitude. This function has two arguments (the array of points - passed as a pointer - and the number of values in the array; you must also use the arrow operator in this function) and will return the amplitude. To find the amplitude, you need to calculate half the difference between the maximum and minimum values of the y-values (you will need to search through the array for the maximum and minimum values again).

The functions are both almost identical. The only difference is the equation at the end so we will do them at the same time.

First, we will create the prototypes. Both functions take the array of points and the integer total number of points and they both return a double. So the prototypes should look like this:

1
2
3
4

double vertical(point *, int );
double amplitude(point *, int );

So lets call the point array p and the integer total.

To find the max and min values we need to create 2 double variables (max and min) and an integer (lcv) that we will use for the loop.

Next we will need to set both max and min to the first y element in the array of points. Then we will have a loop and start from 0 to total. Each time we run through this loop we need to do 3 things:

  • 1. Test if max is less than the current y value? If yes then set max to the current y
  • 2. Test if min is greater than the current y value? If yes then set min to the current y
  • 3. Increment a to the next position in the array. Because we are using a pointer to the array we can do this easily by doing a++

Next we will just return the result of the equation as a double. So your functions should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

double vertical(point *a, int total)
{   
  double min; // minimum y value found in array
  double max; // maximum y value found in array
  int lcv;    // loop control variable
  max = min = a->y;
  for(lcv=0; lcv < total; lcv++) 
  {
    if(max < a->y)
      max = a->y;
    if(min > a->y)
      min = a->y;
    a++;
  }
  return (max + min) / 2.0;
}
double amplitude(point *a, int total)
{
  double min; // minimum y value found in array
  double max; // maximum y value found in array
  int lcv;    // loop control variable
  max = min = a->y;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max < a->y)
      max = a->y;
    if(min > a->y)
      min = a->y;
    a++;
  }
  return (max - min) / 2.0;
}

6. The next function called by main is the frequency function that has two arguments (the array of points - passed as a pointer - and the number of values in the array; again using the arrow operator to access values) and will return the frequency. To calculate the frequency, find the period which is time difference between the maximum and minimum y-values and multiply by 2. Then, divide to calculate the frequency. Please note that you are using the difference between time values, not the y values, to perform the overall computation.
7. Finally, main will call the pshift function that contains two arguments (the array of points - passed as a pointer - and the number of values in the array; again using the arrow operator to access values) and will return the phase shift or horizontal shift. This shift can be found by finding the average of the time values where the maximum and minimum y-values occur; then subtracting it from half the period (see step 6 to find the period).

The functions for steps 6 and 7 are both almost identical expect for the equation at the end so we will do these both at the same time.

For the frequency function we will need to use the absolute value function in the cmath library. To include this you will need to do this at the top of your file.

1
2
3

#include <cmath>

Like the functions in step 4 and 5 they need to have the array of points and the integer total number of points and they both return a double. So the prototypes should look like this:

1
2
3
4

double frequency(point *, int );
double pshift(point *, int );

So lets call the point array p and the integer total.

To find the max and min values we need to create 2 pointers to point variables (max and min) and an integer (lcv) that we will use for the loop.

Next we will need to set both max and min pointers to the same address as a points which is the first position in the array of points. Then we will have a loop and start from 0 to total. Each time we run through this loop we need to do 3 things:

  • 1. Test if max->y is less than the current a->y value? If yes then set max to the current a address.
  • 2. Test if min->y is greater than the current a->y value? If yes then set min to the current a address.
  • 3. Increment a to the next position in the array. Because we are using a pointer to the array we can do this easily by doing a++

Next we will just return the result of the equation as a double. So your functions should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

double frequency(point *a, int total)
{
  point *min; // minimum y value location found in array
  point *max; // maximum y value location found in array
  int lcv;    // loop control variable
  max = min = a;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max->y < a->y)
      max = a;
    if(min->y > a->y)
      min = a;
    a++;
  } 
  return abs(PI / (max->time - min->time));
} 
double pshift(point *a, int total)
{
  point *min; // minimum y value location found in array
  point *max; // maximum y value location found in array
  int lcv;    // loop control variable
  max = min = a;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max->y < a->y)
      max = a;
    if(min->y > a->y)
      min = a;
    a++;
  }
  a -= total;
  return (2 * PI / frequency(a, total)) / 2 - (max->time + min->time) / 2.0;
}

Notice how in the pshift function after the loop we do a -= total. This is because a is currently pointing the last element in the array and if we want to call frequency and pass the address of the first element in the array of points then we need to set a back to the first element.

Also notice that the frequency function uses a variable called PI. This is the value of pi so at the top above the main you will need to define it as a constant. You can do this one of 2 ways:

1
2
3
4
5

#define PI 3.14159
or 
const double PI=3.14159;

Either way will work but I prefer to use the #define since it uses less memory and only takes more processing when you compile the program not in running it.

Outcome

Using the text file provided this is what I got when I ran the program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

[scnaegle@egor ece231]$ ./a.out 
Values: 
  1.5708  -4
  1.6791  -3.3551
  1.7875  -2.7403
  1.8958  -2.1845
  2.0041  -1.7135
  2.1125  -1.3495
  2.2208  -1.1094
  2.3291  -1.0044
  2.4374  -1.0395
  2.5458  -1.2131
  2.6541  -1.5169
  2.7624  -1.9369
  2.8708  -2.4533
  2.9791  -3.0421
  3.0874  -3.6756
  3.1958  -4.3244
  3.3041  -4.9579
  3.4124  -5.5467
  3.5208  -6.0631
  3.6291  -6.4831
  3.7374  -6.7869


  3.8457  -6.9605
  3.9541  -6.9956
  4.0624  -6.8906
  4.1707  -6.6505
  4.2791  -6.2865
  4.3874  -5.8155
  4.4957  -5.2597
  4.6041  -4.6449
  4.7124  -4

Total Number of values = 30

Vertical shift = -4

Amplitude = 2.9956

Frequency = 1.93329

Phase Shift = -1.5166

Part B

Using MATLAB, you need to plot the original data using the data file sp09prog1.txt. To do this, load the file into MATLAB, then assign the first column to be the x values and the second column to be the y values. You can then use the plot command to plot these (you should only plot the points - not any connecting lines).

This is easy. Use the load() function to read in data from the file into a matrix.

1
2
3

table = load('sp09prog1.txt')

Then we need to get the data into arrays of time and y. To do this use matrixvairable(row,column). Use a colon (:) to get everything in either the row or column. In this case we will want all rows in the first column for time and all rows and second column for y.

1
2
3
4

time = table(: , 1)
y = table(: , 2)

Then plot the data using the plot() function. For this you will need to pass 3 things (x values, y values, and symbol). Our x values is the array time and our y values is array y.

1
2
3

plot(time, y, 'o')

Then, using the values you found in the C++ program for each of the four variables, create a cosine curve that can be plotted over the data. You will need to create a matrix of x-values that run from 1 to 2π with an increment of π/100. Then, create a matrix of y values using the cosine equation: where vs is the vertical shift, ps is the phase shift, amp is the amplitude and freq is the frequency. Plot these x and y values using a red line.

This is just the same as the first part only we need to find the x and y values using equations. But first lets set all the values we will need for our calculations which we can get from Part A of the program.

1
2
3
4
5
6
7

vs = -4
amp = 2.9956
freq = 1.93329
ps = -1.5166
PI = 3.14159

Next we will have to create the array x with all the x values. In this case we are going to go from 0 to 2pi and step by pi/100. To do this we have a colon (:) between each argument like this:

1
2
3

x = 0 : PI / 100 : 2 * PI

Now, to create the array y with all the y values we use the equation we were given.

1
2
3

y = vs + amp * (cos(freq * x - ps))

Now, all we need to do is plot it on the graph. However, we want to plot the new equation on the same plot as the last one. To do this we need to use the command hold on. We also want the new graph to look different so lets make it a full line 4px wide and the color be dark red. Like this:

1
2
3
4

hold on
plot(x, y, '', 'LineWidth', 4, 'Color', [.6 0 0])

Now run it and see if your two line match up at all.

]]>