Port changed() function to master

Port the `changed()` forward from #530 to `master`.

Attempting to add a test but I'm hitting an obstacle here. Anyone mind taking a look at this?

```python
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig PATH=$PATH:/usr/local/opt/pkg-config/bin:/usr/local/Cellar/libffi/3.0.13/lib/pkgconfig tox -e py26-django14
GLOB sdist-make: /Users/jdixon/Projects/graphite-web/setup.py
py26-django14 recreate: /Users/jdixon/Projects/graphite-web/.tox/py26-django14
py26-django14 installdeps: cairocffi, django-tagging, pytz, mock, git+git://github.com/graphite-project/whisper.git#egg=whisper, git+git://github.com/graphite-project/ceres.git#egg=ceres, Django<1.5, django-discover-runner, pyparsing
py26-django14 inst: /Users/jdixon/Projects/graphite-web/.tox/dist/graphite-web-0.10.0-alpha.zip
py26-django14 runtests: PYTHONHASHSEED='1567628275'
py26-django14 runtests: commands[0] | django-admin.py test
Could not import graphite.local_settings, using defaults!
/Users/jdixon/Projects/graphite-web/webapp/graphite/settings.py:225: UserWarning: SECRET_KEY is set to an unsafe default. This should be set in local_settings.py for better security
  warn('SECRET_KEY is set to an unsafe default. This should be set in local_settings.py for better security')
Creating test database for alias 'default'...
...........F................................
======================================================================
FAIL: test_changed (tests.test_functions.FunctionsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jdixon/Projects/graphite-web/webapp/tests/test_functions.py", line 355, in test_changed
    self.assertEqual(result, expected)
AssertionError: Lists differ: [TimeSeries(name=changed(colle... != [TimeSeries(name=changed(colle...

First differing element 0:
TimeSeries(name=changed(collectd.test-db1.load.value), start=0, end=1, step=1)
TimeSeries(name=changed(collectd.test-db1.load.value), start=0, end=1, step=1)

  [TimeSeries(name=changed(collectd.test-db1.load.value), start=0, end=1, step=1)]

----------------------------------------------------------------------
Ran 44 tests in 1.184s

FAILED (failures=1)
Destroying test database for alias 'default'...
ERROR: InvocationError: '/Users/jdixon/Projects/graphite-web/.tox/py26-django14/bin/django-admin.py test'
______________________________________________________ summary ______________________________________________________
ERROR:   py26-django14: commands failed
```
That's part of it. I'm also using bad list syntax. I have it working
now, about to push up the changes.

On Sat, Aug 23, 2014 at 07:39:35PM -0700, mark olson wrote:
> > @@ -341,3 +341,15 @@ def test_invert(self):
> >                      continue
> >                  expected_value = math.pow(original_value, -1)
> >                  self.assertEqual(value, expected_value)
> > +
> > +    def test_changed(self):
> > +        config = [
> > +            ([1,2,3,4,4,5,5,5,6,7], [0,0,0,0,1,0,1,1,0,0]),
> > +            ([None,None,None,None,0,0,0,None,None,1], [0,1,1,1,0,1,1,0,1,0])
> > +        ]
> 
> For why the test is failing: I think that that the first expected values be `[0,1,1,1,0,1,0,0,1,1]`, and the 2nd to be `[0,0,0,0,0,0,0,0,0,1] or `[0,1,0,0,1,0,0,1,0,1]`, depending on transformNull/drawNullAsZero
> 
> ---
> Reply to this email directly or view it on GitHub:
> https://github.com/graphite-project/graphite-web/pull/866/files#r16633904

-- 
Jason Dixon
http://obfuscurity.com/
https://twitter.com/obfuscurity