diff --git a/core/forms.py b/core/forms.py
index c38a699..939f64f 100644
--- a/core/forms.py
+++ b/core/forms.py
@@ -1,8 +1,7 @@
 from django.forms import ModelForm
 from models import Cave, Person, PersonExpedition, LogbookEntry, QM, Expedition, Entrance, CaveAndEntrance
 import django.forms as forms
-from django.forms.formsets import formset_factory
-from django.forms.models import formset_factory
+from django.forms.models import modelformset_factory
 from django.contrib.admin.widgets import AdminDateWidget
 import string
 from datetime import date
@@ -20,16 +19,23 @@ class CaveForm(ModelForm):
     class Meta:
         model = Cave
 
-class CaveAndEntranceForm(forms.Form):
-    entrance = forms.ChoiceField(choices=[("", "-----")] + 
-                                         [(x.slug, x.slug) 
-                                          for x 
-                                          in Entrance.objects.all()])
-    entrance_letter = forms.CharField(max_length=20)
-    non_public = forms.BooleanField()
+class VersionControlCommentForm(forms.Form):
+    description_of_change = forms.CharField(required = True, widget=forms.Textarea())
 
-CaveAndEntranceFormSet = formset_factory(CaveAndEntranceForm)
 
+class EntranceForm(ModelForm):
+    #underground_description = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 30}))
+    #explorers = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #equipment = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #survey = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #kataster_status = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #underground_centre_line = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #notes = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    #references = forms.CharField(required = False, widget=TinyMCE(attrs={'cols': 80, 'rows': 10}))
+    class Meta:
+        model = Entrance
+
+CaveAndEntranceFormSet = modelformset_factory(CaveAndEntrance, exclude=('cave'))
 
 class EntranceForm(ModelForm):
     class Meta:
diff --git a/core/models.py b/core/models.py
index c82f448..7b301f5 100644
--- a/core/models.py
+++ b/core/models.py
@@ -10,6 +10,8 @@ from django.conf import settings
 from decimal import Decimal, getcontext
 from django.core.urlresolvers import reverse
 from imagekit.models import ImageModel
+from django.template import Context, loader
+import settings
 getcontext().prec=2 #use 2 significant figures for decimal calculations
 
 from models_survex import *
@@ -339,16 +341,21 @@ class Area(TroggleModel):
         elif self.parent:
             return self.parent.kat_area()
 
-class CaveAndEntrance(TroggleModel):
+class CaveAndEntrance(models.Model):
     cave = models.ForeignKey('Cave')
     entrance = models.ForeignKey('Entrance')
     entrance_letter = models.CharField(max_length=20,blank=True,null=True)
     def __unicode__(self):
         return unicode(self.cave) + unicode(self.entrance_letter)
         
+class CaveSlug(models.Model):
+    cave = models.ForeignKey('Cave')
+    slug = models.SlugField(max_length=50, unique = True)
+    primary = models.BooleanField()
+    
+
 class Cave(TroggleModel):
-    # too much here perhaps
-    slug    = models.SlugField(max_length=50, unique = True)
+    # too much here perhaps, 
     official_name = models.CharField(max_length=160)
     area = models.ManyToManyField(Area, blank=True, null=True)
     kataster_code = models.CharField(max_length=20,blank=True,null=True)
@@ -369,6 +376,7 @@ class Cave(TroggleModel):
     survex_file = models.CharField(max_length=100,blank=True,null=True)
     description_file = models.CharField(max_length=200,blank=True,null=True)
     url = models.CharField(max_length=200,blank=True,null=True)
+    filename = models.CharField(max_length=200)
 
     #class Meta:
     #    unique_together = (("area", "kataster_number"), ("area", "unofficial_number"))
@@ -377,6 +385,15 @@ class Cave(TroggleModel):
 
     #href    = models.CharField(max_length=100)
 
+    def slug(self):
+        primarySlugs = self.caveslug_set.filter(primary = True)
+        if primarySlugs:
+            return primarySlugs[0].slug
+        else:
+            slugs = self.caveslug_set.filter()
+            if slugs:
+                return slugs[0].slug
+
     def reference(self):
         if self.kataster_number:
             return "%s-%s" % (self.kat_area(), self.kataster_number)
@@ -393,17 +410,8 @@ class Cave(TroggleModel):
         #return settings.URL_ROOT + '/cave/' + href + '/'
         return urlparse.urljoin(settings.URL_ROOT, reverse('cave',kwargs={'cave_id':href,}))
 
-    def __unicode__(self):
-        if self.kataster_number:
-            if self.kat_area():
-                return self.kat_area() + u": " + self.kataster_number
-            else:
-                return unicode("l") + u": " + self.kataster_number
-        else:
-            if self.kat_area():
-                return self.kat_area() + u": " + self.unofficial_number
-            else:
-                return self.unofficial_number
+    def __unicode__(self, sep = u": "):
+        return unicode(self.slug())
 
     def get_QMs(self):
         return QM.objects.filter(found_by__cave=self)	
@@ -451,6 +459,17 @@ class Cave(TroggleModel):
         else:
             res += "–" + prevR
         return res
+    
+    def writeDataFile(self):
+        f = open(os.path.join(settings.CAVEDESCRIPTIONS, self.filename), "w")
+        t = loader.get_template('dataformat/cave.xml')
+        c = Context({'cave': self})
+        u = t.render(c)
+        u8 = u.encode("utf-8")
+        f.write(u8)
+        f.close()
+
+    
 
 def getCaveByReference(reference):
     areaname, code = reference.split("-", 1)
@@ -467,10 +486,13 @@ class OtherCaveName(TroggleModel):
     cave = models.ForeignKey(Cave)
     def __unicode__(self):
         return unicode(self.name)
-    
+            
+class EntranceSlug(models.Model):
+    entrance = models.ForeignKey('Entrance')
+    slug = models.SlugField(max_length=50, unique = True)
+    primary = models.BooleanField()
 
 class Entrance(TroggleModel):
-    slug = models.SlugField(max_length=50, unique = True)
     name = models.CharField(max_length=100, blank=True,null=True)
     entrance_description = models.TextField(blank=True,null=True)
     explorers = models.TextField(blank=True,null=True)
@@ -501,19 +523,17 @@ class Entrance(TroggleModel):
     alt = models.TextField(blank=True, null=True)
     northing = models.TextField(blank=True, null=True)
     easting = models.TextField(blank=True, null=True)
-    tag_station = models.TextField()
-    exact_station = models.TextField()
-    other_station = models.TextField()
+    tag_station = models.TextField(blank=True, null=True)
+    exact_station = models.TextField(blank=True, null=True)
+    other_station = models.TextField(blank=True, null=True)
     other_description = models.TextField(blank=True,null=True)
     bearings = models.TextField(blank=True,null=True)
+    url = models.CharField(max_length=200,blank=True,null=True)
+    filename = models.CharField(max_length=200)
+    cached_primary_slug = models.CharField(max_length=200,blank=True,null=True)
+
     def __unicode__(self):
-        a = CaveAndEntrance.objects.filter(entrance = self)
-        name = u''
-        if self.name:
-            name = unicode(self.name) + u' '
-        if len(a) == 1:
-            return name + unicode(a[0])
-        return name + unicode(a)
+        return unicode(self.slug())
     def marking_val(self):
         for m in self.MARKING_CHOICES:
             if m[0] == self.marking:
@@ -523,6 +543,8 @@ class Entrance(TroggleModel):
             if f[0] == self.findability:
                 return f[1]
                 
+    def tag(self):
+        return SurvexStation.objects.lookup(self.tag_station)
 
     def get_absolute_url(self):
         
@@ -535,6 +557,28 @@ class Entrance(TroggleModel):
             
         return res
 
+    def slug(self):
+        if not self.cached_primary_slug:
+            primarySlugs = self.entranceslug_set.filter(primary = True)
+            if primarySlugs:    
+                self.cached_primary_slug = primarySlugs[0].slug
+                self.save()
+            else:
+                slugs = self.entranceslug_set.filter()
+                if slugs:
+                    self.cached_primary_slug = slugs[0].slug
+                    self.save()
+        return self.cached_primary_slug
+
+    def writeDataFile(self):
+        f = open(os.path.join(settings.ENTRANCEDESCRIPTIONS, self.filename), "w")
+        t = loader.get_template('dataformat/entrance.xml')
+        c = Context({'entrance': self})
+        u = t.render(c)
+        u8 = u.encode("utf-8")
+        f.write(u8)
+        f.close()
+
 class CaveDescription(TroggleModel):
     short_name = models.CharField(max_length=50, unique = True)
     long_name = models.CharField(max_length=200, blank=True, null=True)
diff --git a/core/models_survex.py b/core/models_survex.py
index 1bf75ef..b726d59 100644
--- a/core/models_survex.py
+++ b/core/models_survex.py
@@ -56,16 +56,27 @@ class SurvexStationLookUpManager(models.Manager):
     def lookup(self, name):
         blocknames, sep, stationname = name.rpartition(".")
         return self.get(block = SurvexBlock.objects.lookup(blocknames),
-                        name = stationname)
+                        name__iexact = stationname)
 
 class SurvexStation(models.Model):
-    name        = models.CharField(max_length=20)   
+    name        = models.CharField(max_length=100)   
     block       = models.ForeignKey('SurvexBlock')
     equate      = models.ForeignKey('SurvexEquate', blank=True, null=True)
     objects = SurvexStationLookUpManager()
     x = models.FloatField(blank=True, null=True)
     y = models.FloatField(blank=True, null=True)
     z = models.FloatField(blank=True, null=True)
+    
+    def path(self):
+        r = self.name
+        b = self.block
+        while True:
+            if b.name:
+                r = b.name + "." + r
+            if b.parent:
+                b = b.parent
+            else:
+                return r
 
 class SurvexLeg(models.Model):
     block       = models.ForeignKey('SurvexBlock')
@@ -85,7 +96,7 @@ class SurvexBlockLookUpManager(models.Manager):
         blocknames = name.split(".")
         block = SurvexBlock.objects.get(parent=None, survexfile__path="all")
         for blockname in blocknames:
-            block = SurvexBlock.objects.get(parent=block, name=blockname)
+            block = SurvexBlock.objects.get(parent=block, name__iexact=blockname)
         return block
 
 class SurvexBlock(models.Model):
@@ -131,6 +142,7 @@ class SurvexBlock(models.Model):
         if ssl:
             assert len(ssl) == 1
             return ssl[0]
+        #print name
         ss = SurvexStation(name=name, block=self)
         ss.save()
         return ss
diff --git a/core/views_caves.py b/core/views_caves.py
index 8dc2ebe..d8ced23 100644
--- a/core/views_caves.py
+++ b/core/views_caves.py
@@ -1,10 +1,10 @@
 from troggle.core.models import Cave, CaveAndEntrance, Survey, Expedition, QM, CaveDescription, Entrance
-from troggle.core.forms import CaveForm, CaveAndEntranceFormSet
+from troggle.core.forms import CaveForm, CaveAndEntranceFormSet, VersionControlCommentForm, EntranceForm
 import troggle.core.models as models
 import troggle.settings as settings
 from troggle.helper import login_required_if_public
 
-from django.forms.models import formset_factory
+from django.forms.models import modelformset_factory
 from django import forms
 from django.core.urlresolvers import reverse
 from utils import render_with_context # see views_logbooks for explanation on this.
@@ -21,12 +21,23 @@ def getCave(cave_id):
         cave = Cave.objects.get(unofficial_number=cave_id)
     return cave
 
+def caveCmp(x, y):
+    if x.kataster_number:
+      if y.kataster_number:
+        return cmp(x.kataster_number, y.kataster_number)
+      else:
+        return -1
+    else:
+      return 1
+
 def caveindex(request):
     caves = Cave.objects.all()
     notablecavehrefs = [ "161", "204", "258", "76" ]  # could detect notability by trips and notability of people who have been down them
     notablecaves = [Cave.objects.get(kataster_number=kataster_number)  for kataster_number in notablecavehrefs ]
-    caves1623 = Cave.objects.filter(area__short_name = "1623")
-    caves1626 = Cave.objects.filter(area__short_name = "1626")
+    caves1623 = list(Cave.objects.filter(area__short_name = "1623"))
+    caves1626 = list(Cave.objects.filter(area__short_name = "1626"))
+    caves1623.sort(caveCmp)
+    caves1626.sort(caveCmp)
     return render_with_context(request,'caveindex.html', {'caves1623': caves1623, 'caves1626': caves1626, 'notablecaves':notablecaves, 'cavepage': True})
 
 def cave(request, cave_id='', offical_name=''):
@@ -37,33 +48,33 @@ def cave(request, cave_id='', offical_name=''):
         return render_with_context(request,'cave.html', {'cave': cave, 'cavepage': True})
 
 def caveEntrance(request, slug):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': cave})
     else:
         return render_with_context(request,'cave_entrances.html', {'cave': cave})
 
 def caveDescription(request, slug):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': cave})
     else:
         return render_with_context(request,'cave_uground_description.html', {'cave': cave})
 def caveQMs(request, slug):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': cave})
     else:
         return render_with_context(request,'cave_qms.html', {'cave': cave})
 def caveLogbook(request, slug):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': cave})
     else:
         return render_with_context(request,'cave_logbook.html', {'cave': cave})
 
 def caveSlug(request, slug):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if cave.non_public and settings.PUBLIC_SITE and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': cave, 'cave_editable': slug})
     else:
@@ -71,22 +82,49 @@ def caveSlug(request, slug):
 
 @login_required_if_public
 def edit_cave(request, slug=None):
-    cave = Cave.objects.get(slug = slug)
+    cave = Cave.objects.get(caveslug__slug = slug)
     if request.POST:
         form = CaveForm(request.POST, instance=cave)
         ceFormSet = CaveAndEntranceFormSet(request.POST)
+        versionControlForm = VersionControlCommentForm(request.POST)
+        if form.is_valid() and ceFormSet.is_valid() and versionControlForm.is_valid():
+            cave = form.save()
+            ceinsts = ceFormSet.save(commit=False)
+            for ceinst in ceinsts:
+                ceinst.cave = cave
+                ceinst.save()
+            cave.writeDataFile()
+            return HttpResponseRedirect("/" + cave.url)    
     else:
         form = CaveForm(instance=cave)
-        i = [{"entrance": x.entrance.slug, 
-              "entrance_letter": x.entrance_letter, 
-              "non_public": x.non_public} 
-             for x 
-             in cave.caveandentrance_set.all()]
-        ceFormSet = CaveAndEntranceFormSet(initial=i)
+        ceFormSet = CaveAndEntranceFormSet(queryset=cave.caveandentrance_set.all())
+        versionControlForm = VersionControlCommentForm()
+        
     return render_with_context(request, 
                                'editcave2.html', 
                                {'form': form,
-                                'caveAndEntranceFormSet': ceFormSet
+                                'caveAndEntranceFormSet': ceFormSet,
+                                'versionControlForm': versionControlForm
+                                })
+
+@login_required_if_public
+def editEntrance(request, slug=None):
+    entrance = Entrance.objects.get(entranceslug__slug = slug)
+    if request.POST:
+        form = EntranceForm(request.POST, instance = entrance)
+        versionControlForm = VersionControlCommentForm(request.POST)
+        if form.is_valid() and versionControlForm.is_valid():
+            entrance = form.save()
+            entrance.writeDataFile()
+            return HttpResponseRedirect("/" + entrance.url) 
+    else:
+        form = EntranceForm(instance = entrance)
+        versionControlForm = VersionControlCommentForm()
+        
+    return render_with_context(request, 
+                               'editentrance.html', 
+                               {'form': form,
+                                'versionControlForm': versionControlForm
                                 })
 
 def qm(request,cave_id,qm_id,year,grade=None):
@@ -111,7 +149,7 @@ def ent(request, cave_id, ent_letter):
                                                 'letter': cave_and_ent.entrance_letter,})
 
 def entranceSlug(request, slug):
-    entrance = Entrance.objects.get(slug = slug)
+    entrance = Entrance.objects.get(entranceslug__slug = slug)
     if entrance.non_public and not request.user.is_authenticated():
         return render_with_context(request,'nonpublic.html', {'instance': entrance})
     else:
@@ -148,9 +186,9 @@ def cave_description(request, cavedescription_name):
     return render_with_context(request,'cave_description.html', locals())
 
 def get_entrances(request, caveslug):
-    cave = Cave.objects.get(slug = caveslug)
-    return render_with_context(request,'options.html', {"items": [(e.entrance.slug, e.entrance.slug) for e in cave.entrances()]})
+    cave = Cave.objects.get(caveslug__slug = caveslug)
+    return render_with_context(request,'options.html', {"items": [(e.entrance.slug(), e.entrance.slug()) for e in cave.entrances()]})
 
 def get_qms(request, caveslug):
-    cave = Cave.objects.get(slug = caveslug)
-    return render_with_context(request,'options.html', {"items": [(e.entrance.slug, e.entrance.slug) for e in cave.entrances()]})
+    cave = Cave.objects.get(caveslug__slug = caveslug)
+    return render_with_context(request,'options.html', {"items": [(e.entrance.slug(), e.entrance.slug()) for e in cave.entrances()]})
diff --git a/databaseReset.py b/databaseReset.py
index 4a7aeb4..00d6a78 100644
--- a/databaseReset.py
+++ b/databaseReset.py
@@ -8,6 +8,7 @@ from django.db import connection
 from django.contrib.auth.models import User
 from django.http import HttpResponse
 from  django.core.urlresolvers import reverse
+from core.models import Cave, Entrance
 import flatpages.models
 
 
@@ -43,6 +44,11 @@ def import_cavetab():
     print "importing cavetab"
     parsers.cavetab.LoadCaveTab()
 
+def import_caves():
+    import parsers.caves
+    print "importing caves"
+    parsers.caves.readcaves()
+
 def import_people():
     import parsers.people
     parsers.people.LoadPersonsExpos()
@@ -101,7 +107,10 @@ def reset():
     import_survex()
     import_logbooks()
     import_QMs()
-    import_tunnelfiles()
+    try:
+        import_tunnelfiles()
+    except:
+        print "Tunnel files parser broken."
     
     import_surveys()
     import_descriptions()
@@ -180,6 +189,13 @@ def pageredirects():
         f = flatpages.models.Redirect(originalURL = oldURL, newURL = newURL)
         f.save()
 
+def writeCaves():
+    for cave in Cave.objects.all():
+        cave.writeDataFile()
+    for entrance in Entrance.objects.all():
+        entrance.writeDataFile()
+    
+
 if __name__ == "__main__":
     import core.models
     import sys
@@ -192,6 +208,11 @@ if __name__ == "__main__":
         make_dirs()
         pageredirects()
         import_cavetab()
+    elif "cavesnew" in sys.argv:
+        reload_db()
+        make_dirs()
+        pageredirects()
+        import_caves()
     elif "QMs" in sys.argv:
         import_QMs()
     elif "tunnel" in sys.argv:
@@ -201,7 +222,10 @@ if __name__ == "__main__":
     elif "survex" in sys.argv:
         management.call_command('syncdb', interactive=False)  # this sets the path so that import settings works in import_survex
         import_survex()
-    
+    elif "survexpos" in sys.argv:
+        management.call_command('syncdb', interactive=False)  # this sets the path so that import settings works in import_survex
+        import parsers.survex
+        parsers.survex.LoadPos()    
     elif "logbooks" in sys.argv:
         management.call_command('syncdb', interactive=False)  # this sets the path so that import settings works in import_survex
         import_logbooks()
@@ -209,6 +233,8 @@ if __name__ == "__main__":
         import_auto_logbooks()
     elif "dumplogbooks" in sys.argv:
         dumplogbooks()
+    elif "writeCaves" in sys.argv:
+        writeCaves()
     else:
         print "Do 'python databaseReset.py reset'"
 
diff --git a/flatpages/views.py b/flatpages/views.py
index f46488e..d805c20 100644
--- a/flatpages/views.py
+++ b/flatpages/views.py
@@ -23,13 +23,13 @@ def flatpage(request, path):
 
     try:
         r = Cave.objects.get(url = path)
-        return troggle.core.views_caves.caveSlug(request, r.slug)
+        return troggle.core.views_caves.caveSlug(request, r.slug())
     except Cave.DoesNotExist:
         pass
 
     try:
         r = EntranceRedirect.objects.get(originalURL = path)
-        return troggle.core.views_caves.enranceSlug(request, r.entrance.slug)
+        return troggle.core.views_caves.entranceSlug(request, r.entrance.slug())
     except EntranceRedirect.DoesNotExist:
         pass
 
diff --git a/parsers/cavetab.py b/parsers/cavetab.py
index d76a280..9f04105 100644
--- a/parsers/cavetab.py
+++ b/parsers/cavetab.py
@@ -108,14 +108,15 @@ def LoadCaveTab():
             addToDefaultArgs(AutogenFile, "url")
             if line[Area] == "1626":
                 if line[KatasterNumber] != "":
-                    args["slug"] = line[Area] + "-" + line[KatasterNumber]
+                    slug = line[Area] + "-" + line[KatasterNumber]
                 else:
-                    args["slug"] = line[Area] + "-" + line[UnofficialNumber]
+                    slug = line[Area] + "-" + line[UnofficialNumber]
             else:
                 if line[KatasterNumber] != "":
-                    args["slug"] = "1623" + "-" + line[KatasterNumber]
+                    slug = "1623" + "-" + line[KatasterNumber]
                 else:
-                    args["slug"] = "1623" + "-" + line[UnofficialNumber]
+                    slug = "1623" + "-" + line[UnofficialNumber]
+            args["filename"] = "%s.html" % slug
             #The following adds the legacy_file_path.  This is always in either Autogen file or Link file
             for header in (AutogenFile,LinkFile):
                 if line[header]:
@@ -126,8 +127,9 @@ def LoadCaveTab():
             #Noinfo was the name of the old password protected directory, so if it has that then we will
             #set the non_public field of the model instance to true.
             defaultArgs["non_public"]=line[AutogenFile].startswith('noinfo') or line[LinkFile].startswith('noinfo')
-
-            newCave, created=save_carefully(models.Cave, lookupAttribs=args, nonLookupAttribs=defaultArgs)
+            newCave, created = save_carefully(models.Cave, lookupAttribs=args, nonLookupAttribs=defaultArgs)
+            cs = models.CaveSlug(slug = slug, cave = newCave, primary = True)
+            cs.save()
             logging.info("Added cave "+str(newCave)+"\n")
 
             #If we created a new cave, add the area to it. This does mean that if a cave's identifying features have not changed, areas will not be updated from csv.
@@ -148,8 +150,7 @@ def LoadCaveTab():
 
             newCave.save()
 
-            logging.info("Added area "+line[Area]+" to cave "+str(newCave)+"\n")
-
+            logging.info("Added area "+line[Area]+" to cave "+str(newCave)+"\n") 
             if created and line[UnofficialName]:
                 newUnofficialName = models.OtherCaveName(cave = newCave, name = line[UnofficialName])
                 newUnofficialName.save()
@@ -161,70 +162,80 @@ def LoadCaveTab():
             line[MultipleEntrances] == 'entrance' or \
             line[MultipleEntrances] == 'last entrance':
             args = {}
-
-            if line[Entrances]:
-                entrance_letter = line[Entrances]
-            else:
-                entrance_letter = ''
-
             def addToArgs(CSVname, modelName):
                 if line[CSVname]:
                     args[modelName] = line[CSVname]
             def addToArgsViaDict(CSVname, modelName, dictionary):
                 if line[CSVname]:
                     args[modelName] = dictionary[line[CSVname]]
-            addToArgs(EntranceName, 'name')
-            addToArgs(Explorers, 'explorers')
-            addToArgs(Map, 'map_description')
-            addToArgs(Location, 'location_description')
-            addToArgs(Approach, 'approach')
-            addToArgs(EntranceDescription, 'entrance_description')
-            addToArgs(UndergroundDescription, 'underground_description')
-            addToArgs(PhotoOfLocation, 'photo')
-            addToArgsViaDict(Marking, 'marking', {"Paint": "P",
-                                                "Paint (?)": "P?",
-                                                "Tag": "T",
-                                                "Tag (?)": "T?",
-                                                "Retagged": "R",
-                                                "Retag": "R",
-                                                "Spit": "S",
-                                                "Spit (?)": "S?",
-                                                "Unmarked": "U",
-                                                "": "?",
-                                                })
+             
+            if line[Entrances]:
+                entrance_letter = line[Entrances]
+            else:
+                entrance_letter = ''
 
-            addToArgs(MarkingComment, 'marking_comment')
-            addToArgsViaDict(Findability, 'findability', {"Surveyed": "S",
-                                                        "Lost": "L",
-                                                        "Refindable": "R",
-                                                        "": "?",
-                                                        "?": "?",
-                                                        })
-            addToArgs(FindabilityComment, 'findability_description')
-            addToArgs(Easting, 'easting')
-            addToArgs(Northing, 'northing')
-            addToArgs(Altitude, 'alt')
-            addToArgs(DescriptionOfOtherPoint, 'other_description')
-            addToArgs(TagPoint, 'tag_station')
-            addToArgs(ExactEntrance, 'exact_station')
-            addToArgs(OtherPoint, 'other_station')
-            addToArgs(OtherPoint, 'other_description')
-            if line[GPSpreSA]:
-                addToArgs(GPSpreSA, 'other_station')
-                args['other_description'] = 'pre selective availability GPS'
-            if line[GPSpostSA]:
-                addToArgs(GPSpostSA, 'other_station')
-                args['other_description'] = 'post selective availability GPS'
-            addToArgs(Bearings, 'bearings')
-            args['slug'] = newCave.slug + entrance_letter
-            newEntrance = models.Entrance(**args)
-            newEntrance.save()
+            if not line[LinkFile]:
+                addToArgs(Map, 'map_description')
+                addToArgs(Location, 'location_description')
+                addToArgs(Approach, 'approach')
+                addToArgs(EntranceDescription, 'entrance_description')
+                if line[MultipleEntrances] == 'entrance' or \
+                   line[MultipleEntrances] == 'last entrance':
+                    addToArgs(UndergroundDescription, 'underground_description')
+                    addToArgs(AutogenFile, 'url')
+                    addToArgs(EntranceName, 'name')
+                    addToArgs(Explorers, 'explorers')
+                addToArgs(PhotoOfLocation, 'photo')
+                addToArgsViaDict(Marking, 'marking', {"Paint": "P",
+                                                      "Paint (?)": "P?",
+                                                      "Tag": "T",
+                                                      "Tag (?)": "T?",
+                                                      "Retagged": "R",
+                                                      "Retag": "R",
+                                                      "Spit": "S",
+                                                      "Spit (?)": "S?",
+                                                      "Unmarked": "U",
+                                                      "": "?",
+                                                      })
 
-            logging.info("Added entrance "+str(newEntrance)+"\n")
+                addToArgs(MarkingComment, 'marking_comment')
+                addToArgsViaDict(Findability, 'findability', {"Surveyed": "S",
+                                                            "Lost": "L",
+                                                            "Refindable": "R",
+                                                            "": "?",
+                                                            "?": "?",
+                                                            })
+                addToArgs(FindabilityComment, 'findability_description')
+                addToArgs(Easting, 'easting')
+                addToArgs(Northing, 'northing')
+                addToArgs(Altitude, 'alt')
+                addToArgs(DescriptionOfOtherPoint, 'other_description')
+                addToArgs(TagPoint, 'tag_station')
+                addToArgs(ExactEntrance, 'exact_station')
+                addToArgs(OtherPoint, 'other_station')
+                addToArgs(OtherPoint, 'other_description')
+                if line[GPSpreSA]:
+                    addToArgs(GPSpreSA, 'other_station')
+                    args['other_description'] = 'pre selective availability GPS'
+                if line[GPSpostSA]:
+                    addToArgs(GPSpostSA, 'other_station')
+                    args['other_description'] = 'post selective availability GPS'
+                addToArgs(Bearings, 'bearings')
+                args["filename"] = "%s.html" % (slug + entrance_letter)
+            
+                newEntrance = models.Entrance(**args)
+                newEntrance.save()
+                es = models.EntranceSlug(slug = slug + entrance_letter, entrance = newEntrance, primary = True)
+                es.save()
+      
+
+                logging.info("Added entrance "+str(newEntrance)+"\n")
 
 
-            newCaveAndEntrance = models.CaveAndEntrance(cave = newCave, entrance = newEntrance, entrance_letter = entrance_letter)
-            newCaveAndEntrance.save()
+                newCaveAndEntrance = models.CaveAndEntrance(cave = newCave, 
+                                                            entrance = newEntrance, 
+                                                            entrance_letter = entrance_letter)
+                newCaveAndEntrance.save()
 
             logging.info("Added CaveAndEntrance "+str(newCaveAndEntrance)+"\n")
             if line[AutogenFile] != "":
diff --git a/parsers/survex.py b/parsers/survex.py
index 2e0b8d3..d43c303 100644
--- a/parsers/survex.py
+++ b/parsers/survex.py
@@ -59,7 +59,11 @@ def LoadSurvexLineLeg(survexblock, stardata, sline, comment):
         survexblock.save()
         
 def LoadSurvexEquate(survexblock, sline):
-    pass
+    #print sline #
+    stations = sline.split()
+    assert len(stations) > 1
+    for station in stations:
+        survexblock.MakeSurvexStation(station)
 
 def LoadSurvexLinePassage(survexblock, stardata, sline, comment):
     pass
@@ -109,6 +113,7 @@ def RecursiveLoad(survexblock, survexfile, fin, textlines):
         
         # detect the star command
         cmd, line = mstar.groups()
+        cmd = cmd.lower()
         if re.match("include$(?i)", cmd):
             includepath = os.path.join(os.path.split(survexfile.path)[0], re.sub("\.svx$", "", line))
             includesurvexfile = models.SurvexFile(path=includepath, cave=survexfile.cave)
@@ -177,10 +182,12 @@ def RecursiveLoad(survexblock, survexfile, fin, textlines):
                 assert ls[0] == "passage", line
         
         elif cmd == "equate":
-            LoadSurvexEquate(survexblock, sline)
-        
+            LoadSurvexEquate(survexblock, line)
+
+        elif cmd == "fix":
+            survexblock.MakeSurvexStation(line.split()[0])
         else:
-            assert cmd.lower() in [ "sd", "equate", "include", "units", "entrance", "fix", "data", "flags", "title", "export", "instrument", "calibrate", "set", "infer"], (cmd, line, survexblock)
+            assert cmd in [ "sd", "include", "units", "entrance", "data", "flags", "title", "export", "instrument", "calibrate", "set", "infer"], (cmd, line, survexblock)
         
         
 
@@ -211,6 +218,7 @@ def LoadAllSurvexBlocks():
     models.SurvexLeg.objects.all().delete()
     models.SurvexTitle.objects.all().delete()
     models.SurvexPersonRole.objects.all().delete()
+    models.SurvexStation.objects.all().delete()
 
     survexfile = models.SurvexFile(path="all", cave=None)
     survexfile.save()
@@ -248,7 +256,8 @@ def LoadPos():
             try:
                 ss = models.SurvexStation.objects.lookup(name)
             except:
-                pass
+                print name
             ss.x = float(x)
             ss.y = float(y)
             ss.z = float(z)
+            ss.save()
diff --git a/settings.py b/settings.py
index 50fbbae..5e8ba64 100644
--- a/settings.py
+++ b/settings.py
@@ -36,6 +36,8 @@ USE_I18N = True
 # Examples: "http://foo.com/media/", "/media/".
 ADMIN_MEDIA_PREFIX = '/troggle/media-admin/'
 PHOTOS_ROOT = os.path.join(EXPOWEB, 'photos')
+CAVEDESCRIPTIONS = os.path.join(EXPOWEB, "noinfo", "cave_data")
+ENTRANCEDESCRIPTIONS = os.path.join(EXPOWEB, "noinfo", "entrance_data")
 
 MEDIA_URL = urlparse.urljoin(URL_ROOT , '/site_media/')
 SURVEYS_URL = urlparse.urljoin(URL_ROOT , '/survey_scans/')
diff --git a/templates/cave.html b/templates/cave.html
index 5f761b7..f38f66d 100644
--- a/templates/cave.html
+++ b/templates/cave.html
@@ -1,6 +1,5 @@
 {% extends "cavebase.html" %}
 
-
 {% block content %}
 {% block contentheader %}
 <table id="cavepage">
diff --git a/templates/cave_entrances.html b/templates/cave_entrances.html
index e871e41..1ad4db0 100644
--- a/templates/cave_entrances.html
+++ b/templates/cave_entrances.html
@@ -7,7 +7,7 @@
         {{ ent.entrance_letter|safe }}
         {% if ent.entrance.name %}
             {{ ent.entrance.name|safe }}
-        {% endif %}        
+        {% endif %}<a href="{% url editentrance ent.entrance.slug %}">Edit</a>
         <dl>
         {% if ent.entrance.marking %}
             <dt>Marking</dt><dd>{{ ent.entrance.marking_val|safe }}</dd>
diff --git a/templates/dataformat/cave.xml b/templates/dataformat/cave.xml
new file mode 100644
index 0000000..f0894d4
--- /dev/null
+++ b/templates/dataformat/cave.xml
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<!-- Only put one cave in this file -->
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+<cave>
+<non_public>{{ cave.non_public }}</non_public>{% for slug in cave.caveslug_set.all %}
+<caveslug>{{ slug.slug|default_if_none:""|safe }}</caveslug>{% endfor %}
+<official_name>{{ cave.official_name|default_if_none:""|safe }}</official_name>{% for area in cave.area.all %}
+<area>{{ area.short_name|default_if_none:""|safe }}</area>{% endfor %}
+<kataster_code>{{ cave.kataster_code|default_if_none:""|safe }}</kataster_code>
+<kataster_number>{{ cave.kataster_number|default_if_none:""|safe }}</kataster_number> 
+<unofficial_number>{{ cave.unofficial_number|default_if_none:""|safe }}</unofficial_number>
+{% for ce in cave.entrances.all %}
+<entrance>
+  <entranceslug>{{ ce.entrance.slug|default_if_none:""|safe }}</entranceslug>
+  <letter>{{ ce.entrance_letter|default_if_none:""|safe }}</letter>
+</entrance>
+{% endfor %}
+<explorers>{{ cave.explorers|default_if_none:""|safe }}</explorers>
+<underground_description>{{ cave.underground_description|default_if_none:""|safe }}</underground_description>
+<equipment>{{ cave.equipment|default_if_none:""|safe }}</equipment>
+<references>{{ cave.references|default_if_none:""|safe }}</references>
+<survey>{{ cave.survey|default_if_none:""|safe }}</survey>
+<kataster_status>{{ cave.kataster_status|default_if_none:""|safe }}</kataster_status>
+<underground_centre_line>{{ cave.underground_centre_line|default_if_none:""|safe }}</underground_centre_line>
+<notes>{{ cave.notes|default_if_none:""|safe }}</notes>
+<length>{{ cave.length|default_if_none:""|safe }}</length>
+<depth>{{ cave.depth|default_if_none:""|safe }}</depth>
+<extent>{{cave.extent|default_if_none:""|safe }}</extent>
+<survex_file>{{ cave.survex_file|default_if_none:""|safe }}</survex_file>
+<description_file>{{ cave.description_file|default_if_none:""|safe }}</description_file>
+<url>{{ cave.url|default_if_none:""|safe }}</url>
+</cave>
+</body>
+</html>
diff --git a/templates/dataformat/entrance.xml b/templates/dataformat/entrance.xml
new file mode 100644
index 0000000..bdf63ac
--- /dev/null
+++ b/templates/dataformat/entrance.xml
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<!-- Only put one entrance in this file -->
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+<body>
+<entrance>
+<non_public>{{ entrance.non_public }}</non_public>{% for slug in entrance.entranceslug_set.all %}
+<slug>{{ slug.slug|default_if_none:""|safe }}</slug>{% endfor %}
+<name>{{ entrance.name|default_if_none:""|safe }}</name>
+<entrance_description>{{ entrance.entrance_description|default_if_none:""|safe }}</entrance_description>
+<explorers>{{ entrance.explorers|default_if_none:""|safe }}</explorers>
+<map_description>{{ entrance.map_description|default_if_none:""|safe }}</map_description>
+<location_description>{{ entrance.location_description|default_if_none:""|safe }}</location_description>
+<approach>{{ entrance.approach|default_if_none:""|safe }}</approach>
+<underground_description>{{ entrance.underground_description|default_if_none:""|safe }}</underground_description>
+<photo>{{ entrance.photo|default_if_none:""|safe }}</photo>
+<!-- marking options: P  = Paint,
+                      P? = Paint (?),
+                      T  = Tag,
+                      T? = Tag (?),
+                      R  = Retagged,
+                      S  = Spit,
+                      S? = Spit (?),
+                      U  = Unmarked,
+                      ?  = Unknown" -->
+<marking>{{ entrance.marking|default_if_none:""|safe }}</marking> 
+<marking_comment>{{ entrance.marking_comment|default_if_none:""|safe }}</marking_comment>
+<!-- findability options: ? = To be confirmed ...,
+                          S = Surveyed,
+                          L = Lost,
+                          R = Refindable" -->
+<findability>{{ entrance.findability|default_if_none:""|safe }}</findability>
+<findability_description>{{ entrance.findability_description|default_if_none:""|safe }}</findability_description>
+<alt>{{ entrance.alt|default_if_none:""|safe }}</alt>
+<northing>{{ entrance.northing|default_if_none:""|safe }}</northing>
+<easting>{{ entrance.easting|default_if_none:""|safe }}</easting> 
+<tag_station>{{ entrance.tag_station|default_if_none:""|safe }}</tag_station>
+<exact_station>{{ entrance.exact_station|default_if_none:""|safe }}</exact_station>
+<other_station>{{ entrance.other_station|default_if_none:""|safe }}</other_station>
+<other_description>{{ entrance.other_description|default_if_none:""|safe }}</other_description>
+<bearings>{{ entrance.bearings|default_if_none:""|safe }}</bearings>
+<url>{{ entrance.url|default_if_none:""|safe }}</url>
+</entrance>
+</body>
+</html>
diff --git a/templates/editcave2.html b/templates/editcave2.html
index feb4498..e57b4cd 100644
--- a/templates/editcave2.html
+++ b/templates/editcave2.html
@@ -9,9 +9,9 @@
 <script src="{{ settings.TINY_MCE_MEDIA_URL }}tiny_mce.js" type="text/javascript"></script>
 {% endblock %}
 {% block content %}
-<strong> This form does not do anything .... yet ....</strong>
 <form action="" method="post">{% csrf_token %}
     <table>{{ form }}{{caveAndEntranceFormSet}}</table>
+    {{ versionControlForm }}
     <p><input type="submit" value="Sumbit" /></p>
 </form>
 
diff --git a/templates/editentrance.html b/templates/editentrance.html
new file mode 100644
index 0000000..d17d1f9
--- /dev/null
+++ b/templates/editentrance.html
@@ -0,0 +1,18 @@
+{% extends "cavebase.html" %}
+{% load csrffaker %} 
+{% block title %}Edit Entrance{% endblock %}
+{% block extraheaders %}
+
+<link rel="stylesheet" href="{{ settings.MEDIA_URL }}css/ui-lightness/jquery-ui-1.8.12.custom.css" type="text/css" media="all" />
+<script src="{{ settings.MEDIA_URL }}js/jquery-ui-1.8.12.custom.min.js" type="text/javascript"></script>
+<script src="{{ settings.MEDIA_URL }}js/jquery.formset.min.js" type="text/javascript"></script>
+<script src="{{ settings.TINY_MCE_MEDIA_URL }}tiny_mce.js" type="text/javascript"></script>
+{% endblock %}
+{% block content %}
+<form action="" method="post">{% csrf_token %}
+    <table>{{ form }}</table>
+    {{ versionControlForm }}
+    <p><input type="submit" value="Sumbit" /></p>
+</form>
+
+{% endblock %}
diff --git a/urls.py b/urls.py
index 02bd134..01b0185 100644
--- a/urls.py
+++ b/urls.py
@@ -49,6 +49,7 @@ actualurlpatterns = patterns('',
     url(r'^cave/description/([^/]+)/?$', views_caves.caveDescription),
     url(r'^cave/qms/([^/]+)/?$', views_caves.caveQMs),
     url(r'^cave/logbook/([^/]+)/?$', views_caves.caveLogbook),
+    url(r'^entrance/(?P<slug>[^/]+)/edit/', views_caves.editEntrance, name = "editentrance"),
     #url(r'^cavedescription/(?P<cavedescription_name>[^/]+)/?$', views_caves.cave_description, name="cavedescription"),
     #url(r'^cavedescription/?$', object_list, {'queryset':CaveDescription.objects.all(),'template_name':'object_list.html'}, name="cavedescriptions"),
     #url(r'^cavehref/(.+)$',     views_caves.cave,       name="cave"),url(r'cave'),
@@ -83,7 +84,8 @@ actualurlpatterns = patterns('',
     url(r'^eyecandy$', views_other.eyecandy),
 
     (r'^admin/doc/?', include('django.contrib.admindocs.urls')),
-    url(r'^admin/(.*)', admin.site.get_urls, name="admin"),
+    #url(r'^admin/(.*)', admin.site.get_urls, name="admin"),
+    (r'^admin/', include(admin.site.urls)),
     
     # don't know why this needs troggle/ in here.  nice to get it out
     url(r'^troggle/media-admin/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ADMIN_DIR, 'show_indexes':True}),