-ķ
Óže?c       sĒ     d  Z  n p d k Z q d k Z r d k Z s d k l Z l Z t d k l Z v d k	 l
 Z
 l Z l Z x d k Z y d k l Z { d Z | d Z ~ d d	 Z  d
 f  d     YZ d S(   s7  Implement a client cache

The cache is managed as two files.

The cache can be persistent (meaning it is survives a process restart)
or temporary.  It is persistent if the client argument is not None.

Persistent cache files live in the var directory and are named
'c<storage>-<client>-<digit>.zec' where <storage> is the storage
argument (default '1'), <client> is the client argument, and <digit> is
0 or 1.  Temporary cache files are unnamed files in the standard
temporary directory as determined by the tempfile module.

Each cache file has a 12-byte header followed by a sequence of
records.  The header format is as follows:

  offset in header: name -- description

  0: magic -- 4-byte magic number, identifying this as a ZEO cache file

  4: lasttid -- 8-byte last transaction id

Each record has the following form:

  offset in record: name -- description

  0: oidlen -- 2-byte unsigned object id length

  2: reserved (6 bytes)

  8: status -- 1-byte status 'v': valid, 'n': non-version valid, 'i': invalid
               ('n' means only the non-version data in the record is valid)

  9: tlen -- 4-byte (unsigned) record length

  13: vlen -- 2-byte (unsigned) version length

  15: dlen -- 4-byte length of non-version data

  19: serial -- 8-byte non-version serial (timestamp)

  27: oid -- object id

  27+oidlen: data -- non-version data

  27+oidlen+dlen: version -- Version string (if vlen > 0)

  27+oidlen+dlen+vlen: vdlen -- 4-byte length of version data (if vlen > 0)

  31+oidlen+dlen+vlen: vdata -- version data (if vlen > 0)

  31+oidlen+dlen+vlen+vdlen: vserial -- 8-byte version serial (timestamp)
                                 (if vlen > 0)

  27+oidlen+dlen (if vlen == 0) **or**
  39+oidlen+dlen+vlen+vdlen: tlen -- 4-byte (unsigned) record length (for
                                     redundancy and backward traversal)

  31+oidlen+dlen (if vlen == 0) **or**
  43+oidlen+dlen+vlen+vdlen: -- total record length (equal to tlen)

There is a cache size limit.

The cache is managed as follows:

  - Data are written to file 0 until file 0 exceeds limit/2 in size.

  - Data are written to file 1 until file 1 exceeds limit/2 in size.

  - File 0 is truncated to size 0 (or deleted and recreated).

  - Data are written to file 0 until file 0 exceeds limit/2 in size.

  - File 1 is truncated to size 0 (or deleted and recreated).

  - Data are written to file 1 until file 1 exceeds limit/2 in size.

and so on.

On startup, index information is read from file 0 and file 1.
Current serial numbers are sent to the server for verification.
If any serial numbers are not valid, then the server will send back
invalidation messages and the cache entries will be invalidated.

When a cache record is invalidated, the data length is overwritten
with '    '.

If var is not writable, then temporary files are used for
file 0 and file 1.
N(   s   packs   unpack(   s   allocate_lock(   s   oid_reprs   u64s   z64(   s   ICaches   ZEC2i   i   i   s   ClientCachec      sG   t  Z  e Z  d d e e e d  Z Ź d   Z ß d   Z é d   Z	 ų d   Z
 d   Z d	   Z d
   Z $d   Z Id   Z e e e e d  Z ×d   Z żd   Z )d   Z Pd   Z [d   Z d   Z d d d d e i e d  Z §d   Z ÷d   Z üe i d  Z RS(   Ns   1i   c    sN    | |  _  | d |  _  | |  _  t |  _  t	   }  | i |  _  | i |  _  | t j	 oł | t j o  t i   } n  t i i | d | | f  }  | d | d g |  _ }  t t g |  _ }  d |  _  t t g }   x£ d d f D  ] }	 ” t i i | |	  or ¢ t | |	 d  } £ | i  d  t! j o § | i  d  | |	 <n © | |	 t j o Ŗ | | |	 <n n qW­ | d | d j o ® d } n Æ | d | d j o ° d } no ² | d t j oD “ t | d d  | d <µ | d i# t! d	 t$ t% t!   n ¶ d } · t | d <nh ¹ t& i' d
 d  t g |  _ } » t t g |  _ } ¼ | d i# t! d	 t$ t% t!   ½ d } ¾ | |  _ Ą |  i o Į d t( |  i  }
 n
 Ć d }
 Ä |  i* d |  i+ i, | | | | | |
 f  Č |  i-   d  S(   Ni   s   c%s-%s-%%s.zeci    i   s   r+bi   i   s   w+bs    s   suffixs   .zecs   ; last txn=%xs    s&   %s: storage=%r, size=%r; file[%r]=%r%s(.   s   storages   selfs   _storages   sizes   _limits   clients   _clients   Nones   _ltids   allocate_locks   Ls   acquires   _acquires   releases   _releases   vars   oss   getcwds   paths   joins   fmts   _ps   ps   _fs   fs   _currents   z64s   ss   is   existss   opens   fis   reads   magics   currents   writes
   headersizes   lens   tempfiles   TemporaryFiles   u64s   tss   logs	   __class__s   __name__s   _setup_trace(   s   selfs   storages   sizes   clients   vars   ps   Ls   fis   fs   is   tss   currents   ss   fmt(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   __init__ sT   " 	*	"&		0c    sĮ   Ź Š |  i   Ń z Ņ h  |  _ } Ó | i |  _ Ō h  } Õ |  i } Ö |  i	 } × | | t j	 o Ų |  i | |  n Ł |  i | |  |  _ Ū | i   SWd  Ü Ż |  i   Xd  S(   N(   s   selfs   _acquires   _indexs   indexs   gets   _gets   serials   _fs   fs   _currents   currents   Nones
   read_indexs   _poss   itemss   _release(   s   selfs   currents   indexs   fs   serial(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   openŹ s   	c    se   ß ą xX |  i Dą ]J } į | t j	 o4 ä y å | i   Wn ę t j
 o
 ē n Xn q Wd  S(   N(   s   selfs   _fs   fs   Nones   closes   OSError(   s   selfs   f(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   closeß s    	c    s`   é ī ļ |  i t j o š |  i Sn6 ņ |  i   ó z ō |  i   SWd õ ö |  i   Xd S(   s¶   Get the last transaction id stored by setLastTid().

        If the cache is persistent, it is read from the current
        cache file; otherwise it's an instance variable.
        N(   s   selfs   _clients   Nones   _ltids   _acquires   _getLastTids   _release(   s   self(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys
   getLastTidé s   c    sq   ų ł |  i |  i } ś | i d  ū | i d  } ü t |  d j  p
 | t j o ż t	 Sn ’ | Sd  S(   Ni   i   (
   s   selfs   _fs   _currents   fs   seeks   reads   tids   lens   z64s   None(   s   selfs   fs   tid(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _getLastTidų s   #c    s   |  i t j o- | t j o 	t } n 
| |  _ n9 |  i   z |  i |  Wd |  i   Xd S(   s¢   Store the last transaction id.

        If the cache is persistent, it is written to the current
        cache file; otherwise it's an instance variable.
        N(	   s   selfs   _clients   Nones   tids   z64s   _ltids   _acquires   _setLastTids   _release(   s   selfs   tid(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys
   setLastTids   c    s   | t j o t } n4 t |  } t o t |  d j p t  |  i |  i	 } | i d  | i |  d  S(   Ni   i   (   s   tids   Nones   z64s   strs	   __debug__s   lens   AssertionErrors   selfs   _fs   _currents   fs   seeks   write(   s   selfs   tids   f(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _setLastTids   $c    sF    !x6 |  i   D!]% \ } \ } } "| | | |  q Wd S(   sf   Call the verifyFunc on every object in the cache.

        verifyFunc(oid, serialno, version)
        N(   s   selfs   opens   oids   ss   vss
   verifyFunc(   s   selfs
   verifyFuncs   oids   vss   s(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   verifys    c 	   s(  $%|  i   &zż'|  i | t  } (| t j o! )|  i d | |  *t Sn +|  i | d j  } ,t
 |  } -| i |  .| i d  } /t |  d j oA 0|  i d t |  | | d j  f  3|  i | =4t Sn 5t d | d   d } 6| i |  } 7| | j oJ 8|  i d t |  t |  | | d j  f  ;|  i | =<t Sn =| i | d  >| o | d	 d
 !d j o* ?|  i d | |  A| i d  n4 C|  i d | |  D|  i | =E| i d  Wd  FG|  i   Xd  S(   Ni   i    i   sC   invalidate: short record for oid %s at position %d in cache file %ds   >Hi   sM   invalidate: oid mismatch: expected %s read %s at position %d in cache file %di   i   i   s       i   s   ni   s   i(   s   selfs   _acquires   _gets   oids   Nones   ps   _traces   versions   _fs   fs   abss   aps   seeks   reads   hs   lens   logs   oid_reprs   _indexs   unpacks   oidlens   rec_oids   writes   _release(	   s   selfs   oids   versions   ps   oidlens   hs   fs   aps   rec_oid(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys
   invalidate$s:   )2c    s  IJ|  i   KzäL|  i | t  } M| t j o! N|  i d | |  Ot Sn P|  i | d j  } Qt
 |  } R| i }
 S| i } T|
 |  U| d  } Vt d | d   d } W| |  } Xt |  d j o | d d j o
 | | j o& Yt d | d	 d
 ! \ } } }	 n
 [d } \| d j p( | d j  p |	 d j  p | |	 | j oA ]|  i d t |  | | d j  f  `|  i | =at Sn c| d d j oh d| o! e|  i d | |  ft Sn g|	 o. i|  i d | |  j|  i | =kt Sn n m| p | oį n|	 o¶ o| |	  } p|  i d | | | d
 |	  q| d j  |  i j oY t| o u| | d  } n
 wt } x|  i | | | |	 | | y| | | 	 n z| | d
 f Sn ||  i d | |  }t Sn |	 o |
 |	 d  n | | d  } | d  } | | j oĢ |	 o” |
 | d |  | |	  } |  i d | | | d
 |	  | d j  |  i j o/ |  i | | | |	 | | | | | 	 n | | d
 f Sn |  i d | |  t Sn t d | d  d } | |  } | d  } |  i d | | | |  | d j  |  i j o5 |  i | | | |	 | | | t | | |  n | | f SWd  |  i!   Xd  S(   Ni    i    i   s   >Hi   i   s   nvs   >iHii	   i   i’’’’s;   load: bad record for oid %s at position %d in cache file %ds   ni"   i$   i*   i   i&   i   iü’’’i,   i(   s   >ii.   ("   s   selfs   _acquires   _gets   oids   Nones   ps   _traces   versions   _fs   fs   abss   aps   seeks   reads   hs   unpacks   oidlens   rec_oids   lens   tlens   vlens   dlens   logs   oid_reprs   _indexs   datas   _currents   vheaders   _copytocurrents   vs   vdlens   vdatas   vserials   _release(   s   selfs   oids   versions   oidlens   vlens   reads   aps   vdatas   datas   dlens   seeks   fs   hs   ps   rec_oids   tlens   vdlens   vs   vheaders   vserial(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   loadIs   4&	;)

 
	

 c    só  ¢£|  i | |  i j o ¤d Sn „t o# t |  d j p t t |   ¦| d d j oO ©d | | } Ŗd } «t }	 ®| d  t d | | |  | d	 } n# °t o | d d
 j p t  ±|  i |  i } ²| t j oO ³| i | d |  “| i |  } µt |  | j o ¶d Sn n ·| | | g } ø| o4¹t o |	 t j	 p t  ŗ| i |	  »t o  |
 t j | t j j p t  ¼|
 t j oØ ½t d |	 d  d } ¾| i | d | | | d  æ| i |  }
 Ąt |
  | j o Įd Sn Ā| i d  } Ćt |  d j o Äd Sn n Å| i |
  Ę| i |  nK Čt o@ t |	 j o |
 j o
 | j n p t | |	 |
 | f  Ź| i | d d ! Ė|  i |  i } Ģ| i |  i  Ķ| i |  Īt o! | i   |  i | j p t  Ļ|  i o Š|  i |  i | <n Ņ|  i |  i | <Ó|  i | 7_ Ō|  i  d | | o |	 d  p d Õ| o | p | d	 |  d S(   s  Copy a cache hit from the non-current file to the current file.

        Arguments are the file position in the non-current file,
        record length, data length, version string length, header, and
        optionally parts of the record that have already been read.
        Ni   i   s   ni   i    i	   s   >IHIių’’’s   vs   >Iiü’’’i   i   ij   s    (!   s   selfs   _poss   tlens   _limits	   __debug__s   lens   headers   AssertionErrors   oidlens   dlens   vlens   Nones   vheaders   packs   _fs   _currents   fs   datas   seeks   poss   reads   oids   ls   appends   vdatas   vserials   unpacks   vdlens   gs
   writeliness   tells   _indexs   _trace(   s   selfs   poss   oidlens   tlens   dlens   vlens   headers   oids   datas   vheaders   vdatas   vserials   fs   ls   gs   vdlen(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _copytocurrentsX   -		,"
*$J+$c    s  ×Ų|  i   Łz\Ś|  i d | | | t |   Ū| oŻ|  i | t	  } Ž| t	 j o# ß|  i | d d | | |  Sn ą|  i | d j  } įt |  }	 ā| i }
 ć| i } ä|
 |	  å| d  } ęt d | d   d } ē| |  } čt |  d j o | d d j o
 | | j o& ét d	 | d
 d ! \ } } } n  ė|  i | d d | | |  Sķ| d j p( | d j  p | d j p | | | j o# ī|  i | d d | | |  Sn š| o  ń| |  } ņ| d } n  ō|  i | d d | | |  Sö|  i | | | | | |  n  ł|  i | | | d t	 t	  Wd  śū|  i   Xd  S(   Ni:   s    i    i   s   >Hi   i   s   nvs   >iHii	   i   (   s   selfs   _acquires   _traces   oids   versions   serials   lens   datas   _gets   Nones   ps   _stores   _fs   fs   abss   aps   seeks   reads   hs   unpacks   oidlens   rec_oids   tlens   vlens   dlens   nvdatas   nvserials   _release(   s   selfs   oids   serials   versions   datas   nvserials   oidlens   vlens   reads   aps   seeks   dlens   fs   hs   ps   nvdatas   rec_oids   tlen(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   update×s8   "
#4&;#
##c    sj  ż|  i   z?|  i | t  } | t j o |  i d |  t Sn |  i | d j  } 	t	 |  }	 
| i } | i } | |	  | d  } t d | d   d } | |  }
 t |  d j o | d d j o
 |
 | j o& t d | d	 d
 ! \ } } } n
 d } | d j p( | d j  p | d j  p | | | j oA |  i d t |  |	 | d j  f  |  i | =t Sn | d d j o |  i d |  t Sn | o  |  i d |  !d Sn "| | d  #| |  } $|  i d | |  %| SWd  &'|  i   Xd  S(   Ni@   i    i   s   >Hi   i   s   nvs   >iHii	   i   i’’’’sH   modifiedInVersion: bad record for oid %s at position %d in cache file %ds   niJ   iL   s    i   iN   (   s   selfs   _acquires   _gets   oids   Nones   ps   _traces   _fs   fs   abss   aps   seeks   reads   hs   unpacks   oidlens   rec_oids   lens   tlens   vlens   dlens   logs   oid_reprs   _indexs   versions   _release(   s   selfs   oids   oidlens   vlens   dlens   fs   reads   hs   ps   aps   rec_oids   versions   seeks   tlen(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   modifiedInVersionżsB   4&	;)c    s÷  ),|  i   -zĢ.|  i | |  i j o®/|  i   } 0|  i } 1| |  _ 2|  i	 d  3|  i
 d |  5|  i } 6x? | i   D6]. } 7| | d j  | j o 8| | =n q W9|  i | t j	 o =|  i | t j	 oF >|  i | i   ?y @t i |  i |  Wn ABn Xn Ct |  i | d  |  i | <n Ft i d d  |  i | <Gt } H| o I| | 7} n J|  i | i | d t t |   Lt |  _ n Wd  MN|  i   Xd  S(   Nip   s'   flipping cache files.  new current = %di    s   w+bs   suffixs   .zecs    (   s   selfs   _acquires   _poss   sizes   _limits   _getLastTids   ltids   _currents   currents   _traces   logs   _indexs   indexs   keyss   oids   _ps   Nones   _fs   closes   oss   removes   opens   tempfiles   TemporaryFiles   magics   headers   writes
   headersizes   lens   _release(   s   selfs   sizes   indexs   ltids   oids   currents   header(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys	   checkSize)s:    	$	
)c    s    PQ|  i   R| o& S|  i d | | | t |   n# U|  i d | | | t |   Vz# W|  i
 | | | | | |  Wd  XY|  i   Xd  S(   NiZ   i\   (   s   selfs   _acquires   ss   _traces   oids   versions   lens   ps   svs   pvs   _stores   _release(   s   selfs   oids   ps   ss   versions   pvs   sv(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   storePs   
&"#c    s-  [\| o ]d } ^t } n _d t |  t |  }
 `| o4 a|
 t |  d t |  }
 bt |  } n
 dd } ft	 d |
  } ht o t |  d d j  p t  it o | d d j  p t  jt o |
 d d	 j  p t  kt	 d
 t |   d | t	 d | t |   | | g }	 m| o n|	 i |  n o| o/ p|	 i | t	 d t |   | | g  n s|	 i |  t|  i |  i } u| i |  i  v| i |	  x|  i o y|  i |  i | <n {|  i |  i | <}|  i |
 7_ d  S(   Ns    i   i   i    s   >Ii   i   l    i    s   >H6xs   vs   >HI(   s   ss   ps   z64s   lens   oids   tlens   versions   pvs   vlens   packs   stlens	   __debug__s   AssertionErrors   ls   appends   extends   svs   selfs   _fs   _currents   fs   seeks   _poss
   writeliness   _index(   s   selfs   oids   ps   ss   versions   pvs   svs   fs   vlens   ls   tlens   stlen(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _store[s2   	
!	(""<

/c    sś   t  |  _ t i i d  } | o | d |  i } y) t | d  |  _ |  i	 d  Wn> t
 j
 o/ } t  |  _ |  i d | | f  n X|  i d |  n |  i t  j o d   } | |  _	 n d  S(   Ns   ZEO_CACHE_TRACEs   -s   abi    s   cannot write tracefile %s (%s)s   opened tracefile %sc     s
   d  S(   N(    (   s   args(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   notraces   (   s   Nones   selfs
   _tracefiles   oss   environs   gets   tfns   _storages   opens   _traces   IOErrors   msgs   logs   notrace(   s   selfs   notraces   tfns   msg(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _setup_traces   
s    i    c    ss   | o | d O} n  |  i i | d ¢|   £| d d @| B|  i B¤t	 |  „|  |  d  S(   Ni   s   >iiH8si’   i ’’(   s   versions   codes   selfs
   _tracefiles   writes   struct_packs	   time_times   dlens   _currents   lens   oids   serial(   s   selfs   codes   oids   versions   serials   dlens	   time_times   struct_pack(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   _traces   	
	c    sZ  §Ø|  i } ©|  i | } Ŗ| i } «| i }	 ¬t } ­d } Æx”Æd o°| i |  ±|	 d  }
 ²t |
  d j o, “|
 o µ|  i d | |  n ¶Pn ø|
 d d j o& ¹t d |
 d d	 ! \ } } } n
 »d
 } ¼| d j p( | d j  p | d j  p | | | j o ½|  i d | |  ¾Pn Ąt d |
 d   d } Į|	 |  } Ć|
 d d j o | o	Ä| | | d  Å|	 d  } Ęt |  d j o Ē|  i d | |  ČPn Ét d |  d } Ź| | | d | | j o Ė|  i d | |  ĢPn Ķ| | d  Ī|	 d  } Ļ|	 d  |
 d d !j o Š|  i d | |  ŃPn n¬ Ó|
 d d j o
 | d j o Ō| | d | j o Õ|  i d | |  n Ö| | d  ×|	 d  |
 d d !j o Ų|  i d | |  ŁPn n Śt } Ü|
 d d j oD Ż| o Ž| | | <n ą| | | <į|
 d | f | | <n, ć| i |  o å| | =ę| | =n č| | } é| d 7} qO Wė| i |  ģy ķ| i   Wn īļn Xń| o! ņ|  i d | | | f  n õ| Sd  S(   Ni    i   i   s   truncated headeri   s   vnis   >iHii	   i   i’’’’s   invalid header datas   >Hi   s   vi   s   truncated records   >ii+   s   inconsistent lengthsi   s   inconsistent tlens   vni   s   inconsistent nv lengthss   inconsistent nv tlenių’’’s5   read_index: cache file %d has %d records and %d bytes(   s   selfs   _indexs   indexs   _fs	   fileindexs   fs   seeks   reads
   headersizes   poss   counts   hs   lens   rilogs   unpacks   tlens   vlens   dlens   oidlens   oids   vdlens   vss   Nones   serials   has_keys   truncates   log(   s   selfs   serials	   fileindexs   counts   indexs   oidlens   vlens   oids   fs   reads   hs   poss   vss   tlens   vdlens   seeks   dlen(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys
   read_index§s~   		 

&	; !	


!c    s$   ÷ł|  i d | | | f  d  S(   Ns.   read_index: %s at position %d in cache file %d(   s   selfs   logs   msgs   poss	   fileindex(   s   selfs   msgs   poss	   fileindex(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   rilog÷s   c    s+   ü’t  i d |  i |  i | |  d  S(   Ns   ZEC:%s(   s   zLOGs   LOGs   selfs   _ps   _currents   levels   msg(   s   selfs   msgs   level(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   logüs   (   s   __name__s
   __module__s   ICaches   __implements__s   MBs   Nones   __init__s   opens   closes
   getLastTids   _getLastTids
   setLastTids   _setLastTids   verifys
   invalidates   loads   _copytocurrents   updates   modifiedInVersions	   checkSizes   stores   _stores   _setup_traces   times   packs   _traces
   read_indexs   rilogs   zLOGs   INFOs   log(    (    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   ClientCache s,   		F
	
%R<&,'$!P(   s   __doc__s   oss   times   tempfiles   structs   packs   unpacks   threads   allocate_locks
   ZODB.utilss   oid_reprs   u64s   z64s   zLOGs
   ZEO.ICaches   ICaches   magics
   headersizes   MBs   ClientCache(   s   ICaches   magics   MBs   allocate_locks   unpacks   u64s   tempfiles   times   zLOGs   oid_reprs   packs   oss   ClientCaches
   headersizes   z64(    (    s7   /usr/pkg/lib/python2.2/site-packages/ZEO/ClientCache.pys   ?n s   		