text: from contextlib import contextmanager
  
  import os
  import re
  import pickle
  import tempfile
  
  # global settings
  # -----------------------------------------------------------------------------
  class Config(object):
      # main paper information repo file
      db_path = 'db.p'
      # intermediate processing folders
      pdf_dir = os.path.join('data', 'pdf', '10.1101')
      txt_dir = os.path.join('data', 'txt', '10.1101')
      thumbs_dir = os.path.join('static', 'thumbs')
      # intermediate pickles
      tfidf_path = 'tfidf.p'
      meta_path = 'tfidf_meta.p'
      sim_path = 'sim_dict.p'
      user_sim_path = 'user_sim.p'
      # sql database file
      db_serve_path = 'db2.p' # an enriched db.p with various preprocessing info
      database_path = 'as.db'
      serve_cache_path = 'serve_cache.p'
  
      beg_for_hosting_money = 1 # do we beg the active users randomly for money? 0 = no.
      banned_path = 'banned.txt' # for twitter users who are banned
      tmp_dir = 'tmp'
  
  # Context managers for atomic writes courtesy of
  # http://stackoverflow.com/questions/2333872/atomic-writing-to-file-with-python
  @contextmanager
  def _tempfile(*args, **kws):
      """ Context for temporary file.
  
      Will find a free temporary filename upon entering
      and will try to delete the file on leaving
  
      Parameters
      ----------
      suffix : string
          optional file suffix
      """
  
      fd, name = tempfile.mkstemp(*args, **kws)
      os.close(fd)
      try:
          yield name
      finally:
          try:
              os.remove(name)
          except OSError as e:
              if e.errno == 2:
                  pass
              else:
                  raise e
  
  
  @contextmanager
  def open_atomic(filepath, *args, **kwargs):
      """ Open temporary file object that atomically moves to destination upon
      exiting.
  
      Allows reading and writing to and from the same filename.
  
      Parameters
      ----------
      filepath : string
          the file path to be opened
      fsync : bool
          whether to force write the file to disk
      kwargs : mixed
          Any valid keyword arguments for :code:`open`
      """
      fsync = kwargs.pop('fsync', False)
  
      with _tempfile(dir=os.path.dirname(filepath)) as tmppath:
          with open(tmppath, *args, **kwargs) as f:
              yield f
              if fsync:
                  f.flush()
                  os.fsync(f.fileno())
          os.rename(tmppath, filepath)
  
  def safe_pickle_dump(obj, fname):
      with open_atomic(fname, 'wb') as f:
          pickle.dump(obj, f, -1)
  
  
  # arxiv utils
  # -----------------------------------------------------------------------------
  
  def strip_version(idstr):
      """ identity function if arxiv id has no version, otherwise strips it. """
      parts = idstr.split('v')
      return parts[0]
  
  # "1511.08198v1" is an example of a valid arxiv id that we accept
  # "10.1101/2020.01.31.928762v1"
  # "10.1101/836239v2"
  def isvalidid(pid):
     return re.match('^\d+.\d+\/\d+\.\d+\.\d+\.\d+(v\d+)?$|^\d+.\d+\/\d+(v\d+)?$', pid)
     #return re.match('^\d+\.\d+(v\d+)?$', pid)
  
  def add_pdf_url_to_record(record):
     record['links'] = 'https://www.biorxiv.org/content/'+record['doi']+'v'+record['version']+'.full.pdf'
     record['links']
     return record
  