[GRASS-SVN] r49326 - in grass/trunk: gui/icons/grass gui/wxpython/gui_modules gui/wxpython/icons gui/wxpython/xml ps/ps.map/decorations

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Nov 22 17:04:27 EST 2011


Author: annakrat
Date: 2011-11-22 14:04:27 -0800 (Tue, 22 Nov 2011)
New Revision: 49326

Added:
   grass/trunk/gui/icons/grass/image-add.png
   grass/trunk/ps/ps.map/decorations/NorthArrow1.eps
   grass/trunk/ps/ps.map/decorations/NorthArrow3.eps
   grass/trunk/ps/ps.map/decorations/NorthArrow5.eps
   grass/trunk/ps/ps.map/decorations/n_arrow1.eps
   grass/trunk/ps/ps.map/decorations/n_arrow1_fancy.eps
   grass/trunk/ps/ps.map/decorations/n_arrow2.eps
   grass/trunk/ps/ps.map/decorations/north-arrow_1_simple_half_arrow.eps
Modified:
   grass/trunk/gui/wxpython/gui_modules/psmap.py
   grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py
   grass/trunk/gui/wxpython/gui_modules/toolbars.py
   grass/trunk/gui/wxpython/icons/icon.py
   grass/trunk/gui/wxpython/xml/menudata_psmap.xml
Log:
wxGUI: Map Composer: add EPS image and north arrow

Added: grass/trunk/gui/icons/grass/image-add.png
===================================================================
(Binary files differ)


Property changes on: grass/trunk/gui/icons/grass/image-add.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Modified: grass/trunk/gui/wxpython/gui_modules/psmap.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/psmap.py	2011-11-22 18:55:30 UTC (rev 49325)
+++ grass/trunk/gui/wxpython/gui_modules/psmap.py	2011-11-22 22:04:27 UTC (rev 49326)
@@ -20,10 +20,11 @@
 import textwrap
 import Queue
 try:
-    import Image
-    haveImage = True
+    import Image as PILImage
+    #havePILImage = True
+    havePILImage = False
 except ImportError:
-    haveImage = False
+    havePILImage = False
 from math import sin, cos, pi
 
 import grass.script as grass
@@ -101,18 +102,22 @@
             'vectorLegend': wx.Pen(colour = wx.Color(219, 216, 4), width = 2),
             'mapinfo': wx.Pen(colour = wx.Color(5, 184, 249), width = 2),
             'scalebar': wx.Pen(colour = wx.Color(150, 150, 150), width = 2),
+            'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
+            'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
             'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
             'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
             'resize': wx.Pen(colour = 'BLACK', width = 1)
             }
         self.brush = {
             'paper': wx.WHITE_BRUSH,
-            'margins': wx.TRANSPARENT_BRUSH,            
+            'margins': wx.TRANSPARENT_BRUSH,
             'map': wx.Brush(wx.Color(151, 214, 90)),
             'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
             'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
             'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
             'scalebar': wx.Brush(wx.Color(200, 200, 200)),
+            'image': wx.Brush(wx.Color(255, 200, 50)),
+            'northArrow': wx.Brush(wx.Color(255, 255, 255)),
             'box': wx.TRANSPARENT_BRUSH,
             'select':wx.TRANSPARENT_BRUSH,
             'resize': wx.BLACK_BRUSH
@@ -166,7 +171,7 @@
         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
         self.Bind(EVT_CMD_DONE, self.OnCmdDone)
         
-        if not haveImage:
+        if not havePILImage:
             wx.CallAfter(self._showErrMsg)
         
     def _showErrMsg(self):
@@ -304,13 +309,13 @@
                        message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
                 
         # show preview only when user doesn't want to create ps or pdf 
-        if haveImage and event.userData['temp'] and not event.userData['pdfname']:
+        if havePILImage and event.userData['temp'] and not event.userData['pdfname']:
             RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
 ## wx.BusyInfo does not display the message
 ##            busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
 
             try:
-                im = Image.open(event.userData['filename'])
+                im = PILImage.open(event.userData['filename'])
                 if self.instruction[self.pageId]['Orientation'] == 'Landscape':
                     im = im.rotate(270)
                 
@@ -602,6 +607,17 @@
         AddText.SetBitmap(Icons['psMap']["addText"].GetBitmap(self.iconsize))
         decmenu.AppendItem(AddText)
         self.Bind(wx.EVT_MENU, self.OnAddText, AddText) 
+        # eps image
+        AddImage = wx.MenuItem(decmenu, wx.ID_ANY, Icons['psMap']["addImage"].GetLabel())
+        AddImage.SetBitmap(Icons['psMap']["addImage"].GetBitmap(self.iconsize))
+        decmenu.AppendItem(AddImage)
+        self.Bind(wx.EVT_MENU, self.OnAddImage, AddImage) 
+        # north arrow image
+        AddNorthArrow = wx.MenuItem(decmenu, wx.ID_ANY, _("North arrow"))
+        AddNorthArrow.SetBitmap(wx.ArtProvider.GetBitmap(id = wx.ART_MISSING_IMAGE,
+                                client = wx.ART_MENU, size = self.iconsize))
+        decmenu.AppendItem(AddNorthArrow)
+        self.Bind(wx.EVT_MENU, self.OnAddNorthArrow, AddNorthArrow) 
         # Popup the menu.  If an item is selected then its handler
         # will be called before PopupMenu returns.
         self.PopupMenu(decmenu)
@@ -647,6 +663,30 @@
             self.openDialogs['mapinfo'] = dlg
         self.openDialogs['mapinfo'].Show()
         
+    def OnAddImage(self, event, id = None):
+        """!Show dialog for image adding and editing"""
+        position = None
+        if 'image' in self.openDialogs:
+            position = self.openDialogs['image'].GetPosition()
+            self.openDialogs['image'].OnApply(event = None)
+            self.openDialogs['image'].Destroy()
+        dlg = ImageDialog(self, id = id, settings = self.instruction)
+        self.openDialogs['image'] = dlg 
+        if position: 
+            dlg.SetPosition(position)
+        dlg.Show()
+        
+    def OnAddNorthArrow(self, event, id = None):
+        """!Show dialog for north arrow adding and editing"""
+        if self.instruction.FindInstructionByType('northArrow'):
+            id = self.instruction.FindInstructionByType('northArrow').id
+        else: id = None
+        
+        if 'northArrow' not in self.openDialogs:
+            dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
+            self.openDialogs['northArrow'] = dlg
+        self.openDialogs['northArrow'].Show()
+        
     def OnAddText(self, event, id = None):
         """!Show dialog for text adding and editing"""
         position = None
@@ -660,6 +700,7 @@
             dlg.SetPosition(position)
         dlg.Show()
         
+        
     def getModifiedTextBounds(self, x, y, textExtent, rotation):
         """!computes bounding box of rotated text, not very precisely"""
         w, h = textExtent
@@ -794,12 +835,18 @@
         for id in ids:
             itype = self.instruction[id].type
             
-            if itype in ('scalebar', 'mapinfo'):
+            if itype in ('scalebar', 'mapinfo', 'image'):
                 drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                self.canvas.UpdateLabel(itype = itype, id = id)
                 self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                  pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
                 self.canvas.RedrawSelectBox(id)
-                
+            if itype == 'northArrow':
+                self.canvas.UpdateLabel(itype = itype, id = id)
+                drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+                self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+                                 pdc = self.canvas.pdcObj, drawid = id, pdctype = 'bitmap', bb = drawRectangle)
+                self.canvas.RedrawSelectBox(id)
             if itype == 'text':
                 
                 if self.instruction[id]['rotate']:
@@ -835,9 +882,8 @@
             if itype in ('map', 'vector', 'raster'):
                 
                 if itype == 'raster':#set resolution
-                    resol = RunCommand('r.info', read = True, flags = 's', map = self.instruction[id]['raster'])
-                    resol = grass.parse_key_val(resol, val_type = float)
-                    RunCommand('g.region', nsres = resol['nsres'], ewres = resol['ewres'])
+                    info = grass.raster_info(self.instruction[id]['raster'])
+                    RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
                     # change current raster in raster legend
                     
                 if 'rasterLegend' in self.openDialogs:
@@ -864,6 +910,7 @@
                 
             if itype == 'rasterLegend':
                 if self.instruction[id]['rLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
@@ -875,6 +922,7 @@
                 if not self.instruction.FindInstructionByType('vector'):
                     self.deleteObject(id)
                 elif self.instruction[id]['vLegend']:
+                    self.canvas.UpdateLabel(itype = itype, id = id)
                     drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
                     self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
                                      pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
@@ -964,11 +1012,14 @@
         
         
         #labels
-        self.itemLabels = { 'map': ['MAP FRAME'],
-                            'rasterLegend': ['RASTER LEGEND'],
-                            'vectorLegend': ['VECTOR LEGEND'],
-                            'mapinfo': ['MAP INFO'],
-                            'scalebar': ['SCALE BAR']}
+        self.itemLabelsDict = { 'map': 'MAP FRAME',
+                                'rasterLegend': 'RASTER LEGEND',
+                                'vectorLegend': 'VECTOR LEGEND',
+                                'mapinfo': 'MAP INFO',
+                                'scalebar': 'SCALE BAR',
+                                'image': 'IMAGE',
+                                'northArrow': 'NORTH ARROW'}
+        self.itemLabels = {}
         
         # define PseudoDC
         self.pdc = wx.PseudoDC()
@@ -1090,13 +1141,14 @@
             mapId = self.instruction.FindInstructionByType('map').id
         except AttributeError:
             mapId = self.instruction.FindInstructionByType('initMap').id
-            
-        texts = self.instruction.FindInstructionByType('text', list = True)
-        for text in texts:
-            e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[text.id]['where'][0],
-                                       y = self.instruction[text.id]['where'][1], paperToMap = True)
-            self.instruction[text.id]['east'], self.instruction[text.id]['north'] = e, n
-            
+        
+        for itemType in ('text', 'image', 'northArrow'):
+            items = self.instruction.FindInstructionByType(itemType, list = True)
+            for item in items:
+                e, n = PaperMapCoordinates(map = self.instruction[mapId], x = self.instruction[item.id]['where'][0],
+                                           y = self.instruction[item.id]['where'][1], paperToMap = True)
+                self.instruction[item.id]['east'], self.instruction[item.id]['north'] = e, n
+                
     def OnPaint(self, event):
         """!Draw pseudo DC to buffer
         """
@@ -1334,11 +1386,13 @@
         elif event.LeftDClick():
             if self.mouse['use'] == 'pointer' and self.dragId != -1:
                 itemCall = {    'text':self.parent.OnAddText, 'mapinfo': self.parent.OnAddMapinfo,
-                                'scalebar': self.parent.OnAddScalebar,
+                                'scalebar': self.parent.OnAddScalebar, 'image': self.parent.OnAddImage,
+                                'northArrow' : self.parent.OnAddNorthArrow,
                                 'rasterLegend': self.parent.OnAddLegend, 'vectorLegend': self.parent.OnAddLegend,  
                                 'map': self.parent.OnAddMap}
                 itemArg = { 'text': dict(event = None, id = self.dragId), 'mapinfo': dict(event = None),
-                            'scalebar': dict(event = None),
+                            'scalebar': dict(event = None), 'image': dict(event = None, id = self.dragId),
+                            'northArrow': dict(event = None, id = self.dragId),
                             'rasterLegend': dict(event = None), 'vectorLegend': dict(event = None, page = 1),
                             'map': dict(event = None, notebook = True)}
                 type = self.instruction[self.dragId].type
@@ -1355,11 +1409,13 @@
                                                                            canvasToPaper = True)
                 self.RecalculateEN()
                 
-            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend'):
+            elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
                 self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
-                                                                            canvasToPaper = True)[:2]            
+                                                                            canvasToPaper = True)[:2] 
+                if itype in ('image', 'northArrow'):
+                    self.RecalculateEN()
             elif  itype == 'scalebar':
                 self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
                                                                            canvasToPaper = True)
@@ -1468,6 +1524,9 @@
 
                     self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
                     self.pdcObj.SetIdBounds(id, bounds)
+                elif type == 'northArrow':
+                    self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
+                              drawid = id, pdctype = 'bitmap', bb = oRect)
                 else:
                     self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
                               drawid = id, pdctype = 'rectText', bb = oRect)
@@ -1502,8 +1561,18 @@
         pdc.SetId(drawid)
         pdc.SetPen(pen)
         pdc.SetBrush(brush)
+        
+        if pdctype == 'bitmap':
+            if havePILImage:
+                file = self.instruction[drawid]['epsfile']
+                rotation = self.instruction[drawid]['rotate']
+                self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
+            else: # draw only rectangle with label
+                pdctype = 'rectText'
+                
         if pdctype in ('rect', 'rectText'):
             pdc.DrawRectangle(*bb)
+            
         if pdctype == 'rectText':
             dc = wx.PaintDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
             font = self.font
@@ -1512,7 +1581,7 @@
             font.SetStyle(wx.ITALIC)
             dc.SetFont(font)
             pdc.SetFont(font)
-            text = '\n'.join(self.itemLabels[self.instruction[drawid].type])
+            text = '\n'.join(self.itemLabels[drawid])
             w,h,lh = dc.GetMultiLineTextExtent(text)
             textExtent = (w,h)
             textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
@@ -1527,13 +1596,29 @@
             pdc.SetTextForeground(wx.Color(100,100,100,200)) 
             pdc.SetBackgroundMode(wx.TRANSPARENT)
             pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
-            
+                
         pdc.SetIdBounds(drawid, bb)
         pdc.EndDrawing()
         self.Refresh()
 
         return drawid
     
+    def DrawBitmap(self, pdc, filePath, rotation, bbox):
+        """!Draw bitmap using PIL"""
+        pImg = PILImage.open(filePath)
+        if rotation:
+            # get rid of black background
+            pImg = pImg.convert("RGBA")
+            rot = pImg.rotate(rotation, expand = 1)
+            new = PILImage.new('RGBA', rot.size, (255,) * 4)
+            pImg = PILImage.composite(rot, new, rot)
+        pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
+        img = PilImageToWxImage(pImg)
+        bitmap = img.ConvertToBitmap()
+        mask = wx.Mask(bitmap, wx.WHITE)
+        bitmap.SetMask(mask)
+        pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask = True)
+        
     def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
         if textDict['rotate']:
             rot = float(textDict['rotate']) 
@@ -1665,12 +1750,21 @@
         if rasterId:
             rasterName = self.instruction[rasterId]['raster'].split('@')[0]
             
-        self.itemLabels['map'] = self.itemLabels['map'][0:1]
-        self.itemLabels['map'].append("raster: " + rasterName)
+        mapId = self.instruction.FindInstructionByType('map').id
+        self.itemLabels[mapId] = []
+        self.itemLabels[mapId].append(self.itemLabelsDict['map'])
+        self.itemLabels[mapId].append("raster: " + rasterName)
         if vectorId: 
             for map in self.instruction[vectorId]['list']:
-                self.itemLabels['map'].append('vector: ' + map[0].split('@')[0])
+                self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
             
+    def UpdateLabel(self, itype, id):
+        self.itemLabels[id] = []
+        self.itemLabels[id].append(self.itemLabelsDict[itype])
+        if itype == 'image':
+            file = os.path.basename(self.instruction[id]['epsfile'])
+            self.itemLabels[id].append(file)
+        
     def OnSize(self, event):
         """!Init image size to match window size
         """

Modified: grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py	2011-11-22 18:55:30 UTC (rev 49325)
+++ grass/trunk/gui/wxpython/gui_modules/psmap_dialogs.py	2011-11-22 22:04:27 UTC (rev 49326)
@@ -15,6 +15,8 @@
  - PageSetup
  - Mapinfo
  - Text
+ - Image
+ - NorthArrow
  - Scalebar
  - RasterLegend
  - VectorLegend
@@ -34,6 +36,8 @@
  - MapinfoDialog
  - ScalebarDialog
  - TextDialog
+ - ImageDialog
+ - NorthArrowDialog
 
 (C) 2011 by Anna Kratochvilova, and the GRASS Development Team
 This program is free software under the GNU General Public License
@@ -47,9 +51,14 @@
 import os
 import sys
 import string
-from math import ceil, floor
+from math import ceil, floor, sin, cos, pi
 from copy import deepcopy
 from time import strftime, localtime
+try:
+    import Image as PILImage
+    havePILImage = False
+except ImportError:
+    havePILImage = False
 
 import grass.script as grass
 if int(grass.version()['version'].split('.')[0]) > 6:
@@ -374,7 +383,7 @@
                     kwargs = {}
                     if instruction == 'scalebar':
                         kwargs['scale'] = map['scale']
-                    elif instruction == 'text':
+                    elif instruction in ('text', 'eps'):
                         kwargs['mapInstruction'] = map
                     elif instruction in ('vpoints', 'vlines', 'vareas'):
                         kwargs['id'] = wx.NewId()
@@ -403,6 +412,8 @@
                     buffer.append(line)
             
             elif line.startswith('scale '):
+                if isBuffer:
+                    continue
                 ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
                 if not ok: return False
             
@@ -428,6 +439,11 @@
             elif line.startswith('text'):
                 instruction = 'text'
                 isBuffer = True
+                buffer.append(line)
+                
+            elif line.startswith('eps'):
+                instruction = 'eps'
+                isBuffer = True
                 buffer.append(line) 
             
             elif line.startswith('colortable'):
@@ -538,6 +554,7 @@
                               mapinfo = ['mapinfo'],
                               scalebar = ['scalebar'],
                               text = ['text'],
+                              eps = ['image', 'northArrow'],
                               vpoints = ['vector', 'vProperties'],
                               vlines = ['vector', 'vProperties'],
                               vareas = ['vector', 'vProperties'],
@@ -551,6 +568,8 @@
                            mapinfo = Mapinfo,
                            scalebar = Scalebar,
                            text = Text,
+                           image = Image,
+                           northArrow = NorthArrow,
                            rasterLegend = RasterLegend,
                            vectorLegend = VectorLegend,
                            vector = Vector,
@@ -561,12 +580,21 @@
         
         for i in myInstruction:
             instr = self.FindInstructionByType(i)
-            if i in ('text', 'vProperties') or not instr:
+            if i in ('text', 'vProperties', 'image', 'northArrow') or not instr:
                 
                 id = wx.NewId() #!vProperties expect subtype
                 if i == 'vProperties':
                     id = kwargs['id']
                     newInstr = myInstrDict[i](id, subType = instruction[1:])
+                elif i in ('image', 'northArrow'):
+                    commentFound = False
+                    for line in text:
+                        if line.find("# north arrow") >= 0:
+                            commentFound = True
+                    if i == 'image' and commentFound or \
+                       i == 'northArrow' and not commentFound:
+                        continue
+                    newInstr = myInstrDict[i](id, settings = self)
                 else:
                     newInstr = myInstrDict[i](id)
                 ok = newInstr.Read(instruction, text, **kwargs)
@@ -1026,7 +1054,149 @@
         N = region['s'] + (region['n'] - region['s']) / 100 * n
         E = region['w'] + (region['e'] - region['w']) / 100 * e
         return E, N
+        
+class Image(InstructionObject):
+    """!Class representing eps instruction - image"""
+    def __init__(self, id, settings):
+        InstructionObject.__init__(self, id = id)
+        self.settings = settings
+        self.type = 'image'
+        # default values
+        self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
+                                       east = None, north = None,
+                                       rotate = None, scale = 1)
+        # current values
+        self.instruction = dict(self.defaultInstruction)
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
     
+    def Read(self, instruction, text, **kwargs):
+        """!Read instruction and save information"""
+        mapInstr = kwargs['mapInstruction']
+        instr = {}
+        for line in text:
+            try:
+                sub = line.split(None, 1)[0]
+                if sub == 'eps':
+                    e, n = line.split(None, 3)[1:3]
+                    if '%' in e and '%' in n:
+                        instr['XY'] = True
+                        instr['east'], instr['north'] = self.PercentToReal(e, n)
+                    else:
+                        instr['XY'] = False
+                        instr['east'], instr['north'] = float(e), float(n)
+                
+                elif sub == 'epsfile':
+                    instr['epsfile'] = line.split(None, 1)[1]
+                elif sub == 'rotate':
+                    instr['rotate'] = float(line.split(None, 1)[1])
+                elif sub == 'scale':
+                    instr['scale'] = float(line.split(None, 1)[1])
+                        
+            except(IndexError, ValueError):
+                GError(_("Failed to read instruction %s") % instruction)
+                return False
+        if not os.path.exists(instr['epsfile']):
+            GError(_("Failed to read instruction %s: file %s not found.") % instruction, instr['epsfile'])
+            return False
+        
+        instr['epsfile'] = os.path.abspath(instr['epsfile'])
+        instr['size'] = self.GetImageOrigSize(instr['epsfile'])
+        if 'rotate' in instr:
+            instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
+        self.instruction.update(instr)
+        self.ChangeRefPoint(toCenter = False)
+        instr['where'] = PaperMapCoordinates(map = mapInstr, x = self.instruction['east'],
+                                             y = self.instruction['north'], paperToMap = False)       
+        w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
+        instr['rect'] = wx.Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
+                                  w = w * self.instruction['scale'], h = h * self.instruction['scale'])
+        self.instruction.update(instr)
+
+        return True 
+    
+    def PercentToReal(self, e, n):
+        """!Converts eps coordinates from percent of region to map coordinates"""
+        e, n = float(e.strip('%')), float(n.strip('%'))
+        region = grass.region()
+        N = region['s'] + (region['n'] - region['s']) / 100 * n
+        E = region['w'] + (region['e'] - region['w']) / 100 * e
+        return E, N
+        
+    def ChangeRefPoint(self, toCenter):
+        """!Change reference point (left top x center)"""
+        mapInstr = self.settings.FindInstructionByType('map')
+        if not mapInstr:
+            mapInstr = self.settings.FindInstructionByType('initMap')
+        mapId = mapInstr.id
+        if toCenter:
+            center = self.instruction['rect'].GetCentre()
+            ENCenter = PaperMapCoordinates(map = self.settings[mapId],
+                                           x = center[0], y = center[1], paperToMap = True)
+                                           
+            self.instruction['east'], self.instruction['north'] = ENCenter
+        else:
+            x, y = PaperMapCoordinates(map = self.settings[mapId], x = self.instruction['east'],
+                                       y = self.instruction['north'], paperToMap = False)
+            w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
+            h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
+            x -= w * self.instruction['scale'] / 2
+            y -= h * self.instruction['scale'] / 2
+            e, n = PaperMapCoordinates(map = self.settings[mapId], x = x, y = y, paperToMap = True)
+            self.instruction['east'], self.instruction['north'] = e, n
+
+    def GetImageOrigSize(self, imagePath):
+        """!Get image size.
+        
+        If eps, size is read from image header.
+        """
+        fileName = os.path.split(imagePath)[1]
+        # if eps, read info from header
+        if os.path.splitext(fileName)[1].lower() == '.eps':
+            bbInfo = "%%BoundingBox"
+            file = open(imagePath,"r")
+            w = h = 0
+            while file:
+                line = file.readline()
+                if line.find(bbInfo) == 0:
+                    w, h = line.split()[3:5]
+                    break
+            file.close()
+            return float(w), float(h)
+        else: # we can use wx.Image
+            img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
+            return img.GetWidth(), img.GetHeight()
+            
+class NorthArrow(Image):
+    """!Class representing eps instruction -- North Arrow"""
+    def __init__(self, id, settings):
+        Image.__init__(self, id = id, settings = settings)
+        self.type = 'northArrow'
+        
+    def __str__(self):
+        self.ChangeRefPoint(toCenter = True)
+        
+        instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+        instr += "# north arrow\n"
+        instr += string.Template("    epsfile $epsfile\n").substitute(self.instruction)
+        if self.instruction["rotate"]:
+            instr += string.Template("    rotate $rotate\n").substitute(self.instruction)
+        if self.instruction["scale"]:
+            instr += string.Template("    scale $scale\n").substitute(self.instruction)
+        instr += "    end"
+        return instr
+        
 class Scalebar(InstructionObject):
     """!Class representing scalebar instruction"""
     def __init__(self, id):
@@ -1641,7 +1811,7 @@
         self.instruction = settings
         self.objectType = None
         self.unitConv = UnitConversion(self)
-        self.spinCtrlSize = (50, -1)
+        self.spinCtrlSize = (65, -1)
         
         self.Bind(wx.EVT_CLOSE, self.OnClose)
         
@@ -1655,7 +1825,8 @@
         parent.units['unitsCtrl'].SetStringSelection(self.unitConv.findName(dialogDict['unit']))
           
     def AddPosition(self, parent, dialogDict):
-        parent.position = dict()
+        if not hasattr(parent, "position"):
+            parent.position = dict()
         parent.position['comment'] = wx.StaticText(parent, id = wx.ID_ANY,\
                     label = _("Position of the top left corner\nfrom the top left edge of the paper"))
         parent.position['xLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("X:"))
@@ -1668,6 +1839,63 @@
             parent.position['xCtrl'].SetValue("%5.3f" % x)
             parent.position['yCtrl'].SetValue("%5.3f" % y)
         
+    def AddExtendedPosition(self, panel, gridBagSizer, dialogDict):
+        """!Add widgets for setting position relative to paper and to map"""
+        panel.position = dict()
+        positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
+        panel.position['toPaper'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
+        panel.position['toMap'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
+        panel.position['toPaper'].SetValue(dialogDict['XY'])
+        panel.position['toMap'].SetValue(not dialogDict['XY'])
+        
+        gridBagSizer.Add(positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toPaper'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        gridBagSizer.Add(panel.position['toMap'], pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+        
+        # first box - paper coordinates
+        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
+        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerP.AddGrowableCol(1)
+        self.gridBagSizerP.AddGrowableRow(3)
+        
+        self.AddPosition(parent = panel, dialogDict = dialogDict)
+        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
+        self.AddUnits(parent = panel, dialogDict = dialogDict)
+        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
+        
+        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+        
+        # second box - map coordinates
+        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
+        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
+        self.gridBagSizerM.AddGrowableCol(0)
+        self.gridBagSizerM.AddGrowableCol(1)
+        
+        eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
+        northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
+        panel.position['eCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        panel.position['nCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
+        panel.position['eCtrl'].SetValue(str(east))
+        panel.position['nCtrl'].SetValue(str(north))
+        
+        self.gridBagSizerM.Add(eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['eCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        self.gridBagSizerM.Add(panel.position['nCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        
+        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+        
     def AddFont(self, parent, dialogDict, color = True):
         parent.font = dict()
 ##        parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:"))
@@ -5178,74 +5406,22 @@
         panel.Fit()
         
         return panel 
-    
+        
     def _positionPanel(self, notebook):
         panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
         notebook.AddPage(page = panel, text = _("Position"))
 
         border = wx.BoxSizer(wx.VERTICAL) 
 
-        #Position
         box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
         sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
         gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
         gridBagSizer.AddGrowableCol(0)
         gridBagSizer.AddGrowableCol(1)
         
-        self.positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
-        self.paperPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
-        self.mapPositionCtrl = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
-        self.paperPositionCtrl.SetValue(self.textDict['XY'])
-        self.mapPositionCtrl.SetValue(not self.textDict['XY'])
+        #Position
+        self.AddExtendedPosition(panel, gridBagSizer, self.textDict)
         
-        gridBagSizer.Add(self.positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(self.paperPositionCtrl, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        gridBagSizer.Add(self.mapPositionCtrl, pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
-        
-        # first box - paper coordinates
-        box1   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
-        self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerP.AddGrowableCol(1)
-        self.gridBagSizerP.AddGrowableRow(3)
-        
-        self.AddPosition(parent = panel, dialogDict = self.textDict)
-        panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
-        self.AddUnits(parent = panel, dialogDict = self.textDict)
-        self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
-        
-        sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
-        
-        # second box - map coordinates
-        box2   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
-        sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
-        self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
-        self.gridBagSizerM.AddGrowableCol(0)
-        self.gridBagSizerM.AddGrowableCol(1)
-        
-        self.eastingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
-        self.northingLabel  = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
-        self.eastingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        self.northingCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
-        east, north = PaperMapCoordinates(map = self.instruction[self.mapId], x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
-        self.eastingCtrl.SetValue(str(east))
-        self.northingCtrl.SetValue(str(north))
-        
-        self.gridBagSizerM.Add(self.eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.eastingCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        self.gridBagSizerM.Add(self.northingCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
-        
-        sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
-        gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
-        
         #offset
         box3   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Offset"))
         sizerO = wx.StaticBoxSizer(box3, wx.VERTICAL)
@@ -5309,8 +5485,8 @@
         panel.SetSizer(border)
         panel.Fit()
           
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.paperPositionCtrl) 
-        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, self.mapPositionCtrl)
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
         self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotCtrl)
         
         return panel
@@ -5325,7 +5501,7 @@
             self.rotValue.Disable()
             
     def OnPositionType(self, event):
-        if self.paperPositionCtrl.GetValue():
+        if self.positionPanel.position['toPaper'].GetValue():
             for widget in self.gridBagSizerP.GetChildren():
                 widget.GetWindow().Enable()
             for widget in self.gridBagSizerM.GetChildren():
@@ -5406,7 +5582,7 @@
         self.textDict['yoffset'] = self.yoffCtrl.GetValue()
 
         #position
-        if self.paperPositionCtrl.GetValue():
+        if self.positionPanel.position['toPaper'].GetValue():
             self.textDict['XY'] = True
             currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
             self.textDict['unit'] = currUnit
@@ -5426,13 +5602,13 @@
             self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(self.instruction[self.mapId], x, y, paperToMap = True)
         else:
             self.textDict['XY'] = False
-            if self.eastingCtrl.GetValue():
-                self.textDict['east'] = self.eastingCtrl.GetValue() 
+            if self.positionPanel.position['eCtrl'].GetValue():
+                self.textDict['east'] = self.positionPanel.position['eCtrl'].GetValue() 
             else:
                 self.textDict['east'] = self.textDict['east']
 
-            if self.northingCtrl.GetValue():
-                self.textDict['north'] = self.northingCtrl.GetValue() 
+            if self.positionPanel.position['nCtrl'].GetValue():
+                self.textDict['north'] = self.positionPanel.position['nCtrl'].GetValue() 
             else:
                 self.textDict['north'] = self.textDict['north']
 
@@ -5471,9 +5647,471 @@
         self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
         # EN coordinates
         e, n = self.textDict['east'], self.textDict['north']
-        self.eastingCtrl.SetValue(str(self.textDict['east']))
-        self.northingCtrl.SetValue(str(self.textDict['north']))
+        self.positionPanel.position['eCtrl'].SetValue(str(self.textDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.textDict['north']))
         
+class ImageDialog(PsmapDialog):
+    """!Dialog for setting image properties.
+    
+    It's base dialog for North Arrow dialog.
+    """
+    def __init__(self, parent, id, settings, imagePanelName = _("Image")):
+        PsmapDialog.__init__(self, parent = parent, id = id, title = "Image settings",
+                             settings = settings)
+        
+        self.objectType = ('image',)
+        if self.id is not None:
+            self.imageObj = self.instruction[self.id]
+            self.imageDict = self.instruction[id].GetInstruction()
+        else:
+            self.id = wx.NewId()
+            self.imageObj = self._newObject()
+            self.imageDict = self.imageObj.GetInstruction()
+            page = self.instruction.FindInstructionByType('page').GetInstruction()
+            self.imageDict['where'] = page['Left'], page['Top'] 
+                
+        map = self.instruction.FindInstructionByType('map')
+        if not map:
+            map = self.instruction.FindInstructionByType('initMap')
+        self.mapId = map.id
+
+        self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(map = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
+        
+        notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+        self.imagePanelName = imagePanelName
+        self.imagePanel = self._imagePanel(notebook)
+        self.positionPanel = self._positionPanel(notebook)
+        self.OnPositionType(None)
+        
+        if self.imageDict['epsfile']:
+            self.imagePanel.image['dir'].SetValue(os.path.dirname(self.imageDict['epsfile']))
+        else:
+            self.imagePanel.image['dir'].SetValue(self._getImageDirectory())
+        self.OnDirChanged(None)
+     
+        self._layout(notebook)
+        
+        
+    def _newObject(self):
+        """!Create corresponding instruction object"""
+        return Image(self.id, self.instruction)
+        
+    def _imagePanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = self.imagePanelName)
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # choose image
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Image"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        # choose directory
+        panel.image = {}
+        if self.imageDict['epsfile']:
+            startDir = os.path.dirname(self.imageDict['epsfile'])
+        else:
+            startDir = self._getImageDirectory()
+        dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+                                         labelText = _("Choose a directory:"),
+                                         dialogTitle = _("Choose a directory with images"),
+                                         buttonText = _('Browse'),
+                                         startDirectory = startDir,
+                                         changeCallback = self.OnDirChanged)
+        panel.image['dir'] = dir
+       
+        
+        sizer.Add(item = dir, proportion = 0, flag = wx.EXPAND, border = 0)
+        
+        # image list
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        imageList = wx.ListBox(parent = panel, id = wx.ID_ANY)
+        panel.image['list'] = imageList
+        imageList.Bind(wx.EVT_LISTBOX, self.OnImageSelectionChanged)
+        
+        hSizer.Add(item = imageList, proportion = 1, flag = wx.EXPAND | wx.RIGHT, border = 10)
+        
+        # image preview
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        self.previewSize = (150, 150)
+        img = wx.EmptyImage(*self.previewSize)
+        panel.image['preview'] = wx.StaticBitmap(parent = panel, id = wx.ID_ANY,
+                                                bitmap = wx.BitmapFromImage(img))
+        vSizer.Add(item = panel.image['preview'], proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+        panel.image['sizeInfo'] = wx.StaticText(parent = panel, id = wx.ID_ANY)
+        vSizer.Add(item = panel.image['sizeInfo'], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+        
+        hSizer.Add(item = vSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+        sizer.Add(item = hSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 3)
+        
+        epsInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
+                                label = _("Note: only EPS format supported"))
+        sizer.Add(item = epsInfo, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 3)
+        
+        
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        #
+        # rotation
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Scale And Rotation"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        
+        scaleLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Scale:"))
+        if fs:
+            panel.image['scale'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+                                          increment = 0.5, value = 1, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['scale'].SetFormat("%f")
+            panel.image['scale'].SetDigits(1)
+        else:
+            panel.image['scale'] = wx.TextCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                  validator = TCValidator(flag = 'DIGIT_ONLY'))
+        
+        if self.imageDict['scale']:
+            if fs:
+                value = float(self.imageDict['scale'])
+            else:
+                value = str(self.imageDict['scale'])
+        else:
+            if fs:
+                value = 0
+            else:
+                value = '0'
+        panel.image['scale'].SetValue(value)
+            
+        gridSizer.Add(item = scaleLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        gridSizer.Add(item = panel.image['scale'], pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        
+        rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+        if fs:
+            panel.image['rotate'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 360,
+                                          increment = 0.5, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+            panel.image['rotate'].SetFormat("%f")
+            panel.image['rotate'].SetDigits(1)
+        else:
+            panel.image['rotate'] = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+                                                min = 0, max = 359, initial = 0)
+        panel.image['rotate'].SetToolTipString(_("Counterclockwise rotation in degrees"))
+        if self.imageDict['rotate']:
+            panel.image['rotate'].SetValue(int(self.imageDict['rotate']))
+        else:
+            panel.image['rotate'].SetValue(0)
+            
+        gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+        gridSizer.Add(item = panel.image['rotate'], pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+        
+        self._addConvergence(panel = panel, gridBagSizer = gridSizer)
+        sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def _positionPanel(self, notebook):
+        panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+        notebook.AddPage(page = panel, text = _("Position"))
+        border = wx.BoxSizer(wx.VERTICAL)
+        #
+        # set position
+        #
+        box   = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+        
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        gridBagSizer.AddGrowableCol(0)
+        gridBagSizer.AddGrowableCol(1)
+        
+        self.AddExtendedPosition(panel, gridBagSizer, self.imageDict)
+        
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper']) 
+        self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+        
+        
+        sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
+        border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        panel.SetSizer(border)
+        panel.Fit()
+        
+        return panel
+        
+    def OnDirChanged(self, event):
+        """!Image directory changed"""
+        path = self.imagePanel.image['dir'].GetValue()
+        try:
+            files = os.listdir(path)
+        except OSError: # no such directory
+            files = []
+        imageList = []
+        
+        # no setter for startDirectory?
+        try:
+            self.imagePanel.image['dir'].startDirectory = path
+        except AttributeError: # for sure
+            pass
+        for file in files:
+            if os.path.splitext(file)[1].lower() == '.eps':
+                imageList.append(file)
+        
+        imageList.sort()
+        self.imagePanel.image['list'].SetItems(imageList)
+        if self.imageDict['epsfile']:
+            file = os.path.basename(self.imageDict['epsfile'])
+            self.imagePanel.image['list'].SetStringSelection(file)
+        else:
+            self.imagePanel.image['list'].SetSelection(0)
+        self.OnImageSelectionChanged(None)
+        
+    def OnPositionType(self, event):
+        if self.positionPanel.position['toPaper'].GetValue():
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Disable()
+        else:
+            for widget in self.gridBagSizerM.GetChildren():
+                widget.GetWindow().Enable()
+            for widget in self.gridBagSizerP.GetChildren():
+                widget.GetWindow().Disable()
+                
+    def _getImageDirectory(self):
+        """!Default image directory"""
+        return os.getcwd()
+        
+    def _addConvergence(self, panel, gridBagSizer):
+        pass
+        
+    def OnImageSelectionChanged(self, event):
+        """!Image selected, show preview and size"""
+        if not self.imagePanel.image['dir']: # event is emitted when closing dialog an it causes error
+            return
+            
+        if not havePILImage:
+            self.DrawWarningText(_("PIL\nmissing"))
+            return
+        
+        imageName = self.imagePanel.image['list'].GetStringSelection()
+        if not imageName:
+            self.ClearPreview()
+            return
+        basePath = self.imagePanel.image['dir'].GetValue()
+        file = os.path.join(basePath, imageName)
+        if not os.path.exists(file):
+            return
+            
+        if os.path.splitext(file)[1].lower() == '.eps':
+            try:
+                pImg = PILImage.open(file)
+                img = PilImageToWxImage(pImg)
+            except IOError, e:
+                GError(message = _("Unable to read file %s") % file)
+                self.ClearPreview()
+                return
+            self.SetSizeInfoLabel(img)
+            img = self.ScaleToPreview(img)
+            bitmap = img.ConvertToBitmap()
+            self.DrawBitmap(bitmap)
+            
+        else:
+            # TODO: read other formats and convert by PIL to eps
+            pass
+    
+    def ScaleToPreview(self, img):
+        """!Scale image to preview size"""
+        w = img.GetWidth()
+        h = img.GetHeight()
+        if w <= self.previewSize[0] and h <= self.previewSize[1]:
+            return img
+        if w > h:
+            newW = self.previewSize[0]
+            newH = self.previewSize[0] * h / w
+        else:
+            newH = self.previewSize[0]
+            newW = self.previewSize[0] * w / h
+        return img.Scale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+        
+    def DrawWarningText(self, warning):
+        """!Draw text on preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.Brush(wx.Color(250, 250, 250)))
+        dc.Clear()
+        extent = dc.GetTextExtent(warning)
+        posX = self.previewSize[0] / 2 - extent[0] / 2
+        posY = self.previewSize[1] / 2 - extent[1] / 2
+        dc.DrawText(warning, posX, posY)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def DrawBitmap(self, bitmap):
+        """!Draw bitmap, center it if smaller than preview size"""
+        if bitmap.GetWidth() <= self.previewSize[0] and bitmap.GetHeight() <= self.previewSize[1]:
+            buffer = wx.EmptyBitmap(*self.previewSize)
+            dc = wx.MemoryDC()
+            dc.SelectObject(buffer)
+            dc.SetBrush(dc.GetBrush())
+            dc.Clear()
+            posX = self.previewSize[0] / 2 - bitmap.GetWidth() / 2
+            posY = self.previewSize[1] / 2 - bitmap.GetHeight() / 2
+            dc.DrawBitmap(bitmap, posX, posY)
+            self.imagePanel.image['preview'].SetBitmap(buffer)
+            dc.SelectObject(wx.NullBitmap)
+        else:
+            self.imagePanel.image['preview'].SetBitmap(bitmap)
+            
+    def SetSizeInfoLabel(self, image):
+        """!Update image size label"""
+        self.imagePanel.image['sizeInfo'].SetLabel(_("size: %s x %s pts") % (image.GetWidth(), image.GetHeight()))
+        self.imagePanel.image['sizeInfo'].GetContainingSizer().Layout()
+        
+    def ClearPreview(self):
+        """!Clear preview window"""
+        buffer = wx.EmptyBitmap(*self.previewSize)
+        dc = wx.MemoryDC()
+        dc.SelectObject(buffer)
+        dc.SetBrush(wx.WHITE_BRUSH)
+        dc.Clear()
+        mask = wx.Mask(buffer, wx.WHITE)
+        buffer.SetMask(mask)
+        self.imagePanel.image['preview'].SetBitmap(buffer)
+        dc.SelectObject(wx.NullBitmap)
+        
+    def update(self): 
+        # epsfile
+        selected = self.imagePanel.image['list'].GetStringSelection()
+        basePath = self.imagePanel.image['dir'].GetValue()
+        if not selected:
+            gcmd.GMessage(parent = self, message = _("No image selected."))
+            return False
+            
+        self.imageDict['epsfile'] = os.path.join(basePath, selected)
+        
+        #position
+        if self.positionPanel.position['toPaper'].GetValue():
+            self.imageDict['XY'] = True
+            currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+            self.imageDict['unit'] = currUnit
+            if self.positionPanel.position['xCtrl'].GetValue():
+                x = self.positionPanel.position['xCtrl'].GetValue() 
+            else:
+                x = self.imageDict['where'][0]
+
+            if self.positionPanel.position['yCtrl'].GetValue():
+                y = self.positionPanel.position['yCtrl'].GetValue() 
+            else:
+                y = self.imageDict['where'][1]
+
+            x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+            y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+            self.imageDict['where'] = x, y
+            
+        else:
+            self.imageDict['XY'] = False
+            if self.positionPanel.position['eCtrl'].GetValue():
+                e = self.positionPanel.position['eCtrl'].GetValue() 
+            else:
+                self.imageDict['east'] = self.imageDict['east']
+
+            if self.positionPanel.position['nCtrl'].GetValue():
+                n = self.positionPanel.position['nCtrl'].GetValue() 
+            else:
+                self.imageDict['north'] = self.imageDict['north']
+
+            x, y = PaperMapCoordinates(map = self.instruction[self.mapId], x = float(self.imageDict['east']),
+                                       y = float(self.imageDict['north']), paperToMap = False)
+
+        #rotation
+        rot = self.imagePanel.image['rotate'].GetValue()
+        if rot == 0:
+            self.imageDict['rotate'] = None
+        else:
+            self.imageDict['rotate'] = rot
+        
+        #scale
+        self.imageDict['scale'] = self.imagePanel.image['scale'].GetValue()
+                
+        # scale
+        w, h = self.imageObj.GetImageOrigSize(self.imageDict['epsfile'])
+        if self.imageDict['rotate']:
+            self.imageDict['size'] = BBoxAfterRotation(w, h, self.imageDict['rotate'])
+        else:
+            self.imageDict['size'] = w, h
+            
+        w = self.unitConv.convert(value = self.imageDict['size'][0],
+                                  fromUnit = 'point', toUnit = 'inch')
+        h = self.unitConv.convert(value = self.imageDict['size'][1],
+                                  fromUnit = 'point', toUnit = 'inch')
+                                  
+    
+        self.imageDict['rect'] = wx.Rect2D(x = x, y = y,
+                                       w = w * self.imageDict['scale'],
+                                       h = h * self.imageDict['scale'])
+        
+        if self.id not in self.instruction:
+            image = self._newObject()
+            self.instruction.AddInstruction(image)
+        self.instruction[self.id].SetInstruction(self.imageDict)
+        
+        if self.id not in self.parent.objectId:
+            self.parent.objectId.append(self.id)
+
+        return True
+        
+    def updateDialog(self):
+        """!Update text coordinates, after moving"""
+        # XY coordinates
+        x, y = self.imageDict['where'][:2]
+        currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+        x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+        y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+        self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+        self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+        # EN coordinates
+        e, n = self.imageDict['east'], self.imageDict['north']
+        self.positionPanel.position['eCtrl'].SetValue(str(self.imageDict['east']))
+        self.positionPanel.position['nCtrl'].SetValue(str(self.imageDict['north']))
+        
+        
+class NorthArrowDialog(ImageDialog):
+    def __init__(self, parent, id, settings):
+        ImageDialog.__init__(self, parent = parent, id = id, settings = settings,
+                             imagePanelName = _("North Arrow"))
+        
+        self.objectType = ('northArrow',)
+        self.SetTitle(_("North Arrow settings"))
+    
+    def _newObject(self):
+        return NorthArrow(self.id, self.instruction)
+        
+    def _getImageDirectory(self):
+        gisbase = os.getenv("GISBASE")
+        return os.path.join(gisbase, 'etc', 'paint', 'decorations')
+    
+    def _addConvergence(self, panel, gridBagSizer):
+        convergence = wx.Button(parent = panel, id = wx.ID_ANY,
+                                               label = _("Compute convergence"))
+        gridBagSizer.Add(item = convergence, pos = (1, 2),
+                      flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+        convergence.Bind(wx.EVT_BUTTON, self.OnConvergence)
+        panel.image['convergence'] = convergence
+        
+    def OnConvergence(self, event):
+        ret = RunCommand('g.region', read = True, flags = 'ng')
+        if ret:
+            convergence = float(ret.strip().split('=')[1])
+            if convergence < 0:
+                self.imagePanel.image['rotate'].SetValue(abs(convergence))
+            else:
+                self.imagePanel.image['rotate'].SetValue(360 - convergence)
+            
+        
 def convertRGB(rgb):
     """!Converts wx.Colour(r,g,b,a) to string 'r:g:b' or named color,
             or named color/r:g:b string to wx.Colour, depending on input""" 
@@ -5704,3 +6342,67 @@
     else:
         return None
    
+def PilImageToWxImage(pilImage, copyAlpha = True):
+    """!Convert PIL image to wx.Image
+    
+    Based on http://wiki.wxpython.org/WorkingWithImages
+    """
+    hasAlpha = pilImage.mode[-1] == 'A'
+    if copyAlpha and hasAlpha :  # Make sure there is an alpha layer copy.
+        wxImage = wx.EmptyImage( *pilImage.size )
+        pilImageCopyRGBA = pilImage.copy()
+        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+        wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4])  # Create layer and insert alpha values.
+
+    else :    # The resulting image will not have alpha.
+        wxImage = wx.EmptyImage(*pilImage.size)
+        pilImageCopy = pilImage.copy()
+        pilImageCopyRGB = pilImageCopy.convert('RGB')    # Discard any alpha from the PIL image.
+        pilImageRgbData = pilImageCopyRGB.tostring()
+        wxImage.SetData(pilImageRgbData)
+
+    return wxImage
+
+def BBoxAfterRotation(w, h, angle):
+    """!Compute bounding box or rotated rectangle
+    
+    @param w rectangle width
+    @param h rectangle height
+    @param angle angle (0, 360) in degrees
+    """
+    angleRad = angle / 180. * pi
+    ct = cos(angleRad)
+    st = sin(angleRad)
+    
+    hct = h * ct
+    wct = w * ct
+    hst = h * st
+    wst = w * st
+    y = x = 0
+    
+    if 0 < angle <= 90:
+        y_min = y
+        y_max = y + hct + wst
+        x_min = x - hst
+        x_max = x + wct
+    elif 90 < angle <= 180:
+        y_min = y + hct
+        y_max = y + wst
+        x_min = x - hst + wct
+        x_max = x
+    elif 180 < angle <= 270:
+        y_min = y + wst + hct
+        y_max = y
+        x_min = x + wct
+        x_max = x - hst
+    elif 270 < angle <= 360:
+        y_min = y + wst
+        y_max = y + hct
+        x_min = x
+        x_max = x + wct - hst
+        
+    width = int(ceil(abs(x_max) + abs(x_min)))
+    height = int(ceil(abs(y_max) + abs(y_min)))
+    return width, height

Modified: grass/trunk/gui/wxpython/gui_modules/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/toolbars.py	2011-11-22 18:55:30 UTC (rev 49325)
+++ grass/trunk/gui/wxpython/gui_modules/toolbars.py	2011-11-22 22:04:27 UTC (rev 49326)
@@ -1689,8 +1689,8 @@
                                'bind' : self.parent.OnPointer }
         self.OnTool(None)
         
-        from psmap import haveImage
-        if not haveImage:
+        from psmap import havePILImage
+        if not havePILImage:
             self.EnableTool(self.preview, False)
         
     def _toolbarData(self):

Modified: grass/trunk/gui/wxpython/icons/icon.py
===================================================================
--- grass/trunk/gui/wxpython/icons/icon.py	2011-11-22 18:55:30 UTC (rev 49325)
+++ grass/trunk/gui/wxpython/icons/icon.py	2011-11-22 22:04:27 UTC (rev 49326)
@@ -434,13 +434,15 @@
         'quit'       : MetaIcon(img = iconSet['quit'],
                                 label = _('Quit Cartographic Composer')),
         'addText'    : MetaIcon(img = iconSet['text-add'],
-                                label = _('Add text')),
+                                label = _('Text')),
         'addMapinfo' : MetaIcon(img = iconSet['map-info'],
-                                label = _('Add map info')),
+                                label = _('Map info')),
         'addLegend'  : MetaIcon(img = iconSet['legend-add'],
-                                label = _('Add legend')),
+                                label = _('Legend')),
         'addScalebar' : MetaIcon(img = iconSet['scalebar-add'],
-                                 label = _('Add scale bar')),
+                                 label = _('Scale bar')),
+        'addImage'   : MetaIcon(img = iconSet['image-add'],
+                                 label = _('Image')),
         }
     }
 

Modified: grass/trunk/gui/wxpython/xml/menudata_psmap.xml
===================================================================
--- grass/trunk/gui/wxpython/xml/menudata_psmap.xml	2011-11-22 18:55:30 UTC (rev 49325)
+++ grass/trunk/gui/wxpython/xml/menudata_psmap.xml	2011-11-22 22:04:27 UTC (rev 49326)
@@ -94,6 +94,18 @@
 	  <handler>OnAddText</handler>
 	  <shortcut>Ctrl+T</shortcut>
 	</menuitem>
+	<menuitem>
+	  <label>Image</label>
+	  <help>Add image</help>
+	  <handler>OnAddImage</handler>
+	  <shortcut></shortcut>
+	</menuitem>
+	<menuitem>
+	  <label>North Arrow</label>
+	  <help>Add north arrow</help>
+	  <handler>OnAddNorthArrow</handler>
+	  <shortcut></shortcut>
+	</menuitem>
 	<separator/>
 	<menuitem>
 	  <label>Delete</label>

Added: grass/trunk/ps/ps.map/decorations/NorthArrow1.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/NorthArrow1.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/NorthArrow1.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,97 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:31:14 2011
+%%Pages: 1
+%%BoundingBox: 0 0 87 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 87 100
+%%EndPageSetup
+q
+0 g
+43.527 84.66 m 46.293 45.285 l 86.559 42.581 l 46.293 39.878 l 43.527 
+0.499 l 40.762 39.878 l 0.5 42.581 l 40.762 45.285 l 43.527 84.66 l h
+43.527 84.66 m f
+1 w
+0 J
+0 j
+[] 0.0 d
+4 M q 1 0 0 1 0 99.999374 cm
+43.527 -15.34 m 46.293 -54.715 l 86.559 -57.418 l 46.293 -60.121 l 
+43.527 -99.5 l 40.762 -60.121 l 0.5 -57.418 l 40.762 -54.715 l 43.527 
+-15.34 l h
+43.527 -15.34 m S Q
+37.434 85.995 m 37.434 99.999 l 39.699 99.999 l 44.777 92.913 l 45.934 
+91.273 46.875 89.816 47.609 88.363 c 47.68 88.382 l 47.492 90.253 
+47.445 91.956 47.445 94.117 c 47.445 99.999 l 49.379 99.999 l 49.379 
+85.995 l 47.301 85.995 l 42.25 93.101 l 41.141 94.66 40.078 96.257 
+39.297 97.777 c 39.227 97.757 l 39.348 95.988 39.367 94.308 39.367 
+91.976 c 39.367 85.995 l 37.434 85.995 l h
+37.434 85.995 m f
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/NorthArrow3.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/NorthArrow3.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/NorthArrow3.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,103 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:33:43 2011
+%%Pages: 1
+%%BoundingBox: 0 0 26 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 26 100
+%%EndPageSetup
+q
+0 g
+6.328 84.369 m 6.328 99.9 l 8.844 99.9 l 14.469 92.045 l 15.75 90.225 
+16.797 88.608 17.613 86.998 c 17.688 87.022 l 17.48 89.096 17.426 
+90.983 17.426 93.377 c 17.426 99.9 l 19.57 99.9 l 19.57 84.369 l 17.27 
+84.369 l 11.668 92.248 l 10.438 93.979 9.258 95.752 8.395 97.436 c 
+8.316 97.412 l 8.449 95.451 8.473 93.588 8.473 91.006 c 8.473 84.369 l 
+6.328 84.369 l h
+6.328 84.369 m f
+8.875 0.498 m 17.465 0.498 l 17.465 59.483 l 8.875 59.483 l 8.875 0.498 
+l h
+8.875 0.498 m f
+1 w
+0 J
+0 j
+[] 0.0 d
+4 M q 1 0 0 1 0 99.900497 cm
+8.875 -99.402 m 17.465 -99.402 l 17.465 -40.418 l 8.875 -40.418 l 8.875 
+-99.402 l h
+8.875 -99.402 m S Q
+13.41 82.17 m 19.863 70.99 l 26.32 59.807 l 0.5 59.807 l 6.957 70.99 l 
+13.41 82.17 l h
+13.41 82.17 m f
+q 1 0 0 1 0 99.900497 cm
+13.41 -17.73 m 19.863 -28.91 l 26.32 -40.094 l 0.5 -40.094 l 6.957 
+-28.91 l 13.41 -17.73 l h
+13.41 -17.73 m S Q
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/NorthArrow5.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/NorthArrow5.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/NorthArrow5.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,116 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:34:58 2011
+%%Pages: 1
+%%BoundingBox: 0 0 38 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 38 100
+%%EndPageSetup
+q
+0 g
+37.23 37.025 m 37.23 26.88 29.008 18.658 18.867 18.658 c 8.723 18.658 
+0.5 26.88 0.5 37.025 c 0.5 47.169 8.723 55.392 18.867 55.392 c 29.012 
+55.392 37.234 47.169 37.234 37.025 c 37.23 37.025 l h
+37.23 37.025 m f
+1 w
+0 J
+0 j
+[] 0.0 d
+4 M q 1 0 0 1 0 99.970001 cm
+37.23 -62.945 m 37.23 -73.09 29.008 -81.312 18.867 -81.312 c 8.723 
+-81.312 0.5 -73.09 0.5 -62.945 c 0.5 -52.801 8.723 -44.578 18.867 
+-44.578 c 29.012 -44.578 37.234 -52.801 37.234 -62.945 c 37.23 -62.945 
+l h
+37.23 -62.945 m S Q
+12.887 0.501 m 25.258 0.501 l 25.258 71.978 l 12.887 71.978 l 12.887 
+0.501 l h
+12.887 0.501 m f
+1 w
+q 1 0 0 1 0 99.970001 cm
+12.887 -99.469 m 25.258 -99.469 l 25.258 -27.992 l 12.887 -27.992 l 
+12.887 -99.469 l h
+12.887 -99.469 m S Q
+19.422 99.47 m 28.719 85.919 l 38.02 72.372 l 0.824 72.372 l 10.121 
+85.919 l 19.422 99.47 l h
+19.422 99.47 m f
+1 w
+q 1 0 0 1 0 99.970001 cm
+19.422 -0.5 m 28.719 -14.051 l 38.02 -27.598 l 0.824 -27.598 l 10.121 
+-14.051 l 19.422 -0.5 l h
+19.422 -0.5 m S Q
+1 g
+9.449 27.318 m 9.449 46.142 l 13.066 46.142 l 21.176 36.618 l 23.023 
+34.411 24.531 32.454 25.699 30.505 c 25.812 30.529 l 25.512 33.044 
+25.438 35.333 25.438 38.24 c 25.438 46.142 l 28.531 46.142 l 28.531 
+27.318 l 25.211 27.318 l 17.141 36.868 l 15.371 38.962 13.672 41.115 
+12.426 43.154 c 12.316 43.122 l 12.504 40.751 12.543 38.49 12.543 
+35.361 c 12.543 27.318 l 9.449 27.318 l h
+9.449 27.318 m f
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/n_arrow1.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/n_arrow1.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/n_arrow1.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:58:06 2011
+%%Pages: 1
+%%BoundingBox: 0 0 50 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 50 100
+%%EndPageSetup
+q
+0 g
+24.793 25.447 m 23.66 99.525 l 49.973 1.13 l 24.793 25.447 l f
+1 g
+24.793 25.447 m 23.66 99.525 l 0.375 0.377 l 24.793 25.447 l f
+0 g
+0.75 w
+0 J
+0 j
+[] 0.0 d
+10 M q 1 0 0 1 0 99.899994 cm
+24.793 -74.453 m 0.375 -99.523 l 23.66 -0.375 l 49.973 -98.77 l 24.793 
+-74.453 l h
+24.793 -74.453 m S Q
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/n_arrow1_fancy.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/n_arrow1_fancy.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/n_arrow1_fancy.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,955 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:50:00 2011
+%%Pages: 1
+%%BoundingBox: 0 0 75 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%!PS-AdobeFont-1.0: NimbusSanL-Regu 1.06
+%%Title: NimbusSanL-Regu
+%Version: 1.06
+%%CreationDate: Thu Aug  2 14:35:58 2007
+%%Creator: frob
+%Copyright: Copyright (URW)++,Copyright 1999 by (URW)++ Design &
+%Copyright:  Development; Cyrillic glyphs added by Valek Filippov (C)
+%Copyright:  2001-2005
+% Generated by FontForge 20070723 (http://fontforge.sf.net/)
+%%EndComments
+
+FontDirectory/NimbusSanL-Regu known{/NimbusSanL-Regu findfont dup/UniqueID known pop false {dup
+/UniqueID get 5020902 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+11 dict begin
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def
+/FontName /f-0-0 def
+/FontBBox {-174 -285 1022 953 }readonly def
+                     
+/PaintType 0 def
+/FontInfo 9 dict dup begin
+ /version (1.06) readonly def
+ /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2005) readonly def
+ /FullName (Nimbus Sans L Regular) readonly def
+ /FamilyName (Nimbus Sans L) readonly def
+ /Weight (Regular) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition -151 def
+ /UnderlineThickness 50 def
+end readonly def
+/Encoding 256 array
+0 1 255 {1 index exch /.notdef put} for
+dup 1 /N put
+readonly def
+currentdict end
+currentfile eexec
+f983ef0097ece61cf3a79690d73bfb4b0027b850f3158905fdac1bc024d7276e0a12b7ddcede59
+e3601ab4509dfe0977ed5bf624ebc1f818c45f1350d41b052a72743accb053eb06ed043568d319
+6a30bed220227e2a15bacef508449221cf338a8666e92410a9aa91d5a31900a93c01ec21742cd1
+4dc46bffa111ce10b78ae01abaeba7f36cdf79a4733245c63f6d36234d6b0961f1ac295d617793
+1b9ed554bb5fc6741a63c493daabf03d753c7d2b8e8c01e3e280898f810da5985212c8c0bbdee4
+e8ab9b22bea83671c0460443ede9be044168f8ab50be5874d46660f1f8241cb261280a68ae2cd6
+0e1648cff45c0ba9b15cb42f86217172a5b855265c214d4b954937d11b94b7b98738393ce09ce4
+0802e512bea7714fe6f163d1b27c8ec87419fa91767418abc44c94a3a22f97f856b0a4729be697
+3455a7f7ae72c671542e9e74258c2b8b2ad440a1b69bc7de2e54ed6a96d0bfde08b35f6fbf739a
+e18676c03800ff3e63c6fc20927b3158e8d2cb6644eaf7831c6bf0e9b39aa14145e721dc46e792
+da9be78696808fadf24136f9da0c8003cb34ecb8af2b7de9e033545fbca53d881eaea40c638396
+c8d3b08b6e2b8f7d6188d055d6924bafb0cf7ef8bf2719495988b0efe373dd1aea97b0f486d055
+5e3a62cc1b36024ec3ada21bfe1629acf431928facb4ead9c41e3d4cb50ed2f651d2cb6ca8d0b1
+ef49d9e214e06cb029bc1a40b2052938f6bcd05f013d9ed1edc90bdea459c4483ed0d1470e30ee
+0a77ecfb585268a94a8bc6be7d28e5746525107c0a3f05fb5e34e0a2157214be2d95a46fdec2e3
+6afd180688fc710c92b27d69b2ff8b1fc7f73cd5526270e5bb585d7674a351d9bda5dcbc17b40d
+465923103f1d02e7446d949002657763c82c8fe0372afe94104d148679b4e5be01def615b295d7
+c25e24660b2a10dfb0b5b96fc02bdfdadc10afddd821fff6caf17f11d6a7cf157d3d7f1aa25a00
+cea41207c8e160663d23b16d2934ffe6a6c178d456facef20fd46c4b33f6d1ebf103b7cde86d7a
+ff74174d2d3f5820186c696b9245f97554b7f62411429f1dabebf1ce4abebcdd2a4ccc1c06d6ff
+8dd9d7f935ba5218765a81eb3c727a40dae317df89cb3234b1a4f1a0b16f88ed1684d3106c2a6c
+c18aedd3b052df1a2ea7ccb8c6c6111abed60277aaa2b91f1da4a83c0b2d4fae8cfbe2873b7f9e
+c2e9ad05045abd1133b95f70185dea97f1081565ac65139ff102004b00e1e77023782a68a75208
+8f8d8cd2393eb3f649553f0be59b83687f4425290ff1e334794e59ab4dc73b26f1beac4c5d6d4d
+507dd7d13b8721144d28b82eba624965e3d8cf9334083a6a461277026b05583f96e489be17dcfa
+ad73cc5b9c6021527879f2c194a5bb18699cbef3ea4e14950e1aa56abbd38bf509629e8a4f0edf
+0946a47aea100a088151a9e296d1b5d7688aa0b3b121fb93bd52789d22fc32d645230419d1df1d
+106a9a90948fd443eb64a212b3595a133a4a30434b5074ff14f69368de4e0452515257aad6332e
+d29556152c71240df8a6746486d28c6a1315bc5c5ed08a5192c2fd7ba4ddcd7496139ae2e6e47a
+c4971edc88a81e2056ff81081b72cec34df2e6bf1720bc5c6753ae32e31ce0db86b3aba65f2633
+5a57f2f12827f7495183427d3e861b6ba27f7157003a92a9405c8755f71dca78e6cf0730fe5950
+4cbe903beec22765da1f35eabc756bf32e9980eed40c0d1a201e12a71b63171df7ca971e36c03e
+8137e0213fe675b392ad8b3232752dd3864c82f9ff85f814becb6fc7510a1e9917bcf12a90c4ee
+29e036db54278f2413731df21833d1f8149344b46e4c3fc2fa9647e76b3cfd81b4fe88643e427e
+7f6d9b01f99659e531df0c43b4f44ed236f117bb00830dc10a5b1896cbee06fde9b4fd9b0b1384
+05a0bb83d78ca5546a2b41490f5322405f0ea6276d9a13a63b98c59cc9a0428472759009cda518
+c4dfce2449e27df9caac365a6ee3a8ac451167c806889760c404164f941d035b6a1df55c44ebdd
+a9484f4da9b07c059ae59617c0e86ffa71b9a70322acb3b6007112879946f950e04e6b634439b0
+6e05a9781a9ca6b9cbfaf508a835e2daaec957d95fa0031f9ae42c17cfd5adfb81766af25ac523
+7818909e284ae4a439b8b2a5050ddebe0dbde491d135155e98ab579904d045797ea516dbaa4529
+675a381372fd437e53f9372dae38f0eeece282771fe7c3d1e68061cc242e4640131ebfcf340b45
+3e4868ce4825067dfcc88c7d84aee3f06eb202a89979aa520e501288e93f742fc86b6f43e3bba4
+430be40b099cb0535504f966cf50fd9ba9fd358fa184a39eccfd4d8e5c4ec35b448bad9cf5bdf1
+5b729a4137a9618a5a44db7d9740a15e0da9c802b428d40ed5401ed76095c73512cb626630608c
+74143afaa7be85562aac8d8148a5e603e3b69b89706b0c1cf5c85bdeb32611221c13325835238f
+ee492e4a08bce9741094c4cdc3edd691e82d224c7866590510e2c7cccc07e11484f62d79303fd5
+59e4e511eb67bab756f30acecc560f5def3902bfb52abfb7aa48e72f2732b7eb73c0123f6dfe97
+cb69897c1db3d57ff05466c3cce4730e04e921a5e56e8add31933536393bc00b3ab3435ab95096
+5a752b913bfdff22a8e7df7bc441e5bb3a3192bea8a17829faa529e56ac69e5a25a6797615d545
+5e4b430627f9c219a364bf0c55669cb872e403ed1cdffc63cf9223ab581bb9d7967892dfef80da
+723f18e199e0b57f12ef0210326aae328882d982392dfcd40e029ad3f53dcd820b4a61b580bc3f
+1b492453f5c752e05c705bf8bc05485c5499f804a6ed2a28bb63bc7e80759003cc7ef0a1d9d51d
+ab1f785d14eb86bd9a4f4221951da58fe7263e23e58a2414dcedb6ce1943f62a65699080bf568c
+c0c67134d8728963466de6713327129138d203ab8db0079f63349ac8ea689ac7615d866b7f600b
+2e91333b61d73c98401b1cb0432e90fa7bd87d9f4fdfecbc2dd5e5eee5daa7d7bd959e41817e17
+525a472ac035c391b918d549c38bf2b2426798fc27af235a725ddff5dc79afb59198c94528a36b
+8c7cd5683f8af50107b45e02fda4c787b4f14ea4e663bbd615be5b30d6979456f6191b5051f458
+bf19c91ac99a9a8505a03abedc243ba2872c3305b81288a79f5ed8452e2a2caf3fa51208946c72
+b97e6d59ef74bd8b96ced9de45d7cf76a6891c7c0691298855a366737da9be57d98c25c7415122
+c898a1564a052036a3aa550c2bc83478c4e15933de6e4aad64b2e97c640a2e8a14933abaf85907
+f09588cb05432f716f05efe4a669d16c881dadc0faf5a704dc91f5006e512a61372579eeea5f60
+76cb8048d71a1e4a3097bc27433bc3613ebd8291e427bd9cf83c0969562d5363662f74f2ecd570
+71c4d331a26559bf3e307d0e2d1c9a90a3fc92254d2656555dbc0c8c3502985a00e705213e4522
+d5eecccc5f94af0f196501250a4200b04b491f64388f7c3aa37970a8a5bf78a072bcbac61cdbf0
+f95dbd13b8defacae1a53277fea4f19f829fced3b4cc6e209bc2616b9bd7312c87d78cda5c9f6b
+ca02595086adb6dac9b7bc6c9fca577169940fb58c818a37575de491222128989965657ea8b5db
+d96a697ef71778109a1781bd7ddb9b2132da71b3bac95f6f69fc615b7733d709402bc7fa0812d1
+8aa22fab627f91baf4a346d8f103362c0161a3b57d83856c63cc7150fa2ec1ba537a4c608bc28c
+85d388bcf4105158f0c9d40a573bab28148104e2db167ff009d34134008cd1ab4cea4091c04dd6
+eb2353686278cb190506778602b0a642d3997caa982a2b3c84f8bc97e83a177fbe6c69512014cb
+f7ab75d5a35a0521a2d1204d7877f75a8b0816da0bc058c0ccf411b939931bcbbcd1d3d92b0fee
+9e58012677b1db645c14ae63b7c4c3e4b18b890802aaa72c0d8cb771ee4e46ddb6d714894aed78
+16d7164799b70d7b64e0a50b979c3616590b871cbae60b9449d02fab57655abd48843da96359d6
+087ce297a26e192491d1cb8420d7cbf1dc66b68ab4299ed1c500ebb26de35f956348d497c3c085
+8e812fd3d43cd76a41e24f19752bbc8a4a69510c9381cdb8a23031f8c0a914db40a659a5b51e19
+fc9024471cce4e65cbab05a3562a292939887967cbe49331cb58e936a2b6873d3dedfbb3784149
+14a2b78db4daa180a4b40a972fec68f931b75f2109fcf824cc7439ea693c8c080abed27376461d
+d5f86617d1a931cf1caf206e872adf0d8b6e35499fe3df6d3833dca2daee3805fd76f7cc5ef2ac
+6f05134e8da55b15204896002803ad497e67c2ea83b2646bc13a72f73d642ebe4b1d5b00a44474
+4160f3341a84335643e58ee6c64acdfcec21bf506a6a30b70b1fce06b97b23c767e7e429892085
+fbff2996aa68e4776b76de0f66edfd89b015cc3a3e4d70cdf3bcad9d48b4e17b97f568b0f3b155
+7d003cd6f087aab912a15e88e51f6e33c8c8b2ab69fa8e81f09a75e0059723f1de598a20c567e6
+81b60e954bd6d80c7515870bd6158eb93e8af8ae71542d681895e2b32489694f090ebc5b560515
+048626f803b996baa342815b5adfc437dace01d549a6319eff57096c537c9aea7c3f8dd978d426
+24304a68ef2427dbc0acd85a26960f10e348a30cdc46e46dc16700f62108fe6c35059759fe69c7
+29edd6c91e83cd49535e16746b6dff037927de39b77eeb86fadd9ac5c89268c3c529fa1747650c
+f9e16c7626aec25817ea46c1ab2b0a7a9c7ba33087db199adf7594c297a938ddd7ad595c694255
+2ae76711f444b5b833a92cdfea0462b6766685359cd4c2afe4114d884b230fdc86d680a9b10a43
+33d68db6ebc595f86806392857b55452e44288a42f924754c22778c6d7bfc3d4337bb3a8f68055
+d0d6f5053700b784c480509caf63336c687c5bd339757008be54c289a10e62d5c83eee133f3216
+8a68aa259e8247d6afcb25243df6ca8c238ea64082265560188e73a47db7603a1802e7ed3693a9
+b7e5ed7b0332171196792cd5272b640c8a5363978a87f58b9d1022d5e7af38d1e45dbabd89b095
+eb9e581ce8e9c314a8152465a4663fd4a7ad1996c08afe96d3975d67fde3aef4fdbad38c739d0f
+1bb4584f919b4b5b8a06aa94bc3a4162aaaf01cf607fd24e90dd4889795aa0fd42e4cce9b0c432
+3963e288dab83c1d1187c1251d77da1c6602311cf8a73e16699d6646bf62cf68b3da3855648508
+edb97cf3614ed1141d158ce8f86e055e9034fcc9c77fe4f592251dca7e61952859567c6ff4fa83
+15b554ff50b48bec4d99ad1221b7caa1d47a8f430a07d49f561296a74277adb9c21c8b4ca1d3bf
+3b671506f71d8f88d37ec1b03432c2bcaa337659c35747b0eb1721073e4e60e93646c719bc4e27
+c5b5fed52f456f43158ad6ba09e9db6d0c17fa75bd7a80746258f7725116c37770e261c9bcf7f5
+78f3f12ec7037c125fd86e4d38ef23886e18f4e206397006c8c4ba0105e10fcc254a718e3c8ba6
+dd71218c4768fe0d8efe2e01454dd52ef33080a1313911ce3e0afa57f5b74d7caef2440ff148f3
+c8bbe0cb2418a0367dddb217ffb47fd5766ab6db331bd9d2779ceac6e8e3e6562b79d947e687ce
+271f8f024c5cfe61e3453cc7ca45efc6b682d2da8acedda708fc65b668e285e6f542b9fdc07108
+2076c4ec2312de40214f8616ac615a2669bd490e89d5c125d6c0d6378113f4d37f1d6a06c225c7
+b0e879746f13607c0a4b98b7d77ca29572495f4edd58f292ca28417808c8e60c3dd8b1a9d185cc
+805784e9a1ec1f290197637cb2f1ef65d1b114bc0e99a9d3070be7199f3d30db85cb3b65eb8cdd
+60b44567730017f4f851d4b15a15bf4312f79c05d5ea03b1da801149fef5ad43eded70f470e622
+81fda1df9ef72f180630b3b1509eb5fd9c73e7f02fe23f554e5b74007d6384f6255ea4bdd2a6eb
+a0310eda07327884d26c59d53d38f02b11815e8adde0804c621d6cbda143ff30856063abcd0059
+183828625bc486f27c475059855c9dcdb5831ce58532e3e6984b63b690a27373d7d5e613be666e
+d52d9f743fd3c373984fbfb8ac8040dcc222ddff4a2e1f6d93f64aabad9a286e3e07679adc8538
+85c8658e37b0efdb68fe51c09ec2b6b69735b84d2aa481793f0e5982e006d985c0c2b8d394b709
+3a210168e58688ab1c07b99b857e90523f90ea3f4f4202f7751dc55dd7cc187f4afacced589cce
+0189545f2a26c9d283b14ab2aae2e5393d416e014ad99e27f8814c0b1bccd6f798865e243bdc94
+08dff7e6fca3b515e5edd3af9ac11e4bf0a7b7a736959a4f48d4e519d069263b0af143dbf431ce
+df2ab7d4df2cacb62627ea46e77e20233ede4166f291a3a19f62271ea68be133a61b6342782ab5
+8310c4e2b08782800f48d311a7c15d1a6d3f7c6b5bf2d91cf23b931793adab17d9f085a9aecb9d
+4df2c4c50c5329503c4a8ad83fdf446b306c56a2ca97bd50f359280415f8cd4bf01817da0f01a0
+e48bfa4c7a1e85f052a03369b0ad7eb0122585bd4445dd53912b2d1ee8cbd9b7e2716166790c32
+f4e068134102aeedc6ade4d5db39ac29f424b0d5e327d081990adcfad18f6ab64c7f199cddebf0
+490b10847d158b2151a8e79b707af40ba4a38c8c02fc49dcffa7e2813ad7741ab7bb29c93e146d
+81be2a2494791582618f49aa9f904f8faa1ec63adb809cd473ea6743509617fdbf260d4024b410
+1d962f66f361d7257804e354e050004155cf050ffc6adfc28c4f742a3231c5fa37c7c826985c50
+99698eda86f0a2baefff000a4e74597e5bda20f8c36f22ddd94ff45e16ac91fd250eb9d8d0971b
+c4bfda5b6c0c14d850822031fcc8f231023a579c09493ff2ac9f72e81b4c0eaa64fc3401b7e128
+b2642aa708ef990878091956a777d908fa0c4e1f2da3363e098a28b6f141ef68258e2f6ae3ac08
+9b3b89de4379a0da96cfaa81a7fdfae2fe9dbdaa3b21435793e464baaa346a722c385e71398949
+d32b76c6cdef0b05c752130d43ebc45a1738f06281097150423f885470928cc1153cb01b2295df
+e17cb19d3b4d576209425a806b98d83e80158b67120d6ea0a65d94582e248d3dd8ad826bbbc00b
+9b9dd0f4d606a65b1a0ba8eea83cff745e222e6f4645055a9cbdf1d99160e0e4854d989f07cc3f
+393f72af97c3575d6f1d8d4312848bc72bef988cc436c23f4c6a2a5569a79d04a0667611a3b0f2
+e2b8ca0a6ce0536b0e459e21dd3d74d8a94be16cdb3d65a6534be608688944c0d68c62e3989910
+4ad6e587ec0f3fc097ce54d3e25c9f081dec3be6c71b714b9f92c15517dfd763b9bf0496d601fe
+4690a9a815e803221e007a7ca74743f679daf6a626af5a6525b394731febbe7cadb5de910c2163
+e640acb041736fe4e508dcb5c7d87d38e12ff80fc903c26c480b567f057b193f5d4ba352697b94
+81d780d94b815a7d96ba6dcc34e39f43caf780d101bd73488a88d213063432f8e6bea7e7248d85
+ab48b576ee702af9364c81f7d5c74ddad8315ed4345444e0cd92ea23b4394073178807892d2925
+a6a43a75c68881385a78d9d5582d3f3f8bae87ae177ea46dcba9af17217906204f751a358cd8a4
+d8c95ca76651271963b6d2ffdf282b653c85ede30f9c8bb5f113528e221aa1a6507364f74ecae9
+22bc09e6c3f42166b2118a819638a85560c6e1eb7bf2893357a81571201a2bc31a91ab89489fa2
+050d353039a7085aacb83609825ae7392a84b6325bbf17af46a9a3eb63ad14bb387987f6d756ff
+c59a2a08937538a0efa89ca08f9785952d2e8bbba0e6023ebb8fceb5abcc3c0c3c1b980255861d
+991fbf27e70686fa238e92ca9bffbad61bfd48c5b8e8aa8fde96fd9acb2d946b69a51137c90595
+5ceafeafea0acb8a0c561808ec2e0d4fbacdb7ef9f9abfafee72f759e8208559c232ffe5bf6cd3
+e7cbe88ea579e795455f7c25f434345506d98be333bffa7f7cf1f83bc00e38d2503ceb483519e3
+b1e5cb7751c00bd2a13c385e2f88ee5df92086b57fadc621a1a539ff102d4fc4c075ab1d800eb1
+efc6fabdc04f81065f0ef3aa5b947d904410962f6533c1aa49b86178ad45e35d44b866c938876f
+2bdf1dfb28d793bb5d049df0cc3e21b8ae8f9b75ac06f00759d48bf39c61125641612bc6032f5b
+6046d85ae9c7102b99b93f7674e80f96a1d74c1368d2fdfca6e8535a9d80fbaae20d681e1918b4
+af227270f40ee97fbaad4a4216908272cd9767fce64130744d0ac38825384bd51bfe19a150b55d
+d390020ae35929d4026d4d8798cf2fcabc5ffeb88f20129ff22baa1bf3fc412b4042345545075f
+c332a91a87c3ccaaba8c201ac784fab723c1371991d5a4c5d865727dc7170d876a83dd01b10c29
+4e651e39a2d3a7c7de70817b0508f612856ddff87bf404f4c750437a96608c130bbdb8dc140510
+61957ec0976ac3b58e117b85cc17f7be4dd59a34a81ecfea08529704d8cb73176ea03c1d873f0a
+7acb41d533c8d68dbb3d9b879448ed2e52a98957c41682fc30a002015af634229c4d5d6b900586
+a0a0b06b1fedaf188610cc3bfd97eb4261460ce68154b3a5a19a218bbf3035fbc6477889c2be39
+7cad1e44c4fbbf3260bf85eaea01ca97d02b4c366a44fd08be6f197df8243ca699c2b75b54756a
+b361115fcc5828dec91dff364db969960569e59a1c3fd2b76b4f88fd9309f8c9962d02ac778dca
+69f07609b0b9961ffac6d942943cbc2e3682879841df4f1d05350302cefc029100f934704dcec7
+e3f153871533258ad2b5b5ad89d153f53be6390ca66461b84fb405b4722d3e3a205ce3bf339018
+b339f240c4956edd92e16ed988b46813e5e39533804efbc6e426304523b82073d9f296b3f8283f
+12dbb66157440222a888acde1eef4dc861f9e8d0e20c5876f74e99c1dbb0b5fe81eae326545e84
+285864f90353f9c1c21c166deafc24ffcbe1a19522ac8cbabf3bb73c36bda0238a19da380a6ba2
+63cb28f99d3643ca4f4b21ebdb9e19f1d53947c8f43a22320f8eb83f152580d83dd6cf230e30b7
+4d2f0bf26d6b621865797b989714ddc45136974dccdc37baa1a52d021544aab74521e9e2ef0607
+d951b1e4cbe230a9a1095df65774af0c2a0c0f1770dad9e054dc06c81d30801a927e525afce8cb
+8d753bfb1fc2b5d967b9e25c7cfa39bf6fb86dd482da0d871d5c8725cac7b44dcd5c3059f39a4c
+b216177100c0f99572ddadf8d7d53733db55286717ce9ee2a12357b901b675c566909a0b4c71bc
+bc7bbb7d36aa72a7018895b617ed93853602a5fd52daa01da6d6e3b713b7fd9d6f75e05f218572
+11d6ed29349ff0e628c26df07d1c079e556ffc60585ec8e91f38c9b4ef0a708559b4cc4155ff42
+c48c18731bd231b2dcb32399943e3fd64fb66d3011cc85e9fa20e28c741303d5b1f3b7178753cf
+97364716e6bea337a89ee47eaf9b93f938d9d10d82d4c0e3927af3c34927fdd5fab439d303d997
+637e2d21725bca942bad146e4df93b37e5a38e4da57cb1d6e6e278b17a82644c800e6104eb2518
+c03ea9b8e3f9b7611066ef9afc58b893e3fadc53835440a47d93c7052ca4b617c1d958c693ceb6
+0f9a2814cfc1b4a24b32783b389678bdd14fc3ea2124f124afc5ed977097af7a1d3a4d825c55f0
+842b2ac566e43458495b6f51c011d7e78818f6d934203a74a961618625a380923926544b7c13c1
+4b2180f3576cdcd4f2140bc90b2ec84f1aca97f147781866d711448c1dc8df1fcc1a1769ece2ed
+5cea053795c0cbfb7204dc61065c87be00d9c0527d5df881708fdbfb7fbe01a933775548eefb73
+6d014a560cdb4313678581a3b1aa73d546869301f309f189c2df29f3d4bebb3b5a72046354c2ed
+d273c9794c3659bc72fe7fb7442e75b04fc197a49efc2ea39ae0b5d1dce9bb509b5085445a66b6
+a59979c26412f1d6f5ebae84175ff08a90c9be4406797389c439693e2fd2f2c26d2e9dea41c505
+c32477ca50fc01dcd53d388e27cdfd4d73c2ac2fa03b9eb934479f0419ef50036b682c9ad8bfda
+a3adf80a03de9f29b7021cf0441deec0f002fab57da0f5be89f5da4597a2523a2e7886589002e5
+cbbde0356b391148b5502eaa3b3689871a1cebe9b8214992f5349ede7d799a57b85d1e2ae706f8
+567efcf24081165f53810a2dc9568a263f69c40eb55cf31782da10dd970dc79f6593f1cdd9ce55
+2de6c7c9fd3ab21169a2e487d5fa959d659afddd071a0d756b5c7debd602cf9ad3e6b3dc3f29d9
+54cad22ff28cf333ac67b8793f01c6f13c4ae2b6732d60633b59c2d9296ec77b6ee630906adf73
+ef86033317cf59b6ffcf42fd7a68133f0673a5c91b8e0ec7b88872e9ac8d0aa904af6000799d57
+e1dccb74496e345dfea868ad7498f3ec7b85558a1fefb6f03c7d5365cef02b044b220c162c530b
+8cc899887f8846084c7b4fa1dcc631ba3a3773fa22443097b47852b119b42df9d58ef3d55ca10f
+38b04f378562b3bf03140e25544a77e66cb9589e6f9dc0a11b6c2a35fac32ce9bac552dc54270b
+fc025baf639b8aa5e3dfda4908b869969bd633a9b171ed6a04a2ee6e3744d7a348cdf09dacda62
+5269181d8d0fb84b468d2eea50fdf69324bf64ab1db3ad0fb2fb9583937f0be8b41f14a751d711
+5adf2d329db753cd14534cc282f2b4a4bf497a4c7b69cd25a1fb33c5e91796b885176284c77a11
+9b50b077001b566328fd23170e4ae611e3426fc26443587e3982cea97c79fd63a4dfa95efee48d
+d81f90d67e40f283c27947d0f0823d2d2d26210e5243d2029b2ff059336b57b9b1334b0b615bf3
+57c6a732c8d5165f2c9a6f310e48a2e4d7dc965887b45c14c9b744bd98de8f33071f0dea693ad6
+4a55d03b2891660d09775030eb5c0e6e868ab1b90028c373d3448851e225dc9eb442aebb5912ab
+0f3b1107a7d96f9d23983d8a6cfedd589e59fd355ea0aec2a448fd9d254d39331cd80dbfd653ff
+fdb2702cb848144c33c28d207adc51097c28f754521e715be8b7b14c4f86aff04fddb0bd52247d
+814192a884e5af3a8f675cdf0c9dcdee0668773c3a3673af8f51a71bdfea19d0bde8a2a2345316
+4edbf01c932db93128b686cc6fd9a1dbd506b6c52664c5aaa01901c5ac0a8275e0ff4ec66ae332
+6dbc1b3b60c4488b6af86fbf30ddc1e3e3a8d63d7682c222e74605c95af3327e694f3b3c160008
+3f9cc241f97c5013c9a0588c715eb4dd00944e824e43a7a1c1fd144d1098628139034731eb1cbf
+633184cb857a17855f277bbc18751799ae28f48130cbc1ed559ab1a5abfa2576d59fa35772557a
+6fb3d15b4ade8bd38b763be0f8d8166613cc37dbcec1d65aa06c7b9f171028fddf8b55093a2fa5
+09ce882054682fcfe32d510012ef5ddcf39f0ae5ade25af279829f8d47b65b89a40a71ab70c2cd
+961aefb7004d3910c190bf32137e4d9733b971db4616ba789c741efc39c26540d3228884b4bb49
+0bea1ab957682d250cf95e1d41c116623925e7778755c11c654d42dfff1db2a49c5b57c3df98d9
+42373519cb02f367598997028e11c513a99b4abf115c61e2daedebb709068ce06692303cd0be48
+228918a12dc126af0e4f81766acf9a84526add4d2fa145cb5452c09547de307b352e141233cd8a
+ea9f965070a2e6321a795f896c0cebc01ce3a15a81f14c14d74aaca4ab090125fecc310410da79
+bab5dbe07e9eeb2189788f491c457a82abf7f79f427932c8ad38466431e28659056c3d5a4be02c
+8d0d054bcd4f9170aa7b7b0d2e9a4564af66eb7372fe981bf441b68cf8247d11fcf0bfeb6453f9
+d2210dc880b9b9af2bca1dad558c1be18eab687f453d4aac976fb9466a6602ffca1dc852a56c50
+556d777258a7bc26489789fb4fbe2f70034eef6174244ebdcf514c5ff72391d097750ac8a9fcfe
+6c94af17b3a5f2667ca2a02e7f32424ad5a7d902751f7c41c9a7fa5fae2d8d7396f8e586be8ba8
+f960ff3fbcbe783e5ece80def85cdf792e33459d996a28775979b335a8448523c0a187dd8f3c08
+31231231f2a158a7b7642593932c9e0dce8892ae708b9458993d580656e1614f2d076f256a680c
+cd3d370e37cde46dbaf38f096b032170759ec0619cfa0389b17568017f8d2811727965c75eacb1
+bf1b179b69567b0ed8bdce2ce95e98ec7a9a573a79ccd5b4990e46d517324a06ba418b34110fee
+abfb71c1e43cfc1650179fc1e5f65fef017498b83a1eb5fb5e340a1b19ef7f10fd0422f6e7f640
+db9a46762fbbaf33e2eed637ee9d93cad018e33c4fc821212bb0f38f2251827a46f38c38c128df
+a891f0b8ed14054c651b735837a0f862967c3d39912e288dc3939816e015e8be9ba798f68c5e89
+a4184aa18392352bdb53119115b1a100e0941b80fb8017dd198c7d0629e72f27da2d8ebb59de72
+ee46daa03e57b12513988f2023484d9f0480126a378ac134a75c2bfdc4df5b8d8fa77ba3fe2da9
+a01ec9427a00487b3a81b50a118c528b77c22b57265e5f915a063fa3e8bac0ff7cbea9ddb19ab8
+390775df6049cb85921457cfae8a868bc6584a60223fa19a363f98876ea3d1e8a69337a58ffd75
+c9b296ea5485e343c04c72a53945e21fb479495d4686302f39188c01b036253ba0a18fc87aae33
+5fa522a435094c3608cf6e2e37fdf5fa3f59048fdbdbe6c58dabafe941a7af5aa4ee7b44d64df3
+74780e9e2d691b4639e2aaef8c52de72b51f2bb6506e5e98f8ae236d183c9cf250dee46d102d96
+4aefb7b82ef32d19a03aa88ef2ab975f04a6cb5208f570af43f73d804843404eb835e5efe3e348
+87a37816ed3cb02b13e91be5bda75a112d1d27e92e462ec516100ab117b2882993af81dfbb58eb
+b2f5bc5d5eb98e48f73e88144889677b31d3c660839854a5c611a52bb493b644553e6948d71f94
+f04eea57f7d458d7d78bb278d83065bdd9097f252d39a9ecfb408f2229ad5edaf4afd518c80421
+4dd2458b085d7bd382c7a1e697b5e0c1a47c25e2cf084d63bf186635783b56e6b36e7da64e3f9e
+3e7135d74381d957c0c62a6d2c4dda1c21a8e49979dc4946c3bb84680e4386750d4b19c4011759
+d84f90cf31b268f0af056d8566e84939388ff4cda569118ed71a2cd82d28b44e17c84389795a43
+57f70f976891292e15448c74ce895be53e4212079fba23793f3c247827b44f0e39066964e75671
+9c628e6bf4a5f080de8402d5d1c154785564e019f13ca5b45b525b325e29f193557770f88ef82f
+8d7704631969d4ad624206665ee1d38d7ef7a7979aa05d39528beb6b7764d88da381eb63f0cca2
+f797dcac11011445da21da35e051c1db3da576e698451a0675944f5749e465faadfa4bfb09eba5
+177ce8cecbe67fa06b74d75278d7f28c236a596a17fea5467785f345197a43ec5f2e1b7e7e2151
+f287ad9181ac39c9771a1713f45b5ddbb402bf674e3eef369647bbc37b3afb327576831021a1a3
+8fc4840cc4716da8026d16fae600d543a3c4dc4d7cd5baf19f1db2a24a0757ef6c3bd8047288c1
+436eda2bd3f9289e6f8b003dead7b0cf49f3aa8a56adcc26ae300976e1c84bfa04d9a1887682d1
+9ef68f52b76fdd0e03f64cc92dbb3ebeafbcc56f8a2a99af870bf7f0153dde4202ca45c530a056
+2dfae59234f4e3287b93bf427fcaa8d236606aa43aff3862063c0bd73dde6bdd3ab4a8c4d6ad9c
+24da288dacffd02aca90dfdc72444c9bcbd331755876f649e4b665d69921097c364eb8b0562090
+e10f4d719b2b5afc9312ed39c77e91ece761c6c940133f940a74e5ce3c05d9703556d28a583972
+7c54800ad0e496885aa4052f65813ae552e8dce8d6f73949d0fcf5059e85ca8a1c137d751c6b8a
+87a52b198254d01258074227501dbe50de2b82bd2510e5788c46ac997c65bf44dd6928ca9f7a90
+2bb957e277e7380123cdd93cf75dd6c7e5a56f93f114b6e46e0407d3ed544d781ef6fbfc704a03
+5b7b737eb332457977f223d87ba6e3dbe827b4fae9e687f6975731d42a8977cfa67f94e90df98c
+a790e89713dcbc07cf27ea8c4584cc933fc342e5c5e740ee920ac3403d4deee426d35e1062a2cc
+7d5e23f568b49495c8b4556a8bbb0480ade618566f537b440ce52ff7d2cd89fc806fc388e9d7fc
+8bf15882a38ae0e11915ab03c272c8a312094938b9b4282ef3a321e3bd82701a50f8a4380fb325
+33cf4a100b0f96475a0f12fe9ce7e6a41784fe7c83f05869d42b70febe4f60bf749429bfc4721a
+cc4e17a961bd7da411471edb7a32f4479f2f079239c9bedcceaf35119982d686545cbb1eb0e9f4
+29e9dbac1b743d28d12c6ffaf8f98a3bbd60518803d997a56bb515602dd3a75f7ace8adf16a6ee
+79233fee1d21bf40914f29521638aef27eb796b06b5fe274444e0833ab9a79bddcb334435b815d
+0af72964e8cc297d246c6bd6d78e0e8394d8359084963b01416db54a3e3a6d9784320814c4fa99
+aab6c4934b76a26c5e014d3fd202935f2f9399dda83b4d652ab89936578ac2c70daec483f69422
+b25472458417b87f2861ff90aa37e45c07ac19fe09a4c2d37c917941f01682e650fce1785d114a
+bd5949ae733bdaaad98a802437f465bb7d2d1e0d4118d6ddc9aee8e08e606d9703c319001725da
+095dc1e3a421f0c5315e28765e9571982039d5313efe20de55e7b614184c4a1e4eaf4a89c62331
+c6f2511d706c2c4248c626e6474c450db1838f1d8b264e406d6f85dc63e78936a3f7d84baaf49b
+bd3ba15c58fc4734fdeb13d1f1557f29ee53fdbcca5d008c60f868ab756608ce889de583309a30
+3cebdeed91e7c4922526f12558d2e751ec11b3c0bea88065ab0241f9d1e4c6144150f92f917b62
+9295da2e8433a66b4a6e6c8571b684a675af7e77cfa6723f82dc6ac13a8a568ed06a519ea0a272
+5cdc99096ac0ce941b93207ed3f5991241f709ef7f9e8b2acb77100cf293452a1917d32c2f2a79
+8af506a827be2d3f3ce87e3d920a0d8cf8e98a4bd3bd99e12f4374e0f6ad25af32793c5f85b77e
+213c7805156d53eba08d9a84ba43abbba8202d43091436113d930a138dfdd15774397f496aea91
+72ff0302555658d3b4f6926fc115bf3de066f2d3bdac9738ecb824713de70361c91374fbac965e
+d71ee2aaf3a27a9cc5564dd26a4bf30dad76ec5f955915b1363ddc6bfb706b559fbee46f6b6338
+dd6a07ccdb23b33b0237c8f0a428fcbf6db62fe6906e4a593b4dfaff151b2cd167951a70f53539
+4d84b7ad727bca8403cfd661abf9a72ca0634822f0ebf66ed148fd7b29513eb151c8d76ea7b749
+02d76ef7a88d5c571873bd219a9f7e60b5d6b77bbc1afe19165f88bbcf45cffa773fa9379259c6
+1a930395ce89109c5e3a14066dcf9dc8387209c84273ecac6a6cb033d54cbe4451036b0b5335bc
+4b3a2c6f6a4395fdecf9c1b88d3b8840e0a94b0516c5821cdb3b15aa06ef3fe3a2c4729e258156
+fb7ade7c1b8f673dc87a8c87d6229df03d88fdb8d7e122cbdb3c8e9eed4ddd03ef86bf2b6fb140
+187441e7d3ad4bff4bb61e57dacbb792e9f4263770c169933f99eaa94f686169ac46803bf6324b
+8498c154ca78482224ad28253607ce99680a755c573b8cc5bd9840b2c8a2518cfeec51a396ec8e
+3b6c3f980a3896feedde1a0605ab8d7891736e2c9502b5e2b3de8d76da62afee99a77e1b079bf6
+f92363e8a5b6e605245952f9cb351206b65eddff62ab5730b81d85311489f9b4f4eb4690844b47
+a8a2cc0881180d3b5bb8f6bd73afcef9300002c1680503cab52a1c6c10b038c312a0c5e59c6007
+2d4405937a8776bffb1c07d0a8761bb4aab03dedb634ce0192bb51b07dfc815073beb441be59d2
+a5b29a64e559a0d0f33022188ca9e9ee43530036e15604ac28bb7349b1f6b57ffea79982da0f9f
+ef3b0447ce31ab3bbfc0c03b7a421a836b8bf793fccbe963059de30c4ec0ea18bd7f3d00ceadc9
+e611bf4c1376a64087008b5941734d404646b9f698dcae3c906f2208158f670d807d7ac8509a38
+a95d16679d11cc23115fd80301e84f4b200ee160fe96e54346be77e24998e679a0e1c0579135af
+c37c68c5163028b2c026f5d22035539795135e468f192814b49c4967e4873799ae4fccd31cdf23
+f754ec82068c2448ee44a452a0b4bf877a7c420006ce3e9e032d830e2bcb814e447b01473cf593
+3f6d82cb74e6d1d5d6211484ff1ab6add9a46397b42fe3c7b7cf6357ccabffeda61f6aeab2ef6a
+84ba261f837fc8bffdbfb3ca6901c2b4b29834e08d4d45a2dd4e8a51c229d30915ec1bcb1c5486
+a57eb7490c70c0dbfa01fd1c53c99832c7e26e50265f54b8197a0316d30a5646f6e4a71d475e03
+460d81e8b658327db8a1b1437334d3a907947b2c899e4a53ffe9e8227b2d5420ad4109b2b136ad
+0292b5ccaa83556e85b2018e629113c3e0d4d484bff995a484643f661975737cb0eb80f2b1ab31
+9b1ec6251c49ebe855e2d6ea533398f9b3148316210b46ed555ef68a949b73f31a4457f4558865
+4bf21d554b39eb23850e3a10c2ae0e7369c685641f6d8f43936c9250768af2829cc655bc027fa6
+40aa14b18a70aa3a7552491145e6a7df0d81e0b7e1f3587ff086712368c48351d661add7e96a25
+b33f9f1f777cbd3ad42b6786c8b0ae23f5e61421a0b660b7381809f13664aea3067bad45ad8451
+c40e07f38f9b6185867caa2a9ddc8c37647c6b6a77d281185db7a56c39cdab0ace10890f5c0d78
+07fc420a2d0948c3880dd22e0b6aada2580f9a635d12a305a89415a24ee12b834a6d01e9f1a756
+b492f4aab442368cc18c700e1016014b12e2ca27f141ac3084ce37b42a4c41d41a3ae37aa2e400
+28aa8f3dd3f0b80df124f33e60d97ee975dc98338c7d2290544d8da601fdef3da00db855237a17
+4cd3dda0a9a404c749c849f5592390320053c4de8004c650117289b8f0c44cbef09e2fdae18a59
+3f2c7ae524cee7e3560e3116bba293c02937b0e95fe22687ee328feb89d6738ebd1604031d248c
+eb6a11f9ffa7b2625d3ad21050df6f25d1bb4f3d5d269bbaf8d56d25ac40905ba0adab22ccfc77
+33dcdf3680fa85a94f65445951e960e817427a9126a9c767f263f324dfd34841554bedd86841df
+ba7e43986958d688da35786f0497a6d04fcbb6eef0d1e8d9575af1fdbeece6cfe66c574e615834
+6774b185fb5c4e3bc71b45b5202f79210579b4bc35b21f60843b811df3515cc0d81d665e7eb018
+619a243e72c29636b8d9366166797292ac7023cccacc9401999bedc5920fe7f51458d13eb772d6
+500f471416f079bee7c9bfc25a0858b10dc043cc9a219ab9a71ad62d68ba22432e1dfa7d7930f8
+73a9af0ceca0cc4a4667d1102a8a685adfdbc5a1b4cea2e9a94d1766ccc8f9e74213876f3d7bfb
+e0950006b11f656a37641f9cfbd0b23c19dcac6d9c2b5cf0e38d8a58ed42c7d37d88bb9a96ad28
+64fcbc6033bd464ca519c9e8b24e1033ae844ce27b866f2fe38b09d4a262867f4782f15a5a0e76
+2f76e1dae8062ba108e759c6d8f00ec4da4b4bff0e3b22b22fdc733b708e0c8ed1acc316d8677e
+488adff3fd5d912fbee47a55e583d814d6a77044767539c2a1b964f5a2522b482186ec9f957684
+f090862afac4707e5b48722a97df0d272c713ba3b611aacdbaa0ed665ce873979c55cd6a9dac4f
+b8aeca0b0cb0f6fe85e7c97088ac6f4ed2bce9a0d16527d001507702138709bcabdb694a61da95
+692e67999aa628b73837f53ca6892788ac702cd6eb52f8c79b92c866213a6126049797a48454b5
+3318cfdebcbe1c50fd139abe01c30feec51f0cb7e9d9a863250021dfe7c27786e88b6baedd48d9
+49dc481684e3faf67ca81ee76cfbd63b547d7a43f3ec9ad09b1bc9e31462a43245f40ee9f0cbe0
+70805a1abf940f2ed8300be39fecb86120ec4b0e680d890903458cb93153fd2ed736b87307aec4
+beb473ec4935bfb0b8c01ad84dac20d13b997a884930e3c6abdaabb083f6f66c5b936ec4624fd1
+d1ca39011688ef21faff4f69b93f7fe73a7ae036c3d15f6f5da6838536f3fe0f7543f3f9460b19
+7a7892d6424ba822cdcb26e2b3dd7ca75ad2710b9ab49c6d5810f68d1a0426987f1e462034ddb4
+aea10e8e04be42ea10cd8552670f9251994dd8e844245e97a5902b65d08fd41013de3f3cf0cd6d
+fec75852ec385747f789cb0d846d0d8f4f0c823fe8a6202101f2cdb1811cac9e719f54bffb04d6
+46ebf824a17db7d78137f4e962f3fe6a19fec02697503d1f5c1a467799d2c347e8f85395eb9bd6
+3f4e6a52fa05d4a3e25700b4de22c41d97c719cd5a7576a3dc797c96bf68c5ce7922a8fc928d6a
+a344fb67d4115cafa38e82f75f621c9153f7f2f9e5ab5817e000d5eba9a789eae7831e1a75a382
+c6181a130b0ae6aac0e5cec25c567f1c3eb72caeba74fcd4ab5da3b73412e76399a56533ca6044
+f2c2df96153ea47213cdc057e3cdfc8923b80543e5c5b226628dc0bece91e30fafeb8d4a860c90
+021c1a996d178c6c85e9be45f28edd3fba26d6ef2e486c477670a17494c453ff09074c083aa8b7
+4de9493f207b555c56e72fdb8867ccac10f060675e0393d1e5c6b2f44f08458dfa45cd4bdddc3c
+e3aeb5c7afaa73086cc7399ec8874f529e4af63bcb4df147edda137e552ca22f45ff9fa03ac41f
+724b870d8656fd9bb93690eeb0e7df81e6957e602a0159ebf6692fadbc46c9ded8ec229d9bb5cb
+617518127e557671723dd8768b1ee594ec29c4a096ec4fe6192ec5038eea033d0894c70de3920d
+1deac65b4fb001ed0c851779ed7154ef5a848257c973c7f02aa72c1067dd09b13575a33d313796
+9d683ebd38e8b61cf62fd3f4e3ce98c266e088aef330d9acb450ebbf96bf63600e83f13152eb03
+53801d2fca3e18eef4f1fd438afe54026028dfd703cfce0bca12b0d2fdba236918d27517393dc2
+ebd744f78e3dec0ce74805418f1a93252abef1ad71acc1809460a8dc42380086a593b8167212ad
+7ee18288d203244dd3a2025b8449c47021ff7620fb89d3ed41f8547bd5328e7ac7cf5f0ebfc314
+bd4afa8323d0cba57e98058af91ff4002edb452461e95eb2bff94e464bed868dc3014915a91070
+4c5740a1ffe4eb3caffe27c199f573a2b8310ef7dca5dd1baaee4eb5add21887d9b65246d93e36
+a72766e664b83245aea45114ca3c11b50d51d218eddd1fdade2aeabd385ce371734446745552c5
+322e029c892e227dcb3fd626cccdbb1731d4cd23057686833fc20906fb3640b2481fdadf09ee20
+e487556f5dafb429d648d74f57c8f6aa04f2ef121df2fd850667df1668f97d7216472070848408
+61f2627f31e8858bfe5851c35fdbb4a81e41645ceac4873fd2447ff94ebe8b83636578eaed2be0
+3bd8f283fb6832c10a917d9ad056ac7ce149186b5664cc52cab3939ef44f35b43bf33cf06416fd
+ff848179580a7c39732e7eeffce44f7b24cfb288534f47163a273f2a5d9f30ae802af8ca1dd90b
+b7149e3c3a3082fa471257bff78019380b1ac8238b735666c2df052ea0b436789bee7ad5dd407e
+9c20774d5ff3e0af9187e24065dc9a119cb8842c5f37421d005f27d787a611a8f52ce76aa34ee0
+ac7236905c28d6d9841415387be7eca5c533ef618397c89f3df4cb86ea2e38ec497e380efd1274
+3f6bc297629e86fd88cc269eaadd0dd63984e253caa270ac816df54077f7981cf1f1d5a77aa46b
+7538794d9d414db7f7eda8831fd123f843b4b6a963648b2f31696932926626e040cda63af93f25
+d4a6e304d3b05c171c7186f5ba239f9e2156a0e9d30fd016aafff969eecff0111120c07706f095
+05359f63199c3e19e8142bc84b7efccaa61b1f13828755bf18cab9eb638f17c3f20342f60c1e18
+50332c16c8d21c2640dbb93652c7cc6469486584f2e036160ed2334c5cbf3b343c9c20fb460fe0
+492ac14315bbe89139796ad76f219f2f78aa252aba529db54863fba815857b4369dbf510ecf4db
+2255912af8fb0a1d7c1a2d176fbfbbff0182b969c8b02780868d2267b49d78b449702c46d12673
+19d79a101cabf6afef50a912b2fcb8482539e49e919f3b1270599e8ccd1becd4fc4b973bf1d412
+764dcc3013c707039fc5db85b8c4759f7fb9be1fd2fc5d972e117af55ef2586b4441a440f35084
+0210186a5ed1e4019761f7b460cebf431c6d564322cc22362d93433f843166133fdcd079db0f03
+591ae83885345c227b918e762e71db2b5e86653898d20f80c18c7f811797cd7f4a0b3c6c5d3289
+c5fe808a7068f3d19e8c4ae145fb822d59d2344bd47dd56fc4f2c7237119a44710846bae73c9d1
+3db5f08114ae8fbf644831e81dec6206d933c007f15c0c0ca65091a451a3f4268529df3d047f8c
+04bfbd7d7bc02b76fd3aaf76991f6f0b2b4b6a4fb87dfb7281a260920f79aa6c0cd16bd15de94e
+8681fc684280948d6279ca994a078a261860c868d0a029c70f80903265db27ed97912c5a80e648
+aa078a321e5cb431c0bb2a9d21e9929a4ff4b1f9dbe980bf7ae713f76ba86fd6dfc798d7488b11
+5e7c30d1068322010037fc6c9bcc6182df29c66b2477dc0197f1ec7f48a7473b80a284d917378e
+89b79c9aef1e975fc3edc7c60ba3afdace73264dd561ad9478a3cbbf9858978620c79c09d660b1
+048d3ff8044dc2bf02d1282e396f5c6298c30f3116285c16d3262630330c4fea515f629d480bcb
+aaaeba211aabcb932c2c8c9cbb2d48092f69f11c221d9ca068c529213b4303e7db0af9ea0ecefa
+45fdcfa5478312aeee4e7ab6d393b8b578cc181bde18d1386eee5ecb8aa46d9c62eb8dac91fc33
+75f93917170a43c2fb48ec5bf00d15c5fcf1d55710b6801ba04b406ad183dff76e19ee9526e6c3
+8d5c2b084e8f36b7a9b168ff8d2027c20b0d79d120a0785a35f93ac1f2a7319c65e68a4abbfd0e
+e8a3e9b14b3c5f230482032323b501a82424aa3256af1f7b5de145b16848b9bdb70bccc4f83c23
+1aae58de03afd4b7d0c7cadadff17b2dbe285300606de214cef1c6241d2f2969f0b9741dc34d8d
+fdd30331d8fb2b12d3bffc004ad1e9bccaf126e96a5e340a89e8a91a9eb19ea03d4886f768ce06
+3c702f25f5ccc8f473f3a4b85fad95d7a92d2e3318f635bbd79a8a4eee3f1208e9e69a7d63de37
+3262d38eb8ac6121f3df1bba843a961b5d3e7f8735ff641ea99fefd347df900b678758080fe745
+538c9d5ad428839bb6840d084a49b2cc475319a99b33a178a4b4f24e56a9c2519e8c010f81de92
+5cb895a446c87b63ecea312c8b230151adf735c6b7b158a1d655e44e2f5c77c2b461b97e494dd0
+98fdea07d1940427d2a3f2585abf264bc4edefada3790a85e0889e90e45c38482909b802b8c4c6
+78e1129af4382e479e49a9e406e7120b85955936ffd8a40f41e91238e4d11c7e660b902897e974
+6f9948ec29ed59c91597ab7d2137149edc67bc432e470a404bb9e6b1f98bcfdf1d49389f828e3f
+35c203a3aededd8d4d3e6617c959d5c401fae6756223f2ff5b52134cc2804d20bb08498b8d00b0
+660fd27b4511a9a099a8487b7622184d781b47453611484da293aaa6b7e8124785991f755bbf68
+9c4cd86e573f40e4f9cce9ffb6c5a84a419e32002acd3392e677cdc2883bddc975bf0550a41e7d
+5623d745f389fab05918c7cdfc9f49327eb8c4a59fad6ba52b0f075fe0a2851fde85910cf5cc95
+90b7d7bea3a1a8a251e37f6a20205b946b01da9adba76d14506850b6e634ddfdb3c853739461d4
+28ac3349438634bc2c4577fa2a337990eb7bec05a6d9b90cfe70856680d5e822480f77f580c3a1
+e82b87dc2c2c554235da6133e79ad708786a8fbfc34d813f4e4330afbd5e03f7ef0875a7a07aa2
+01c7e71ab6a818afb9399ebfd88e1d438e5d4634172f2f7000c10112692c4e9f0273a8db1c559b
+2e8d66fe93521514d2896b7321372d441e1e7c63edc272b30b6735ae53ac1b08c352aced8e8e56
+9d3d3dc4e7b79c9a58310d03ac8d2760522cce13bb95bddbb22a13b13cfb78bbbf43cbee6adfb3
+33ea66621a5616442fb9eb4d5855eafb1573075650d05b9b36e80e8ee6e5a4115aa1234ef0898c
+52ba94d85072c4da759dc246ae56ea526be02430ffa280c4052cf73d6eb4b62c3282d829291772
+63931d89f27b1e1dc8de5ecabd3e348ae919c983913e6ea48b21bc0827807fba233c132aaf170f
+20b33ba72160f184a3df9b130e3bd09301e12d0b22dbf56ce6fc87ce156de4377498cad735a6f5
+e57840ebd7706ee44c6b44a9bc0120cd4f50720ba4b4f4002e11db98d7db9a31a5c300d81546ef
+990481b7f9c278f0853c05b0fe5ef2586b4441a4218a64a07ed2bd6c547de31987297af9e99f16
+ecc361ec2650cbfc0ca9b55cb8f5b11408d58fe29e46eb31a0537fe757800abd0f34398cef4e77
+362a140d3ef6b00e83e143656b00cd218db158d44f5df1c5976fe708f15e32642e629645f1dc1a
+3d22742637a809f2197ff9a60d1f58e74d0937f8d8cbf0b0de616809d91cfe77675bc90ebd5cd4
+4fc09ca0625e8cd6144b620bea2183744d33c42e535b4879ee3fc032610eab99688a6e80081516
+4ce529eab33e85cb2a84ca3cea8074039a5b0b9e2065fd72389d02c6608660adcdd7ddeb2c4feb
+5a32e3276025f5c3ff65bf4b01473897164745b05a4c1e1dbaeeb2506bd306e266e613b16b93ac
+0f869aecf140786a639f9856d2f47dfd448564cd6067590cd7c75bbe8b58eef67d2ea38c965e69
+c090c242e29f12dee8b4335b8ecf7ef341de3a30892c09ef87913cf5147ae0cc255e05eb602420
+ae22e8c2754976dc6ce94fc477f330dba72728449d459b2ecfecec62d0be91a9397b312a7d46b0
+cb7cfa2fc664397dbf9a50bcfbc63ed6fd6a7941d36a37a815cc9290c79fe24f19d1a5c1cf0671
+a73c6c22abb9525618c9a3a9909f1850a9f470d2fde679c254bf516641ef96f46574633a94bd7e
+c9890023100e55c6a51f1124b3dec6a7fd42f63499a1066d8d27a25819a7ca1a979e04a8f1fa55
+d4aaa3eb05d8205cf93fe5d372778e809ba05dfb1e0a1e60ab6d1140d4c0bd8e2db88e7d68eca8
+e3f3e2248cb6fcd2919c12d60bf4549cad356000877d0241f7f19487e8c2b17a522bac5a91f864
+630e2ea4d2f5b7bef4d091064ed22d2f597d18c9f04e2e2e1be2ed884cafd31231da6133e79ad7
+08400c02fa56a3f3f5eb56a713fe068d4cf564e7e20dec5cd4696759cc35d34fc0efce5bdda7c0
+2eaad828006036386ca3432c6c005aee97bc884afccd3b642c0a17f418e3f2e436dd02237531cf
+86ae391102b2023ae0913471b6797a8e71031412ac87b96a7173d5a56332ddc5811f8672b37795
+5fb5e39f90d787ed2b0cdb81866f79165c8353c9cc1f0924b5f4ab6bd5197ea6273aed03c838f6
+a78bd9c40eb8b71b436c0803bd569c3ae55ffac24dac9de63cf6f851c5e2199c11d9da77009e55
+3109e47298f63c44644470d768725db00743efd4b012665664b3f663da65c6329da22e64b466f5
+6bb45e7afa47e1d2e8680a49fb4948a8c424c175ebb3f221a458d75f3f84929ba4716c503c81e9
+baf81999337a0e74d9c386e2b46aa7ecaa0689e5b00465cc49f96f7003d7d0bd1463372602a5a1
+8bdf3e924493566ee07b37df97814292f85845f2cdae528cf8e6d40b1b4c7ab83c276f3d9712e7
+cd00e96f8139dee7bc8d17b48a57a39210ae727a8563319091fb1944279c1e670a24093b0d03ac
+8d4a479d2eead32e98af57251eaef7a6a110493471c97c04cb50fed0461db5d0f89df4f461b67b
+f479fac30463af0eb0a5c40b3ada200bda798ca929d04caca634d46b3fcfc12980c2ece9439363
+ee588b4cfbfe1adf3520a28209e59572148f5dd6e4891d9bdfb2525b5d4e16fb79c13a65e1d687
+2b1e2ef1c761d1ba66ea1ca508c2a3bb27a32515269ed4377d1ee7ddc8c94c4078bc4b352211ce
+a13495326faf27554edfc3a8854cdd4ed995df19dedd2beaa478a9409a77f75fc1f4d57ac4352a
+faface9ad01b0b621cd8572b3c65878ea89e3f43269e8a0c3854c1454418f7b0b385044a15ccc1
+823961ceac3f500a09579e605f92f0bbc9f2d8168c50cd9e61b84e0fc17ad73c36227e22447b9e
+f1296f2fe302f23663deef0fc1eb759acc9dd1909f369fca5564adb3f0b2ed33428c75fcea4caa
+c27e7e2ebcb3f50fe19f3a3904eb94baf40c40bfdf8a787e622563a2cbf6c32de0eb309ebbc440
+2e31bcdce135d63f42f314928df9816b69e19f732539bd00b5950b5aa8fc6cb3bec0f14e60c3b9
+7423680fd8158fae9b076f3d25aa3fd81bb5132f9b1f150acaf2cbc0744e0d4f42b186af0591f1
+6f51eca0ab48aa2525dbbf629b4754f23549f1f9a88d2ec444c26f28ad54c9c388ed9c00c9b2f5
+a19a32fb8880c47ebb8016ceb36d0cc17489b3e4e552984ff17ec5388f14541759ec95282eaeb4
+a2d6e3192cebedc3526f99363024cdebb040b3da29dc93b58f6090f2f5bac6c67c8ea488b3f0ef
+f0d6228e20a5b865bb2d1870e9e76c9663fb32e899c3f1f03507e174af0e77433fb35748aba9dc
+78f419fab7c9e508f73824460a7fe6ee23fca964a2839043a19ecb24b15b6406769b703a3b831b
+d6c4c82ee4af7aad7e5295f85353c7d3476119fc664568089a3350ca986913f16002e2889a7f09
+1e02e3a400cf8b83ece85176f96fc41efa93d5d658f45ac91e6e566184cc0376ebc6c8491f09c5
+e6b12eeea7e4e445a8821e03a381c468bdef4f7074b631a3146675b53f7539b211e0b3b1885eb1
+73883c4cacf1223ef4f6dcaed8054c8738fc3dd1abf1566be3b4d8e99bc538504742ab18cb9e5c
+f97c9e5284aba6f591e2d87f00952d0388baee7c3ba1182073481edc7b9c0e761a85a1643941fc
+9a0bb39252d59c5b0abad385ca9296546fdb9faf2bd384db91bd96c59da8250df2b5d125d0b254
+6bc7e2c50ed4dc568d8f1b65b6f327842bed0e7e910e44ddfa302f5b30ec127aef3f02f11dc0ce
+8a94bd9a77c33c8e366ad06f6675806d7f4e77282f88376fcc8e1772e41ee7f1e9cde177b826f9
+069ed5c3d3d0b4bd54bd60e01d4c768cb47b27624853fd9e3760387debdb46d9dfb6da0f7afc1e
+1ca352f141b9039c6d2f3ee7ba88dbd5f1a0db0753962fad600b9245a3a6bdb0bc0dae1e65c3b2
+7bf95a52353bff9d34d860a5d9de8ea0547b9100c160b7b631ef5d8e2bdae77d7a915788bef9eb
+9111d4d7f60f0329462d2ea14a7da9289922a575fd88a52c1aa98cf1f4f34b705464336e3ab7cb
+09d81e427e3bf24e87bf7147dfc0c52e6c67205181ad234ca1ff0dedd467d4a13bf9afdc6167bb
+6f33a47f1ab1477ab32752c256286b25438259a143a6d95b2c6e5dd38dca03fd6c803782dd7dab
+0c7c0647f48a84a163cfec2ce098a2ee99d2b0d46e0afc85091c8402b36b41cc096e733d3e7252
+c2a4b58f54369f049d0924a6903f8ad3e1bbea39e25bfa05815f79eef03e1748b2d581fe117ab2
+e3c7a8f520c194b3c5e98fdea58f19b4e79d677ad54a7fa485a7a9712896618b0c33694a3c3467
+a245c52cd39fe9730e7c2634d298c1638a0c7109692cf258f8a6d0bdf578cd28f72e48176a9599
+93014e050a7d060918fde0a223eab19396cca9c895a0d5bb26eeeb9190df3f07e2d6243d7a8454
+04be35983125b133d37bf15f8c7cffc8ecf514969e23fabd262facea11fee56fa69682307719c2
+16b7881b733d24403eb703c288cbf898749f3e81fe24451e063b3c02cb2ef8dcfc36179a525662
+d47e0e6325b93d885973935c91cc6c52749a939d32fa1f5a74b689d06d161914dffba8335c544a
+d8c4e83522f403157b7aa2ab15593a7583c684e472df545d24a4894038195781caa9f0f49a66fc
+62fbd0a5155743b7c17c9e6ffae86076684c20a77b1e74abf75aab577b93dcde8c3ff60aed1a87
+ec006d276725215681e444c21acbb6318f41d175894c303738994c15099f4021950a8b389dc2ab
+91b74ed57317f7faf10f00bda6be25467f05676ac4192c369ce03bb374617ad5bebcc56ffc07cb
+5d8e7da3e17b7ab3d9d5dba4b8354c03a64f02be62ef5df14b9b9376e79a803423bc55c5cee397
+2f75faf61dc41d1e8415ca55d3cf7036121cfe771be80b697389c047c601dbb8548f0d58ed841d
+25531a41d8664730f34e2b187bbeb8d9c16ae7591ca61fb2ab36ff3b6782c7e97833827a1ff866
+44ae56f463956635883b55891a08fa707e90c392ae4721fdb0b2311f8cf00a4703faad8114b615
+eef9737684a3c53ca307abd11558ce0810db4d94a444fc6babbbe40f3fca201d7f66ed5f834d33
+eeb1189648d68efefb7af5a080f1b6297b75e7815b4680e3c4b2676f3c763fd9d28fd00374c2ff
+2697bb8b96ea13cebdf68eb17001c041d24e19c97d33d448f4d6aa3d50d8720b0377135f30b479
+d973ebebb93031aa1faee6c275b21cd88852d903f08e2629066e18bfcdfe736b208429a99f7420
+7fe3f156e82b16cbe3d401aaf8ea2a417a7ded77fc22d8f047685fb642b7e25a50c5141c1f1f38
+a14ce3c0b8b3447d8f48de07c687e4c4cf69204e85c6489a3cadf29ca7f2363308621dfd1f48ef
+e47d7fcb3f67441ce965f04f42b78d23500d25890201f30d13dc767cebd955da0ce6f6411001fa
+c35b8ff9762eeafda44864cf1fd2f8c5c006ae8afaea913ae1c75765e4d6d77b7e21a6d16daac8
+1366f23778d2c5b9a64872015bbad846c77d4a9b93353935d2b6e57b39ebbb02993c18f5228d99
+a76250b85311629162556dd299f7eb2479c705c6e477167faec90ace944145a22a5cdca376cd2f
+809ee685329d8ae45f3d29b2187bd4077b1e7c5889aad999a67759f2b649e82031f198bc592bff
+385a196f4b9943300e1c9557ccad85497b9f2c5ac963b85527302a1d7c42d5d5c8c58328318a64
+10df0437225eb017494c3aa09f129275a02d0f0d2d5e24fa35a6b0112435d63cc0706491cdb6e7
+5dd957789831d30481e3b8e52d678d0990202a4310255adefea4a4b48abf4b835d35c66f7f279e
+1d7cd4887798ef065d2218056e2374c03c99fc2e17a24a9e70b49440f5e20c8806dc23e1b1b545
+716dcea57adc5e40d7df2a7a259b559cd37c2d8fb1eeb6731601ccb46af23de0ba8c1628f4b88a
+9b2d468c96730bff946e66a5d200ae32702e6fa6c907ca03518731f60b1252a5cc2dd1f9bd9042
+8c2e0f0a7c54d92afc89333da6a83c324af0629a26996457d6374437d9cef97bb99eff0e98a22c
+6b0deba1062f3c48226dbc9a5899cc864b975bd1f082d7e511a5b4cf9c0d7f30d371f689da42f1
+1df7c18389941337b9c07e1cf5f5cbf33e400feb6f4aaee60a026da25d51a3bc14d427d37fbc1e
+64e938a4de50f52578768bc70ce533272db34369f898761aec2c8dda5931f895d28872ec6f209d
+78be4f4ab8da35f65697c57405ce7ae5541c9ff509d5762aa6297e7a0194059eef3a2ae5d59dfa
+d4e9807cba47217ba163742c83f8205052cd729ed6f8c452af9712dee557d4bf8a303209d36bdd
+db790812c4e532165f955c981339226c4ccdb89f78666953c02eb2f38c4cacff62da858e16feb7
+bd379b92d9420a26fe2a0aa0c71e0640001644137c538d2da78a5403cae324705be07519a4c612
+4f4e299c41497f23ab3c479ac8e309dc694cb84b693a40ef5fa7d4eaeb84e97643474253f982e3
+8060a81ef3deb08144992e048e8fe2e9719ee6c840e5be01142f4a62ff3f2f1b1d70997f1fcd18
+3c5cdc04d67e5f46f946eefd6abbcf0170141516c7bffc2a07efb440dce1ce888a5acbe4c407c8
+fa46e28d20e7774d2e374e224b991242df5a20cf3be574c410a1a88badb054b812e7f3ea575682
+e6a86792ff4ea12bb43245bfdf588df7ceae590954e88607c4201efb34b2a9cffaaa392ab52f72
+ec08de1424d2420bf7b82f2a0dc2aa083310b4a6f2a68ab5ee8384bbbf4ed9f932308c2836d6de
+8da231dee2b4f08790d1653490b71ad5d0bed41b06f659f8c3a771b82c8e58ec4e0a0c5a9f7f98
+74bc6a1479b918050f06e4d1b49232d8b44f312a5f6666b49e54389c18e7d89a399fac13ea6ea5
+84dd48ac68c0ee40d26e4f2ac32951a3aef14c503c7ca2d05701b756990b9809e25384b0815fe2
+bf5084ed21d8cdab1fe3cbe15c41e8a94336359df9ed3a43c529529a9e7f63d8de36720e108d1a
+9feb0b9ec91379b57d2ac8a6799176ca5d5956ab877d87050d86ab917689c93652b729d4746f6f
+34de32680d8ab5c5a4565512d6ec950a60f5b0b141f348d1934b4f3689640592f22d1c1cbcdd51
+16b204061afc1b8f15afcb06f4c44905d17b8e44ec96ca2888b34eb85465ed2b2620756ed963fb
+b9312883c8aaf4870c52eb032bb5cb7458b2fbd796b670e972f576dd3941c76cbed5c40b669f0d
+cb34b31d295010975536989bd2a479acfcf324fd549b3e41bdefd06f42492c36d8c0201d2526e5
+3ad34e552b2384e39836743766e384e5858f33ac842cfedc28022ee8dbefb2a2c3a408a6be8482
+6023124f7eec8295a2e1079480f30eb64479f2673da8f051267142dc54e88dc8dc4ef41036f1de
+1b9a198e5006f8336b29720288c9f2e545ec8663171a280273b1626f882c6894be2fa2532c2f20
+e4e24f1406c0627f9cc4021cac67c83a60b39f1849b483757f18ca956ec3bbaea96cb0e2a10477
+e69a6040dc3b5321391af5478fdded8730e825818d960c6f4a305d653a732f1c51c2ca3e3adc4a
+3722958d50a78359cabcffaae1d75ce79e72e09a354c5e805967e30ae708c109ee75ef233df667
+82bebc4c5dd9ed6ef0a50eb2693787576a19b42e70e3d0c073fdfe1b3562083bc01d9b38868e64
+b8ae90b9f3164e2a29fbb1f1bdfd8ffc2a842ac2f9801d4839c97f4bdaf1466038eb4b6975e777
+acbdd875beb59268f0eae6d3a03c2bb60bda0ffaaf77c4f33d4671ee85f301521557a6f323f1b0
+d060326fd87c60f65e4220b7fdf85de8f0ed64661fddba2efd3374fc45a507437a1ad2ab4938e4
+ccbe2411ffb70718397e156d24ab018436fecd39af252f3f9527397cdab675b261045194cb3d3b
+5aca47c98f1177ca1322775aa8c29216fb7f8ce0fbe698479abd173b9541fdebbc3cde6ad12be8
+16108a049d5462572544912ecac19e6e9fc6dc06160904e7bb14796e5becff4df3a8f645825c9f
+59fb419bfb5ced8e5b449a2e57adc9693e9d34e6bb5a600d16189bf146f3dbaf4f75d16b303a32
+2048ddc0de4a91156aa427f1b137a714f7ec2a4aaf612de4819dede79b78c90a86c901278125bf
+2999c9acfd90a866830d00a0f1c83a87cec69cb2f382c935bc571ea3b53fb22664be95d8e95d22
+9b9985d992dbc6439f0ca52762b3cd7a4a50973c17de473f987151687da95caf1457c524a4406c
+98bd025f353124da7e6389a921e56de4d1ca7901cb37f051b9d3b78709640530cd549c9907ee6d
+ef35aeb2eecd1c9a1a4ae7686da61b848371dcacd9f02cc320f29ef144a10803df5dc462188709
+a85504074b8439c1a3a7c253581597d6f94289e7113c678fae406b6586ec40fe51769903be7225
+9817704579212bbe802679ef21f7578fae78d1f8c29a5438b656f13d14ac4b10d1b48d83dd1ec6
+e569358f9dce2093f319f9d3663e331744bca142ec6b901acb9b5594ea7423072d96a61e523336
+059c1091823b03dc675671cfc688bd2062830e0edf7a5d400c680784691ff46bf4d8853a42c573
+20414a0c7b838bf2bc33726d8a61d11dc42005b909b241b553c37462ba057c30e7bdeeb3ec5513
+ddca5046dbf783c780ffccdc188b5890daf03c94c8bbeadd2e33e95a8bad7cf8c890753d607e1e
+74dda3963d32cd37ad2d0eb722498718df3827236d7f073eed7fc3c0ce0fb5629f08d4a71d1825
+c4d158ef364c8d69e8767acbaa92e1751a266718d67fb61b4a07c485cb887f04bd30468bd6ff51
+63e5e35c7b4bf6ead5db27d8690d7c54b2be107d8180396ba6046e8b1ec7f51a624a52ad2f9e25
+96df52d886aa0f5f0316fb0a6ff881ef3cf2a11debba86921f94b6ab18088a61ccb125c7732c36
+81373e4151094543ad56ba6b5b915ca303a753a65aa189f6d71bcd8ab565ab5696b9b0a2fb5b7f
+eef3dcd6ef83f859fa4be52c24c31ec711534577aba733b4f0ec2ca742f8bd658d7646e6af057d
+09b504f072b85e8ce75c51cdb3b17d34c06c1ca57b88e7ae944d289bcbc1f7ad27898a703c0b2b
+9e0dfc9f87a6b2c1d9ea2cc05fef8bffb8cffd8d8246ddc86e135a8361d36748680881d25daeef
+be63d60e449d50acc1718f1b6df6297849d31eecb6c990304d5e37d6bcd83c17c4ebded22db524
+66af31cdd0b576d69ed50ef359cb44507a79462b282504a48a4b8bbe2ef617837ae266e3ab90e5
+f45647ed6b99c6d8b6121f1f7771f75b76362f01bbe8a8b4268d4755c7b613b2faed3f108c29bd
+a855012eea6c22210f618b416e25534efec4c0f6d0feaa4ce7517802f2ccf54c96c4b5b9227bb5
+9f8c8a49fb435d4134dce397f41f3b6d295f6453b9483c3c1d2ffd47a3199b370f2f31b3772afd
+59d0135ee2970b66acc4a1a0d3a18be2b3cc0a8a261e9dfe32b1a63ebc7fd99af94cabd34eeafc
+a393ab83b5ced9b4e60f868e0b7aad2c2f21b0d84919f1c1598e6143440481e3c4a97750300f7e
+0660eb65416215d13d8f546f74c4700693327ae762ef61db4463f3644d534a3b4127c06741f0f3
+394f395ed384c4139b7ffc5b02185dd9e9fc4a9a790d91eda97f8262e6327779701f7440a27120
+c75242cb2e3c5570399c648b21da288d2a9d610dd11d5f9cfae9aa1caf9f05437bc137d8cf0e83
+272ecdec1c574ee6880505f03fb673c5ef5e31a674d1fa390de77900b9dc1fe4d73311032af31f
+6985bf38005fd3498d569de012062aa9c4e5baee3ee651230cf8f06f9562482e56aef639b4e9b1
+4fe104d7a4e59d9f59ed573a530fead02933ab576a225e00d4681821a6bd294b96c9f73ead9eba
+509ae5d9008007ece9e52dbe377e161c5b5e1fe556db12e167595ca9024a24c72e65527e3f4b94
+353bc5fd302dcd2343dfc038950bbc4c1249776e2561a90c9a5ca9c045f6812d9491a77d5f775c
+caf51b81f299e1f9122c50712fcd660bf649f6282aee3c072d41bfb68cc3aec648f2201fd414d5
+0e1375dc1fa058a80f54ef48522715a66f46b0da8861864fdf8e22f6e47cb32837b34ffdc5b578
+717a1119c6e7ef7566c58b373d111eb6c2bf1e9853d13c6223fac9ad3123765163c06dfc0637c6
+92af835e89ebecf5b37620104cb8f17851abfa357e02703a059d960d9df6f7fdbb168337708e7f
+919c04c802ea2e2b3a3babf74eb86e63de9b8644627d8985a1ad3b8adcca509f7a7debdd4634cb
+f42715063265b57d40eb7475423c3838359cb5a1fccfcc7874c782cd859ba71d5f114991e6fe5e
+557fd360943786fa161075b6783140ef30382f184be07a3b0bb616442a4a4007af227492a99485
+4b40298b9e9b4e4483dd252b2230f1f615a122918f32c3ea0a68805fcc73bca40be7f3fd94e698
+d0a65005a64dcbb7d97f60cab183acc86762873f18b673dc194cfce103f07cad09c8fd6b1f532d
+72cc86ea99ea24a21a41a2e09837093d5e1f1e3d74342cc4466d9ed9c1722d8665b00a9f254950
+c286426737b8690914d856ac20f1bf27180e6f9b00981bc8b3b165c5cc7e02a689dccfd58c1b59
+39186c590a97d04d5710fb5506bcfff05f8c6241c125e300235afcd2311d997a1369783a83ee1f
+040b8fe44804dd62ff7e5e77dbfd66177a934eaee33737d643092a0cf65e51b131a7ce8e502102
+aba1a8a68b8d95c5b0651c83214017ea2bd5e5a52d7e9d8afbba7cd22bbcaae087ead54739401b
+0d8acda7766d94d640feecca18f1829ae75da4aba8485bc9dfc9c67409c7d465f54d740ccc8ed6
+452872082bea2773fd5d646a809f5d382b69955db3a56e61849017f103bec6de80850132002216
+dfd301110250985d8241933cab0ceac16e90d929dda1d3169a8de16ca98aeec1bf59b9b4e0ec46
+0a2631f6d3ad4f84fde5b5dcd29d53afbc6c8a3adf15d234b13de3fce52689a74f49cdf2d9affd
+89a098d6fa7c0f93724a08324ed1ce7db85034bf4a67e7d0573db8e2fbd09e123156b2d066bccd
+9db05b87cf61545a6e219009452b7541aba3802cade07019910ced99eccd026725d0853f9f1597
+03f449d1e1d33902148421d34f132378dd12d9e79168bcd8dec5bfe47c862adbf7883e46dcf0c2
+41e068ca77b72ce9a73a3ac40f568481f62d9f36ede5f0264c4d8f9b2ce03e19e70a94d0e467a9
+832efbacffcff9efbcbd405432914bc36fcbd16c4c2aba631f8213239b69f183482bd292247042
+7fbab78cc598a57819dae5e3321efef1fdb44e084a4402b8cee480242e42dc09bbf208042dea79
+68a643851cac21aebc1ba2740ac999d965b43feaedc8c76a32ff8d4fa30e2c8444b01716af4878
+ecf291309cbdb70c5bfbd4134ad5d044a04a057405a91e1a1ef15980383cd4aadd4190904d5528
+e55138635714ec3f9d8e0fe1bd1e8ed4b742ea90572f1ac8d01e711c074a4125ea595fbce07461
+21a5d022d16b2125a1577850f6d1010279a5dbbf135eb8edcdcfc459b7b554192149c29327f86e
+477dd3d13fa5ae3a78cfb714c9a750067ba154407ef22158670059820c8041941f7ff5c27c016b
+20b867f83a9c8955dcd282dbb6f72bd2067dfc1e91373a3021be2be6aec5f90c8001878077eabc
+92639f5beb892bfded1d04136bb3140dafaeeeb31c21d8baf03715fc56ecc16e7dd11c12df0bb6
+8240772f2c59829482cf97f6a922c8c7deccd1a395e7ba2a1a855206c27630ae1f236606a3a9db
+a1404326b8b484d5d2564b480ee7422365234cef2609605ad9e24294ce5f5bdd61a479c33fe53e
+e8bf857e2d2a25dbbc9a1cfad3a5d7b2f1155d29367e318c8a82e1e0aa236b8442838e3deeb9f7
+455923cd769d28c1f780c0d3bffc275e0242ec975d2beb7f6bb5222b2cdd196e4ec94452050a76
+a4aa6352633cd58f461fd646f23758e343b5a386927b66ac6ef1acc84839f8bcca9f9f93f18cb4
+c6bbc663a951dd5211acd684ef945c10f156b5b6e1c182a7a580b3966716c334ddd9f78a404873
+a738ab6ccf8a335f1f6dc830d7d74e021bbca95d260b34d1933177e5ead9c2793d264c94e8bb27
+4b9712afb7862bbd8f74b4cce27cac9f29c086bb30162820a229e6d5c83410a8b876fad5b8a028
+abc067885b5cec60995550d35f60afd1da93e3dc14c42decd2b0800706a222e9e4b7d7bba9646f
+6a3ef9489dfb011045a6444cb599c62dcae4b11de7d8d98f8e58a9a4feba0e5f7301b795f4085b
+aa4a7085c5a438d0b784b21186787abf88b455f1e2ef19fbbb4501d5c69c22b219737aa5ceca0d
+0475bb6916685534448816d2791a31544769ff1152c2f2cf4c7cd3f64c6830522219349254d11e
+6ff2056a341648e9caf2fc5c6f48a8713448b4a0a7bf4f250df1f9ab9db798e0c5d2cad0116608
+a0a6190d8fa4f8e67f705d8dfc7cd8be652b13ec24beb159f97d22997094e38e90fe6e9f3d2a07
+ac92f1648c78e6ca7452481fb78dfefdb4399c62986b652e08ca4a9a4966cbbb572c4b2c8bedb9
+285372904836abcea90e91ee6fe8dbe8fcf718f4e0ce97b29be634db1f19b541e003409442a59e
+320cd38789b76eb79e35acb1e09f5ac2eee068664a0f505c61c07da5bbf439acd52feb4caac79f
+f05756472aada68f6aad5a1b760468859d9297e3ac4ceaf7830c09d3562c012d48cf7da5f93d79
+42a15fd76be4e90cb1a966503d32dd2fc39c1cd01c629b600ba6463288466ebf44a4df63fe2040
+67d6a39719ab32b5073d4bdd022933b5bb5652510919af2f90863be9f08dc507609487ebd7b796
+a3f0b029e13492cd0a1dc002d85b8da0d2ddf319f7e732ed40a87c984340976292119ab947b5f5
+b9e5e31e6023e22e6ef0d04bb9d9cbb7de56a1626c5925847300a6dbeed495b18deeb815807010
+52e4b37d9e0b346aa8a55621bf5dfe3bd1cbf2051e62ab1e1da21387b5f38c119934ffab0e8158
+107bc33f36a537996faf01870b85d5da02977ba62fb8e5d4878e1be660a6414c9084a3a5f05a4a
+2c3c1f311a589ba7afc5418e3b480c92f91033ea61d0a6a1f9e209226f2cab2d9c10e2b54f22e9
+a730ab8d48548cd28c3dab415b03a59345bdfa9656cbdf48363eb233dead8ed309268a629bbc3c
+6e2d85eab15f3b769afef377e4602fee3efe33401eba124aa4d4593c5356214c59db31702f44d3
+3f89196e09e6e2215687c448c9615c69d7163b2867252de9771c9ee8a39587bb374d1b705d61c4
+2da4a8a7ed8ebd24d1062d377fb37fd84d5ec3eac25d5d39bdc91f7c820b9fe806984bcfd3c375
+3a607650a6ee4460a24906f75b38f2c442a65909bb70e7383f9e90a06f13fa2acf0a37e59a3118
+5b6f9437e741571dbefb518dd564140aab4c91d37e6435ab9b2b376bf6522f90b5660ccd1d7e8b
+82dc3a41d34e2c39cdfa05f1e4a7ebdd3586e69c6ccc4847e086052dc7d6cd4d8302c34f4f0402
+daf9549bdd83c24c44a68cc2e0c2635686c6e49ed8bd5675749650a79e40588f4315fdb9c187fa
+7b4956151b7123f36937b06fd147eb8d51a8eeac5461441d24afbadc7922cfc237823efff1a3e7
+42b336e84702189c648ab7078d6097d8fd5f3baec947d63912156478662aeda72a501c747a325d
+1227cd4093ffe9a931367dde46d65857290ade9dc3d8eb73e7149dacc34c08faa51f9fa39e0c13
+d14be58999496dfde61566e68f83135a0e43cab3cc6395217a0845423210cb032c63d56bae6877
+3991e91f186b198105f165723e08f6db39e889ef3f944d339886c0c6ed8e41c20c0743864a50d3
+7c281abf47fba6d08728aa21a833f22aead0bc38d211caf58d44d01e10c2da4065a3082e562e82
+e3f1def28b5fbab1e93cc3716256b98ce87e4dde9e93622e5ddce60981e89ad0d70d0fa8b1638f
+4c12ee82a601073f84ccd47b631781ef34da22b5cd35023f23c6fff02973f993d7457efe579da6
+4d7110867d6fabe6b41b97e9e711369232f98cac9975d56d69cfc98530e76ecfa380311854170f
+98cc43596a3d4019d08c25e59dbc3eb850e026cd484644353c125e38f199b22ccf0a502d675d5e
+0be2a4df28ea88c3ca6b939b4b19e81ab728d3e44648830f0ccaac81f705d098c127f07f56ca85
+50ceb827722d046ce419a2504d8d6740cf9ccb5d079f1086dff76bcef4bd20e854eed00bce0858
+522818c8ebae755857d51961a9c61ab5367445b621562c645664f6df9f63a21246ca26d21aeb97
+ab2b271003d5734719358b16d2af5cbc1799c88b899e3c964c453e53de23d02bd3137cc0c1f074
+70d8ffea99d6a27e835ac56c977c149dfd13de3c0c328f8edd67c1f95953b9892e0147a245ee0d
+4e5912c7eba0b810c0667b17b545543b0662d53be35c26192356522fd7db85df65e5db4d6573b6
+c0c0f5da3747e6fd6c4a041525f7e48b56ae420995938a2229c967e98c8256c28f3a99b0739f75
+f0f1d250db34ecd7abcf25b86e6b94de40d033d99710fa654fafc2adf0118f750a07aea2c94f20
+5cbd091eb2a3bbbff77253122f179395e088c6b7a9f06ad421055622a1cc0538e8b3f03c4dec14
+746a49b2a19bb161ef7d5da64a4562e3a0ad91e4ad5a052d74c1473febc4f186cd6b73d48a895e
+8bbba44657d00663d5e76686f65a7ddc45ab8194be9fcd289e170994d8f17d4847080ec3f0fc36
+f811035bde3970e330f1b654034faf87b01b9981330b3513c2f32e13a280b52c92449525bd879f
+684edc107a40c02da468ede54c9bf7ae72d4c314563e55d9d19496d0f80472b2f3c8398700bee6
+42314f87fcee7e0fb9e4500fc980e0a9f755c71cd9afe4b3946aa06d2ae458ea77080c3308f65b
+fa253674be7182dea45a8d2c029a570cb3914f7c7cd0cf31f9b537b4f2f7cf918c5e82c6ab36f6
+5ac444ce935e1d14f413c2c005ce388ef8175d7c8e7bfd68640c650385b646fd00dbdfbb9e0ec8
+3d93f7ddd486a358a8493a4327d11568d3145b52cfbd0bd5b4d7def679906fe1297a16908e16b9
+de0a13986d5ebf4f829c4de8eeab729480c1372c0b85c462d02d8e6bb0c45fb26e4d82f0152eea
+9b745e1c20e478ea50110efdc5bf0164a678ecf71278fb2bf0c8a53a99ec0f46029eaff9229108
+234fa1624b5e33f9272a232f64acd955839b942f8f8cd3f3e3871a443f685149bc5ad0083f6baf
+20c14025309173788aab5568160b31e7f7ab6f10f4033345656fe958613d626e8ab7091aae62e2
+150d7f854d5740f601c0756b4d04a2f4ced1f833042b4ea609a051defe8aed847795cacc657c5d
+de3331323d5f21b24154b3b2c991e3da5de77d00a4577ccc862f035c10f2c073f85b97fb489a5d
+5a17d84d9ca133a018a22788ef86afd7c1c8952eadc6cf5139605b19df95546e90a839440d56ea
+29625d57eba80472486cae74bd099198ab8619cbb6fcd652774b0a97806f5f83f6e8a109eeca85
+cc7bfd19ae0cf27336e00d98d130f932be9752cbb97a14a44fc6407b286744ff893a26ede2d28c
+6d5a2c2369388cd6a23bf8e102d7014b3944afea96cbe03735db0e6e4922d4c5b2b6add56d317f
+3532fc50a410cf19be859075abe70ed195996f9b9afc7b1f3b1a5d1602fc6d55d5171ccc345e28
+040625e4fabb286990116ff9dfdbbbd193d503d5ff027b0f4a3b124f2e0a1e428379ac6fecfa31
+3fd135a6f38da32b37b3d6b877e5148b55aa40567b78d69bfc59681acf8c871507eb03518650ee
+ac7270883e7003ab9ca8a2e531516c309c31f67a059349b0f603f584c6d91770ded8a825c6f759
+cb3128bb928cb1e671c1684cfa153a41e6e775ebdf54f25d11865ad5972e8bf3193fa4044fa618
+bfb88b621420c86a5a30b4716feaa63197c6081bb1f324605d018e8c63753fab6f972670cbaa9a
+4946b9c20fa42c6e52c9751654a3cd885fd9efe11600771861ae0d026fe0dbe642b073c91036ae
+eecfaa08a7d85983eb13828c3903c532c0829802ff8b45e64e39079f65a5b84ff91b65688eb31e
+6d5fc58cadc44319885bda8d78db2aab9fc4a268e3397d12d51ca0ffc79929344f97a6201c01a1
+83d2c0c2702049048205649b91a784c7095b8630b00c1ee0af742945873049981540863fe38a4e
+57cfc8647c85c069296284599f169506c9df019471e0ca8fbc9abf7d1af1dcec4802e72bfb1d16
+138585e451918e0c421966a52ac29c21aa3822870959543691460c52ee43517b8588c365888921
+e4560d3e28f72358325197f09baea07fccf9d10b238659be645e0bcdd5e76534b21b52941a1e48
+267faae6abd43149987eb5385b44a422c0d6eb37c818542c3553452c97e016c26d38a4c0b53ae8
+b156167a5e11b861b44bc488bb2bb0cc652e3a1d12e616a502d1fcf31bfdcead55e2fdffc121ce
+85f525ba491feb547a3d16d85f65ad30e430dca5c603685abe8484d4c4144f91c5595a3fda9351
+e17f00eeccfcdb2e0465566192b23a9a78c14d62fdb3b1963c780f6855dd73382089094e921ce0
+9784e1f5408c620f6481d300d9fa6f8c23876a49281b0d425090497b767614696424dcecad04f0
+767bb7601b99dd3bc5cc14d2dd77c09101fbd3b6e725e5c68ba66a5a371fd6f3ca6351ef075645
+a3c03492f7fbfa225a5f3e01b962177026d94e845953d5781064633edc41fcfed874e011304723
+a52fe8ebe5d6efc5e69b9edf735067ba2d3ef221ee6244034df2469afb6056dba877ca9850d4e2
+0ce756a79a38e74b356019de03ca6651e54d1523e12ba9d9dd8e44dae7a920eba8784607fd0eae
+b0b456bad6e739e264aa0a3f4d5cc5584e072cfc8e0a2b949b4102d14fe3bbcd7ded2405718b0a
+7cd41deff91bd415340d6de94797c53cd734d14a11be9fd9de57cc35175f24913e96f95315ad3c
+66ee102176e59a3b669c0b992d1b6c3cc131b33119eca4fae72f7553cb977dcffbd5ea29728ac5
+a645eaab33042a0ad86e8b28fbdf79325e28c3801cd0f9d8a2b563aaebcebfc6540a3ea351caa6
+01ba8e5c5bfed770d61d7366f96d6bcde2db981b51e38ba35237ead55fa9c1cc2b3381131c1dbb
+39ddd7229d06e4b9d203d066666c8ad6aaa1a6df0d346f843205c41a95f72df3027c9e6486a008
+8f8f8e7c9ef820e2e80766fc706c4df71ba5801863b29a917a16abcd824d9a94c9081208685f8a
+4398004d8afa25087ba3fc81dceed46b7d6fc92d3b9557514899c5c97114ed722616b477ccfe4f
+4e1faba32e6a24a091a7a1067628ecc8c421f8a967c6e0136a9c23ef642100eb91c300975d6dc2
+c09da077e24fed0aeaf2876b91d0db63c4e347afd558f61344eafd38df995bd98fcb720ce19023
+c26e0b1157e299e18d13fc7715bc1141d449f05fc6bf234ab5af157696a354495e45a818f41a00
+7e601b49500e7554695a4c21c8f6fb67d7b81379f6d3abff7b059f277e48c0291852c6af3e9d41
+2526e6b23653e0283af4ff8f06503ef135f552270f04d735cc21fbaa059025e7e32cc7f03bdc40
+6a167be87ce1442f285aba9aab9f4ff91daed0f04eadcc8e98a6ef670263a76e5b77baf65f979e
+202658c06d0deaa83aeb577e4872a916a87b8aad9e9c9b22630d3b3b95b790f11f83bc6a52497a
+7c03264d70f55b6ee2ecf4f5af13d45df4bcefc85437ad3d9b78e565e3dadc353e972fc21ba6f8
+ce701cb9c1aae65b2ffd89d65075bd6a5ae8f195d13165969e08c20a6143efa43a31963e81805b
+584f93e1957713065d371abeef4ade6c3c024f37bcb2cc00895252332325359e6f7425665f46bf
+49ed14cbdd14a659876670d962d36aab38e75c47db93978cc7c30e5e33185c437cfc260caa8c3a
+f8a0fe39d955fe41a89344db01f0f33632b571832eff64ed70de8b5dcf90e73e908b274441d7e3
+4e14381c6a88bf71db27038b3037bcd5eb5a4a1c9b6067d2874b898c95dee5b114c10528dd3cd0
+4d4127190405f89ad7461b66eac5bb976c6eb433a43db8847ab105a9d6e004c1d08e17ecc40286
+2aeba56fa63297c5dab64a0f3dba016a5af5c761de36c9bdf0b375c0bd6fd3c0fa3787e362103c
+3f96d6d1bca0fe0b3fa33c034f472204cef2949742fa5b973d21b8af8e7c1ede70cb40860f7a58
+ac12a7709be24ba724166770215440b0dd64dbe6af369ec9fc0d82e3c7a597884e4330109ab763
+1b8f8a62f0ce7dc17c9919d55bd997497b66e4089b640ada46e454b4cd90a45a5805eda36ec5db
+69ca53cd3380d2f59c9cc4c6d52139cc33324161adabcf2eb44cfce47ba893bd4a53d4480118c1
+ba64436d3771ded3182b2de8306237012aea5d5a2995abcbc097e7535e259053c58c8de2a6c7c8
+d21ad6feec5907c2f6783541c68d00be43776a8e766d72a8fa8123d819d38f1f53f36bd48adcc6
+f7a1455cc87453f96e550903df9b819196a27061facc772b773dbd1444c37d3136a0d3158d79e9
+8a70e8e030dbaa42c202db2c0f8b03687f3d48b0f1783124024a5ebc0433990b1591459766cbea
+adebafa313226d839697f97e14cad664856368583b3e2e79609cac4c81afe602dd4200cfa43fda
+4f1e48d68b13f27533ab9f3fd05a0143378b81d7e5bc77eb8829d3d4e896af1c31ae42d39bc60f
+687306a10107727c8fc2fb98ad61af9b7808b6afccd125519cc4f98828e53ac23388ffa188e885
+c64a97439cabfeeaca48453cf4c6ac118ff667c21300d1c1ed5fef10e03f22e69e36248e476519
+a677fd224e37ac95fa3d9aeea5b2482da91aec2f5e7a2b57a84ec7ec8699fc6581757cfc8ed6ba
+b56242725f615304b3cc39c20e8dd67136f864ad32605b0ea9ab0d3662bb1ec7e317684a5a6afd
+8c3e83358db1392bdfb53dcb2d1624ba8772f701a3626967c0a543a4b01d70aadea4d1c2c86383
+c6eb9a722a6c833c0c5f7e92efd67ff6bb9fc72a9933a446ac965c26c72ab279c5755890d21a9d
+d9f3862582bdb1d9ccd1963a21bacd4be17d03819ab523f4473b20a87f120dcef914c72144e350
+ac33a94859de19fc1c45816ba504646b8b53410dedf6f2b1dd9b2f0b2749013aeba319bc7d2e1a
+dc99cbcff5d5ca41baf982ab06c3741fdde91b5ae8601be0a690a8848d30eb1727351734daa8ec
+8fc416bb425309b1232d290ad42ab8d97062812696531e1a5f6f87844f9ad9fe0cc660a7c4bb1f
+7c2d37ac95214fe2cb4537f763691698dfc6cb42aee39ca3e37910a5caa4bbc93b20d756593622
+3f79d777d14971397338d791989bdd842a25eb4747a45fb3d0d853000205301a799d0f1a597a34
+fad9c47ba0c27a82251b4d460f1de01fd0066bef08e4e6139412f5f7b46ca9c6fc7b5e1bff8f5a
+24498699cc168b419278a41f5eb1845b41a298cda7e237d3b149ebc1ebb02c33433c0cc8043bee
+875475cc389dfdb141fa31a67c9b97f2bd9afcdcbd16b0682b3da7c3fe91ce83fa0eee07e155db
+bafa26ff706798c07bc149d963c31bd8b3d9736a21d45d5d7761f6d93111a10b978b32a00b6593
+4ad2e4df3c2979ce6179aaa50a28348d3fd1743d482c16a2538eaaa17f6894fea19a21411ac73f
+f779f355ae9fca182a55d43f1080a60721ec087738c87987c4699e24c19172afdf0461ef5d7582
+0f2957bf75b1b396bf2a5462c7be537e67d28ddeb130863434670c75b36878888a430846e1f656
+5c9f0f529ad4e5d2386dc61f9fb0f4782a802c853cf5830763f5b9df5d77c5c3fef77c14fa64b9
+66573237b911aa353738e3ce2683d5a4612ddce6c8f50cd2c0b11912b7b09cb60590ea9b25dad4
+1363a82751aff5a9da8e1fb9643a84f3701b518b059e935a3199685c4bf2afa07980ad93fcc6e7
+733a7c1cdb6d9ea9756eb985041297452d74381a609bb8c3f9cc4c7b9ad09e57753602e856b551
+1cda7b0c9a5e0fbab6c9ef7d7e8d6751760312ba04d771974ce5b6c18d9de0d4bf76d5e5b6cd7c
+3706f94693215165881bf682231eb90cb99794177468d89877475bd1510e117d5f845f26fa3037
+62c92c2ced4c73a82afeedb275f48fb2cbbee350511004a58efd38e7002e91260e40f0792b73db
+c2158d542146aac2b860479bf6046c7e0e4edc26090205846fc8e333cc60a4aa3990290508b400
+fb02f09560be4f200d272c713ba3b615e2b40b9552cd70a67a098edf6f1bc4ea86732f1fcc762f
+513a1a004d39c1dd6d8d065024ad72b147c850945b7bfb29e830d4ef2e84d694422f1c89bc34ee
+502aca300df3c5a3e0ff8359668b11ea33ce14ef62cca8e2dfb8e5ab68d96a9a2552bf53af81e7
+8c84d96f3b1eda14e19ac07e75e3d3e5454200592a259bc950ccb398dc20862141083a5190c1b2
+cb0aa0d8d3e8a5a3b21004fd002040c4b3ea35de14ccc1ccd679d99308409a138c1ec129a71a1b
+b1443d1754f4763765b6409e8280e25b5965f444cbb2a6b78bf8541250b992e39d0a4c14ed92c7
+b9ca642ec4002946f593ae24cc194f41357a86b418c8451b342860441b9d2e33c7f8a81ecfc0e5
+630d23ee1fe752b2536ca59253c97aa18712f73f2b0335eeb0c2a26cbd98eedc669e9388314277
+18070324999284196cdbae8f16946b2bbf2b9f2a8e0a59284473831de3315a2dc0ae872b1036a8
+040d9c2a0c77a6c0c473c293ab7e19837fd227b352e8bf1bc817c76412f1d6abd47d809e989b3b
+2f89285d2693824df3191a6d1bc8c9853f2bf81b8c96607a02b31d23d7495a590cf3f96d7328c4
+fd74452dc16c2818512abf981c423d146e9d7a46bf2ef32a98dda4f6695f42532fabb8abba65de
+15bf69090b724a247fcdfefd6f1a83cc35a049d3324bd39816f4ee13a5a38da73a3c3fb031daf9
+bf78fde0f8f6bdd0e897a3b24e090b54a955b232b2258e5f2bfbfbe13db81f6abd243d73e3ff7d
+5d21527541ce6258732e85baddc7e56dc1ae4b2bdead6d8de14b406a7234ab0c0fb1b6f129a787
+7adb864cfe9abef498ea89232ee6639c0cea4dbd515a7a09aafbe65d04ec923e1200fcce3a2f68
+4c07f202273eb6a93f7ae0771e7115385296132be25b258f67273c5a0f28f98627abf77751b786
+0e123e4a4e70422114eafe03c2606f854588ef418312650f11393ea15bfa6337b955355a183573
+948398e4438b3e13fc83a36f2d86cca04e6787f6a0b29bfbb9aba924f37f5174e3ee892d16102d
+37b14d7743d9725ac7367217425cf6263f30097ef995d81458db1357305c6044d6e490d9631e9e
+e456db83af1d454176174c786a03a7771b02c10daa800cfa6819f878c871f0b3230e5aeb87d8e9
+b5d0e701fc2dd78a2ef5f9e3f0e060eeafc7ebeb813d13d4d77f1130256ceda94dd73b6e7b423d
+7f4c0c55f3491bbf6153b106b1316b9eb2ce72b263f05fda150b748d74b05f238982702f9564fb
+43259e9fd1f77d753f7a9bee8d81b2ea2d5babfa686d76582857a1a2338a5f8c2733728fdd4adf
+fcc90331d2670c260111b76369299e8f79a9570d277107c81fbd22faf23d821471f8359f13980f
+282516b7800ba8ecbac26e646e401a4d7a644fc3851749c5d19a915fb046bc40de6256a24184d6
+66de6f54e6855060071896eea3338fbea7771f129a449e5bbb498f5edf7dfb723d4838d670b76a
+e2842b726e757d534c24ebc471588ea38760f07b59c9af9649132871a23ce328acfee7f583f7ff
+0486e07187a3d4942aaa9e6a38c61543299873ae9c902dc5777ef58d396b5feb718509da30302c
+a268a9fe75e8343ea5f4da3a39445369280cfca5442939a61f82f24b15bfc71d2e1b2880df0117
+3232527227875329ab6069618cde196f153e7ec3b1dc5fa627ed4f49a43550d02cdd80cfc131d8
+6dfd6ef64530f16be3c08b2fe804ba2c8b8ef512bac05420f7809507cdc6aedbfa690c85a1bee6
+f424799dd0407f40e90051ce3d6b1020719e059187a78047533060ed3426bb7c314b179b608fdb
+19f181e4cf616e0eb850c40885f2e1d9c5afa60dd6480166d7b227b731c8491237112df20561ef
+85e4a3d2074bf8ba61da1e50699e9f9aba612c8a9a536cfaf7c9137b08aeee41148f96118a43a9
+01722f64a6457937eb18f9733fc353987b8e1fb9da5ec6c7229dad8d045654bcf4426f7148ef19
+42cd42954a8e5e5767ddd899f178f6f2443b93be25d5d61b9c06e68d653ba56f1506a88f9439a8
+96b3f604880099548ab0dbc39b26237dd1bbf9c1858716d858b94377708b44d800b95f77ba4f63
+577d1758719e208c1d4757e53eec9ad4e1919e197b4507d1d43355c142e91c3d4d80064fa7fd5a
+85d7c08f43cdb63e507726b4378853d6ad68ecc29592eef5a8b72869a2164552ae622f3f02dfa6
+cc2b5452898943fb90521daee4b1679df0d385b9ff15c9ac6c120b30626415ed3415d06608b8b1
+82f3efd579a539771a2af421119c43a5444f187b55fb3b8668eafbcb63b919a2e2152aaa0d6261
+3c37ca5002c6daea891411cb46d58d815d7f231678185a0ea2b59ceb1030a8a9959f3426a66635
+2ce86ddb34220f43b9f0695747f65b5c7d0c0bdaf97f76a67c396f24f5c3d277a375744310a9f0
+9dbe9f4501739523f301d94e6519029352ff5c1cced0d6dd89af38c49d8fdfadbfc0baf374d259
+404ce7bfd2bf94a09a02e3463ab9c6d975190944acde85894ca4537a35ae86e26af1bd5e5bb7c7
+d24e671bd182153a5022047bd8c138016aa85f3b7b62bfdbc06ae4dbe5e37528d6c6432b3db333
+a1347a09838c17b5de1b2f9570c33e7580978d48effc18fa8e0fec834076990e0d4b8abaa2c336
+40801153c5ffc858524015d49008574cf40c060b751c67395e8d39952b5514463241e8aca46f92
+701b889780db90362ca74b5d13c5f9d3362a0b53d2dbaac2c54836e4e42422aa713a20a5124ee3
+6b353631a3933a5bbe368b0c4fd93aac08fdbdd55759778a0b7ff59a185e2f9162c0ab4ce98bd3
+7fdc7a85dddcddc3d5eba60201668eda23e041e6920b10912d251171fd3fa5bdbeae378e996d03
+9c7b07bc4aca72e81625f6f816a2bb469d2458518988aaddceb796926d796673c030554e705e8e
+1197dda5d61007e137efd266bb6053fbe808fd68b95f649b50109518836141ee20b699c2f78e7a
+9e22515d0b5abd22a8357ff0aa61d8e40e4377c1cd97676bfec98b4cf3b387b6e312c7216764c5
+f58a63270bcd48fedab0be2c141e65a3f87cd1aa32413c478f2625567dcec884af2848745c44bf
+331796792e34b2fc19118560b1a8ef113d4ee885b30bb7a687387f2bf539c82fbf14805f06b586
+4bed94e4d7999d0db417743bb2fbf4909c9c4f255b
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
+{restore}if
+
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 75 100
+%%EndPageSetup
+q
+0 g
+37.918 21.906 m 37.195 69.218 l 53.93 6.375 l 37.918 21.906 l f
+1 g
+37.918 21.906 m 37.195 69.218 l 22.391 5.894 l 37.918 21.906 l f
+0 g
+0.75 w
+0 J
+0 j
+[] 0.0 d
+10 M q 1 0 0 1 0 99.034828 cm
+37.918 -77.129 m 22.391 -93.141 l 37.195 -29.816 l 53.93 -92.66 l 
+37.918 -77.129 l h
+37.918 -77.129 m S Q
+1.75 w
+q 1 0 0 1 0 99.034828 cm
+74.48 -61.355 m 74.48 -81.684 58.004 -98.16 37.68 -98.16 c 17.352 
+-98.16 0.875 -81.684 0.875 -61.355 c 0.875 -41.031 17.352 -24.555 37.68 
+-24.555 c 58.004 -24.555 74.48 -41.031 74.48 -61.355 c h
+74.48 -61.355 m S Q
+BT
+21.028038 0.322993 -0.322993 21.028038 29.489128 83.496735 Tm
+/f-0-0 1 Tf
+<01>Tj
+ET
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/n_arrow2.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/n_arrow2.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/n_arrow2.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,90 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 23:08:28 2011
+%%Pages: 1
+%%BoundingBox: 0 0 22 101
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 22 101
+%%EndPageSetup
+q
+0 g
+2.369778 w
+0 J
+0 j
+[] 0.0 d
+4 M q 0.71227 0 0 1 0 100.596039 cm
+15.444 -1 m 4.431 -76.719 l 9.926 -77.52 l 21.893 -90.621 l 20.961 
+-77.52 l 26.456 -76.719 l 15.444 -1 l h
+15.444 -1 m S Q
+2.369778 w
+q 0.71227 0 0 1 0 100.596039 cm
+1.81 -94.781 m 1.404 -98.574 l 8.424 -99.598 l 9.384 -85.285 l 22.463 
+-99.598 l 29.483 -98.574 l 29.077 -94.781 l S Q
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF

Added: grass/trunk/ps/ps.map/decorations/north-arrow_1_simple_half_arrow.eps
===================================================================
--- grass/trunk/ps/ps.map/decorations/north-arrow_1_simple_half_arrow.eps	                        (rev 0)
+++ grass/trunk/ps/ps.map/decorations/north-arrow_1_simple_half_arrow.eps	2011-11-22 22:04:27 UTC (rev 49326)
@@ -0,0 +1,84 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: cairo 1.8.10 (http://cairographics.org)
+%%CreationDate: Mon Nov 21 22:27:03 2011
+%%Pages: 1
+%%BoundingBox: 0 0 19 100
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+/cairo_eps_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+/q { gsave } bind def
+/Q { grestore } bind def
+/cm { 6 array astore concat } bind def
+/w { setlinewidth } bind def
+/J { setlinecap } bind def
+/j { setlinejoin } bind def
+/M { setmiterlimit } bind def
+/d { setdash } bind def
+/m { moveto } bind def
+/l { lineto } bind def
+/c { curveto } bind def
+/h { closepath } bind def
+/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
+      0 exch rlineto 0 rlineto closepath } bind def
+/S { stroke } bind def
+/f { fill } bind def
+/f* { eofill } bind def
+/B { fill stroke } bind def
+/B* { eofill stroke } bind def
+/n { newpath } bind def
+/W { clip } bind def
+/W* { eoclip } bind def
+/BT { } bind def
+/ET { } bind def
+/pdfmark where { pop globaldict /?pdfmark /exec load put }
+    { globaldict begin /?pdfmark /pop load def /pdfmark
+    /cleartomark load def end } ifelse
+/BDC { mark 3 1 roll /BDC pdfmark } bind def
+/EMC { mark /EMC pdfmark } bind def
+/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
+/Tj { show currentpoint cairo_store_point } bind def
+/TJ {
+  {
+    dup
+    type /stringtype eq
+    { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
+  } forall
+  currentpoint cairo_store_point
+} bind def
+/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
+    cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
+/Tf { pop /cairo_font exch def /cairo_font_matrix where
+      { pop cairo_selectfont } if } bind def
+/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
+      /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
+      /cairo_font where { pop cairo_selectfont } if } bind def
+/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
+      cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
+/g { setgray } bind def
+/rg { setrgbcolor } bind def
+/d1 { setcachedevice } bind def
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+%%PageBoundingBox: 0 0 19 100
+%%EndPageSetup
+q
+0 g
+3.254 -0 m 3.598 86.867 l 19.141 61.309 l 8.434 68.215 l 9.125 0.172 l 
+3.254 -0 l h
+3.254 -0 m f
+0 100 m 2.797 100 l 6.445 94.641 l 6.445 100 l 9.27 100 l 9.27 90.309 l 
+6.445 90.309 l 2.816 95.629 l 2.816 90.309 l 0 90.309 l 0 100 l h
+0 100 m f
+Q
+showpage
+%%Trailer
+count op_count sub {pop} repeat
+countdictstack dict_count sub {end} repeat
+cairo_eps_state restore
+%%EOF



More information about the grass-commit mailing list