reactive.coffee

Tutorial

Getting Started

Reactive depends on jQuery and Underscore:

<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js'></script>

Reactive is hosted on cdnjs as well, so you can source directly from there:

<script src='//cdnjs.cloudflare.com/ajax/libs/reactive-coffee/1.2.2/reactive-coffee.min.js'></script>

If you're using Bower, you can also add Reactive as a dependency for your project:

bower install --save reactive-coffee

If you're using node (or browserify, etc.), you can install via NPM:

npm install --save reactive-coffee

This will transitively pull in the above dependencies for Reactive (temp. note: bower has issues solving dependency version constraints).

If you are not using server-side CoffeeScript compilation (recommended for production), you can get started quickly with client-side compilation:

<script src='//cdnjs.cloudflare.com/ajax/libs/coffee-script/1.6.3/coffee-script.min.js'></script>
<script type="text/coffeescript">
  # Your code goes here!
</script>

To follow along with these examples and use reactive HTML element tags without having to use their fully qualified name in rx.rxt.tags, include this at the top of your CoffeeScript:

rx.rxt.importTags()

This lets you write:

span 'hello world'

Alternatively, to use without polluting the global namespace (recommended for larger-scale apps), just shorten the namespace prefix:

T = rx.rxt.tags
T.span 'hello world'

The following examples also lift rx.bind out of its namespace:

bind = rx.bind

You can play with the following examples in this minimal jsFiddle.

Cells

The core building block is an observable cell, ObsCell.

x = rx.cell()

A cell is just a container for a value (initialized to undefined above, but you could also have passed in an initial value). You can get/set this value:

x = rx.cell(0)
x.set(3)
x.get() # 3

You can put arbitrary values into cells, such as arrays and objects.

Events

The special thing about observables is that you can subscribe to events on them, where events are fired when the value of the cell changes in some way. For simple cells like the above, there's just a single on-set event type:

subscriptionId = x.onSet.sub ([oldVal, newVal]) ->
  console.log "x was set from #{oldVal} to #{newVal}"

The listener is just a simple callback. All event types take callbacks of a single argument—the type of that argument is event-specific, and in the case of onSet it's a pair of [old value, new value]. The sub method returns a unique identifier for this subscription, which can later be used to unsubscribe a listener:

x.onSet.unsub(subscriptionId)

Once subscribed, you can start reacting to its events. For instance:

firstName = rx.cell('John')
# This ensures .name will always reflect the firstName
firstName.onSet.sub ([oldVal, newVal]) ->
  $('.name').text(newVal)
firstName.set('Jane')

Events immediately invoke a newly added listener to bring them up to speed on the current value, but you can suppress this first invocation with the simple rx.skipFirst utility function:

x.onSet.sub rx.skipFirst ([oldVal, newVal]) -> ...

Dependent Cells

The above is a simple way of observing and responding to events on cells, but it's a bit verbose. In most UIs, you really just want to be able to declaratively express your views in terms of a model (data binding), rather than explicitly manage listeners.

To extend the above example, let's say you now had a displayed name that depended on two cells (comprising your "model"). You could just create explicit subscriptions and listeners:

firstName = rx.cell('John')
lastName = rx.cell('Smith')

updateName = ->
  $('.name').text("#{firstName.get()} #{lastName.get()}")
firstName.onSet.sub -> updateName
lastName.onSet.sub -> updateName

firstName.set('Jane')
lastName.set('Doe')

However, the primary way in which these cells are to be composed is via bind, which lets you simply write an expression or function in terms of the dependent nodes:

fullName = bind -> "#{firstName.get()} #{lastName.get()}"

Now, fullName is always bound to the firstName + lastName. Key here is that no explicit subscription management is necessary. This scales well to more complex dependencies, and is more readable/declarative:

displayName = bind ->
  if showRealName.get()
    "Full name: #{fullName.get()}"
  else
    "Fake name: #{fakeName.get()}"

The bindings are managed such that only the dependent cells that could possibly affect the result are effective dependencies. In this example, at any moment, fullName depends either only on showRealName and fullName or only on showRealName and fakeName. If showRealName is false, changes to firstName and lastName will not trigger a re-render of the .name.

firstName and lastName are source cells that support setting of values. fullName is itself also a cell, but a "read-only" dependent cell that we can bind to some expression of source cells. These do not have a set method.

Dependent cells can in turn be bound to as well:

greeting = bind -> "Welcome back #{fullName.get()}!"

These bindings can form an arbitrary DAG.

Reactive programming is the same concept behind how spreadsheet calculations work, and is similar to the data-binding feature present in many of the other frameworks—which is an effective paradigm for frontend UI development—but instead of being exclusively applied to view components, typically confined to a template language, this is generalized to be a generic way of expressing arbitrary time-varying data structures.

When you set a cell to the same value (value doesn't change), the event is not propagated. This is a useful efficiency boost that assumes/encourages you to think of binds/cells not as reacting to discrete events, but more abstractly as continuous time-varying signals. In general, your cells are encouraged to be deterministic in their effects, if not pure functions altogether.

Transactions

Sometimes you want to make a more complex update on some cells, while preserving certain semantics/invariants over them. For instance, consider two cells representing the balances in two different bank accounts. When transferring funds from one to the other, there will transiently be a moment when the total funds across both will be either greater or less than what it really should be:

a = rx.cell(5)
b = rx.cell(3)
sum = bind -> a.get() + b.get()
# sum should always be 8, but when transferring 1 from a to b...
a.set(a.get() - 1)
# sum is now 7!
b.set(b.get() + 1)
# sum back to 8

To prevent these "glitches" from being visible, we can bundle up the operations into a transaction. Throughout the duration of this transaction, events will not be propagated. For instance:

rx.transaction =>
  a.set(a.get() - 1)
  # sum will not yet have received any events
  b.set(b.get() + 1)
# now sum will have received notifications, but it will see that the `a`
# and `b` still sum to 8.

Arrays and Maps

Cells are the most general type of observable container. However, there are also observable containers with special support for arrays and maps (that is, Javascript objects, which are basically maps). This specialized support is for more efficient and fine-grained event types reflecting changes to particular sub-parts rather than an all-encompassing onSet event whenever any part of the array or map changes.

For instance, arrays commonly have elements inserted into or removed from them, in which case we'd like to avoid re-rendering entire dependent sections of the DOM or otherwise needing to figure out what parts have changed (the relationship between these reactive data structures and DOM UI rendering will be explained in later sections).

Arrays support an onChange event. It fires with a triple [index, removed, added], where index is the offset into the array where the change is happening, removed is the sub-array of elements removed, and added is the sub-array of elements inserted. Example:

xs = rx.array([1,2,3])
xs.onChange.sub ([index, removed, added]) ->
  console.log "replaced #{removed.length} element(s) at offset #{index} with #{added.length} new element(s)"
xs.push(4)
# replaced 0 element(s) at offset 3 with 1 new element(s)

From a declarative point of view, you can define a dependent array to be a mapped transformation of a source array:

ys = xs.map (x) -> 2 * x
# ys.all() is now [2, 4, 6, 8]
xs.push(5)
# ys.all() is now [2, 4, 6, 8, 10]

Besides push as shown in the above example, there are a few other mutation methods built in. Some are modeled after Javascript's Array methods, e.g. splice, while others are new, e.g. insert.

However, for arbitrary transformations of arrays, you can use the update method, which actually does the smart thing and performs a diff between the old and new contents of the array, so as to minimize the downstream dependencies. So in fact, you could implement all other update methods in terms of update. The above push example could also have been written with xs.update(xs.all().concat([4])), and that would have similarly resulted in just a single element insertion in the downstream mapped array.

In the same spirit, you can convert an ObsCell containing an array to a DepArray with cellToArray, which simply maintains the DepArray via the update mechanism (diffing and issuing minimal downstream change events):

cell = rx.cell([1,2,3])
xs = rx.cellToArray(cell)
xs.onChange.sub ([index, removed, added]) ->
  console.log "replaced #{removed.length} element(s) at offset #{index} with #{removed.length} new element(s)"
cell.set(cell.get().concat([4]))
# replaced 0 element(s) at offset 3 with 1 new element(s)

Objects also exist, but are called maps. They are pretty straightforward as regular containers:

months = rx.map()
months.put('Mar', 3)
months.put('Aug', 8)
months.put('Oct', 10)
months.get('Mar') # 3
months.remove('Oct') # 10
months.all() # {"Mar": 3, "Aug": 8}

With maps, there are three different event types:

months = rx.map({"Mar": 3, "Aug": 8})
months.onAdd.sub ([key, val]) ->
  console.log "set #{key} to #{val}"
# set Mar to 3
# set Aug to 8
months.onChange.sub ([key, oldVal, newVal]) ->
  console.log "updated #{key} (which had mapped to #{oldVal}) to #{newVal}"
months.onRemove.sub ([key, val]) ->
  console.log "removed #{key} which had mapped to #{val}"

months.set('May', 5)
# set May to 5
months.set('Mar', 'three')
# updated Mar (which had mapped to 3) to three
months.remove('Oct')
# removed Aug which had mapped to 8

The key to maps is that you can bind to changes to just certain keys. For instance, if you had:

mar = bind -> months.get('Mar')
dec = bind -> months.get('Dec')

Then mar will be re-evaluated only when the "Mar" key is changed/removed, and dec will only when the "Dec" key is inserted.

Object-Oriented Programming: A Pattern for Public and Private cells.

Often, when using an object-oriented approach, one wants to expose values to the user without permitting them to change those values directly. When using reactive, we would also want the user to be able to subscribe listeners. to these private cells. In addition, we still need to be able to set the value of the cell internally. To achieve this, we can make use of rx.bind, which returns a DepCell object. These objects do not have a set method, and thus cannot be directly mutated by the user:

class Incrementer
  constructor: ->
    _value = rx.cell(0) # private field which can be freely changed within this constructor's scope.
    @value = bind => _value.get() # public field; its value mirrors that of _value, but cannot be directly changed by the user.
    @increment = => _value.set(value.get() + 1)

inc = new Incrementer()
inc.value.onSet.sub ([oldVal, newVal]) -> console.log(newVal)
inc.increment() # prints 1
inc.value.set(42) # error, not allowed.

The usefulness of this pattern is not limited to object oriented programming. We can use this any time we wish to return a read-only cell:

autoIncrementedCell = (start) -> 
  value = rx.cell(start)
  setInterval(value.set(value.get() + 1), 1000)
  return bind -> value.get()

c = autoIncrementedCell(0)
c.onSet.sub ([oldVal, newVal]) -> console.log(newVal)

Static Templates

Now for a brief jump to something entirely different from reactive programming....

The "template" system is implemented as an embedded domain-specific language (DSL) in CoffeeScript, which happens to have a syntax that lends itself well to expressing the template structure.

Here's a simple template:

div {class: 'sidebar'}, [
  h2 {}, ['Send a message']
  form {action: '/msg', method: 'POST'}, [
    input {type: 'text', name: 'comment', placeholder: 'Your message'}, []
    select {name: 'recipient'}, [
      option {value: '0'}, ['John']
      option {value: '1'}, ['Jane']
    ]
    button {class: 'submit-btn'}, ['Send']
  ]
]

It translates to the following HTML:

<div class="sidebar">
  <h2>Send a message</h2>
  <form action='/msg' method='POST'>
    <input type='text' name='comment' placeholder='Your message'/>
    <select name='recipient'>
      <option value='0'>John</option>
      <option value='1'>Jane</option>
    </select>
    <button class='submit-btn'>Send</button>
  </form>
</div>

Note how the children of a DOM node are always lists, even when it's just a single text node.

Since this is CoffeeScript, you can embed arbitrary logic:

# Loops:

ul {class: 'friends'},
  for name in names
    li {class: 'friend'}, [name]

# Or equivalently:

ul {class: 'friends'}, names.map (name) ->
  li {class: 'friend'}, [name]

# Conditionals:

div {class: 'profile'}, [
  img {src: "#{user.picUrl}"}, []
  if signedIn
    button {}, ["Add #{user.name}" as a friend."]
  else
    p {}, ["Sign up to connect with #{user.name}!"]
]

Side note: for loops, it's generally better to prefer using .map(), since it's the same interface for both Array and rx.array, and it also creates a unique binding for the element, avoiding a common pitfall with JavaScript/CoffeeScript loops and closures (you can also use CoffeeScript's handy do keyword).

So far we've been feeding full explicit arguments to each tag. They are actually more flexible in what they take. We can clean up a bunch of the syntactic noise in the last example by replacing ['string'] with just 'string', and omitting empty arguments like {} and [] (the remaining argument is treated as the attributes or the contents based on its type):

div {class: 'profile'}, [
  img {src: "#{user.picUrl}"}
  if signedIn
    button "Add #{user.name}" as a friend."
  else
    p "Sign up to connect with #{user.name}!"
]

Tags are really just functions that return DOM elements (wrapped in jQuery objects), so you are free to attach behaviors to them:

$button = button {class: 'submit-btn'}, 'Click Me!'
$button.click -> $(this).text('I been clicked.')

However, since often times you may be working with deeply nested templates structures where it's clumsy to tack on behaviors afterward, you can for convenience supply a function in an attribute named init, which is immediately invoked with the current element bound to this:

table {}, properties.map (prop) ->
  tr [
    td prop.name
    td [
      input {
        type: 'text'
        value: prop.value
        placeholder: 'Enter property value'
        init: -> @blur => setProperty(prop, @val())
      }
    ]
  ]

Since CoffeeScript assignments are expressions and it automatically manages variable scoping, we also have a convenient way of naming elements anywhere in a template structure:

table {}, properties.map (prop) ->
  $row = tr [
    td prop.name
    td [
      input {
        type: 'text'
        value: prop.value
        placeholder: 'Enter property value'
        init: -> @blur =>
          $row.css('opacity', .5)
          setProperty(prop, @val())
      }
    ]
  ]

init was an example of a special attribute. These are just attributes that are intercepted and handled differently from others, which are simply passed on as regular HTML attributes on the DOM element. Besides init, built-in special attributes include:

  • style, which in addition to regular style strings accepts jQuery-style mappings like {fontSize: 10}, so you can write:

    div {
      style: bind ->
        width: score.get()
        color: if team.get() == 'a' then 'red' else 'blue'
        display: 'none' if gameMode.get() != 'running'
    }
    
  • class, which in addition to regular class strings accepts an array of class names (filtering out undefined), e.g.:

    button {
      class: bind -> [
        'btn'
        'btn-primary' if formComplete.get()
      ]
    }
    

    (You can also access this transform directly via rxt.smushClasses.)

  • and all jQuery events: click, focus, mouseleave, keyup, load, etc. So we could have bound the blur event in the earlier example directly (note it also takes a jQuery object as this):

    ...
          input {
            type: 'text'
            value: prop.value
            placeholder: 'Enter property value'
            blur: ->
              $row.css('opacity', .5)
              setProperty(prop, @val())
          }
    ...
    

You can also add your own special attribute by inserting a function into the specialAttrs global structure.

Reactive Templates

Reactive templates tie together the UI-building style from the previous section with the reactive programming primitives from earlier.

Now, you could just write explicit imperative code to transform the DOM in a way that consistently reflects the bindings you're interested in. For instance:

$('body').append(input {
  class: 'name passive'
  type: 'text'
  placeholder: 'Name'
  value: ''
})
displayName.onSet.sub ([oldVal, newVal]) ->
  $('.name').val(newVal)
isActive.onSet.sub ([oldVal, newVal]) ->
  if newVal
    $('.name').removeClass('passive').addClass('active')
  else
    $('.name').removeClass('active').addClass('passive')

However, more complex transformations can become more involved.

names = rx.array(['1','2','3','4','5'])
$('body').append($nameList = div {class: 'name-list'})
spans = names.map (name) -> span name
spans.onChange.sub ([index, added, removed]) ->
  # Homework: fill in logic here for efficiently inserting/removing DOM
  # nodes!

You also shouldn't have to repeatedly code this logic any time you want to make bindings, and it would be much more clear to specify the template declaratively:

$('body').append(
  input {
    class: bind -> "name #{if isActive.get() then 'active' else 'passive'}"
    type: 'text'
    placeholder: 'Name'
    value: bind -> displayName.get()
  }
)

$('body').append(
  div {class: 'name-list'}, names.map (name) ->
    span name
)

You're declaring what the UI should always look like over time, and the system frees you from the responsibility of maintaining this.

Here's another quick example, this one of a todo list. Notice how here we are using a raw array in a cell, rather than an rx.array. This is fine but not as efficient in the face of large arrays.

tasks = rx.cell(['Get milk', 'Take out trash', 'Clean up room'])
$('body').append(
  ul {class: 'tasks'}, bind ->
    for task in tasks.get()
      li {class: 'task'}, "User: #{task}"
)

Any attribute can be a cell:

input {value: bind -> displayName.get()}

Contents can be a cell that returns an array (of strings or elements):

span {}, bind -> [displayName.get()]
div {}, bind -> names.all()

# shorthand:
span bind -> displayName.get()
div bind -> names.all()

or an observable array:

div {}, names
# results in: <div>01234</div>

# shorthand:
div names

div {}, names.map (name) ->
  span {}, [name]
# results in: <div><span>0</span><span>1</span>...</div>

# shorthand:
div names.map (name) ->
  span name

You have very fine-grained control over the re-rendering process. For instance, say we had a model like the following:

class User
  constructor: (id, name) ->
    @id = rx.cell(id)
    @name = rx.cell(name)

class App
  constructor: (users) ->
    @users = rx.array(users)

app = new App([
  new User('John', 0)
  new User('Jane', 1)
])

If we wanted to just re-render individual elements, we could do that with:

select app.users.map (user) ->
  option {value: bind -> "#{user.id.get()}"}, bind -> "#{user.name.get()}"

On the other hand, if we wanted to re-render the entire section whenever anything changed, we could do so with:

select bind -> app.users.all().map (user) ->
  option {value: "#{user.id.get()}"}, "#{user.name.get()}"
Key Lesson: Nested bind/map calls are insulated from outer calls, re-rendering only what's necessary.

As an escape hatch, to insulate some code fn from the current bind context and not subscribe to any dependencies therein, you can use rx.snap(fn). This is evaluated only once:

div {class: 'editor'}, bind -> [
  input {type: 'text', value: snap -> x.get()}
]

Without the snap, anytime x changes, the entire div would be re-rendered, but with a bind, the text box's contents would be re-rendered. snap is the "anti-bind".

Sometimes you will want to append an observable array after some element. Or you may want to make one element among a set conditionally rendered. For these situations, there's a handy rx.flatten utility function:

div {}, rx.flatten [
  h1 {}, 'Header'
  headerItems.map (item) -> ...
  bind -> separator if showSeparator.get()
  h1 {}, 'Footer'
  footerItems.map (item) -> ...
]

(These behaviors may be folded into core rxt behavior if it proves to be a sensible default.)

More on Arrays and Reactive Templates

Arrays also support an indexed method which returns a copy of the array, but which actually tracks the indices of its elements, such that when you map the array, the mapper function is given the index (as a reactive cell) in addition to the current element. This way you can react to shifts in the position of each element.

For instance, if you had a list where you wanted the rows to be styled based on whether they're prime:

xs = rx.array(...)
ul xs.indexed().map (x,i) ->
  li {class: bind -> if isPrime(i.get()) then 'prime' else ''}, x
# shifts the entire array, but still only prime rows have class "prime"
xs.removeAt(0)

This is not built into map since it would make maps more expensive, and in general this is a less-frequently used feature.

Components

Making reusable components is as simple as defining a function, where the convention is to pass in a single named argument object, as opposed to regular arguments, since components have a tendency to demand a fairly unwieldy set of parameters:

#
# tabs: array of tab contents, where each tab content is itself an array of
#   elements or text
# initialTabIndex: index of initial tab; defaults to 0
# activeClass: class to set an active tab; defaults to 'active-tab'
# change: a callback that is called whenever the active tab is changed,
#   and is passed the new active tab index
#

tabs = (opts) ->
  opts = _(opts).defaults
    initialTabIndex: 0
    activeClass: 'active-tab'
    change: ->
  opts = rx.rxt.cast opts,
    tabs: 'array'

  activeTabIndex = rx.cell(opts.initialTabIndex)

  div {class: 'tabs'}, [
    ul {class: 'nav-tabs'}, opts.tabs.map ([tabName, tabContents], i) ->
      li {
        class: bind ->
          [
            "nav-tab"
            "#{if activeTabIndex.get() == i then opts.activeClass else ''}"
          ].join(' ')
        click: ->
          activeTabIndex.set(i)
          opts.change(i)
      }, [tabName]
    div {class: 'tab-content'}, bind ->
      [tabName, tabContents] = opts.tabs.at(activeTabIndex.get())
      tabContents
  ]

Above, we used a convenience function rxt.cast which lets us cast inputs to the desired observable data type (cell or array).

Now we can use this with:

modifyTab = -> ['MODIFY']
createTab = -> ['CREATE']
stylesTab = -> ['STYLES']

tabs {
  activeClass: 'my-active-tab'
  tabs: rx.array([
    ['Properties', modifyTab()]
    ['Create', createTab()]
    ['Styles', stylesTab()]
  ])
}

When defining abstractions, it's almost always better to err on the side of making everything dynamic, since you can always opt-out of dynamism by stopping propagation (e.g. with snap or with hoisting things out of a bind), whereas you cannot later reintroduce dynamism into places with no dynamic bindings.

Binding To DOM Element Attributes

We can treat certain interactive DOM elements' attributes as cells, thus binding to them as well.

Consider a type-ahead search component, where the completion list only displays items that prefix-match the given query. Furthermore, we want the completion list to only show up if it's enabled by the checkbox and when we actually have focused on the input text field:

class Doc
  constructor: (@title, @url) ->

docs = [
  new Doc('An axiomatic basis for computer programming', 'http://sigpl.or.kr/school/2005w/slides/2_17_1.pdf')
  new Doc('The next 700 programming languages', 'http://www.thecorememory.com/Next_700.pdf')
  new Doc('A theory of type polymorphism in programming', 'http://courses.engr.illinois.edu/cs421/sp2012/project/milner-polymorphism.pdf')
  new Doc('A semantics of multiple inheritance', 'http://lucacardelli.name/Papers/Inheritance.pdf')
]

$('body').append(
  div {class: 'search'}, [
    $query = input {type: 'text', placeholder: 'Enter query'}
    $showResults = input {type: 'checkbox', id: 'show-results'}
    label {for: 'show-results'}, 'Show type-ahead results'
    div {class: 'results'}, bind ->
      focused = $query.rx('focused')
      console.log 'firing', focused
      if focused.get() and $showResults.rx('checked').get()
        for doc in docs when doc.title.indexOf($query.rx('val').get()) >= 0
          div [
            a {href: doc.url}, doc.title
          ]
      else
        []
  ]
)

We are using three different types of reactive element attributes. rx(property) returns the value of the given property (focused, checked, val) as a cell.

Lifting

Often times your models will consist of objects or instances with various observable fields. For instance, consider the User class defined earlier:

class User
  constructor: (id, name) ->
    @id = rx.cell(id)
    @name = rx.cell(name)

You can alternatively take advantage of the dynamic runtime and use the meta-facility rx.lift to convert a plain old Javascript object containing non-observable fields to one with observable fields:

x = {a:0, b:[], c:{}, d:null}
rx.lift(x) # also returns x
x.a.get() # 0
x.b.all() # []
x.c.get() # {}
x.d.get() # null

It also makes writing User above simpler:

class User
  constructor: (@id, @name) -> rx.lift(@)
new User(0, 'Joe').name.get() # Joe

By default, fields that are arrays are turned into rx.array, while others are turned into rx.cell. You can control/refine how fields are lifted by passing in a spec (by default, uses rx.liftSpec to generate one). See the API documentation for more details.

Anti-Pattern: Non-Nesting

Do not construct UIs "out-of-band" from the bind hierarchy:

namedisp = span {class: 'name'}, username.get()
popup = div {class: 'modal'}, bind -> namedisp

The above will either

  • fail to ever update namedisp, assuming there is no outer bind running this code, or
  • cause any outer bind running this code (not shown) to re-evaluate (likely unintended).

This doesn't mean you always need to syntactically nest your code in the following way:

popup =
  div {class: 'modal'}, bind ->
    span {class: 'name'}, username.get()

Instead, you can maintain the original structure of the code, but just defer running the code until you're inside the bind, using functions:

namedisp = -> span {class: 'name'}, username.get()
popup = div {class: 'modal'}, bind -> namedisp()

Next Steps

Congrats on making it all the way through the basic tutorial! You can continue to learn more about "advanced" concepts (really just more details), or read more on the motivation/design rationale behind the library.

Otherwise, go forth and build some web apps using Reactive! Drop us a line if you do and would like to share your work on the website.