scriptencoding utf-8

set foldmethod=manual

call org#buffer#init()
call org#windows#init()

set noswapfile

setlocal ignorecase         " searches ignore case
setlocal smartcase          " searches use smart case
setlocal autoindent 
setlocal fileformat=unix
setlocal backspace=2
setlocal nowrap
setlocal tw=78
setlocal expandtab
setlocal nosmarttab
setlocal softtabstop=0 
setlocal foldcolumn=1 
setlocal tabstop=4   
setlocal shiftwidth=4
setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^\\s*\\-\\s\\+
setlocal indentexpr=
setlocal foldexpr=org#fold#level(v:lnum)
"setlocal iskeyword+=<
setlocal nocindent
setlocal iskeyword=@,39,45,48-57,_,129-255


" LINE BELOW IS MAJOR IF THAT ENCOMPASSES MOST OF org.vim
" endif is near bottom of document
" everything in between is executed only the first time an
" org file is opened
if !exists('g:org_loaded')
" Load the checkbox plugin
execute 'runtime ftplugins/vo_checkbox.vim'

" set calfunc depending on which calendar version installed
if exists(':Calendar')==2 
    if exists('*Calendar')>0 
        let s:Calfunc=function('Calendar')
    else " we have to assume it's more recent version
        let s:Calfunc=function('calendar#show')
    endif
    if !exists('g:calendar_navi') 
        let g:calendar_navi=''
    endif    
endif    

function! s:SID()
    return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfun
let g:org_sid = s:SID()
let sid='<SNR>' . g:org_sid . '_'
function! OrgSID(func)
    execute 'call <SNR>'.s:SID().'_'.a:func
endfunction

if has('win32') || has('win64')
    let s:cmd_line_quote_fix = '^'
else
    let s:cmd_line_quote_fix = ''
endif
let g:org_filename_wildcards = ['*.org']
let s:sfile = expand("<sfile>:p:h")
let s:last_refile_point = []
let g:org_todos_done_dict = {}
let g:org_todos_notdone_dict = {}
let g:org_agenda_todos_done_pattern = ''
let g:org_agenda_todos_notdone_pattern = ''
let g:org_clock_history=[]
let g:org_reverse_note_order = 0
let g:org_html_app=''
let g:org_pdf_app=''
let s:org_headMatch = '^\*\+\s'
let s:org_cal_date = '2000-01-01'
let g:org_export_babel_evaluate = 1
let g:org_tag_group_arrange = 0
let g:org_first_sparse=1
let g:org_clocks_in_agenda = 0
let s:remstring = '^\s*:\S'
let s:block_line = '^\s*\(:\|DEADLINE\|SCHEDULED\|CLOSED\|<\d\d\d\d-\|[\d\d\d\d-\)'
"let s:remstring = '^\s*\(:\|DEADLINE:\|SCHEDULED:\|CLOSED:\|<\d\d\d\d-\)'
let g:org_use_calendar = 1
let g:org_todoitems=[]
let s:headline = ''
let g:org_ColumnHead = 'Lines'
let g:org_gray_agenda = 0
let g:org_sparse_lines_after = 10
let g:org_log_todos=0
let g:org_timegrid=[8,20,2]
let w:v.org_colview_list = []
let s:firsttext = ''
let g:org_supported_link_types = '\(http\|file\|mailto\)'
let g:org_unsupported_link_types = '\(vm\|wl\|mhe\|rmail\|gnus\|bbdb\|irc\|info\|shell\|elisp\)'


let w:v.org_item_len=100
let w:sparse_on = 0
let g:org_folds = 1
let g:org_show_fold_lines = 1
let g:org_columns_default_width = 15
let s:org_columns_master_heading = 0
let w:v.org_colview_list=[]
let g:org_show_fold_dots = 0
let g:org_show_matches_folded=1
let g:org_indent_from_head = 0
let g:org_agenda_skip_gap = 2
let g:org_agenda_days=7
let g:org_agenda_minforskip = 8

let g:org_show_balloon_tips=1
let g:org_datelist = []
let g:org_search_spec = ''
let g:org_deadline_warning_days = 3
let s:org_weekdays = ['mon','tue','wed','thu','fri','sat','sun']
let s:org_weekdaystring = '\cmon\|tue\|wed\|thu\|fri\|sat\|sun'
let s:org_months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']
let s:org_monthstring = '\c\(jan\|feb\|mar\|apr\|may\|jun\|jul\|aug\|sep\|oct\|nov\|dec\)\S*'
let s:include_inherited_props=0
let s:AgendaBufferName = "__Agenda__"
let s:sparse_lines = {}
let s:search_list = []
let s:last_search_list = []

"testing stuff
function! CustomSearchesSetup()
    let g:org_custom_searches = [
                \    { 'name':"Next week's agenda", 'type':'agenda', 
                \                'agenda_date':'+1w','agenda_duration':'w'}
                \    ,{ 'name':"Next week's TODOS", 'type':'agenda', 
                \                'agenda_date':'+1w','agenda_duration':'w','spec':'+UNFINISHED_TODOS'}
                \    , { 'name':'Home tags', 'type':'tags', 'spec':'+HOME'}
                \    , { 'name':'Home tags', 'type':'sparse_tree', 'spec':'+HOME'}
                \    , [ { 'name':"Next week's agenda", 'type':'agenda', 
                \                'agenda_date':'+1w','agenda_duration':'w'}
                \        ,{ 'name':'Home tags', 'type':'tags', 'spec':'+HOME'}
                \      ]   
                \    ,  [ { 'name':'Home tags', 'type':'tags', 'spec':'+HOME'}
                \        ,{ 'name':"Next week's agenda", 'type':'agenda', 
                \                'agenda_date':'+1w','agenda_duration':'w'}
                \      ]   
                \           ]
endfunction
function! s:RunCustom(search)
    " search arg is either number of predefined custom search,
    " or full spec for search from agenda dashboard
    if type(a:search) == type(1)
        let search_spec = g:org_custom_searches[a:search]
    else
        let search_spec = a:search
    endif
    
    if !exists("g:agenda_files") || (g:agenda_files == [])
        if has('dialog_con') || has('dialog_gui')
            unsilent call confirm("No agenda files defined.  Will add current file to agenda files.")
        endif
        call s:CurfileAgenda()
    endif

    if type(search_spec) == type({})
        "single spec
        let s:search_list = [ search_spec ]
    else
        " block agenda specs
        let s:search_list = search_spec
    endif

    let this_time_list = s:search_list
    if this_time_list[0].type !~ 'sparse_tree'
        let curfile = expand("%:p")
        let curtab = tabpagenr()
        let curwin = winnr()
        :AAgenda
        " delete redo block (always just one) if any
        if get(this_time_list[0],'redo_num') > 0
            "redo_num is block in agenda to redo
            let redo_num = s:AgendaBlockNum(this_time_list[0].redo_num)
            normal gg
            if redo_num > 1
                for i in range(1,redo_num - 1)
                    call search('^==============','','')
                endfor
            endif
            let start_line = (line('.') == 1) ? 1 : line('.') + 1
            let test_end = search('^=========','W','')
            let end_line = test_end > 0 ? test_end - 1 : line('$')
            silent exec start_line . ',' . end_line . 'delete'
            call append(start_line - 1,['',''])  " append to agenda buf
            let s:agenda_insert_point = start_line 
        elseif len(this_time_list) == 1
            silent exec '%d'
            let s:agenda_insert_point = 1
        else
            let s:agenda_insert_point = line('$')
        endif
    endif

    let i = 0
    for item in this_time_list
        if i > 0 
            call append(line('$'),['',repeat('=',70),'',''])  " append to agenda buf
            let s:agenda_insert_point = line('$')
        endif
        let mydict = item
        if mydict.type ==? 'agenda'
            let mydate = DateCueResult( get(mydict,'agenda_date',''), s:Today())
            let mydur = get(mydict, 'agenda_duration','w')
            let mydur = (mydur == 'w') ? '7' : (mydur == 'd' ? '1' : mydur)
            
            call OrgRunAgenda( mydate, 
                            \  get(mydict, 'agenda_duration', 'w'),
                            \  get(mydict, 'spec','')  )
            let save_line = line('.')
            let last_line = search('^============','W','') - 1
            exec (last_line <= 0) ? line('$') : last_line
            if (g:org_agenda_include_clocktable == 1) 
                call append(line('.'),OrgGetClocktable(g:agenda_files,' :narrow 40! :tstart ' . '"<' . mydate . ' xxx 00:00>" :tend "<' . calutil#cal(calutil#jul(mydate) + mydur ) . ' xxx 00:00>" :link ')[3:-3])
            endif
            exec save_line
        elseif mydict.type ==? 'sparse_tree'
            call OrgRunSearch( mydict.spec, 1 )
        elseif mydict.type ==? 'sparse_tree_regex'
            silent call s:SparseTreeRun(mydict.spec)
        elseif mydict.type ==? 'tags'
            call OrgRunSearch( mydict.spec )
        elseif mydict.type ==? 'tags-todo'
            " add todos to spec
            call OrgRunSearch( mydict.spec,'agenda_todo' )
        endif
        let i += 1
    endfor
    set foldlevel=999
    execute s:agenda_insert_point
    nohl   
endfunction
"Section Tag and Todo Funcs
function! OrgProcessConfigLines()
    let b:v.org_config_lines = []
    let b:v.todoitems = []
    silent g/^#+/call add( b:v.org_config_lines, getline(line('.')) )
    
    " clear out for new tag settings
    let b:v.tagdict = {}
    let b:v.buf_tags_static_spec = ''
    let b:v.tagchars=''
    let b:v.tags_order = []
    if g:org_tags_alist ==# ''
        let b:v.dynamic_tags=1
    else
        let b:v.dynamic_tags=0
    endif
    
    for line in b:v.org_config_lines
        if line =~ '^#+CATEGORY'
            let b:v.buffer_category = matchstr( line ,'^#+CATEGORY:\s*\zs.*')
            let b:v.org_inherited_defaults['CATEGORY'] = b:v.buffer_category
        elseif line =~ '^#+COLUMNS'
            let b:v.buffer_columns = matchstr( line ,'^#+COLUMNS:\s*\zs.*')
            let b:v.org_inherited_defaults['COLUMNS'] = b:v.buffer_columns
            "let w:v.org_current_columns = b:v.buffer_columns
        elseif line =~ '#+STARTUP:'
            let startup_list = split(matchstr( line, '#+STARTUP:\s*\zs.*') )
            for item in startup_list
               silent! exec "let b:v." . item . "=1"
            endfor
        elseif line =~ '#+TAGS:'
            let newtags = matchstr( line, '#+TAGS:\s*\zs.*') 
            if newtags ==# ''
                let b:v.dynamic_tags = 1
            else
                let b:v.buf_tags_static_spec .= newtags . ' \n '
            endif
        elseif line =~ '\(#+TODO:\|#+SEQ_TODO:\)'
            call OrgTodoSetup(matchstr(line,'\(#+TODO:\|#+SEQ_TODO:\)\s*\zs.*'))
        elseif line =~ '#+PROPERTY:'
            let m = matchlist(line,'.\{-}:\s*\(.\{-}\)_ALL \(.*\)')
            if m[2] ># ''
               let b:v.prop_all_dict[toupper(m[1])] = m[2]
            endif
        endif
    endfor
    if empty(b:v.todoitems)
        call OrgTodoSetup(g:org_todo_setup)
    endif

    call OrgTagSetup( b:v.buf_tags_static_spec )

    " get rid of b:v.buffer_category (and columns also) and just use o_i_d var???
    if b:v.buffer_category ==# ''
        let b:v.buffer_category = expand("%:t:r")
    endif

    normal gg
endfunction
function! s:EditProp(property)
    let s:edit_prop = toupper(a:property)
    let propval = get(s:GetProperties(line('.'),0), s:edit_prop,'')
    function! s:PropCompleteFunc(arghead, sd, gf)
        let prop = matchstr(a:sd,'^.\{-}\ze:')
        let valuelist = split(get(b:v.prop_all_dict, s:edit_prop, ''))
        let matches = filter(valuelist, 'v:val =~ a:arghead')
        return join(matches, "\n")
    endfunction
    let myfunc = '<SNR>' . s:SID() . '_PropCompleteFunc'
    let newval = input("Enter value for " . s:edit_prop . ": ", propval, 'custom,' . myfunc)
    if newval != propval
        call s:SetProp(s:edit_prop, newval)
        echo s:edit_prop . " changed to: " newval
    else
        echo s:edit_prop . " not changed."
    endif
endfunction
function! OrgTodoConvert(orgtodo)
    let todolist = []
    let sublist = []
    let b:v.tododict = {}
   " let templist = []
    let temp_list = split(a:orgtodo,'\s\+')

    for item in temp_list
        if item == '|' 
            continue
        endif
        let b:v.tododict[item] = {}
        if matchstr(item,'.*(.)') ==# ''
            let b:v.tododict[item].todotext = item
            let b:v.tododict[item].todochar = ''
        else
            let b:v.tododict[item].todotext = matchstr(item,'.*\ze(.)')
            let b:v.tododict[item].todochar = matchstr(item,'.*(\zs.\ze)')
        endif
    endfor
    " count '|' chars in list, if 0 or 1 then
    " it is like Org-mode format, otherwise
    " sublists are used in non-done slot"
    let bar_count = count(split(a:orgtodo,'\zs'),'|')
    let after_bar = 0
    if bar_count >= 2
        for item in temp_list
           if item != '|'
                call add(sublist,item)
           elseif (item ==? '|') 
               call add(todolist,sublist)
               let sublist = []
           endif
        endfor
    else
        for item in temp_list
           if (item != '|') && (after_bar == 1)
                call add(sublist,item)
            elseif (item != '|') && (after_bar == 0)
                call add(todolist,item)
           elseif (item ==? '|') 
               let sublist = []
               let after_bar = 1
            endif
        endfor
    endif
    if sublist != []
        call add(todolist,sublist)
    endif
    return todolist
endfunction
        
function! OrgTodoSetup(todolist_str)
    let todolist = OrgTodoConvert(a:todolist_str)
    let b:v.todo_setup = a:todolist_str
    "set up list and patterns for use throughout
    let b:v.todoitems=[]
    let b:v.todo_first_letters = ''
    "let b:v.fulltodos=todolist
    let b:v.todocycle=[]
    let b:v.todoMatch=''
    let b:v.todoNotDoneMatch=''
    let b:v.todoDoneMatch=''
    let i = 0
    while i < len(todolist) 
        if type(todolist[i]) == type('abc')
            let thistodo = matchstr(todolist[i],'.*ze(.)')
            let thistodo = b:v.tododict[todolist[i]].todotext
            let todolist[i] = substitute(todolist[i],'(.)','','')
            call add(b:v.todoitems,thistodo)
            call add(b:v.todocycle,thistodo)
            " add to patterns
            "let newtodo = b:v.todoitems[len(b:v.todoitems)-1]
            let newtodo = thistodo
            let b:v.todoMatch .= newtodo . '\|'
            if i < len(todolist) - 1
                let b:v.todoNotDoneMatch .= newtodo . '\|'
                let g:org_todos_notdone_dict[newtodo] = 1
            else
                let b:v.todoDoneMatch .= newtodo . '\|'
                let g:org_todos_done_dict[newtodo] = 1
            endif
        else
            "item is itself a list
            let j = 0
            while j < len(todolist[i])
                let thisitem = b:v.tododict[todolist[i][j]].todotext
                let todolist[i][j] = substitute(todolist[i][j],'(.)','','')
                call add(b:v.todoitems,thisitem )
                if j == 0
                    call add(b:v.todocycle,thisitem)
                endif
                " add to patterns
                let b:v.todoMatch .= thisitem . '\|'
                if i < len(todolist) - 1
                    let b:v.todoNotDoneMatch .= thisitem . '\|'
                    let g:org_todos_notdone_dict[thisitem] = 1
                else
                    let b:v.todoDoneMatch .= thisitem . '\|'
                    let g:org_todos_done_dict[thisitem] = 1
                endif
                let j += 1
            endwhile
        endif
        let i += 1
    endwhile
    let b:v.todoMatch = '^\*\+\s*\zs\('.b:v.todoMatch[:-2] . ')'
    let b:v.todoDoneMatch = '^\*\+\s*\zs\('.b:v.todoDoneMatch[:-2] . ')'
    let b:v.todoNotDoneMatch = '^\*\+\s*\zs\('.b:v.todoNotDoneMatch[:-2] . ')'
    let b:v.fulltodos = todolist

    syntax clear DONETODO
    exec 'syntax match DONETODO /' . b:v.todoDoneMatch[1:] . '/ containedin=OL1,OL2,OL3,OL4,OL5,OL6'
    syntax clear NOTDONETODO
    exec 'syntax match NOTDONETODO /' . b:v.todoNotDoneMatch[1:] . '/ containedin=OL1,OL2,OL3,OL4,OL5,OL6'

    call s:OrgCustomTodoHighlights()
    for item in keys( b:v.tododict )
        let item_char = tolower( b:v.tododict[item].todochar)
        if item_char ==# ''
            let item_char = tolower(item[0])
        endif
    endfor

endfunction
function! s:CurfileAgenda()
    exec "let g:agenda_files=['".expand("%:p")."']"
endfunction

function! OrgTagSetup(tagspec)
       let b:v.tags = split(tr(a:tagspec,'{}','  '),'\s\+') 
       for item in b:v.tags
            if item =~ '('
                let char = matchstr(item,'(\zs.\ze)')
                let tag = matchstr(item,'.*\ze(')
            else
                "find an unused character
                let char = ''
                let tag = item   
                let i = 0
                while i < len(item)
                    "if !has_key(chardict, item[i])
                    " find char that isn't in tagchars yet
                    if b:v.tagchars !~ item[i]
                        let char = item[i]
                        "let chardict[item[i]] = 1
                        break
                    endif
                    let i += 1
                endwhile
                if char ==# ''
                    for i in range(65,90)
                        if b:v.tagchars !~ nr2char(i)
                            let char = nr2char(i)
                            break
                        endif
                    endfor
                endif
            endif
            let b:v.tagdict[item] = {'char':char, 'tag':tag, 'exclude':'', 'exgroup':0}
            call add(b:v.tags_order,item)
            if char != ''
                let b:v.tagchars .= char
            endif
        endfor

       let templist = a:tagspec
       let i = 1
        while templist =~ '{.\{}}'
            "cycle through groups and add exclude chars for any group members
            let strikeout = matchstr(templist,'{.\{-}}')
            let exclusive = matchstr(templist,'{\zs.\{-}\ze}')
            let templist = substitute(templist,strikeout,'','')
            let xlist = split(exclusive,'\s\+')
            for item in xlist
                let b:v.tagdict[item].exgroup = i
                for x in xlist
                    if x != item
                           let b:v.tagdict[item].exclude .= b:v.tagdict[x].char
                    endif
                endfor
            endfor
            let i += 1
        endwhile
endfunction


function! OrgTagsEdit(...)
    let line_file_str = ''
    let lineno=line('.')
    let file = expand("%")
    if bufname("%") ==? ('__Agenda__')
        " new file and lineno below to test with new line marker in agenda
        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
        let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))

        call org#SaveLocation()
        call org#LocateFile(file)
        call s:SetDynamicTags()
        call org#RestoreLocation()

        let b:v.tagdict = getbufvar(file,'v').tagdict
        let b:v.tags_order = getbufvar(file,'v').tags_order
    else
        call s:SetDynamicTags()
    endif
    
    let heading_tags = get(s:GetProperties(lineno,0,file),'TAGS','')
    
    let new_heading_tags = s:TagMenu(heading_tags)
    if new_heading_tags != heading_tags
            silent call s:SetProp('tags',new_heading_tags,lineno, file)
    endif
endfunction

function! s:TagMenu(heading_tags)
    let heading_tags = a:heading_tags
    
    let tagstring = ''
    let tagchars = ''
    for item in b:v.tags_order
        let tagchars .= b:v.tagdict[item].char
        if match(heading_tags,':'.b:v.tagdict[item].tag .':') >= 0
            let tagstring .= b:v.tagdict[item].char
        endif
    endfor

    hi Cursor guibg=black
    let cue = ''
    set nomore
    while 1
        echo repeat('-',winwidth(0)-1)
        echohl Title | echo 'Choose tags:   ' | echohl None | echon '( <enter> to accept, <esc> to cancel )'
        echo '------------'
        let oldgroup = 0
        let items_in_row = 1
        for item in b:v.tags_order
            if item ==? '\n'
                continue
            endif
            let curindex = index(b:v.tags_order,item)
            let newgroup = b:v.tagdict[item].exgroup
            let select = ' '
            if match(tagstring,b:v.tagdict[item].char) >= 0
                let select = 'X'
                echohl Question
            else
                echohl None
            endif
            "if (g:org_tag_group_arrange == 0) || (newgroup != oldgroup) || (newgroup == 0 ) || (b:v.tags_order[curindex+1] ==? '\n')
            if (curindex == 0) || (b:v.tags_order[curindex-1] ==? '\n') || (winwidth(0) - (items_in_row*20) < 20)
                echo repeat(' ',3) . '[' | echohl Question | echon select | echohl None | echon '] ' 
                echohl None | echon b:v.tagdict[item].tag | echohl Title | echon '('.b:v.tagdict[item].char.')' | echohl None
                let nextindent = repeat(' ',12-len(b:v.tagdict[item].tag))
                let items_in_row = 1
            else    
                "echon repeat(' ',3) . 
                echon nextindent
                echon '[' | echohl Question | echon select | echohl None | echon '] ' 
                echohl None | echon b:v.tagdict[item].tag | echohl Title | echon '('.b:v.tagdict[item].char.')' | echohl None
                let nextindent = repeat(' ',12-len(b:v.tagdict[item].tag))
                let items_in_row += 1
                "echon repeat(' ', 12-len(b:v.tagdict[item]))
            endif
            let oldgroup = b:v.tagdict[item].exgroup
        endfor
        echo ""
            "echohl LineNr | echon 'Date+time ['.basedate . ' '.basetime.']: ' 
            "echohl None | echon cue.'_   =>' | echohl WildMenu | echon ' '.newdate.' '.newtime
            let nchar = getchar()
            let newchar = nr2char(nchar)
            if (nchar ==? "\<BS>") && (len(cue)>0)
                let cue = cue[:-2]
            elseif nchar ==? "\<s-c-up>"
                let cue = ((curdif-365>=0) ?'+':'').(curdif-365).'d'
            elseif newchar ==? "\<s-cr>"
                " add new tag . . . todo . . .
            elseif newchar ==? "\<cr>"
                break
            elseif newchar ==? "\<Esc>"
                hi Cursor guibg=gray
                redraw
                return a:heading_tags
            elseif (match(tagchars,newchar) >= 0) 
                if (match(tagstring,newchar) == -1) 
                    let tagstring .= newchar
                    " check for mutually exclusve tags
                    for item in keys(b:v.tagdict)
                        if b:v.tagdict[item].char ==? newchar
                            let exclude_str = b:v.tagdict[item].exclude
                            let tagstring = tr(tagstring,exclude_str,repeat(' ',len(exclude_str)))
                            break
                        endif
                    endfor
                else
                    let tagstring = tr(tagstring,newchar,' ')
                endif
            endif
            call substitute(tagstring,' ','','')
            echon repeat(' ',72)
            redraw
    endwhile

    hi Cursor guibg=gray
    redraw
    echo 
    set more

    let heading_tags = ''
    for item in keys(b:v.tagdict)
        if (item!='\n') && (match(tagstring, b:v.tagdict[item].char) >= 0)
            let heading_tags .= b:v.tagdict[item].tag . ':'
        endif
    endfor
    if heading_tags ># '' | let heading_tags = ':' . heading_tags | endif
    return heading_tags
endfunction

function! s:SetDynamicTags()
    let taglist = s:GetBufferTags()
    let chardict = {}
    let b:v.tagdict = {}
    let b:v.tagchars = ''
    let b:v.tags_order = []

    if b:v.buf_tags_static_spec ==# ''
        let static_tags = g:org_tags_alist . ' ' . g:org_tags_persistent_alist
        if static_tags ==# ''
            let b:v.dynamic_tags_only = 1
        endif
    elseif exists('b:v.noptags')
        let static_tags = b:v.buf_tags_static_spec
    else
        let static_tags = b:v.buf_tags_static_spec . ' ' . g:org_tags_persistent_alist
    endif

    if exists('b:v.dynamic_tags_only') && (b:v.dynamic_tags_only == 1)
        let setup_string = join(taglist)
    elseif exists('b:v.dynamic_tags') && (b:v.dynamic_tags == 1)
        "first need to remove dups in dynamic taglist
        let temp_list = split(static_tags)
        for i in range(0,len(temp_list)-1)
            if temp_list[i] =~ '(.)'
               let temp_list[i] = matchstr(temp_list[i],'^.*\ze(')
            endif
        endfor
        let dup_list = s:Intersect( temp_list, taglist )
        for item in dup_list
            call remove( taglist, index(taglist, item) )
        endfor
        let setup_string =  static_tags . ' ' . join(taglist) 
    else
        let setup_string = static_tags
    endif

    call OrgTagSetup( setup_string )

endfunction
        
function! s:GetBufferTags()
    let save_cursor = getpos(".") 
    let b:v.buftagdict = {}
    " call addtags for each headline in buffer
    g/^\*/call s:AddTagsToDict(line("."))
    call setpos('.',save_cursor)
    return sort(keys(b:v.buftagdict))
endfunction
inoremap <F5> <C-R>=OrgEffort()<CR>
noremap <F5> A<C-R>=OrgEffort()<CR>
function! OrgEffort()
    if getline(line('.'))=~':Effort:'
        call setline(line('.'), substitute(getline(line('.')),'ort:\zs.*','',''))
        normal A  
        call complete(col('.'),b:v.effort)
    endif
    return ''
endfunction
function! s:AddTagsToDict(line)
    let taglist = s:GetTagList(a:line)
    if !empty(taglist)
        for item in taglist
            execute "let b:v.buftagdict['" . item . "'] = 1"
        endfor
    endif
endfunction

function! s:GetTagList(line)
    let text = getline(a:line+1)
    if (text !~ b:v.drawerMatch) && (text !~ b:v.dateMatch) && (text =~ s:remstring)
        let tags = matchlist(text,':\(\S*\):\s*$')
        " include replacement of mistaken double colons with single colon
        let tagstr = substitute(tags[1],'::',':','g')
        if !empty(tags)
            return split(tagstr,':')
        else
            return []
        endif
    else
        return []
    endif
endfunction
function! s:IsTagLine(line)
    let text = getline(a:line)
    return (text !~ b:v.drawerMatch) && (text !~ b:v.dateMatch) && (text =~ s:remstring)
endfunction
function! s:GetTags(line)
    if s:IsTagLine(a:line+1)
        return matchstr(getline(a:line+1),':.*$')
    else
        return ''
    endif
endfunction
function! s:AddTag(tag,line)
    if s:IsTagLine(a:line + 1)
        if matchstr(getline(a:line+1),':'.a:tag.':') ==# ''
            call setline(a:line+1,getline(a:line+1) . ':' .a:tag. ':')
        endif
    else
        call append(a:line, '     :' . a:tag . ':')
    endif
endfunction
function! s:TagInput(line)
    let linetags = s:GetTagList(a:line)
    if empty(linetags)
        call append(a:line,':')
    endif   
    let buftags = s:GetBufferTags()
    let displaytags = deepcopy(buftags)
    call insert(displaytags,'  Exit Menu')
    while 1
        let curstatus = []
        call add(curstatus,0)
        let i = 1
        let linetags = s:GetTagList(a:line)
        while i < len(buftags) + 1 
            if index(linetags, buftags[i-1]) >= 0 
                let cbox = '[ X ]'
                call add(curstatus,1)
            else
                let cbox = '     '
                call add(curstatus,0)
            endif

            let displaytags[i] = cbox . s:PrePad('&'.buftags[i-1],28)
            let i += 1
        endwhile

        let @/=''
        if foldclosed(a:line) > 0
            let b:v.sparse_list = [a:line]
        else
            normal V
        endif
        redraw
        if foldclosed(a:line) > 0
            let b:v.sparse_list = []
        else
            normal V
        endif
        "call insert(displaytags,'Choose tags below:')
        "let key = inputlist(displaytags) - 1 
        let taglist = join(displaytags,"\n") 
        set guioptions+=v
        let key = confirm('Choose tags:',taglist)-1
        set guioptions-=v
        "call remove(displaytags,0)
        if (key == 0)   " || (key == 1)
            " need setline for final redraw
            call setline(a:line+1,getline(a:line+1))
            redraw
            break
        endif
        let curstatus[key] = 1 - curstatus[key]
        let newtags = ''
        let i = 1
        while i < len(curstatus)
            if curstatus[i] == 1
                let newtags .= ':' . buftags[i-1] . ':'
            endif
            let i += 1
        endwhile
        let newtags = substitute(newtags, '::',':','g')
        call setline(a:line+1, repeat(' ',s:Starcount(a:line)+1) . newtags)

    endwhile
    if empty(s:GetTagList(a:line))
        execute a:line+1 .'d'
        execute a:line
    endif   
endfunction

function! s:UnconvertTags(line)
    if s:IsTagLine(a:line+1)
        normal J
    endif
endfunction
function! <SID>GlobalUnconvertTags(state)
    if exists('g:org_emacs_autoconvert') && (g:org_emacs_autoconvert != 0)
        let s:save_cursor = getpos(".")
        let s:last_changenr = a:state
        mkview
        normal A 
        g/^\*\+\s/call s:UnconvertTags(line("."))
        silent! %s/^\(\s*\):\(DEADLINE\|SCHEDULED\|CLOSED\|CLOCK\|<\d\d\d\d-\d\d-\d\d\)/\1\2/
    endif
endfunction
function! <SID>UndoUnconvertTags()
    if exists('g:org_emacs_autoconvert') && (g:org_emacs_autoconvert != 0)
        silent exec 'undo ' . s:last_changenr 
        silent undo
        loadview
        call setpos(".",s:save_cursor)
    endif
endfunction

function! s:ConvertTags(line)
    let tags = matchstr(getline(a:line), '\(:\S*:\)\s*$')
    if tags ># ''
        s/\s\+:.*:\s*$//
        call append(a:line, repeat(' ',s:Starcount(a:line)+1) . tags)
    endif
endfunction
function! <SID>GlobalConvertTags()
    "if exists('g:org_emacs_autoconvert') && (g:org_emacs_autoconvert != 0)
        let save_cursor = getpos(".")
        g/^\*\+\s/call s:ConvertTags(line("."))
        silent! %s/^\(\s*\)\(DEADLINE:\|SCHEDULED:\|CLOSED:\|CLOCK:\|<\d\d\d\d-\d\d-\d\d\)/\1:\2/
        call setpos(".",save_cursor)
    "endif
endfunction
function! s:GlobalFormatTags()
    let save_cursor = getpos(".")
    g/^\*\+\s/call s:FormatTags(line("."))
    call setpos(".",save_cursor)
endfunction
function! s:FormatTags(line)
    let tagmatch = matchlist(getline(a:line),'\(:\S*:\)\s*$')
    if !empty(tagmatch)
        let linetags = tagmatch[1]
        s/\s\+:.*:\s*$//
        " add newtags back in, including new tag
        call setline(a:line,getline(a:line) . '    ' 
                    \ . repeat(' ', winwidth(0) - len(getline(a:line)) - len(linetags) - 15) 
                    \ . linetags)
    endif
endfunction

function! s:FCTest(line)
    if foldclosed(a:line) != a:line
        return a:line . ' ---  ' . foldclosed(a:line)
    endif
endfunction

function! OrgSequenceTodo(line,...)
    if a:0 == 1
        if a:1 ==? 'x'
            let newtodo = ''
        else
            for item in b:v.todoitems
                if item[0] ==? a:1
                    let newtodo = item
                endif
            endfor
        endif
    endif
    let linetext = getline(a:line)
    if (linetext =~ s:org_headMatch) 
        " get first word in line and its index in todoitems
        let tword = matchstr(linetext,'\*\+\s\+\zs\S\+\ze')
        if a:0 == 1
            call s:ReplaceTodo(newtodo)
        else
            call s:ReplaceTodo()
        endif
    endif
endfunction
function! s:NextTodo(curtodo)
    let curtodo = a:curtodo
    " check whether word is in todoitems and make appropriate
    " substitution
    let i = index(b:v.todoitems, curtodo)
    if i == -1
        " Not found -> start with first todo
        let newtodo = b:v.todoitems[0]
    elseif i == len(b:v.todoitems) - 1
        " All cycled -> next is empty
        let newtodo = ''
    else
        let newtodo = b:v.todoitems[i+1]
    endif
    return newtodo
endfunction
function! s:PreviousTodo(curtodo)
    let curtodo = a:curtodo
    " check whether word is in todoitems and make appropriate
    " substitution
    let i = index(b:v.todoitems, curtodo)
    if i == -1
        " Not found -> Start with last todo
        let last = len(b:v.todoitems) - 1
        let newtodo = b:v.todoitems[last]
    elseif i == 0
        " All cycled -> next is empty
        let newtodo = ''
    else
        let newtodo = b:v.todoitems[i-1]
    endif
    return newtodo
endfunction

function! OrgTodoDashboard(...)
    let key = (a:0==1) ? a:1 : ''
    let save_cursor = getpos('.')
    let save_window = winnr()
    if bufname("%") ==? ('__Agenda__')
        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
        let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))
        let buffer_lineno = s:ActualBufferLine(lineno,bufnr(file))
        let b:v.todoitems = getbufvar(file,'v').todoitems
        let b:v.todo_setup = getbufvar(file,'v').todo_setup
        let props = s:GetProperties(buffer_lineno, 0, file)
        let Replace_func = function('s:AgendaReplaceTodo')
    else
        exec s:OrgGetHead()
        let props = s:GetProperties(line('.'),0)
        let Replace_func = function('s:ReplaceTodo')
    endif

    if key ==# ''
        echohl MoreMsg
        echo " ================================="
        echo " Todos defined in this " . (bufname("%") ==? ('__Agenda__') ? "heading's" : "" ) . " document are:"
        echo "    " . b:v.todo_setup
        echo " ================================="
        echo " Press key for a todo command:"
        echo " ---------------------------------"
        echo " f (or n)  cycle current heading's todo Forward/Next"
        echo " b (or p)  cycle current heading's todo Backward/Previous"
        echo " t         mark current heading with initial 'unfinished' state"
        echo " d         mark current heading with main 'finished' state"
        "if bufname("%") !=? ('__Agenda__')
            let i = 1
            for item in b:v.todoitems 
                echo ' ' . i . '   mark current heading as ' . item
                let i += 1
            endfor
        "endif
        echo " "
        echohl Question
        let key = nr2char(getchar())
        redraw
    endif
    "let thisline = getline(line('.'))
    "let curTodo = matchstr(thisline, '\*\+ \zs\S\+')
    
    if key =~? 'f\|n'
        call Replace_func()
    elseif key =~? 'b\|p'
        call Replace_func('todo-bkwd')
    elseif key ==? 't'
        "call Replace_func(b:v.todoitems[0])
        call Replace_func('first-todo')
    elseif key ==? 'd'
        "let done_state = (type(b:v.fulltodos[-1])==type([])) ? b:v.fulltodos[-1][0] : b:v.fulltodos[-1]
        "call Replace_func(done_state)
        call Replace_func('first-done')
    elseif key =~ '[1-9]'
        call Replace_func(b:v.todoitems[key-1])
    else
        echo "No todo action selected."
    endif
    echohl None
    exe save_window . 'wincmd w'
    call setpos('.',save_cursor)
endfunction
function! s:AgendaReplaceTodo(...)
    " wrapper to call OrgAgendaGetText to do todo operation
    "  OrgAgendaGetText does double duty (needs to be
    "  refactored) and both retrieves text from main buffer
    "  and handles todo replacements
    if bufname('%') != '__Agenda__'
        echo "Not in agenda, can't use AgendaReplaceTodo"
        return
    endif
    if empty(b:v.heading_marks_dict)
        " just mark and do current item
        let b:v.heading_marks_dict[line('.')] = 1
    endif

    for item in sort(keys(b:v.heading_marks_dict), 's:ReverseSort')
        " go to the line first, then process
        exec item   
        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
        let b:v.fulltodos = getbufvar(file,'v').fulltodos
        let b:v.todoitems = getbufvar(file,'v').todoitems
        let todoword = matchstr(getline(line('.')), '.* \*\+ \zs\S\+')
        if a:0 == 0
            let newtodo = 'todo-fwd'
        else
            let newtodo = a:1
        endif
        if newtodo == 'todo-fwd'
            let newtodo = s:NextTodo(todoword)
        elseif newtodo == 'todo-bkwd'
            let newtodo = s:PreviousTodo(todoword)
        elseif newtodo == 'first-todo'
            let newtodo = b:v.todoitems[0]
        elseif newtodo == 'first-done'
            let newtodo = (type(b:v.fulltodos[-1])==type([])) ? b:v.fulltodos[-1][0] : b:v.fulltodos[-1]
        else
            let newtodo = a:1
        endif
        call OrgAgendaGetText(1,newtodo)
        execute 'sign unplace ' . item . ' buffer=' . bufnr('%')
    endfor
    let b:v.heading_marks_dict = {}

endfunction
function! s:ReplaceTodo(...)
    "a:1 would be newtodo word
    let save_cursor = getpos('.')
    if getline(line('.'))[0] == '*'
        exec s:OrgGetHead()
    endif
    let thisline = getline(line('.'))
    if bufname("%") !=? '__Agenda__'
        let todoword = matchstr(thisline, '\*\+ \zs\S\+')
    else
        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
        " fulltodos needed for s:NewTodo()
        let b:v.fulltodos = getbufvar(file,'v').fulltodos
        let b:v.todoitems = getbufvar(file,'v').todoitems
        let todoword = matchstr(thisline, '.* \*\+ \zs\S\+')
    endif

    if a:0 == 0
        let newtodo = 'todo-fwd'
    else
        let newtodo = a:1
    endif
    if newtodo == 'todo-fwd'
        let newtodo = s:NextTodo(todoword)
    elseif newtodo == 'todo-bkwd'
        let newtodo = s:PreviousTodo(todoword)
    elseif newtodo == 'first-todo'
        let newtodo = b:v.todoitems[0]
    elseif newtodo == 'first-done'
        let newtodo = (type(b:v.fulltodos[-1])==type([])) ? b:v.fulltodos[-1][0] : b:v.fulltodos[-1]
    else
        let newtodo = a:1
    endif

    " if going to main done state check for repeater and change date if necessary
    if  (bufnr("%") != bufnr('Agenda')) && (newtodo =~ b:v.todoDoneMatch[11:])
        let newtodo = s:CheckDateRepeaterDone(todoword, newtodo)
    endif
    let s:last_newtodo = newtodo    " used to set agenda line in next pass from agenda

    if newtodo ># ''
        let newtodo .= ' '
    endif
    if (index(b:v.todoitems,todoword) >= 0) 
        if newtodo ># ''
            let newline = substitute(getline(line(".")),
                        \ '\* ' . todoword.' ',
                        \ '\* ' . newtodo,'g')
        else
            let newline = substitute(getline(line(".")),
                        \ '\* ' . todoword.' ',
                        \ '\* ' . '','g')
        endif
    else
        let newline = substitute(getline(line(".")),
                    \ '\zs\* \ze\S\+', 
                    \ '\* ' . newtodo ,'g')
    endif


    call setline(line("."),newline)
    if exists("*Org_after_todo_state_change_hook") && (bufnr("%") != bufnr('Agenda'))
        let Hook = function("Org_after_todo_state_change_hook")
        call Hook(line('.'),todoword,newtodo)
    endif

    call setpos('.',save_cursor)
endfunction
function! s:CheckDateRepeaterDone(state1,state2)
    "check for date repeater on change of todo to done state
    " and handle logging and resetting of date"
    let newtodo = a:state2
    let props = s:GetProperties(line('.'),0)
    let repeat_pattern = '\d\d\d\d-\d\d-\d\d.*[ +.]+\d\+\S\+.*'
    for dateprop in ['DEADLINE','SCHEDULED','TIMESTAMP']
        let thisdate = get(props,dateprop)
        if thisdate =~ repeat_pattern
            "put in log note
            call OrgConfirmDrawer("LOGBOOK")
            let str = ":- State: " . printf('%.10s','"'.a:state2.'"') . "   from: " . printf('%.10s','"'.a:state1.'"') .
                        \ '    [' . org#Timestamp() . ']'
            call append(line("."), repeat(' ',len(matchstr(getline(line(".")),'^\s*'))) . str)
            exec s:OrgGetHead()
            let newtodo = b:v.todocycle[0]
            "change date as appropriate
            let basedate = matchstr(thisdate,'\d\d\d\d-\d\d-\d\d')
            let cue = '+' . matchstr(thisdate,'+\d*[dwmy]')
            if     thisdate =~ ' +\d*[dwmy]'
                let newdate = DateCueResult(cue,basedate)
            elseif thisdate =~ '\.+\d*[dwmy]'
                let newdate = DateCueResult(cue,org#Timestamp()[0:9])
            elseif thisdate =~ '++\d*[dwmy]'
                let newdate = DateCueResult(cue,basedate)
                let i = 0
                while newdate <= org#Timestamp()[0:9]
                    if i == 9
                        unsilent call confirm('Ten adjustments failed to bring to future date.')
                        break
                    endif
                    let newdate = DateCueResult(cue,newdate)
                    let i += 1
                endwhile
            endif
            let mydow = calutil#dayname(newdate)
            call s:SetProp(dateprop,'<' . newdate . ' ' . mydow . thisdate[14:] . '>')
            " break as soon as one repeater is found
            unsilent call confirm('Repeater date: entering log and resetting date.')
            break
        endif
    endfor
    return newtodo
endfunction

"Section Navigation Funcs
"
function! s:OrgSubtreeLastLine()
    " Return the line number of the next head at same level, 0 for none
    return s:OrgSubtreeLastLine_l(line("."))
endfunction

function! s:OrgSubtreeLastLine_l(line)
    if a:line == 0
        return line("$")
    endif
    let l:starthead = s:OrgGetHead_l(a:line)
    let l:stars = s:Starcount(l:starthead) 
    let l:mypattern = substitute(b:v.headMatchLevel,'level', '1,'.l:stars, "")    
    let l:lastline = s:Range_Search(l:mypattern,'nW', line("$"), l:starthead) 
    " lastline now has NextHead on abs basis so return end of subtree
    if l:lastline != 0 
        let l:lastline -= 1
    else
        let l:lastline = line("$")
    endif
    return l:lastline

endfunction

function! s:HasAncestorHeadOf(line,ancestor)
    let ultimate = s:OrgUltimateParentHead_l(a:line)
    if (a:line < a:ancestor) || (a:ancestor < ultimate)
        let result = 0
    elseif (a:line == a:ancestor)
        let result = 1
    else
        let test_ancestor = s:OrgParentHead_l(a:line) 
        while 1
            if (test_ancestor == a:ancestor)
               let result = 1
               break
            elseif test_ancestor < ultimate 
               let result = 0
               break
            endif
            let test_ancestor = s:OrgParentHead_l(test_ancestor)
        endwhile
    endif

    return result
endfunction
function! s:OrgUltimateParentHead()
    " Return the line number of the parent heading, 0 for none
    return s:OrgUltimateParentHead_l(line("."))
endfunction

function! s:OrgUltimateParentHead_l(line)
    " returns 0 for main headings, main heading otherwise
    let l:starthead = s:OrgGetHead_l(a:line)

    if s:Ind(l:starthead) >  1
        return s:Range_Search('^* ','bnW',1,l:starthead)
    else
        return 0
    endif
endfunction

function! s:OrgParentHead()
    " Return the line number of the parent heading, 0 for none
    return s:OrgParentHead_l(line("."))
endfunction

function! s:OrgParentHead_l(line)
    " todo -- get b:v.levelstars in here
    let l:starthead = s:OrgGetHead_l(a:line)
    let l:parentheadlevel = s:Starcount(l:starthead) - b:v.levelstars
    if l:parentheadlevel <= 0 
        return 0
    else
        let l:mypattern = substitute(b:v.headMatchLevel,'level',l:parentheadlevel,'')
        return s:Range_Search(l:mypattern,'bnW',1,l:starthead)
    endif
endfunction


function! s:Range_Search(stext, flags, ...)
    " searches range, restores cursor to 
    " beginning position, and returns
    " first occurrence of pattern
    let save_cursor = getpos(".")
    " a:1 and a:2 are stopline and startline
    if a:0 == 2
        let l:stopline = a:1
        " go to startline
        execute a:2 
        normal! $
    elseif a:0 == 1
        let l:stopline = a:1
    else
        let l:stopline = line("$")
    endif
    let l:result =  search(a:stext, a:flags, l:stopline)
    call setpos('.',save_cursor)
    return l:result
endfunction

function! s:OrgGetHead()
    return s:OrgGetHead_l(line("."))
endfunction

function! s:OrgGetHead_l(line)
    if s:IsText(a:line)   
        return s:Range_Search(b:v.headMatch,'nb', 1, a:line)
    else
        return a:line
    endif
endfunction

function! s:OrgPrevSiblingHead()
    return s:OrgPrevSiblingHead_l(line("."))
endfunction
function! s:OrgPrevSiblingHead_l(line)
    if s:Ind(a:line) > 0
        let upperline = s:OrgParentHead_l(a:line)
    else
        let upperline = 0
    endif
    let sibline = s:OrgPrevHeadSameLevel_l(a:line)
    if (sibline <= upperline) 
        let sibline = 0
    endif
    return sibline
endfunction

function! s:OrgNextSiblingHead()
    return s:OrgNextSiblingHead_l(line("."))
endfunction
function! s:OrgNextSiblingHead_l(line)
    if s:Ind(a:line) > 0
        let lastline = s:OrgSubtreeLastLine_l(s:OrgParentHead_l(a:line))
    else
        let lastline = line("$")
    endif
    let sibline = s:OrgNextHeadSameLevel_l(a:line)
    if (sibline > lastline) 
        let sibline = 0
    endif
    return sibline
endfunction

function! s:OrgNextHead()
    " Return the line number of the next heading, 0 for none
    return s:OrgNextHead_l(line("."))
endfunction
function! s:OrgNextHead_l(line)
    return s:Range_Search(b:v.headMatch,'n', line("$"),a:line)
endfunction

function! s:OrgPrevHead()
    " Return the line number of the previous heading, 0 for none

    return s:OrgPrevHead_l(line("."))

endfunction

function! s:OrgPrevHead_l(line)

    return s:Range_Search(b:v.headMatch,'nb', 1, a:line-1)

endfunction

function! s:OrgNextHeadSameLevel()
    " Return the line number of the next head at same level, 0 for none
    return s:OrgNextHeadSameLevel_l(line("."))
endfunction

function! s:OrgNextHeadSameLevel_l(line)
    let level = s:Starcount(a:line) 
    let mypattern = substitute(b:v.headMatchLevel,'level', level, "") 
    let foundline = s:Range_Search(mypattern,'nW', line("$"), a:line)
    if foundline < line ("$")
        return foundline
    else
        if s:Starcount(foundline) > 0
            return foundline
        else
            return 0
        endif
    endif       
endfunction

function! s:OrgPrevHeadSameLevel()
    " Return the line number of the previous heading, 0 for none
    return s:OrgPrevHeadSameLevel_l(line("."))
endfunction
function! s:OrgPrevHeadSameLevel_l(line)
    let l:level = s:Starcount(a:line)
    let l:mypattern = substitute(b:v.headMatchLevel,'level', l:level, "") 
    let foundline = s:Range_Search(mypattern,'nbW', 1, a:line-1)
    if foundline > 1
        return foundline
    else
        if (s:Starcount(foundline) > 0) && (a:line != 1)
            return 1
        else
            return 0
        endif
    endif       

endfunction

function! s:OrgFirstChildHead()
    " Return the line number of first child, 0 for none
    return s:OrgFirstChildHead_l(line("."))
endfunction
function! s:OrgFirstChildHead_l(line)
    let l:starthead = s:OrgGetHead_l(a:line)

    let l:level = s:Starcount(l:starthead) + 1
    let l:nexthead = s:OrgNextHeadSameLevel_l(l:starthead)
    if l:nexthead == 0 
        let l:nexthead = line("$") 
    endif
    let l:mypattern = substitute(b:v.headMatchLevel,'level', l:level, "") 
    return s:Range_Search(l:mypattern,'nW',l:nexthead, l:starthead)
endfunction

function! s:OrgLastChildHead()
    " Return the line number of the last child, 0 for none
    return s:OrgLastChildHead_l(line("."))
endfunction

function! s:OrgLastChildHead_l(line)
    " returns line number of last immediate child, 0 if none
    let l:starthead = s:OrgGetHead_l(a:line)

    let l:level = s:Starcount(l:starthead) + 1

    let l:nexthead = s:OrgNextHeadSameLevel_l(l:starthead)
    if l:nexthead == 0 
        let l:nexthead = line("$") 
    endif

    let l:mypattern = substitute(b:v.headMatchLevel,'level', l:level, "") 
    return s:Range_Search(l:mypattern,'nbW',l:starthead, l:nexthead)

endfunction

function! s:MyLastChild(line)
    " Return the line number of the last decendent of parent line
    let l:parentindent = s:Ind(a:line)
    if s:IsText(a:line+1)
        let l:searchline = s:NextLevelLine(a:line+1)
    else    
        let l:searchline = a:line+1
    endif
    while s:Ind(l:searchline) > l:parentindent
        let l:searchline = l:searchline+1
    endwhile
    return l:searchline-1
endfunction

function! s:NextVisibleHead(line)
    " Return line of next visible heanding, 0 if none
    let save_cursor = getpos(".")

    while 1
        let nh = s:OrgNextHead()
        if (nh == 0) || s:IsVisibleHeading(nh)
            break
        endif
        execute nh
    endwhile

    call setpos('.',save_cursor)
    return nh

endfunction

function! s:FoldStatus(line)
    " adds new heading or text level depending on type
    let l:fc = foldclosed(a:line)
    if l:fc == -1
        let l:status = 'unfolded'
    elseif l:fc > 0 && l:fc < a:line
        let l:status = 'infold'
    elseif l:fc == a:line
        let l:status = 'foldhead'
    endif   
    return l:status
endfunction 

function! OrgEnterFunc()
    let syn_items = synstack(line('.'),col('.'))
    call map(syn_items, "synIDattr(v:val,'name')")
    if (index(syn_items,'Org_Full_Link') >= 0) || ( index(syn_items,'Org_Half_Link') >= 0)
        call FollowLink( OrgGetLink() )
    else
        call OrgNewHead('same')
    endif
endfunction
        
function! OrgNewHead(type,...)
    " adds new heading or text level depending on type
    if a:0 == 1
        normal 
    endif
    execute s:OrgGetHead()
    let l:org_line = line(".")
    let l:linebegin = matchlist(getline(line(".")),'^\(\**\s*\)')[1]
    if s:IsText(line(".")) == 0

        let l:lastline  = s:OrgSubtreeLastLine()  
        if a:type ==? 'levelup'
            let l:linebegin = substitute(l:linebegin,'^\*\{'.b:v.levelstars.'}','','')
        elseif a:type ==? 'leveldown'
            let l:linebegin = substitute(l:linebegin,'^\*',repeat('*',b:v.levelstars+1),'')
        endif   
        call append( l:lastline ,l:linebegin)
        execute l:lastline + 1
        startinsert!

    endif
    return ''
endfunction

function! s:IsText(line)
    " checks for whether line is any kind of text block
    " test if line matches all-inclusive text block pattern
    return (getline(a:line) !~ b:v.headMatch) && (a:line <= line('$')) 
endfunction 

function! s:NextLevelAbs(line)
    " Return line of next heading
    " in absolute terms, not just visible headings
    let l:i = 1
    " go down to next non-text line
    while s:IsText(a:line + l:i)
        let l:i = l:i + 1
        "if (a:line + l:i) == line("$")
        :"  return 0
        "endif  
    endwhile    
    return a:line + l:i
endfunction

function! s:NextLevelLine(line)
    " Return line of next heading
    let l:fend = foldclosedend(a:line)
    if l:fend == -1
        let l:i = 1
        " go down to next non-text line
        while s:IsText(a:line + l:i) 
            let l:i = l:i + 1
        endwhile    
        return a:line + l:i
    else
        return l:fend+1
    endif
endfunction

function! s:HasChild(line)
    " checks for whether heading line has
    " a sublevel
    " checks to see if heading has a non-text sublevel 
    let nh = s:OrgNextHead_l(a:line)
    if nh == 0 
        return 0
    else
        return (s:Ind(nh) > s:Ind(a:line))
    endif
    
"    if s:IsText(a:line + 1) && 
"                \   (s:Ind(s:NextLevelLine(a:line+1)) > s:Ind(a:line))
"        return 1
"    elseif s:IsText(a:line + 1) == 0 && 
"                \   (s:Ind(s:NextLevelLine(a:line)) > s:Ind(a:line))
"        return 1
"    else
"        return 0    
"    endif   
endfunction

function! s:DoFullCollapse(line) 
    let lastline = s:OrgSubtreeLastLine_l(a:line)
    if lastline == a:line 
        return
    else
        while foldclosedend(a:line) < lastline
            normal! zc
        endwhile
    endif
    " make sure headline is not just 
    " text collapse
    " test if line matches all-inclusive text block pattern
 "   while foldclosed(a:line) == -1 && (s:HasChild(a:line) || s:IsText(a:line+1))
 "       normal! zc
 "   endwhile       
 "   if s:IsTextOnlyFold(a:line) && s:HasChild(a:line)
 "       normal! zc
 "       if s:IsTextOnlyFold(a:line) && s:HasChild(a:line)
 "           normal! zc
 "           if s:IsTextOnlyFold(a:line) && s:HasChild(a:line)
 "               normal! zc
 "           endif
 "       endif   
 "   endif   
endfunction

function! s:IsTextOnlyFold(line)
    " checks for whether heading line has full fold
    " or merely a text fold
    "if s:IsText(a:line + 1) && (foldclosed(a:line + 1) == a:line) 
    if s:IsText(a:line + 1) && (foldclosedend(a:line) > 0)
                \    && (s:Ind(foldclosedend(a:line)) <= s:Ind(a:line))
        return 1
    else
        return 0
    endif   
endfunction

function! s:MaxVisIndent(headingline)
    " returns max indent for 
    " visible lines in a heading's subtree
    " used by ShowSubs
    let l:line = a:headingline
    let l:endline = s:OrgSubtreeLastLine()
    "let l:endline = s:MyLastChild(l:line)
    let l:maxi = s:Ind(l:line)
    let l:textflag = 0
    while l:line <= l:endline
        if (s:Ind(l:line) > l:maxi) && 
                    \   ( foldclosed(l:line) == l:line 
                    \  || foldclosed(l:line) == -1  )
            let l:maxi = s:Ind(l:line)
            if s:IsText(l:line)
                let l:textflag = 1
            endif   
        endif
        let l:line = l:line + 1
    endwhile    
    return l:maxi + l:textflag
endfunction

function! OrgShowLess(headingline)
    " collapses headings at farthest out visible level
    let l:maxi = s:MaxVisIndent(a:headingline)
    let l:offset = l:maxi - s:Ind(a:headingline)
    echo 'offset:  ' . l:offset
    if l:offset > 1 
        call s:ShowSubs(l:offset - 1,0)
    elseif l:offset == 1
        normal zc
        "normal! zc
    endif   
endfunction


function! OrgShowMore(headingline)
    " expands headings at furthest out 
    " visible level in a heading's subtree
    let l:maxi = s:MaxVisIndent(a:headingline)
    let l:offset = l:maxi - s:Ind(a:headingline)
    if l:offset >= 0 
        call s:ShowSubs(l:offset + 1,0)
        if l:maxi == s:MaxVisIndent(a:headingline)
            "call OrgSingleHeadingText('expand')
        endif
    endif
endfunction

function! OrgShowSubs(number,withtext)
    " used by comma-num mapping
    " expands/collapses individual heading to level visibility equal to a:number
    if getline(line('.'))[0] != '*'
        exec s:OrgPrevHead()
    endif
    let cur_level = s:Ind(line('.')) - 1
    if a:number > cur_level
        let rel_level = a:number - cur_level 
        if rel_level >= 1
             call s:ShowSubs(rel_level  ,0)
         endif
    else
        call s:DoFullCollapse(line('.'))
    endif
    normal ztkj
endfunction

function! s:ShowSubs(number,withtext)
    " shows specif number of levels down from current 
    " heading, includes text
    " or merely a text fold
    let save_cursor = getpos(".")

    call s:DoFullCollapse(line("."))
    let l:start = foldclosed(line("."))
    if l:start != -1
        let l:end = foldclosedend(line("."))
        exec "" . l:start . "," . l:end . "foldc!"
        exec "normal! zv"
        let to_level = 2
        for to_level in range( 2 , a:number )
            exec "" . l:start . "," . l:end . "foldo"
        endfor
    endif
    if a:withtext == 0
        call OrgSingleHeadingText('collapse')
    endif   

    call setpos(".",save_cursor)
endfunction

" 2 args of start line num and direction ('up' or 'down')
"command -nargs=* OrgMoveLevel :call OrgMoveLevel(<f-args>,v:count1)
nmap <buffer> <localleader>,q :<C-U>call OrgMoveLevel(line('.'),'up',v:count1)<cr>

function! OrgMoveLevel(line, direction,...)
    if (getline(a:line) !~ b:v.headMatch)
        echo "Must be on a heading line to move subtrees."
        return
    endif
    if a:0>=1
        let mycount = a:1
    else
        let mycount = 1
    endif
    " move a heading tree up, down, left, or right
    let lastline = s:OrgSubtreeLastLine_l(a:line)
    if a:direction ==? 'up'
        let l:headabove = a:line
        let count_message = ''
        for i in range( 1, mycount)
            let lasthead = l:headabove
            let l:headabove = s:OrgPrevSiblingHead_l(l:headabove)
            if l:headabove  > 0
                let count_message = 'Moved up ' . i . ' levels.' 
            elseif i == 1
                " break with no message here
                break
            else
                let l:headabove = lasthead
                if i <= mycount | let count_message .= '  No more siblings above.' | endif
                break
            endif
        endfor
        if l:headabove > 0 
            let l:lines = getline(line("."), lastline)
            call s:DoFullCollapse(a:line)
            silent normal! dd
            call append(l:headabove-1,l:lines)
            execute l:headabove
            call s:ShowSubs(1,0)
            echo count_message
        else
            echo "No sibling heading above in this subtree."
        endif
    elseif a:direction ==? 'down'
        let l:headbelow = a:line
        let count_message = ''
        for i in range(1, mycount)
            let lasthead = l:headbelow
            let l:headbelow = s:OrgNextSiblingHead_l(l:headbelow)
            if l:headbelow  > 0
                let count_message = 'Moved down ' . i . ' levels.' 
            elseif i == 1
                " break with no message here
                break
            else
                let l:headbelow = lasthead
                if i <= mycount | let count_message .= '  No more siblings below.' | endif
                break
            endif
        endfor
        if l:headbelow > 0 
            let endofnext = s:OrgSubtreeLastLine_l(l:headbelow)
            let lines = getline(line("."),lastline)
            silent call append(endofnext,lines)
            execute endofnext + 1
            " set mark and go back to delete original subtree
            normal ma
            execute a:line
            call s:DoFullCollapse(a:line)
            silent normal! dd
            normal g'a
            call s:ShowSubs(1,0)
            echo count_message
        else 
            echo "No sibling below in this subtree."
        endif
    elseif a:direction ==? 'left'
        if s:Ind(a:line) > 2 
            " first move to be last sibling
            let movetoline = s:OrgSubtreeLastLine_l(s:OrgParentHead_l(a:line))
            let lines = getline(line("."),lastline)
            call append(movetoline,lines)
            execute movetoline + 1
            " set mark and go back to delete original subtree
            normal ma
            execute a:line
            call s:DoFullCollapse(a:line)
            silent exe 'normal! dd'
            normal g'a
            " now move tree to the left
            normal ma
            silent execute line(".") ',' . s:OrgSubtreeLastLine() . 's/^' . repeat('\*',b:v.levelstars) .'//'
            call s:DoFullCollapse(a:line)
            normal g'a
            call s:ShowSubs(1,0)
            execute line(".")
        else 
            echo "You're already at main heading level."
        endif       
    elseif a:direction ==? 'right'
        if s:Ind(s:OrgPrevHead_l(a:line)) >= s:Ind(a:line)
            execute a:line . ',' . lastline . 's/^\*/'.repeat('\*',b:v.levelstars+1).'/'
            call s:DoFullCollapse(a:line)
            execute a:line
            call s:ShowSubs(1,0)
        else
            echo "Already at lowest level of this subtree."
        endif   
    endif
endfunction

function! OrgNavigateLevels(direction)
    " Move among headings 
    " direction: "up", "down", "right", "left","end", or 'home'
    if s:IsText(line("."))
        exec s:OrgGetHead()
        return  
    endif

    if s:Ind(line(".")) > 0 
        let lowerlimit = s:OrgParentHead()
        let upperlimit = s:OrgSubtreeLastLine_l(lowerlimit)
    else
        let lowerlimit = 0
        let upperlimit = line("$")
    endif       

    if a:direction ==? "left"
        let dest = s:OrgParentHead()
        let msg = "At highest level."
    elseif a:direction ==? "home"
        let dest = s:OrgParentHead()
        let msg = "At highest level."
    elseif a:direction ==? "right"
        let dest = s:OrgFirstChildHead()
        let msg = (dest > 0 ? "Has subheadings, but none visible."
                    \  : "No more subheadings.")
    elseif a:direction ==? 'end'
        let dest = s:OrgLastChildHead()
        let msg = (dest > 0 ? "Has subheadings, but none visible."
                    \  : "No more subheadings.")
    elseif a:direction ==? 'up'
        let dest = s:OrgPrevHeadSameLevel()
        let msg = "Can't go up more here."
    elseif a:direction ==? 'down'
        let dest = s:OrgNextHeadSameLevel()
        let msg = "Can't go down more."
    endif

    let visible = s:IsVisibleHeading(dest) 
    if (dest > 0) && visible && (dest >= lowerlimit) && (dest <= upperlimit) 
        execute dest
    else 
        echo msg
    endif   
endfunction

function! OrgHeadingFirstText(headline)
    exec a:headline + 1
    let found = 0
    while 1
        let thisline = getline(line('.'))
        if thisline =~ b:v.headMatch
            break
        else
            if (thisline !~ s:remstring) && (thisline !~ b:v.dateMatch)
                \ && (thisline !~ b:v.drawerMatch)
                let found = line('.')
                break
            elseif line('.') == line('$')
                break
            endif
        endif
        exec line('.') + 1
    endwhile
    return found
endfunction

function! OrgUnfoldBodyText(headline)
    if OrgHeadingFirstText(a:headline) > 0
        normal zv
    endif
endfunction

function! OrgExpandWithoutText(tolevel)
    " expand all headings but leave Body Text collapsed 
    " tolevel: number, 0 to 9, of level to expand to
    "  expand levels to 'tolevel' with all body text collapsed
    let l:startline = 1 
    let l:endline = line("$")
    let l:execstr = "set foldlevel=" . string(a:tolevel  )
    "let l:execstr = "set foldlevel=" . (a:tolevel - 1)
    exec l:execstr  
    call OrgBodyTextOperation(l:startline,l:endline,"collapse")
endfunction
function! s:OrgExpandSubtree(headline,...)
    if a:0 > 0
        let withtext = a:1
    endif
    let save_cursor = getpos(".")
    call s:DoFullFold(a:headline)
    "let end = foldclosedend(a:headline)
    "normal! zO
    "call OrgBodyTextOperation(a:headline, end, 'collapse')
    call s:ShowSubs(3,withtext)
    call setpos(".",save_cursor)
endfunction
function! s:OrgExpandHead(headline)
    let save_cursor = getpos(".")
    call s:DoFullFold(a:headline)
    "let end = foldclosedend(a:headline)
    "normal! zO
    "call OrgBodyTextOperation(a:headline, end, 'collapse')
    call s:ShowSubs(1,0)
    while foldclosed(a:headline) !=  -1
        normal! zo
    endwhile
    call setpos(".",save_cursor)
endfunction
function! s:DoFullFold(headline)
    let save_cursor = getpos(".")
    "normal! zo
    call s:DoAllTextFold(a:headline)
    let fend = foldclosedend(a:headline)
    if ((fend > a:headline) && (s:Ind(fend+1) > s:Ind(a:headline)))
                \ || (s:Ind(a:headline+1) > s:Ind(a:headline))
        normal zc
    endif
    call setpos(".",save_cursor)
endfunction
function! s:OrgCycle(headline)
    let save_cursor = getpos(".")
    let topline = line("w0")

    let end = foldclosedend(a:headline)
    if (end>0) && (s:Ind(end+1) <= s:Ind(a:headline))
        call s:OrgExpandHead(a:headline)
        let endline = end
    elseif ((end == -1) && (s:Ind(s:OrgNextHead_l(a:headline)) > s:Ind(a:headline))          
                \ && (foldclosed(s:OrgNextHead_l(a:headline)) > 0))
        let nextsamelevel = s:OrgNextHeadSameLevel_l(a:headline)
        "let nextuplevel = s:OrgNextHeadSameLevel_l(s:OrgParentHead_l(a:headline)) 
        let nextuplevel = s:OrgNextHeadSameLevel_l(a:headline) 
        if (nextsamelevel > 0) && (nextsamelevel > nextuplevel)
            let endline = nextsamelevel
        elseif nextuplevel > a:headline
            let endline = nextuplevel - 1
        else 
            let endline = line('$') 
        endif
        if b:v.cycle_with_text
            call OrgBodyTextOperation(a:headline+1,endline,'expand')
        else
            call s:OrgExpandSubtree(a:headline,0)
        endif
    else
        call s:DoFullFold(a:headline)
    endif

    exe "normal! " . topline . "G"
    normal zt
    call setpos(".",save_cursor)
    if exists('endline') && line('w$') < endline
        normal ztkj
    endif
endfunction
function! OrgCycle()
    if getline(line(".")) =~ b:v.headMatch
        call s:OrgCycle(line("."))
    elseif getline(line(".")) =~ b:v.drawerMatch
        normal! za
    elseif getline(line('.')) =~ '^\s*|.*|\s*$'
        " we're in a table, do tab and short circuit
        exec "normal i\tl"
        return
    endif
endfunction
let s:orgskipthirdcycle = 0
function! OrgGlobalCycle()
    if getline(line('.')) =~ '^\s*|.*|\s*$'
        "short circuit if we're in table
        exec "normal i\<s-tab>l"
        return
    endif
    if exists('w:sparse_on') && w:sparse_on
        call s:ClearSparseTree()
    endif
    if (&foldlevel > 1) && (&foldlevel != b:v.global_cycle_levels_to_show)
        call OrgExpandWithoutText(1)
    elseif &foldlevel == 1
        call OrgExpandWithoutText(b:v.global_cycle_levels_to_show)
    "elseif (&foldlevel > 1) && ( s:orgskipthirdcycle == 0 ) 
    "    let s = getpos('.')
    "    g/^\*\+ /call OrgUnfoldBodyText(line('.'))
    "    call setpos('.',s)
    "    let s:orgskipthirdcycle = 1
    else
        let save_cursor = getpos('.')
        set foldlevel=9999
        silent exec 'g/' . b:v.drawerMatch . '/normal! zc'
        let s:orgskipthirdcycle = 0
        call setpos('.',save_cursor)
    endif
endfunction
function! s:LastTextLine(headingline)
    " returns last text line of text under
    " a heading, or 0 if no text
    let l:retval = 0
    if s:IsText(a:line + 1) 
        let l:i = a:line + 1
        while s:IsText(l:i)
            let l:i = l:i + 1
        endwhile
        let l:retval = l:i - 1
    endif
    return l:retval
endfunction

function! s:ShowSynStack()
    for id in synstack(line("."),col("."))
        echo synIDattr(id,"name")
    endfor  
endfunction
function! s:SignList()
    let signlist = ''
    redir => signlist
    silent execute "sign list"
    redir END
    return split(signlist,'\n')
endfunction
function! s:DeleteSigns()
    " first delete all placed signs
    sign unplace *
    let signs = s:SignList()
    for item in signs
        silent execute "sign undefine " . matchstr(item,'\S\+ \zs\S\+\ze ') 
    endfor
    sign define piet text=>>
    sign define fbegin text=>
    sign define fend text=<
    sign define marked text=> linehl=Org_Marked
endfunction

function! s:GetPlacedSignsString(buffer)
    let placedstr = ''
    redir => placedstr
        silent execute "sign place buffer=".a:buffer
    redir END
    return placedstr

endfunction
function! s:GetProperties(hl,withtextinfo,...)
    let save_cursor = getpos(".")
    if a:0 >=1
        let curtab = tabpagenr()
        let curwin = winnr()
    " optional args are: a:1 - lineno, a:2 - file
        call org#LocateFile(a:1)
    endif
    let datesdone = 0
    let result1 = {}
    let result = {}

    let linetext = getline(a:hl)
    if linetext[0] == '*'
        let hl = a:hl
    else
        let hl = s:OrgGetHead_l(a:hl)
        let linetext = getline(hl)
    endif

    let result1['LINE'] = hl
    let result1['LEVEL'] = s:Ind(hl) - 1
    "let linetext = getline(hl)
    let result1['ITEM'] = linetext
    let result1['FILE'] = expand("%:t")
    " get date on headline, if any
    if linetext =~ b:v.dateMatch
        let result1['ld'] = matchlist(linetext,b:v.dateMatch)[1]
    endif
    if (getline(hl+1) =~ b:v.tagMatch) && (getline(hl+1) !~ b:v.drawerMatch)
        let result1['TAGS'] = matchstr(getline(hl+1),b:v.tagMatch)
    endif
    if linetext =~ b:v.todoMatch
        let result1['TODO'] = matchstr(linetext,b:v.todoMatch)
    else
        let result1['TODO'] = ''
    endif

    let line = hl + 1
    "let firsttext=0
    while 1
        let ltext = getline(line)
        if ltext =~ b:v.propMatch
            let result = s:GetPropVals(line+1)        
        elseif (ltext =~ '^\s*:\s*CLOCK')
            " do nothing
        elseif  (ltext !~ s:block_line) || (ltext =~ b:v.headMatch)
            call extend(result, result1)
            if datesdone
                call extend(result, dateresult)
            endif
            let result['BLOCK_END'] = line - 1
            break
        elseif (ltext =~ b:v.dateMatch) && !datesdone
            let dateresult = s:GetDateVals(line)
            let datesdone = 1
            " no break, go back around to check for props
        "elseif  (ltext =~ '^\s*$') || (ltext =~ '^\s*:\s*CLOCK')
        endif
        let line += 1
    endwhile
    " *****************************************
    " get inherited properties
    if s:include_inherited_props == 1
        for item in b:v.org_inherited_properties
            if index(keys(result), item) == -1
                let result[item] = s:IProp(hl , item)
            endif
        endfor
    endif
    " *****************************************
    " get last line
    if a:withtextinfo
        "let result['tbegin'] = line 
        let result['TEND'] = s:OrgNextHead_l(hl) - 1
    endif
    if a:0 >= 1
        execute "tabnext ".curtab
        execute curwin . "wincmd w"
    endif
    call setpos(".",save_cursor)
    "debugging
    let g:org_result = result
    return result
endfunction

function! s:GetDateVals(line)
    "result is dict with all date vals 
    let myline = a:line
    let result = {}
    while 1
        let ltext = getline(myline)
        let mtest1 = '<\zs'.b:v.dateMatch.'.*\ze>'
        let mtest2 = '\[\zs'.b:v.dateMatch.'.*\ze\]'
        if ltext =~ mtest1
            "let mymatch = matchlist(ltext, '.\{-}\(<\d\d\d\d-\d\d-\d\d\) \S\S\S\( \d\d:\d\d\)*')
            "let mydate = mymatch[1] . mymatch[2] . '>'
            let mymatch = '^\s*\(:DEADLINE:\|:SCHEDULED:\|:CLOSED:\|:<\)\s*\zs.*'
            let mydate = matchstr(ltext,mymatch)
            let mydate = (mydate[0]=='<') ? mydate[1:-2] : mydate[:-2]
            if ltext =~ 'DEADLINE'
                let dtype = 'DEADLINE'
            elseif ltext =~ 'SCHEDULED'
                let dtype = 'SCHEDULED'
            elseif ltext =~ 'CLOSED'
                let dtype = 'CLOSED'
            else
                let dtype = 'TIMESTAMP'
            endif
        elseif ltext =~ mtest2
            let mydate = matchstr(ltext, mtest2)
            "let mydate = substitute(ltext, '\(\[\d\d\d\d-\d\d-\d\d\) \S\S\S\( \d\d:\d\d\)*','\1\2','')
            let dtype = 'TIMESTAMP_IA'
        else
            break
        endif

        try
            "only add if first of dtype encountered
            if get(result,dtype) == 0
                let result[dtype] = mydate  
            endif
        catch /^Vim\%((\a\+)\)\=:E/ 
        endtry
        let myline += 1
    endwhile
    return result
endfunction

function! s:GetPropVals(line)
    "result is dict with all prop vals 
    let myline = a:line
    let result = {}
    while 1
        let ltext = getline(myline)
        if ltext =~ b:v.propvalMatch
            let mtch = matchlist(ltext, b:v.propvalMatch)
            " mtch[1] is now property, mtch[2] is its value
            try
                let result[toupper(mtch[1])] = mtch[2]   
            catch /^Vim\%((\a\+)\)\=:E/ 
            endtry
        else
            break
        endif
        let myline += 1
    endwhile
    return result
endfunction


function! s:RedoTextIndent()
    set fdm=manual
    set foldlevel=9999
    exec 1
    let myindent = 0
    while line(".") < line("$")
        let line = getline(line("."))
        if matchstr(line,'^\*\+') ># ''
            let myindent = len(matchstr(line,'^\*\+')) + g:org_indent_from_head 
            normal j
        else 
            let text = matchstr(line,'^ *\zs.*')
            let spaces = len(matchstr(line,'^ *'))
            if (spaces != (myindent + 1)) && (text != '')
                call setline(line("."),repeat(' ',myindent+1) . text)
            endif
            normal j
        endif
    endwhile
    exec 1
    set fdm=expr
endfunction

function! s:LoremIpsum()
    let lines = ['Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?","At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.']
    return split(lines[org#util#random(3)-1],'\%70c\S*\zs \ze')
endfunction

function! s:SetRandomDate(...)
    call s:OrgGetHead()
    if a:0 == 1
        let date_type = a:1
    else
        let date_type = ['DEADLINE','TIMESTAMP','SCHEDULED'][org#util#random(3)-1]
    endif
    if date_type != ''
        call s:SetProp(date_type,org#randomData())
    else
        let hl = line('.')
        let dmatch = match(getline(hl),'\s*<\d\d\d\d-\d\d-\d\d')
        if dmatch > 0
            let dmatch = dmatch - 1
            call setline(hl,getline(hl)[:dmatch])
        endif
        let newd = org#randomData()
        execute hl
        execute "normal A ". newd
    endif
endfunction
function! s:SetRandomTodo()
    let newtodo = b:v.todoitems[org#util#random(3)-1]
    if index(b:v.todoitems,matchstr(getline(line('.')),'^\*\+ \zs\S*\ze ')) >= 0
        call setline(line('.'),matchstr(getline(line('.')),'^\*\+ ') . newtodo . 
                    \    ' '. matchstr(getline(line('.')),'^\*\+ \S* \zs.*')) 
    else
        call setline(line('.'),matchstr(getline(line('.')),'^\*\+ ') . newtodo . 
                    \    ' '.  matchstr(getline(line('.')),'^\*\+ \zs.*')) 
    endif

endfunction

function! s:UpdateHeadlineSums()
    g/^\s*:TOTALCLOCKTIME/d
    call OrgMakeDict()
    let g:tempdict = {}
    g/^\*\+ /let g:tempdict[line('.')] = b:v.org_dict.SumTime(line('.'),'ITEMCLOCKTIME')
    let items = sort(map(copy(keys(g:tempdict)),"str2nr(v:val)"),'s:NumCompare')
    let i = len(items) - 1
    while i >= 0
        if g:tempdict[items[i]] != '0:00'
            call s:SetProp('TOTALCLOCKTIME',g:tempdict[items[i]],items[i])
        endif
        let i = i-1
    endwhile
endfunction

function! s:IProp(headline,property)
    let prop = a:property
    let parent = s:OrgParentHead_l(a:headline)
    if parent == 0 
        return get(b:v.org_inherited_defaults,prop)
    else
        return s:GetProperties(parent,0)[prop]
    endif
endfunction 

function! OrgMakeDictInherited(...)
    let get_tags = ((a:0==1) && (a:1 =='get_tags_too')) ? 1 : 0
    if (b:v.last_idict_time >= getftime(expand('%:p')) && (&modified==0))
        " now check and return if last run had tags or this run doesn't need them
        if (b:v.last_idict_with_tags == 1) || (get_tags == 0)
            return
        endif
    endif
    let b:v.last_idict_time = localtime()
    let b:v.last_idict_with_tags = get_tags
    if s:OrgVal('g:org_save_when_searched') > 0 | write! | endif
    let b:v.org_dict = {}
    call OrgProcessConfigLines()
    let b:v.org_dict =  {'0':{'c':[],'CATEGORY':b:v.org_inherited_defaults['CATEGORY'] }}
    function! b:v.org_dict.iprop(ndx,property) dict
        let prop = a:property
        let ndx = a:ndx
        let result = get(self[ndx] , prop,'')
        if (result ==# '') && (ndx != 0)
            "recurse up through parents in tree
            let result = b:v.org_dict.iprop(self[ndx].parent,prop)
        endif
        return result
    endfunction 
    execute 1
   let next = 1
   if s:IsText(line('.'))
      let next = s:OrgNextHead()
   endif
   while next > 0
      execute next
      if getline(line('.'))[1] ==? ' '
          let parent = 0
      else
          let parent = s:OrgParentHead()
      endif
      let b:v.org_dict[line('.')] = {'parent': parent}
      let next = s:OrgNextHead()
   endwhile 
   " parent properties assigned above, now explicity record CATEGORY for 
   " any headlines where CATEGORY won't be inherited
   if get_tags == 0
       silent execute 'g/^\s*:CATEGORY:/let b:v.org_dict[s:OrgGetHead()].CATEGORY = matchstr(getline(line(".")),":CATEGORY:\\s*\\zs.*")'
    else
       silent execute 'g/^\s*:CATEGORY:/let b:v.org_dict[s:OrgGetHead()].CATEGORY = matchstr(getline(line(".")),":CATEGORY:\\s*\\zs.*")'
       silent g/^\*\+\s*\S/call s:GetBasicMeta(line('.'))
    endif
endfunction
function! s:GetBasicMeta(line)
   "let b:v.org_dict[a:line].CATEGORY = matchstr(getline(a:line),":CATEGORY:\\s*\\zs.*")
   let this_line = getline(a:line)
   let todo =  matchstr(this_line,b:v.todoMatch)
   "let b:v.org_dict[a:line].TODO = matchstr(getline(a:line),b:v.todoMatch)
   if s:IsTagLine(a:line + 1)
       let tags = matchstr(getline(a:line+1),'^\s*\zs.*')
    else
        let tags = ''
   endif
   let b:v.org_dict[a:line].props = {'ITEM': this_line,'TODO':todo,'TAGS':tags}
endfunction
function! OrgMakeDict()
    if (b:v.last_dict_time >= getftime(expand('%:p')) && (&modified==0))
        return
    endif
    " save new dict time to use in future searches
    let b:v.last_dict_time = localtime()
    "let b:v.org_dict = {}
    "save buffer changes since last_dict
    if s:OrgVal('g:org_save_when_searched') > 0 | write! | endif
    " and recreate the dict
    call OrgMakeDictInherited()
    function! b:v.org_dict.SumTime(ndx,property) dict
        let prop = a:property
        let result = get(self[a:ndx].props , prop,'0:00')
        " now recursion down the subtree of children in c
        for item in self[a:ndx].c
            let result = s:AddTime(result,b:v.org_dict.SumTime(item,prop))
        endfor
        return result
    endfunction 
    function! b:v.org_dict.Sum(ndx,property) dict
        let prop = a:property
        let result = get(self[a:ndx].props , prop)
        " now recursion down the subtree of children in c
        for item in self[a:ndx].c
            let result += b:v.org_dict.Sum(item,prop)
        endfor
        return result
    endfunction 
    execute 1
   let next = 1
   if s:IsText(line('.'))
      let next = s:OrgNextHead()
   endif
   while next > 0
      execute next
      let b:v.org_dict[line('.')].c = []
      let b:v.org_dict[line('.')].props = s:GetProperties(line('.'),1)
      let parent = b:v.org_dict[line('.')].parent
      call add(b:v.org_dict[parent].c ,line('.'))
      let next = s:OrgNextHead()
   endwhile 
endfunction

function! s:ClearSparseTreeOld()
    set fdm=manual
    silent exe '%s/^*x//'
    silent exe 'undojoin | %s/^*o//'
    "g/^*x/call substitute(getline(line(".")),'^*x',''))
    "g/^*o/call substitute(getline(line(".")),'^*o',''))

    call clearmatches()
    set fdm=expr
    echo "sparse tree view cleared"
endfunction

function! s:SparseTreeRun(term)

    call s:ClearSparseLists()
    let w:sparse_on = 1
    execute 'g/' . a:term . '/call add(b:v.sparse_list,line("."))'
    call s:SparseTreeDoFolds()
    call clearmatches()
    let g:org_first_sparse=1
    let b:v.signstring= s:GetPlacedSignsString(bufnr("%")) 
    set fdm=expr
    set foldlevel=0
    let g:org_first_sparse=1
    execute 'let @/ ="' . a:term .'"'
    execute 'g/' . a:term . '/normal zv'
    set hlsearch
    execute 1
endfunction

function! s:SparseTreeDoFolds()
    let i = len(b:v.sparse_list) - 1
    while i >= 0
        "if b:v.sparse_list[i] + g:org_sparse_lines_after > line("$")
        if b:v.sparse_list[i] + 10 > line("$")
            call remove(b:v.sparse_list, i) "insert(b:v.fold_list,0)
            let i -= 1
            continue
        "elseif (i>0) && (b:v.sparse_list[i] < b:v.sparse_list[i-1] + g:org_sparse_lines_after)
        elseif (i>0) && (b:v.sparse_list[i] < b:v.sparse_list[i-1] + 10)
            call remove(b:v.sparse_list, i) "insert(b:v.fold_list,0)
            let i -= 1
            continue
        else
            let phead = s:OrgUltimateParentHead_l(b:v.sparse_list[i])
            if phead >= 1 
                call insert(b:v.fold_list,phead-1)
            else
                " match is already on level 1 head
                call insert(b:v.fold_list,b:v.sparse_list[i]-1)
            endif
        endif

        let i -= 1
    endwhile        
    "call map(b:v.sparse_list,"v:val + g:org_sparse_lines_after")
    call map(b:v.sparse_list,"v:val + 10")
    call insert(b:v.sparse_list, 1)
    call add(b:v.fold_list, line("$"))

    " sign method to potentially supersede list based method above
    call s:DeleteSigns()
    for item in b:v.sparse_list
        execute "sign place " . item ." line=".item." name=fbegin buffer=".bufnr("%")
    endfor
    for item in b:v.fold_list
        execute "sign place " . item ." line=".item." name=fend buffer=".bufnr("%")
    endfor
    let s:sparse_lines = {}
    for item in b:v.sparse_list
        let s:sparse_lines[item] = 1
        let s:sparse_lines[item-1] = 1
    endfor
    for item in b:v.fold_list
        let s:sparse_lines[item] = 1
    endfor
    " FoldTouch below instead of fdm line above to save time
    " updating folds for just newly changed foldlevel lines
    "call s:FoldTouch()

endfunction

function! s:ClearSparseLists()
    " mylist with lines of matches
    let b:v.sparse_list = []
    " foldlist with line before previous level 1 parent
    let b:v.fold_list = []
    let b:v.sparse_heads = []
endfunction
function! s:ClearSparseTree()
    " mylist with lines of matches
    let w:sparse_on = 0
    let b:v.sparse_list = []
    " foldlist with line before previous level 1 parent
    let b:v.fold_list = []
    set fdm=expr
    set foldlevel=1
    execute 1
endfunction

function! s:FoldTouch()
    " not used right now, since speed increase over 
    " set fdm=expr is uncertain, and was having problems
    " in cleanly undoing it.
    "
    " touch each line in lists to update their fold levels  
    let i = 0
    while i < len(b:v.sparse_list)
        execute b:v.sparse_list[i]
        " insert letter 'b' to  force level update and then undo
        silent execute "normal! ib"
        silent execute "normal! u"
        execute b:v.fold_list[i]
        silent execute "normal! ib"
        silent execute "normal! u"
        let i += 1
    endwhile
endfunction

function! s:OrgIfExpr()
    let mypattern = ''
    " two wrapper subst statements around middle 
    " subst are to make dates work properly with substitute/split
    " operation
    let ifstring_list = [[]]
    let test_str = g:org_search_spec
    if test_str[0] !~ '[+-]'
        let test_str = '+' . test_str
    endif

    let ndx=0
    let result_if_list = []
"try
    while 1
" text string
" curly bracket reg ex string
" numeric comparison
" single operand -- TAG or TODO

        let m = matchlist(test_str,'^\(|'
                    \ .  '\|[+-]\w\{-}[!<>\=]=*".\{-}"'         
                    \ .  '\|[+-]\w\{-}[!\=]=*{.\{-}}'           
                    \ .  '\|[+-]\w\{-}[=<>!]=*[0-9+-.][0-9.]*'  
                    \ .  '\|[+-]\w*\)'                          
                    \ .  '\(.*\)')
        if m[1] == '|'
            call add(ifstring_list,[])
            let ndx += 1
            let test_str = m[2]
            if test_str !~ '+\|-'
                let test_str = '+' . test_str
            endif
        elseif m[1] ># ''
            call add(ifstring_list[ndx],m[1])
            let test_str = m[2]
            if test_str == ''
                break
            endif
        else
            break
        endif
    endwhile
        
    for ifstr in ifstring_list

        let b:v.my_if_list = ifstr
        let ifexpr = ''
        " okay, right now we have split list with each item prepended by + or -
        " now change each item to be a pattern match equation in parens
        " e.g.,'( prop1 =~ propval) && (prop2 =~ propval) && (thisline =~tag)
        let i = 0
        "using while structure because for structure doesn't allow changing
        " items?
        while i < len(b:v.my_if_list)
            let item = b:v.my_if_list[i]
            if item[0] !~ '+\|-'
                let item = '+' . item
            endif
            " Propmatch has '=' sign and something before and after
            if item =~ 'TEXT=\S.*'
                let mtch = matchlist(item[1:],'\(\S.*\)=\(\S.*\)')
                let b:v.my_if_list[i] = "(s:Range_Search('" . mtch[2][1:-2] . "','nbW'," 
                let b:v.my_if_list[i] .= 'tbegin,tend)> 0)'
                let i += 1
                " loop to next item
                continue
            endif
            if item =~ '\S.*[=><]\S.*'
                if item =~ '[^<>!]=\\('
                    let item = substitute(item,'=','=~','')
                elseif item =~ '[^!]={'
                    let item = substitute(item,'[^!]\zs=','=~','')
                    let item = substitute(item,'{','"','')
                    let item = substitute(item,'}','"','')
                elseif item =~ '!={'
                    let item = substitute(item,'!=','!~','')
                    let item = substitute(item,'{','"','')
                    let item = substitute(item,'}','"','')
                elseif item =~ '[^<>!]=[^=]'
                    let item = substitute(item,'=','==','')
                endif
                let pat = '\(\S\{-}\)\(==\|=\~\|!\~\|>=\|<=\|!=\|<\|>\)\(\S.*\)'
                let mtch = matchlist(item[1:],pat)
                let mtch[1] = toupper(mtch[1])
                if mtch[3] =~ '^[+\-0-9.][0-9.]*$'
                    " numeric comparison
                    let b:v.my_if_list[i] = (item[0]=='-' ? '!' : '') . '(get(lineprops,"' . mtch[1] . '") ' . mtch[2]. mtch[3] . ')'
                else
                    " string comparison
                    let rightside="'".mtch[3][1:-2]."'"
                    let b:v.my_if_list[i] = (item[0]=='-' ? '!' : '') . '(get(lineprops,"' . mtch[1] . '","") ' . mtch[2]. rightside. ')'
                             " line below is addd on to exclude headings not
                             " having an entry at all from the comparison
                             "   \ . '&& (get(lineprops,"' . mtch[1] . '","") != "")'
                endif
                let i += 1
                " loop to next item
                continue
            endif

            " it must be a todo or tag item
            if item[0] ==? '+'
                let op = '=~'
            elseif item[0] ==? '-'
                let op = '!~'
            endif
            " if it's in todoitems assume it's a todo search item, not a tag
            if index(b:v.todoitems,item[1:]) >= 0
                let item = '(lineprops.TODO ' . op . " '" . item[1:] . "')"
                "let item = '(lineprops.TODO ' . op . " '^\\*\\+\\s*" . item[1:] . "')"
                let b:v.my_if_list[i] = item
            elseif item[1:] =~? 'UNFINISHED_TODO\|UNDONE_TODO'
                let item = '(lineprops.TODO ' . op . " '" . b:v.todoNotDoneMatch[11:] . "')"
                let b:v.my_if_list[i] = item
            elseif item[1:] =~? 'FINISHED_TODO\|DONE_TODO'
                let item = '(lineprops.TODO ' . op . " '" . b:v.todoDoneMatch[11:] . "')"
                let b:v.my_if_list[i] = item
            elseif item[1:] ==? 'ANY_TODO'
                let item = '(lineprops.TODO ' . op . " '" . b:v.todoMatch[11:] . "')"
                let b:v.my_if_list[i] = item
            else
                "not a todo so we treat it as a tag item
                let item = '(get(lineprops,"TAGS","") ' . op . " ':" . item[1:] . ":')"
                let b:v.my_if_list[i] = item
            endif
            let i += 1 
        endwhile    
        let i = 0
        let b:v.check1 = b:v.my_if_list
        let ifexpr = ''
        while i < len(b:v.my_if_list) 
            let ifexpr .= b:v.my_if_list[i]
            if i < len(b:v.my_if_list) - 1
                let ifexpr .= ' && '
            endif
            let i += 1
        endwhile

        "return ifexpr
        call add(result_if_list, ifexpr)
    endfor
"    let succeeded = 1
"finally
"    if !exists('succeeded')
"        return []
"    else
        return result_if_list
"    endif
endfunction

function! s:CheckIfExpr(line,ifexpr,...)
    " this is 'ifexpr' eval func used for agenda date searches
    let headline = s:OrgGetHead_l(a:line)
    " 0 arg is to not get start and end line numbers
    let lineprops=s:GetProperties(headline,0)
    " _thisline_ is variable evaluated in myifexpr
    let thisline = getline(headline)
    if s:IsTagLine(headline + 1)
        let thisline .= ' ' . getline(headline+1)
    endif
    let result = 0
    for item in a:ifexpr
        if eval(item) == 1
            let result = 1
            break
        endif
    endfor
    return result

endfunction

function! FileDict()
    return s:filedict
endfunction

function! s:OrgIfExprResults(ifexpr,...)
    " ifexpr has single compound expression that will evaluate
    " as true only for desired lines
    let sparse_search = 0
    if a:0 > 0
        let sparse_search = a:1
    endif

    "let myifexpr = a:ifexpr
    
    execute 1
    if getline(line('.'))!~ '^\*\+ '
        let headline = s:OrgNextHead()
    else
        let headline = 1
    endif
    let g:checkexpr = a:ifexpr
    while 1
        if headline > 0 
            execute headline
            " _thisline_ is variable evaluated in myifexpr
            let thisline = getline(headline)
            if s:IsTagLine(headline + 1)
                let thisline .= ' ' . getline(headline+1)
            endif
            " lineprops is main variable tested in 'ifexpr' 
            " expression that gets evaluated
            "let lineprops = s:GetProperties(headline,1)
            let lineprops = b:v.org_dict[headline].props

            for if_item in a:ifexpr
                " next line is to fix for text area search
                " now that we can reference tbegin and tend
                let myifexpr = substitute(if_item,'\cTBEGIN,TEND',get(lineprops,'LINE') .','. get(lineprops,'TEND'),"")
                "
                "********  eval() is what does it all ***************
                if eval(myifexpr)
                    if sparse_search
                        let keyval = headline
                    else
                        "let keyval = s:PrePad(index(s:agenda_files_copy, lineprops.file . '.org'),3,'0') . s:PrePad(headline,5,'0')
                        "let keyval = s:PrePad(lineprops.file,3,'0') . s:PrePad(headline,5,'0')
                        let keyval = s:PrePad(s:filenum,3,'0') . s:PrePad(headline,5,'0')
                    endif

                    let g:adict[keyval]=lineprops
                    if !exists('g:adict[keyval].CATEGORY')
                        let g:adict[keyval].CATEGORY = b:v.org_dict.iprop(headline,'CATEGORY')
                    endif
                    break
                endif
            endfor
            normal l
            let headline = s:OrgNextHead() 
        else
            break
        endif
    endwhile
endfunction

function! s:MakeResults(search_spec,...)
    let s:filedict = copy(g:agenda_files)
    let sparse_search = 0
    if a:0 > 0
        let sparse_search = a:1
    endif
    let save_cursor = getpos(".")
    "let curfile = substitute(expand("%"),' ','\\ ','g')
    let curfile = substitute(expand("%:p"),' ','\\ ','g')
    let curtab = tabpagenr()
    let curwin = winnr()

    let g:org_search_spec = a:search_spec
    let g:org_todoitems=[]
    let g:adict = {}
    let g:datedict = {}
    let s:agenda_files_copy = copy(g:agenda_files)
    " fix so copy doesn't have full path. .  .
    "call map(s:agenda_files_copy, 'matchstr(v:val,"[\\/]") > "" ? matchstr(v:val,"[^/\\\\]*$") : v:val')
    if sparse_search 
        call OrgMakeDict()
        let ifexpr = s:OrgIfExpr()
        call s:OrgIfExprResults(ifexpr,sparse_search)
    else
        let g:in_agenda_search = 1
        for file in g:agenda_files
            "execute 'tab drop ' . file
            call org#LocateFile(file)
            call org#SaveLocation()
           " let bnum = bufnr(file)
           " if bnum == -1 
           "     execute 'tabedit ' . file
           " else
           "    execute 'b' . bnum 
           " endif
            let s:filenum = index(g:agenda_files,file)
            if g:org_search_spec =~ '[<>\=!]'
                call OrgMakeDict()
            else
                " it's just todos and/or tags
                call OrgMakeDictInherited('get_tags_too')
            endif
            let ifexpr = s:OrgIfExpr()
            let g:org_todoitems = extend(g:org_todoitems,b:v.todoitems)
            call s:OrgIfExprResults(ifexpr,sparse_search)
            call org#RestoreLocation()
        endfor
        unlet g:in_agenda_search
        "call org#LocateFile(curfile)
        execute 'tabnext ' . curtab
        execute curwin . 'wincmd w'
    endif
    call setpos(".",save_cursor)
endfunction
function! s:DaysInMonth(date)
        let month = str2nr(a:date[5:6])
        let year = str2nr(a:date[0:3])
        if (month == 2) && (year % 4) 
            let days = 28 
        elseif month == 2
            let days = 29
        elseif index([1,3,5,7,8,10,12],month) >= 0 
            let days = 31
        else
            let days = 30
        endif
        return days
endfunction

function! s:MakeAgenda(date,count,...)
    if a:0 >= 1
        let g:org_search_spec = a:1
    else
        let g:org_search_spec = ''
    endif
    let as_today = ''
    if a:0 >= 2
        let as_today = a:2
    endif
    
    "call org#SaveLocation()
    let curtab = tabpagenr()
    let curwin = winnr()

    let l:count = a:count
    if l:count ==? 'd' | let l:count = 1 | endif
    if l:count ==? 'w'
        let g:agenda_startdate = calutil#cal(calutil#jul(a:date) - calutil#dow(a:date))
        let g:org_agenda_days=7
    elseif l:count ==? 'm'
        let g:agenda_startdate = a:date[0:7].'01'
        let g:org_agenda_days = s:DaysInMonth(a:date)
    elseif l:count ==? 'y'
        let g:agenda_startdate = a:date[0:3].'-01-01'
        let g:org_agenda_days = ( a:date[0:3] % 4 == 0 ) ? 366 : 365
    else
        let g:agenda_startdate = a:date
        let g:org_agenda_days = l:count
    endif
    if l:count == 1 | let as_today = g:agenda_startdate | endif
    let g:adict = {}
    let s:filedict = copy(g:agenda_files)
    let s:agenda_files_copy = copy(g:agenda_files)
    let g:datedict = {}
    call s:MakeCalendar(g:agenda_startdate,g:org_agenda_days)
    let g:in_agenda_search=1
    for file in g:agenda_files
        call org#LocateFile(file)
        call org#SaveLocation()
        " for now g:org_search_spec is limited to tags and
        " todo prop which are part of OrgMakeDictInherited
        " If ever want to expand to general props can 
        " add OrgMakeDict()
        call OrgMakeDictInherited()
        let s:filenum = index(g:agenda_files,file)
        let t:agenda_date=a:date
        if as_today ># ''
            call s:GetDateHeads(g:agenda_startdate,g:org_agenda_days,as_today)
        else 
            call s:GetDateHeads(g:agenda_startdate,g:org_agenda_days)
        endif
        call org#RestoreLocation()
    endfor
    unlet g:in_agenda_search

    "call org#RestoreLocation()
    exec 'tabnext ' . curtab
    exec curwin . 'wincmd w'

endfunction

function! s:NumCompare(i1, i2)
    return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1
endfunc

function! OrgRunSearch(search_spec,...)
        "set mouseshape-=n:busy,v:busy,i:busy
    if bufnr('Calendar') > 0 
        execute 'bw!' . bufnr('Calendar')
    endif   

    try

    if bufnr('__Agenda__') >= 0
        "bwipeout __Agenda__
    endif

    let g:agenda_head_lookup={}
    let sparse_search = 0
    let search_type = ''
    if a:0 > 0
        if a:1 == 1
            let sparse_search = a:1
        else
            let search_type=a:1
        endif
    endif
    let g:adict={}
    let g:agenda_date_dict={}
    if !exists("g:agenda_files") || (g:agenda_files == [])
        if has('dialog_con') || has('dialog_gui')
            unsilent call confirm("No agenda files defined.  Will add current file to agenda files.")
        endif
        call s:CurfileAgenda()
    endif
    if exists('b:v.sparse_list') && (len(b:v.sparse_list) > 0)
        call s:ClearSparseTree()
    endif
    call s:MakeResults(a:search_spec,sparse_search)

    if sparse_search
        call s:ResultsToSparseTree()
    else
        call s:ResultsToAgenda( search_type )
    endif

    finally
        "set mouseshape-=n:busy,v:busy,i:busy
    endtry
endfunction
function! s:ResultsToAgenda( search_type )
    " FOR OrgRunSearch()  
    ":AAgenda
    :EditAgenda
    let b:v={}
    call s:AgendaBufSyntax()
    set nowrap
    
    call s:DoAgendaMaps()
    
    let i = 0
    call s:ADictPlaceSigns()
    let b:v.heading_marks_dict = {}
    "call setline(line('$'), ["Headlines matching search spec: ".g:org_search_spec,''])
    let lines = []
    let lines = lines +  ["Headlines matching search spec: ".g:org_search_spec,'']
    if a:search_type ==? 'agenda_todo'
        let msg = "Press <num>r to re-search: "
        let numstr= ''
        nmap <buffer> r :call OrgRunSearch(g:org_search_spec,'agenda_todo')<cr>
        let tlist = ['ANY_TODO','UNFINISHED_TODOS', 'FINISHED_TODOS'] + s:Union(g:org_todoitems,[])
        for item in tlist
            let num = index(tlist,item)
            let numstr .= '('.num.')'.item.'  '
            execute "nmap <buffer> ".num."r  :silent call OrgRunCustom({'redo_num':line('.'), 'type':'tags-todo', 'spec':'". tlist[num] . "'})<CR>"
        endfor
        "call add(lines,split(msg.numstr,'\%72c\S*\zs '))
        let lines = lines + split(msg.numstr,'\%72c\S*\zs ')
        call add(lines,'')
    endif
    for key in sort(keys(g:adict))
        call add(lines , key . ' ' . 
                    \ printf("%-12.12s",g:adict[key].CATEGORY ) . ' ' .
                    \ s:PrePad(matchstr(g:adict[key].ITEM,'^\*\+ '),8) .
                    \ matchstr(g:adict[key].ITEM,'\* \zs.*$'))
        let i += 1
    endfor
    call append(s:agenda_insert_point,lines)
endfunction
function! s:ToFromAgenda()
    if bufname('%') == '__Agenda__'
        for i in range(1, winnr('$'))
            exe i . 'wincmd w'
            if bufname('%') !~ '__Agenda__\|__Calendar' 
                break
            endif
        endfor
        "windo if bufname('%') !~ '__Agenda__\|__Calendar' | let return | endif
    elseif bufwinnr('__Agenda__') > 0
        exec bufwinnr('__Agenda__') . 'wincmd w'
    endif
endfunction
function! s:DoAgendaMaps()
    execute "source " . s:sfile . '/vimorg-agenda-mappings.vim'

    command! -buffer -nargs=* Agenda :call OrgAgendaCommand(<f-args>)

    " user can have a function in their vimrc to have their own 
    " agenda mappings
    if exists('*OrgCustomAgendaMaps')
        call OrgCustomAgendaMaps()
    endif
endfunction

function! s:OrgAgendaTab()
    if getline(line(".")) !~ '^\d\+'
        return
    endif
    let thisline = getline(line('.'))
    let file = s:agenda_files_copy[str2nr(matchstr(thisline, '^\d\d\d'))]
    if bufwinnr(file) == -1
        call s:OrgAgendaToBuf()
    else
        call s:MoveToHeadingFromAgenda(line('.'))
        if b:v.chosen_agenda_heading != line('.')
            "back to agenda and do agendatobuf from there
            call org#LocateFile('__Agenda__')
            call s:OrgAgendaToBuf()
        else
            " we're in file buffer, ready to cycle
            call s:OrgCycle(line('.'))
            call org#LocateFile('__Agenda__')
        endif
    endif
endfunction
function! s:ToggleHeadingMark(line)
    let line = a:line
    if (bufname('%') == '__Agenda__' && getline(line) !~ '^\d\{8}\s')
            \ || ((&filetype == 'org') && getline(line) !~ b:v.headMatch)
        return
    endif
    let list_item = get(b:v.heading_marks_dict, line)
    if list_item == 0
        let b:v.heading_marks_dict[line] = 1
        execute "sign place " . line('.') . " line=" . line('.') . " name=marked buffer=".bufnr("%")
    else
        unlet b:v.heading_marks_dict[line] 
        execute "sign unplace " . line('.') . " buffer=".bufnr("%")
    endif
endfunction
function! s:DeleteHeadingMarks()
    if bufname('%')=='__Agenda__'
        for item in keys(b:v.heading_marks_dict)
            execute "sign unplace " . item . " buffer=".bufnr("%")
        endfor
    else
        sign unplace *
    endif
    let b:v.heading_marks = []
    let b:v.heading_marks_dict = {}
endfunction
function! s:ResultsToSparseTree()
        "call s:ClearSparseTree()
        let w:sparse_on = 1
        let temp = []
        for key in keys(g:adict)
            call add(temp,g:adict[key].LINE)
        endfor
        let b:v.sparse_list = sort(temp,'s:NumCompare')
        "for key in keys(g:adict)
        "   call add(b:v.sparse_heads,str2nr(key))
        "endfor
        "for item in sort(b:v.sparse_heads,'NumCompare')
        call sort(b:v.fold_list,"s:NumCompare")
        call s:SparseTreeDoFolds()
        "for item in sort(b:v.fold_list,'NumCompare')
        set fdm=expr
        set foldlevel=0
        call clearmatches()
        for item in b:v.sparse_list
            if item > 11
                execute item - g:org_sparse_lines_after
                normal! zv
                call matchadd('Search','\%' . (item - g:org_sparse_lines_after) . 'l')
            endif
        endfor
        execute 1
endfunction

function! s:TestTime()
    let g:timestart=join(reltime(), ' ') 
    let g:start = strftime("%")
    let i = 0
    set fdm=expr
    let g:timefinish=join(reltime(), ' ')
    echo g:timestart . ' --- ' . g:timefinish
endfunction
function! s:TestTime2(fu)
    let g:timestart=join(reltime(), ' ') 
    let g:start = strftime("%")
    let i = 0
    execute a:fu
    let g:timefinish=join(reltime(), ' ')
    echo g:timestart . ' --- ' . g:timefinish
endfunction

function! s:ADictPlaceSigns()
    let myl=[]
    call s:DeleteSigns()  " signs were placed during search
    for key in keys(g:adict)
        let headline = matchstr(key,'^\d\d\d\zs\d\+')
        let filenum = str2nr(key[0:2])
        let buf = bufnr(s:agenda_files_copy[filenum])
        try
            silent execute "sign place " . headline . " line=" 
                        \ . headline . " name=piet buffer=" . buf  
        catch 
            echo "ERROR: headline " . headline . ' and buf ' .buf 
            echo key .', '. matchstr(key,'^.*\ze_\d\+$')
        finally
        endtry
    endfor
endfunction
function! s:DateDictPlaceSigns()
    let myl=[]
    call s:DeleteSigns()  " signs were placed in GetDateHeads
    for key in keys(g:agenda_date_dict)
        let myl = get(g:agenda_date_dict[key], 'l')
        if len(myl) > 0
            for item in myl
                let dateline = matchstr(item,'^\d\d\d\zs\d\+')
                let filenum = str2nr(item[0:2])
                let buf = bufnr(s:agenda_files_copy[filenum])
                try
                    silent execute "sign place " . dateline . " line=" 
                                \ . dateline . " name=piet buffer=" . buf  
                catch 
                    echo "ERROR: headline " . headline . ' and buf ' . buf . ' and dateline ' . dateline

                    echo (matchstr(item,'^\d\+\s\+\zs\S\+') . '.org')
                finally
                endtry
            endfor
        endif
    endfor
endfunction

function! s:DateDictToScreen()
    ":%d   "delete all lines
    let lines = ["Press <f> or <b> for next or previous period, q to close agenda," ,
                \ "<Enter> on a heading to synch main file, <ctl-Enter> to goto line," ,
                \ "<tab> to cycle heading text, <shift-Enter> to cycle Todos.",'']
    let search_spec = g:org_search_spec ># '' ? g:org_search_spec : 'None - include all heads'
    let d = g:org_agenda_days
    let start_week = 'W' . org#ISODateToYWD(g:agenda_startdate)[1]
    let end_date = calutil#cal(calutil#jul(g:agenda_startdate)+g:org_agenda_days-1)
    let end_week = 'W' . org#ISODateToYWD(end_date)[1]
    if d==1                |  let type = 'Day-agenda (' . start_week . '):'
    elseif d==7            |  let type = 'Week-agenda (' . start_week . '):'
    elseif (d>27 && d<32)  | let type = 'Month-agenda (' . start_week . '-' . end_week . '):'
    elseif (d>364 && d<366) | let type = 'Year-agenda:'
    else                   | let type = 'Agenda:'
    endif

    call add(lines,"Agenda view for " . g:agenda_startdate 
                \ . " to ". calutil#cal(calutil#jul(g:agenda_startdate)+g:org_agenda_days-1)
                \ . ' matching FILTER: ' . search_spec  )
    call add(lines,'')
    call add(lines,type)
    
    call s:DateDictPlaceSigns()
    let b:v.heading_marks_dict = {}
    let gap = 0
    let mycount = len(keys(g:agenda_date_dict)) 
    for key in sort(keys(g:agenda_date_dict))
        if empty(g:agenda_date_dict[key].l)
            let gap +=1
            call add(lines, g:agenda_date_dict[key].marker)
        else
            if (gap > g:org_agenda_skip_gap) && (g:org_agenda_minforskip <= mycount)
                call remove(lines, len(lines)-gap, -1 )
                let lines = lines + ['','  [. . . ' .gap. ' empty days omitted ]','']
            endif
            let gap = 0
            call add(lines, g:agenda_date_dict[key].marker)
            if ((g:org_agenda_days == 1) || (key == strftime("%Y-%m-%d"))) && exists('g:org_timegrid') && (g:org_timegrid != [])
                let lines = lines + s:PlaceTimeGrid(g:agenda_date_dict[key].l)
            else
                let lines = lines + g:agenda_date_dict[key].l
            endif
        endif
    endfor

    if (gap > g:org_agenda_skip_gap) && (g:org_agenda_minforskip <= mycount)
        call remove(lines, len(lines)-gap, -1 )
        let lines = lines + ['','  [. . . ' .gap. ' empty days omitted ]','']
    endif
    " finally, place all the prepared result lines in agenda buffer
    call append(s:agenda_insert_point-1, lines)
endfunction
function! s:TimeGridSort(s1, s2)
    return (a:s1[23:] == a:s2[23:]) ? 0 : (a:s1[23:] > a:s2[23:]) ? 1 : -1
endfunction
function! s:PlaceTimeGrid(lines)
    let lines = a:lines
    " assemble timegrid for agenda view
    if lines[0] =~ '\%24c\d\d:\d\d'
        "if, at least one time item put grid lines in and sort with other time items
        let grid = s:TimeGrid(g:org_timegrid[0],g:org_timegrid[1],g:org_timegrid[2])
        let lines = grid + lines
        let i = len(grid) - 1
        while ((i < len(lines)) && matchstr(lines[i],'\%24c\d\d:\d\d') )
            let i += 1
        endwhile
        let lines = sort(lines[0:i-1], 's:TimeGridSort') + lines[i :]
        " now delete duplicates where grid is same as actual entry
        " skip this part until rest is working. . . 
        "let i = 0
        "while i < len(lines)
        "    let match1 = matchstr(getline(line('.')),'\%24c.*\%29c')
        "    let match2 = matchstr(getline(line('.')-1),'\%24c.*\%29c')
        "    if match1 ==? match2
        "        if match1[0] ==? ' '
        "            normal ddk
        "        else
        "            normal kdd
        "        endif
        "    endif
        "    exec line('.')-1
        "endwhile
    endif
    return lines
endfunction
function! OrgRunAgenda(date,count,...)
    try

    if bufname('%') ==? '__Agenda__'
        "wincmd k
    endif
    let g:agenda_head_lookup={}
    let win = bufwinnr('Calendar')
    let file = expand('%:p')
    if win >= 0 
        execute win . 'wincmd w'
        normal ggjjj
        wincmd l
        execute 'bw!' . bufnr('Calendar')

    endif   
    if !exists("g:agenda_files") || (g:agenda_files == [])
        unsilent call confirm("No agenda files defined.  Will add current file to agenda files.")
        call s:CurfileAgenda()
    endif
    if exists('b:v.sparse_list') && (len(b:v.sparse_list) > 0)
        call s:ClearSparseTree()
    endif
    " a:1 is search_spec, a:2 is "today" for search
    if a:0 == 1
        call s:MakeAgenda(a:date,a:count,a:1)
    elseif a:0 == 2
        call s:MakeAgenda(a:date,a:count,a:1,a:2)
    else
        call s:MakeAgenda(a:date,a:count)
    endif
    AAgenda
    call s:SetupDateAgendaWin()
    "we are no in newly created agenda buf/window
    
    for key in keys(g:agenda_date_dict)
        call sort(g:agenda_date_dict[key].l, 's:AgendaCompare')
    endfor
    call s:DateDictToScreen()
    if win >= 0
        let year = matchstr(t:agenda_date,'\d\d\d\d')
        let month = matchstr(t:agenda_date,'\d-\zs\d\d\ze-')
        execute 'Calendar ' . year .' '. str2nr(month) 
        execute bufwinnr('Agenda').'wincmd w'
    endif
    " we're in agenda, do rigamarole to get top column heading window, 
    " if any, back to zero height
    let curheight=winheight(0)
    call org#LocateFile(file)
    "wincmd k
    resize
    call org#LocateFile('__Agenda__')
    "wincmd j
    execute 1
    execute 'resize ' . curheight   

    finally
        "set mouseshape-=n:busy,v:busy,i:busy
    endtry

endfunction
function! OrgRunCustom(arg)
    call s:RunCustom(a:arg)
endfunction
function! s:SetupDateAgendaWin()
    EditAgenda
    let b:v={}
    call s:AgendaBufSyntax()
    set nowrap
    call s:DoAgendaMaps()

    command! -buffer -nargs=* Agenda :call OrgAgendaCommand(<f-args>)

endfunction

function! OrgRefreshCalendarAgenda()
    let g:org_search_spec = matchstr(getline(5),'FILTER:\s*\zs.*$')
    if g:org_search_spec =~ '\c^None'
       let g:org_search_spec = ''
    endif
    call OrgRunCustom({'redo_num': line('.'),'type':'agenda', 'agenda_date': g:agenda_startdate, 'agenda_duration': g:org_agenda_days, 'spec': g:org_search_spec})
endfunction
function! s:Resize()
    let cur = winheight(0)
    resize 
    resize cur
endfunction

function! s:GetDateHeads(date1,count,...)
    " a:1 is date for warnings
    let save_cursor=getpos(".")
    if g:org_search_spec ># ''
        let b:v.agenda_ifexpr = s:OrgIfExpr()
    endif
    let g:date1 = a:date1
    let date1 = a:date1
    let date2 = calutil#Jul2Cal(calutil#Cal2Jul(split(date1,'-')[0],split(date1,'-')[1],split(date1,'-')[2]) + a:count)
    execute 1
    while search('[^-][[<]\d\d\d\d-\d\d-\d\d','W') > 0
        "if ((g:org_search_spec ># '') && (s:CheckIfExpr(line("."),b:v.agenda_ifexpr)==0))
        "    continue
        "endif
        let repeatlist = []
        let line = getline(line("."))
        let datematch = matchstr(line,'[[<]\d\d\d\d-\d\d-\d\d\ze')
        let repeatmatch = matchstr(line, '<\d\d\d\d-\d\d-\d\d.*[ +.]+\d\+\S\+.*>\ze')
        if repeatmatch != ''
            " if date has repeater then call once for each repeat in period
            let repeatlist = s:RepeatMatch(repeatmatch[1:],date1,date2)
            for dateitem in repeatlist
                if a:0 == 1
                    call s:ProcessDateMatch(dateitem,date1,date2,a:1)
                else
                    call s:ProcessDateMatch(dateitem,date1,date2)
                endif
            endfor
        else
            if (datematch[0]!='[') || g:org_clocks_in_agenda
                if a:0 == 1
                    call s:ProcessDateMatch(datematch[1:],date1,date2,a:1)
                else
                    call s:ProcessDateMatch(datematch[1:],date1,date2)
                endif
            endif
        endif
        "endif
    endwhile
    call setpos(".",save_cursor)
endfunction

function! s:ProcessDateMatch(datematch,date1,date2,...)
    if a:0 > 0
        let today = a:1
    else
        let today = strftime("%Y-%m-%d")
    endif
    let datematch = a:datematch
    let rangedate = matchstr(getline(line(".")),'--<\zs\d\d\d\d-\d\d-\d\d')

    let locator = s:PrePad(s:filenum,3,'0') . s:PrePad(line('.'),5,'0') . '  '
    
    let g:myline = s:OrgGetHead_l(line('.'))
    "let g:myline = s:OrgParentHead_l(line('.'))
    "if g:myline == 0
    "    let filename = org#Pad(b:v.org_dict[g:myline].CATEGORY,13)
    "else
        "let filename = org#Pad(b:v.org_dict.iprop(g:myline,'CATEGORY'),12) . ' '
        let filename = printf("%-12.12s",b:v.org_dict.iprop(g:myline,'CATEGORY')) . ' '
    "endif
    let line = getline(line("."))
    let date1 = a:date1
    let date2 = a:date2
    let s:headline=0
    if (datematch >= date1) && (datematch < date2)
                \ && ((g:org_search_spec ==# '') || (s:CheckIfExpr(line("."),b:v.agenda_ifexpr)))
        let mlist = matchlist(line,'\(DEADLINE\|SCHEDULED\|CLOSED\)')
        call s:SetHeadInfo()
        if empty(mlist)
            " it's a regular date, first check for time parts
            let tmatch = matchstr(line,' \zs\d\d:\d\d\ze.*[[>]')
            if tmatch ># ''
                let tmatch2 = matchstr(line,'<.\{-}-\zs\d\d:\d\d\ze.*>')
                if tmatch2 ># ''
                    let tmatch .= '-' . tmatch2
                else
                    if match(line,':\s*CLOCK\s*:') >= 0
                        let tmatch .= '-'.matchstr(line,'--\[.\{-}\zs\d\d:\d\d\ze\]')
                        let s:headtext = s:headtext[0:6] . 'Clocked: ('.matchstr(line,'->\s*\zs.*$') .') '.s:headtext[7:]
                    else
                        let tmatch .= '......'
                    endif
                endif
            endif
            call add(g:agenda_date_dict[datematch].l,  locator . filename . org#Pad(tmatch,11) . s:headtext)
            "call add(g:agenda_date_dict[datematch].l,  line(".") . repeat(' ',6-len(line("."))) . filename . org#Pad(tmatch,11) . s:headtext)
            if rangedate != ''
                "let startdate = matchstr(line,'<\zs\d\d\d\d-\d\d-\d\d\ze')
                "let thisday = calutil#jul(datematch) - calutil#jul(startdate) + 1
                let days_in_range = calutil#jul(rangedate) - calutil#jul(datematch) + 1
                "let rangestr = '('.thisday.'/'.days_in_range.')'
                let i = days_in_range
                "while (rangedate < date2) && (rangedate > datematch)
                while (rangedate > datematch)
                    let rangestr = '('.i.'/'.days_in_range.')'
                    if exists("g:agenda_date_dict['".rangedate."']")
                        "call add(g:agenda_date_dict[rangedate].l,  line(".") . repeat(' ',6-len(line("."))) . 
                        call add(g:agenda_date_dict[rangedate].l,  locator . 
                                    \ filename . org#Pad(rangestr,11) . s:headtext)
                    endif
                    let rangedate = calutil#cal(calutil#jul(rangedate) - 1)
                    let i = i - 1
                endwhile
                " to end of line to avoid double
                " treatment
                normal $
            endif
        else
            " it's a deadline/scheduled/closed date
            let type = org#Pad(mlist[1][0] . tolower(mlist[1][1:]) . ':' , 11)
            call add(g:agenda_date_dict[datematch].l,  locator . filename . type  . s:headtext)
        endif
    endif
    " Now test for late and upcoming warnings if 'today' is in range and not
    " a done-type todo
    if (today >= date1) && (today < date2) && (getline(g:myline) !~ b:v.todoDoneMatch)
        if (datematch < today) && (match(line,'\(DEADLINE\|SCHEDULED\)')>-1)
                    \ && ((g:org_search_spec ==# '') || (s:CheckIfExpr(line("."),b:v.agenda_ifexpr)))
            let mlist = matchlist(line,'\(DEADLINE\|SCHEDULED\)')
            call s:SetHeadInfo()
            if !empty(mlist)
                let dayspast = calutil#jul(today) - calutil#jul(datematch)
                if mlist[1] ==? 'DEADLINE'
                    let newpart = org#Pad('In',6-len(dayspast)) . '-' . dayspast . ' d.:' 
                else
                    let newpart = org#Pad('Sched:',9-len(dayspast)) . dayspast . 'X:'
                endif
                call add(g:agenda_date_dict[today].l,  locator . filename . newpart . s:headtext)
            endif
            " also put in warning entry for deadlines when appropriate
        elseif (datematch > today) && (match(line,'DEADLINE')>-1)
                    \ && ((g:org_search_spec ==# '') || (s:CheckIfExpr(line("."),b:v.agenda_ifexpr)))
            let mlist = matchlist(line,'DEADLINE')
            call s:SetHeadInfo()
            if !empty(mlist)
                let daysahead = calutil#jul(datematch) - calutil#jul(today)
                let g:specific_warning = str2nr(matchstr(line,'<\S*\d\d.*-\zs\d\+\zed.*>'))
                if (daysahead <= g:org_deadline_warning_days) || (daysahead <= g:specific_warning)
                    let newpart = org#Pad('In',7-len(daysahead)) . daysahead . ' d.:' 
                    call add(g:agenda_date_dict[today].l,  locator . filename . newpart . s:headtext)
                endif
            endif
        endif
    endif
    " finally handle things for a range that began before date1
    if (rangedate != '')  && (datematch < date1)
                \ && ((g:org_search_spec ==# '') || (s:CheckIfExpr(line("."),b:v.agenda_ifexpr)))
        let days_in_range = calutil#jul(rangedate) - calutil#jul(datematch) + 1
        if rangedate >= date2
            let last_day_to_add = calutil#jul(date2) - calutil#jul(datematch) 
            let rangedate = calutil#cal(calutil#jul(date2)-1)
        else
            let last_day_to_add = days_in_range
        endif

        call s:SetHeadInfo()
        let i = last_day_to_add
        while (rangedate >= date1)
            let rangestr = '('.i.'/'.days_in_range.')'
            call add(g:agenda_date_dict[rangedate].l,  locator . 
                        \ filename . org#Pad(rangestr,11) . s:headtext)
            let rangedate = calutil#cal(calutil#jul(rangedate) - 1)
            let i = i - 1
        endwhile
        " go past match to avoid double treatment
        normal $
    endif
    if s:headline > 0
        let g:agenda_head_lookup[line(".")]=s:headline
    endif
endfunction

function! s:SetHeadInfo()
    let s:headline = s:OrgGetHead_l(line("."))
    let s:headtext = getline(s:headline)
    let s:mystars = matchstr(s:headtext,'^\*\+')
    let s:headstars = s:PrePad(s:mystars,6)
    let s:headtext = s:headstars . ' ' . s:headtext[len(s:mystars)+1:]
endfunction

function! s:RepeatMatch(rptdate, date1, date2)
    let yearflag = 0
    let basedate = matchstr(a:rptdate,'\d\d\d\d-\d\d-\d\d')
    if basedate >= a:date2
        " no need for repeat, rturn to check fo deadlien warnings
        return [basedate]
    endif
    let date1 = a:date1
    if basedate > date1
        let date1 = basedate
    endif
    let baserpt = matchstr(a:rptdate, ' \S\S\S [.+]\{0,1}+\zs\S\+\ze.*>')
    let rptnum = matchstr(baserpt, '^\d\+')
    let rpttype = matchstr(baserpt, '^\d\+\zs.')
    let g:rptlist = []
    let date1jul = calutil#jul(date1)
    let date2jul = calutil#jul(a:date2)
    if rpttype ==? 'w'
        let rpttype = 'd'
        let rptnum = str2nr(rptnum)*7
    endif
    if rpttype ==? 'y'
        let rpttype = 'm'
        let rptnum = str2nr(rptnum)*12
        let yearflag = 1
    endif
    if rpttype ==? 'd'
        let dmod = (date1jul - calutil#jul(basedate)) % rptnum
        let i = 0
        while 1
            let testjul = date1jul - dmod + (i*rptnum)
            if testjul < date2jul
                call add(g:rptlist, calutil#cal(testjul))
            else
                break
            endif
            let i += 1
        endwhile
    elseif rpttype ==? 'm'
        let g:special = baserpt[-1:]
        let monthday = str2nr(basedate[8:]) 
        let baseclone = basedate
        " this if-structure assigns begin test month as 
        " first repeat month _before_ date1
        if yearflag
            if (date1[:6]) >= (date1[:3] . baseclone[4:6]) 
                let baseclone = date1[:3] . baseclone[4:]
            else
                let baseclone = string(str2nr(date1[:3]) - 1) . baseclone[4:]
            endif
            let first_of_month_jul = calutil#jul(baseclone[:7]. '01')
        else
            let first_of_month_jul = calutil#jul(date1[:4] .
                        \ s:Pre0( date1[5:6] ) . '-01')
                        "\ s:Pre0( date1[5:6] - 1) . '-01')
        endif

        if g:special ==? '*'
            let specialnum = (monthday / 7) + 1
            let specialdaynum = calutil#dow(basedate)
        endif
        while 1
            if g:special != '*'
                let testjul = first_of_month_jul - 1 + monthday
            else
                " process for 'xth weekday of month' type
                let fdow = calutil#dow(calutil#cal(first_of_month_jul))
                if fdow == specialdaynum
                    let testjul = first_of_month_jul + (specialnum-1)*7
                elseif fdow < specialdaynum
                    let testjul = first_of_month_jul + (specialnum-1)*7
                                \ + (specialdaynum - fdow)
                elseif fdow > specialdaynum
                    let testjul = first_of_month_jul + (specialnum*7)
                                \ - (fdow - specialdaynum)
                endif
            endif

            if (testjul < date2jul) && (testjul >= first_of_month_jul)
                call add(g:rptlist, calutil#cal(testjul))
            else
                "put in this one to check for deadline warnings
                "if len(g:rptlist)>0
                call add(g:rptlist, calutil#cal(testjul))
                "endif
                break
            endif
            let first_cal = calutil#cal(first_of_month_jul)
            let nextmonth = str2nr(first_cal[5:6]) + rptnum
            let year = str2nr(first_cal[0:3]) 
            if nextmonth >= 13
                let nextmonth = (nextmonth-12)
                let year += 1 
            endif
            let first_of_month_jul = calutil#jul(string(year) . '-' . s:Pre0(nextmonth) . '-01')
        endwhile
    endif

    return g:rptlist

endfunction

function! s:BufMinMaxDate()
    let b:v.MinMaxDate=['2099-12-31','1900-01-01']
    g/<\d\d\d\d-\d\d-\d\d/call s:CheckMinMax()

endfunction
function! s:CheckMinMax()
    let date = matchstr(getline(line(".")),'<\zs\d\d\d\d-\d\d-\d\d')
    if (date < b:v.MinMaxDate[0])
        let b:v.MinMaxDate[0] = date
    endif
    if (date > b:v.MinMaxDate[1])
        let b:v.MinMaxDate[1] = date
    endif
endfunction        
function! s:Timeline(...)
    if a:0 > 0
        let spec = a:1
    else
        let spec = ''
    endif
    if bufname("%") ==? '__Agenda__'
        "go back up to main org buffer
        "wincmd k
    endif
    if exists('g:org_search_spec')
        let prev_spec = g:org_search_spec
    endif
    if exists('g:agenda_files')
        let prev_files = g:agenda_files
    endif
    exec "let g:agenda_files=['".substitute(expand("%:p"),' ','\\ ','g')."']"
    call s:BufMinMaxDate()
    let num_days = 1 + calutil#jul(b:v.MinMaxDate[1]) - calutil#jul(b:v.MinMaxDate[0])
    try
        "AAgenda
        call OrgRunAgenda(b:v.MinMaxDate[0], num_days,spec)
    finally
        if exists('prev_spec')
            let g:org_search_spec = prev_spec
        endif
        if exists('prev_files')
            let g:agenda_files = prev_files
        endif
    endtry
endfunction

function! s:Pre0(s)
    return repeat('0',2 - len(a:s)) . a:s
endfunction

function! s:PrePad(s,amt,...)
    if a:0 > 0
        let char = a:1
    else
        let char = ' '
    endif
    return repeat(char,a:amt - len(a:s)) . a:s
endfunction
function! s:AgendaCompare(i0, i1)
    let mymstr = '^\(\d\+\)\s\+\(\S\+\)\s\+\(\%24c.\{11}\).*\(\*\+\)\s\(.*$\)'
    " mymstr below would be better match string regex, but generic dates
    " have no text at position 24 to match \S . . . "
    "let mymstr = '^\(\d\+\)\s\+\(\S\+\)\s\+\(\S.\{10}\).*\(\*\+\)\s\(.*$\)'
    " [1] is lineno, [2] is file, [3] is scheduling, [4] is levelstarts, 
    " [5] is headtext
    let cp0 = matchlist(a:i0,mymstr)
    let cp1 = matchlist(a:i1,mymstr)
    let myitems = [cp0, cp1]
    let sched_comp = []
    let i = 0
    while i < 2
        let item = myitems[i]
        if item[3][0] ==? 'S'
            if item[3][5] ==? ':'
                "let str_ord = 'a' . substitute(item[3][6:8],' ', '0','')
                let str_ord = 'aa' . s:PrePad(1000-str2nr(item[3][6:8]),' ', '0')
            else
                let str_ord = 'ab000'
            endif
        elseif item[3][0] ==? 'I' 
            if matchstr(item[3],'-') ># ''
                let str_ord = 'd-'.s:PrePad(1000-str2nr(matchstr(item[3],'\d\+')),3,'0')
            else
                let str_ord = 'da'.s:PrePad(matchstr(item[3],'\d\+'),3,'0')
            endif
        elseif item[3][0] ==? 'D'
            let str_ord = 'd0000'
        elseif item[3][0] ==? ' '
            let str_ord = 'zzzzz'
        else
            let str_ord = item[3][:4]
        endif
        call add(sched_comp,str_ord.item[2].s:PrePad(item[1],5,'0'))
        let i += 1
    endwhile 

    return sched_comp[0] ==? sched_comp[1] ? 0 : sched_comp[0] > sched_comp[1] ? 1 : -1

"    let num1 = str2nr(matchstr(a:i1,'In *\zs[ -]\d\+\ze d.:'))
"    let num2 = str2nr(matchstr(a:i2,'In *\zs[ -]\d\+\ze d.:'))
"    if num1 == 0 
"        let num1 = str2nr(matchstr(a:i1,'Sched: *\zs\d\+\zeX:'))
"        if num1 !=0 
"            let num1 = -num1 - 10000
"        endif
"    endif
"    if num2 == 0 
"        let num2 = str2nr(matchstr(a:i2,'Sched: *\zs\d\+\zeX:'))
"        if num2 !=0 
"            let num2 = -num2 - 10000
"        endif
"    endif
"    if (a:i1 =~ '^\d\+\s\+\S\+\s\+\d') 
"        let num1=num1-20000
"    endif
"    if (a:i2 =~ '^\d\+\s\+\S\+\s\+\d') 
"        let num2=num2-20000
"    endif

"    return num1 == num2 ? 0 : num1 > num2 ? 1 : -1

endfunc

function! s:DateListAdd(valdict)
    let namelist = [' GENERAL','SCHEDULED','CLOSED','DEADLINE']
    let templist = []
    call add(templist, get(a:valdict,'ud',0))
    call add(templist, get(a:valdict,'sd',0))
    call add(templist, get(a:valdict,'cd',0))
    call add(templist, get(a:valdict,'dd',0))
    let i = 0
    while i < 4
        if templist[i] != 0
            call add(g:org_datelist, templist[i] . ' ' . namelist[i] . ' ' . a:valdict.l )
        endif
        let i += 1
    endwhile
    return a:valdict
endfunction 

function! OrgAgendaMove(direction,count)
    " need to add functionaity for count, refactor
    let cnt = (a:count == 0) ? 1 : a:count
    let cnt = (a:direction ==? 'forward') ? cnt : -cnt
    let date_jul = calutil#jul(g:agenda_startdate)
    let ymd_list = split(g:agenda_startdate,'-')

    if g:org_agenda_days == 1 
        let g:agenda_startdate = calutil#cal(date_jul + (cnt * 1))
    elseif g:org_agenda_days == 7
        let g:agenda_startdate = calutil#cal(date_jul + (cnt * 7))
    elseif g:org_agenda_days >= 360
        let g:agenda_startdate = string(ymd_list[0] + (cnt * 1)) .'-01-01'
    else
        let ymd_list[1] = ymd_list[1] + (cnt * 1)
        if ymd_list[1] > 0
            let ymd_list[0] += ymd_list[1] / 12
            let ymd_list[1] = ymd_list[1] % 12
        else
            let ymd_list[0] += (ymd_list[1] / 12) - 1
            let ymd_list[1] = 12 + (ymd_list[1] % 12)
        endif
        let g:agenda_startdate = ymd_list[0] . '-' .
                    \ s:Pre0(string(ymd_list[1])) .'-01'
        let g:org_agenda_days = s:DaysInMonth(g:agenda_startdate)
    endif

    if g:org_agenda_days == 1
        "call OrgRunAgenda(g:agenda_startdate,g:org_agenda_days,g:org_search_spec,g:agenda_startdate)
        call OrgRunCustom({'redo_num': line('.'), 'type':'agenda', 'agenda_date': g:agenda_startdate, 'agenda_duration': g:org_agenda_days, 'spec': g:org_search_spec})
    else
        "call OrgRunAgenda(g:agenda_startdate,g:org_agenda_days,g:org_search_spec)
        call s:RunCustom({'redo_num': line('.'), 'type':'agenda', 'agenda_date': g:agenda_startdate, 'agenda_duration': g:org_agenda_days ,'spec': g:org_search_spec})
    endif
endfunction

function! s:TimeGrid(starthour,endhour,inc)
    let result = []
    for i in range(a:starthour, a:endhour,a:inc)
        call add(result,repeat(' ',23).s:Pre0(i).':00......       ------------')
    endfor
    return result
endfunction

function! s:MakeCalendar(date, daycount)
    "function! s:MakeCalendar(year, month, day, daycount)
    " this function is taken from vim tip by Siegfried Bublitz
    " at: http://vim.wikia.com/wiki/Generate_calendar_file
    " with many mods to 1.output to list rather than to buffer
    " and 2. get weekday and weekno from calutils
    let g:agenda_date_dict = {}
    let g:agenda_head_lookup = {}
    "let startdate = calutil#Jul2Cal((calutil#Cal2Jul(a:year,a:month,a:day) - calutil#DayOfWeek(a:year,a:month,a:day)))
    let year = split(a:date,'-')[0]
    let month = split(a:date,'-')[1]
    let day = split(a:date,'-')[2]
    let day = str2nr(day)

    if a:daycount == 7
        let wd = 1
    elseif (a:daycount>=28) && (a:daycount <=31)
        let wd = calutil#dow(a:date[0:7].'01') + 1
    else
        let wd = calutil#dow(a:date) + 1
    endif
    let week = 1 + (calutil#Cal2Jul(year,month,day) - calutil#Cal2Jul(year,1,1)) / 7
    let index = 0
    let datetext = ''
    let diy = 777 " day in year, wrong before next year
    while (index < a:daycount) " no of days to output
        let diy = diy + 1
        if (wd > 7)
            let wd = 1
            let week = week + 1
            if (week >= 53)
                if (week >= 54)
                    let week = 1
                elseif (day >= 28 || day <= 3)
                    let week = 1
                endif
            endif
        endif
        let monthnames=['January','February','March','April','May','June','July',
                    \ 'August','September','October','November','December']
        "let daynames = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
        let daynames = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
        let dn = daynames[wd-1]
        if ((day > 31) || (month == 2 && (day > 29 || day > 28 && year % 4))
                    \ || (month == 4 && day > 30) || (month == 6 && day > 30)
                    \ || (month == 9 && day > 30) || (month == 11 && day > 30))
            let day = 1
            let month = month + 1
            if (month > 12)
                let month = 1
                let diy = 1
                let year = year + 1
                if (wd <= 3)
                    let week = 1
                endif
            endif
        endif

        let datetext = dn . repeat(' ',10-len(dn)) . (day<10?'   ':'  ') . 
                    \ day . ' ' . monthnames[month-1] . ' ' . year . (wd == 1 ? ' Wk' . week : '' )

        let g:agenda_date_dict[year . '-' . s:Pre0(month) .  '-' .  (day<10 ? '0'.day : day) ]
                    \ = {'marker': datetext, 'l': [] }
        let index = index + 1
        let day = day + 1
        let wd = wd + 1
    endwhile

endfunction

function! s:ActualBufferLine(lineref_in_agenda,bufnumber)
    let actual_line = matchstr(s:GetPlacedSignsString(a:bufnumber),'line=\zs\d\+\ze\s\+id='.a:lineref_in_agenda)
    return actual_line
endfunction

function! s:AgendaPutText(...)
    let save_cursor = getpos(".")
    let thisline = getline(line("."))
    if thisline =~ '^\d\+\s\+'
        if (getline(line(".") + 1) =~ '^\*\+ ')
            "let file = matchstr(thisline,'^\d\+\s\+\zs\S\+\ze')
            "let file = s:filedict[str2nr(matchstr(thisline, '^\d\d\d'))]
            let file = s:agenda_files_copy[str2nr(matchstr(thisline, '^\d\d\d'))]
            "let lineno = matchstr(thisline,'^\d\+\ze\s\+')
            let lineno = str2nr(matchstr(thisline,'^\d\d\d\zs\d*'))
            let starttab = tabpagenr() 

            "call org#LocateFile(file.'.org')
            call org#LocateFile(file)
            if g:agenda_date_dict != {}
                "let confirmhead = g:agenda_head_lookup[lineno]
                let confirmhead = lineno
            elseif g:adict != {}
                let confirmhead = lineno
            endif
            let newhead = matchstr(s:GetPlacedSignsString(bufnr("%")),'line=\zs\d\+\ze\s\+id='.confirmhead)
            let newhead = s:OrgGetHead_l(newhead)
            execute newhead
            let lastline = s:OrgNextHead_l(newhead) - 1
            if lastline > newhead
                let g:text = getline(newhead,lastline)
            elseif lastline == -1
                let g:text = getline(newhead,line('$'))
            else    
                let g:text = []
            endif

            execute 'tabnext ' . starttab
            execute bufwinnr('Agenda').'wincmd w'

            call setpos(".",save_cursor)
            " okay, we're back in agenda and have main buffer's
            " text in g:text, now need to compare it

            normal j
            let firstline = line(".")
            let daytextpat = '^\S\+\s\+\d\{1,2}\s\S\+\s\d\d\d\d'
            while (getline(line(".")) !~ '^\d\+\s\+') && (line(".") != line("$"))
                        \ && (getline(line(".")) !~ daytextpat)
                        \ && (getline(line(".")) !~ '\d empty days omitted')
                normal j
            endwhile
            let lastline = line(".")
            if (lastline < line("$"))  ||
                        \ ( (getline(line(".")) =~ '^\d\+\s\+')
                        \ || (getline(line(".")) =~ daytextpat) 
                        \ || (getline(line(".")) =~ '\d empty days omitted') )
                let lastline = line(".") - 1
            endif
            "execute firstline . ', ' . lastline . 'd'
            if g:text ==? getline(firstline, lastline)
                echo "headings are identical"
            else
                if g:adict != {}
                    let resp = confirm("Heading's text has changed, save changes?","&Save\n&Cancel",1)
                    if resp == 1
                        call s:SaveHeadline(file, newhead,getline(firstline,lastline))
                        "call s:SaveHeadline(file, confirmhead,getline(firstline,lastline))
                    else
                        echo "Changes were _not_ saved."
                    endif
                else
                    call confirm("Heading's text has changed, but saving is\n"
                        \ . "temporarily disabled for date-based agenda views.\n"
                        \ . "No changes are being saved, original buffer text remains as it was.")
                endif
            endif
        endif
    else
        echo "You're not on a headline line."
    endif
    call setpos(".",save_cursor)
endfunction
function! s:SaveHeadline(file, headline, lines)
    let file = a:file
    let headline = a:headline
    let lines=a:lines
    let starttab = tabpagenr() 

    "call org#LocateFile(file.'.org')
    call org#LocateFile(file)
    "let newhead = matchstr(s:GetPlacedSignsString(bufnr("%")),'line=\zs\d\+\ze\s\+id='.headline)
    let newhead = a:headline
    execute newhead

    let lastline = s:OrgNextHead_l(newhead) - 1
    execute newhead+1.','.lastline.'d'
    " don't delete orig headline b/c that's where sign is placed
    call setline(newhead,lines[0])
    call append(newhead,lines[1:])

    execute 'tabnext ' . starttab
    execute bufwinnr('Agenda').'wincmd w'

endfunction
function! OrgAgendaGetText(...)
    "type: 'datedict' for date agenda, 'adict' for regular search
    let cycle_todo = 0
    if a:0 >= 1 
        let cycle_todo = 1
        if a:0 == 2
            let newtodo = a:2
        endif
    endif
    " called by <TAB> map to toggle view of heading's body text in agenda
    " view
    let save_cursor = getpos(".")
    let thisline = getline(line("."))
    let curTodo = matchstr(thisline, '\*\+ \zs\S\+')
    if thisline =~ '^\d\+\s\+'
        if (getline(line(".") + 1) =~ '^\d\+\s\+') || (line(".") == line("$")) ||
                    \ (getline(line(".") + 1 ) =~ '^\S\+\s\+\d\{1,2}\s\S\+\s\d\d\d\d')
                    \ || (getline(line(".") + 1 ) =~ '\d empty days omitted')

            let starttab = tabpagenr() 

            " go to the heading's file
            let file = s:agenda_files_copy[str2nr(matchstr(thisline, '^\d\d\d'))]
            let lineno = str2nr(matchstr(thisline,'^\d\d\d\zs\d*'))
            call org#LocateFile(file)

            let save_cursor2 = getpos(".")
            
            let newhead = matchstr(s:GetPlacedSignsString(bufnr("%")),'line=\zs\d\+\ze\s\+id=' . lineno)
            let newhead = s:OrgGetHead_l(newhead)
            
            execute newhead

            if cycle_todo
                " do todo operation
                if a:0 >= 2
                    silent call s:ReplaceTodo(newtodo)
                else
                    silent call s:ReplaceTodo()
                endif
                "normal V
                "redraw
                "sleep 100m
                "normal V
            else
                " get the heading's text block
                let lastline = s:OrgNextHead_l(newhead) - 1
                if lastline > newhead
                    let g:text = getline(newhead,lastline)
                elseif lastline == -1 
                    let g:text = getline(newhead,line('$'))
                else    
                    let g:text = []
                endif
            endif
            call setpos(".",save_cursor2)
            " now go back to agenda
            execute 'tabnext ' . starttab
            execute bufwinnr('Agenda').'wincmd w'
            if !cycle_todo
                call append(line("."),g:text)
            endif
        else
            " we're dealing with toggle of agenda heading that already
            " has main buffer heading text in agenda. . . 
            normal j
            let firstline = line(".")
            let daytextpat = '^\S\+\s\+\d\{1,2}\s\S\+\s\d\d\d\d'
            while (getline(line(".")) !~ '^\d\+\s\+') && (line(".") != line("$"))
                        \ && (getline(line(".")) !~ daytextpat)
                        \ && (getline(line(".")) !~ '\d empty days omitted')
                normal j
            endwhile
            let lastline = line(".")
            if (lastline < line("$"))  ||
                        \ ( (getline(line(".")) =~ '^\d\+\s\+')
                        \ || (getline(line(".")) =~ daytextpat) 
                        \ || (getline(line(".")) =~ '\d empty days omitted')) 
                let lastline = line(".") - 1
            endif
            call setpos(".",save_cursor)
            " see if it there are changes that need to be
            " pushed back to main buffer
            call s:AgendaPutText()
            silent execute firstline . ', ' . lastline . 'd'
        endif
    else
        echo "You're not on a headline line."
    endif
    call setpos(".",save_cursor)
    if cycle_todo
        " we did cycle in main buffer, now do in agenda
        if a:0 >= 2
            silent call s:ReplaceTodo(s:last_newtodo)
        else
            silent call s:ReplaceTodo(s:last_newtodo)
        endif
        echo "Todo cycled."
    endif
endfunction

function! s:MoveToHeadingFromAgenda(agenda_line)
    "given line from agenda, go to the associated file and heading
    let thisline = getline(a:agenda_line)
    let file = s:agenda_files_copy[str2nr(matchstr(thisline, '^\d\d\d'))]
    let lineno = str2nr(matchstr(thisline,'^\d\d\d\zs\d*'))
    call org#LocateFile(file)
    " need to check sign at this lineno, since for date agenda we're not necessarily at heading
    let newhead = matchstr(s:GetPlacedSignsString(bufnr("%")),'line=\zs\d\+\ze\s\+id=' . lineno)
    let newhead = s:OrgGetHead_l(newhead)
    execute newhead
endfunction


function! s:IsVisibleHeading(line)
    " returns 1 if line is of a visible heading,
    " 0 if not
    " a heading is visible if foldclosed = -1
    " (i.e., it's not in a fold) 
    " OR if it's not in an earlier-started fold
    " (i.e. start of fold heading is in is 
    " same as line of heading)
    " ***************************   the second and third lines of if 
    " statement are necessary because of bug where foldclosed is less 
    " than a head even though it is the fold head ***************
    let fc = foldclosed(a:line)
    if ((a:line > 0) && (fc == -1)) || (fc == a:line)
                \ || ((fc < a:line) &&  s:IsText(fc) )
                \ || ((fc < a:line) &&  (foldclosedend(fc) < a:line) )
        "   \ || (s:Ind(a:line) == 2)
        return 1
    else    
        return 0
    endif
endfunction

function! OrgSingleHeadingText(operation)
    " expand or collapse all visible Body Text
    " under Heading fold that cursor is in
    " operation:  "collapse" or "expand"
    " expand or collapse all Body Text 
    " currently visible under current heading
    let l:startline = line(".")
    let l:endline = s:OrgSubtreeLastLine_l(l:startline) - 1
    call OrgBodyTextOperation(l:startline,l:endline,a:operation)
endfunction

function! s:StarLevelFromTo(from, to)
    let save_cursor = getpos(".")
    set fdm=manual
    let b:v.levelstars = a:to
    ChangeSyn
    g/^\*\+/call setline(line("."),substitute(getline(line(".")),'^\*\+','*' . 
                \ repeat('*',(len(matchstr(getline(line(".")),'^\*\+')) - 1) * a:to / a:from),''))
    set fdm=expr
    call setpos(".",save_cursor)
endfunction

function! s:StarsForLevel(level)
    return 1 + (a:level - 1) * b:v.levelstars
endfunction

function! s:OrgExpandLevelText(startlevel, endlevel)
    " expand regular text for headings by level
    let save_cursor = getpos(".")

    normal gg
    let startlevel = s:StarsForLevel(a:startlevel)
    let endlevel = s:StarsForLevel(a:endlevel)
    let l:mypattern = substitute(b:v.headMatchLevel,'level', startlevel . ',' . endlevel, "") 
    while search(l:mypattern, 'cW') > 0
        execute line(".") + 1
        while getline(line(".")) =~ b:v.drawerMatch
           execute line(".") + 1
           normal! j
        endwhile
        if s:IsText(line(".")) 
            normal zv
        endif
        "normal l
    endwhile

    call setpos('.',save_cursor)

endfunction

" just an idea using 'global' not used anywhere yet
" visible is problem, must operate only on visible, doesn't do ths now
function! s:BodyTextOperation3(startline,endline, operation)
    let l:oldcursor = line(".")
    let nh = 0
    call cursor(a:startline,0)
    g/\*\{4,}/s:DoAllTextFold(line("."))
    call cursor(l:oldcursor,0)

endfunction


function! OrgBodyTextOperation(startline,endline, operation)
    " expand or collapse all Body Text from startline to endline
    " operation:  "collapse" or "expand"
    " save original line 
    let l:oldcursor = line(".")
    let nh = 0
    " go to startline
    call cursor(a:startline,0)
    " travel from start to end operating on any
    while 1
        if getline(line(".")) =~ b:v.headMatch
            if a:operation ==? "collapse"
                call s:DoAllTextFold(line("."))
            elseif a:operation ==? 'expand'
                normal zv
            endif
            "elseif s:IsText(line(".")+1) && foldclosed(line(".")) == line(".")
            "elseif foldclosed(line(".")) == line(".")
            "   "echo 'in expand area'
            "   if a:operation ==? 'expand'
            "       normal zv
            "   endif   
        endif
        let lastnh = nh
        let nh = s:NextVisibleHead(line("."))
        "echo 'last ' . lastnh . '    now ' . nh
        if (nh == 0) || (nh >= a:endline) || (nh == lastnh) 
            "echo "hit break"
            break
        elseif lastnh == nh
            break
            echo "bad exit from BodyTextOp"
        else
            "echo "hit ex"
            execute nh 
        endif

    endwhile
    " now go back to original line position in buffer
    call cursor(l:oldcursor,0)
endfunction

let g:calendar_sign = 'OrgCalSign'
function! OrgCalSign(day, month, year)
  if a:year .'-'.s:Pre0(a:month).'-'.s:Pre0(a:day) ==? s:org_cal_date
      return 1
  else
      return 0
  endif
endfunction
function! OrgSetLine(line, file, newtext)
    let save_cursor = getpos(".")
    let curfile = expand("%:t")

    call org#LocateFile(a:file)
    call setline(a:line,a:newtext)
    
    call org#LocateFile(curfile)
    call setpos('.',save_cursor)
endfunction
function! OrgGetLine(line, file)
    let save_cursor = getpos(".")
    let curfile = expand("%:t")

    call org#LocateFile(a:file)
    let result = getline(a:line)
    
    call org#LocateFile(curfile)
    call setpos('.',save_cursor)
    return result
endfunction
function! OrgAgendaDateType()
    " return type of date line in Agenda
    let text = getline(line('.'))[19:29]
    if text =~ 'Sched'
        let result = 'Scheduled'
    elseif text =~ '\(In \|DEADLINE\)'
       let result = 'Deadline'
    elseif text =~ 'Closed'
        let result = 'Closed'
    elseif text =~ '('
        let result = 'Range'
    else
        let result = 'Regular'
    endif
    return result
endfunction

function! GetDateAtCursor()

    return matchstr( GetDateSpecAtCursor() , '^[[<]\zs\d\d\d\d-\d\d-\d\d' )

endfunction

function! GetDateSpecAtCursor()
    let savecursor = getpos(".")
    " save visual bell settings so no bell
    " when not found"
    let orig_vb = &vb
    let orig_t_vb = &t_vb
    set vb t_vb=

    "  check for date string within brackets
    normal! va<
    silent! normal! "xy
    call setpos('.',savecursor)
    if len(@x) < 7 
        "normal! vi["xy
        normal! va[
        silent! normal! "xy
    endif

    if (len(@x)>=15) && (len(@x)<41)
        let date = matchstr(@x,'^[[<]\d\d\d\d-\d\d-\d\d')
    else
        let date = ''
    endif

    " restore visual bell settings
    let &vb = orig_vb
    let &t_vb = orig_t_vb

    if date ># ''
        " return with only opening '<' or '['
        return @x
    else
        return ''
    endif

    call setpos(".", savecursor)
        
endfunction

function! CalEdit( sdate, stime )
        " bring up calendar to edit and return a date value
        call org#SaveLocation()
        let basedate = a:sdate ==# '' ? s:Today() : a:sdate 
        let basetime = a:stime
        let newdate = '<' . basedate[0:9] . ' ' . calutil#dayname(basedate[0:9]) . (basetime ># '' ? ' ' . basetime : '') . '>'
        let newtime = basetime

        hi Cursor guibg=black
        let s:org_cal_date = newdate[1:10]
        call s:Calfunc(1,newdate[1:4],str2nr(newdate[6:7]))
        " highlight chosen dates in calendar
        hi Ag_Date guifg=red
        call matchadd('Ag_Date','+\s\{0,1}\d\+')
        redraw
        let g:calendar_action='<SNR>'.s:SID().'_CalendarInsertDate'
        let cue = ''
        while 1
            echohl LineNr | echon 'Date+time ['.basedate . ' '.basetime.']: ' 
            "echohl None | echon cue.'_   =>' | echohl WildMenu | echon ' '.newdate[:-2] . ' ' . newtime 
            echohl None | echon cue.'_   =>' | echohl WildMenu | echon ' '.newdate[:-2] . '>' 
            let nchar = getchar()
            let newchar = nr2char(nchar)
            if newdate !~ 'interpret'
                let curdif = calutil#jul(newdate[1:10])-calutil#jul(s:Today())
            endif
            if (nchar ==? "\<BS>") && (len(cue)>0)
                let cue = cue[:-2]
            elseif nchar ==? "\<s-right>"
                let cue = ((curdif+1>=0) ?'+':'').(curdif+1).'d'
            elseif nchar ==? "\<s-left>"
                let cue = ((curdif-1>=0) ?'+':'').(curdif-1).'d'
            elseif nchar ==? "\<s-down>"
                let cue = ((curdif+7>=0) ?'+':'').(curdif+7).'d'
            elseif nchar ==? "\<s-up>"
                let cue = ((curdif-7>=0) ?'+':'').(curdif-7).'d'
            elseif nchar ==? "\<c-down>"
                let cue = ((curdif+30>=0) ?'+':'').(curdif+30).'d'
            elseif nchar ==? "\<c-up>"
                let cue = ((curdif-30>=0) ?'+':'').(curdif-30).'d'
            elseif nchar ==? "\<s-c-down>"
                let cue = ((curdif+365>=0) ?'+':'').(curdif+365).'d'
            elseif nchar ==? "\<s-c-up>"
                let cue = ((curdif-365>=0) ?'+':'').(curdif-365).'d'
            elseif newchar ==? "\<cr>"
                break
            elseif newchar ==? "\<Esc>"
                hi Cursor guibg=gray
                if bufwinnr('__Calendar') > 0
                    bdelete Calendar
                endif
                redraw
                return ''
            elseif (nchar ==? "\<LeftMouse>") && (v:mouse_win > 0) && (bufwinnr('__Calendar') == v:mouse_win)
                let g:cal_list=[]
                exe v:mouse_win . "wincmd w"
                exe v:mouse_lnum
                exe "normal " . v:mouse_col."|"
                normal 
                if g:cal_list != []
                    if newtime ># ''
                        let timespec = newtime
                    else
                        let timespec = matchstr(newdate,'\S\+:.*>')
                    endif
                    let newdate = '<'.g:cal_list[0].'-'.s:Pre0(g:cal_list[1]).'-'.s:Pre0(g:cal_list[2]) . ' '
                    let newdate .= calutil#dayname( g:cal_list[0].'-'.g:cal_list[1].'-'.g:cal_list[2])
                    let newdate .=  timespec ># '' ? ' ' . timespec : ''.'>'
                    break
                endif
            else
                let cue .= newchar
            endif
            try
                let newdate = '<' . s:GetNewDate(cue,basedate,basetime)  . '>'
            catch
                " don't raise error if user mistypes cue. . . 
                " or if last char makes cue uninterpretable
                let newdate = "can't interpret date cue  "
            endtry
            if g:org_use_calendar && (match(newdate,'\d\d\d\d-\d\d')>=0)
                let s:org_cal_date = newdate[1:10]
                call s:Calfunc(1,newdate[1:4],str2nr(newdate[6:7]))
            endif
            echon repeat(' ',72)
            redraw
        endwhile
        hi Cursor guibg=gray
        bdelete __Calendar
        call org#RestoreLocation()
        return newdate 
endfunction

command! OrgColumns :call OrgColumnsDashboard()
function! OrgColumnsDashboard(...)
    let key = (a:0==1) ? a:1 : ''
    let save_cursor = getpos('.')
    if !exists('w:v.columnview')
        let w:v={'columnview':0}
        let w:v.org_item_len=100
        let w:v.org_colview_list = []
        let w:v.org_current_columns = ''
        let w:v.org_column_item_head = ''
    endif
    if !exists('b:v.org_columns_show_headings')
        let b:v.org_columns_show_headings = 0
    endif
    let force_all = 0

    echohl WarningMsg
    let save_more = &more
    set nomore
    while 1
    if key ==# ''
            echohl MoreMsg
            echo "=========================================="
            echo " Buffer default columns:           " . b:v.buffer_columns
            echo " Current default columns:          " . w:v.org_current_columns
            echo " Column view is currently:         " . (w:v.columnview==1 ? 'ON' : 'OFF')
            echo " Show column headers is currently: " . (b:v.org_columns_show_headings ? 'ON' : 'OFF')
            echo " Heading line count is currently:  " . (g:org_show_fold_lines==1 ? 'ON' : 'OFF')
            if (w:v.columnview == 0) && (force_all == 1)
                    echo " NEXT CHOICE WILL BE APPLIED TO ENTIRE BUFFER"
            endif
            echo " "
            echo " Press key to enter a columns command"
            echo " ------------------------------------"
            if (w:v.columnview == 0) && (force_all == 0)
                    echo " f   force all of buffer to use chosen columns"
            endif
            if w:v.org_current_columns != b:v.buffer_columns
                echo " r   revert to buffer default columns"
            endif
            echo " t   toggle column view on/off"
            echo " h   toggle show headings on/off"
            echo " l   line count on/off"
            if len(g:org_custom_column_options) > 0 
                echo " Custom columns settings:"
            endif
            let i = 0
            while i < len(g:org_custom_column_options) 
                echo " " . i . "   " . g:org_custom_column_options[i]
                let i += 1
            endwhile
            echo " ------------------------------------"
            echo " "
            echohl Question
            let key = nr2char(getchar())
            redraw
        endif
        
        if key ==? 'f'
            let force_all = 1
            let key = ''
            redraw
            continue
        endif

        let master_head = (force_all == 1 ) ? 0 : line('.')
       
        if key ==? 'r'
            let w:v.org_current_columns = b:v.buffer_columns
            if w:v.columnview == 1
                "turn off col view
                call ToggleColumnView(master_head, w:v.org_current_columns)
            endif
            call ToggleColumnView(master_head, w:v.org_current_columns)
        elseif key ==? 't'
            " current columns will get set in SetColumnHeads()
            call ToggleColumnView(master_head,'')
        elseif key ==? 'h'
            let b:v.org_columns_show_headings = 1 - b:v.org_columns_show_headings
        elseif key ==? 'l'
            let g:org_show_fold_lines = 1 - g:org_show_fold_lines
        elseif key =~ '[0-9]'
            let w:v.org_current_columns = g:org_custom_column_options[key]
            if w:v.columnview == 1
                " turn off
                call ToggleColumnView(master_head, w:v.org_current_columns)
            endif
            call ToggleColumnView(master_head, w:v.org_current_columns)
        else
            echo "No column option selected."
        endif
        break
    endwhile

    if b:v.org_columns_show_headings == 0
        call s:ColHeadWindow('',0)
    elseif (w:v.columnview == 1) && (bufnr('ColHeadBuffer') == -1) 
        call s:ColHeadWindow(w:v.org_column_item_head)
    endif
    echohl None
    let &more = save_more
    call s:AdjustItemLen()
    " redraw folded headings
    setlocal foldtext=OrgFoldText()
    call setpos('.',save_cursor)
endfunction
function! OrgDateDashboard(...)
    let key = (a:0==1) ? a:1 : ''
    let save_cursor = getpos('.')
    let save_window = winnr()
    if bufname("%") ==? ('__Agenda__')
        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
        let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))
        let buffer_lineno = s:ActualBufferLine(lineno,bufnr(file))
        let props = s:GetProperties(buffer_lineno, 0, file)
    else
        let props = s:GetProperties(line('.'),0)
    endif

    if key ==# ''
        echohl MoreMsg
        echo " ================================="
        echo " Press key, for a date command:"
        echo " ---------------------------------"
        echo " d   set DEADLINE for current heading (currently: " . get(props,'DEADLINE','NONE') . ')'
        echo " s   set SCHEDULED for current heading (currently: " . get(props,'SCHEDULED','NONE') . ')'
        echo " c   set CLOSED for current heading (currently: " . get(props,'CLOSED','NONE') . ')'
        echo " t   set TIMESTAMP for current heading (currently: " . get(props,'TIMESTAMP','NONE') . ')'
        echo " g   set date at cursor"
        echo " "        
        echo " "
        echohl Question
        let key = nr2char(getchar())
        redraw
    endif
    if key ==? 'd'
        call OrgDateEdit('DEADLINE')
    elseif key ==? 's'
        call OrgDateEdit('SCHEDULED')
    elseif key ==? 'c'
        call OrgDateEdit('CLOSED')
    elseif key ==? 't'
        call OrgDateEdit('TIMESTAMP')
    elseif key ==? 'g' && (bufname('%') != '__Agenda__')
        call OrgDateEdit('ATCURSOR')
    else
        echo "No date command selected."
    endif
    echohl None
    exe save_window . 'wincmd w'
    call setpos('.',save_cursor)
endfunction
function! OrgAgendaDateInc(datecue)
    let agline = getline(line('.'))
    if agline =~ 'Deadline:\|In.*\dd\.:'
        call OrgDateEdit('DEADLINE',a:datecue)
    elseif agline =~ 'Scheduled:\|Sched:'
        call OrgDateEdit('SCHEDULED',a:datecue)
        let type = 'SCHEDULED'
    elseif agline =~ 'Closed:'
        call OrgDateEdit('CLOSED',a:datecue)
    else
        call OrgDateEdit('TIMESTAMP',a:datecue)
    endif
    
endfunction
function! OrgDateEdit(type,...)
    if a:0 == 1
        "use this to bypass calendar ui
        let datecue = a:1
    endif
    " type can equal DEADLINE/CLOSED/SCHEDULED/TIMESTAMP/ATCURSOR 
    let save_cursor = getpos('.')
    let old_cal_navi = g:calendar_navi
    unlet g:calendar_navi
    try
        let dtype = a:type
        if bufname("%") ==? ('__Agenda__')
            "get file, lineno, and other data if in Agenda
            let from_agenda=1
            let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
            let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))
            let buffer_lineno = s:ActualBufferLine(lineno,bufnr(file))
            let bufline = OrgGetLine(buffer_lineno,file)
        else
            let from_agenda=0
            let buffer_lineno = line('.')
            let bufline = getline(buffer_lineno)
            let file = expand("%:t")
        endif
        if dtype =~ '\(DEADLINE\|SCHEDULED\|CLOSED\|TIMESTAMP\|ATCURSOR\)'
            if dtype == 'ATCURSOR'
                let my_date = GetDateSpecAtCursor()
            else
                let my_date = s:GetProp(dtype,buffer_lineno, file)
            endif
        
            let bracket = my_date[0]
            let orig_date = matchstr( my_date, '[[<]\zs\d\d\d\d-\d\d-\d\d' )
            let orig_time = matchstr( my_date, '[[<]\d\d\d\d-\d\d-\d\d ... \zs\d\d:\d\d' )
            if orig_time ># ''
                let rpt_or_warning = matchstr( my_date, ' \d\d:\d\d\zs .*\ze.$')
            else    
                let rpt_or_warning = matchstr( my_date, '-\d\d-\d\d \S\S\S\zs .*\ze.$')
            endif

            if !exists('datecue')
                let cal_result = CalEdit(orig_date, orig_time)
                if cal_result ==# ''
                    return
                endif
            else
                let cal_result = s:GetNewDate(datecue, orig_date, orig_time)
                let cal_result = bracket . cal_result . (bracket=='<'?'>':']')
            endif
            if bracket == '['
                let cal_result = '[' . cal_result[1:-2] . rpt_or_warning .  ']'
            else
                let cal_result = '<' . cal_result[1:-2] . rpt_or_warning .  '>'
            endif

            " back to main window if agenda is present and cursor is in it
            if (from_agenda == 0) && bufname("%") ==? '__Agenda__'
               "wincmd k 
               exe bufwinnr(file) . 'wincmd w'
            endif

            if dtype == 'ATCURSOR'
                " put new date into text
                call setpos('.', save_cursor)
                if cal_result =~ '^.\d\d\d\d-\d\d'
                    let @x = cal_result[1:-2]
                    if my_date ># ''
                        "replace existing date within delimiters
                        exec 'normal vi' . my_date[0] . 'd'
                        normal h"xpll
                    else
                        "paste in brand new date
                        exec 'normal i <> '
                        normal hh"xpll
                    endif
                endif
            else
                " set the prop with new date . . . 
                if (from_agenda == 0)
                    "just set the prop if we're in org file buffer
                    call s:SetProp(dtype,cal_result,buffer_lineno, file)
                else
                    if empty(b:v.heading_marks_dict)
                        " just mark and do current item
                        "let b:v.heading_marks = [line('.')]
                        let b:v.heading_marks_dict[line('.')] = 1
                    endif
                    for item in sort(keys(b:v.heading_marks_dict), 's:ReverseSort')
                        exec item
                        let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
                        let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))
                        let buffer_lineno = s:ActualBufferLine(lineno,bufnr(file))
                        let bufline = OrgGetLine(buffer_lineno,file)
                        call s:SetProp(dtype,cal_result,buffer_lineno, file)
                        "put prop change indicator on line(s)
                        let cur_line = getline(line('.'))
                        let mylen = winwidth(0) - 29
                        let cur_line = (len(cur_line) > mylen) ? cur_line[:mylen] : cur_line . repeat(' ', mylen-len(cur_line))
                        let change_indicator = ' ' . dtype[0] . ' => ' . dtype . ' on ' . cal_result 
                        call setline(line('.'), cur_line . change_indicator)
                        execute 'sign unplace ' . item . ' buffer=' . bufnr('%')
                    endfor
                    let b:v.heading_marks = []
                    let b:v.heading_marks_dict = {}
                endif
            endif

            redraw
            echo 
            redraw
        else
            echo "Date type wasn't DEADLINE, SCHEDULED, CLOSED, TIMESTAMP, or ATCURSOR."
        endif
    finally
        let g:calendar_navi = old_cal_navi
        call setpos('.',save_cursor)
    endtry
endfunction

function! s:GetNewTime(cue, basetime)
    " called from caledit()
    let timecue = a:cue
    if timecue =~ '\d\d:\d\d'
        let mytime = ' '.timecue
    else
        let mytime = ''
    endif
    return mytime

endfunction

function! s:GetNewDate(cue,basedate,basetime)
    " called from caledit()
    if match(a:cue,'\S:') >= 0
        let mlist = matchlist(a:cue, '^\(.*\) \(\S\+:.*\)')
        let cue = mlist[1]
        let timecue = mlist[2]
    else
        let cue = a:cue
        let timecue = ''
    endif
    let basedate = a:basedate
    let newdate = DateCueResult( cue , basedate )
    let tmatch = matchlist( timecue , '\(\d\{1,2}\):\(\d\d\)\(am\|pm\)*')
    if !empty(tmatch)
        let hours = tmatch[1]
        if (tmatch[3]=='pm') && (hours < 12) 
            let hours = hours + 12
        elseif (tmatch[3]=='am') && (hours == 12) 
            let hours = 0
        endif 
        let hours = s:Pre0(hours)
        let mytime = ' ' . hours . ':' . tmatch[2]
    else
        let mytime = a:basetime ># '' ? ' ' . a:basetime : ''
    endif
    let mydow = calutil#dayname(newdate)
    return newdate . ' ' . mydow . mytime
endfunction
function! DateCueResult( cue, basedate)
        let cue = a:cue
        let basedate = a:basedate
        if cue =~ '^\(+\|++\|-\|--\)$'
            let cue = cue . '1d'
        elseif cue =~ '^\(+\|++\|-\|--\)\d\+$'
            let cue = cue .'d'
        endif
        if cue ==? '.'
            let newdate = strftime('%Y-%m-%d')
        elseif cue ==# ''
            let newdate = a:basedate
        elseif (cue =~ '^\d\+$') && (str2nr(cue) <= 31)
            " day of month string
            if str2nr(cue) > str2nr(basedate[8:9])
                let newdate = calutil#cal(calutil#jul(basedate[0:7].s:Pre0(cue)))
            else 
                let newmonth = s:Pre0(basedate[5:6]+1)
                let newdate = calutil#cal(calutil#jul(basedate[0:4].newmonth.'-'.s:Pre0(cue)))
            endif
        elseif cue =~ '^\d\+[-/]\d\+$'
            " month/day string
            let month = matchstr(cue,'^\d\+')
            let day = matchstr(cue,'\d\+$')
            let year = basedate[0:3]
            if basedate[0:4] . s:Pre0(month) . '-' . s:Pre0(day) < basedate
                let year = year + 1
            endif
            let newdate = calutil#cal(calutil#Cal2Jul(year,month,day))
        elseif cue =~ '\d\+/\d\+/\d\+'
            " m/d/y string
            let month = matchstr(cue,'^\d\+\ze/.*/')
            let day = matchstr(cue,'/\zs\d\+\ze/')
            let year = matchstr(cue,'/\zs\d\+\ze$')
            if len(year) < 3
                let year +=2000
            endif
            let newdate = calutil#cal(calutil#Cal2Jul(year,month,day))
        elseif cue =~ '\d\+-\d\+-\d\+'
            " y-m-d string
            let year = matchstr(cue,'^\d\+\ze-.*-')
            if year < 100
                let year +=2000
            endif
            let month = matchstr(cue,'-\zs\d\+\ze-')
            let day = matchstr(cue,'-\zs\d\+\ze$')
            let newdate = calutil#cal(calutil#Cal2Jul(year,month,day))

        elseif cue =~ s:org_monthstring . ' \d\+$'
            let month_str = matchstr(cue,'^' . s:org_monthstring)
            let month = 1 + index(s:org_months, tolower(month_str[:2]))
            let day = matchstr(cue,' \zs\d\+$')
            let year = basedate[0:3]
            if basedate[0:4] . s:Pre0(month) . '-' . s:Pre0(day) < basedate
                let year = year + 1
            endif
            let newdate = calutil#cal(calutil#Cal2Jul(year,month,day))
        elseif cue =~ s:org_monthstring . ' \d\+ \d\+$'
            let month_str = matchstr(cue,'^' . s:org_monthstring)
            let month = 1 + index(s:org_months, tolower(month_str[:2]))
            let day = matchstr(cue,' \zs\d\+\ze ')
            let year = str2nr(matchstr(cue,' \d\+ \zs\d\+$'))
            let year = (year < 1800) ? 2000 + year : year
            let newdate = calutil#cal(calutil#Cal2Jul(year,month,day))
        elseif cue =~ s:org_weekdaystring
            " wed, 3tue, 5fri, i.e., dow string
            let mycount = matchstr(cue,'^\d\+')
            let myday = matchstr(cue,s:org_weekdaystring) 
            let newday = index(s:org_weekdays,tolower(myday))
            let oldday = calutil#dow(matchstr(basedate,'\d\d\d\d-\d\d-\d\d'))
            if newday > oldday
                let amt=newday-oldday
            elseif newday < oldday
                let amt =7-oldday+newday
            else
                let amt = 7
            endif
            let amt = amt + (mycount*7)
            let newdate=calutil#cal(calutil#jul(basedate)+amt)
        elseif cue =~ '\c\([-+]\|[-+][-+]\)\d\+[ dwmy]'
            " plus minus count of dwmy
            let mlist =  matchlist(cue,'\c\([-+]\|[-+][-+]\)\(\d\+\)\([ wdmy]\)')
            let op = mlist[1]
            let mycount = mlist[2]
            let type = mlist[3]
            if len(op) == 1
                let mydate = strftime('%Y-%m-%d')
            else
                let mydate = basedate
            endif
            let op = op[0]
            let year = mydate[0:3]
            let month = mydate[5:6]
            let day = mydate[8:9]
            if type ==? 'y'
                let type = 'm'
                let mycount = mycount * 12
            elseif type ==? 'w'
                let type='d'
                let mycount = mycount * 7
            endif
            if type ==? 'm'
                if (op ==? '+')
                    let yplus = mycount / 12
                    let mplus = mycount % 12
                    let year +=   yplus
                    let month += mplus
                    if month > 12
                        let month = month - 12
                        let year = year + 1
                    endif
                elseif ((mycount % 12) >= month) && (op ==? '-')
                    let yminus = mycount/12
                    let year = year - yminus - 1
                    let month = (month + 12 - (mycount % 12))   
                else " '-' with month greater
                    let month = month - (mycount % 12)
                    let year = year - (mycount / 12)
                endif
                " correct for bad dates
                while calutil#cal(calutil#jul(year.'-'.s:Pre0(month).'-'.s:Pre0(day)))[5:6] != month
                    let day = day - 1
                endwhile
            elseif (type ==? 'd') || (type ==? ' ')
                let newjul = calutil#jul(mydate)
                if op ==? '+'
                    let newjul = newjul + mycount
                else
                    let newjul = newjul - mycount
                endif
                "execute 'let newjul = newjul ' . op . mycount
                let mydate = calutil#cal(newjul)
                let year = mydate[0:3]
                let month = mydate[5:6]
                let day = mydate[8:9]
            endif

            let newdate = year . '-' . s:Pre0(month) . '-' . s:Pre0(day)
        else
            return " ?? can't interpret your spec"
        endif
        return newdate
endfunction
function! s:TimeInc(direction)
    let save_cursor = getpos(".")
    let i = 0
    let col = save_cursor[2] - 1
    let line = getline(line("."))
    if line[col] =~ '\d'
        let i = 1
        while i < 6
            let start = col - i
            let end = col - i + 6
            silent execute 'let timetest = line[' . start . ':' . end .']'
            if timetest =~ ' \d\d:\d\d[>\]]'
                break
            endif          
            let i += 1
        endwhile
    else
        let i = 6
    endif
    if i == 6
        execute "normal! \<s-up>"
        return
    else
        let start = col - i + 1
        let end = col - i + 5
        execute 'let time = line[' . start . ':' . end .']'
        if i > 3
            let newminutes = (time[3:4] + (a:direction *5)) 
            let newminutes = newminutes - (newminutes % 5)
            if (newminutes >= 60) 
                let newminutes = 0
                let newhours = time[0:1] + 1
            elseif (newminutes == -5) && (a:direction == -1)
                let newminutes = 55
                let newhours = time[0:1] - 1
            else
                let newhours = time[0:1]
            endif
        else
            let newhours = time[0:1] + (1 * a:direction)
            let newminutes = time[3:4]
        endif
        if newhours >= 24
            let newhours = 0
            "let tempsave = getpos(".")
        elseif newhours < 0
            let newhours = 23
            "execute "normal ".start-6."|"
            "call OrgDateInc(a:direction)
            "call setpos(".",tempsave)         
        endif
        let matchcol = col-i+2
        execute 's/\%'.matchcol.'c\zs\d\d:\d\d/' . s:Pre0(newhours) . ':' . s:Pre0(newminutes).'/'
    endif
    call setpos(".",save_cursor)
endfunction
function! OrgDateInc(direction)
    "       <dddd-dd-dd
    "       01234567890
    "       09876543210
    let save_cursor = getpos(".")
    let i = 0
    let col = save_cursor[2] - 1
    let line = getline(line("."))
    if line[col] =~ '\d'
        let i = 1
        while i < 21
            let start = col - i
            let end = col - i + 11
            silent execute 'let datetest = line[' . start . ':' . end .']'
            if datetest =~ '[<[]\d\d\d\d-\d\d-\d\d'
                break
            endif          
            let i += 1
        endwhile
    else
        let i = 21
    endif
    if i == 21
        execute "normal! \<s-up>"
        return
    else
        if i > 12
            call setpos(".",save_cursor)
            call s:TimeInc(a:direction)
            return
        endif
        let start = col - i + 1
        let end = col - i + 11
        execute 'let date = line[' . start . ':' . end .']'
        if i > 7
            let newdate = calutil#cal(calutil#jul(date) + a:direction)
            let newyear = newdate[0:3]
            let newmonth = newdate[5:6]
            let newday = newdate[8:9]
        elseif i < 5
            let spot = 'year'
            let newyear = date[0:3] + a:direction
            let newmonth = date[5:6]
            let newday = date[8:9]
            "execute 's/\d\d\d\d/' . newyear . '/'
        else
            let spot = 'month'
            let newmonth = date[5:6] + a:direction  
            let newday = date[8:9]
            if newmonth > 12
                let newyear = date[0:3] + 1
                let newmonth = '01'
                let newday = '01'
            elseif newmonth < 1
                let newyear = date[0:3] - 1
                let newmonth = '12'
                let newday = '31'
            else
                let newyear = date[0:3]
                let newday = date[8:9]
            endif
        endif
        " correct for bad dates
        while calutil#cal(calutil#jul(newyear.'-'.newmonth.'-'.newday))[5:6] != newmonth
            let newday = newday - 1
        endwhile
        let matchcol = col-i+2
        execute 's/\%'.matchcol.'c\zs\d\d\d\d-\d\d-\d\d/' . newyear . '-' . s:Pre0(newmonth) . '-' . s:Pre0(newday).'/'
        " update dow if there is one
        let end +=5
        silent execute 'let datetest = line[' . start . ':' . end .']'
        if datetest =~ '\d\d\d\d-\d\d-\d\d \S\S\S'
            let dow = calutil#DayOfWeek(newyear,newmonth,newday,2)
            silent execute 's/\%'.matchcol.'c\(\d\d\d\d-\d\d-\d\d \)\S\S\S/\1' . dow.'/'
        endif          
    endif
    call setpos(".",save_cursor)
endfunction

function! s:GetClock()
    return '['.strftime("%Y-%m-%d %a %H:%M").']'
endfunction 
function! OrgClockIn(...)
    let save_cursor=getpos(".")
    let lineno=line('.')
    if bufname("%") ==? ('__Agenda__')
        let lineno = matchstr(getline(line('.')),'^\d\+')
        let file = matchstr(getline(line('.')),'^\d\+\s*\zs\S\+').'.org'
        let str = ','.lineno.',"'.file.'"'
        call s:SetProp('CLOCKIN','',lineno,file)
    else
   
        if a:0 > 1
            execute a:1
        endif
        execute s:OrgGetHead()
        if s:IsTagLine(line(".")+1)
            execute line('.')+1
        endif
        call append(line('.'),'  :CLOCK: '.s:GetClock())
        let dict={'file':expand("%"),'line':line('.'),'Timestamp':org#Timestamp()}
        call add(g:org_clock_history,dict)
    endif


    call setpos(".",save_cursor)
endfunction
function! s:GetOpenClock()
    let found_line = 0
    let file = ''
    if !exists('g:agenda_files') || (g:agenda_files == [])
        unsilent call confirm("No agenda files defined, will search only this buffer for open clocks.")
        let found_line = search('CLOCK: \[\d\d\d\d-\d\d-\d\d \S\S\S \d\d:\d\d\]\($\|\s\)','w')
    else
        let g:in_agenda_search = 1
        for file in g:agenda_files
            call org#LocateFile(file)
            let found_line = search('CLOCK: \[\d\d\d\d-\d\d-\d\d \S\S\S \d\d:\d\d\]\($\|\s\)','w')
            let file = expand("%")
            if found_line > 0
                break
            endif
        endfor
        unlet g:in_agenda_search
    endif
    return [file,found_line]
endfunction
function! OrgClockOut(...)
    let cur_file=expand("%")
    let save_cursor= getpos('.')
    if a:0 > 1
        execute a:1
    else
        let oc = s:GetOpenClock()
        if oc[0] ># '' 
           call org#LocateFile(oc[0])
           execute oc[1]
        endif
    endif
    execute s:OrgGetHead()
    let bottom = s:OrgNextHead() > 0 ? s:OrgNextHead() - 1 : line("$")
    let str = 'CLOCK: \[\d\d\d\d-\d\d-\d\d \S\S\S \d\d:\d\d\]\($\|\s\)'
    let found = s:Range_Search(str,'n',bottom,line("."))
    if found
        execute found
        execute 'normal A--' . s:GetClock() 
        if b:v.clock_to_logbook 
            let headline = s:OrgGetHead()
            let clockline = getline(line(".")) . ' -> ' . s:ClockTime(line("."))
            normal! dd
            call OrgConfirmDrawer("LOGBOOK",headline)
            let clockline = matchstr(getline(line(".")),'^\s*') . matchstr(clockline,'\S.*')
            call append(line("."),clockline )
        endif
        let msg = "Open clock found and clocked out in \n"
        let msg .= "file: ".expand("%")."\n"
        let msg .= "in headline at line number: ".headline
        call confirm(msg)
    else
        echo 'No open clock found. . . .'
    endif
    call org#LocateFile(cur_file)
    call setpos(".",save_cursor)
endfunction
function! s:UpdateAllClocks()
    %g/^\s*:CLOCK:/call s:AddClockTime(line("."))
endfunction
function! s:AddClockTime(line)
    call setline(a:line,matchstr(getline(a:line),'.*\]') . ' -> ' . s:ClockTime(a:line))
endfunction

function! s:UpdateClockSums()
    let save_cursor = getpos(".")
    g/^\s*:ItemClockTime/d
    call s:UpdateAllClocks()
    g/^\s*:CLOCK:/call s:SetProp('ItemClockTime', s:SumClockLines(line(".")))
    call setpos(".",save_cursor)
endfunction

function! s:SumClockLines(line)
    let save_cursor = getpos(".")
    execute s:OrgGetHead_l(a:line) + 1
    "execute a:line + 1
    let hours = 0
    let minutes = 0
    while 1
        let text = getline(line("."))
        if text !~ s:remstring
            break
        endif
        let time = matchstr(text,'CLOCK.*->\s*\zs\d\+:\d\+')
        if time ># ''
            let hours   += str2nr(split(time,':')[0])
            let minutes += str2nr(split(time,':')[1])
        endif

        if line('.') == line('$')
            break
        else
            execute line('.') + 1
        endif
        
    endwhile
    let totalminutes = (60 * hours) + minutes
    call setpos(".",save_cursor)
    return (totalminutes/60) . ':' . s:Pre0(totalminutes % 60)

endfunction
function! s:UpdateBlock()
    normal j
   ?^#+BEGIN:
    let block_type = matchstr(getline(line('.')),'\S\+\s\+\zs\S\+')
   if matchstr(getline(line('.')+1),'^#+END') ==# ''
        normal jV/^#+END/-1
dk
    endif
    if block_type ==? 'clocktable'
        let block_type='ClockTable'
    endif
    let mycommand = block_type.'()'
    execute "call append(line('.'),".mycommand.")"
endfunction
function! ClockTable()
    let save_cursor = getpos(".")

    call s:UpdateClockSums()
    call s:UpdateHeadlineSums()
    call OrgMakeDict()
    let g:ctable_dict = {}
    let mycommand = "let g:ctable_dict[line('.')] = "
                \ . "{'text':s:GetProperties(line('.'),0)['ITEM']"
                \ . " , 'time':s:GetProperties(line('.'),0)['TOTALCLOCKTIME']}"
    g/:TOTALCLOCKTIME/execute mycommand
    let total='00:00'
    for item in keys(g:ctable_dict)
        "let test = g:ctable_dict[item].text
        if g:ctable_dict[item].text[0:1] ==? '* '
        "if test[0:1] ==? '* '
            let total = s:AddTime(total,g:ctable_dict[item].time)
        endif
    endfor
    let result = ['Clock summary at ['.org#Timestamp().']','',
                \ '|Lev| Heading                      |  ClockTime',
                \ '|---+------------------------------+-------+--------' ,
                \ '|   |                      *TOTAL* | '.total ]
    for item in sort(keys(g:ctable_dict),'s:NumCompare')
        let level = len(matchstr(g:ctable_dict[item].text,'^\*\+')) 
        let treesym = repeat('   ',level-2) . (level > 1 ? '\_ ' : '')
        let str = '| '.level.' | ' 
                    \ . org#Pad(treesym . matchstr(g:ctable_dict[item].text,'^\*\+ \zs.*')[:20],28) . ' | '
                    \ . repeat('      | ',level-1)
                    \ . s:PrePad(g:ctable_dict[item].time,5) . ' |'
        if g:ctable_dict[item].text[0:1] ==? '* '
            call add(result, '|---+------------------------------+-------+-------+' )
        endif
        call add(result, str)
    endfor
    call setpos(".",save_cursor)
    
    unlet b:v.org_dict
    return result

endfunction

function! s:NumCompare(i1,i2)
    let i1 = str2nr(a:i1)
    let i2 = str2nr(a:i2)
    return i1 == i2 ? 0 : i1>i2 ? 1 : -1
endfunction

function! s:ClockTime(line)
    let ctext = getline(a:line)
    let start = matchstr(ctext,'CLOCK:\s*\[\zs\S\+\s\S\+\s\S\+\ze\]')
    let end = matchstr(ctext,'--\[\zs.*\ze\]')
    let daydifference = calutil#jul(end[0:9])-calutil#jul(start[0:9])
    let startmin = 60*start[15:16] + start[18:19]
    let endmin = 60*end[15:16] + end[18:19]
    let totalmin = (daydifference * 1440) + (endmin - startmin)
    return string(totalmin/60) . ':' . s:Pre0(totalmin % 60)
endfunction
function! s:AddTime(time1, time2)
    let time1 = a:time1
    let time2 = a:time2
    if match(time1,':') == -1 | let time1 = '00:00' | endif
    if match(time2,':') == -1 | let time2 = '00:00' | endif
    let hours = str2nr(matchstr(time1,'^.*\ze:')) + str2nr(matchstr(time2,'^.*\ze:'))
    let minutes = (60*hours) + time1[-2:] + time2[-2:]
    return (minutes/60) . ':' . s:Pre0(minutes % 60)
endfunction
function! s:GetProp(key,...)
    let save_cursor = getpos(".")
    if a:0 >=2
        let curtab = tabpagenr()
        let curwin = winnr()
    " optional args are: a:1 - lineno, a:2 - file
        call org#LocateFile(a:2)
    endif
    if (a:0 >= 1) && (a:1 > 0)
        execute a:1 
    endif
    execute s:OrgGetHead() + 1
    let myval = ''
    while 1
        let text = getline(line("."))
        if text !~ s:remstring
            break
        endif
        let mymatch = matchstr(text,':\s*'.a:key.'\s*:')
        if mymatch ># ''
            let myval = matchstr(text,':\s*'.a:key.'\s*:\s*\zs.*$')
            break
        endif
        execute line(".") + 1
        if line(".") == line("$")
            break
        endif
    endwhile
    if a:0 >= 2
        execute "tabnext ".curtab
        execute curwin . "wincmd w"
    endif
    call setpos(".",save_cursor)
    return myval

endfunction
function! s:SetDateProp(type,newdate,...)
    " almost identical to s:GetProp() above, need to refactor
    let save_cursor = getpos(".")
    if a:0 == 1
        execute a:1 + 1
    else
        execute line(".") + 1
    endif
    let myval = ''
    while 1
        let text = getline(line("."))
        if text !~ s:remstring
            break
        endif
        let mymatch = matchstr(text,'\s*'.a:type.'\s*:')
        if mymatch ># ''
            execute 's/'.a:type.'.*$/'.a:type.':<'.a:newdate.'>/'
            break
        endif
        execute line(".") + 1
    endwhile
    call setpos(".",save_cursor)
    return myval
endfunction
function! s:SetProp(key, val,...)
    let save_cursor = getpos(".")
    " optional args are: a:1 - lineno, a:2 - file
    if a:0 >=2
        let curtab = tabpagenr()
        let curwin = winnr()
        call org#LocateFile(a:2)
    endif
    if (a:0 >= 1) && (a:1 > 0)
        execute a:1 
    endif
    let key = a:key
    let val = a:val
    execute s:OrgGetHead() 
    " block_end was end of properties block, but getting that 
    " from GetProperties(line('.'),0) creates problems with 
    " line numbers having changed from previous run of OrgMakeDict
    " So, just use next head as end of block for now.
    let block_end = s:OrgNextHead()
    let block_end = (block_end == 0) ? line('$') : block_end
    if key =~ 'DEADLINE\|SCHEDULED\|CLOSED\|TIMESTAMP'
        " it's one of the five date props
        " find existing date line if there is one
        if key ==? 'TIMESTAMP' 
            let key = ''
            let foundline = s:Range_Search('^\s*:\s*<\d\d\d\d-\d\d-\d\d','n',block_end,line("."))
        elseif key ==? 'TIMESTAMP_IA' 
            let key = ''
            let foundline = s:Range_Search('^\s*:\s*[\d\d\d\d-\d\d-\d\d','n',block_end,line("."))
        else
            let foundline = s:Range_Search('^\s*\(:\)\{}'.key.'\s*:','n',block_end,line("."))
        endif
        if foundline > 0
            "exec foundline
            "exec 's/:\s*<\d\d\d\d-\d\d-\d\d \S\S\S\( \d\d:\d\d\)*/' . (key ==# '' ? ':' : ': ') . a:val[:-2]
            call setline(foundline,substitute(getline(foundline),
                            \ ':\s*<\d\d\d\d-\d\d-\d\d \S\S\S.*$', (key ==# '' ? ':' : ': ') . a:val,''))
                            "\ ':\s*<\d\d\d\d-\d\d-\d\d \S\S\S.*$', (key ==# '' ? ':' : ': ') . a:val[:-2],''))
        else
            let line_ind = len(matchstr(getline(line(".")),'^\**'))+1 + g:org_indent_from_head
            if s:IsTagLine(line('.')+1)
                execute line('.') + 1
            endif
            call append(line("."),org#Pad(' ',line_ind)
                        \ .':'.key.(key ==# '' ? '' : ': ').a:val)
        endif
    elseif key ==? 'tags'
        let indent_count = len(matchstr(getline(line(".")),'^\*\+ '))
        let curindent = repeat(' ',indent_count)
        let newval = curindent . a:val
        if s:IsTagLine(line('.') + 1)
            call setline(line('.') + 1, newval)
        else
            call append(line('.'), newval)
        endif
        "execute line('.') + 1
        "normal =$
        "execute line('.') - 1
    elseif key ==? 'CLOCKIN'
        call OrgClockIn()
    elseif key ==? 'CLOCKOUT'
        call OrgClockOut(a:val)
    else
        " it's a regular key/val pair in properties drawer
        call OrgConfirmDrawer("PROPERTIES")
        while (getline(line(".")) !~ '^\s*:\s*' . key) && 
                    \ (getline(line(".")) =~ s:remstring) &&
                    \ (line('.') != line('$'))
            execute line(".") + 1
        endwhile

        if (getline(line(".")) =~ s:remstring) && (getline(line('.')) !~ '^\s*:END:')
            call setline(line("."), matchstr(getline(line(".")),'^\s*:') .
                        \ key . ': ' . val)
        else
            execute line(".") - 1
            call OrgConfirmDrawer("PROPERTIES")
            let curindent = matchstr(getline(line(".")),'^\s*')
            let newline = curindent . ':' . key . ': ' . val
            call append(line("."),newline)
        endif
    endif

    if exists("*Org_property_changed_functions") && (bufnr("%") != bufnr('Agenda'))
        let Hook = function("Org_property_changed_functions")
        silent execute "call Hook(line('.'),a:key, a:val)"
    endif
    if a:0 >=2
        "back to tab/window where setprop call was made
        execute "tabnext ".curtab
        execute curwin . "wincmd w"
    endif
    call setpos(".",save_cursor)
endfunction
function! s:CurrentRemoveFromAgendaFiles()
        let cur_file1 = fnamemodify(expand("%:p"), ":~")[1:]
        let cur_file = substitute(cur_file1,'\','\\\\','g')
        let cur_file = substitute(cur_file,'\\ ','\ ','g')

        let file_count = len(g:agenda_files) 
        
        let ndx = -1
        for i in range(0, file_count - 1 )
            if g:agenda_files[i] =~ '\c' . cur_file
                let ndx = i
                break
            endif
        endfor
        if ndx > -1
            call remove(g:agenda_files,ndx)
            echo cur_file1 . ' was removed from agenda files list.'
        else
            echo cur_file1 . ' was not in agenda files list.'
        endif
endfunction

function! s:CurrentToAgendaFiles(top_or_bottom)
        " argument should be either 'top' or 'bottom'
        let cur_file1 = fnamemodify(expand("%:p"), ":~")
        let cur_file = substitute(cur_file1[1:],'\','\\\\','g')
        let cur_file = substitute(cur_file,'\\ ','\ ','g')

        if !exists('g:agenda_files')
            let g:agenda_files = []
        endif
        let file_count = len(g:agenda_files) 
        
        let ndx = -1
        for i in range(0, file_count - 1 )
            if g:agenda_files[i] =~ '\c' . cur_file
                let ndx = i
                break
            endif
        endfor
        if ndx > -1
            call remove(g:agenda_files,ndx)
        endif
        if a:top_or_bottom == 'top'
            let g:agenda_files = [cur_file1] + g:agenda_files
        else
            let g:agenda_files = g:agenda_files + [cur_file1]
        endif
        echo cur_file1 . ' is at ' . a:top_or_bottom . ' of agenda files list.'
endfunction

function! s:OrgGotoChosenFile(...)
    if a:0 == 1
        " type is 'agenda' or 'all'
        let type = a:1
    else
        let type = 'all'
    endif
    let fdict = {}
    let bufnums= []
    let bufnums_nonagenda = []
    if exists('g:agenda_files') && !empty(g:agenda_files)
        for i in range(0, len(g:agenda_files) - 1)
            let buf = bufnr(g:agenda_files[i])
            let buf = (buf == -1 ? 10000 + i : buf)
            let fdict[buf] = g:agenda_files[i]
            call add(bufnums,buf)
        endfor
    endif
    if type == 'all'
        let buffers = split(org#redir('buffers'), "\n")
        for item in buffers
            let m = matchlist(item,'\s*\(\d\+\).*"\(.*\)"')
            if get(fdict, m[1], -1 ) == -1
                "put buffer as key and fname as value
                let fdict[m[1]] = m[2]
                call add(bufnums_nonagenda,str2nr(m[1]))
            endif
        endfor
        " get rid of non org buffers
        for bufnum in keys(fdict)
            if (getbufvar(str2nr(bufnum), "&filetype") !=# 'org') && (bufnum < 10000)
               unlet fdict[bufnum]
               call remove(bufnums_nonagenda,index(bufnums_nonagenda,str2nr(bufnum)))
           endif
        endfor
    endif

    redraw
    echo "Agenda files:"
    echo "============================="
    let nums = range(char2nr('a'),char2nr('z')) + range(char2nr('0'), char2nr('9')) 

    for i in range(0,len(bufnums)-1)
        echo '   ' . nr2char(nums[i]) . '  ' . g:agenda_files[i]
    endfor
    echo "Non-agenda org files:"
    echo "============================="
    for i in range(0,len(bufnums_nonagenda)-1)
        echo '   ' . nr2char(nums[i + len(bufnums)]) . '  ' . fdict[bufnums_nonagenda[i]]
    endfor
    let bufnums = bufnums + bufnums_nonagenda
    echo ""
    echo "Press a key to go to chosen file: "
    silent let x = nr2char(getchar())
    redraw
    
    if x =~ '[0-9a-z]'
        silent call org#LocateFile(fdict[bufnums[index(nums,char2nr(x))]])
    endif

endfunction
function! s:CycleAgendaFiles(direction)
    if exists('g:agenda_files') && !empty('g:agenda_files')
        let cur_file = fnamemodify(expand("%:p"), ":~")[1:]
        let cur_file = substitute(cur_file,'\','\\\\','g')
        let cur_file = substitute(cur_file,'\\ ','\ ','g')

        let file_count = len(g:agenda_files) 
        "let ndx = index(g:agenda_files,cur_file) 
        let ndx = -1
        for i in range(0, file_count - 1 )
            if g:agenda_files[i] =~ '\c' . cur_file
                let ndx = i
                break
            endif
        endfor
        if ndx > -1
            "let ndx = (ndx == len(g:agenda_files)) ? 0 : ndx 
            let ndx += (a:direction ==? 'backward') ? -1 : 1
            if a:direction == 'backward'
                let ndx = (ndx == -1) ? (len(g:agenda_files) - 1) : ndx 
            elseif a:direction == 'forward'
                let ndx = (ndx == len(g:agenda_files)  ? 0 : ndx) 
            endif

            let filename = g:agenda_files[ndx]
        else
            let filename = g:agenda_files[0]
        endif
        call org#LocateFile(filename)
    else
        echo "No agenda files defined."
    endif
    
endfunction

function! OrgConfirmDrawer(type,...)
    let line = s:OrgGetHead()
    if a:0 == 1
        let line = a:1
    endif
    execute line
    let indent = repeat(' ', len(matchstr(getline(line('.')),'^\*\+ ')))
    let bottom = s:OrgNextHead() > 0 ? s:OrgNextHead() - 1 : line("$")
    let found = s:Range_Search(':\s*'. a:type . '\s*:','n',bottom,line)
    if !found
        while getline(line(".") + 1) =~ s:remstring
            execute line('.')+1
        endwhile
        "execute 'normal o:'. a:type . ':'
        "execute 'normal o:END:'
        "normal k
        call append(line('.'),[ indent . ':' . a:type . ':' , indent . ':END:'] ) 
        execute line('.') + 1
    else
        execute found
    endif
endfunction

function! OrgGetLink()
    let savecursor = getpos('.')

    let linkdict = {'link':'','desc':''}
    let curpos = getpos('.')[2]
    call search('\[\[','bc',line('.'))
    let startpos = getpos('.')[2] - 1
    call search(']]','ce',line('.'))
    let endpos = getpos('.')[2] - 1
    if (curpos >= startpos) && (curpos <= endpos)
        let linktext = getline(line("."))[ startpos : endpos ]
        if linktext =~ ']\['
            let linkdict.link = matchstr(linktext,'\[\[\zs.*\ze]\[')
            let linkdict.desc = matchstr(linktext,']\[\zs.*\ze]]')
        else
            let linkdict.link = matchstr(linktext,'\[\[\zs.*\ze]]')
        endif
    endif
    call setpos('.',savecursor)
    return linkdict
endfunction
function! FollowLink(ldict)
    let ld = a:ldict
    let ld.suffix = ''
    "process things so org-compatible while still calling Utl
    let prefix = matchstr(ld.link,'\S\{-1,}\ze:')
    if exists(":Utl") == 0
       echo "The Vim plugin Utl.vim must be installed to follow links."
        echo "You can find a copy at:"
        echo 'http://www.vim.org/scripts/script.php?script_id=293'
        return
    endif
    if prefix =~ g:org_unsupported_link_types
        echo 'Link type "' . prefix '" not supported in VimOrganizer.'
        return
    endif
    " now have to translate from org format to Utl format
    if ld.link[0] ==# '#'
        let ld.link = '#tn=:CUSTOM_ID:\s\*' . ld.link[1:]
        let prefix = '#'
    elseif prefix ==? 'file' && (ld.link[5] ==# '.')  
        " || ld.link[5:6] ==# '\S:') 
        " take file prefix out b/c Utl can't handle relative file paths
        let ld.link = ld.link[5:]
    endif

    if prefix ==? 'file' && (ld.link =~ '::')
        let mylist = split(ld.link,'::')
        let ld.link = mylist[0]
        let ld.suffix = mylist[1]
    endif

    if (prefix ==# '') || ((prefix !~ g:org_supported_link_types) && (prefix != '#'))
        " we have org text search that needs different treatment
        call FollowTextLink(a:ldict.link)
        "for search_type in ['dedicated', 'headline1', 'headline2', 'general']
        "    let savecursor = getpos('.')
        "    if search_type is 'dedicated'
        "        let newlink = '#tn=<<' . a:ldict.link . '>>'
        "    elseif search_type is 'headline1'
        "        let newlink = '#tn=' . b:v.todoMatch . a:ldict.link 
        "    elseif search_type is 'headline2'
        "        let newlink = '#tn=^*\+ ' . a:ldict.link
        "    else
        "        let newlink = '#tn=' . a:ldict.link
        "    endif

        "    let newlink = substitute(newlink,' ','\\ ','g')
        "    let g:newlink = newlink
        "    silent! exec 'Utl o '. newlink . ' split'

        "    if line('.') != savecursor[1] 
        "        break
        "    endif
        "endfor
    else
        exec 'Utl o ' . ld.link . ' split'
        if ld.suffix ># ''
            call FollowTextLink(ld.suffix)
        endif
    end
endfunction
function! FollowTextLink(link)
    for search_type in ['dedicated', 'headline1', 'headline2', 'general']
        let savecursor = getpos('.')
        if search_type is 'dedicated'
            let newlink = '#tn=<<' . a:link . '>>'
        elseif search_type is 'headline1'
            let newlink = '#tn=' . b:v.todoMatch . a:link 
        elseif search_type is 'headline2'
            let newlink = '#tn=^*\+ ' . a:link
        else
            let newlink = '#tn=' . a:link
        endif

        let newlink = substitute(newlink,' ','\\ ','g')
        let g:newlink = newlink
        silent! exec 'Utl o '. newlink . ' split'

        if line('.') != savecursor[1] 
            break
        endif
    endfor
endfunction
function! EditLink()
    "is this here: and is this there:
    let thislink = OrgGetLink()

    let link = input('Link: ', thislink.link)
    let desc = input('Description: ', thislink.desc)
    
    if thislink.link !=# ''
        "delete existing hyperlink
        call search('\[\[','b',line('.'))
        normal v/]]/e
xx
    endif 

    silent exec 'normal i[[' . link . ']' . (desc ># '' ? '[' . desc . ']' : '') . ']'
    echo ''
endfunction
function! OrgMouseDate()
    let @x=''
    let date=''
    let save_cursor = getpos(".")
    let found = ''
    silent! let date = GetDateAtCursor()
    call setpos('.',save_cursor)
    let linkdict = OrgGetLink()
    if date ># ''
        let found='date'
        let date = date[0:9]
    elseif linkdict.link ># ''
        let found= 'link'
    else
        call setpos(".",save_cursor)
        " get area between colons, if any, in @x
        normal T:vt:"xy
        if (matchstr(@x,'\S\+') ># '') && (len(@x)<25)
            let found = 'tag'
        endif
    endif
    call setpos(".",save_cursor)
    if found ==? 'date'
        silent call s:RunCustom({'type':'agenda','agenda_date':date, 'agenda_duration':'d'})
        "call OrgRunAgenda(date,1,'',date)
        " go to 8th line in agenda buf
        execute 8
    elseif found ==? 'link'
        call FollowLink(linkdict)
    elseif found ==? 'tag'
        "call OrgRunSearch('+'.@x)
        silent call s:RunCustom({'type':'tags','spec':@x})
    else
        echo 'Nothing found to search for.'
    endif

endfunction
function! s:SetColumnHead()
" NOT USED NOW, NEEDS to be redone since switch to using orgmode-style col
" specs
    "let i = 0
    "while i < len(w:v.org_colview_list)
    "    let result .= '|' . s:PrePad(w:v.org_colview_list[i] , w:v.org_colview_list[i+1]) . ' ' 
    "    let i += 2
    "endwhile
    "let g:org_ColumnHead = result[:-2]
endfunction

function! s:OrgSetColumnList(line_for_cols,...)
    " call GetProperties making sure it gets inherited props (viz. COLUMNS)
    let save_inherit_setting = s:include_inherited_props
    let s:include_inherited_props = 1
    try
        let column_prop = s:GetProperties(a:line_for_cols,0)['COLUMNS']
    finally
        let s:include_inherited_props = save_inherit_setting
    endtry

    if (a:0 >= 1) && (a:1==0)
        " use 0 for master head, i.e., columns for entire doc
        let w:v.org_columns_master_heading = a:1
    else
        let w:v.org_columns_master_heading = s:OrgGetHead_l(a:line_for_cols)
    endif
    if (a:0 >= 2) && (a:2 ># '')
        " use column spec that was passed in
        let column_prop = a:2
    else   
        let w:v.org_current_columns = column_prop
    endif
    
    let result = ''
    let g:org_column_headers = ''
    let i = 0
    
    if column_prop ># ''
        let w:v.org_colview_list=split(column_prop,' ')
    else
        let w:v.org_colview_list=[]
    endif
    
    call s:SetColumnHeaders()

endfunction
function! s:SetColumnHeaders()
    " build g:org_column_headers
    let g:org_column_headers = ''
    let w:v.org_column_item_head = ''
    for item in (w:v.org_colview_list)
        let [ fmt, field, hdr ] = matchlist(item,'%\(\d*\)\(\S\{-}[^({]*\)(*\([^ )]*\)')[1:3]
        let fmt = (fmt ==# '') ? '%-' . g:org_columns_default_width . 's' : ('%-' . fmt . 's')
        if field ==# 'ITEM' 
           let w:v.org_column_item_head = (hdr=='') ? 'ITEM' : hdr
           continue 
        endif
        let g:org_column_headers .= printf('|' . fmt, (hdr ==# '') ? field : hdr )  
    endfor

endfunction
function! s:GetFoldColumns(line)
    let save_inherit_setting = s:include_inherited_props
    let s:include_inherited_props = 1
    try
        let props = s:GetProperties(a:line,0)
    finally
        let s:include_inherited_props = save_inherit_setting
    endtry
    " build text string with column values
    let result = ''
    for item in (w:v.org_colview_list)
        let [ fmt, field, hdr ] = matchlist(item,'%\(\d*\)\(\S\{-}[^({]*\)(*\(\S*\))*')[1:3]
        if field ==# 'ITEM' | continue | endif
        let fldtext = get(props,toupper(field),'')
        let fmt = (fmt ==# '') ? g:org_columns_default_width :  fmt 
        " truncate text if too long
        "let fldtext = (len(fldtext)<=fmt) ? fldtext : (fldtext[:fmt-3] . '..')
        let fldtext = (strchars(fldtext)<=fmt) ? fldtext : (fldtext[:fmt-3] . '..')
        let result .= printf( '|%-'.fmt.'s', fldtext,'') 
    endfor

    return result

endfunction
function! ToggleColumnView(master_head,col_spec)

    if w:v.columnview
        let winnum = bufwinnr('ColHeadBuffer')
        if winnum > 0 
            execute "bw!" . bufnr('ColHeadBuffer')
        endif
        let w:v.columnview = 0
    else
        call s:OrgSetColumnList(line('.'),a:master_head,a:col_spec)
        call s:ColHeadWindow(w:v.org_column_item_head)
        let w:v.columnview = 1
    endif   
endfunction
function! <SID>ColumnStatusLine()
    if exists('g:org_column_headers')
        let part2 = s:PrePad(g:org_column_headers, winwidth(0)-13) 

        return '   ' . w:v.org_column_item_head .  part2
    endif
endfunction
function! s:AdjustItemLen()
    " called on VimResized event, adjusts length of heading when folded
    if &filetype != 'org'
        return
    endif

    if !exists('w:v.columnview')
        let w:v={'columnview':0, 'org_item_len':100, 'org_colview_list':[],'org_current_columns':'','org_column_item_head':''}
    endif
    let i = 1
    let w:v.total_columns_width = 3
    let colspec = split(w:v.org_current_columns, ' ')
    
    for item in colspec
        let [ flen, field ] = matchlist(item,'%\(\d*\)\(\S\{-}[^({]*\)')[1:2]
        if field == 'ITEM' | continue | endif
        let w:v.total_columns_width += (flen > 0) ? flen : g:org_columns_default_width
    endfor
    
    let w:v.org_item_len = winwidth(0) - 10 - ((w:v.columnview==1) ? w:v.total_columns_width : 0)
endfunction
au VimResized * :call s:ResizedWin()
function! s:ResizedWin()
    let curwin = winnr()
    ""avoid using 'windo' b/c it screws up colheadbuffer's 0 height
    for i in range(1,winnr('$'))
        if getbufvar(winbufnr(i),'&filetype') == 'org'
             exec i . 'wincmd w'
             call s:AdjustItemLen()
        endif
    endfor
    exec curwin . 'wincmd w'
endfunction

function! <SID>CalendarChoice(day, month, year, week, dir)
    let g:agenda_startdate = a:year.'-' . s:Pre0(a:month).'-'.s:Pre0(a:day) 
    "call OrgRunAgenda(g:agenda_startdate, g:org_agenda_days,g:org_search_spec)
    silent call s:RunCustom({'type':'agenda','agenda_date':g:agenda_startdate, 'agenda_duration':'d', 'spec':g:org_search_spec})
endfunction
function! <SID>CalendarInsertDate(day, month, year, week, dir)
    if (a:year > 0) && (a:month>0) && (a:day>0)
        let g:cal_list=[a:year,a:month,a:day] 
    endif
    
    "call confirm('got here')
endfunction
function! OrgFunc(func,...)
    "not working, itnended to be general way to 
    " call script-local functions
    let myfunc = function('<SNR>'.s:SID().'_'.a:func)
    if a:000 > 0
        let myargs = split(a:000,',')
    else
        let myargs = ''
    endif
endfunction
    
function! s:MyPopup()
    call feedkeys("i\<c-x>\<c-u>")
endfunction

let g:calendar_action = '<SNR>' . s:SID() .'_CalendarChoice'
let b:v.ColorList=['purple', 'green', 'white', 'black','blue','red','orange','green']
function! s:CompleteOrg(findstart, base)
    if a:findstart
        " locate the start of the word
        let line = getline('.')
        let start = col('.') - 1
        while (start > 0) && (line[start - 1] =~ '\a')
            let start -= 1
        endwhile
        return start
    else
        let prop = matchstr(getline(line(".")),'^\s*:\zs\s*\S\+\s*\ze:')
        " find months matching with "a:base"
        let res = []
        execute "let proplist = b:v." . prop . 'List' 
        "for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")
        for m in proplist
            if m =~ '^' . a:base
                call add(res, m)
            endif
        endfor
        return res
    endif
endfunction
"set completefunc=CompleteOrg


function! OrgFoldText(...)
    " Create string used for folded text blocks
    if a:0 == 1
        let l:line = getline(line("."))
        let foldstart = line(".")
    else
        let l:line = getline(v:foldstart)
        let foldstart = v:foldstart
    endif
    let origline = l:line
    let l:nextline = getline(foldstart + 1)
    let myind = s:Ind(foldstart)

    "let level_highlight = hlID(b:v.foldcolors[myind])
    let level_highlight = hlID('OL' . (myind-1) . 'Folded')

    " get rid of header prefix
    let l:line = substitute(l:line,'^\*\+\s*','','g')
    let l:line = repeat(' ', s:Starcount(foldstart)+1) . l:line 
    let line_count = v:foldend - v:foldstart

    if l:line =~ b:v.drawerMatch
        "let level_highlight = hlID('Title')
        let level_highlight = hlID('Org_Drawer_Folded')
        let l:line = repeat(' ', strchars(matchstr(l:line,'^ *'))-1)
                    \ . matchstr(l:line,'\S.*$') 
        let line_count = line_count - 1
    elseif l:line[0] ==? '#'
        let level_highlight = hlID('VisualNOS')
    elseif w:v.columnview==1
        let mytrim = w:v.org_item_len
        let line = line[:mytrim]
    else
        let mytrim = w:v.org_item_len
        let line = line[:mytrim]
    endif
    if exists('w:sparse_on') && w:sparse_on && (a:0 == 0) 
        let b:v.signstring= s:GetPlacedSignsString(bufnr("%")) 
        if match(b:v.signstring,'line='.v:foldstart.'\s\sid=\d\+\s\sname=fbegin') >=0
        "if index(b:v.sparse_list,v:foldstart) > -1            "v:foldstart == 10
            let l:line = '* * * * * * * * * * * ' . (v:foldend - v:foldstart) . ' lines skipped here * * * * * * *'
            let l:line .= repeat(' ', winwidth(0)-strchars(l:line)-28) . 'SPARSETREE SKIP >>'
            let level_highlight = hlID('TabLineFill')
        endif
    endif
    if g:org_show_fold_dots 
        let l:line .= '...'
    endif
    let offset = &fdc + 5*(&number) + (w:v.columnview ? 7 : 1)
    if w:v.columnview && (origline =~ b:v.headMatch) 
        if (w:v.org_columns_master_heading == 0) || s:HasAncestorHeadOf(foldstart,w:v.org_columns_master_heading)
            let l:line .= s:PrePad(s:GetFoldColumns(foldstart), winwidth(0)-strchars(l:line) - offset)
        else
            let offset -= 6
        endif
    endif
    if a:0 && (foldclosed(line('.')) > 0)
        let l:line .= s:PrePad("(" 
            \  . s:PrePad( (foldclosedend(line('.'))-foldclosed(line('.'))) . ")",5),
            \ winwidth(0)-strchars(l:line) - offset) 
    elseif (g:org_show_fold_lines ) || (l:line =~ b:v.drawerMatch) 
        let offset = (w:v.columnview && l:line =~ b:v.drawerMatch) ? offset - 6 : offset 
        let l:line .= s:PrePad("|" . s:PrePad( line_count . "|",5),
                    \ winwidth(0)-strchars(l:line) - offset) 
    endif
    if exists('v:foldhighlight')
        if get(b:v.heading_marks_dict, v:foldstart) == 1
            let v:foldhighlight =  hlID('CursorLine')
        elseif foldstart == b:v.chosen_agenda_heading
            let v:foldhighlight = hlID('Org_Chosen_Agenda_Heading' . (myind>6 ? '' : myind-1))
        else
            let v:foldhighlight = level_highlight
        endif
        if exists('v:todohighlight')
            if matchstr(origline, b:v.todoMatch) ># ''
                let this_todo = matchstr(origline, '^\*\+ \zs\S*')
                if hlID(this_todo) > 55      " > 55 avoids built-in todo group
                   let v:todohighlight = hlID(this_todo) 
                else
                    let v:todohighlight = ('* ' . this_todo =~ b:v.todoDoneMatch) ? hlID('DONETODO') : hlID('NOTDONETODO')
                endif
            else
                let v:todohighlight=0
            endif
        endif
    endif
    return l:line
endfunction
function! s:MySort(comppattern) range
    let b:v.sortcompare = a:comppattern
    let b:v.complist = ['\s*\S\+','\s*\S\+\s\+\zs\S\+','\s*\(\S\+\s\+\)\{2}\zs\S\+'
                \ , '\s*\(\S\+\s\+\)\{3}\zs\S\+'
                \ , '\s*\(\S\+\s\+\)\{4}\zs\S\+'
                \ , '\s*\(\S\+\s\+\)\{5}\zs\S\+'
                \ , '\s*\(\S\+\s\+\)\{6}\zs\S\+']
    let mylines = getline(a:firstline, a:lastline)
    let mylines = sort(mylines,"s:BCompare")
    call setline(a:firstline, mylines)
    unlet b:v.sortcompare
    unlet b:v.complist
endfunction

function! s:BCompare(i1,i2)
    if !exists('b:v.sortcompare')
        echo 'b:v.sortcompare is not defined'
        return
    endif
    let i = 0

    while i < len(b:v.sortcompare)
        " prefix an item by 'n' if you want numeric sorting
        if (i < len(b:v.sortcompare) - 1) && (b:v.sortcompare[i] ==? 'n')
            let i = i + 1
            let m1 = str2nr(matchstr(a:i1,b:v.complist[b:v.sortcompare[i]-1])) 
            let m2 = str2nr(matchstr(a:i2,b:v.complist[b:v.sortcompare[i]-1]))
        else
            let m1 = matchstr(a:i1,b:v.complist[b:v.sortcompare[i]-1]) 
            let m2 = matchstr(a:i2,b:v.complist[b:v.sortcompare[i]-1])
        endif
        if m1 == m2
            if i == len(b:v.sortcompare) - 1
                return 0
            else
                let i += 1
                continue
            endif
        elseif m1 > m2 
            return 1
        else 
            return -1
        endif
    endwhile
endfunction

function! s:OrgShowMatch(cycleflag)
    "wincmd k
    " first, make sure agenda buffer has same heading pattern
    " and todo list as main buffer
    call s:GotoMainWindow()
    let l:headMatch = b:v.headMatch
    let l:todoitems = b:v.todoitems
    "wincmd j
    call s:GotoAgendaWindow()
    let b:v.headMatch = l:headMatch
    let b:v.todoitems = l:todoitems
    if a:cycleflag
        call OrgSequenceTodo(line("."))
    endif
    "let g:showndx = line(".")-1
    if getline(line(".")) =~ '^\d\+'
        let g:showndx = matchlist(getline(line(".")),'^\d\+')[0]
        execute "let b:v.sparse_list = [" . g:showndx . ']'
    endif
    "wincmd k
    call s:GotoMainWindow()
    call OrgExpandWithoutText(1)
    execute g:showndx
    "execute g:alines[g:showndx]
    normal zv
    if a:cycleflag
        call OrgSequenceTodo(line("."))
    endif
    if getline(line(".")) =~ b:v.headMatch
        call OrgBodyTextOperation(line("."),s:OrgNextHead(),'collapse')
    endif
    "wincmd j
    call s:GotoAgendaWindow()
endfunction
command! MySynch call <SID>OrgShowMatch(0)
command! MySynchCycle call <SID>OrgShowMatch(1)
command! MyAgendaToBuf call <SID>OrgAgendaToBufTest()
command! AgendaMoveToBuf call s:OrgAgendaToBuf()

command! -range CodeEval :call <SID>CodeEval
command! -buffer -nargs=* Agenda :call OrgAgendaCommand(<f-args>)
function! CodeEval() range
    
endfunction

function! OrgAgendaCommand(...)
    if exists('a:1')
        let mydate = a:1
    else
        let mydate = s:Today()
    endif
    if exists('a:2')
        let viewdays = a:2
    else
        let viewdays = 'w'
    endif
    if exists('a:3')
        let search_spec = a:3
    else
        let search_spec = ''
    endif
    if mydate =~ '\d\d\d\d-\d\d-\d\d'
        call OrgRunAgenda(mydate,viewdays,search_spec)
    else
        call OrgRunAgenda(DateCueResult(mydate,s:Today()),viewdays,search_spec)
    endif
endfunction

function! s:OrgAgendaToBufTest()
    " this loads unfolded buffer into same window as Agenda
    if getline(line(".")) =~ '^\d\+'
        let thisline = getline(line('.'))
        let g:tofile = s:filedict[str2nr(matchstr(thisline, '^\d\d\d'))]
        let g:showndx = str2nr(matchstr(thisline,'^\d\d\d\zs\d*'))
        "let g:showndx = matchlist(getline(line(".")),'^\d\+')[0]
        "let g:tofile = matchlist(getline(line(".")),'^\d\+\s*\(\S\+\)')[1]
    endif
    let cur_buf = bufnr("%")
    "let g:org_folds=0
    let newbuf = bufnr(g:tofile)
    execute "b"newbuf
    set ft=org
    execute g:showndx
    normal zv
    "let g:org_folds=1
endfunction
function! s:OrgAgendaToBuf()
    let win = bufwinnr('Calendar')
    
    if win >= 0 
        execute win . 'wincmd w'
        wincmd c
        execute bufwinnr('Agenda').'wincmd w'
    endif   
    
    if getline(line(".")) =~ '^\d\+'
        let thisline = getline(line('.'))
        let g:tofile = s:filedict[str2nr(matchstr(thisline, '^\d\d\d'))]
        let g:showndx = str2nr(matchstr(thisline,'^\d\d\d\zs\d*'))
    endif
    let ag_line = line(".")
    let ag_height = winheight(0)
    let cur_buf = bufnr("%")  " should be Agenda
    close!
    call org#LocateFile(g:tofile )
    
    AAgenda
    
    call org#LocateFile(g:tofile )
    "if &fdm != 'expr'
    "    set fdm=expr
    "endif
    set foldlevel=1
    let newhead = matchstr(s:GetPlacedSignsString(bufnr("%")),'line=\zs\d\+\ze\s\+id=' . g:showndx)
    let newhead = s:OrgGetHead_l(newhead)
    execute newhead
    
    normal! zv
    if getline(line('.')) =~ b:v.headMatch
        "restrict to headings only
        call s:OrgExpandSubtree(line('.'),0)
        "call s:OrgExpandSubtree(g:showndx,0)
    endif

    let b:v.chosen_agenda_heading = s:OrgGetHead()
    call clearmatches()
    let headlevel = s:Ind(b:v.chosen_agenda_heading)
    let headlevel = (headlevel > 6) ? '' : headlevel-1
    call matchadd('Org_Chosen_Agenda_Heading' . headlevel,'\%' . b:v.chosen_agenda_heading .'l')
    
    execute bufwinnr('Agenda').'wincmd w'

    execute ag_line
    resize
    execute "resize " . ag_height 

    if win >= 0
        Calendar
        execute 1
        call org#LocateFile('__Agenda__')
    endif
endfunction

function! s:OrgSource()
    unlet g:org_loaded
    source $VIM/vimfiles/ftplugin/org.vim
endfunction

function! s:OrgSetLevel(startlevel, endlevel)
    "call OrgExpandWithoutText(a:endlevel)
    call s:OrgExpandLevelText(a:startlevel, a:endlevel)
endfunction

function! s:Starcount(line)
    " used to get number of stars for a heading
    return (len(matchstr(getline(a:line),'^\**\s'))-1)
endfunction

function! s:GotoAgendaWindow()
    "wincmd b
    silent execute "b __Agenda__"
endfunction

function! s:GotoMainWindow()
    wincmd t
endfunction

function! s:Ind(line) 
    " used to get level of a heading (todo : rename this function)
    "return 1 + (len(matchstr(getline(a:line),'^\**\s'))-1)/b:v.levelstars  
    return 2 + (len(matchstr(getline(a:line),'^\**\s'))-2)/b:v.levelstars  

endfunction

function! s:DoAllTextFold(line)
    "let d = inputdialog('in fullfold')
    if s:IsText(a:line+1) == 0
        return 
    endif
    while ((s:NextVisibleHead(a:line) != foldclosedend(a:line) + 1) 
                \ && (foldclosedend(a:line) <= line("$"))
                \ && (s:NextVisibleHead(a:line) != 0)
                \ && (org#fold#level(a:line) =~ '>')) 
                \ || (foldclosedend(a:line) < 0)  
                \ || ((s:NextVisibleHead(a:line) == 0) && (s:OrgSubtreeLastLine() == line('$')) && (foldclosedend(a:line)!=line('$')))
        call OrgDoSingleFold(a:line)
    endwhile
endfunction

function! OrgDoSingleFold(line)
    if (foldclosed(a:line) == -1) "&& (getline(a:line+1) !~ b:v.headMatch)
        if (getline(a:line+1) !~ b:v.headMatch) || (s:Ind(a:line+1) > s:Ind(a:line))
            while (foldclosed(a:line) == -1) && (a:line != line('$'))
                normal! zc
            endwhile
        endif
        "elseif (foldclosed(a:line) < a:line)
        " do nothing, line is not visible
    else
        let cur_end = foldclosedend(a:line)
        " I know runaway can happen if at last heading in document,
        " not sure where else
        let runaway_count = 0
        if (cur_end >= line("$")) "|| (org#fold#level(cur_end+1) ==? '<0')
            return
        endif
        if getline(cur_end+1) =~ b:v.drawerMatch
            "while (foldclosedend(a:line) == cur_end) && (runaway_count < 10)
            while (foldclosedend(a:line) == cur_end) && (cur_end != line("$"))
                let runaway_count += 1
                normal! zc
            endwhile
        elseif getline(cur_end+1) !~ b:v.headMatch
            "while (foldclosedend(a:line) == cur_end) && (runaway_count < 10)
            while (foldclosedend(a:line) == cur_end) && (cur_end <= line("$"))
                let runaway_count += 1
                normal! zc
            endwhile
        elseif (getline(cur_end+1) =~ b:v.headMatch) && (s:Ind(cur_end+1) > s:Ind(a:line))
            while (foldclosedend(a:line) == cur_end) && (cur_end != line("$"))
                "   let runaway_count += 1
                normal! zc
            endwhile
        endif
    endif
endfunction


function! s:AlignSection(regex,skip,extra) range
    " skip is first part of regex, 'regex' is part to match
    " they must work together so that 'skip.regex' is matched
    " and the point where they connect is where space is inserted
    let extra = a:extra
    let sep = empty(a:regex) ? '=' : a:regex
    let minst = 999
    let maxst = 0
    let b:v.stposd = {}
    let section = getline(a:firstline, a:lastline)
    for line in section
        let stpos = matchend(line,a:skip)   
        let b:v.stposd[index(section,line)]=stpos
        if maxst < stpos
            let maxst = stpos
        endif
        let stpos = len(matchstr(matchstr(line,a:skip),'\s*$'))
        if minst > stpos
            let minst = stpos
        endif
    endfor
    call map(section, 's:AlignLine(v:val, sep, a:skip, minst, maxst - matchend(v:val,a:skip), extra)')
    call setline(a:firstline, section)
endfunction

function! s:AlignLine(line, sep, skip, maxpos, offset, extra)
    let b:v.m = matchlist(a:line, '\(' .a:skip . '\)\('.a:sep.'.*\)')
    if empty(b:v.m)
        return a:line
    endif
    let spaces = repeat(' ',  a:offset + a:extra)
    exec 'return b:v.m[1][:-' . a:maxpos .'] . spaces . b:v.m[3]'
endfunction
function! s:AlignSectionR(regex,skip,extra) range
    let extra = a:extra
    let sep = empty(a:regex) ? '=' : a:regex
    let minst = 999
    let maxpos = 0
    let maxst = 0
    let b:v.stposd = {}
    let section = getline(a:firstline, a:lastline)
    for line in section
        execute 'let pos = matchend(line, a:skip ." *".sep)'
        if maxpos < pos
            let maxpos = pos
        endif
        let stpos = len(matchstr(matchstr(line,a:skip),'\s*$')) 
        if minst > stpos
            let minst = stpos
        endif
    endfor
    call map(section, 's:AlignLine(v:val, sep, a:skip, minst, maxpos - matchend(v:val,a:skip.sep) , extra)')
    call setline(a:firstline, section)
endfunction
function! s:ColHeadWindow(itemhead,...)
    if (a:0 >= 1) && (a:1 == 0) 
       if bufnr('ColHeadBuffer') > -1
           bw ColHeadBuffer
       endif
       return
    endif

    au! BufEnter ColHeadBuffer
    "let s:AgendaBufferName = 'ColHeadBuffer'
    "call s:AgendaBufferOpen(1)
    "let s:AgendaBufferName = '__Agenda__'
    1split ColHeadBuffer
    call s:ScratchBufSetup()
    
    execute "setlocal statusline=%#OrgColumnHeadings#%{<SNR>" . s:SID() . '_ColumnStatusLine()}'
    set winfixheight
    set winminheight=0
    let w:v = {'org_column_item_head': a:itemhead}
    
    wincmd j
    " make lower window as big as possible to shrink 
    " ColHeadWindow to zero height
    let curheight = winheight(0)
    resize 100
    if bufwinnr('Agenda') > 0
        execute "resize " . curheight 
    endif
    au BufEnter ColHeadBuffer call s:ColHeadBufferEnter()
endfunction

function! s:ColHeadBufferEnter()
    "prevents user from entering this buffer
    "wincmd j
endfunction
" AgendaBufferOpen
" Open the scratch buffer
function! s:AgendaBufferOpen(new_win)
    let save_sb = &splitbelow
    let save_sr = &splitright
    let split_win = a:new_win
    let t = g:org_agenda_window_position
    if t == 'top'
        let g:vsplit=0
        set nosplitbelow
    elseif t == 'bottom'
        let g:vsplit = 0
        set splitbelow
    elseif t == 'left'
        let g:vsplit = 1
        set nosplitright
    elseif t == 'right'
        let g:vsplit = 1
        set splitright
    endif
    " If the current buffer is modified then open the scratch buffer in a new
    " window
    "if !split_win && &modified
    "    let split_win = 1
    "endif

    " Check whether the scratch buffer is already created
    let scr_bufnum = bufnr(s:AgendaBufferName)
    "if scr_bufnum == -1
    if scr_bufnum == -1
        " open a new scratch buffer
        if split_win
            if exists('g:vsplit') && (g:vsplit==1)
                exe "vsplit __Agenda__"
            else
                exe "split __Agenda__"
            endif
        else
            exe "edit " . s:AgendaBufferName
        endif
    else
        " Agenda buffer is already created. Check whether it is open
        " in one of the windows
        let scr_winnum = bufwinnr(scr_bufnum)
        if scr_winnum != -1
            " Jump to the window which has the scratch buffer if we are not
            " already in that window
            if winnr() != scr_winnum
                exe scr_winnum . "wincmd w"
            endif
        else
            " open a window and put existing Agenda in
            if split_win
                if exists('g:vsplit') && (g:vsplit==1)
                    exe "vsplit +buffer __Agenda__"
                else
                    exe "split +buffer __Agenda__"
                endif

            else
                exe "buffer " . scr_bufnum
            endif
        endif
    endif
    let &splitbelow = save_sb
    let &splitright = save_sr
endfunction

command! EditAgendaFiles :call <SID>EditAgendaFiles()
command! OrgCycleAgendaForward :call <SID>CycleAgendaFiles('forward')
command! OrgCycleAgendaBackward :call <SID>CycleAgendaFiles('backward')
command! OrgChooseOrgBuffer :call <SID>OrgGotoChosenFile()
function! s:EditAgendaFiles()
    call org#SaveLocation()
    if !exists("g:agenda_files") || (g:agenda_files == [])
        call s:CurfileAgenda()
    endif
    tabnew Edit_Agenda_Files
    call s:ScratchBufSetup()
    set buftype=acwrite
    autocmd BufLeave <buffer> :call <SID>SaveAgendaFiles(0)
    autocmd BufWriteCmd <buffer> :call <SID>SaveAgendaFiles(1)
    command! W :call s:SaveAgendaFiles()
    let msg = "These are your current agenda files:"
    let msg2 = "Org files in your 'g:org_agenda_select_dirs' are below."
    call setline(1,[msg])
    call append(1, repeat('-',winwidth(0)-5))
    call append("$",g:agenda_files + ['',''])
    " change '\ ' to plain ' ' for current text in buffer
    silent! execute '%s/\\ / /g'
    let line = repeat('-',winwidth(0)-5)
    call append("$",[line] + [msg2,"To add files to 'g:agenda_files' copy or move them ","to between the preceding lines and press :W to save (or :q to cancel):","",""])
    for item in g:org_agenda_select_dirs
        for wild_card in g:org_filename_wildcards
            let dir_files = split(globpath(item,wild_card),"\n")
        endfor
        let heading_path = substitute(expand('~'),'\','\\\\','g')
        call map(dir_files,'substitute( v:val  , ' . "'" . heading_path . "'" . ' , ''~'','''')')
        call append("$",dir_files)
    endfor
endfunction
function! s:SaveAgendaFiles(save)
    " saves edited file list into g:agenda_files
    " yank files into @a
   set nomodified
   if a:save == 1
       normal gg/^--
jV/^--
?^\S
"ay 
       let @a = substitute(@a,' ','\\ ','g')
       if @a[0] != '-'
            let g:agenda_files = split(@a,"\n")
        else
            let g:agenda_files=[]
        endif
    endif
    :bw
    delcommand W
    call org#RestoreLocation()
endfunction
"function! s:CycleAgendaFiles()
"    let i = 0
"    while i < len(g:agenda_files)
"        if g:agenda_files[i] =~ bufname('%') . '$'
"            let i += 1
"            break
"        endif 
"        let i += 1
"    endwhile
"    if i >= len(g:agenda_files) - 1
"        let i = 0
"    endif
"    
"    call org#LocateFile(g:agenda_files[i])
"endfunction
function! s:ScratchBufSetup()
    "setlocal buftype=nofile
    setlocal buftype=nofile
    setlocal bufhidden=hide
    setlocal noswapfile
    setlocal buflisted
    setlocal fdc=1
endfunction
function! s:Emacs2PDF()
    silent !"c:program files (x86)\emacs\emacs\bin\emacs.exe" -batch --visit=newtest3.org --funcall org-export-as-pdf
    "silent !c:\sumatra.exe newtest3.org
endfunction
function! s:Today()
    return strftime("%Y-%m-%d")
endfunction

function! OrgCustomSearchMenu()
    if !exists('g:org_custom_searches') || empty(g:org_custom_searches)
        echo "No custom searches defined."
    else
        echo " Press number to run custom search:"
        echo " ----------------------------------"
        let i = 1
        for item in g:org_custom_searches
            if type(item)==type({})
                echo printf(" (%d) %-25s %10s", i, item.name, item.type )
            elseif type(item) == type([])
                echo printf(" (%d) %-25s %10s", i, item[0].name, item[0].type )
                for each in item[1:]
                    "echo printf(" (%d) %-25s %10s", i, each.name, each.type )
                    echo printf("    + %-25s %10s", each.name, each.type )
                endfor
            endif
            let i += 1
            unlet item
        endfor
        echo " "
        let key = nr2char(getchar())
        let itemnum = str2nr(key)
        if itemnum > 0 && itemnum <= len(g:org_custom_searches)
            call s:RunCustom( itemnum - 1 )
        else
            echo 'No search was chosen.'
        endif
    endif
endfunction

function! s:AgendaBlockNum(line)
    let block_num = 0
    let sep_list = []
    silent g/^========/call add(sep_list,line('.'))
    call add(sep_list,line('$'))
    for i in range(1,len(sep_list))
       if  a:line < sep_list[i-1]
           let block_num = i
           break
       endif
    endfor
    return block_num
endfunction

function! OrgAgendaFilesDashboard()
        echohl MoreMsg
        echo ""
        echo " ======================================"
        echo " Press key for an agenda files command:"
        echo " --------------------------------------"
        echo " e       Edit agenda files"
        if (bufname('%') != '__Agenda__') 
        echo " t       Current file to top of agenda file list"
        echo " b       Current file to bottom of agenda file list"
        echo " r       Remove Current file from agenda file list"
        endif
        echo " n or f  Cycle to next file in agenda files"
        echo " p or b  Cycle to previous file in agenda files"
        echo " c or g  Choose agenda file to goto"
        echo ""
        echohl None
        let key = nr2char(getchar())
        redraw
        if key =~? 'e'
            EditAgendaFiles
        elseif key =~? 't'
            call <SID>CurrentToAgendaFiles('top')
        elseif key =~? 'b'
            call <SID>CurrentToAgendaFiles('bottom')
        elseif key =~? 'r'
            call <SID>CurrentRemoveFromAgendaFiles()
        elseif key =~? 'n\|f'
            call <SID>CycleAgendaFiles('forward')
        elseif key =~? 'p\|b'
            call <SID>CycleAgendaFiles('backward')
        elseif key =~? 'c\|g'
            call <SID>OrgGotoChosenFile()
        else
            echo "No option chosen."
        endif
    "endif
endfunction
function! OrgAgendaDashboard()
    if (bufnr('__Agenda__') >= 0) && (bufwinnr('__Agenda__') == -1)
        " move agenda to cur tab if it exists and is on a different tab
        "let curtab = tabpagenr()
        "" go to current agenda win and close it
        "call org#LocateFile('__Agenda__')
        "wincmd c
        ""back to start tab and open
        "execute "tabnext ".curtab
        "split
        "winc j
        "buffer __Agenda__
        AAgenda
    else
        " show dashboard if there is no agenda buffer or it's 
        " already on this tab page
        let restrict = 0
        let saved_afiles = []
        while 1
            echohl MoreMsg
            echo ""
            echo " ================================"
            echo " Press key for an agenda command:"
            echo " --------------------------------"
            echo " a   Agenda for current week"
            echo " t   List of all TODO entries"
            echo " m   Match a TAGS/PROP/TODO query"
            echo " L   Timeline for current buffer"
            "echo ' s   Freeform regex search, not heading-metadata'
            echo " "
            echo " c   Show custom search menu"
            echo " "
            echo " h   Headline-metadata-based sparse tree search"
            echo " f   Freeform (i.e., regex) sparse tree search" 
            echo " <   restrict to current buffer"
            if restrict == 1
                echo "     Will restrict to current buffer.  Press a key to choose search..."
            endif
            echo ""
            echohl None
            let key = nr2char(getchar())
            redraw
            if key == '<'
                let restrict = 1
                continue
            else
                break
            endif
        endwhile
        if restrict == 1
            let save_win = winnr()
            for winnum in range(1,winnr('$'))
                exec winnum . 'wincmd w'
                if expand('%') =~ '\.org$'
                    let saved_afiles = copy(g:agenda_files)
                    let g:agenda_files = [expand('%:p')]
                    break
                endif
            endfor
            exec save_win . 'wincmd w'
        endif
        try
            if key =~ '[tTaALcCmM]' && bufnr('__Agenda__') >= 0
                bwipeout __Agenda__
            endif
            if key ==? 't'
                "silent execute "call OrgRunSearch('+ANY_TODO','agenda_todo')"
                silent call s:RunCustom({'type':'tags-todo','spec':'+ANY_TODO'})
            elseif key ==? 'a'
                "if (g:org_search_spec ==# '') 
                    "let g:org_search_spec = g:agenda_default_search_spec
                "endif
                "silent execute "call OrgRunAgenda(s:Today(),'w', g:org_agenda_default_search_spec)"
                let today = s:Today()
                silent call s:RunCustom({'type':'agenda','agenda_date':today, 'agenda_duration':'w'})

            elseif key ==? 'L'
                silent execute "call s:Timeline()"
            elseif key ==? 'c'
                execute "call OrgCustomSearchMenu()"
            elseif key ==? 'm'
                let mysearch = input("Enter search string: ")
                silent call s:RunCustom({'type':'tags','spec':mysearch})
                "silent execute "call OrgRunSearch(mysearch)"
            elseif key ==? 'h'
                let g:org_sparse_spec = input("Enter search string: ")
                if bufname("%") ==? '__Agenda__'
                    :bd
                endif
                silent execute "call OrgRunSearch(g:org_sparse_spec,1)"
            elseif key ==? 'f'
                let g:org_sparse_spec = input("Enter search string: ")
                if bufname("%") ==? '__Agenda__'
                    :bd
                endif
                silent call s:SparseTreeRun(g:org_sparse_spec)
            endif
        finally
            if bufname('%') == '__Agenda__'
                if !exists("b:v")
                    let b:v = {}
                endif
                let b:v.agenda_files = copy(g:agenda_files)
                let @/=''
            endif
            if len(saved_afiles) > 0
                let g:agenda_files = copy(saved_afiles)
            endif
        endtry
    endif
endfunction

function! s:AgendaBufSyntax()
    "called once whenever new agenda buffer is opened from regular or date agenda
    "searches
    call s:AgendaHighlight()
    syntax clear
    if has("conceal")
        syntax match Locator '^\d\+' conceal containedin=AOL1,AOL2,AOL3,AOL4,AOL5,agenda_todo,agenda_done,agenda_scheduled,agenda_scheduled_previous
        syntax match TimeGridSpace '^ \{8}\ze *\d\d:\d\d' conceal containedin=agenda_timegrid
        "for agenda clocktable
        syn region Org_Full_Link concealends matchgroup=linkends start='\[\[\(.\{-1,}\)]\[' end=']]'
    endif	
    syntax match agenda_timegrid '^\s*\d\d:\d\d.\{14}--.*' 
    syntax match AOL1 '^\d\+\s\+\S\+\s\{-1,16}\*\{1} .*$'hs=s+23
    syntax match AOL2 '^\d\+\s\+\S\+\s\{-1,16}\*\{2} .*$'hs=s+23
    syntax match AOL3 '^\d\+\s\+\S\+\s\{-1,16}\*\{3} .*$'hs=s+23
    syntax match AOL4 '^\d\+\s\+\S\+\s\{-1,16}\*\{4} .*$'hs=s+23
    syntax match AOL5 '^\d\+\s\+\S\+\s\{-1,16}\*\{5} .*$'hs=s+23
    
    let donepat_fragment = '\(' . join(keys(g:org_todos_done_dict),'\|') . '\)'
    let donepat = ' \*\+ \zs' . donepat_fragment . ' '
    exec "syntax match DONETODO /" . donepat . '/ containedin=AOL1,AOL2,AOL3,AOL4,AOL5'
    let notdonepat_fragment = '\(' . join(keys(g:org_todos_notdone_dict),'\|') . '\)'
    let notdonepat = ' \*\+ \zs' . notdonepat_fragment . ' '
    exec "syntax match NOTDONETODO /" . notdonepat . '/ containedin=AOL1,AOL2,AOL3,AOL4,AOL5'
    
    syntax match agenda_scheduled_previous  '^\d\+\s\+\S\+\s\+Sched.\{-}:.*$'
    syntax match agenda_scheduled  '^\d\+\s\+\S\+\s\+Scheduled:.*$'
    
    exec 'syntax match agenda_todo  /^\d\+\s\+\S\+\s\+\(In\|Deadline\|(\d\).\{-}:.\{-}\* ' . notdonepat_fragment . ' .*$/ contains=Locator'
    exec 'syntax match agenda_done  /^\d\+\s\+\S\+\s\+\(In\|Deadline\|(\d\).\{-}:.\{-}\* ' . donepat_fragment . ' .*$/'
    let daytextpat = '/^[^S]\S\+\s\+\d\{1,2}\s\S\+\s\d\d\d\d.*/'
    let wkendtextpat = '/^S\S\+\s\+\d\{1,2}\s\S\+\s\d\d\d\d.*/'
    exec 'syntax match agenda_date ' . daytextpat  
    
    exec 'syntax match agenda_weekenddate ' . wkendtextpat  
    syntax match agenda_omitted_days ' \[\. \..\{-}empty days omitted \]'

    " call to set up syntax and highlights for custom todos in agenda
    call s:OrgCustomTodoHighlights()
    
endfunction
function! s:AgendaHighlight()
    if g:org_gray_agenda
        hi link AOL1 NONE 
        hi link AOL2 NONE
        hi link AOL3 NONE
        hi link AOL4 NONE
        hi link AOL5 NONE
        hi Deadline guifg=lightred
        hi Scheduled guifg=lightyellow
    else
        hi link AOL1 OL1
        hi link AOL2 OL2
        hi link AOL3 OL3
        hi link AOL4 OL4
        hi link AOL5 OL5
        hi Deadline guifg=NONE
        hi Scheduled guifg=NONE
    endif
endfunction

function! OrgScreenLines() range
    " returns lines as
    " seen on screen, including folded text overlays
    " Call with visual selection set, or will
    " use last selection
    let save_cursor = getpos('.')
    let newline=0
    let oldline=1
    let mylines=[]
    normal '>
    let endline = line('.')
    " go to first line of selection
    normal '<
    while (line('.') <= endline) && (newline != oldline)
        let oldline=line('.')
        let newline=oldline
        call add(mylines,OrgFoldText(line('.')))
        normal j
        let newline=line('.')
    endwhile
    call setpos('.',save_cursor)
    return mylines
endfunction

function! s:CurTodo(line)
    let result = matchstr(getline(a:line),'.*\* \zs\S\+\ze ')
    if index(b:v.todoitems,curtodo) == -1
        let result = ''
    endif
    return result
endfunction

"autocmd CursorHold * call s:Timer()
function! s:Timer()
    call feedkeys("f\e")
    " K_IGNORE keycode does not work after version 7.2.025)
    echo strftime("%c")
    " there are numerous other keysequences that you can use
endfunction

autocmd BufNewFile __Agenda__ call s:ScratchBufSetup()
"autocmd BufWinEnter __Agenda__ call s:AgendaBufSyntax()
" Command to edit the scratch buffer in the current window
"command! -nargs=0 Agenda call s:AgendaBufferOpen(0)
" Command to open the scratch buffer in a new split window
command! -nargs=0 AAgenda call s:AgendaBufferOpen(1)
command! -nargs=0 EditAgenda call s:AgendaBufferOpen(0)

command! -nargs=0 OrgToPDF :call s:ExportToPDF()
command! -nargs=0 OrgToHTML :call s:ExportToHTML()
command! -nargs=0 OrgToAscii :call s:ExportToAscii()
command! -nargs=0 OrgToDocBook :call s:ExportToDocBook()
function! s:OrgHasEmacsVar()
    let result = 1
    if !exists('g:org_command_for_emacsclient')
        let msg = "=============================================== \n"
                \ . "You're trying to call out to Emacs but \n"
                \ . "you haven't set an Emacs command variable. \n"
                \ . "You should set this in your vimrc by including \n"
               \ . "a line like: \n\n"
               \ . "    let g:org_command_for_emacsclient=[put command to start emacs here] \n\n"
               \ . "See :h vimorg-emacs-setup for more info. \n\n"
               \ . "The call you attempted to Emacs will now be aborted.  \n"
               \ . "Revise your vimrc and restart Vim to use this feature.\n"
               \ . "==============================================\n"
               \ . "Press <enter> to continue."
        call input(msg)
        let result = 0
    endif
    return result
endfunction
function! OrgGetClocktable(filelist, options)
    let i = 0
    let filelist = copy(a:filelist)
    let filestr = ''
    while i < len(filelist)
        let filelist[i] = substitute(expand(filelist[i]),'\','/','g')
        let filelist[i] = '"' . substitute(filelist[i],' ','\ ','g') . '" '
        let filestr .=  filelist[i] 
        let i += 1
    endwhile
    let clkfile = '~/cblock.org'
    
    let mylist = ['#+BEGIN: clocktable :scope (' . filestr . ') ' . a:options ,'','#+END:','']
    
    call writefile(mylist, expand(clkfile) )

    let part1 = '(let ((org-confirm-babel-evaluate nil)(buf (find-file \' . s:cmd_line_quote_fix . '"' . clkfile . '\' . s:cmd_line_quote_fix . '"' . '))) (progn (org-dblock-update)(save-buffer buf)(kill-buffer buf)))' 
        let orgcmd = g:org_command_for_emacsclient . ' --eval ' . s:cmd_line_quote_fix . '"' . part1 . s:cmd_line_quote_fix . '"'
        "redraw
        "unsilent echo "Calculating in Emacs. . . "
        if exists('*xolox#shell#execute')
            silent call xolox#shell#execute(orgcmd, 1)
        else
          silent  exe '!' . orgcmd
        endif
        
        return readfile(expand('~/cblock.org'))
endfunction
function! OrgEvalBlock()
    let savecursor = getpos('.')
    let save_showcmd = &showcmd | set noshowcmd
    
    let start = search('^#+begin:','bnW','') 
    let prev_end = search('^#+end','bnW','') 
    let end = search('^#+end','nW','') 
    if (start == 0) || (end == 0) || ( ( prev_end > start ) && (prev_end < line('.') ) )
        unsilent echo "You aren't in a dynamic block."
        return
    endif

    exec start
    let block_name = matchstr(getline(line('.')),'\c^#+BEGIN:\s*\zs\S\+')

    if start < end - 1
        exec (start+1) . ',' . (end-1) . 'delete'
    endif
    exec start
    let line_mark = '@@@@@' . start . '@e@f@g@h'
    exec 'normal o' . line_mark 
    
    silent write!
    let this_file = substitute(expand("%:p"),'\','/','g')
    let this_file = substitute(this_file,' ','\ ','g')

    let part1 = '(let ((org-confirm-babel-evaluate nil)(buf (find-file \' . s:cmd_line_quote_fix . '"' . this_file . '\' . s:cmd_line_quote_fix . '"' . '))) (progn (search-forward \^"' . line_mark . '\^" )(forward-line -1)(org-dblock-update)(beginning-of-line)(set-mark (point))(re-search-forward \^"^#\\+END\^")(end-of-line)(write-region (mark) (point) \' . s:cmd_line_quote_fix . '"~/org-block.org\' . s:cmd_line_quote_fix . '")(set-buffer buf) (not-modified) (kill-this-buffer)))' 
    " line below was using org-narrow-to-block, which may use again
        "let part1 = '(let ((org-confirm-babel-evaluate nil)(buf (find-file \' . s:cmd_line_quote_fix . '"' . this_file . '\' . s:cmd_line_quote_fix . '"' . '))) (progn (search-forward \^"' . line_mark . '\^" )(forward-line -1)(org-dblock-update)(org-narrow-to-block)(write-region (point-min) (point-max) \' . s:cmd_line_quote_fix . '"~/org-block.org\' . s:cmd_line_quote_fix . '")(set-buffer buf) (not-modified) (kill-this-buffer)))' 
        let orgcmd = g:org_command_for_emacsclient . ' --eval ' . s:cmd_line_quote_fix . '"' . part1 . s:cmd_line_quote_fix . '"'
        redraw
        unsilent echo "Calculating in Emacs. . . "
        if exists('*xolox#shell#execute')
            silent call xolox#shell#execute(orgcmd, 1)
        else
          silent  exe '!' . orgcmd
        endif
        let g:orgcmd = orgcmd
        exec start
        normal 3ddk
        silent exe 'read ~/org-block.org'
        redraw
        unsilent echo "Block is being evaluated in Emacs. . .   Evaluation complete."

        let &showcmd = save_showcmd
    call setpos('.',savecursor)
    "return readfile(expand('~/org-block.org'))
endfunction

function! s:OrgTableOptionList(A,L,P)
    return keys(s:OrgTableEvalOptions())
endfunction
command! -buffer -nargs=? -complete=customlist,s:OrgTableOptions OrgTblEval :call OrgEvalTable(<f-args>)
function! s:OrgTableEvalOptions()
    return  { 'col_right':'org-table-move-column-right',
                            \ 'col_left': 'org-table-move-column-left',
                            \ 'col_delete': 'org-table-delete-column',
                            \ 'col_insert': 'org-table-insert-column',
                            \ 'row_down': 'org-table-move-row-down',
                            \ 'row_up': 'org-table-move-row-up',
                            \ 'row_delete': 'org-table-kill-row',
                            \ 'row_insert': 'org-table-insert-row',
                            \ 'row_sort_region_alpha': 'org-table-sort-lines nil ?a',
                            \ 'row_sort_region_numeric': 'org-table-sort-lines nil ?n',
                            \ 'row_sort_region_alpha_reverse': 'org-table-sort-lines nil ?A',
                            \ 'row_sort_region_numeric_reverse': 'org-table-sort-lines nil ?N',
                            \ 'row_hline_insert': 'org-table-insert-hline',
                           \  'convert_region_to_table':'org-table-convert-region (point-min) (point-max)'  }
endfunction

command! -buffer -nargs=0 OrgTableDashboard :call OrgTableDashboard()
function! OrgTableDashboard()
    if s:OrgHasEmacsVar() == 0
       return
    endif
    let save_more = &more | set nomore
    let save_showcmd = &showcmd | set noshowcmd
    " different dashboard for "in table" and "not in table"
    " show export dashboard
    if getline(line('.')) =~ '^\s*$'
        let rows_cols = input("Create new table (enter rows, columns): ")
        if rows_cols =~ '^\d\+\s*,\s*\d\+$'
            let [rows,cols] = split(rows_cols,',')
            call org#tbl#create(cols,rows)
        elseif rows_cols =~ '^\d\+\s\+\d\+$'
            let [rows,cols] = split(rows_cols,' ')
            call org#tbl#create(cols,rows)
        endif
        return
    endif
    echohl MoreMsg
    echo " --------------------------------"
    echo " Press key for table  operation:"
    echo " --------------------------------"
    if getline(line('.')) !~ b:v.tableMatch
        let mydict = {  't' : 'convert_region_to_table'}  
        echo " [t]  Create (t)able from current block" 
    else
        let mydict = { 'l':'col_left', 'r':'col_right', 'e':'col_delete', 'o':'col_insert',
                \     'd':'row_down', 'u':'row_up', 'x':'row_delete', 
                \     'i':'row_insert', 'a':'row_sort_region_alpha', 'A':'row_sort_region_alpha_reverse',
                \     'n':'row_sort_region_numeric', 'N':'row_sort_region_numeric', 'h':'row_hline_insert'
                \      } 
        echo " COLUMN:  [l] Move left  [r] Move right  [e] Delete  [o] Insert"
        echo " ROW:     [d] Move down  [u] Move up     [x] Delete  [i] Insert"
        echo " "
        echo " RowSort: [a] alpha(a-z)     [A] alpha(z-a)"
        echo "          [n] numeric(1..9)  [N] numeric(9-1)"
        echo ""
        echo "          [h] insert horizontal line"
    endif
    echo " "
    echohl None
    let key = nr2char(getchar())
    for item in keys(mydict)
        if key == 't'
            let thisline = getline(line('.'))
            if thisline !~ '^\s*$'
                let firstline = search('^\s*$','nb','') + 1
                let lastline = search('^\s*$','n','') - 1
                exec firstline . ',' . lastline . 'call OrgEvalTable(mydict[item])'
            else
                echo "You aren't in a block of text."
            endif
            break
        elseif (key =~# item) 
            exec 'OrgTblEval ' . mydict[item]
            break
        endif
    endfor
    let &more = save_more
    let &showcmd = save_showcmd

endfunction

function! OrgEvalTable(...) range
    let options = s:OrgTableEvalOptions()
    if a:0 == 1
        let opt = a:1
        let opt_cmd = '(' . options[opt] . ')'
    else
        let opt = 'just_eval'
        let opt_cmd = ''
    endif
    let savecursor = getpos('.')
    if a:firstline == a:lastline
        " get start, end for whole table
        "call search('^\s*[^|]','b','')
        call search('^\(\s*|\)\@!','b','')
        let start=line('.')
        call search('^\(\s*|\)\@!','','')
        let end=line('.')
    else
        let start=a:firstline
        let end  =a:lastline
    endif
    let line_offset = savecursor[1] - start + 1
    "let line_offset = savecursor[1] - start 
    " find first line after table block and check for formulas
        exe start . ',' . end . 'w! ~/org-tbl-block.org'
        if opt != 'convert_region_to_table'
            let part1 = '(let ((org-confirm-babel-evaluate nil)'
                       \  . '(buf (find-file \' . s:cmd_line_quote_fix . '"~/org-tbl-block.org\' . s:cmd_line_quote_fix . '"' . ')))'
                       \  . '(progn (beginning-of-line ' . line_offset . ')(forward-char ' . savecursor[2] .')'
                       \  . '(org-table-maybe-eval-formula)' 
                       \  . ((opt=='just_eval') ? '' : '(unwind-protect ') . opt_cmd 
                       \  . '(org-table-recalculate-buffer-tables)(save-buffer buf)(kill-buffer buf))))' 
        else
            let part1 = '(let ((org-confirm-babel-evaluate nil)'
                       \  . '(buf (find-file \' . s:cmd_line_quote_fix . '"~/org-tbl-block.org\' . s:cmd_line_quote_fix . '"' . ')))'
                       \  . '(progn (beginning-of-line ' . line_offset . ')(forward-char ' . savecursor[2] .')'
                       \  . '(goto-char (point-min))(set-mark (point))(goto-char (point-max))' . opt_cmd
                       \  . '(save-buffer buf)(kill-buffer buf)))' 
        endif
        let orgcmd = g:org_command_for_emacsclient . ' --eval ' . s:cmd_line_quote_fix . '"' . part1 . s:cmd_line_quote_fix . '"'
        redraw
        unsilent echo "Calculating in Emacs. . . "

        let g:orgcmd = orgcmd

        "if exists('*xolox#shell#execute')
        "    silent let myx = xolox#shell#execute(orgcmd . '| cat', 1)
        "else
            silent exe '!' . orgcmd
        "endif
        exe start .',' . end . 'read ~/org-tbl-block.org'
        exe start . ',' . end . 'd'
        redraw
        unsilent echo "Calculating in Emacs. . .   Calculations complete. " 
    "else
    "    unsilent echo "No #+TBLFM line at end of table, so no calculations necessary."
    "endif
    call setpos('.',savecursor)
endfunction
function! OrgEval()
    if s:OrgHasEmacsVar() == 0
        call confirm('VimOrganizer has not been configured to make calls to Emacs.'
                  \ . "\nPlease see :h vimorg-emacs-setup.") 
       return
    endif
    " check if we're in source block
    let line = getline(line('.'))
    let start = search('\c^#+begin_src','cbnW','')
    let prev_end = search('\c^#+end_src','bnW','') 
    let end = search('\c^#+end_src','cnW','') 
    if (start > 0) && (end > start) && ( prev_end < start )
        call OrgEvalSource()
        return
    endif
    " check if we're in dynamic block
    let start = search('^#+begin:','bnW','')
    let prev_end = search('^#+end','bnW','') 
    let end = search('^#+end','nW','') 
    if (start > 0) && (end > start) && ( prev_end < start )
        call OrgEvalBlock()
        return
    endif
    "check if we're in a table
    if line =~ '^\s*|.*|\s*$'
        call OrgEvalTable()
        return
    endif

   unsilent echo "No evaluation done.  You must be in a table, or on an initial "
            \ . "\nblock line that begins in col 0 with #+BEGIN . . ."
    
endfunction

function! OrgEvalSource()
    let savecursor = getpos('.')
    let start = search('^#+begin_src','cbnW','') - 1
    let prev_end = search('^#+end_src','bnW','') 
    let end = search('^#+end_src','cnW','') 
    if (start == -1) || (end == 0) || ( ( prev_end > start ) && (prev_end < line('.') ) )
        unsilent echo "You aren't in a code block."
        return
    endif
    exec end
    " include results if there is result block w/in a couple of lines
    if ( search('^\s*#+results','nW','') - end ) <= 3
        call search('^\s*#+results','','')
        if getline(line('.')+1) =~ '#+BEGIN_RESULT'
            call search('^#+END_RESULT')
            normal j
        else
            " :'s used as linebegins w/first blank line as end of result block
            call search('^\s*$','','')
        endif
        normal k
        let end = line('.')
    endif
    exe start . ',' . end . 'w! ~/org-src-block.org'
    let part1 = '(let ((org-confirm-babel-evaluate nil)) (progn (find-file \' . s:cmd_line_quote_fix . '"~/org-src-block.org\' . s:cmd_line_quote_fix . '"' . ')(org-babel-next-src-block)(org-babel-execute-src-block)(save-buffer)(kill-buffer)))' 
    let orgcmd = g:org_command_for_emacsclient . ' --eval ' . s:cmd_line_quote_fix . '"' . part1 . s:cmd_line_quote_fix . '"'
    if exists('*xolox#shell#execute')
        silent call xolox#shell#execute(orgcmd, 1)
    else
        silent exe "!" . orgcmd
    endif
    exe start .',' . end . 'read ~/org-src-block.org'
    exe start . ',' . end . 'd'
    call setpos('.',savecursor)
endfunction
function! MyExpTest()
    let g:orgpath='c:\users\herbert\emacsclientw.exe --eval '
    let g:myfilename = substitute(expand("%:p"),'\','/','g')
    let g:myfilename = substitute(g:myfilename, '/ ','\ ','g')
    let g:myvar = '(let ((org-export-babel-evaluate nil)) (progn (find-file \^' . '"' . g:myfilename . '\^' . '"' . ') (org-export-as-html-and-open 3) (kill-buffer) ))'
    let g:myc =  '!' . g:orgpath . '^"' . g:myvar . '^"' 
    silent exec g:myc
endfunction
function! OrgExportDashboard()
    if s:OrgHasEmacsVar() == 0
       return
    endif
    let save_more = &more | set nomore
    let save_showcmd = &showcmd | set noshowcmd
    " show export dashboard
    "let mydict = { 't':'template', 'a':'ascii', 'n':'latin1', 'u':'utf8',
    let mydict = { 't':'template', 'a':'ascii', 'A':'ascii', 'o':'odt', 'O':'odt-and-open',
            \     'n':'latin1', 'N':'latin1', 'u':'utf8','U':'utf8',
            \     'h':'html', 'b':'html-and-open', 'l':'latex', 
            \     'f':'freemind', 'j':'taskjuggler', 'k':'taskjuggler-and-open',
            \     'p':'pdf', 'd':'pdf-and-open', 'D':'docbook', 'g':'tangle',  
            \     'F':'current-file', 'P':'current-project', 'E':'all' } 
    echohl MoreMsg
    echo " Press key for export operation:"
    echo " --------------------------------"
    echo " [t]   insert the export options template block"
    echo " "
    echo " [a/n/u]  export as ASCII/Latin1/utf8  [A/N/U] ...and open in buffer"
    echo " "
    echo " [h] export as HTML"
    echo " [b] export as HTML and open in browser"
    echo " "
    echo " [l] export as LaTeX"
    echo " [p] export as LaTeX and process to PDF"
    echo " [d] . . . and open PDF file"
    echo " "
    echo " [o] export as ODT        [O] as ODT and open"
    echo " [D] export as DocBook"
    echo " [V] export as DocBook, process to PDF, and open"
    echo " [x] export as XOXO       [j] export as TaskJuggler"
    echo " [m] export as Freemind   [k] export as TaskJuggler and open"

    echo " [g] tangle file"
    echo " "
    echo " [F] publish current file"
    echo " [P] publish current project"
    echo " [E] publish all projects"
    echo " "
    echohl None
    let key = nr2char(getchar())
    for item in keys(mydict)
        if (item ==# key) && (item !=# 't')
            "let g:org_emacs_autoconvert = 1
            "call s:GlobalUnconvertTags(changenr())
            let exportfile = expand('%:t') 
            silent exec 'write'

            let orgpath = g:org_command_for_emacsclient . ' -n --eval '
            let g:myfilename = substitute(expand("%:p"),'\','/','g')
            let g:myfilename = substitute(g:myfilename, '/ ','\ ','g')
            " set org-mode to either auto-evaluate all exec blocks or evaluate none w/o
            " confirming each with yes/no
            if g:org_export_babel_evaluate == 1
                let g:mypart1 = '(let ((org-export-babel-evaluate t)(org-confirm-babel-evaluate nil)'
            else
                let g:mypart1 = '(let ((org-export-babel-evaluate nil)'
            endif
            let g:mypart1 .= '(buf (find-file \' . s:cmd_line_quote_fix . '"' . g:myfilename . '\' . s:cmd_line_quote_fix . '"))) (progn  (' 

            if item =~? 'g' 
                let g:mypart3 = ' ) (set-buffer buf) (not-modified) (kill-this-buffer) ))'
            else  
                let g:mypart3 = ' nil ) (set-buffer buf) (not-modified) (kill-this-buffer) ))'
            endif
            
            if item =~# 'F\|P\|E'
                let command_part2 = ' org-publish-' . mydict[key]
            elseif item == 'g'
                let command_part2 = ' org-babel-tangle'
            else
                let command_part2 = ' org-export-as-' . mydict[key]
            endif

            let orgcmd =  orgpath . s:cmd_line_quote_fix . '"' . g:mypart1 . command_part2 . g:mypart3 . s:cmd_line_quote_fix . '"'
            let g:orgcmd = orgcmd
            " execute the call out to emacs
            redraw
            echo "Export in progress. . . "
            if exists('*xolox#shell#execute')
                "silent! let g:expmsg = xolox#shell#execute(orgcmd . ' | cat ', 1)
                silent! call xolox#shell#execute(orgcmd , 1)
            else
                "execute '!' . orgcmd
                silent! execute '!' . orgcmd
            endif
            redraw
            echo "Export in progress. . . Export complete."
            break
        endif
    endfor
    if key ==# 't' 
        let template = [
                    \ '#+TITLE:     ' . expand("%p")
                    \ ,'#+AUTHOR:   '
                    \ ,'#+EMAIL:    '
                    \ ,'#+DATE:     ' . strftime("%Y %b %d %H:%M")
                    \ ,'#+DESCRIPTION: '
                    \ ,'#+KEYWORDS: '
                    \ ,'#+LANGUAGE:  en'
                    \ ,'#+OPTIONS:   H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t'
                    \ ,'#+OPTIONS:   TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc'
                    \ ,'#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js'
                    \ ,'#+EXPORT_SELECT_TAGS: export'
                    \ ,'#+EXPORT_EXCLUDE_TAGS: noexport'
                    \ ,'#+LINK_UP:   '
                    \ ,'#+LINK_HOME: '
                    \ ,'#+XSLT: '
                    \ ]
        silent call append(line('.')-1,template)
    elseif key =~# 'A\|N\|U'
        exec 'split ' . expand('%:r') . '.txt'
        normal gg
    endif

    let &more = save_more
    let &showcmd = save_showcmd

endfunction

function! s:MailLookup()
    Utl openlink https://mail.google.com/mail/?hl=en&shva=1#search/after:2010-10-24+before:2010-10-26
    "https://mail.google.com/mail/?hl=en&shva=1#search/after%3A2010-10-24+before%3A2010-10-26
endfunction
function! s:UniqueList(list)
    " returns the union of two lists
    " (some algo ...)
    let rdict = {}
    for item in a:list
            let rdict[item] = 1
    endfor
    return sort(map(keys(rdict),'str2nr(v:val)'))
endfunc 
function! s:Union(list1, list2)
    " returns the union of two lists
    " (some algo ...)
    let rdict = {}
    for item in a:list1
            let rdict[item] = 1
    endfor
    for item in a:list2
            let rdict[item] = 1
    endfor
    return sort(keys(rdict))
endfunc 
function! s:Intersect(list1, list2)
    " returns the intersection of two lists
    " (some algo ...)
    " fro andy wokula on vim-use mailing list
    let rdict = {}
    for item in a:list1
        if has_key(rdict, item)
            let rdict[item] += 1
        else
            let rdict[item] = 1
        endif
    endfor
    for item in a:list2
        if has_key(rdict, item)
            let rdict[item] += 1
        else
            let rdict[item] = 1
        endif
    endfor
    call filter(rdict, 'v:val == 2')
    return sort(keys(rdict))
endfunc 

function! OrgSetEmphasis( emph_char ) range
    let emph_char = a:emph_char
    let my_mode = mode()
    if my_mode ==? 'v'
        exe 'normal oi' . emph_char 
        exe 'normal gvoi' . emph_char
    else
        exe 'normal i' . emph_char . emph_char
    endif
endfunction

function! s:OrgCustomTodoHighlights()
    if !exists('g:org_todo_custom_highlights')
        return
    endif
    for item in keys(g:org_todo_custom_highlights)
        let d = g:org_todo_custom_highlights
        if has('gui_running')
            let fg = get(d[item], 'guifg')
            let bg = get(d[item], 'guibg')
            exec 'hi! ' . item . ((fg>#'')  ? ' guifg=' . fg : '') . ((bg>#'') ? ' guibg=' . bg : '')
        else
            let fg = get(d[item], 'ctermfg')
            let bg = get(d[item], 'ctermfg')
            exec 'hi! ' . item . ((fg>#'')  ? ' ctermfg=' . fg : '') . ((bg>#'') ? ' ctermbg=' . bg : '')
        endif

        " xxxx todo put back in containedins, do synclears? check order?
        if bufname('%')=='__Agenda__'
            exec 'syntax match ' . item . ' ' .  '+ \*\+ \zs' . item . ' + containedin=AOL1,AOL2,AOL3,AOL4,AOL5,AOL6' 
        else
            " delete current match if it already exists
            let mymatches = getmatches()
            let tempdict = {}
            for i in range(0, len(mymatches)-1)
                let tempdict[i] = mymatches[i]
            endfor
            for i in keys(tempdict)
                if tempdict[i].group == item
                    exec 'syntax clear ' . tempdict[i].group
                    break
                endif
            endfor
            "now put new match in
            exec 'syntax match ' . item . ' ' .  '+\*\+ \zs' . item . ' + containedin=OL1,OL2,OL3,OL4,OL5,OL6' 
        endif
        
    endfor
endfunction

function! OrgSetColors()
    " Set highlights for outline headings.  These are set from existing
    " highlights in a colorscheme:
    "  OL1 from Statement
    "  OL2 from Identifier
    "  OL3 from Constant
    "  OL4 from Comment
    "  OL5 from Special
    for pair in [ ['OL1','Statement'], ['OL2','Identifier'], ['OL3','Constant'],
            \     ['OL4','Comment'],   ['OL5','Special'] ]
        execute 'hi clear ' . pair[0]
        execute 'hi clear ' . pair[0] .'Folded'
        execute 'hi ' . pair[0] . ' ' . org#GetGroupHighlight( pair[1] )
        execute 'hi ' . pair[0] . 'Folded ' . org#GetGroupHighlight( pair[1] )
        execute 'hi ' . pair[0] . ' gui=NONE'
        execute 'hi ' . pair[0] . 'Folded gui=bold'
    endfor
    
    if has('gui_running')
        hi! FoldColumn guifg=bg guibg=bg 
    else
        try
            hi! FoldColumn ctermfg=bg ctermbg=bg 
        catch
            hi! FoldColumn ctermfg=0 ctermbg=0
        endtry
    endif
   
    "show text on SignColumn
    hi! SignColumn guibg=fg guibg=bg 
  

    " various text item "highlightings" are below
    " change to suit your taste and put in OrgCustomColors() (see below)
    hi! Org_Drawer guifg=pink ctermfg=magenta
    hi! Org_Drawer_Folded guifg=pink ctermfg=magenta gui=bold cterm=bold
    hi! Org_Property_Value guifg=pink ctermfg=magenta
    hi! Org_Block guifg=#555555 ctermfg=magenta
    hi! Org_Src_Block guifg=#555555 ctermfg=magenta
    hi! Org_Table guifg=#888888 guibg=#333333 ctermfg=magenta
    hi! Org_Config_Line guifg=darkgray ctermfg=magenta
    hi! Org_Tag guifg=lightgreen ctermfg=blue
    hi! Org_Date guifg=magenta ctermfg=magenta gui=underline cterm=underline
    hi! Org_Star guifg=#444444 ctermfg=darkgray
    hi! Props guifg=#ffa0a0 ctermfg=gray
    hi! Org_Code guifg=darkgray gui=bold ctermfg=14
    hi! Org_Itals gui=italic guifg=#aaaaaa ctermfg=lightgray
    hi! Org_Bold gui=bold guifg=#aaaaaa ctermfg=lightgray
    hi! Org_Underline gui=underline guifg=#aaaaaa ctermfg=lightgray
    hi! Org_Marked gui=bold guibg=#bbaacc ctermbg=lightgray
    hi! Org_Lnumber guifg=#999999 ctermfg=gray

    " agenda highlight groups below 
    hi Overdue guifg=red
    hi Upcoming guifg=yellow
    hi DateType guifg=#dd66bb
    hi Locator guifg=#333333

    "hi agenda_dayline guifg=#44aa44 gui=underline
    "hi agenda_weekendline guifg=#55ee55 gui=underline
    hi agenda_omitted_days guifg=#555555 ctermfg=gray
    hi agenda_todo guifg=lightred gui=bold ctermfg=lightred cterm=bold
    hi agenda_done guifg=lightgreen ctermfg=lightgreen
    hi agenda_date guifg=lightblue ctermfg=lightblue
    hi agenda_weekenddate guifg=lightblue gui=bold ctermfg=lightblue cterm=bold
    hi agenda_scheduled guifg=lightyellow ctermfg=lightyellow
    hi agenda_scheduled_previous guifg=lightmagenta ctermfg=lightmagenta
    hi agenda_timegrid guifg=#666666 ctermfg=gray
    " end agenda highlights
  
    if has("conceal")
        hi! default linkends guifg=blue ctermfg=blue
    endif
    hi! Org_Full_Link guifg=cyan gui=underline ctermfg=lightblue cterm=underline
    hi! Org_Half_Link guifg=cyan gui=underline ctermfg=lightblue cterm=underline
    highlight OrgColumnHeadings guibg=#444444 guifg=#aaaaaa gui=underline

    hi! DONETODO guifg=green ctermfg=green
    hi! NOTDONETODO guifg=red ctermfg=lightred

    "user can define OrgCustomColors() in vimrc for above items, these will be executed
    "here and override the defaults above.
    if exists('*OrgCustomColors')
        call OrgCustomColors()
    endif

    call s:OrgCustomTodoHighlights()

    " below is for setting highlight groups for when agenda is used to
    " select a headline in main doc, or when items are marked.
    " Use g:org_selector_ctermbg and/or g:org_selector_guibg 
    " to customize.
    for i in range(1,5)
        let hlstring = org#GetGroupHighlight('OL' . i)
        let ctermbg = 'ctermbg=' . (exists('g:org_selector_ctermbg') ? g:org_selector_ctermbg : 'gray')
        let guibg = 'guibg=' . (exists('g:org_selector_guibg') ? g:org_selector_guibg : '#333333')
        if hlstring =~ 'ctermbg'
            let hlstring = substitute(hlstring,'ctermbg=\S+',ctermbg,'')
        else
            let hlstring = hlstring . ' ' . ctermbg
        endif
        if hlstring =~ 'guibg'
            let hlstring = substitute(hlstring,'guibg=\S+',guibg,'')
        else
            let hlstring = hlstring . ' ' . guibg
        endif
        exec 'hi! Org_Chosen_Agenda_Heading' . i . ' ' . hlstring
    endfor
    exec 'hi! Org_Chosen_Agenda_Heading ' . guibg . ' ' . ctermbg
endfunction
autocmd ColorScheme  * :silent! call OrgSetColors()
call OrgSetColors()

function! s:OrgPromoteSubheads()
    let line = s:OrgGetHead()
    let star_count = 1 + len(matchstr(getline(line('.')),'^\*\+'))
    let start_line = line + 1
    let end_line = s:OrgSubtreeLastLine()
    let subheads = []
    execute start_line . ',' . end_line . 'g/^\*\{' . star_count . '} /call add(subheads,line("."))'
    for i in sort(subheads,'<SID>ReverseSort')
        exec i
        call OrgMoveLevel(i,'left')
    endfor
    execute line
    echo "Subheads promoted."
endfunction
"Section for refile and archive funcs
function! OrgRefileDashboard()
    echohl MoreMsg
    echo " ================================"
    echo " Persisted point is: " . (!exists('persistent_refile_point') ? 'None' : join(s:persistent_refile_point,'/'))
    echo " Last point used:    " . (!exists('s:last_refile_point') ? 'None' : join(s:last_refile_point,'/'))
    echo " ================================"
    echo " Press key for a refile command:"
    echo " --------------------------------"
    echo " r / l / p  refile subtree to new point/last point/persisted point"
    echo " j / z / t  jump to new point/last point/persistent point"
    echo " s          set persistent refile point "
    echo " a          archive to _archive file"
    echo " v          jump to _archive file"
    echo ""
    echohl Question
    let key = nr2char(getchar())
    redraw
    if key ==? 'r'
        call s:OrgRefile(line('.'))
    elseif key ==? 'l'
        call s:OrgRefileToLastPoint(line('.'))
    elseif key ==? 'p'
        call s:OrgRefileToPermPoint(line('.'))
    elseif key ==? 'j'
        call s:OrgJumpToRefilePoint()
    elseif key ==? 'z'
        call s:OrgJumpToLastRefilePoint()
    elseif key ==? 't'
        call s:OrgJumpToRefilePointPersistent()
    elseif key ==? 's'
        call s:OrgSetRefilePoint()
    elseif key ==? 'v'
        call org#LocateFile(expand('%:p') . '_archive')
    elseif key ==? 'a'
        if confirm('Confirm that you want to archive subtree(s)',"&Yes\n&Cancel")
            call s:DoRefile(['_archive'],[line('.')])
        endif
    else
        echo "No refile option selected."
    endif
    echohl None
endfunction
function! s:OrgGatherDashboard()
    echohl MoreMsg
    echo " ================================"
    echo " Press key for a mark/gather/sort command:"
    echo " --------------------------------"
    echo " <space>    toggle mark on/off for current heading"
    echo " d          delete all marks"
    echo " h          gather marked headings to current heading"
    echo " s          sort subheads of current heading"
    echo ""
    echohl Question
    let key = nr2char(getchar())
    redraw
    if key ==? ' '
        call s:ToggleHeadingMark(line('.'))
    elseif key ==? 'd'
        call s:DeleteHeadingMarks()
    elseif key ==? 'h'
        call s:GatherMarks()
    elseif key ==? 's'
        call s:OrgSortSubheads()
    else
        echo "No gather/mark option selected."
    endif
    echohl None
endfunction

let g:org_heading_temp=['','','','','','','','']
function! s:OutlineHeads()
    let level = s:Ind(line('.'))
    let g:org_heading_temp[level-1] = matchstr(getline(line('.')),'^\*\+ \zs.*')
    " put level 1 head in result
    let result = expand("%:t") .  g:org_heading_temp[0]
    " now add full tree to level of current heading
    for item in g:org_heading_temp[1: level-1]
        let result .= '/' . item
    endfor
    return result 
endfunction
function! s:GetMyItems(arghead)
    " assemble and return list of subheads of argument file/heading
    let arghead = a:arghead
    let result = []
    if a:arghead[-1:] == '*'
        let arghead = arghead[:-2]
    endif
    let ilist = split(arghead,'/')
    call org#SaveLocation()
    if expand("%:t") != ilist[0]
        "call org#LocateFile( '~\Desktop\org_files\' . ilist[0] )
        call org#LocateFile( fnamemodify(s:refile_file,":p:h:") . '/' . ilist[0] )
        if &ft != 'org'
            set ft=org
        endif
    endif
    if a:arghead[-1:] == '*'
        let tolevel = 3
    else
        let tolevel = len(ilist)
    endif
    exec 'g/^\*\{1,' . tolevel . '} /call add(result, s:OutlineHeads())'
    call org#RestoreLocation()
    return result
endfunction
function! OrgFileList(arghead,sd,gf)
    let arghead = substitute(a:arghead,'\~','\\\~','g')
    let s:myheads  = ['[current file]'] + copy(g:agenda_files)
    let matches = filter( copy( s:myheads ),'v:val =~ arghead')
    redraw!
    return join( matches, "\n" )
endfunction

function! OrgHeadingList(arghead,sd,gf)
    let arghead = a:arghead
    let s:myheads = s:GetMyItems(arghead)
    let matches = filter( copy( s:myheads ),'v:val =~ a:arghead')
    redraw!
    return join( matches, "\n" )
endfunction

function! s:GetTarget()
    let orig_wildmode = &wildmode
    set wildmode=list:full
    try
        " need to modify getcmdline to strip back on bs
        cmap <c-BS> <C-\>egetcmdline()[-1:] == '/' ? matchstr(getcmdline()[:-2], '.*\ze/.*' ) . '/' : matchstr(getcmdline(), '.*\ze/.*') . '/'<CR>
        while 1
            let s:refile_file = ''
            "let s:refile_file = input("Target file: ","[current file]",'custom,s:FileList')
            let file_default = (bufname('%')==#'__Agenda__') ? g:agenda_files[0] : ""    
            "[current file]"
            let s:refile_file = input("Target file: ",file_default,'custom,OrgFileList')
            if s:refile_file ==# '[current file]'
                let s:refile_file = expand("%") 
            elseif index(g:agenda_files,s:refile_file) == -1
                break
            endif
            let heading = input('Outline heading: ', fnamemodify(s:refile_file,':t:') . "\t",'custom,OrgHeadingList')
            let head = matchstr(heading,'.\{-}/\zs.*')
            if head ==# ''
                continue
            else
                return [ s:refile_file, head]
            endif
        endwhile
    finally
        let &wildmode = orig_wildmode
        cunmap <c-BS>
    endtry
endfunction
function! s:OrgJumpToRefilePointPersistent()
    if exists('s:persistent_refile_point') && (len(s:persistent_refile_point)==2)
        call s:OrgGotoHeading( s:persistent_refile_point[0], s:persistent_refile_point[1] )
        normal zv
    else
        echo 'No persistent refile point assigned.'
    endif
endfunction
function! s:OrgJumpToLastRefilePoint()
    if exists('s:last_refile_point') && (len(s:last_refile_point)==2)
        let p = s:last_refile_point
        call s:OrgGotoHeading( p[0], p[1])
        normal zv
    else
        echo 'No last refile point yet.'
    endif
endfunction
function! s:OrgJumpToRefilePoint()
    let my_refile_point = s:GetTarget()
    if len(my_refile_point)==2
        call s:OrgGotoHeading( my_refile_point[0], my_refile_point[1] )
        normal zv
    else
        echo "Jump aborted."
    endif
endfunction
function! s:OrgSetRefilePoint()
    let s:persistent_refile_point = s:GetTarget()
endfunction
function! OrgSetArchivePoint()
    let s:archive_refile_point = s:GetTarget()
endfunction

function! OrgRefileToArchive(headline)
    if exists('s:archive_refile_point') && (s:archive_refile_point[1] !=# '')
        silent call s:DoRefile( s:archive_refile_point, [a:headline] )
        redraw!
        let p = s:archive_refile_point
        echo "Tree(s) refiled to: " . p[0] . '/' . p[1]
    else
        echo 'Refile aborted, archive point not assigned.'
    endif
endfunction
function! s:OrgRefileToPermPoint(headline)
    if exists('s:persistent_refile_point') && (s:persistent_refile_point[1] !=# '')
        silent call s:DoRefile( s:persistent_refile_point, [a:headline] )
        redraw!
        echo "Tree(s) refiled to: \n" . s:persistent_refile_point[0] . '/' . s:persistent_refile_point[1]
    else
        echo 'Refile aborted, persistent point not defined.'
    endif
endfunction
function! s:OrgRefileToLastPoint(headline)
    if exists('s:last_refile_point') && (s:last_refile_point[1] !=# '')
        silent call s:DoRefile( s:last_refile_point, [a:headline] )
        redraw!
        echo "Tree(s) refiled to: " . s:last_refile_point[0] . '/' . s:last_refile_point[1]
    else
        echo 'Refile aborted, no last point yet.'
    endif
endfunction
function! s:OrgSortSubheads()
    let start = line('.')
    if getline(start) !~ b:v.headMatch
        echo "You must be on a heading to sort subheads."
        return
    endif
   
    " FIRST DELETE ALL SIGNS
    sign unplace *
    let b:v.heading_marks_dict = {}
    let end = s:OrgSubtreeLastLine()
    execute start . ',' . end . 'g/^\*\{' . s:Ind(line('.')) . '} /call s:PlaceSignsForSort(line("."))'
    exec start
    call s:GatherMarks('forward')
    
endfunction
function! s:PlaceSignsForSort(line)
    exec 'sign place ' . a:line . " line=" . a:line . " name=marked buffer=".bufnr("%")
endfunction
command! -buffer OrgGatherMarks :call <SID>GatherMarks()
command! -buffer OrgGatherAgendaMarks :call <SID>GatherMarks('agenda')
function! s:GatherMarks(...)
    if getline(line('.')) !~ b:v.headMatch
        echo "You must be on a heading to gather."
        return
    endif
    let targ_list = [expand('%:p'), getline(line('.'))]
    if (a:0 == 1) && (a:1 ==# 'agenda')
        call org#LocateFile('__Agenda__')
    endif
    if org#redir('sign place') =~ 'name=marked'
        if (a:0 == 1) && (a:1 !=# 'agenda')
            silent call s:DoRefile( targ_list, [line('.')], a:1 )
        else
            silent call s:DoRefile( targ_list, [line('.')])
        endif
        call s:OrgGotoHeading(targ_list[0], targ_list[1])
        call OrgShowSubs(s:Ind(line('.')), 0)
        redraw!
        echo "Gathered marked headings to subheads of current heading."
    else
        echo 'No headings marked, nothing gathered.'
    endif
endfunction
function! s:OrgRefile(headline)
    let targ_list = s:GetTarget()
    if targ_list[1] !=# ''
        silent call s:DoRefile( targ_list, [a:headline] )
        redraw!
        echo "Tree(s) refiled to: " . targ_list[0] . '/' . targ_list[1]
    else
        echo 'Refile aborted.'
    endif
endfunction
func! GetMarks()
    echo b:v.heading_marks
endfunction
function! s:ChangeLevel( text_lines, change_val )
    let mylines = split( a:text_lines, "\n")
    let change_val = a:change_val
    let i = 0
    while i < len(mylines)
        if mylines[i][0] == '*'
            if change_val > 0
                let mylines[i] = repeat('*',change_val) . mylines[i]
            else
                let abs_change = -(change_val)
                let mylines[i] = mylines[i][ abs_change :] 
            endif
        endif
        let i += 1
    endwhile
    return mylines
endfunction
function! s:DoRefile(targ_list,heading_list,...)

    if a:0 == 1 
        let sort_type = a:1
    endif
    let targ_list = a:targ_list
    let heading_list = a:heading_list
    let file_lines_dict = {}
    let first_lines = {}
    let held_lines = {}
    call org#SaveLocation()


    if bufname('%') == '__Agenda__'
        if len(b:v.heading_marks_dict) >= 1
            let heading_list = keys(b:v.heading_marks_dict)
        endif
        " go through and assemble dict of files and lists of lines for each
        for item in heading_list
            exec item
            let file = s:filedict[str2nr(matchstr(getline(line('.')), '^\d\d\d'))]
            let lineno = str2nr(matchstr(getline(line('.')),'^\d\d\d\zs\d*'))
            let buffer_lineno = s:ActualBufferLine(lineno,bufnr(file))
            
            if type(get(file_lines_dict,file)) == 0
                " add first line item
                let file_lines_dict[file] = [buffer_lineno]
            else
                " add subsequent lines
                call add(file_lines_dict[file], buffer_lineno)
            endif
        endfor
    else
        let file_lines_dict = s:AssembleFileHeadingsDict()
        if empty(file_lines_dict) 
            let file_lines_dict = { expand('%:p'):heading_list}
        endif
    endif

    " now that we have dict of file(s) and linelists in file_lines_dict
    " we can go through and refile/archive 
    let archiving = (targ_list[0] == '_archive')
    if archiving 
        call s:ArchiveSubtrees(targ_list, file_lines_dict)
    else
        for afile in keys(file_lines_dict)
            call org#LocateFile(afile)
            " need to get heads and avoid duplicates in case we're in date agenda view
            let linelist = file_lines_dict[afile]
            call map( linelist, 's:OrgGetHead_l(v:val)')
            let linelist = s:UniqueList(linelist)
            " now linelist has list of heading line numbers, go through
            for aline in sort(linelist,'<SID>ReverseSort')
                call org#LocateFile(afile)
                exec aline
                let refile_stars = s:Ind(aline) - 1
                " delete subhead, but first guarantee it's not in a fold
                normal! zv
                
                let aline_text = getline(aline)
                silent execute aline . ',' . s:OrgSubtreeLastLine_l(aline) .  'delete x'

                " now go to refile point and put back in
                call s:OrgGotoHeading(targ_list[0],targ_list[1])
                let target_stars = s:Ind(line('.')) " don't subtract 1 b/c refile will be subhead
                if refile_stars != target_stars
                    let x = s:ChangeLevel( @x, target_stars - refile_stars )
                else
                    let x = split( @x, "\n")
                endif
                
                let line_buf = string(aline) . bufname('%')
                if g:org_sort_with_todo_words 
                    let first_lines[aline_text . bufname('%')] = line_buf
                else
                    let first_lines[matchstr(aline_text,b:v.todoMatch . '\{0,1}\s\{0,1}\zs.*') . bufname('%')] = line_buf
                endif
                let held_lines[line_buf] = x
                "let held_lines[x[0]] = x
                echo "Refiled " . x[0] . ' to: ' . join(targ_list,'/')
            endfor  " for lines in this file
            "now go back and clear out its heading marks
            call org#LocateFile(afile)
            let b:v.heading_marks_dict = {}
        endfor " for files in file_lines_dict
        
        " now put all the lines in . . .
        " lines below were when each subtree was appended individually
        " that's not case anymore, may need to rework and associate
        " them with append of 'held_lines' to get ordering option. . .
        for heading_line in (exists('sort_type') ? sort(keys(first_lines)) : keys(first_lines))
        "for heading_line in keys(held_lines)
            call s:OrgGotoHeading(targ_list[0],targ_list[1])
            if g:org_reverse_note_order
                let insert_line = s:OrgNextHead() - 1
                if insert_line == -1
                    let insert_line = line('$')
                endif
                exec insert_line
            else
                exec s:OrgSubtreeLastLine()
            endif
            silent call append(line('.') , held_lines[first_lines[heading_line]])
        endfor
    endif
    if !archiving
        let s:last_refile_point = targ_list
    endif

    call org#RestoreLocation()
    if bufname('%') == '__Agenda__'
        if !empty(b:v.heading_marks_dict)
            "need reverse list of str2nr(keys)
            for line in sort(map(keys(b:v.heading_marks_dict), 'str2nr(v:val)'),'s:ReverseSort')
                exec line . 'delete'
            endfor
        else   "just delete this line
            delete
        endif
    endif    
    call s:DeleteHeadingMarks()

endfunction
function! s:AssembleFileHeadingsDict()
    call org#SaveLocation()
    let file_lines_dict = {}
    let signlist = split(org#redir('sign place'),"\n")
    for line in signlist
        let ftest = matchstr(line, '^Signs for \zs.*\ze:$')
        if (ftest ># '')        "&& (getbufvar(ftest,'&filetype') == 'org')
            let file = ftest
            continue
        endif
        let markmatch = matchlist(line,'\s*line=\(\d\+\).*name=\(.*$\)')
        if !empty(markmatch) && (markmatch[2] == 'marked')
            if get(file_lines_dict, file, []) == [] 
                let file_lines_dict[file] = [ str2nr(markmatch[1]) ]
            else
                call add(file_lines_dict[file] , str2nr(markmatch[1]))
            endif
        endif
    endfor
    call org#RestoreLocation()
    return file_lines_dict
endfunction
func! s:ReverseSort(i1, i2)
   return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? -1 : 1
endfunc
function! s:ArchiveSubtrees(targ_list, file_lines_dict)
    let targ_list = a:targ_list
    let file_lines_dict = a:file_lines_dict
    let msg = ''

    for afile in keys(file_lines_dict)
        call org#LocateFile(afile)
        "need this dict for category
        call OrgMakeDictInherited()
        " need to get heads and avoid duplicates in case we're in date agenda view
        let linelist = file_lines_dict[afile]
        call map( linelist, 's:OrgGetHead_l(v:val)')
        let linelist = s:UniqueList(linelist)
        " reverse sort avoids problems with deleting as we go . . .
        for aline in sort(linelist,'<SID>ReverseSort')
            call org#LocateFile(afile)
            exec aline
            let refile_stars = s:Ind(aline) - 1
            " we will delete subhead, but first guarantee it's not in a fold
            normal! zv
            
            call s:SetProp('ARCHIVE_TIME', strftime('%Y-%m-%d %a %H:%M'))
            call s:SetProp('ARCHIVE_FILE', afile)
            call s:SetProp('ARCHIVE_OLPATH', matchstr(getline(s:OrgParentHead()),'^\*\+\s\+\zs.*$') )
            call s:SetProp('ARCHIVE_CATEGORY', b:v.org_dict.iprop(aline,'CATEGORY'))

            silent execute aline . ',' . s:OrgSubtreeLastLine_l(aline) .  'delete x'
            
            call org#LocateFile(afile . '_archive')
            if line('$') == 1
                let prefix_lines = [' #    -*- mode: org -*-',
                            \ ' vim:ft=org:','','',
                            \ 'Archived entries from file ' . afile ]
                call setline(1,prefix_lines)
            endif
            let target_stars = 1
            if refile_stars != target_stars
                let x = s:ChangeLevel( @x, target_stars - refile_stars )
            else
                let x = split( @x, "\n")
            endif
            silent call append(line('$') , x)
            let msg .= "Archived " . x[0] . " to: " . afile . "_archive\n"
        endfor  " for lines in this file
        " now write changes in this archive file and quit
        silent wq
        echo msg
        echo "  Press any key to continue..."
        call getchar()
    endfor  " for files in file list
endfunction
function! s:OrgGotoHeading(target_file, target_head, ...)
    call org#LocateFile( a:target_file )
    normal gg
    let head_list = split(a:target_head,'/')
    let head_list[0] = (head_list[0][0] ==# '*' ? head_list[0] : '\* ' . head_list[0])
    call search( head_list[0], 'c', '')
    "call search( '^\* ' . head_list[0], 'c', '')
    let heading_line = line('.')
    let last_subline = s:OrgSubtreeLastLine_l(line('.'))
    let i = 1
    while i < len(head_list)
        let stars = repeat('\*', i + 1)
        call search( '^' . stars . ' ' . head_list[i], '', last_subline)
        let i += 1
    endwhile
endfunction 
    
function! s:OrgVal(variable_str)
    " takes variable as an argument and tests whether it's defined
    " if not returns -1, otherwise return variable value
    if exists(a:variable_str) 
        execute 'let val=' . a:variable_str
    else
        let val = -1
    endif
    return val
endfunction

command! PreLoadTags :silent  call <SID>GlobalConvertTags()
command! PreWriteTags :silent call <SID>GlobalUnconvertTags(changenr())
command! PostWriteTags :silent call <SID>UndoUnconvertTags()
au BufRead *.org :PreLoadTags
au BufWrite *.org :PreWriteTags
au BufWritePost *.org :PostWriteTags

setlocal fillchars=|, 

"Section Narrow Region
let g:nrrw_rgn_vert=1
let g:nrrw_custom_options={'wrap':0}
command! -buffer Narrow :call NarrowCodeBlock(line('.'))

function! NarrowCodeBlock(line)
    if exists(":NarrowRegion") == 0
       echo "The Vim plugin NrrwRgn.vim must be installed for"
        echo "narrowing to work.  You can find a copy at:"
        echo 'http://www.vim.org/scripts/script.php?script_id=3075'
        return
    endif
    " function first tests if inside src block, and if so
    " narrows the code block.  If not, then
    " tests for headline and narrows the heading subtree
    " save buf vars to put in new org buffer if subtree narrowing
    let main_buf_vars = b:v
    execute a:line
    call search('^#+begin_src','b','')
    let start=line('.') + 1
    let language = matchstr(getline(line('.')), '^#+begin_src \zs\S\+')
    if language == 'emacs-lisp'
        let language = 'lisp'
    endif
    call search('^#+end_src','','')
    let end=line('.') - 1

    let start_width = winwidth(0)
    let &winwidth = winwidth(0) / 3
    if (start <= a:line) && (end >= a:line)
        execute start ',' . end . 'call nrrwrgn#NrrwRgn()'
        set nomodified
        if filereadable($VIMRUNTIME . '/ftplugin/' . language . '.vim')
            execute 'set ft=' . language
        endif
        if filereadable($VIMRUNTIME. '/syntax/' . language . '.vim')
            execute 'set syntax=' . language
        endif

        let &winwidth=start_width*2/3
    else
        let start = s:OrgGetHead_l(a:line)
        if start > 0 
            let end = s:OrgSubtreeLastLine_l(start)
            execute start . ',' . end . 'call nrrwrgn#NrrwRgn()'
            " then set ftype in new buffer
            set ft=org
            set nomodified
            let b:v = main_buf_vars
            let &winwidth=start_width*2/3
        else
            execute a:line
            echo "You're not in a source code block or an outline heading."
        endif
    endif
endfunction
" Org Menu Entries
amenu &Org.&View.Entire\ &Document.To\ Level\ &1<tab>,1 :set foldlevel=1<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &2<tab>,2 :set foldlevel=2<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &3<tab>,3 :set foldlevel=3<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &4<tab>,4 :set foldlevel=4<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &5<tab>,5 :set foldlevel=5<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &6<tab>,6 :set foldlevel=6<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &7<tab>,7 :set foldlevel=7<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &8<tab>,8 :set foldlevel=8<cr>
amenu &Org.&View.Entire\ &Document.To\ Level\ &9<tab>,9 :set foldlevel=9<cr>
amenu &Org.&View.Entire\ &Document.Expand\ Level\ &All :set foldlevel=99999<cr>
amenu &Org.&View.&Subtree.To\ Level\ &1<tab>,,1 :silent call OrgShowSubs(1,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &2<tab>,,2 :silent call OrgShowSubs(2,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &3<tab>,,3 :silent call OrgShowSubs(3,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &4<tab>,,4 :silent call OrgShowSubs(4,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &5<tab>,,5 :silent call OrgShowSubs(5,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &6<tab>,,6 :silent call OrgShowSubs(6,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &7<tab>,,7 :silent call OrgShowSubs(7,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &8<tab>,,8 :silent call OrgShowSubs(8,0)<cr>
amenu &Org.&View.&Subtree.To\ Level\ &9\ \ \ \ \ \ <tab>,,9 :silent call OrgShowSubs(9,0)cr>
amenu &Org.-Sep1- :
amenu &Org.&New\ Heading.New\ Head\ Same\ Level<tab><cr>(or\ <s-cr>) :call OrgNewHead('same')<cr>
amenu &Org.&New\ Heading.New\ Subhead<tab><c-cr> :call OrgNewHead('leveldown')<cr>
amenu &Org.&New\ Heading.New\ Head\ Parent\ Level<tab><s-c-cr> :call OrgNewHead('levelup')<cr>
amenu &Org.&Navigate\ Headings.&Up\ to\ Parent\ Heading<tab><a-left> :exec <SID>OrgParentHead()<cr>
amenu &Org.&Navigate\ Headings.&First\ Child\ Heading<tab><a-right> :exec <SID>OrgFirstChildHead()<cr>
amenu &Org.&Navigate\ Headings.&Last\ Child\ Heading :exec <SID>OrgLastChildHead()<cr>
amenu &Org.&Navigate\ Headings.&Next\ Heading :exec <SID>OrgNextHead()<cr>
amenu &Org.&Navigate\ Headings.&Previous\ Heading :exec <SID>OrgPrevHead()<cr>
amenu &Org.&Navigate\ Headings.Next\ &Same\ Level :exec <SID>OrgNextHeadSameLevel()<cr>
amenu &Org.&Navigate\ Headings.Previous\ Same\ Level :exec <SID>OrgPrevHeadSameLevel()<cr>
amenu &Org.&Navigate\ Headings.Next\ &Sibling<tab><a-down> :exec <SID>OrgNextSiblingHead()<cr>
amenu &Org.&Navigate\ Headings.Previous\ Sibling<tab><a-up> :exec <SID>OrgPrevSiblingHead()<cr>
amenu &Org.Edit\ &Structure.Move\ Subtree\ &Up<tab><c-a-up> :call OrgMoveLevel(line('.'),'up')<cr>
amenu &Org.Edit\ &Structure.Move\ Subtree\ &Down<tab><c-a-down> :call OrgMoveLevel(line('.'),'down')<cr>
amenu &Org.Edit\ &Structure.&Promote\ Subtree<tab><c-a-left> :call OrgMoveLevel(line('.'),'left')<cr>
amenu &Org.Edit\ &Structure.&Demote\ Subtree<tab><c-a-right> :call OrgMoveLevel(line('.'),'right')<cr>
vmenu &Org.&Editing.&Bold\ (*)<tab>,cb              "zdi*<C-R>z*<ESC>l
vmenu &Org.&Editing.&Italic\ (/)<tab>,ci            "zdi/<C-R>z/<ESC>l
vmenu &Org.&Editing.&Underline\ (_)<tab>,cu         "zdi_<C-R>z_<ESC>l
vmenu &Org.&Editing.&Code\ (=)<tab>,cc              "zdi=<C-R>z=<ESC>l
amenu &Org.&Editing.-Sep22- :
amenu &Org.&Editing.&Narrow<tab>,na :silent call NarrowCodeBlock(line('.'))<cr>
"amenu &Org.&Editing.Narrow\ &Codeblock<tab>,nc :silent call NarrowCodeBlock(line('.'))<cr>
"amenu &Org.&Editing.Narrow\ Outline\ &Subtree<tab>,ns :silent call NarrowOutline(line('.'))<cr>
amenu &Org.&Refile.&Refile\ to\ Point<tab>,rh :call OrgRefile(line('.'))<cr>
amenu &Org.&Refile.&Jump\ to\ Point<tab>,rj :call OrgJumpToRefilePoint()<cr>
amenu &Org.&Refile.&Jump\ to\ Persistent\ Point<tab>,rx :call OrgJumpToRefilePointPersistent()<cr>
amenu &Org.&Refile.&Jump\ to\ Point<tab>,rj :call OrgJumpToRefilePoint()<cr>
amenu &Org.&Refile.&Set\ Persistent\ Refile\ Point<tab>,rs :call OrgSetRefilePoint()<cr>
amenu &Org.&Refile.Refile\ to\ Persistent\ Point<tab>,rp :call OrgRefileToPermPoint(line('.'))<cr>
amenu &Org.Open\ Capture\ File :call org#OpenCaptureFile()<cr>
amenu &Org.&Mark/Gather/Sort.&Mark/Unmark\ Heading<tab>,<space> :call <SID>ToggleHeadingMark(line('.'))<cr>
amenu &Org.&Mark/Gather/Sort.&Unmark\ all<tab>,<c-space> :call <SID>DeleteHeadingMarks()<cr>
amenu &Org.&Mark/Gather/Sort.&Gather\ to\ current\ heading<tab>,gh :call <SID>GatherMarks()<cr>
amenu &Org.&Mark/Gather/Sort.&Sort\ subheads<tab>,gs :call <SID>OrgSortSubheads()<cr>
amenu &Org.-Sep2- :
amenu &Org.&Columns\ Menu :call OrgColumnsDashboard()<cr>
amenu &Org.&Hyperlinks.Add/&edit\ link<tab>,le :call EditLink()<cr>
amenu &Org.&Hyperlinks.&Follow\ link<tab>,lf :call FollowLink(OrgGetLink())<cr>
amenu &Org.&Hyperlinks.&Next\ link<tab>,ln :/]]<cr>
amenu &Org.&Hyperlinks.&Previous\ link<tab>,lp :?]]<cr>
amenu &Org.&Hyperlinks.Perma-compre&ss\ links<tab>,lc :set conceallevel=3\|set concealcursor=nc<cr>
amenu &Org.&Hyperlinks.&Autocompress\ links<tab>,la :set conceallevel=3\|set concealcursor=c<cr>
amenu &Org.&Hyperlinks.No\ auto&compress\ links<tab>,lx :set conceallevel=0<cr>
amenu &Org.&Table.$Table\ Dashboard<tab>,b :call OrgTableDashboard()<cr>
amenu &Org.&Table.E$valuate\ Table<tab>,v :call OrgTableDashboard()<cr>
amenu &Org.-Sep3- :
amenu <silent> &Org.TODO\ &Dashboard<tab>,t :call OrgTodoDashboard()<CR>
amenu <silent> &Org.TODO\ &Cycle<tab><s-cr> :call <SID>ReplaceTodo()<CR>
"amenu <silent> &Org.TODO\ Cycle\ &Backward<tab><c-s-cr> :call <SID>ReplaceTodo('todo-bkwd')<CR>
amenu &Org.Edit\ TA&GS<tab>,et  :call OrgTagsEdit()<cr>
amenu &Org.&Dates\ and\ Scheduling.Add/Edit\ &Deadline<tab>,dd :call OrgDateEdit('DEADLINE')<cr>
amenu &Org.&Dates\ and\ Scheduling.Add/Edit\ &Scheduled<tab>,ds :call OrgDateEdit('SCHEDULED')<cr>
amenu &Org.&Dates\ and\ Scheduling.Add/Edit\ &Closed<tab>,dc :call OrgDateEdit('CLOSED')<cr>
amenu &Org.&Dates\ and\ Scheduling.Add/Edit\ &Timestamp<tab>,dt :call OrgDateEdit('TIMESTAMP')<cr>
amenu &Org.&Dates\ and\ Scheduling.Add/Edit\ &GenericDate<tab>,dg :call OrgDateEdit('ATCURSOR')<cr>
amenu &Org.&Logging\ work.Clock\ in<tab>,ci :call OrgClockIn(line('.'))<cr>
amenu &Org.&Logging\ work.Clock\ out<tab>,co :call OrgClockOut()<cr>
amenu &Org.-Sep4- :
amenu &Org.Agenda\ command<tab>,ag :call OrgAgendaDashboard()<cr>
amenu &Org.Special\ &views\ current\ file :call OrgCustomSearchMenu()<cr>
amenu &Org.Agenda\ &files<tab>,af.&Edit\ Agenda\ Files :EditAgendaFiles<cr>
amenu &Org.Agenda\ &files<tab>,af.Current\ file\ to\ &top :call {sid}CurrentToAgendaFiles('top')<cr>
amenu &Org.Agenda\ &files<tab>,af.Current\ file\ to\ &bottom :call {sid}CurrentToAgendaFiles('bottom')<cr>
amenu &Org.Agenda\ &files<tab>,af.Current\ file\ &remove :call {sid}CurrentRemoveFromAgendaFiles()<cr>
amenu &Org.Agenda\ &files<tab>,af.Cycle\ to\ &next :call {sid}CycleAgendaFiles('forward')<cr>
amenu &Org.Agenda\ &files<tab>,af.Cycle\ to\ &previous :call {sid}CycleAgendaFiles('backward')<cr>
amenu &Org.Agenda\ &files<tab>,af.&Choose\ file\ to\ goto :call {sid}OrgGotoChosenFile()<cr>
amenu &Org.-Sep45- :
amenu <silent> &Org.&Do\ Emacs\ Eval<tab>,v :call OrgEval()<cr>
amenu &Org.-Sep5- :
amenu &Org.Narro&w.Outline\ &Subtree<tab>,ns :call NarrowCodeBlock(line('.'))<cr>
amenu &Org.Narro&w.&Code\ Block<tab>,nc :call NarrowCodeBlock(line('.'))<cr>
amenu &Org.-Sep6- :
amenu &Org.Open\ Capture\ Buffer :call org#CaptureBuffer()<cr>
amenu &Org.-Sep7- :
amenu &Org.Export/Publish\ w/Emacs :call OrgExportDashboard()<cr>
amenu &Org.-Sep8- :
amenu <silent> &Org.R&e-read\ Config\ Lines :call OrgProcessConfigLines()<cr>

"*********************************************************************
"*********************************************************************
"  'endif' below is special 'endif' closing the 'if !exists(org_loaded)
"  line near top of file.  Thus the main functions are loaded
"  only once for all buffers, with settngs at begin of file
"  and mappings below this line executed for each buffer 
"  having org filetype
"*********************************************************************
"*********************************************************************
endif

let g:org_loaded=1
let b:v.org_loaded=1
"*********************************************************************
"*********************************************************************
"*********************************************************************
"*********************************************************************
" convert to VimOrganizer tag format and add colon (:) before dates
PreLoadTags
" below is default todo setup, anything different can be done
" in vimrc (or in future using a config line in the org file itself)
if !exists('g:in_agenda_search') && ( &foldmethod!= 'expr') && !exists('b:v.bufloaded')
    setlocal foldmethod=expr
    "setlocal foldexpr=org#fold#level(v:lnum)
    set foldlevel=1
    let b:v.bufloaded=1
else
    setlocal foldmethod=manual
endif
"if !exists('b:v.todoitems')
"    call OrgTodoSetup('TODO | DONE')
"endif
if !exists('g:org_todo_setup')
    let g:org_todo_setup = 'TODO | DONE'
endif
if !exists('g:org_tag_setup')
    let g:org_tag_setup = '{home(h) work(w)}'
endif

call OrgProcessConfigLines()
"syntax match OL1 +^\(*\)\{1}\s.*+ 
"syntax match OL2 +^\(*\)\{2}\s.*+ 
"syntax match OL3 +^\(*\)\{3}\s.*+ contains=CONTAINED
"exec "syntax match DONETODO '" . b:v.todoDoneMatch . "' containedin=OL1,OL2,OL3,OL4,OL5,OL6" 
"exec "syntax match DONETODO '" . b:v.todoDoneMatch . "' containedin=OL1,OL2,OL3,OL4,OL5,OL6" 
"exec "syntax match NOTDONETODO '" . b:v.todoNotDoneMatch . "' containedin=OL1,OL2,OL3,OL4,OL5,OL6" 
"using matchadd b/c syntax match wouldn't show up as contained in OL group
"with start of '^'

"Menu stuff
function! MenuCycle()
    if foldclosed(line('.')) > -1
        exec foldclosed(line('.'))
    else
        exec s:OrgGetHead()
    endif
    call OrgCycle()
endfunction

nmap <silent> <buffer> <localleader>t    :call OrgTodoDashboard()<CR>
nmap <silent> <buffer> <s-CR>    :call <SID>ReplaceTodo()<CR>
nmap <silent> <buffer> <s-right>    :call <SID>ReplaceTodo()<CR>
nmap <silent> <buffer> <localleader><space>     :call <SID>ToggleHeadingMark(line('.'))<CR>
nmap <silent> <buffer> <localleader><c-space>     :call <SID>DeleteHeadingMarks()<CR>
" c-s-cr already taken
nmap <silent> <buffer> <s-left>    :call <SID>ReplaceTodo('todo-bkwd')<CR>
if !has('gui_running')
    nmap <silent> <buffer> <localleader>nt   :call <SID>ReplaceTodo()<CR>
endif
execute "source " . expand("<sfile>:p:h") . '/vimorg-main-mappings.vim'
" next line call is to get signs defined
call s:DeleteSigns()
" below is autocmd to change tw for lines that have comments on them
" I think this should go in vimrc so i runs for each buffer load
"  :autocmd CursorMoved,CursorMovedI * :if match(getline(line(".")), '^*\*\s') == 0 | :setlocal textwidth=99 | :else | :setlocal textwidth=79 | :endif 
set com=sO::\ -,mO::\ \ ,eO:::,::,sO:>\ -,mO:>\ \ ,eO:>>,:>
set fo=qtcwn
let b:v.current_syntax = "org"
setlocal foldtext=OrgFoldText()

"user can define OrgCustomSettings() in vimrc to change default settings
"in org buffers.  If syntax or highlight related, though, should 
"make changes in OrgCustomColors()
if exists('*OrgCustomSettings')
    call OrgCustomSettings()
endif


" vim:set nofoldenable: