anchor.diff:  }
   """
   
  -####
  -# GroupSelectionRegion
  -#
  -# Draws a border around the selected opinion(s)
  -# Shows a bubble mouth for selected opinions or 
  -# a user name + avatar display if we've selected
  -# an individual opinion.
  -GroupSelectionRegion = ReactiveComponent
  -  displayName: 'GroupSelectionRegion'
  -
  -  render : -> 
  -    hist = fetch 'histogram'
  -
  -    has_histogram_focus = hist.selected_opinions || hist.selected_opinion
  -    if has_histogram_focus
  +
  +
  +# top secret proposal creation component
  +EditProposal = ReactiveComponent
  +  displayName: 'EditProposal'
  +
  +  saveProposal : -> 
  +    $el = $(@getDOMNode())
  +
  +    name = $el.find('#name').val()
  +    description = fetch("description-#{@data().key}").html
  +    slug = $el.find('#slug').val()
  +    cluster = $el.find('#cluster').val()
  +    cluster = null if cluster == ""
  +    active = $el.find('#open_for_discussion:checked').length > 0
  +    hide_on_homepage = $el.find('#listed_on_homepage:checked').length == 0
  +
  +    if @props.fresh
  +      proposal =
  +        key : '/new/proposal'
  +        name : name
  +        description : description
  +        cluster : cluster
  +        slug : slug
  +        active: active
  +        hide_on_homepage: hide_on_homepage
  +
  +    else 
  +      proposal = @data()
  +      _.extend proposal, 
  +        cluster: cluster
  +        name: name
  +        slug: slug
  +        description: description
  +        active: active
  +        hide_on_homepage: hide_on_homepage
  +
  +    if @local.roles
  +      proposal.roles = @local.roles
  +      proposal.invitations = @local.invitations
  +
  +    if @local.description_fields
  +      for field in @local.description_fields
  +        edited_html = fetch("field-#{field.id}-html-#{proposal.key}")
  +        field.html = edited_html.html if edited_html.html
  +      proposal.description_fields = JSON.stringify(@local.description_fields)
  +
  +    save proposal, -> 
  +      loadPage "/#{slug}"
  +
  +  render : ->
  +    user = fetch('/current_user')
  +    proposal = @data()
  +    subdomain = fetch '/subdomain'
  +    
  +    if (permit('update proposal', proposal) < 0) || (!@props.fresh && !proposal.slug )
  +      return DIV null, 'Nothing to see here, move on' 
  +
  +    block_style = 
  +      width: CONTENT_WIDTH
  +      padding: '2px 0px'
  +      marginBottom: 12
  +      position: 'relative'
  +
  +    description_field_style =
  +      fontSize: 18
  +      width: CONTENT_WIDTH - 200
  +      padding: 12
  +      marginBottom: 8
  +      border: '1px solid #ccc'
  +
  +    input_style = _.extend {}, description_field_style, 
  +      display: 'block'
  +
  +    label_style =
  +      fontSize: 24
  +      fontWeight: 600
  +      width: 240
  +      display: 'inline-block'
  +      color: focus_blue
  +      marginBottom: 3
  +
  +    operation_style = 
  +      color: '#aaa'
  +      textDecoration: 'underline'
  +      fontSize: 14
  +      cursor: 'pointer'
  +      display: 'block'      
  +
  +
  +    if !@local.description_fields
  +      @local.description_fields = if @data().description_fields 
  +                                    $.parseJSON(@data().description_fields) || [] 
  +                                  else 
  +                                    []
  +      @local.open_fields = []
  +
  +      if @local.description_fields.length > 0
  +        if @local.description_fields[0].group
  +          # Right now, we just downgrade group syntax to flat description list syntax
  +          # TODO: when editing a proposal, support the proposal description groups 
  +          # syntax (or get rid of it)
  +          @local.description_fields = _.flatten \
  +                                         @local.description_fields.map \
  +                                            (group) -> group.items
  +
  +        # Add unique identifiers to each field so we can hide/edit them
  +        for field,idx in @local.description_fields
  +          field.id = idx
  +
  +      save @local
  +
  +    toggleDescriptionFieldOpen = (field, field_open) =>
  +      if field_open
  +        @local.open_fields = _.without @local.open_fields, field.id
  +      else
  +        @local.open_fields.push field.id
  +      save @local
  +
  +    DIV null, 
  +      DashHeader 
  +        name: if @props.fresh then "New Proposal" else "Edit #{proposal.name}"
         DIV 
           style: 
  -          width: BODY_WIDTH + 80
  -          border: "3px solid #{if get_selected_point() then '#ccc' else focus_blue }"
  -          height: '100%'
  -          position: 'absolute'
  -          borderRadius: 16
  -          marginLeft: if lefty then 200 else -BODY_WIDTH/2 - 40
  -          left: if lefty then 0 else '50%'
  -          top: 18
  -
  -        # draw a bubble mouth
  -        if hist.selected_opinions
  -          w = 40; h = 30
  -          left = translateStanceToPixelX(hist.selected_opinion_value, BODY_WIDTH) + 10
  +          width: CONTENT_WIDTH
  +          margin: 'auto'
  +          padding: '3em 0'
  +          position: 'relative'
  +        A 
  +          style: 
  +            color: '#777'
  +            position: 'absolute'
  +            left: -100
  +            top: 54
  +          href: "/#{proposal.slug}"
  +
  +          I
  +            className: 'fa fa-arrow-left'
  +            style: 
  +              paddingRight: 10
  +          'back'
  +
  +
  +        DIV style: block_style,
  +          LABEL htmlFor:'slug', style: label_style, 'URL:'
  +          INPUT 
  +            id:'slug'
  +            name:'slug'
  +            pattern:'^.{3,}'
  +            placeholder: "The URL in #{window.location.origin}/URL. " + \
  +                         "Just letters, numbers, underscores, dashes."
  +            required:'required'
  +            defaultValue: if @props.fresh then null else proposal.slug
  +            style: input_style
  +
  +        DIV style: block_style,
  +          LABEL htmlFor:'name', style: label_style, 'Summary:'
  +          INPUT 
  +            id:'name'
  +            name:'name'
  +            pattern:'^.{3,}'
  +            placeholder:'Aim for 3-8 words with a verb and noun.'
  +            required:'required'
  +            defaultValue: if @props.fresh then null else proposal.name
  +            style: input_style
  +
  +        DIV style: block_style,
  +          LABEL htmlFor:'description', style: label_style, 'Description:'
  +          
  +          WysiwygEditor
  +            key:"description-#{proposal.key}"
  +            placeholder:'Clearly describe the details.'
  +            style: input_style
  +            html: if @props.fresh then null else proposal.description
  +
  +          # Expandable description fields
   
             DIV 
  -            style: cssTriangle 'top', \
  -                               (if get_selected_point() then '#ccc' else focus_blue), \
  -                               w, h,               
  -                                  position: 'relative'
  -                                  top: -32
  -                                  left: left
  -
  -            DIV
  -              style: cssTriangle 'top', 'white', w - 1, h - 1,
  -                position: 'relative'
  -                left: -(w - 2)/2
  -                top: 6
  -
  -        # draw a name + avatar display for the selected opinion
  -        else 
  -          place_avatar_opinion_value = \
  -               if hist.selected_opinion_value > 0 then .8 else -.8
  -          left = translateStanceToPixelX(place_avatar_opinion_value, BODY_WIDTH) + 20
  -
  -          avatar_size = 80
  -          user = fetch(fetch(hist.selected_opinion).user)
  -          name = user.name or 'Anonymous'
  -          title = "#{name}'#{if name[name.length - 1] != 's' then 's' else ''} Opinion"
  -
  -          name_width = widthWhenRendered(title, {fontSize: '30px', fontWeight: '600'})
  -
  -          if hist.selected_opinion_value > 0
  -            name_style = 
  -              left: -28 - avatar_size * .5 - name_width 
  -              borderTopLeftRadius: 16
  -              paddingRight: avatar_size * .75
  -              paddingLeft: 18
  -
  -          else
  -            name_style = 
  -              left: avatar_size/4
  -              borderTopRightRadius: 16
  -              paddingLeft: avatar_size * .75
  -              paddingRight: 18
  -                
  -          DIV style: {left: left, position: 'absolute'},
  -
  -            DIV null,
  -              Avatar 
  -                key: user
  -                user: user
  -                hide_tooltip: true
  +            style: 
  +              marginBottom: 20
  +              marginLeft: 45
  +              display: if not fetch('/current_user').is_super_admin then 'none'
  +
  +            for field in @local.description_fields
  +              field_open = field.id in @local.open_fields
  +              DIV 
  +                key: "field-#{field.id}"
  +                style: _.extend({}, block_style, {width: ''}),
  +
  +                I 
  +                  className: "fa fa-#{if field_open then 'minus' else 'plus'}-circle"
  +                  style: 
  +                    position: 'absolute'
  +                    left: -20
  +                    top: 18
  +                    color: '#414141'
  +                    cursor: 'pointer'
  +                  onClick: do (field, field_open) => => 
  +                    toggleDescriptionFieldOpen(field, field_open)
  +
  +                if field_open
  +                  [INPUT
  +                    style: _.extend {}, description_field_style, \
  +                                    {width: description_field_style.width - 45}
  +                    type: 'text'
  +                    id:"field-#{field.id}-label"
  +                    name:"field-#{field.id}-label"
  +                    pattern:'^.{3,}'
  +                    placeholder:'Label'
  +                    required:'required'
  +                    onChange: do(field) => (e) => 
  +                      field.label = e.target.value; save(@local)
  +                    value: field.label
  +
  +                  WysiwygEditor
  +                    key:"field-#{field.id}-html-#{proposal.key}"
  +                    name:"field-#{field.id}-html"
  +                    placeholder:'Text that is shown when expanded'
  +                    style: _.extend {}, description_field_style, \
  +                                    {width: description_field_style.width - 45}
  +                    html: field.html]
  +
  +                else
  +                  DIV 
  +                    style: 
  +                      fontSize: 18
  +                      fontWeight: 600
  +                      cursor: 'pointer'
  +                      marginTop: 12
  +                      marginLeft: 5
  +                      width: description_field_style.width - 45
  +                    onClick: do (field, field_open) => => 
  +                      toggleDescriptionFieldOpen(field, field_open)
  +                    field.label
  +
  +                DIV 
  +                  style: 
  +                    position: 'absolute'
  +                    right: 150
  +                    top: 12
  +
  +                  A
  +                    style: operation_style
  +                    onClick: do (field, field_open) => => 
  +                      toggleDescriptionFieldOpen(field, field_open)
  +                    if field_open then 'close' else 'edit'
  +
  +                  A
  +                    style: operation_style
  +                    onClick: do (field) => =>
  +                      @local.description_fields = \
  +                        _.filter @local.description_fields, \
  +                                 (fld) -> fld.id != field.id
  +                      save @local
  +                    'delete'
  +
  +            SPAN
  +              style: 
  +                color: '#aaa'
  +                cursor: 'pointer'
  +                fontSize: 18
  +                marginLeft: -18
  +
  +              onClick: => 
  +                new_id = 0
  +                for field in @local.description_fields
  +                  new_id += field.id  
  +                new_id += 1
  +                @local.description_fields.push {label: null, html: null, id: new_id}
  +                @local.open_fields.push new_id
  +                save @local
  +
  +              "+ "
  +              SPAN 
                   style: 
  -                  position: 'absolute'
  -                  width: avatar_size
  -                  height: avatar_size
  -                  top: -avatar_size * .75
  -                  left: -avatar_size/4
  -                  zIndex: 99 
  -                  border: "3px solid #{focus_blue}"
  -
  -              DIV 
  -                style: _.extend name_style,
  -                  position: 'absolute'
  -                  backgroundColor: focus_blue
  -                  paddingTop: 8
  -                  paddingBottom: 8
  -                  color: 'white'
  -                  top: -58
  -                  width: name_width + 10 + 18 + avatar_size * .75 + 10
  -
  -
  -                SPAN 
  -                  style: 
  -                    fontSize: 30
  -                  title
  -
  -    else 
  -      SPAN null
  +                  textDecoration: 'underline'
  +                  marginLeft: 7
  +                "Add expandable description section"
  +
  +
  +        DIV style: block_style,
  +          LABEL htmlFor:'cluster', style: label_style, 'Group (optional):'
  +          INPUT 
  +            id:'cluster'
  +            name:'cluster'
  +            pattern:'^.{3,}'
  +            placeholder:'The group to which this proposal belongs, if any.'
  +            defaultValue: if @props.fresh then null else proposal.cluster
  +            style: input_style
  +
  +        DIV style: block_style,
  +          LABEL htmlFor: 'listed_on_homepage', style: label_style, 'List on homepage?'
  +
  +          INPUT 
  +            id: 'listed_on_homepage'
  +            name: 'listed_on_homepage'
  +            type: 'checkbox'
  +            defaultChecked: if @props.fresh then true else !proposal.hide_on_homepage
  +            style: {fontSize: 24}
  +
  +        DIV style: block_style,
  +          LABEL 
  +            htmlFor: 'open_for_discussion'
  +            style: label_style
  +            'Open for discussion?'
  +
  +          INPUT 
  +            id: 'open_for_discussion'
  +            name: 'open_for_discussion'
  +            type: 'checkbox'
  +            defaultChecked: if @props.fresh then true else proposal.active
  +            style: {fontSize: 24}
  +
  +
  +        DIV null, 
  +          SPAN 
  +            style: _.extend {}, label_style,
  +              textDecoration: 'underline'
  +              cursor: 'pointer'
  +              width: 400
  +              position: 'relative'
  +            onClick: => 
  +              @local.edit_roles = !@local.edit_roles
  +              save @local
  +            I 
  +              className: 'fa-child fa'
  +              style: 
  +                position: 'absolute'
  +                left: -25
  +                top: 5
  +
  +            'Permissions and invitations'
  +
  +          DIV 
  +            style: 
  +              width: CONTENT_WIDTH
  +              backgroundColor: '#fafafa'
  +              padding: '10px 60px'
  +              display: if @local.edit_roles then 'block' else 'none' 
  +                  # roles has to be rendered so that default roles 
  +                  # are set on the proposal
  +
  +            ProposalRoles key: @local
  +
  +        DIV null,
  +          INPUT 
  +            className:'button primary_button'
  +            type:'submit'
  +            style: 
  +              width: 300
  +              marginTop: 35
  +            value:"#{if @props.fresh then 'Publish' else 'Update'}"
  +            onClick: @saveProposal
   
   
   Homepage = ReactiveComponent
  
positive.code:       StateGraph()
  
    resetSelection: (e) ->
  
      if !fetch('auth').form
        hist = fetch 'histogram'
  
negative.code:         stroke_width: stroke_width
          dash_array: dash
  
  ####
  # GroupSelectionRegion
  #
  # Draws a border around the selected opinion(s)
  # Shows a bubble mouth for selected opinions or 
  # a user name + avatar display if we've selected
  # an individual opinion.
  GroupSelectionRegion = ReactiveComponent
    displayName: 'GroupSelectionRegion'
  
    render : -> 
      hist = fetch 'histogram'
  
      has_histogram_focus = hist.selected_opinions || hist.selected_opinion
      if has_histogram_focus
        DIV 
          style: 
            width: BODY_WIDTH + 80
            border: "3px solid #{if get_selected_point() then '#ccc' else focus_blue }"
            height: '100%'
            position: 'absolute'
            borderRadius: 16
            marginLeft: if lefty then 200 else -BODY_WIDTH/2 - 40
            left: if lefty then 0 else '50%'
            top: 18
  
          # draw a bubble mouth
          if hist.selected_opinions
            w = 40; h = 30
            left = translateStanceToPixelX(hist.selected_opinion_value, BODY_WIDTH) + 10
  
            DIV 
              style: cssTriangle 'top', \
                                 (if get_selected_point() then '#ccc' else focus_blue), \
                                 w, h,               
                                    position: 'relative'
                                    top: -32
                                    left: left
  
              DIV
                style: cssTriangle 'top', 'white', w - 1, h - 1,
                  position: 'relative'
                  left: -(w - 2)/2
                  top: 6
  
          # draw a name + avatar display for the selected opinion
          else 
            place_avatar_opinion_value = \
                 if hist.selected_opinion_value > 0 then .8 else -.8
            left = translateStanceToPixelX(place_avatar_opinion_value, BODY_WIDTH) + 20
  
            avatar_size = 80
            user = fetch(fetch(hist.selected_opinion).user)
            name = user.name or 'Anonymous'
            title = "#{name}'#{if name[name.length - 1] != 's' then 's' else ''} Opinion"
  
            name_width = widthWhenRendered(title, {fontSize: '30px', fontWeight: '600'})
  
            if hist.selected_opinion_value > 0
              name_style = 
                left: -28 - avatar_size * .5 - name_width 
                borderTopLeftRadius: 16
                paddingRight: avatar_size * .75
                paddingLeft: 18
  
            else
              name_style = 
                left: avatar_size/4
                borderTopRightRadius: 16
                paddingLeft: avatar_size * .75
                paddingRight: 18
                  
            DIV style: {left: left, position: 'absolute'},
  
              DIV null,
                Avatar 
                  key: user
                  user: user
                  hide_tooltip: true
                  style: 
                    position: 'absolute'
                    width: avatar_size
                    height: avatar_size
                    top: -avatar_size * .75
                    left: -avatar_size/4
                    zIndex: 99 
                    border: "3px solid #{focus_blue}"
  
                DIV 
                  style: _.extend name_style,
                    position: 'absolute'
                    backgroundColor: focus_blue
                    paddingTop: 8
                    paddingBottom: 8
                    color: 'white'
                    top: -58
                    width: name_width + 10 + 18 + avatar_size * .75 + 10
  
  
                  SPAN 
                    style: 
                      fontSize: 30
                    title
  
      else 
        SPAN null
  
  ##
  # YourPoints
  