def pull(i):
    """
    Input:  {
              (path)  - repo UOA (where to create entry)
              (type)  - type
              (url)   - URL

                or

              (data_uoa)      - repo UOA

              (clone)         - if 'yes', clone repo instead of update

              (current_repos) - if resolving dependencies on other repos, list of repos being updated (to avoid infinite recursion)

              (git)           - if 'yes', use git protocol instead of https

              (ignore_pull)   - useful just for switching to another branch

              (stable)        - take stable version (highly experimental)
              (version)       - checkout version (default - stable)
              (branch)        - git branch
              (checkout)      - git checkout
            }

    Output: {
              return       - return code =  0, if successful
                                         >  0, if error
              (error)      - error text if return > 0
            }

    """

    o=i.get('out','')

    xrecache=False

    pp=[]
    px=i.get('path','')
    t=i.get('type','')
    url=i.get('url','')

    stable=i.get('stable','')
    version=i.get('version','')
    if stable=='yes': version='stable'
    branch=i.get('branch','')
    checkout=i.get('checkout','')

    ip=i.get('ignore_pull','')

    cr=i.get('current_repos',[])

    tt='pull'
    if i.get('clone','')=='yes': tt='clone'

    if px!='': 
       pp.append({'path':px, 'type':t, 'url':url})

    uoa=i.get('data_uoa','')

    cids=i.get('cids',[])
    if len(cids)>0 and uoa=='': 
       uoa=cids[0]

    # If url is not empty and uoa is empty, get name from URL:
    if url!='' and uoa=='' and px=='':
       ix=url.rfind('/')
       if ix>0:
          uoa=url[ix+1:]
          if uoa.endswith('.git'):
             uoa=uoa[:-4]

          i['data_uoa']=uoa

    if uoa=='' and len(pp)==0 and url=='': 
       uoa='*'

    if uoa!='':
       if uoa.find('*')>=0 or uoa.find('?')>=0:
          r=ck.list_data({'module_uoa':work['self_module_uoa'], 'data_uoa':uoa})
          if r['return']>0: return r

          lst=r['lst']
          for q in lst:
              # Loading repo
              r=ck.access({'action':'load',
                           'module_uoa':work['self_module_uoa'],
                           'data_uoa':q['data_uoa'],
                           'common':'yes'})
              if r['return']>0: return r
              d=r['dict']
              t=d.get('shared','')
              duoa=r['data_uoa']

              if d.get('recache','')=='yes':
                 xrecache=True

              if t!='':
                 p=d.get('path','')
                 url=d.get('url','')
                 checkouts=d.get('checkouts',{})
                 pp.append({'path':p, 'type':t, 'url':url, 'data_uoa':duoa, 'checkouts':checkouts})
       else:
          # Loading repo
          r=ck.access({'action':'load',
                       'module_uoa':work['self_module_uoa'],
                       'data_uoa':uoa,
                       'common':'yes'})
          if r['return']>0: 
             if r['return']==16:
                # If not found, try to add from GIT

                i['action']='add'
                i['shared']='yes'
                x=i.get('quiet','')
                if x=='': x='yes'
                i['quiet']=x
                i['current_repos']=cr

                return add(i)
             else:
                return r

          d=r['dict']
          duoa=r['data_uoa']

          if d.get('recache','')=='yes':
             xrecache=True

          p=d['path']
          t=d.get('shared','')
          url=d.get('url','')
          checkouts=d.get('checkouts',{})

          pp.append({'path':p, 'type':t, 'url':url, 'data_uoa':duoa, 'checkouts':checkouts})

    # Updating ...
    for q in pp:
        p=q.get('path','')
        duoa=q.get('data_uoa','')
        t=q.get('type','')
        url=q.get('url','')

        # Semi hack (useful for Anton)
        if i.get('git','')=='yes':
           url=url.replace('https://','git@')

           j=url.find('/')
           if j>0:
              url=url[:j]+':'+url[j+1:]

           url+='.git'

        if o=='con' and tt!='clone':
           ck.out('******************************************************************')
           ck.out('Updating repo "'+duoa+'" ...')
           ck.out('')
           ck.out('  Local path: '+p)
           ck.out('  URL:        '+url)

        if t=='git':
           # Check if git is installed
           rq=ck.gen_tmp_file({})
           if rq['return']>0: return rq
           xfn=rq['file_name']

           os.system('git --version > '+xfn)

           rq=ck.load_text_file({'text_file':xfn, 
                                 'delete_after_read':'yes'})
           xs=''
           if rq['return']==0:
              xs=rq['string'].strip()

           if xs.find(' version ')<0:
              return{'return':1, 'error':'git command line client is not found - please, install it or download repo as zip'}

           # Continue
           try:
              px=os.getcwd()
           except OSError:
              from os.path import expanduser
              px=expanduser("~")

           if not os.path.isdir(p):
              os.makedirs(p)

           if o=='con':
              ck.out('')
              ck.out('  cd '+p)
           os.chdir(p)

           r=0
           if ip!='yes':
              s=ck.cfg['repo_types'][t][tt].replace('$#url#$', url).replace('$#path#$', p)

              if o=='con':
                 ck.out('  '+s)
                 ck.out('')

              r=os.system(s)

              if o=='con': 
                 ck.out('')

           os.chdir(px) # Restore path

           if r>0:
              if o=='con':
                 ck.out('')
                 ck.out(' WARNING: repository update likely failed OR IN A DIFFERENT BRANCH/CHECKOUT (git exit code: '+str(r)+')')
                 ck.out('')
                 rx=ck.inp({'text': 'Would you like to continue (Y/n)?: '})
                 x=rx['string'].lower()
                 if x=='n' or x=='no':
                    return {'return':1, 'error':'repository update likely failed - exit code '+str(r)}
              else:
                 return {'return':1, 'error':'repository update likely failed - exit code '+str(r)}
        else:
           if o=='con':
              ck.out('CK warning: this repository is not shared!')

        # Check deps
        if tt!='clone': # clone is done in add ...
           if o=='con':
              ck.out('  ========================================')
              ck.out('  Checking dependencies on other repos ...')
              ck.out('')

           r=deps({'path':p,
                   'current_path':cr,
                   'how':'pull',
                   'version':version,
                   'branch':branch,
                   'checkout':checkout,
                   'out':o})
           if r['return']>0: return r

    # Re-caching ...
    if xrecache:
       if o=='con':
          ck.out('  ==============================================')
          ck.out('  At least one repository requires recaching ...')
          ck.out('')

       r=recache({'out':o})
       if r['return']>0: return r

    return {'return':0}
Input:  {
              (path)  - repo UOA (where to create entry)
              (type)  - type
              (url)   - URL

                or

              (data_uoa)      - repo UOA

              (clone)         - if 'yes', clone repo instead of update

              (current_repos) - if resolving dependencies on other repos, list of repos being updated (to avoid infinite recursion)

              (git)           - if 'yes', use git protocol instead of https

              (ignore_pull)   - useful just for switching to another branch

              (stable)        - take stable version (highly experimental)
              (version)       - checkout version (default - stable)
              (branch)        - git branch
              (checkout)      - git checkout
            }

    Output: {
              return       - return code =  0, if successful
                                         >  0, if error
              (error)      - error text if return > 0
            }