Revision 109

View differences:

org.gvsig.educa.batovi/trunk/org.gvsig.educa.batovi.activity/skeleton/GvSIGActivity.py
1
import os, shutil, stat
2
import gtk, gobject
3
import popen2
4
from os import path as Path
5

  
6
import logging
7
import sugar.activity.activity as activity
8
from sugar.activity.activity import Activity
9
from sugar.datastore import datastore
10

  
11
"""
12
Alternative paths to locate JRE
13
"""
14
JAVA_HOME_PATHS=(
15
#"/usr/lib/jvm/jre", # gcj path DOESN'T WORK!!!
16
str(Path.join(Path.expanduser("~"),"Activities/Java.activity/jre")), # Java activity path
17
    )
18

  
19
# LOG level config
20
logging.basicConfig(level=logging.DEBUG)
21
#logging.basicConfig(level=logging.INFO)
22

  
23

  
24
"""
25
gvSIG batovi activity
26

  
27
Requires:
28

  
29
* Sugar builds > 706
30

  
31
* A java installed or the Java activity installed
32

  
33
  For more information see: http://www.mediagala.com/rap/foro/viewtopic.php?f=8&t=166
34

  
35
On first _run_ executes son post-install actions.
36

  
37
"""
38
class GvSIGActivity(Activity):
39
    # gvSIG Home path (where is gvSIG activity)
40
    gvsig_activity=None
41

  
42
    # gvSIG Home path (where is gvSIG installation)
43
    gvsig_home=None
44

  
45

  
46
    #Java Home
47
    java_home=None
48

  
49

  
50
    def __init__(self, handle):
51
      logging.debug('Creating GvSIG handler.')
52
      
53
      Activity.__init__(self, handle)
54
      self.handle = handle
55

  
56
      # Register run() to run from gtk_main_loop
57
      # as soon as it gets idle.
58
      # Which is kludge to make it run after the loop has begun
59
      self.idleFunc = gobject.idle_add(self.run)
60

  
61
    def run(self):
62
      # Remove run() because we want it to run only once
63
      gobject.source_remove(self.idleFunc)
64

  
65
      # locate and check jre
66
      if not self.initializeJavaHome():
67
        # Exiting with a error  
68
        self.showMessageError("Can't found any JRE to run gvSIG:\nSee http://www.mediagala.com/rap/foro/viewtopic.php?f=8&t=166\nfor more information")
69
        logging.error("No JRE found!!!")
70
        logging.debug("Closing activity");
71
        self.close(True)
72
        return
73

  
74
      # setup environ properties
75
      self.gvsig_activity=activity.get_bundle_path()
76
      self.gvsig_home=Path.join(self.gvsig_activity, 'gvSIG')
77

  
78
      os.environ['GVSIG_HOME']=self.gvsig_home
79
      os.environ['GVSIG_ACTIVITY']=self.gvsig_activity
80
      os.environ['JAVA_HOME']=self.java_home
81

  
82
      # do post-install actions
83
      self.postInstall()
84

  
85
      # identify gvSIG launcher
86
      gvSIG_sh = Path.join(activity.get_bundle_path(), 'gvSIG', 'gvSIG.sh')
87

  
88
      if not Path.exists(gvSIG_sh):
89
        raise Exception("Missing gvSIG launcher: %s" % gvSIG_sh)
90

  
91
      # check execution permission
92
      self.fixExcecutionFilePermission(gvSIG_sh)
93
      
94
      try:
95
        logging.info("Executing '%s'" % gvSIG_sh);
96

  
97
        # execute gvSIG.sh
98
        gvSIG_process = popen2.Popen4('%s' % gvSIG_sh, 16)
99

  
100
        # writing stout in log file
101
        logging.info(gvSIG_process.fromchild.read())
102

  
103
        # wait until gvSIG exit
104
        rcode = gvSIG_process.wait()
105

  
106
        logging.info('gvSIG.sh returned with code=%d' % rcode)
107

  
108
      finally:
109
        logging.debug("Closing activity");
110
        self.close(True)
111

  
112
    def showMessageError(self, message):
113
        md = gtk.MessageDialog(self, 
114
              gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, 
115
              gtk.BUTTONS_CLOSE, message)
116
        md.run()
117
        md.destroy()
118

  
119
    """
120
    Initialize property ``java_home``
121

  
122
    Try to locate a valid java in ``JAVA_HOME_PATHS`` list
123

  
124
    Check that existe a *bin/java* executable file inside of it.
125

  
126
    If not JRE found returns False. Otherwise returns True
127
    """
128
    def initializeJavaHome(self):
129
      for jhome in JAVA_HOME_PATHS:
130
        logging.debug("check jre in %s" % jhome)
131
        if not Path.exists(jhome):
132
          logging.debug("%s not found" % jhome)
133
          continue
134
        if self.checkJavaExecutable(jhome):
135
          self.java_home=jhome
136
          logging.debug("ussing '%s' for JAVA_HOME" % jhome)
137
          return True
138
      else:
139
        logging.debug("No Java available in register paths: %s" % repr(JAVA_HOME_PATHS))
140
        return False
141

  
142

  
143

  
144

  
145
    """
146
    Check ``javaHome`` folder: check that exist a *bin/java* executable file
147

  
148
    Returns True/False
149
    """
150
    def checkJavaExecutable(self, javaHome):
151
      javaExe=Path.join(javaHome,"bin","java")
152
      if not Path.exists(javaExe):
153
        return False
154
      return os.access(javaExe, os.X_OK)
155

  
156
    """
157
    Run post install actions.
158

  
159
    This actions usually will be execute just once, in first activity run
160
    """
161
    def postInstall(self):
162
      self.installInGvSIGUserHome()
163
      self.installInUserHome()
164
      self.execScripts()
165

  
166
    """
167
    *Post Intall process:* Excecutes install scripts
168

  
169
    This actions usually will be execute just once, in first activity run.
170
    """
171
    def execScripts(self):
172
      # check if ther is any file to copy to 
173
      sourceFolder = Path.join(activity.get_bundle_path(), 'post-install', 'scripts')
174

  
175
      if not Path.exists(sourceFolder):
176
        # No files to execute
177
        return
178

  
179
      everyScriptOk = True
180

  
181
      # for all file/dir in souceFolder
182
      scriptFiles = os.listdir(sourceFolder)
183

  
184
      for aFile in scriptFiles:
185
        fext = Path.splitext(aFile)[1]
186
        aFilePath = Path.join(sourceFolder,aFile)
187
        if fext == "py":
188
          # Exec python script
189
          execOk = self.execPython(aFilePath)
190
          if execOk:
191
            shutil.move(aFilePath,aFilePath+".done")
192
          else:
193
             everyScriptOk=False
194

  
195

  
196
        elif fext == "sh":
197
          # Exec Shell script
198
          execOk = self.execShell(aFilePath)
199
          if execOk:
200
            shutil.move(aFilePath,aFilePath+".done")
201
          else:
202
             everyScriptOk=False
203

  
204
        elif fext == "done":
205
          # Nothing to do
206
          pass
207

  
208
        else:
209
          # Ignoring file
210
          logging.debug("Ignoring post-install script: " + aFilePath)
211

  
212

  
213
      if everyScriptOk:
214
        # rename folder to avoid execution on next application open
215
        shutil.move(sourceFolder, sourceFolder+".done")
216

  
217
    """
218
    Excecutes a python script file
219
    """
220
    def execPython(self,aFile):
221
      logging.debug("Executing python script '%s'" % aFile);
222
      try:
223
        # open file in read-only mode
224
        f = file(aFile,"r")
225

  
226
        # exec script
227
        try:
228
          exec f
229
        finally:
230
          f.close()
231

  
232
        return True
233
      except Exception, exc:
234
        logging.error("Excecuting file %s: %s" % (aFile,exc));
235
        return False
236
      
237
    """
238
    Fix (set) execution permission of a file
239
    """
240
    def fixExcecutionFilePermission(self, aFile):
241
      # check execution permission
242
      if not os.access(aFile, os.X_OK):
243
        # set excecution permission
244
        os.chmod(aFile,os.stat(aFile)+stat.S_IEXEC)
245

  
246
    """
247
    Excecutes a shell script file
248
    """
249
    def execShell(self,aFile):
250
      logging.debug("Executing '%s'" % aFile);
251
      try:
252
        mProcess = popen2.Popen4('%s' % aFile, 16)
253
        logging.debug(mProcess.fromchild.read())
254
        rcode = mProcess.wait()
255
        return rcode == 0
256
      except Exception, exc:
257
        logging.error("Excecuting file %s: %s" % (aFile,exc));
258
        return False
259

  
260

  
261
    """
262
    *Post Intall process:* Install files in user home
263

  
264
    Move files from ``{activity_folder}/post-install/user-home`` to ``$HOME``
265

  
266
    **NOTE**: if a file/dir already exist **will be ignored** (Keeping untouched original files)
267
    """
268
    def installInUserHome(self):
269
      # check if ther is any file to copy to 
270
      sourceFolder = Path.join(activity.get_bundle_path(), 'post-install', 'user-home')
271

  
272
      if not Path.exists(sourceFolder):
273
        # No files to copy
274
        return
275

  
276
      homeUserFolder = Path.expanduser("~")
277

  
278
      #merge folder
279
      self.mergeFolder(sourceFolder,homeUserFolder)
280

  
281
      #rename source folder to prevent rerun of this step
282
      os.rename(sourceFolder,sourceFolder+".done")
283

  
284
      #done
285
      return
286

  
287
    """
288
    *Post Intall process:* Install files in the gvSIG user home folder
289

  
290
    Move files from ``{activity_folder}/post-install/user-gvsig-home`` to ``$HOME/gvSIG``
291
    """
292
    def installInGvSIGUserHome(self):
293
      # check if ther is any file to copy to 
294
      sourceFolder = Path.join(activity.get_bundle_path(), 'post-install', 'user-gvsig-home')
295

  
296
      if not Path.exists(sourceFolder):
297
        # No files to copy
298
        return
299

  
300
      homeGvsigUserFolder = Path.expanduser("~/gvSIG")
301

  
302
      if not Path.exists(homeGvsigUserFolder):
303
        # Create gvSIG user home folder
304
        os.mkdir(homeGvsigUserFolder)
305

  
306

  
307
      #move files
308
      self.mergeFolder(sourceFolder,homeGvsigUserFolder)
309

  
310
      #rename source folder to prevent rerun of this step
311
      os.rename(sourceFolder,sourceFolder+".done")
312

  
313
      #done
314
      return
315

  
316
    """
317
    Move files from ``sourceFolder`` into ``targetFolder``
318

  
319
    ``sourceFolder`` must be a folder
320
    ``targetFolder`` must be a folder or not exists (so it will be created)
321
    ``overrideTarget`` if it's ``False`` raise an exception when target already contains the file/dir to move. if ``ignoreExisting``
322
    ``ignoreExisting`` modifies ``overrideTarget`` option (when it's ``False``) to don't raise an exception, just skip file/folder
323
    """
324
    def moveFiles(self,sourceFolder,targetFolder,overrideTarget=True,ignoreExisting=True):
325
      if not Path.exists(targetFolder):
326
        # Create target folder
327
        os.makedirs(targetFolder)
328
        # set overrideTarget to True because target is new
329
        overrideTarget=True
330
      elif not Path.isdir(targetFolder):
331
        raise Exception("%s must be a dir" % targetFolder)
332

  
333
      # for all file/dir in souceFolder
334
      toMoveList = os.listdir(sourceFolder)
335
      for toMove in toMoveList:
336

  
337
        target = Path.join(targetFolder,toMove)
338
        # check if exists target
339
        if Path.exists(target):
340
          if overrideTarget:
341
            if ignoreExisting:
342
              continue
343
            
344
          else:
345
            if ignoreExisting:
346
              continue
347
            else:
348
              raise Exception("%s alredy exists in target folder %s" % (toMove, targetFolder))
349

  
350

  
351
        # move file/dir
352
        shutil.move(Path.join(sourceFolder, toMove), targetFolder)
353

  
354
   
355
    """
356
    Merge folder content: Copy all missing folders and files from
357
    ``sourceFolder`` to ``targetFolder``.
358

  
359
    Process doesn't override existing files in ``targetFolder``
360
    """
361
    def mergeFolder(self,sourceFolder,targetFolder):
362
      # get folder contents
363
      names = os.listdir(sourceFolder)
364

  
365
      if not Path.exists(targetFolder):
366
        # Create target folder if not exists
367
        os.makedirs(targetFolder)
368

  
369
      for name in names:
370
        srcname = Path.join(sourceFolder, name)
371
        dstname = Path.join(targetFolder, name)
372
        if Path.isdir(srcname):
373
          # Recursive call to mergeFolder
374
          self.mergeFolder(srcname,dstname)
375
        else:
376
          if not Path.exists(dstname):
377
            # Copy new file
378
            shutil.copy(srcname,dstname)
379
          else:
380
            # skip existing file
381
            continue
382

  
383

  
384

  
385

  
386

  
org.gvsig.educa.batovi/trunk/org.gvsig.educa.batovi.activity/skeleton/post-install/README.rst
1
===========================================
2
gvSIG batovi Activity Post-intall process
3
===========================================
4

  
5

  
6
This folder contains all supported *post-intall* actions implemented in gvSIG activity.
7

  
8

  
9
user-gvsig-home
10
================
11

  
12
Files of this folder will be **merged** (copy only files than no exists on target folder) with *~/gvSIG* folder of user intallation in first gvSIG activity execution.
13

  
14

  
15
After that this folder will be renamed to *user-gvsig-home.done*.
16

  
17

  
18
user-home
19
===========
20

  
21
Files of this folder will be **merged** (copy only files than no exists on target folder)  to *user home* folder.
22

  
23
After that this folder will be removed.
24

  
25
scripts
26
========
27

  
28
Excecutes contained scripts in first gvSIG activity execution. Only *Pyhon* (files ``.py``) and *Shell* (files ``.sh``) are allowed (other files will be ignored).
29

  
30
Before all execution this environ variables will be set:
31

  
32
* ``GVSIG_ACTIVITY``: root folder of gvSIG activity (usually ``~/Activities/org.gvsig.batovi.activity``)
33

  
34
* ``GVSIG_HOME``: root folder of gvSIG installation (usually ``$GVSIG_ACTIVITY/gvSIG``)
35

  
36
After the script excution will be renamed (adds ``.done``) to prevent future executions.
37

  
38
When all script were executed, this folder will be renamed (adds ``.done``).
39

  
40
See log file for problems in script executions.
org.gvsig.educa.batovi/trunk/org.gvsig.educa.batovi.activity/skeleton/activity/activity.info
1
[Activity]
2
name = gvSIG Batovi
3
bundle_id = org.gvsig.batovi.GvSIGActivity
4
class = GvSIGActivity.GvSIGActivity
5
icon = activity-gvsig
6
activity_version = ${version}
7
host_version = 1
8
show_launcher = yes
9

  
org.gvsig.educa.batovi/trunk/org.gvsig.educa.batovi.activity/skeleton/activity/activity-gvsig.svg
1
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
<!-- Created with Inkscape (http://www.inkscape.org/) -->
3

  
4
<svg
5
   xmlns:dc="http://purl.org/dc/elements/1.1/"
6
   xmlns:cc="http://creativecommons.org/ns#"
7
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
   xmlns:svg="http://www.w3.org/2000/svg"
9
   xmlns="http://www.w3.org/2000/svg"
10
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
   width="55"
13
   height="55"
14
   id="svg4502"
15
   sodipodi:version="0.32"
16
   inkscape:version="0.48.2 r9819"
17
   version="1.0"
18
   sodipodi:docname="logo_gvsig.svg"
19
   inkscape:output_extension="org.inkscape.output.svg.inkscape">
20
  <defs
21
     id="defs4504" />
22
  <sodipodi:namedview
23
     id="base"
24
     pagecolor="#ffffff"
25
     bordercolor="#666666"
26
     borderopacity="1.0"
27
     gridtolerance="10000"
28
     guidetolerance="10"
29
     objecttolerance="10"
30
     inkscape:pageopacity="0.0"
31
     inkscape:pageshadow="2"
32
     inkscape:zoom="1"
33
     inkscape:cx="32.531924"
34
     inkscape:cy="23.680342"
35
     inkscape:document-units="px"
36
     inkscape:current-layer="layer3"
37
     width="55px"
38
     height="55px"
39
     inkscape:window-width="1440"
40
     inkscape:window-height="876"
41
     inkscape:window-x="0"
42
     inkscape:window-y="24"
43
     showgrid="false"
44
     inkscape:window-maximized="1">
45
    <inkscape:grid
46
       id="GridFromPre046Settings"
47
       type="xygrid"
48
       originx="0px"
49
       originy="0px"
50
       spacingx="15px"
51
       spacingy="15px"
52
       color="#0000ff"
53
       empcolor="#0000ff"
54
       opacity="0.2"
55
       empopacity="0.4"
56
       empspacing="5" />
57
  </sodipodi:namedview>
58
  <metadata
59
     id="metadata4507">
60
    <rdf:RDF>
61
      <cc:Work
62
         rdf:about="">
63
        <dc:format>image/svg+xml</dc:format>
64
        <dc:type
65
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
66
        <dc:title></dc:title>
67
      </cc:Work>
68
    </rdf:RDF>
69
  </metadata>
70
  <g
71
     inkscape:groupmode="layer"
72
     id="layer3"
73
     inkscape:label="gvSIG"
74
     style="display:inline">
75
    <path
76
       inkscape:connector-curvature="0"
77
       d="m 39.045533,15.464691 5.008004,0.01002 -2.83453,2.78445 -2.173474,-2.794466 z"
78
       id="path3167"
79
       style="opacity:0.9;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
80
    <path
81
       inkscape:connector-curvature="0"
82
       d="m 31.753879,43.809995 2.914658,-1.171873 -0.691105,1.582529 -0.470752,1.021633 -1.752801,-1.432289 z"
83
       id="path3169"
84
       style="opacity:0.9;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
85
    <path
86
       inkscape:connector-curvature="0"
87
       d="m 32.754444,44.199731 c -1.006043,-0.811367 -0.942467,-0.909284 -0.900076,-0.946376 1.029815,0.665011 1.157454,2.59338 3.343757,-1.369367 0.04861,0 -0.19716,0.182445 -0.489271,0.808227 -0.749217,1.4631 -0.57733,2.576404 -1.95441,1.507516 z M 39.015523,14.29865 c 0.02911,0.04721 0.0029,0.113605 -0.10325,0.262168 m 0,0 c -0.235226,0.329008 -0.783149,1.239702 -1.246618,2.071982 l -0.436597,0.784028 -0.99873,2.172872 c -0.211322,0.662323 -0.149824,0.340818 -0.283311,0.695752 -0.851761,2.264795 -1.136771,4.0885 -0.876162,5.606343 0.15208,0.885747 1.103754,3.671021 0.740732,2.525289 -1.055611,-3.331599 -0.374263,-0.110081 0.46825,1.548953 l 0.506476,1.676798 c -0.376992,-1.104849 -0.0094,-0.01827 0.322667,0.546688 0.144246,0.245467 -0.251526,1.103205 -0.251526,1.252601 l -2.600479,3.843859 -1.904781,2.400568 c -1.047629,1.320312 -1.898975,2.425595 -1.89188,2.456183 0.0071,0.03059 0.299529,0.287225 0.649852,0.570303 0.414154,0.334657 0.623184,0.528457 0.59759,0.55405 -0.05919,0.05919 -1.073573,0.295913 -1.758876,0.410463 -1.214277,0.20297 -2.627521,0.284616 -3.851841,0.222524 -2.343425,-0.118842 -4.647166,-0.729425 -6.776012,-1.79591 -1.783328,-0.893392 -3.089809,-1.848315 -4.586564,-3.352376 -1.624587,-1.97553 -0.953207,-1.093241 -1.961815,-2.364074 C 11.22125,34.11736 10.268777,31.576881 9.8960536,28.715131 9.7899424,27.900417 9.7903578,25.45811 9.8967473,24.641457 10.300998,21.538365 11.386492,18.82179 13.193665,16.390529 c 0.771959,-1.072328 -0.136037,0.15859 1.024592,-1.249459 0.611433,-0.701827 1.638575,-1.638054 2.499035,-2.277838 2.419486,-1.798975 5.106641,-2.880747 8.169743,-3.2889027 0.805568,-0.1073415 2.589827,-0.1495905 3.451273,-0.081722 3.420086,0.2694485 6.629524,1.5090367 9.294084,3.5896747 0.491753,0.383988 1.317771,1.110414 1.383131,1.216368 m -1.560959,22.110078 c 0.743443,-1.368642 1.546847,-2.477745 2.43279,-3.358479 0.543554,-0.540358 0.946412,-0.86191 1.492751,-1.191485 0.187925,-0.113364 0.347133,-0.222732 0.353795,-0.243039 0.0067,-0.02031 -0.194006,-0.141267 -0.445928,-0.2688 -2.012917,-1.019018 -3.59431,-2.706785 -3.912617,-4.584878 -0.0568,-0.207256 0.04596,0.280857 -0.124777,-0.398347 l -0.05745,-1.255803 0.196786,-1.446482 c 1.076898,-2.372767 1.206196,-2.516959 2.617915,-4.202801 0.407242,-0.48632 1.36236,-1.555087 1.565091,-1.745254 0.143999,-0.135075 0.142508,-0.136329 0.444611,0.373919 1.765305,2.981576 2.429605,5.568978 2.273216,8.853986 -0.09665,2.030145 -0.366432,3.61138 -0.896776,5.25613 -0.995198,3.086407 -2.835522,5.77324 -5.317913,7.764032 -0.899273,0.721188 -2.663277,1.856756 -2.749838,1.770195 -0.08036,-0.08036 0.661546,-2.174539 1.24226,-3.506548 0.185851,-0.426293 0.337909,-0.81198 0.337909,-0.857085 z m 1.398,-22.009444 c 2.8125,-0.07498 0.209333,-0.147678 2.513796,-0.272677 0.851564,-0.223161 1.96777,-0.04869 2.50391,-0.12385 -0.7399,2.071371 -0.168365,1.140579 -0.854924,1.827405 -0.686559,0.686823 -2.221305,2.710631 -2.245305,2.710631"
88
       id="path2412"
89
       style="opacity:0.9;fill:none;stroke:#eebe0e;stroke-width:1.01694441;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
90
       sodipodi:nodetypes="ccccccccsccsssccsccscsssssccssccssssccsscsccccsssssssscccccsc" />
91
    <path
92
       inkscape:connector-curvature="0"
93
       d="m 37.454564,36.40872 c 0.743443,-1.368643 1.546847,-2.477746 2.43279,-3.358479 0.543554,-0.540358 0.946412,-0.861911 1.492751,-1.191485 0.187925,-0.113364 0.347133,-0.222732 0.353795,-0.24304 0.0067,-0.02031 -0.194006,-0.141266 -0.445928,-0.268799 -2.012917,-1.019018 -3.212956,-2.611446 -3.912617,-4.584878 l -0.211641,-0.959123 c 0,0 -0.184842,-0.408725 0.226167,-2.141464 0.419943,-1.199861 1.309327,-2.627679 2.617915,-4.2028 0.405343,-0.487905 1.362361,-1.555088 1.565092,-1.745255 0.143998,-0.135076 0.142507,-0.136329 0.44461,0.373918 1.765306,2.981577 2.429605,5.56898 2.273216,8.853987 -0.09665,2.030145 -0.366432,3.61138 -0.896776,5.256131 -0.995198,3.086406 -2.835521,5.773238 -5.317912,7.764032 -0.587931,0.471501 -1.676121,1.213824 -2.310514,1.576147 -0.4333,0.247472 -0.417775,0.240983 -0.450374,0.188235 l 3.5e-5,-3.7e-5 c -0.06146,-0.09945 0.710462,-2.255581 1.253311,-3.500737 0.18585,-0.426292 0.337909,-0.809016 0.337909,-0.850498"
94
       id="path2410"
95
       style="opacity:0.9;fill:#3e83c3;stroke-width:25.21345139;stroke-miterlimit:4;stroke-dasharray:none"
96
       sodipodi:nodetypes="csscscccsssssssccsc" />
97
    <path
98
       inkscape:connector-curvature="0"
99
       d="m 38.532721,14.407793 c 0.02821,0.04693 0.0028,0.112922 -0.100075,0.260591 m 0,0 c -0.227984,0.327031 -0.759034,1.232252 -1.208229,2.059531 l -0.423152,0.779316 -0.967975,2.159815 c -0.204814,0.658339 -0.145209,0.338769 -0.274585,0.691571 -0.825532,2.251184 -1.101765,4.063927 -0.84918,5.57265 0.147397,0.880422 0.207888,0.829618 0.65437,1.933026 0.270532,0.668576 -0.05279,0.341313 0.763786,1.990376 l 0.675684,1.287657 c -0.36538,-1.098208 0.237371,0.803143 0.374334,1.048822 0.136967,0.245677 0.187432,0.843867 0.187432,0.992362 l -3.444425,4.073469 -1.846122,2.386141 c -1.015368,1.312379 -1.840495,2.411021 -1.83362,2.441424 0.0071,0.03039 0.290304,0.285499 0.62984,0.566875 0.401399,0.332643 0.603993,0.525281 0.579186,0.550718 -0.05738,0.05884 -1.040514,0.294133 -1.70471,0.407995 -1.176884,0.201755 -2.546606,0.282908 -3.733226,0.221191 -2.271253,-0.118132 -4.504052,-0.725046 -6.567338,-1.785119 -1.728412,-0.888022 -2.994658,-1.837211 -4.445323,-3.332227 -1.574555,-1.963658 -0.923851,-1.086672 -1.9014,-2.349867 -1.503627,-2.256711 -2.426764,-4.781923 -2.788011,-7.626475 -0.102841,-0.809818 -0.102439,-3.237448 6.73e-4,-4.049193 0.391801,-3.084444 1.443869,-5.784691 3.195389,-8.201343 0.748189,-1.065882 -0.131846,0.157639 0.99304,-1.241949 0.592603,-0.697611 1.588114,-1.628211 2.422078,-2.264149 2.344977,-1.788164 4.949384,-2.863436 7.918155,-3.269138 0.780762,-0.1066957 2.510073,-0.1486915 3.344992,-0.08123 3.314765,0.2678291 6.425367,1.4999688 9.007873,3.5681018 0.476609,0.381681 1.494986,0.96972 1.340537,1.209059"
100
       id="path2412-0"
101
       style="opacity:0.9;fill:#eebe0e;fill-opacity:1;stroke:none"
102
       sodipodi:nodetypes="cccsccsssccsccscsssssccssccssssc" />
103
    <path
104
       style="fill:#ffffff;fill-opacity:1;stroke:none"
105
       d="m 43.5746,14.52427 -4.065864,-0.08839 c -1.473139,3.240906 -7.080337,8.589903 -1.90035,18.163806 -2.268556,3.962783 -4.435019,6.09836 -6.584932,9.501746 l 2.253903,1.811963 c 1.753035,-2.268634 1.569667,-2.495936 3.623922,-7.689787 1.459857,-2.14221 1.900097,-3.277945 4.154252,-4.419418 -1.656469,-0.763306 -3.061836,-2.341526 -3.800698,-3.668116 -0.525075,-1.592748 -0.796986,-3.819661 0.08838,-5.61266 0.99004,-1.454308 2.187197,-3.412551 2.96101,-4.110059 0.966867,-1.027473 2.165514,-2.681112 3.270373,-3.889085 z"
106
       id="path4065"
107
       inkscape:connector-curvature="0"
108
       sodipodi:nodetypes="ccccccccccc" />
109
  </g>
110
</svg>

Also available in: Unified diff