github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/ppapi/syscall_fd_nacl.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ppapi
     6  
     7  import (
     8  	"encoding/base64"
     9  	"fmt"
    10  	"math/rand"
    11  	"runtime"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  	"syscall"
    16  )
    17  
    18  // files is the table indexed by file descriptor.
    19  var files struct {
    20  	sync.RWMutex
    21  	tab []*file
    22  }
    23  
    24  // A file is an open file, something with a file descriptor.
    25  // A particular *file may appear in the files table multiple times, due to use of Dup or Dup2.
    26  type file struct {
    27  	fdref int      // used in files.tab
    28  	impl  fileImpl // underlying implementation
    29  }
    30  
    31  // A fileImpl is the implementation of something that can be a file.
    32  type fileImpl interface {
    33  	// Standard operations.
    34  	// These can be called concurrently from multiple goroutines.
    35  	stat(*syscall.Stat_t) error
    36  	read([]byte) (int, error)
    37  	write([]byte) (int, error)
    38  	seek(int64, int) (int64, error)
    39  	pread([]byte, int64) (int, error)
    40  	pwrite([]byte, int64) (int, error)
    41  
    42  	// Close is called when the last reference to a *file is removed
    43  	// from the file descriptor table. It may be called concurrently
    44  	// with active operations such as blocked read or write calls.
    45  	close() error
    46  }
    47  
    48  // newFD adds impl to the file descriptor table,
    49  // returning the new file descriptor.
    50  // Like Unix, it uses the lowest available descriptor.
    51  func newFD(impl fileImpl) int {
    52  	files.Lock()
    53  	defer files.Unlock()
    54  	f := &file{impl: impl, fdref: 1}
    55  	for fd, oldf := range files.tab {
    56  		// Look if there is a space for a new file
    57  		if oldf == nil {
    58  			files.tab[fd] = f
    59  			return fd
    60  		}
    61  	}
    62  	fd := len(files.tab)
    63  	files.tab = append(files.tab, f)
    64  	return fd
    65  }
    66  
    67  var stdin = &defaultFileImpl{}
    68  var stdout = &consoleLogFile{logLevel: PP_LOGLEVEL_LOG}
    69  var stderr = &consoleLogFile{logLevel: PP_LOGLEVEL_WARNING}
    70  
    71  // Install Native Client stdin, stdout, stderr.
    72  func init_fds() {
    73  	if len(files.tab) != 0 {
    74  		return
    75  	}
    76  	newFD(stdin)
    77  	newFD(stdout)
    78  	newFD(stderr)
    79  }
    80  
    81  func fdToFileRep(fd int) (*file, error) {
    82  	files.Lock()
    83  	defer files.Unlock()
    84  	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
    85  		return nil, syscall.EBADF
    86  	}
    87  	return files.tab[fd], nil
    88  }
    89  
    90  // fdToFile retrieves the *file corresponding to a file descriptor.
    91  func fdToFile(fd int) (fileImpl, error) {
    92  	file, err := fdToFileRep(fd)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return file.impl, nil
    97  }
    98  
    99  var symLinks map[string]string
   100  var tmpFiles map[string]*bytesBufFileData
   101  
   102  func initSymlinks() {
   103  	if symLinks == nil {
   104  		symLinks = map[string]string{}
   105  	}
   106  }
   107  
   108  func initTmpFiles() {
   109  	if tmpFiles == nil {
   110  		tmpFiles = map[string]*bytesBufFileData{}
   111  	}
   112  }
   113  
   114  func resolveSymlink(path string) string {
   115  	initSymlinks()
   116  	seen := map[string]bool{}
   117  	for {
   118  		if _, ok := seen[path]; ok {
   119  			panic(fmt.Sprintf("Infinite loop in symlink %s %v", path, seen))
   120  		}
   121  		seen[path] = true
   122  		if nextPath, ok := symLinks[path]; ok {
   123  			path = nextPath
   124  		} else {
   125  			break
   126  		}
   127  	}
   128  	return path
   129  }
   130  
   131  func (PPAPISyscallImpl) Open(path string, mode int, perm uint32) (fd int, err error) {
   132  	path = resolveSymlink(path)
   133  	//fmt.Printf("Opening: \"%s\" (resolved to \"%s\") %d %d\n", origPath, path, mode, perm)
   134  	// TODO(bprosnitz) Handle modes better
   135  	initEnvVars()
   136  	if strings.HasPrefix(path, envVars["TMPDIR"]) {
   137  		initTmpFiles()
   138  		data, ok := tmpFiles[path]
   139  		if !ok {
   140  			data = newByteBufFileData(path)
   141  			tmpFiles[path] = data
   142  		}
   143  		bbFile := &bytesBufFile{
   144  			dat:   data,
   145  			index: 0,
   146  		}
   147  		return newFD(bbFile), nil
   148  	}
   149  	if strings.HasPrefix(path, "/usr/local/google/home") {
   150  		return 0, fmt.Errorf("File not found: %s", path)
   151  	}
   152  	switch path {
   153  	case "/etc/localtime":
   154  		data, err := base64.StdEncoding.DecodeString(base64_localtime)
   155  		if err != nil {
   156  			panic(fmt.Sprintf("Error decoding base64: %v", err))
   157  		}
   158  		return newFD(&bytesReadFile{data, 0, sync.Mutex{}}), nil
   159  	case "/dev/urandom":
   160  		return newFD(&randomImpl{}), nil
   161  	default:
   162  		panic(fmt.Sprintf("Open() not implemented. Path: %s", path))
   163  	}
   164  }
   165  
   166  func (PPAPISyscallImpl) Close(fd int) error {
   167  	files.Lock()
   168  	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
   169  		files.Unlock()
   170  		return syscall.EBADF
   171  	}
   172  	f := files.tab[fd]
   173  	files.tab[fd] = nil
   174  	f.fdref--
   175  	fdref := f.fdref
   176  	if fdref > 0 {
   177  		files.Unlock()
   178  		panic("Shouldn't get here until Dup/Dup2 is implemented")
   179  		return nil
   180  	}
   181  	files.Unlock()
   182  	return f.impl.close()
   183  }
   184  
   185  func (PPAPISyscallImpl) CloseOnExec(fd int) {
   186  	// nothing to do - no exec
   187  }
   188  
   189  func (PPAPISyscallImpl) Dup(fd int) (int, error) {
   190  	panic("Dup not yet uncommented")
   191  	/*
   192  	   files.Lock()
   193  	   defer files.Unlock()
   194  	   if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
   195  	       return -1, EBADF
   196  	   }
   197  	   f := files.tab[fd]
   198  	   f.fdref++
   199  	   for newfd, oldf := range files.tab {
   200  	       if oldf == nil {
   201  	           files.tab[newfd] = f
   202  	           return newfd, nil
   203  	       }
   204  	   }
   205  	   newfd := len(files.tab)
   206  	   files.tab = append(files.tab, f)
   207  	   return newfd, nil*/
   208  }
   209  
   210  func (PPAPISyscallImpl) Dup2(fd, newfd int) error {
   211  	panic("Dup2 not yet uncommented")
   212  	/*
   213  	   files.Lock()
   214  	   defer files.Unlock()
   215  	   if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
   216  	       files.Unlock()
   217  	       return EBADF
   218  	   }
   219  	   f := files.tab[fd]
   220  	   f.fdref++
   221  	   for cap(files.tab) <= newfd {
   222  	       files.tab = append(files.tab[:cap(files.tab)], nil)
   223  	   }
   224  	   oldf := files.tab[newfd]
   225  	   var oldfdref int
   226  	   if oldf != nil {
   227  	       oldf.fdref--
   228  	       oldfdref = oldf.fdref
   229  	   }
   230  	   files.tab[newfd] = f
   231  	   files.Unlock()
   232  	   if oldf != nil {
   233  	       if oldfdref == 0 {
   234  	           oldf.impl.close()
   235  	       }
   236  	   }
   237  	   return nil*/
   238  }
   239  
   240  var dirMade map[string]bool
   241  
   242  func (PPAPISyscallImpl) Stat(path string, stat *syscall.Stat_t) (err error) {
   243  	switch path {
   244  	case "/tmp/revocation_dir/caveat_dir", "/tmp/revocation_dir", "/tmp/revocation_dir/revocation_dir":
   245  		if dirMade != nil {
   246  			if _, ok := dirMade[path]; ok {
   247  				stat.Mode = syscall.S_IFDIR
   248  				return nil
   249  			}
   250  		}
   251  		return fmt.Errorf("path %s does not exist", path)
   252  	case "/tmp":
   253  		stat.Mode = syscall.S_IFDIR
   254  		return nil
   255  	default:
   256  		panic(fmt.Sprintf("Stat() not implemented for %s", path))
   257  	}
   258  }
   259  
   260  func (PPAPISyscallImpl) Mkdir(path string, mode uint32) (err error) {
   261  	switch path {
   262  	case "/tmp/revocation_dir/caveat_dir", "/tmp/revocation_dir/revocation_dir", "/tmp/revocation_dir":
   263  		if dirMade == nil {
   264  			dirMade = map[string]bool{}
   265  		}
   266  		dirMade[path] = true
   267  		return nil
   268  
   269  	default:
   270  		panic(fmt.Sprintf("Mkdir() not implemented for %s", path))
   271  	}
   272  }
   273  
   274  func (PPAPISyscallImpl) Fstat(fd int, st *syscall.Stat_t) error {
   275  	panic("Fstat not yet uncommented")
   276  	/*
   277  	   f, err := fdToFile(fd)
   278  	   if err != nil {
   279  	       return err
   280  	   }
   281  	   return f.impl.stat(st)*/
   282  }
   283  
   284  func (PPAPISyscallImpl) Read(fd int, b []byte) (int, error) {
   285  	f, err := fdToFile(fd)
   286  	if err != nil {
   287  		return 0, err
   288  	}
   289  	return f.read(b)
   290  }
   291  
   292  func (PPAPISyscallImpl) Write(fd int, b []byte) (int, error) {
   293  	f, err := fdToFile(fd)
   294  	if err != nil {
   295  		return 0, err
   296  	}
   297  	return f.write(b)
   298  }
   299  
   300  func (PPAPISyscallImpl) Pread(fd int, b []byte, offset int64) (int, error) {
   301  	panic("Pread not yet uncommented")
   302  	/*
   303  	   f, err := fdToFile(fd)
   304  	   if err != nil {
   305  	       return 0, err
   306  	   }
   307  	   return f.impl.pread(b, offset)*/
   308  }
   309  
   310  func (PPAPISyscallImpl) Pwrite(fd int, b []byte, offset int64) (int, error) {
   311  	panic("Pwrite not yet uncommented")
   312  	/*
   313  	   f, err := fdToFile(fd)
   314  	   if err != nil {
   315  	       return 0, err
   316  	   }
   317  	   return f.impl.pwrite(b, offset)*/
   318  }
   319  
   320  func (PPAPISyscallImpl) Seek(fd int, offset int64, whence int) (int64, error) {
   321  	panic("Seek not yet uncommented")
   322  	/*f, err := fdToFile(fd)
   323  	  if err != nil {
   324  	      return 0, err
   325  	  }
   326  	  return f.impl.seek(offset, whence)*/
   327  }
   328  
   329  func (PPAPISyscallImpl) Unlink(path string) (err error) {
   330  	//fmt.Printf("Unlinking: %s Links: %v\n", path, symLinks)
   331  	initSymlinks()
   332  	if _, ok := symLinks[path]; ok {
   333  		delete(symLinks, path)
   334  		return nil
   335  	}
   336  	return fmt.Errorf("File %s not a symlink", path)
   337  }
   338  
   339  func (PPAPISyscallImpl) Rmdir(path string) (err error) {
   340  	//fmt.Printf("Attempting to remove dir: %s\n", path)
   341  	path = resolveSymlink(path)
   342  	switch path {
   343  	case "/tmp/NaClMain.FATAL", "/tmp/NaClMain.ERROR", "/tmp/NaClMain.WARNING", "/tmp/NaClMain.INFO":
   344  		return fmt.Errorf("Dir %s not found", path)
   345  	default:
   346  		panic(fmt.Sprintf("Rmdir() %s not implemented]", path))
   347  	}
   348  }
   349  
   350  func (PPAPISyscallImpl) Symlink(oldpath string, newpath string) (err error) {
   351  	//fmt.Printf("Symlinked %s to %s\n", newpath, oldpath)
   352  	initSymlinks()
   353  	symLinks[newpath] = oldpath
   354  	return nil
   355  }
   356  
   357  func (PPAPISyscallImpl) Fsync(fd int) (err error) {
   358  	// This is a no-op because everything is in memory right now.
   359  	// Implement if this changes.
   360  	return err
   361  }
   362  
   363  type consoleLogFile struct {
   364  	impl     PPAPISyscallImpl
   365  	logLevel LogLevel
   366  }
   367  
   368  func (*consoleLogFile) close() error { return nil }
   369  func (*consoleLogFile) stat(*syscall.Stat_t) error {
   370  	panic("stat not implemented")
   371  }
   372  func (*consoleLogFile) read([]byte) (int, error) {
   373  	panic("Cannot read from log file")
   374  }
   375  func (c *consoleLogFile) writeLine(b []byte) (int, error) {
   376  	_, file, line, _ := runtime.Caller(3)
   377  	loc := file + ":" + strconv.Itoa(line)
   378  	// Unfortunately nacl truncates logs at 128 chars.
   379  	batchSize := 128
   380  	for i := 0; i*batchSize < len(b); i++ {
   381  		min := i * batchSize
   382  		max := (i + 1) * batchSize
   383  		if max > len(b) {
   384  			max = len(b)
   385  		}
   386  		c.impl.Instance.LogWithSourceString(c.logLevel, loc, string(b[min:max]))
   387  	}
   388  	return len(b), nil
   389  }
   390  func (c *consoleLogFile) write(b []byte) (int, error) {
   391  	s := string(b)
   392  	parts := strings.Split(s, "\n")
   393  	written := len(parts) - 1 // newlines
   394  	for _, part := range parts {
   395  		additionalWrite, err := c.writeLine([]byte(part))
   396  		if err != nil {
   397  			return 0, err
   398  		}
   399  		written += additionalWrite
   400  	}
   401  	return written, nil
   402  }
   403  func (*consoleLogFile) seek(int64, int) (int64, error) {
   404  	panic("Cannot seek in log file.")
   405  }
   406  func (c *consoleLogFile) pread(b []byte, offset int64) (int, error) {
   407  	return c.read(b[offset:])
   408  }
   409  func (c *consoleLogFile) pwrite(b []byte, offset int64) (int, error) {
   410  	return c.write(b[offset:])
   411  }
   412  
   413  // defaulFileImpl imlements fileImpl.
   414  // It can be embedded to complete a partial fileImpl implementation.
   415  type defaultFileImpl struct{}
   416  
   417  func (*defaultFileImpl) close() error                      { return nil }
   418  func (*defaultFileImpl) stat(*syscall.Stat_t) error        { return syscall.ENOSYS }
   419  func (*defaultFileImpl) read([]byte) (int, error)          { return 0, syscall.ENOSYS }
   420  func (*defaultFileImpl) write([]byte) (int, error)         { return 0, syscall.ENOSYS }
   421  func (*defaultFileImpl) seek(int64, int) (int64, error)    { return 0, syscall.ENOSYS }
   422  func (*defaultFileImpl) pread([]byte, int64) (int, error)  { return 0, syscall.ENOSYS }
   423  func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, syscall.ENOSYS }
   424  
   425  type randomImpl struct{}
   426  
   427  func (*randomImpl) close() error               { return nil }
   428  func (*randomImpl) stat(*syscall.Stat_t) error { return syscall.ENOSYS }
   429  func (*randomImpl) read(b []byte) (int, error) {
   430  	// TODO(bprosnitz) Make cryptographically secure?
   431  	for i, _ := range b {
   432  		b[i] = byte(rand.Uint32())
   433  	}
   434  	return len(b), nil
   435  }
   436  func (*randomImpl) write([]byte) (int, error)      { return 0, syscall.ENOSYS }
   437  func (*randomImpl) seek(int64, int) (int64, error) { return 0, syscall.ENOSYS }
   438  func (r *randomImpl) pread(b []byte, offset int64) (int, error) {
   439  	return r.read(b[offset:])
   440  }
   441  func (*randomImpl) pwrite([]byte, int64) (int, error) { return 0, syscall.ENOSYS }
   442  
   443  type bytesReadFile struct {
   444  	bytes     []byte
   445  	indexRead int
   446  	lock      sync.Mutex
   447  }
   448  
   449  func (*bytesReadFile) close() error { return nil }
   450  func (*bytesReadFile) stat(*syscall.Stat_t) error {
   451  	panic("Stat not implemented")
   452  }
   453  func (brf *bytesReadFile) read(b []byte) (int, error) {
   454  	brf.lock.Lock()
   455  	amt := copy(b, brf.bytes[brf.indexRead:])
   456  	brf.indexRead += amt
   457  	brf.lock.Unlock()
   458  	return amt, nil
   459  }
   460  func (*bytesReadFile) write([]byte) (int, error) {
   461  	panic("Cannot write to a read file")
   462  }
   463  func (*bytesReadFile) seek(int64, int) (int64, error) {
   464  	panic("Seek not implemented")
   465  }
   466  func (brf *bytesReadFile) pread(b []byte, offset int64) (int, error) {
   467  	return brf.read(b[offset:])
   468  }
   469  func (*bytesReadFile) pwrite([]byte, int64) (int, error) {
   470  	panic("Cannot write to a read file")
   471  }
   472  
   473  type bytesBufFileData struct {
   474  	bytes []byte
   475  	lock  sync.Mutex
   476  	path  string // This is just for debugging, can be removed.
   477  }
   478  
   479  type bytesBufFile struct {
   480  	dat   *bytesBufFileData
   481  	index int
   482  }
   483  
   484  func newByteBufFileData(path string) *bytesBufFileData {
   485  	return &bytesBufFileData{
   486  		bytes: []byte{},
   487  		path:  path,
   488  	}
   489  }
   490  func (bbf *bytesBufFile) close() error {
   491  	bbf.dat = nil
   492  	return nil
   493  }
   494  func (*bytesBufFile) stat(*syscall.Stat_t) error {
   495  	panic("Stat not implemented")
   496  }
   497  func (bbf *bytesBufFile) read(b []byte) (int, error) {
   498  	if bbf.dat == nil {
   499  		panic("Cannot read closed file")
   500  	}
   501  	bbf.dat.lock.Lock()
   502  	amt := copy(b, bbf.dat.bytes[bbf.index:])
   503  	bbf.index += amt
   504  	bbf.dat.lock.Unlock()
   505  	return amt, nil
   506  }
   507  func (bbf *bytesBufFile) write(b []byte) (int, error) {
   508  	if bbf.dat == nil {
   509  		panic("Cannot write to closed file")
   510  	}
   511  	bbf.dat.lock.Lock()
   512  	neededSize := bbf.index + len(b) + 1
   513  	if neededSize >= len(bbf.dat.bytes) {
   514  		newBuf := make([]byte, neededSize)
   515  		copy(newBuf, bbf.dat.bytes)
   516  		bbf.dat.bytes = newBuf
   517  	}
   518  	fmt.Printf("temp file %s is now %d bytes long", bbf.dat.path, len(bbf.dat.bytes))
   519  	if copy(bbf.dat.bytes[bbf.index:], b) != len(b) {
   520  		panic("Invalid copy during write")
   521  	}
   522  	bbf.index += len(b)
   523  	bbf.dat.lock.Unlock()
   524  	return len(b), nil
   525  }
   526  func (*bytesBufFile) seek(int64, int) (int64, error) {
   527  	panic("Seek not implemented")
   528  }
   529  func (bbf *bytesBufFile) pread(b []byte, offset int64) (int, error) {
   530  	return bbf.read(b[offset:])
   531  }
   532  func (bbf *bytesBufFile) pwrite(b []byte, offset int64) (int, error) {
   533  	return bbf.write(b[offset:])
   534  }
   535  
   536  const base64_localtime = "VFppZjIAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAC5AAAABAAAABCepkig" +
   537  	"n7sVkKCGKqChmveQy4kaoNIj9HDSYSYQ1v50INiArZDa/tGg28CQENzes6DdqayQ" +
   538  	"3r6VoN+JjpDgnneg4WlwkOJ+WaDjSVKQ5F47oOUpNJDmR1gg5xJREOgnOiDo8jMQ" +
   539  	"6gccIOrSFRDr5v4g7LH3EO3G4CDukdkQ76/8oPBxuxDxj96g8n/BkPNvwKD0X6OQ" +
   540  	"9U+ioPY/hZD3L4Sg+CiiEPkPZqD6CIQQ+viDIPvoZhD82GUg/chIEP64RyD/qCoQ" +
   541  	"AJgpIAGIDBACeAsgA3EokARhJ6AFUQqQBkEJoAcw7JAHjUOgCRDOkAmtvyAK8LCQ" +
   542  	"C+CvoAzZzRANwJGgDrmvEA+priAQmZEQEYmQIBJ5cxATaXIgFFlVEBVJVCAWOTcQ" +
   543  	"Fyk2IBgiU5AZCRggGgI1kBryNKAb4heQHNIWoB3B+ZAesfigH6HbkCB2KyAhgb2Q" +
   544  	"IlYNICNq2hAkNe8gJUq8ECYV0SAnKp4QJ/7toCkKgBAp3s+gKupiECu+saAs036Q" +
   545  	"LZ6ToC6zYJAvfnWgMJNCkDFnkiAycySQM0d0IDRTBpA1J1YgNjLokDcHOCA4HAUQ" +
   546  	"OOcaIDn75xA6xvwgO9vJEDywGKA9u6sQPo/6oD+bjRBAb9ygQYSpkEJPvqBDZIuQ" +
   547  	"RC+goEVEbZBF89MgRy2KEEfTtSBJDWwQSbOXIErtThBLnLOgTNZqkE18laBOtkyQ" +
   548  	"T1x3oFCWLpBRPFmgUnYQkFMcO6BUVfKQVPwdoFY11JBW5TogWB7xEFjFHCBZ/tMQ" +
   549  	"WqT+IFvetRBchOAgXb6XEF5kwiBfnnkQYE3eoGGHlZBiLcCgY2d3kGQNoqBlR1mQ" +
   550  	"Ze2EoGcnO5BnzWagaQcdkGmtSKBq5v+Qa5ZlIGzQHBBtdkcgbq/+EG9WKSBwj+AQ" +
   551  	"cTYLIHJvwhBzFe0gdE+kEHT/CaB2OMCQdt7roHgYopB4vs2gefiEkHqer6B72GaQ" +
   552  	"fH6RoH24SJB+XnOgf5gqkAABAAECAwEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA" +
   553  	"AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA" +
   554  	"AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA" +
   555  	"AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEA" +
   556  	"AQABAAEAAQAB//+dkAEA//+PgAAE//+dkAEI//+dkAEMUERUAFBTVABQV1QAUFBU" +
   557  	"AAAAAAEAAAABVFppZjIAAAAAAAAAAAAAAAAAAAAAAAAFAAAABQAAAAAAAAC6AAAA" +
   558  	"BQAAABT/////XgQawP////+epkig/////5+7FZD/////oIYqoP////+hmveQ////" +
   559  	"/8uJGqD/////0iP0cP/////SYSYQ/////9b+dCD/////2ICtkP/////a/tGg////" +
   560  	"/9vAkBD/////3N6zoP/////dqayQ/////96+laD/////34mOkP/////gnneg////" +
   561  	"/+FpcJD/////4n5ZoP/////jSVKQ/////+ReO6D/////5Sk0kP/////mR1gg////" +
   562  	"/+cSURD/////6Cc6IP/////o8jMQ/////+oHHCD/////6tIVEP/////r5v4g////" +
   563  	"/+yx9xD/////7cbgIP/////ukdkQ/////++v/KD/////8HG7EP/////xj96g////" +
   564  	"//J/wZD/////82/AoP/////0X6OQ//////VPoqD/////9j+FkP/////3L4Sg////" +
   565  	"//goohD/////+Q9moP/////6CIQQ//////r4gyD/////++hmEP/////82GUg////" +
   566  	"//3ISBD//////rhHIP//////qCoQAAAAAACYKSAAAAAAAYgMEAAAAAACeAsgAAAA" +
   567  	"AANxKJAAAAAABGEnoAAAAAAFUQqQAAAAAAZBCaAAAAAABzDskAAAAAAHjUOgAAAA" +
   568  	"AAkQzpAAAAAACa2/IAAAAAAK8LCQAAAAAAvgr6AAAAAADNnNEAAAAAANwJGgAAAA" +
   569  	"AA65rxAAAAAAD6muIAAAAAAQmZEQAAAAABGJkCAAAAAAEnlzEAAAAAATaXIgAAAA" +
   570  	"ABRZVRAAAAAAFUlUIAAAAAAWOTcQAAAAABcpNiAAAAAAGCJTkAAAAAAZCRggAAAA" +
   571  	"ABoCNZAAAAAAGvI0oAAAAAAb4heQAAAAABzSFqAAAAAAHcH5kAAAAAAesfigAAAA" +
   572  	"AB+h25AAAAAAIHYrIAAAAAAhgb2QAAAAACJWDSAAAAAAI2raEAAAAAAkNe8gAAAA" +
   573  	"ACVKvBAAAAAAJhXRIAAAAAAnKp4QAAAAACf+7aAAAAAAKQqAEAAAAAAp3s+gAAAA" +
   574  	"ACrqYhAAAAAAK76xoAAAAAAs036QAAAAAC2ek6AAAAAALrNgkAAAAAAvfnWgAAAA" +
   575  	"ADCTQpAAAAAAMWeSIAAAAAAycySQAAAAADNHdCAAAAAANFMGkAAAAAA1J1YgAAAA" +
   576  	"ADYy6JAAAAAANwc4IAAAAAA4HAUQAAAAADjnGiAAAAAAOfvnEAAAAAA6xvwgAAAA" +
   577  	"ADvbyRAAAAAAPLAYoAAAAAA9u6sQAAAAAD6P+qAAAAAAP5uNEAAAAABAb9ygAAAA" +
   578  	"AEGEqZAAAAAAQk++oAAAAABDZIuQAAAAAEQvoKAAAAAARURtkAAAAABF89MgAAAA" +
   579  	"AEctihAAAAAAR9O1IAAAAABJDWwQAAAAAEmzlyAAAAAASu1OEAAAAABLnLOgAAAA" +
   580  	"AEzWapAAAAAATXyVoAAAAABOtkyQAAAAAE9cd6AAAAAAUJYukAAAAABRPFmgAAAA" +
   581  	"AFJ2EJAAAAAAUxw7oAAAAABUVfKQAAAAAFT8HaAAAAAAVjXUkAAAAABW5TogAAAA" +
   582  	"AFge8RAAAAAAWMUcIAAAAABZ/tMQAAAAAFqk/iAAAAAAW961EAAAAABchOAgAAAA" +
   583  	"AF2+lxAAAAAAXmTCIAAAAABfnnkQAAAAAGBN3qAAAAAAYYeVkAAAAABiLcCgAAAA" +
   584  	"AGNnd5AAAAAAZA2ioAAAAABlR1mQAAAAAGXthKAAAAAAZyc7kAAAAABnzWagAAAA" +
   585  	"AGkHHZAAAAAAaa1IoAAAAABq5v+QAAAAAGuWZSAAAAAAbNAcEAAAAABtdkcgAAAA" +
   586  	"AG6v/hAAAAAAb1YpIAAAAABwj+AQAAAAAHE2CyAAAAAAcm/CEAAAAABzFe0gAAAA" +
   587  	"AHRPpBAAAAAAdP8JoAAAAAB2OMCQAAAAAHbe66AAAAAAeBiikAAAAAB4vs2gAAAA" +
   588  	"AHn4hJAAAAAAep6voAAAAAB72GaQAAAAAHx+kaAAAAAAfbhIkAAAAAB+XnOgAAAA" +
   589  	"AH+YKpACAQIBAgMEAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIB" +
   590  	"AgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIB" +
   591  	"AgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIB" +
   592  	"AgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQL/" +
   593  	"/5EmAAD//52QAQT//4+AAAj//52QAQz//52QARBMTVQAUERUAFBTVABQV1QAUFBU" +
   594  	"AAAAAAABAAAAAAEKUFNUOFBEVCxNMy4yLjAsTTExLjEuMAo="