Index: trunk/images_nodist/session.svg
===================================================================
--- trunk/images_nodist/session.svg	(revision 4668)
+++ trunk/images_nodist/session.svg	(revision 4668)
@@ -0,0 +1,649 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="51.08881"
+   height="40.82074"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.45.1"
+   sodipodi:docbase="/home/marco/svg/2008"
+   sodipodi:docname="box-open-0.1.svg"
+   version="1.0"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3815">
+      <stop
+         style="stop-color:#b1883f;stop-opacity:1;"
+         offset="0"
+         id="stop3817" />
+      <stop
+         style="stop-color:#b1883f;stop-opacity:0;"
+         offset="1"
+         id="stop3819" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient7504">
+      <stop
+         style="stop-color:white;stop-opacity:0.53218883"
+         offset="0"
+         id="stop7506" />
+      <stop
+         style="stop-color:white;stop-opacity:0;"
+         offset="1"
+         id="stop7508" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5734">
+      <stop
+         style="stop-color:white;stop-opacity:0.88627452"
+         offset="0"
+         id="stop5736" />
+      <stop
+         style="stop-color:white;stop-opacity:0.14509805"
+         offset="1"
+         id="stop5738" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5838">
+      <stop
+         style="stop-color:#7c6634;stop-opacity:1;"
+         offset="0"
+         id="stop5840" />
+      <stop
+         style="stop-color:#5f4e28;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop5842" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5056">
+      <stop
+         id="stop5058"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:0.13541667;" />
+      <stop
+         id="stop5060"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5050">
+      <stop
+         id="stop5052"
+         offset="0.0000000"
+         style="stop-color:#000000;stop-opacity:0.15625000;" />
+      <stop
+         id="stop5054"
+         offset="1"
+         style="stop-color:#000000;stop-opacity:0;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5030">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.20833331;"
+         offset="0.0000000"
+         id="stop5032" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop5034" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4294">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.66799998"
+         offset="0"
+         id="stop4296" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4298" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3546">
+      <stop
+         style="stop-color:#e6be76;stop-opacity:1;"
+         offset="0"
+         id="stop3548" />
+      <stop
+         style="stop-color:#ba9a5f;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop3550" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5734"
+       id="linearGradient5740"
+       x1="46"
+       y1="37.749943"
+       x2="63.75"
+       y2="102.78278"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.388313,0,0,0.376593,-5.514659e-2,-2.49561)" />
+    <linearGradient
+       y2="42.025642"
+       y1="12.897436"
+       xlink:href="#linearGradient2166"
+       x2="63.358974"
+       x1="97.410255"
+       inkscape:collect="always"
+       id="linearGradient2176"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.384615,8.589744)" />
+    <linearGradient
+       y2="12"
+       y1="41"
+       xlink:href="#linearGradient2166"
+       x2="95"
+       x1="61"
+       inkscape:collect="always"
+       id="linearGradient2172"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.384615,8.589744)" />
+    <linearGradient
+       y2="895.68713"
+       y1="1079.7177"
+       xlink:href="#linearGradient1017"
+       x2="441.94626"
+       x1="97.909615"
+       inkscape:collect="always"
+       id="linearGradient6641"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.154701,0.866025)" />
+    <linearGradient
+       y2="1285.3988"
+       y1="1285.3988"
+       xlink:href="#linearGradient1017"
+       x2="84.609047"
+       x1="181.43164"
+       inkscape:collect="always"
+       id="linearGradient5876"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.154701,0.866025)" />
+    <linearGradient
+       y2="21.069715"
+       y1="813.86877"
+       xlink:href="#linearGradient6517"
+       x2="841.63055"
+       x1="45.506062"
+       inkscape:collect="always"
+       id="linearGradient5092"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.928107,0,0,0.69608,-112.1865,694.2911)" />
+    <linearGradient
+       id="linearGradient8387">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.0000000;"
+         offset="0.0000000"
+         id="stop8388" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.098039217;"
+         offset="0.42613181"
+         id="stop8392" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.16853933;"
+         offset="0.52207208"
+         id="stop8389" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.098039217;"
+         offset="0.63933450"
+         id="stop8391" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop8390" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient6517">
+      <stop
+         style="stop-color:#002f8a;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop6518" />
+      <stop
+         style="stop-color:#005dcc;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop6520" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2152">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2153" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.49803922;"
+         offset="0.0099999998"
+         id="stop2778" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop2154" />
+    </linearGradient>
+    <linearGradient
+       y2="-157.47726"
+       y1="-177.46144"
+       xlink:href="#linearGradient1022"
+       x2="9.707943"
+       x1="-8.4761829"
+       id="linearGradient1021"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.578926,0.633342)" />
+    <linearGradient
+       y2="-127.91295"
+       y1="-154.59496"
+       xlink:href="#linearGradient1017"
+       x2="12.010341"
+       x1="-3.191411"
+       id="linearGradient1025"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.555191,0.643008)" />
+    <linearGradient
+       y2="-178.84084"
+       y1="-210.38924"
+       xlink:href="#linearGradient1017"
+       x2="-19.672827"
+       x1="-27.045366"
+       id="linearGradient1026"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.916124,0.521887)" />
+    <linearGradient
+       id="linearGradient2302">
+      <stop
+         style="stop-color:#2c3d78;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2303" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2304" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1022">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.40833300;"
+         offset="0.0000000"
+         id="stop1024" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop1023" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient1017">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.17500000;"
+         offset="0.0000000"
+         id="stop1019" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0.37500000;"
+         offset="1.0000000"
+         id="stop1018" />
+    </linearGradient>
+    <defs
+       id="defs877">
+      <linearGradient
+         y2="0.5"
+         y1="0.5"
+         xlink:href="#linearGradient1017"
+         x2="1"
+         x1="0"
+         spreadMethod="pad"
+         id="linearGradient585"
+         gradientUnits="objectBoundingBox" />
+      <linearGradient
+         y2="0.5"
+         y1="0.5"
+         xlink:href="#linearGradient1022"
+         x2="1"
+         x1="0"
+         spreadMethod="pad"
+         id="linearGradient579"
+         gradientUnits="objectBoundingBox" />
+      <linearGradient
+         y2="0.60227275"
+         y1="0.51136363"
+         xlink:href="#linearGradient579"
+         x2="0.41176471"
+         x1="0.4852941"
+         id="linearGradient582" />
+      <linearGradient
+         y2="1.0964912"
+         y1="0.12280702"
+         xlink:href="#linearGradient585"
+         x2="0.3272059"
+         x1="0.50735295"
+         id="linearGradient584" />
+      <linearGradient
+         xlink:href="#linearGradient585"
+         id="linearGradient589" />
+    </defs>
+    <linearGradient
+       id="linearGradient3658">
+      <stop
+         style="stop-color:#ffff47;stop-opacity:1;"
+         offset="0"
+         id="stop3660" />
+      <stop
+         style="stop-color:#ffdd47;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop3662" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4564">
+      <stop
+         style="stop-color:#c6a965;stop-opacity:1;"
+         offset="0"
+         id="stop4566" />
+      <stop
+         style="stop-color:#b79d5d;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop4568" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4580">
+      <stop
+         style="stop-color:#d3b46b;stop-opacity:1;"
+         offset="0"
+         id="stop4582" />
+      <stop
+         style="stop-color:#ad9457;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop4584" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4596">
+      <stop
+         style="stop-color:#937541;stop-opacity:1;"
+         offset="0"
+         id="stop4598" />
+      <stop
+         style="stop-color:#524124;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop4600" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4612">
+      <stop
+         style="stop-color:#193670;stop-opacity:1;"
+         offset="0"
+         id="stop4614" />
+      <stop
+         style="stop-color:#132955;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop4616" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2166">
+      <stop
+         style="stop-color:#009300;stop-opacity:1.0000000;"
+         offset="0.0000000"
+         id="stop2168" />
+      <stop
+         style="stop-color:#00cd00;stop-opacity:1.0000000;"
+         offset="1.0000000"
+         id="stop2170" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3755"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,1.055011,1.5082821)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3759"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,1.0550113,1.5082821)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5030"
+       id="radialGradient3765"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0177515,0,0,0.1310797,127.25834,37.243336)"
+       cx="-59.60252"
+       cy="522.11993"
+       fx="-59.60252"
+       fy="522.11993"
+       r="61.16605" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5030"
+       id="radialGradient3796"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0177515,0,0,0.1310797,127.25834,37.243336)"
+       cx="-59.60252"
+       cy="522.11993"
+       fx="-59.60252"
+       fy="522.11993"
+       r="61.16605" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3803"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-64.882697,27.267619)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3806"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-64.882697,27.267619)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3815"
+       id="linearGradient3821"
+       x1="-79.732391"
+       y1="63.816757"
+       x2="-80.912842"
+       y2="57.477097"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1,0,0,-1,-165.99332,117.92031)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3815"
+       id="linearGradient3838"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1,0,0,-1,-113.1261,122.66317)"
+       x1="-79.732391"
+       y1="63.816757"
+       x2="-82.772545"
+       y2="59.333252" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3841"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-11.944989,32.258282)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3844"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-11.944989,32.258282)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5030"
+       id="radialGradient3861"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0177515,0,0,0.1310797,127.25834,37.243336)"
+       cx="-59.60252"
+       cy="522.11993"
+       fx="-59.60252"
+       fy="522.11993"
+       r="61.16605" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3863"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-11.944989,32.258282)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient3865"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.341035,0,0,0.341035,-11.944989,32.258282)"
+       x1="-81.671494"
+       y1="-10.987402"
+       x2="-83.836975"
+       y2="190.88261" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3815"
+       id="linearGradient3867"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1,0,0,-1,-113.1261,122.66317)"
+       x1="-79.732391"
+       y1="63.816757"
+       x2="-82.772545"
+       y2="59.333252" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8284271"
+     inkscape:cx="20.570675"
+     inkscape:cy="-26.943759"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="913"
+     inkscape:window-height="710"
+     inkscape:window-x="30"
+     inkscape:window-y="5"
+     showborder="false"
+     showgrid="false"
+     inkscape:showpageshadow="false"
+     width="48px"
+     height="48px" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(110.04367,-53.811123)">
+    <g
+       id="g6343"
+       inkscape:groupmode="layer"
+       inkscape:label="Layer 1"
+       transform="matrix(0.6454805,0,0,0.6454805,234.71183,124.03662)" />
+    <g
+       id="g9086"
+       inkscape:groupmode="layer"
+       inkscape:label="Layer 1"
+       transform="matrix(0.6454805,0,0,0.6454805,180.49147,34.726518)" />
+    <g
+       id="g3825">
+      <path
+         inkscape:transform-center-x="-6.026071"
+         inkscape:transform-center-y="-8.329675"
+         sodipodi:nodetypes="cccsc"
+         id="path3823"
+         d="M -86.623105,54.489535 C -86.623105,54.489535 -93.37311,59.924486 -93.37311,59.924486 L -107.6537,65.549227 C -107.6537,65.549227 -100.31677,58.695342 -100.31677,58.695342 C -100.31677,58.695342 -86.623105,54.489535 -86.623105,54.489535 z "
+         style="fill:#b1883f;fill-opacity:1;fill-rule:evenodd;stroke:#746137;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         transform="matrix(0.4176239,0,0,0.8311427,-112.31209,-3.117884)"
+         d="M 127.76384 105.68266 A 61.16605 11.926199 0 1 1  5.431736,105.68266 A 61.16605 11.926199 0 1 1  127.76384 105.68266 z"
+         sodipodi:ry="11.926199"
+         sodipodi:rx="61.16605"
+         sodipodi:cy="105.68266"
+         sodipodi:cx="66.597786"
+         id="path3782"
+         style="color:#000000;fill:url(#radialGradient3796);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         sodipodi:type="arc" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3784"
+         d="M -80.885932,63.528182 L -100.31271,58.888017 L -100.43771,83.714158 L -80.885932,88.352168 L -80.885932,63.528182 z "
+         style="fill:#c7a465;fill-opacity:1;fill-rule:nonzero;stroke:#746137;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3786"
+         d="M -80.495766,63.524502 L -66.479523,59.312192 L -66.391135,83.70756 L -80.459155,88.259337 L -80.495766,63.524502 z "
+         style="fill:#c7a465;fill-opacity:1;fill-rule:nonzero;stroke:#746137;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3788"
+         d="M -85.961079,54.311123 L -66.273711,59.022967 L -80.767049,63.259337 L -100.43771,58.703685 L -85.961079,54.311123 z "
+         style="fill:#82642f;fill-opacity:1;fill-rule:nonzero;stroke:#746137;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3792"
+         d="M -81.417561,63.863221 L -81.417561,76.74957 C -84.694545,80.06392 -99.979165,55.276567 -99.786401,78.409507 L -99.778553,59.474836 L -81.417561,63.863221 z "
+         style="opacity:0.81171546;fill:url(#linearGradient3806);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path3794"
+         d="M -79.986992,63.85196 C -79.986992,63.85196 -79.986992,76.738309 -79.986992,76.738309 C -75.383439,57.824095 -66.709947,64.559769 -67.063501,59.963575 L -79.986992,63.85196 z "
+         style="opacity:0.81171546;fill:url(#linearGradient3803);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         inkscape:transform-center-y="-8.3223685"
+         inkscape:transform-center-x="-10.429825"
+         sodipodi:nodetypes="cccsc"
+         id="path3790"
+         d="M -74.31573,72.895758 C -74.31573,72.895758 -80.5743,63.739982 -80.5743,63.739982 L -65.875944,59.320564 C -65.875944,59.320564 -60.822643,68.096899 -60.822643,68.096899 C -60.822643,68.096899 -74.31573,72.895758 -74.31573,72.895758 z "
+         style="fill:#b1883f;fill-opacity:1;fill-rule:evenodd;stroke:#746137;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path3813"
+         d="M -67.705475,59.313708 C -67.705475,59.313708 -86.090252,55.071068 -86.090252,55.071068 L -98.02896,58.731601 C -83.77896,63.231601 -80.205475,57.188708 -67.705475,59.313708 z "
+         style="fill:url(#linearGradient3821);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
Index: trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 4668)
+++ trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java	(revision 4668)
@@ -0,0 +1,136 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import javax.swing.filechooser.FileFilter;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.session.SessionReader;
+
+public class SessionLoadAction extends JosmAction {
+    public SessionLoadAction() {
+        super(tr("Load Session"), "open", tr("Load a session from file."), null, false);
+        putValue("help", ht("/Action/SessionLoad"));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        String curDir = Main.pref.get("lastDirectory");
+        if (curDir.equals("")) {
+            curDir = ".";
+        }
+        JFileChooser fc = new JFileChooser(new File(curDir));
+        fc.setDialogTitle(tr("Open session"));
+        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
+        fc.setMultiSelectionEnabled(false);
+        fc.setAcceptAllFileFilterUsed(true);
+        FileFilter ff = new ExtensionFileFilter("jos,joz", "jos", tr("Session file (*.jos, *.joz)"));
+        fc.addChoosableFileFilter(ff);
+        int answer = fc.showOpenDialog(Main.parent);
+        if (answer != JFileChooser.APPROVE_OPTION)
+            return;
+
+        if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
+            Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
+        }
+        File file = fc.getSelectedFile();
+        boolean zip = true;
+        if (file.getName().toLowerCase().endsWith(".jos")) {
+            zip = false;
+        }
+        Main.worker.submit(new Loader(file, zip));
+    }
+
+    public class Loader extends PleaseWaitRunnable {
+
+        private boolean canceled;
+        private File file;
+        private boolean zip;
+        private List<Layer> layers;
+        private List<Runnable> postLoadTasks;
+
+        public Loader(File file, boolean zip) {
+            super(tr("Loading session ''{0}''", file.getName()));
+            this.file = file;
+            this.zip = zip;
+        }
+
+        @Override
+        protected void cancel() {
+            Thread.currentThread().dumpStack();
+            canceled = true;
+        }
+
+        @Override
+        protected void finish() {
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    if (canceled) return;
+                    for (Layer l : layers) {
+                        if (canceled) return;
+                        Main.main.addLayer(l);
+                    }
+                    for (Runnable task : postLoadTasks) {
+                        if (canceled) return;
+                        if (task == null) continue;
+                        task.run();
+                    }
+                }
+            });
+        }
+
+        @Override
+        protected void realRun() {
+            try {
+                ProgressMonitor monitor = getProgressMonitor();
+                SessionReader reader = new SessionReader();
+                reader.loadSession(file, zip, monitor);
+                layers = reader.getLayers();
+                postLoadTasks = reader.getPostLoadTasks();
+            } catch (IllegalDataException e) {
+                e.printStackTrace();
+                HelpAwareOptionPane.showMessageDialogInEDT(
+                        Main.parent,
+                        tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", file.getName(), e.getMessage()),
+                        tr("Data Error"),
+                        JOptionPane.ERROR_MESSAGE,
+                        null
+                );
+                cancel();
+            } catch (IOException e) {
+                e.printStackTrace();
+                HelpAwareOptionPane.showMessageDialogInEDT(
+                        Main.parent,
+                        tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", file.getName(), e.getMessage()),
+                        tr("IO Error"),
+                        JOptionPane.ERROR_MESSAGE,
+                        null
+                );
+                cancel();
+            } catch (RuntimeException e) {
+                cancel();
+                throw e;
+            } catch (Throwable t) {
+                cancel();
+                throw new RuntimeException(t);
+            }
+        }
+    }
+}
+
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 4667)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 4668)
@@ -70,4 +70,5 @@
 import org.openstreetmap.josm.actions.SaveAsAction;
 import org.openstreetmap.josm.actions.SelectAllAction;
+import org.openstreetmap.josm.actions.SessionLoadAction;
 import org.openstreetmap.josm.actions.ShowStatusReportAction;
 import org.openstreetmap.josm.actions.SimplifyWayAction;
@@ -98,4 +99,5 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.tagging.TaggingPresetSearchAction;
+import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Shortcut;
 
@@ -117,4 +119,5 @@
     public final JosmAction save = new SaveAction();
     public final JosmAction saveAs = new SaveAsAction();
+    public final JosmAction sessionLoad = new SessionLoadAction();
     public final JosmAction gpxExport = new GpxExportAction();
     public final DownloadAction download = new DownloadAction();
@@ -190,4 +193,5 @@
 
     public final JMenu fileMenu = addMenu(marktr("File"), KeyEvent.VK_F, 0, ht("/Menu/File"));
+    public final JMenu sessionMenu = new JMenu(tr("Session")); // submenu of the file menu
     public final JMenu editMenu = addMenu(marktr("Edit"), KeyEvent.VK_E, 1, ht("/Menu/Edit"));
     public final JMenu viewMenu = addMenu(marktr("View"), KeyEvent.VK_V, 2, ht("/Menu/View"));
@@ -206,4 +210,5 @@
     public JMenu audioMenu = null;
     public final JMenu helpMenu = addMenu(marktr("Help"), KeyEvent.VK_H, 7, ht("/Menu/Help"));
+
     public final int defaultMenuPos = 7;
 
@@ -357,4 +362,10 @@
         add(fileMenu, save);
         add(fileMenu, saveAs);
+        if (Main.pref.getBoolean("session")) {
+            sessionMenu.setToolTipText(tr("Save and load the current session (list of layers, etc.)"));
+            sessionMenu.setIcon(ImageProvider.get("session"));
+            add(sessionMenu, sessionLoad);
+            fileMenu.add(sessionMenu);
+        }
         add(fileMenu, gpxExport);
         fileMenu.addSeparator();
Index: trunk/src/org/openstreetmap/josm/io/OsmImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmImporter.java	(revision 4667)
+++ trunk/src/org/openstreetmap/josm/io/OsmImporter.java	(revision 4668)
@@ -22,4 +22,7 @@
 public class OsmImporter extends FileImporter {
 
+    private OsmDataLayer layer;
+    private Runnable postLayerTask;
+
     public OsmImporter() {
         super(new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files") + " (*.osm *.xml)"));
@@ -30,5 +33,6 @@
     }
 
-    @Override public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
+    @Override
+    public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
         try {
             FileInputStream in = new FileInputStream(file);
@@ -41,23 +45,11 @@
 
     protected void importData(InputStream in, final File associatedFile) throws IllegalDataException {
-        final DataSet dataSet = OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
-        final OsmDataLayer layer = new OsmDataLayer(dataSet, associatedFile.getName(), associatedFile);
-        addDataLayer(dataSet, layer, associatedFile.getPath()); 
-    }
-        
-    protected void addDataLayer(final DataSet dataSet, final OsmDataLayer layer, final String filePath) { 
+        loadLayer(in, associatedFile, associatedFile.getName(), NullProgressMonitor.INSTANCE);
         // FIXME: remove UI stuff from IO subsystem
-        //
         Runnable uiStuff = new Runnable() {
             @Override
             public void run() {
-                if (dataSet.allPrimitives().isEmpty()) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("No data found in file {0}.", filePath),
-                            tr("Open OSM file"),
-                            JOptionPane.INFORMATION_MESSAGE);
-                }
                 Main.main.addLayer(layer);
+                postLayerTask.run();
                 layer.onPostLoadFromFile();
             }
@@ -69,3 +61,40 @@
         }
     }
+
+    /**
+     * Load osm data layer from InputStream.
+     * associatedFile can be null if the stream does not come from a file.
+     */
+    public void loadLayer(InputStream in, final File associatedFile, final String layerName, ProgressMonitor progressMonitor) throws IllegalDataException {
+        final DataSet dataSet = OsmReader.parseDataSet(in, progressMonitor);
+        String name = associatedFile == null ? OsmDataLayer.createNewName() : associatedFile.getName();
+        layer = new OsmDataLayer(dataSet, layerName, associatedFile);
+        postLayerTask = new Runnable() {
+            @Override
+            public void run() {
+                if (dataSet.allPrimitives().isEmpty()) {
+                    String msg;
+                    if (associatedFile == null) {
+                        msg = tr("No data found for layer ''{0}''.", layerName);
+                    } else {
+                        msg = tr("No data found in file ''{0}''.", associatedFile.getPath());
+                    }
+                    JOptionPane.showMessageDialog(
+                            Main.parent,
+                            msg,
+                            tr("Open OSM file"),
+                            JOptionPane.INFORMATION_MESSAGE);
+                }
+                layer.onPostLoadFromFile();
+            }
+        };
+    }
+
+    public OsmDataLayer getLayer() {
+        return layer;
+    }
+
+    public Runnable getPostLayerTask() {
+        return postLayerTask;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java	(revision 4668)
+++ trunk/src/org/openstreetmap/josm/io/session/OsmDataSessionImporter.java	(revision 4668)
@@ -0,0 +1,52 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Element;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.OsmImporter;
+import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
+
+public class OsmDataSessionImporter implements SessionLayerImporter {
+
+    @Override
+    public Layer load(Element elem, ImportSupport support, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
+        String version = elem.getAttribute("version");
+        if (!"0.1".equals(version)) {
+            throw new IllegalDataException(tr("Version ''{0}'' of meta data for osm data layer is not supported. Expected: 0.1", version));
+        }
+        try {
+            XPathFactory xPathFactory = XPathFactory.newInstance();
+            XPath xpath = xPathFactory.newXPath();
+            XPathExpression fileExp = xpath.compile("file/text()");
+            String fileStr = (String) fileExp.evaluate(elem, XPathConstants.STRING);
+            if (fileStr == null || fileStr.equals("")) {
+                throw new IllegalDataException(tr("File name expected for layer no. {0}", support.getLayerIndex()));
+            }
+
+            OsmImporter importer = new OsmImporter();
+            InputStream in = support.getInputStream(fileStr);
+            importer.loadLayer(in, support.getFile(fileStr), support.getLayerName(), progressMonitor);
+
+            support.addPostLayersTask(importer.getPostLayerTask());
+            return importer.getLayer();
+
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
+
Index: trunk/src/org/openstreetmap/josm/io/session/SessionLayerImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionLayerImporter.java	(revision 4668)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionLayerImporter.java	(revision 4668)
@@ -0,0 +1,19 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import java.io.IOException;
+
+import org.w3c.dom.Element;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.session.SessionReader.ImportSupport;
+
+public interface SessionLayerImporter {
+    /**
+     * Load the layer from xml meta-data.
+     */
+    Layer load(Element elem, ImportSupport support, ProgressMonitor progressMonitor) throws IOException, IllegalDataException;
+}
+
Index: trunk/src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 4668)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 4668)
@@ -0,0 +1,500 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io.session;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.Utils.equal;
+
+import java.awt.Component;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Reads a .jos session file and loads the layers in the process.
+ *
+ */
+public class SessionReader {
+
+    private static Map<String, Class<? extends SessionLayerImporter>> sessionLayerImporters = new HashMap<String, Class<? extends SessionLayerImporter>>();
+    static {
+        registerSessionLayerImporter("osm-data", OsmDataSessionImporter.class);
+    }
+
+    public static void registerSessionLayerImporter(String layerType, Class<? extends SessionLayerImporter> importer) {
+        sessionLayerImporters.put(layerType, importer);
+    }
+
+    public static SessionLayerImporter getSessionLayerImporter(String layerType) {
+        Class<? extends SessionLayerImporter> importerClass = sessionLayerImporters.get(layerType);
+        if (importerClass == null)
+            return null;
+        SessionLayerImporter importer = null;
+        try {
+            importer = importerClass.newInstance();
+        } catch (InstantiationException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+        return importer;
+    }
+
+    private File sessionFile;
+    private boolean zip; /* true, if session file is a .joz file; false if it is a .jos file */
+    private ZipFile zipFile;
+    private List<Layer> layers = new ArrayList<Layer>();
+    private List<Runnable> postLoadTasks = new ArrayList<Runnable>();
+
+    /**
+     * @return list of layers that are later added to the mapview
+     */
+    public List<Layer> getLayers() {
+        return layers;
+    }
+
+    /**
+     * @return actions executed in EDT after layers have been added (message dialog, etc.)
+     */
+    public List<Runnable> getPostLoadTasks() {
+        return postLoadTasks;
+    }
+
+    public class ImportSupport {
+
+        private String layerName;
+        private int layerIndex;
+        private LinkedHashMap<Integer,SessionLayerImporter> layerDependencies;
+
+        public ImportSupport(String layerName, int layerIndex, LinkedHashMap<Integer,SessionLayerImporter> layerDependencies) {
+            this.layerName = layerName;
+            this.layerIndex = layerIndex;
+            this.layerDependencies = layerDependencies;
+        }
+
+        /**
+         * Path of the file inside the zip archive.
+         * Used as alternative return value for getFile method.
+         */
+        private String inZipPath;
+
+        /**
+         * Add a task, e.g. a message dialog, that should
+         * be executed in EDT after all layers have been added.
+         */
+        public void addPostLayersTask(Runnable task) {
+            postLoadTasks.add(task);
+        }
+
+        /**
+         * Return an InputStream for a URI from a .jos/.joz file.
+         *
+         * The following forms are supported:
+         *
+         * - absolute file (both .jos and .joz):
+         *         "file:///home/user/data.osm"
+         *         "file:/home/user/data.osm"
+         *         "file:///C:/files/data.osm"
+         *         "file:/C:/file/data.osm"
+         *         "/home/user/data.osm"
+         *         "C:\files\data.osm"          (not a URI, but recognized by File constructor on Windows systems)
+         * - standalone .jos files:
+         *     - relative uri:
+         *         "save/data.osm"
+         *         "../project2/data.osm"
+         * - for .joz files:
+         *     - file inside zip archive:
+         *         "layers/01/data.osm"
+         *     - relativ to the .joz file:
+         *         "../save/data.osm"           ("../" steps out of the archive)
+         *
+         * @throws IOException Thrown when no Stream can be opened for the given URI, e.g. when the linked file has been deleted.
+         */
+        public InputStream getInputStream(String uriStr) throws IOException {
+            File file = getFile(uriStr);
+            try {
+                if (file != null) {
+                    return new BufferedInputStream(new FileInputStream(file));
+                } else if (inZipPath != null) {
+                    ZipEntry entry = zipFile.getEntry(inZipPath);
+                    if (entry != null) {
+                        InputStream is = zipFile.getInputStream(entry);
+                        return is;
+                    }
+                }
+            } catch (FileNotFoundException e) {
+                throw new IOException(tr("File ''{0}'' does not exist.", file.getPath()));
+            }
+            throw new IOException(tr("Unable to locate file  ''{0}''.", uriStr));
+        }
+
+        /**
+         * Return a File for a URI from a .jos file.
+         *
+         * Returns null if the URI points to a file inside the zip archive.
+         * In this case, inZipPath will be set to the corresponding path.
+         */
+        public File getFile(String uriStr) throws IOException {
+            inZipPath = null;
+            try {
+                URI uri = new URI(uriStr);
+                if ("file".equals(uri.getScheme())) {
+                    // absolute path
+                    return new File(uri);
+                } else if (uri.getScheme() == null) {
+                    // Check if this is an absolute path without 'file:' scheme part.
+                    // At this point, (as an exception) platform dependent path separator will be recognized.
+                    // (This form is discouraged, only for users that like to copy and paste a path manually.)
+                    File file = new File(uriStr);
+                    if (file.isAbsolute()) {
+                        return file;
+                    } else {
+                        // for relative paths, only forward slashes are permitted
+                        if (isZip()) {
+                            if (uri.getPath().startsWith("../")) {
+                                // relative to session file - "../" step out of the archive
+                                String relPath = uri.getPath().substring(3);
+                                return new File(sessionFile.toURI().resolve(relPath));
+                            } else {
+                                // file inside zip archive
+                                inZipPath = uriStr;
+                                return null;
+                            }
+                        } else {
+                            return new File(sessionFile.toURI().resolve(uri));
+                        }
+                    }
+                } else {
+                    throw new IOException(tr("Unsupported scheme ''{0}'' in URI ''{1}''.", uri.getScheme(), uriStr));
+                }
+            } catch (URISyntaxException e) {
+                throw new IOException(e);
+            }
+        }
+
+        /**
+         * Returns true if we are reading from a .joz file.
+         */
+        public boolean isZip() {
+            return zip;
+        }
+
+        /**
+         * Name of the layer that is currently imported.
+         */
+        public String getLayerName() {
+            return layerName;
+        }
+
+        /**
+         * Index of the layer that is currently imported.
+         */
+        public int getLayerIndex() {
+            return layerIndex;
+        }
+
+        /**
+         * Dependencies - maps the layer index to the importer of the given
+         * layer. All the dependent importers have loaded completely at this point.
+         */
+        public LinkedHashMap<Integer,SessionLayerImporter> getLayerDependencies() {
+            return layerDependencies;
+        }
+    }
+
+    private void error(String msg) throws IllegalDataException {
+        throw new IllegalDataException(msg);
+    }
+
+    private void parseJos(Document doc, ProgressMonitor progressMonitor) throws IllegalDataException {
+        Element root = doc.getDocumentElement();
+        if (!equal(root.getTagName(), "josm-session")) {
+            error(tr("Unexpected root element ''{0}'' in session file", root.getTagName()));
+        }
+        String version = root.getAttribute("version");
+        if (!"0.1".equals(version)) {
+            error(tr("Version ''{0}'' of session file is not supported. Expected: 0.1", version));
+        }
+
+        NodeList layersNL = root.getElementsByTagName("layers");
+        if (layersNL.getLength() == 0) return;
+
+        Element layersEl = (Element) layersNL.item(0);
+
+        MultiMap<Integer, Integer> deps = new MultiMap<Integer, Integer>();
+        Map<Integer, Element> elems = new HashMap<Integer, Element>();
+
+        NodeList nodes = layersEl.getChildNodes();
+
+        for (int i=0; i<nodes.getLength(); ++i) {
+            Node node = nodes.item(i);
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                Element e = (Element) node;
+                if (equal(e.getTagName(), "layer")) {
+
+                    if (!e.hasAttribute("index")) {
+                        error(tr("missing mandatory attribute ''index'' for element ''layer''"));
+                    }
+                    Integer idx = null;
+                    try {
+                        idx = Integer.parseInt(e.getAttribute("index"));
+                    } catch (NumberFormatException ex) {}
+                    if (idx == null) {
+                        error(tr("unexpected format of attribute ''index'' for element ''layer''"));
+                    }
+                    if (elems.containsKey(idx)) {
+                        error(tr("attribute ''index'' ({0}) for element ''layer'' must be unique", Integer.toString(idx)));
+                    }
+                    elems.put(idx, e);
+
+                    deps.putVoid(idx);
+                    String depStr = e.getAttribute("depends");
+                    if (depStr != null) {
+                        for (String sd : depStr.split(",")) {
+                            Integer d = null;
+                            try {
+                                d = Integer.parseInt(sd);
+                            } catch (NumberFormatException ex) {}
+                            if (d != null) {
+                                deps.put(idx, d);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        List<Integer> sorted = Utils.topologicalSort(deps);
+        final Map<Integer, Layer> layersMap = new TreeMap<Integer, Layer>(Collections.reverseOrder());
+        final Map<Integer, SessionLayerImporter> importers = new HashMap<Integer, SessionLayerImporter>();
+        final Map<Integer, String> names = new HashMap<Integer, String>();
+
+        progressMonitor.setTicksCount(sorted.size());
+        LAYER: for (int idx: sorted) {
+            Element e = elems.get(idx);
+            if (e == null) {
+                error(tr("missing layer with index {0}", idx));
+            }
+            if (!e.hasAttribute("name")) {
+                error(tr("missing mandatory attribute ''name'' for element ''layer''"));
+            }
+            String name = e.getAttribute("name");
+            names.put(idx, name);
+            if (!e.hasAttribute("type")) {
+                error(tr("missing mandatory attribute ''type'' for element ''layer''"));
+            }
+            String type = e.getAttribute("type");
+            SessionLayerImporter imp = getSessionLayerImporter(type);
+            if (imp == null) {
+                CancelOrContinueDialog dialog = new CancelOrContinueDialog();
+                dialog.show(
+                    tr("Unable to load layer"),
+                    tr("Cannot load layer of type ''{0}'' because no suitable importer was found.", type),
+                    JOptionPane.WARNING_MESSAGE,
+                    progressMonitor
+                );
+                if (dialog.isCancel()) {
+                    progressMonitor.cancel();
+                    return;
+                } else {
+                    continue;
+                }
+            } else {
+                importers.put(idx, imp);
+                LinkedHashMap<Integer,SessionLayerImporter> depsImp = new LinkedHashMap<Integer,SessionLayerImporter>();
+                for (int d : deps.get(idx)) {
+                    SessionLayerImporter dImp = importers.get(d);
+                    if (dImp == null) {
+                        CancelOrContinueDialog dialog = new CancelOrContinueDialog();
+                        dialog.show(
+                            tr("Unable to load layer"),
+                            tr("Cannot load layer {0} because it depends no layer {1} which has been skipped.", idx, d),
+                            JOptionPane.WARNING_MESSAGE,
+                            progressMonitor
+                        );
+                        if (dialog.isCancel()) {
+                            progressMonitor.cancel();
+                            return;
+                        } else {
+                            continue LAYER;
+                        }
+                    }
+                    depsImp.put(d, dImp);
+                }
+                ImportSupport support = new ImportSupport(name, idx, depsImp);
+                Layer layer = null;
+                Exception exception = null;
+                try {
+                    layer = imp.load(e, support, progressMonitor.createSubTaskMonitor(1, false));
+                } catch (IllegalDataException ex) {
+                    exception = ex;
+                } catch (IOException ex) {
+                    exception = ex;
+                }
+                if (exception != null) {
+                    exception.printStackTrace();
+                    CancelOrContinueDialog dialog = new CancelOrContinueDialog();
+                    dialog.show(
+                        tr("Error loading layer"),
+                        tr("<html>Could not load layer {0} ''{1}''.<br>Error is:<br>{2}</html>", idx, name, exception.getMessage()),
+                        JOptionPane.ERROR_MESSAGE,
+                        progressMonitor
+                    );
+                    if (dialog.isCancel()) {
+                        progressMonitor.cancel();
+                        return;
+                    } else {
+                        continue;
+                    }
+                }
+
+                if (layer == null) throw new RuntimeException();
+                layersMap.put(idx, layer);
+            }
+            progressMonitor.worked(1);
+        }
+
+        layers = new ArrayList<Layer>();
+        for (Entry<Integer, Layer> e : layersMap.entrySet()) {
+            Layer l = e.getValue();
+            if (l == null) continue;
+            l.setName(names.get(e.getKey()));
+            layers.add(l);
+        }
+    }
+
+    /**
+     * Show Dialog when there is an error for one layer.
+     * Ask the user whether to cancel the complete session loading or just to skip this layer.
+     *
+     * This is expected to run in a worker thread (PleaseWaitRunnable), so invokeAndWait is
+     * needed to block the current thread and wait for the result of the modal dialog from EDT.
+     */
+    private class CancelOrContinueDialog {
+
+        private boolean cancel;
+
+        public void show(final String title, final String message, final int icon, final ProgressMonitor progressMonitor) {
+            try {
+                SwingUtilities.invokeAndWait(new Runnable() {
+                    @Override public void run() {
+                        Component parent;
+                        if (progressMonitor instanceof PleaseWaitProgressMonitor) {
+                            parent = ((PleaseWaitProgressMonitor) progressMonitor).getDialog();
+                        } else {
+                            parent = Main.parent;
+                        }
+                        ExtendedDialog dlg = new ExtendedDialog(
+                                parent,
+                                title,
+                                new String[] { tr("Cancel"), tr("Skip layer and continue") }
+                        );
+                        dlg.setButtonIcons(new String[] {"cancel", "dialogs/next"});
+                        dlg.setIcon(icon);
+                        dlg.setContent(message);
+                        dlg.showDialog();
+                        cancel = dlg.getValue() != 2;
+                    }
+                });
+            } catch (InvocationTargetException ex) {
+                throw new RuntimeException(ex);
+            } catch (InterruptedException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        public boolean isCancel() {
+            return cancel;
+        }
+    }
+
+    public void loadSession(File sessionFile, boolean zip, ProgressMonitor progressMonitor) throws IllegalDataException, IOException {
+        if (progressMonitor == null) {
+            progressMonitor = NullProgressMonitor.INSTANCE;
+        }
+        this.sessionFile = sessionFile;
+        this.zip = zip;
+
+        InputStream josIS = null;
+
+        if (zip) {
+            try {
+                zipFile = new ZipFile(sessionFile);
+                ZipEntry josEntry = null;
+                Enumeration<? extends ZipEntry> entries = zipFile.entries();
+                while (entries.hasMoreElements()) {
+                    ZipEntry entry = entries.nextElement();
+                    if (entry.getName().toLowerCase().endsWith(".jos")) {
+                        josEntry = entry;
+                        break;
+                    }
+                }
+                if (josEntry == null) {
+                    error(tr("expected .jos file inside .joz archive"));
+                }
+                josIS = zipFile.getInputStream(josEntry);
+            } catch (ZipException ze) {
+                throw new IOException(ze);
+            }
+        } else {
+            try {
+                josIS = new FileInputStream(sessionFile);
+            } catch (FileNotFoundException ex) {
+                throw new IOException(ex);
+            }
+        }
+
+        try {
+            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+            builderFactory.setValidating(false);
+            builderFactory.setNamespaceAware(true);
+            DocumentBuilder builder = builderFactory.newDocumentBuilder();
+            Document document = builder.parse(josIS);
+            parseJos(document, progressMonitor);
+        } catch (SAXException e) {
+            throw new IllegalDataException(e);
+        } catch (ParserConfigurationException e) {
+            throw new IOException(e);
+        }
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/tools/MultiMap.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/MultiMap.java	(revision 4667)
+++ trunk/src/org/openstreetmap/josm/tools/MultiMap.java	(revision 4668)
@@ -2,7 +2,9 @@
 package org.openstreetmap.josm.tools;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -13,5 +15,5 @@
  *
  * Corresponds to Google guava LinkedHashMultimap and Apache Collections MultiValueMap
- * but it is an independent (simplistic) implementation.
+ * but it is an independent (simple) implementation.
  *
  */
@@ -116,3 +118,31 @@
         return map.values();
     }
+
+    /**
+     * Removes a cerain key=value mapping
+     *
+     * @return true, if something was removed
+     */
+    public boolean remove(A key, B value) {
+        Set<B> values = get(key);
+        if (values != null) {
+            return values.remove(value);
+        }
+        return false;
+    }
+
+    /**
+     * Removes all mappings for a certain key
+     */
+    public LinkedHashSet<B> remove(A key) {
+        return map.remove(key);
+    }
+
+    public String toString() {
+        List<String> entries = new ArrayList<String>(map.size());
+        for (A key : map.keySet()) {
+            entries.add(key + "->{" + Utils.join(",", map.get(key)) + "}");
+        }
+        return "(" + Utils.join(",", entries) + ")";
+    }
 }
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4667)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 4668)
@@ -19,5 +19,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 /**
@@ -62,5 +64,5 @@
 		return new FilteredCollection<T>(collection, predicate);
 	}
-    
+
     /**
      * Filter a collection by (sub)class.
@@ -233,5 +235,5 @@
     /**
      * <p>Utility method for closing an input stream.</p>
-     * 
+     *
      * @param is the input stream. May be null.
      */
@@ -247,5 +249,5 @@
     /**
      * <p>Utility method for closing an output stream.</p>
-     * 
+     *
      * @param os the output stream. May be null.
      */
@@ -261,5 +263,5 @@
     /**
      * <p>Utility method for closing a reader.</p>
-     * 
+     *
      * @param reader the reader. May be null.
      */
@@ -355,3 +357,42 @@
         return new String(hexChars);
     }
+
+    /**
+     * Topological sort.
+     *
+     * @param dependencies contains mappings (key -> value). In the final list of sorted objects, the key will come
+     * after the value. (In other words, the key depends on the value(s).)
+     * There must not be cyclic dependencies.
+     * @return the list of sorted objects
+     */
+    public static <T> List<T> topologicalSort(final MultiMap<T,T> dependencies) {
+        MultiMap<T,T> deps = new MultiMap<T,T>();
+        for (T key : dependencies.keySet()) {
+            deps.putVoid(key);
+            for (T val : dependencies.get(key)) {
+                deps.putVoid(val);
+                deps.put(key, val);
+            }
+        }
+
+        int size = deps.size();
+        List<T> sorted = new ArrayList<T>();
+        for (int i=0; i<size; ++i) {
+            T parentless = null;
+            for (T key : deps.keySet()) {
+                if (deps.get(key).size() == 0) {
+                    parentless = key;
+                    break;
+                }
+            }
+            if (parentless == null) throw new RuntimeException();
+            sorted.add(parentless);
+            deps.remove(parentless);
+            for (T key : deps.keySet()) {
+                deps.remove(key, parentless);
+            }
+        }
+        if (sorted.size() != size) throw new RuntimeException();
+        return sorted;
+    }
 }
