Telefio :: Group messaging – SMS

There is a very simple and easy to use group text messaging web site called Telefio that I think you can use for something. It’s free (at least for now) but still very useful. If you are a group leader, youth leader, marketer, advertiser, club leader, teacher, parent or just anybody who wants to notify a group of people fast, I think Telefio.com will be pretty useful for you. I know how useful it is for me because I can send a message out to 180 youth members in no time. It’s a lot better than trying to send it on my phone because I can send a message only to 10 people at a time.

Telefio also groups members into categories so you can send a message a certain group. Paid plans are not available at the moment but you will be allowed to send a message using any phone that can text. Pretty cool.

Members can reply to messages sent to them and those replies are grouped also.

You can sign up for a free account at telefio.com.

Ruby on Rails on Google Chrome OS

Have you been wondering how you can get Ruby on Rails running on the Google Chromium OS? Here is a way you can do it but do it at your own risk.

  1. I’m assuming that you know how to switch to development mode and make the file system writable. If not, here is a good tutorial.
  2. Once you’re logged in, go to http://www.archlinux.org/packages/core/i686/xz/ and download that file. This is a decompressor. Open shell, go to /home/chronos/user/Downloads folder and type tar -xvf xz-5.0.1-1-i686.pkg.tar.gz
  3. You will get a new folder in /Downloads called /usr. Type cd usr and then ls. You will see a list of folders like /bin and /lib. Do cd bin and then mv * /usr/bin/ . This will move everything that’s in the /bin folder to /usr/bin. Do that for all the folders in the usr folder. If you get an error saying that a certain file is a directory, open that directory and move all the files to the correct location in the systems /usr directory, make sure it’s consistent. Once that’s done, you should be able to run xz -d filename to decompress a file.
  4. Go to http://www.archlinux.org/packages/extra/i686/ruby/ and download that file also. These are the actual ruby files. Go to the /Downloads directory and and type xz -d ruby-1.9.2_p180-1-i686.pkg.tar.xz to decompress this file. Once decompressed, type tar -xvf ruby-1.9.2_p180-1-i686.pkg.tar . You will get a usr/ directory again. Do the same thing as you did with the other usr/ directory. Copy all the directories and files into the correct locations (/home/chronos/user/Downloads/usr/bin/* to /usr/bin/*, etc.)
  5. Once all the ruby files have been copied to the correct locations, you should be able to run ruby -v. Now it gets easier. Type gem install rails and it will install rails and it’s dependencies. You should know what to do from there on : )

Good luck! If you have any questions, feel free to ask.

NashaSMS: Free Group SMS Messaging

Our church youth was pretty large and we couldn’t notify everybody about an event because calling 180 people is impossible and texting…you will run out of messages by the time you text everybody. So we created a small site, as a subdomain on our youth website (www.molodezh.com), that allowed us to notify all the members using SMS messages from the site. We used Google Voice for a while but then Google started limiting the amount of messages that could be sent out daily. So what did we do? We created www.nashasms.com and now there is no limit AND it’s also open to other youth groups and churches to use. And yes, it’s free, because we know that it’s expensive to send SMS messages so we made it free for you.

If you want to notify your youth group, worship group, or any other group, try nashasms (www.nashasms.com)…I’m telling you, it’s a great tool!

Google Voice API Wrapper (PHP)

Update: Since this was written in 2010, Google might have changed Voice in a way that would make the below code unusable. If someone has any fixes, please let me know.

Since Google Voice does not have an official API, I decided to create a wrapper with PHP. Many people have been asking about some Google Voice API documentation but there isn’t any. This wrapper only sends and receives SMS messages for now. I will be adding more functions to it later. If you don’t like the way it works, then you can just use this as an example.

Note: Don’t forget to set $_rnr_se in the code below.


<?php
// GoogleVoice(EMAIL, PASSWORD)
$gv = new GoogleVoice('example@gmail.com', 'password');
// Sends an SMS. send_sms(NUMBER, MESSAGE)
echo $gv->send_sms('15555555555', 'Example');
// Gets all the sms
// get_sms() - returns all the sms
// get_sms(true) - returns all the unread sms
echo $gv->get_sms();

/**
  * Google Voice API Wrapper
  * 
  * new GoogleVoice(EMAIL, PASSWORD)
  * send_sms(NUMBER, MESSAGE)
  * get_sms()
  * get_sms(true) - unread
  *
  * @author Artem Kalinchuk
**/

Class GoogleVoice {
	/**
	  * Modify this
	**/
	var $account_type = 'GOOGLE'; 	// The Google account type
	var $service = 'grandcentral'; 	// Service for Google Voice is grandcentral (it may change)
	var $source = '';				// The host of your site (for logging purposes) 
	// _rnr_se - This can be found in the source code of the inbox page of your Google Voice
	// Simply view the source and search for '_rnr_se'. Should be a string of about 30
	// characters (numbers, letters, and symbols)
	var $_rnr_se = ''; 
	
	/**
	  * Do not modify
	**/
	var $url = 'https://www.google.com/';	// Google HTTPS URL
	var $auth; 								// The AUTH key
	var $email;								// Users email address
	var $password;							// Users password
	
	function __construct ($email, $password) {
		if ($email)
			$this->email = $email;
		if ($password)
			$this->password = $password;
			
		// Authenticate if the Auth key is empty
		if ($this->auth == '') {
			$this->authenticate();
		}
	}
	
	/**
	  * authenticate
	  * Authenticates using the email and password.
	  * @return Auth Session Key
	**/
	
	function authenticate () {
		$form_data = array();
		$form_data['accountType'] = $this->account_type;
		$form_data['Email'] = $this->email;
		$form_data['Passwd'] = $this->password;
		$form_data['service'] = $this->service;
		$form_data['source'] = $this->source;
		
		$response = $this->transmit($form_data, 'accounts/ClientLogin');
		preg_match("/Auth\=(.*)/", $response, $matches);

		if (count($matches) == 0) {
			return $response;
		} else {
			$this->auth = str_replace("Auth=", "", $matches[0]);
			return $this->auth;
		}
	}
	
	/**
	  * transmit
	  * Transmits the passed in POST data
	  * @param $form_data An array of POST fields and values
	  * @param $path The path to call
	  * @return Response from the server
	**/
	
	function transmit ($form_data, $path, $USE_POST=true) {
		$url = $this->url.$path;
		$fields = array();
		
		foreach ($form_data as $field => $value)
			$fields[] = $field.'='.urlencode($value);
		
		// POST or GET?
		if ($USE_POST) {
			$ch = curl_init($url);
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_POST, count($form_data));
			curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $fields));
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded", "Authorization: GoogleLogin auth=".$this->auth));
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		} else {
			$ch = curl_init($url.'?'.implode('&', $fields));
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		}
		
		$response = curl_exec($ch);
		
		return $response;
	}
	
	/**
	  * send_sms
	  * Sends an SMS message
	  * @param $phone_number The number to send the SMS message to
	  * @param $text The message
	  * @return Response from the server (success or fail)
	**/
	
	function send_sms ($phone_number, $text) {
		$form_data = array();
		$form_data['phoneNumber'] = $phone_number;
		$form_data['text'] = $text;
		$form_data['id'] = '';
		$form_data['_rnr_se'] = $this->_rnr_se;
		
		$response = $this->transmit($form_data, 'voice/sms/send/');
		
		return $response;
	}
	
	/**
	  * get_sms
	  * Gets the HTML of the SMS inbox
	  * @param $UNREAD boolean - Show unread or not
	  * @return The HTML from the SMS inbox page
	**/
	
	function get_sms($UNREAD=false) {
		$form_data = array();
		$form_data['auth'] = $this->auth;
		
		if ($UNREAD)
			$path = 'voice/inbox/recent/unread/';
		else
			$path = 'voice/inbox/recent/';
			
		$response = $this->transmit($form_data, $path, false);
		
		return $response;
	}
}
?>

Google Voice API – Ruby on Rails

I’ve been searching google for a ruby on rails Google Voice API but couldn’t find anything. I decided to make my own…since I know there are others that would like some help. This is just a simple way of sending an SMS message using Google Voice.

The first thing you have to do is login using your Google account.


require 'net/http'
require 'net/https'
require 'uri'

login_response = ''

url = URI.parse('https://www.google.com/accounts/ClientLogin')
login_req = Net::HTTP::Post.new(url.path)
login_req.form_data = {'accountType' => 'GOOGLE', 'Email' => 'YOUR_GOOGLE_ACCOUNT(full)', 'Passwd' => 'YOUR_PASSWORD', 'service' => 'grandcentral', 'source' => 'ANYTHING_YOU_WANT(eg. mysite.com)'}
login_con = Net::HTTP.new(url.host, url.port)
login_con.use_ssl = true
login_con.start {|http| login_response = http.request(login_req)}

Notice the last line. It sets login_response to the http response which contains the auth token that you will need to use when sending the SMS message.

Once you have successfully logged in, you can send the message.


url = URI.parse('https://www.google.com/voice/sms/send/')
req = Net::HTTP::Post.new(url.path, { 'Content-type' => 'application/x-www-form-urlencoded', 'Authorization' => 'GoogleLogin auth='+login_response.body.match("Auth\=(.*)")[0].gsub("Auth=", "") })
# We're sending the auth token back to google
req.form_data = {'id' => '', 'phoneNumber' => '555555555', 'text' => 'Sample message', '_rnr_se' => 'FROM_GOOGLE_VOICE_PAGE(view source)'}
con = Net::HTTP.new(url.host, url.port)
con.use_ssl = true
con.start {|http| response = http.request(req)}

The response will be {“ok”:true…} if successful. Notice ‘_rnr_se’. You can get this by going to your google voice inbox and viewing the source for that page. Search for ‘_rnr_se’ and use that value to send it back to google. As you can see, we’re sending “auth” with the google auth response that we got after logging into google.

I split the code into 2 parts but it should be put together into 1 part.

Hostmonster 500 error/dispatch Problem

The following error was found in my fastcgi.crash.log

[23/Jul/2009:10:00:28 :: 23983] Dispatcher failed to catch: undefined
method `read’ for class `FCGI::Stream’ (NameError) /usr/lib/ruby/gems/
1.8/gems/rack-1.0.0/lib/rack/handler/fastcgi.rb:7
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
103:in `process_request’ /home/username/rails/app/vendor/rails/
railties/lib/fcgi_handler.rb:153:in `with_signal_handler’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
101:in `process_request’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
78:in `process_each_request’
/usr/lib/ruby/gems/1.8/gems/fcgi-0.8.7/lib/fcgi.rb:117:in
`session’ /usr/lib/ruby/gems/1.8/gems/fcgi-0.8.7/lib/fcgi.rb:104:in
`each_request’
/usr/lib/ruby/gems/1.8/gems/fcgi-0.8.7/lib/fcgi.rb:36:in `each’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
77:in `process_each_request’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
76:in `catch’ /home/username/rails/app/vendor/rails/railties/lib/
fcgi_handler.rb:76:in `process_each_request’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
51:in `process!’
/home/username/rails/app/vendor/rails/railties/lib/fcgi_handler.rb:
23:in `process!’
dispatch.fcgi:24
unhandled dispatch error

Josh’s message got me on the right track to a fix, but didn’t quite
work. I believe this is in fact a bug in the rack gem.

Step 1: Install the rack gem locally

gem install rack

Step 2: Fix the bug in the locally installed rack gem

Edit /path/to/local/gems/rackrack-1.0.0/lib/rack/handler/fastcgi.rb.
Move line #7 to just below the definition of the read method. It
should look as follows.

class FCGI::Stream
def read(n, buffer=nil)
buf = _rack_read_without_buffer n
buffer.replace(buf.to_s) if buffer
buf
end
alias _rack_read_without_buffer read
end

You can determine the path to your locally installed gems by running
‘gem env’. Look for ‘INSTALLATION DIRECTORY’.

Step 3: Tell your rails app to use the local gem instead of the system
gem

Edit the environment.rb file for your application and add the
following to the top.

ENV[‘GEM_PATH’] = ‘/path/to/local/ruby/gems’

Use the path exactly as listed next to ‘INSTALLATION DIRECTORY’ when
you run ‘gem env’. In my case, it was /home/username/ruby/gems. You
should not need to specify the path to the global system gems.

Step 4: Kill any running dispatch.fcgi processes

killall -u username dispatch.fcgi

Step 5: Try to access your app

At this point my rails app started with no problem.

Got from : http://aspn.activestate.com/ASPN/Mail/Message/ruby-talk/3732081

JavaScript :: Drag Objects on Page

I was working on a little JavaScript program and I wanted to let users be able to drag objects around on the screen and make the web page customizable but could not find any usable code.  I searched for hours until I found a pretty good script that does the job right.

Click here for an example. (Click on the header to move the object around on the page)

The Code

First you will need some divs to move around on the page.

1
2
3
4
5
6
<div id="boxB" cass="box" style="left:400px;top:150px;">
  <div class="bar" style="width:12em;"
       onmousedown="dragStart(event, 'boxB')">Drag Box B</div>
  <div class="content" style="width:12em;">This is Box B, drag it using the bar above.</div>
 
</div>

Some styles for the divs….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.box {
  background-color: #ffff00;
  border: 1px solid #000000;
  color: #000000;
  padding: 0px;
  position: absolute;
}
 
.bar {
  background-color: #008080;
  color: #ffffff;
  cursor: move;
  font-weight: bold;
  padding: 2px 1em 2px 1em;
}
 
.content {
  padding: 1em;
}

And the JavaScript… (leave the header as it is because this is not my work)
This first function determines the browser that the user is using and the version to make sure it’s compatible.

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
//*****************************************************************************
// Do not remove this notice.
//
// Copyright 2001 by Mike Hall.
// See http://www.brainjar.com for terms of use.
//*****************************************************************************
 
// Determine browser and version.
 
function Browser() {
 
  var ua, s, i;
 
  this.isIE    = false;
  this.isNS    = false;
  this.version = null;
 
  ua = navigator.userAgent;
 
  s = "MSIE";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isIE = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }
 
  s = "Netscape6/";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }
 
  // Treat any other "Gecko" browser as NS 6.1.
 
  s = "Gecko";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = 6.1;
    return;
  }
}
 
var browser = new Browser();
 
// Global object to hold drag information.
 
var dragObj = new Object();
dragObj.zIndex = 0;

The DragStart function which is called when the user clicks on the header to move the object…

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
function dragStart(event, id) {
 
  var el;
  var x, y;
 
  // If an element id was given, find it. Otherwise use the element being
  // clicked on.
 
  if (id)
    dragObj.elNode = document.getElementById(id);
  else {
    if (browser.isIE)
      dragObj.elNode = window.event.srcElement;
    if (browser.isNS)
      dragObj.elNode = event.target;
 
    // If this is a text node, use its parent element.
 
    if (dragObj.elNode.nodeType == 3)
      dragObj.elNode = dragObj.elNode.parentNode;
  }
 
  // Get cursor position with respect to the page.
 
  if (browser.isIE) {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isNS) {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }
 
  // Save starting positions of cursor and element.
 
  dragObj.cursorStartX = x;
  dragObj.cursorStartY = y;
  dragObj.elStartLeft  = parseInt(dragObj.elNode.style.left, 10);
  dragObj.elStartTop   = parseInt(dragObj.elNode.style.top,  10);
 
  if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0;
  if (isNaN(dragObj.elStartTop))  dragObj.elStartTop  = 0;
 
  // Update element's z-index.
 
  dragObj.elNode.style.zIndex = ++dragObj.zIndex;
 
  // Capture mousemove and mouseup events on the page.
 
  if (browser.isIE) {
    document.attachEvent("onmousemove", dragGo);
    document.attachEvent("onmouseup",   dragStop);
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS) {
    document.addEventListener("mousemove", dragGo,   true);
    document.addEventListener("mouseup",   dragStop, true);
    event.preventDefault();
  }
}

DragGo…moves the object

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
function dragGo(event) {
 
  var x, y;
 
  // Get cursor position with respect to the page.
 
  if (browser.isIE) {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isNS) {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }
 
  // Move drag element by the same amount the cursor has moved.
 
  dragObj.elNode.style.left = (dragObj.elStartLeft + x - dragObj.cursorStartX) + "px";
  dragObj.elNode.style.top  = (dragObj.elStartTop  + y - dragObj.cursorStartY) + "px";
 
  if (browser.isIE) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS)
    event.preventDefault();
}

And DragStop which stops the object from moving

1
2
3
4
5
6
7
8
9
10
11
12
13
function dragStop(event) {
 
  // Stop capturing mousemove and mouseup events.
 
  if (browser.isIE) {
    document.detachEvent("onmousemove", dragGo);
    document.detachEvent("onmouseup",   dragStop);
  }
  if (browser.isNS) {
    document.removeEventListener("mousemove", dragGo,   true);
    document.removeEventListener("mouseup",   dragStop, true);
  }
}

And that’s it. Here is the combined version of all the code…feel free to use but don’t remove the header.

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<style type="text/css">
 
.box {
  background-color: #ffff00;
  border: 1px solid #000000;
  color: #000000;
  padding: 0px;
  position: absolute;
}
 
.bar {
  background-color: #008080;
  color: #ffffff;
  cursor: move;
  font-weight: bold;
  padding: 2px 1em 2px 1em;
}
 
.content {
  padding: 1em;
}
 
</style>
 
<script type="text/javascript">
//<![CDATA[
 
//*****************************************************************************
// Do not remove this notice.
//
// Copyright 2001 by Mike Hall.
// See http://www.brainjar.com for terms of use.
//*****************************************************************************
 
// Determine browser and version.
 
function Browser() {
 
  var ua, s, i;
 
  this.isIE    = false;
  this.isNS    = false;
  this.version = null;
 
  ua = navigator.userAgent;
 
  s = "MSIE";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isIE = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }
 
  s = "Netscape6/";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = parseFloat(ua.substr(i + s.length));
    return;
  }
 
  // Treat any other "Gecko" browser as NS 6.1.
 
  s = "Gecko";
  if ((i = ua.indexOf(s)) >= 0) {
    this.isNS = true;
    this.version = 6.1;
    return;
  }
}
 
var browser = new Browser();
 
// Global object to hold drag information.
 
var dragObj = new Object();
dragObj.zIndex = 0;
 
function dragStart(event, id) {
 
  var el;
  var x, y;
 
  // If an element id was given, find it. Otherwise use the element being
  // clicked on.
 
  if (id)
    dragObj.elNode = document.getElementById(id);
  else {
    if (browser.isIE)
      dragObj.elNode = window.event.srcElement;
    if (browser.isNS)
      dragObj.elNode = event.target;
 
    // If this is a text node, use its parent element.
 
    if (dragObj.elNode.nodeType == 3)
      dragObj.elNode = dragObj.elNode.parentNode;
  }
 
  // Get cursor position with respect to the page.
 
  if (browser.isIE) {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isNS) {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }
 
  // Save starting positions of cursor and element.
 
  dragObj.cursorStartX = x;
  dragObj.cursorStartY = y;
  dragObj.elStartLeft  = parseInt(dragObj.elNode.style.left, 10);
  dragObj.elStartTop   = parseInt(dragObj.elNode.style.top,  10);
 
  if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0;
  if (isNaN(dragObj.elStartTop))  dragObj.elStartTop  = 0;
 
  // Update element's z-index.
 
  dragObj.elNode.style.zIndex = ++dragObj.zIndex;
 
  // Capture mousemove and mouseup events on the page.
 
  if (browser.isIE) {
    document.attachEvent("onmousemove", dragGo);
    document.attachEvent("onmouseup",   dragStop);
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS) {
    document.addEventListener("mousemove", dragGo,   true);
    document.addEventListener("mouseup",   dragStop, true);
    event.preventDefault();
  }
}
 
function dragGo(event) {
 
  var x, y;
 
  // Get cursor position with respect to the page.
 
  if (browser.isIE) {
    x = window.event.clientX + document.documentElement.scrollLeft
      + document.body.scrollLeft;
    y = window.event.clientY + document.documentElement.scrollTop
      + document.body.scrollTop;
  }
  if (browser.isNS) {
    x = event.clientX + window.scrollX;
    y = event.clientY + window.scrollY;
  }
 
  // Move drag element by the same amount the cursor has moved.
 
  dragObj.elNode.style.left = (dragObj.elStartLeft + x - dragObj.cursorStartX) + "px";
  dragObj.elNode.style.top  = (dragObj.elStartTop  + y - dragObj.cursorStartY) + "px";
 
  if (browser.isIE) {
    window.event.cancelBubble = true;
    window.event.returnValue = false;
  }
  if (browser.isNS)
    event.preventDefault();
}
 
function dragStop(event) {
 
  // Stop capturing mousemove and mouseup events.
 
  if (browser.isIE) {
    document.detachEvent("onmousemove", dragGo);
    document.detachEvent("onmouseup",   dragStop);
  }
  if (browser.isNS) {
    document.removeEventListener("mousemove", dragGo,   true);
    document.removeEventListener("mouseup",   dragStop, true);
  }
}
 
//]]>
</script>
 
<div id="boxB" class="box" style="left:400px;top:150px;">
  <div class="bar" style="width:12em;"
       onmousedown="dragStart(event, 'boxB')">Drag Box B</div>
  <div class="content" style="width:12em;">This is Box B, drag it using the bar above.</div>
 
</div>

FeedStitch :: Combining multiple twitter feeds into one

Recently, some of our youth members left on missionary trips to countries like Russia and Ukraine to help with orphanages and churches around the Kamchatka area.  I’m sure many of you know what Twitter is.  The three groups that went use Twitter to communicate with us back in the US.

What I wanted to do is combine all three feeds into one and post it on our youth website, molodezh.com, but could not figure out how to do it until I finally found www.feedstitch.com.  Feedstitch.com is awesome! You can merge as many feeds from many services like Twitter, Flickr, Delicious, Github, and Tumblr into one feed.  So I combined all feeds into one using feedstitch and used Magpie RSS parser to parse the rss which was in a short, customizable URL.  It’s worth checking it out.