diff --git a/ffmap/db/routers.py b/ffmap/db/routers.py index 268c8ca..a578dbb 100755 --- a/ffmap/db/routers.py +++ b/ffmap/db/routers.py @@ -94,6 +94,7 @@ mysql.execute(""" `community` varchar(200) COLLATE utf8_unicode_ci NOT NULL, `hood` varchar(30) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `v2` tinyint(1) NOT NULL, + `local` tinyint(1) NOT NULL, `gateway` tinyint(1) NOT NULL, `status_text` varchar(200) COLLATE utf8_unicode_ci NOT NULL, `contact` varchar(200) COLLATE utf8_unicode_ci NOT NULL, diff --git a/ffmap/mapnik/routers_local.xml b/ffmap/mapnik/routers_local.xml new file mode 100644 index 0000000..e4da0c4 --- /dev/null +++ b/ffmap/mapnik/routers_local.xml @@ -0,0 +1,109 @@ + + + + + + + + + + shadow1 + color + + csv + csv/links_local.csv + + + + shadow1 + l3_color + + csv + csv/l3_links_local.csv + + + + routerpoint + + csv + csv/routers_local.csv + + + diff --git a/ffmap/mapnik/run.sh b/ffmap/mapnik/run.sh index 2a098d6..077014d 100755 --- a/ffmap/mapnik/run.sh +++ b/ffmap/mapnik/run.sh @@ -2,6 +2,7 @@ liteserv.py routers.xml --processes=5 & liteserv.py routers_v2.xml -p 8003 --processes=5 & +liteserv.py routers_local.xml -p 8004 --processes=5 & liteserv.py hoods.xml -p 8001 --processes=5 & liteserv.py hoods_v2.xml -p 8002 --processes=5 diff --git a/ffmap/mapnik/tilestache.cfg b/ffmap/mapnik/tilestache.cfg index 9566ede..99e9981 100644 --- a/ffmap/mapnik/tilestache.cfg +++ b/ffmap/mapnik/tilestache.cfg @@ -24,6 +24,16 @@ "metatile": {"buffer": 128}, "cache lifespan": 300 }, + "tiles/routers_local": { + "provider": { + "class": "dynmapnik:DynMapnik", + "kwargs": { + "mapfile": "/usr/share/ffmap/routers_local.xml" + } + }, + "metatile": {"buffer": 128}, + "cache lifespan": 300 + }, "tiles/hoods": { "provider": { "class": "dynmapnik:DynMapnik", diff --git a/ffmap/maptools.py b/ffmap/maptools.py index 2d04da3..2df00fd 100644 --- a/ffmap/maptools.py +++ b/ffmap/maptools.py @@ -11,8 +11,6 @@ import math import numpy as np from scipy.spatial import Voronoi -import urllib.request, json - EARTH_RADIUS = 6378137.0 def touch(fname, times=None): @@ -70,13 +68,13 @@ def draw_voronoi_lines(csv, hoods): def update_mapnik_csv(mysql): routers = mysql.fetchall(""" - SELECT router.status, router.lat, router.lng, hoods.name AS hood, router.wan_uplink FROM router - LEFT JOIN hoods ON router.hood = hoods.name + SELECT router.status, router.lat, router.lng, router.wan_uplink, v2, local FROM router WHERE router.lat IS NOT NULL AND router.lng IS NOT NULL """) rv1 = "lng,lat,status\n" rv2 = "lng,lat,status\n" + rvlocal = "lng,lat,status\n" for router in routers: tmpstatus = router["status"] @@ -87,20 +85,23 @@ def update_mapnik_csv(mysql): router["lat"], tmpstatus ) - if router["hood"]: - rv1 += tmp - else: + if router["local"]: + rvlocal += tmp + elif router["v2"]: rv2 += tmp + else: + rv1 += tmp with open(os.path.join(CONFIG["csv_dir"], "routers.csv"), "w") as csv: csv.write(rv1) with open(os.path.join(CONFIG["csv_dir"], "routers_v2.csv"), "w") as csv: csv.write(rv2) + with open(os.path.join(CONFIG["csv_dir"], "routers_local.csv"), "w") as csv: + csv.write(rvlocal) dblinks = mysql.fetchall(""" - SELECT r1.id AS rid, r2.id AS nid, r1.lat AS rlat, r1.lng AS rlng, r2.lat AS nlat, r2.lng AS nlng, n.netif AS netif, n.type AS type, MAX(quality) AS quality, hoods.name AS hood + SELECT r1.id AS rid, r2.id AS nid, r1.lat AS rlat, r1.lng AS rlng, r2.lat AS nlat, r2.lng AS nlng, n.netif AS netif, n.type AS type, MAX(quality) AS quality, r1.v2, r1.local FROM router AS r1 - LEFT JOIN hoods ON r1.hood = hoods.name INNER JOIN router_neighbor AS n ON r1.id = n.router INNER JOIN ( SELECT router, mac FROM router_netif GROUP BY mac, router @@ -108,12 +109,14 @@ def update_mapnik_csv(mysql): INNER JOIN router AS r2 ON net.router = r2.id WHERE r1.lat IS NOT NULL AND r1.lng IS NOT NULL AND r2.lat IS NOT NULL AND r2.lng IS NOT NULL AND r1.status = 'online' - GROUP BY r1.id, r1.lat, r1.lng, r2.id, r2.lat, r2.lng, n.netif, n.type, hoods.name + GROUP BY r1.id, r1.lat, r1.lng, r2.id, r2.lat, r2.lng, n.netif, n.type, r1.v2, r1.local """) links = [] linksl3 = [] linksv2 = [] linksl3v2 = [] + linkslocal = [] + linksl3local = [] dictl3 = {} dictl2 = {} # The following code is very ugly, but works and is not too slow. Maybe make it nicer at some point ... @@ -133,10 +136,12 @@ def update_mapnik_csv(mysql): row["nlng"], row["nlat"], ) - if row["hood"]: - linksl3.append(tmp) - else: + if row["local"]: + linksl3local.append(tmp) + elif row["v2"]: linksl3v2.append(tmp) + else: + linksl3.append(tmp) else: # Check for duplicate if row["nid"] in dictl2.keys() and row["rid"] in dictl2[row["nid"]].keys(): @@ -168,14 +173,16 @@ def update_mapnik_csv(mysql): row["nlat"], row["quality"], ) - dictl2[row["rid"]][row["nid"]] = {'hood':row["hood"],'data':tmp} + dictl2[row["rid"]][row["nid"]] = {'v2':row["v2"],'local':row["local"],'data':tmp} for d1 in dictl2.values(): for d2 in d1.values(): - if d2["hood"]: - links.append(d2["data"]) - else: + if d2["local"]: + linkslocal.append(d2["data"]) + elif d2["v2"]: linksv2.append(d2["data"]) + else: + links.append(d2["data"]) with open(os.path.join(CONFIG["csv_dir"], "links.csv"), "w") as csv: csv.write("WKT,quality\n") @@ -187,6 +194,11 @@ def update_mapnik_csv(mysql): for link in sorted(linksv2, key=lambda l: l[4]): csv.write("\"LINESTRING (%f %f,%f %f)\",%i\n" % link) + with open(os.path.join(CONFIG["csv_dir"], "links_local.csv"), "w") as csv: + csv.write("WKT,quality\n") + for link in sorted(linkslocal, key=lambda l: l[4]): + csv.write("\"LINESTRING (%f %f,%f %f)\",%i\n" % link) + with open(os.path.join(CONFIG["csv_dir"], "l3_links.csv"), "w") as csv: csv.write("WKT\n") for link in linksl3: @@ -197,6 +209,11 @@ def update_mapnik_csv(mysql): for link in linksl3v2: csv.write("\"LINESTRING (%f %f,%f %f)\"\n" % link) + with open(os.path.join(CONFIG["csv_dir"], "l3_links_local.csv"), "w") as csv: + csv.write("WKT\n") + for link in linksl3local: + csv.write("\"LINESTRING (%f %f,%f %f)\"\n" % link) + dbhoods = mysql.fetchall(""" SELECT name, lat, lng FROM hoods WHERE lat IS NOT NULL AND lng IS NOT NULL @@ -247,6 +264,7 @@ def update_mapnik_csv(mysql): touch("/usr/share/ffmap/hoods_v2.xml") touch("/usr/share/ffmap/routers.xml") touch("/usr/share/ffmap/routers_v2.xml") + touch("/usr/share/ffmap/routers_local.xml") if __name__ == '__main__': update_mapnik_csv() diff --git a/ffmap/routertools.py b/ffmap/routertools.py index 23d4161..3e3c983 100644 --- a/ffmap/routertools.py +++ b/ffmap/routertools.py @@ -43,7 +43,7 @@ def ban_router(mysql,dbid): mysql.execute("INSERT INTO banned (mac, added) VALUES (%s, %s)",(mac,added,)) mysql.commit() -def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime): +def import_nodewatcher_xml(mysql, mac, xml, banned, hoodsv2, netifdict, statstime): #global router_rate_limit_list #if mac in router_rate_limit_list: @@ -64,6 +64,7 @@ def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime): try: findrouter = mysql.findone("SELECT router FROM router_netif WHERE mac = %s LIMIT 1",(mac2int(mac),)) router_update = parse_nodewatcher_xml(xml,statstime) + router_update["local"] = bool(router_update["hood"] and not router_update["hood"] in hoodsv2) # cancel if banned mac found for n in router_update["netifs"]: @@ -164,7 +165,7 @@ def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime): sys_loadavg = %s, sys_procrun = %s, sys_proctot = %s, clients = %s, clients_eth = %s, clients_w2 = %s, clients_w5 = %s, w2_active = %s, w2_busy = %s, w5_active = %s, w5_busy = %s, w2_airtime = %s, w5_airtime = %s, wan_uplink = %s, tc_enabled = %s, tc_in = %s, tc_out = %s, cpu = %s, chipset = %s, hardware = %s, os = %s, - batman = %s, routing_protocol = %s, kernel = %s, nodewatcher = %s, firmware = %s, firmware_rev = %s, description = %s, position_comment = %s, community = %s, hood = %s, v2 = %s, gateway = %s, + batman = %s, routing_protocol = %s, kernel = %s, nodewatcher = %s, firmware = %s, firmware_rev = %s, description = %s, position_comment = %s, community = %s, hood = %s, v2 = %s, local = %s, gateway = %s, status_text = %s, contact = %s, lng = %s, lat = %s, neighbors = %s, reset = %s WHERE id = %s """,( @@ -172,7 +173,7 @@ def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime): ru["sys_loadavg"],ru["processes"]["runnable"],ru["processes"]["total"],ru["clients"],ru["clients_eth"],ru["clients_w2"],ru["clients_w5"], ru["w2_active"],ru["w2_busy"],ru["w5_active"],ru["w5_busy"],ru["w2_airtime"],ru["w5_airtime"],ru["has_wan_uplink"],ru["tc_enabled"],ru["tc_in"],ru["tc_out"], ru["cpu"],ru["chipset"],ru["hardware"],ru["os"], - ru["batman_adv"],ru["rt_protocol"],ru["kernel"],ru["nodewatcher"],ru["firmware"],ru["firmware_rev"],ru["description"],ru["position_comment"],ru["community"],ru["hood"],ru["v2"],ru["gateway"], + ru["batman_adv"],ru["rt_protocol"],ru["kernel"],ru["nodewatcher"],ru["firmware"],ru["firmware_rev"],ru["description"],ru["position_comment"],ru["community"],ru["hood"],ru["v2"],ru["local"],ru["gateway"], ru["status_text"],ru["contact"],ru["lng"],ru["lat"],ru["visible_neighbours"],reset,router_id,)) # Previously, I just deleted all entries and recreated them again with INSERT. @@ -237,15 +238,15 @@ def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime): sys_loadavg, sys_procrun, sys_proctot, clients, clients_eth, clients_w2, clients_w5, w2_active, w2_busy, w5_active, w5_busy, w2_airtime, w5_airtime, wan_uplink, tc_enabled, tc_in, tc_out, cpu, chipset, hardware, os, - batman, routing_protocol, kernel, nodewatcher, firmware, firmware_rev, description, position_comment, community, hood, v2, gateway, + batman, routing_protocol, kernel, nodewatcher, firmware, firmware_rev, description, position_comment, community, hood, v2, local, gateway, status_text, contact, lng, lat, neighbors) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """,( ru["status"],ru["hostname"],created,ru["last_contact"],ru["sys_time"].strftime('%Y-%m-%d %H:%M:%S'),ru["sys_uptime"],ru["memory"]["free"],ru["memory"]["buffering"],ru["memory"]["caching"], ru["sys_loadavg"],ru["processes"]["runnable"],ru["processes"]["total"],ru["clients"],ru["clients_eth"],ru["clients_w2"],ru["clients_w5"], None,None,None,None,None,None,ru["has_wan_uplink"],ru["tc_enabled"],ru["tc_in"],ru["tc_out"], ru["cpu"],ru["chipset"],ru["hardware"],ru["os"], - ru["batman_adv"],ru["rt_protocol"],ru["kernel"],ru["nodewatcher"],ru["firmware"],ru["firmware_rev"],ru["description"],ru["position_comment"],ru["community"],ru["hood"],ru["v2"],ru["gateway"], + ru["batman_adv"],ru["rt_protocol"],ru["kernel"],ru["nodewatcher"],ru["firmware"],ru["firmware_rev"],ru["description"],ru["position_comment"],ru["community"],ru["hood"],ru["v2"],ru["local"],ru["gateway"], ru["status_text"],ru["contact"],ru["lng"],ru["lat"],ru["visible_neighbours"],)) router_id = mysql.cursor().lastrowid diff --git a/ffmap/stattools.py b/ffmap/stattools.py index 6a6f415..9cabc94 100644 --- a/ffmap/stattools.py +++ b/ffmap/stattools.py @@ -214,7 +214,7 @@ def hoods(mysql,selectgw=None): def hoods_sum(mysql,selectgw=None): data = mysql.fetchall(""" - SELECT hood, COUNT(id) AS count, SUM(clients) AS clients, MAX(v2) AS v2 + SELECT hood, COUNT(id) AS count, SUM(clients) AS clients, MAX(v2) AS v2, MAX(local) AS local FROM router GROUP BY hood """) @@ -222,7 +222,7 @@ def hoods_sum(mysql,selectgw=None): for rs in data: if not rs["hood"]: rs["hood"] = "Default" - result[rs["hood"]] = {"routers": rs["count"], "clients": rs["clients"], "v2": rs["v2"]} + result[rs["hood"]] = {"routers": rs["count"], "clients": rs["clients"], "v2": rs["v2"], "local": rs["local"]} return result def hoods_gws(mysql): diff --git a/ffmap/web/api.py b/ffmap/web/api.py index 6d44b2f..a9d8d36 100755 --- a/ffmap/web/api.py +++ b/ffmap/web/api.py @@ -64,19 +64,22 @@ def load_neighbor_stats(dbid): # map ajax @api.route('/get_nearest_router') def get_nearest_router(): - if request.args.get("layer") == "none": - r = make_response(bson2json(None)) - r.mimetype = 'application/json' - return r - lng = float(request.args.get("lng")) lat = float(request.args.get("lat")) - where = "" - if request.args.get("layer") == "v1": - where = " AND h.id IS NOT NULL " - elif request.args.get("layer") == "v2": - where = " AND h.id IS NULL " + wherelist = [] + if request.args.get("v1") == "on": + wherelist.append("(v2 = FALSE AND local = FALSE)") + if request.args.get("v2") == "on": + wherelist.append("(v2 = TRUE AND local = FALSE)") + if request.args.get("local") == "on": + wherelist.append("local = TRUE") + if wherelist: + where = " AND ( " + ' OR '.join(wherelist) + " ) " + else: + r = make_response(bson2json(None)) + r.mimetype = 'application/json' + return r mysql = FreifunkMySQL() router = mysql.findone(""" @@ -95,6 +98,10 @@ def get_nearest_router(): distance ASC LIMIT 1 """,(lat,lng,lat,)) + if not router: + r = make_response(bson2json(None)) + r.mimetype = 'application/json' + return r router["neighbours"] = mysql.fetchall(""" SELECT nb.mac, nb.netif, nb.quality, r.hostname, r.id @@ -143,6 +150,9 @@ def alfred(): banned = mysql.fetchall(""" SELECT mac FROM banned """,(),"mac") + hoodsv2 = mysql.fetchall(""" + SELECT name FROM hoodsv2 + """,(),"name") statstime = utcnow() netifdict = mysql.fetchdict("SELECT id, name FROM netifs",(),"name","id") if request.method == 'POST': @@ -157,7 +167,7 @@ def alfred(): # load router status xml data i = 1 for mac, xml in alfred_data.get("64", {}).items(): - import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime) + import_nodewatcher_xml(mysql, mac, xml, banned, hoodsv2, netifdict, statstime) if (i%500 == 0): mysql.commit() i += 1 diff --git a/ffmap/web/application.py b/ffmap/web/application.py index 28d9d12..b1dbcfb 100755 --- a/ffmap/web/application.py +++ b/ffmap/web/application.py @@ -29,6 +29,7 @@ app.register_blueprint(filters) tileurls = { "routers": "/tiles/routers", "routers_v2": "/tiles/routers_v2", + "routers_local": "/tiles/routers_local", "hoods": "/tiles/hoods", "hoods_v2": "/tiles/hoods_v2", } @@ -51,7 +52,7 @@ def router_list(): mysql = FreifunkMySQL() routers = mysql.fetchall(""" - SELECT router.id, hostname, status, hood, contact, nickname, hardware, router.created, sys_uptime, last_contact, clients, reset, blocked, v2 + SELECT router.id, hostname, status, hood, contact, nickname, hardware, router.created, sys_uptime, last_contact, clients, reset, blocked, v2, local FROM router LEFT JOIN users ON router.contact = users.email LEFT JOIN ( @@ -450,7 +451,7 @@ def user_info(nickname): else: flash("You are not authorized to perform this action!", "danger") routers = mysql.fetchall(""" - SELECT id, hostname, status, hood, firmware, hardware, created, sys_uptime, clients, reset, blocked, v2 + SELECT id, hostname, status, hood, firmware, hardware, created, sys_uptime, clients, reset, blocked, v2, local FROM router LEFT JOIN ( SELECT router, blocked.mac AS blocked FROM router_netif diff --git a/ffmap/web/static/css/style.css b/ffmap/web/static/css/style.css index 8f080b8..d9b762b 100644 --- a/ffmap/web/static/css/style.css +++ b/ffmap/web/static/css/style.css @@ -45,3 +45,18 @@ table.neighbours { padding-left: 5px; padding-right: 7px; } + +.hoodv2 { + color: #2db200; +} +.hoodlocal { + color: #ffbf00; +} + +.hoodv2 a { + color: #2db200; +} +.hoodlocal a { + color: #ffbf00; +} + diff --git a/ffmap/web/static/js/map.js b/ffmap/web/static/js/map.js index 285b633..97886ee 100644 --- a/ffmap/web/static/js/map.js +++ b/ffmap/web/static/js/map.js @@ -28,6 +28,7 @@ var overlay_config = { var routers = new L.TileLayer(tileurls.routers + '/{z}/{x}/{y}.png', overlay_config).addTo(map); var routers_v2 = new L.TileLayer(tileurls.routers_v2 + '/{z}/{x}/{y}.png', overlay_config).addTo(map); +var routers_local = new L.TileLayer(tileurls.routers_local + '/{z}/{x}/{y}.png', overlay_config).addTo(map); var hoods = new L.TileLayer(tileurls.hoods + '/{z}/{x}/{y}.png', overlay_config); var hoods_v2 = new L.TileLayer(tileurls.hoods_v2 + '/{z}/{x}/{y}.png', overlay_config); var popuplayer = new L.TileLayer(''); @@ -36,10 +37,11 @@ layersControl = new L.Control.Layers({ "openstreetmap.de": tilesosmde, "Thunderforest Outdoors": tilestfod }, { - "Routers": routers, - "Routers v2 und dezentral": routers_v2, - "Hoods": hoods, - "Hoods v2": hoods_v2, + "Routers V1": routers, + "Routers V2": routers_v2, + "Local Routers": routers_local, + "Hoods V1": hoods, + "Hoods V2": hoods_v2, "Position-Popup": popuplayer }); map.addControl(layersControl); @@ -71,15 +73,17 @@ map.on('click', function(pos) { var size_of_world_in_px = map.options.crs.scale(map.getZoom()); layeropt = "" - if (map.hasLayer(routers) && !map.hasLayer(routers_v2)) { + if (map.hasLayer(routers)) { console.debug("Looking for router in V1 ..."); - layeropt = "&layer=v1" - } else if (!map.hasLayer(routers) && map.hasLayer(routers_v2)) { + layeropt += "&v1=on" + } + if (map.hasLayer(routers_v2)) { console.debug("Looking for router in V2 ..."); - layeropt = "&layer=v2" - } else if (!map.hasLayer(routers) && !map.hasLayer(routers_v2)) { - console.debug("No layer specified to look in."); - layeropt = "&layer=none" + layeropt += "&v2=on" + } + if (map.hasLayer(routers_local)) { + console.debug("Looking for router in local hoods ..."); + layeropt += "&local=on" } var px_per_deg_lng = size_of_world_in_px / 360; diff --git a/ffmap/web/templates/router.html b/ffmap/web/templates/router.html index c73b0b3..db64506 100644 --- a/ffmap/web/templates/router.html +++ b/ffmap/web/templates/router.html @@ -140,7 +140,7 @@ Position{{ router.position_comment }} {%- endif %} {%- if router.hood %} - Hood{{ router.hood }} + Hood{{ router.hood }} {%- if router.community %} ({{ router.community }}) {%- endif -%} diff --git a/ffmap/web/templates/router_list.html b/ffmap/web/templates/router_list.html index 489ccfb..cf385da 100644 --- a/ffmap/web/templates/router_list.html +++ b/ffmap/web/templates/router_list.html @@ -47,7 +47,7 @@ {%- if router.reset %} - Reset!{%- endif %}{%- if router.blocked and not router.v2 %} - Blocked!{%- endif %} {{ router.status }} - {{ router.hood }} + {{ router.hood }} {{ router.nickname if router.nickname else "" }} {{ router.hardware }} {{ router.created|utc2local|format_dt_date }} diff --git a/ffmap/web/templates/statistics.html b/ffmap/web/templates/statistics.html index bc883bc..ffb2c47 100644 --- a/ffmap/web/templates/statistics.html +++ b/ffmap/web/templates/statistics.html @@ -45,9 +45,6 @@ .table-hoods .firstrow { text-align: left; } - .hoodv2 a { - color: #2db200; - } {% endblock %} @@ -73,7 +70,7 @@ {%- for hood, value in hoods|dictsort %} - {{ hood }} + {{ hood }} {{ hoods_gws[hood] or "-" }} {{ value["online"] or 0 }} {{ value["offline"] or 0 }}{%- if value["orphaned"] %} ({{ value["orphaned"] or 0 }}){%- endif %} diff --git a/ffmap/web/templates/user.html b/ffmap/web/templates/user.html index e3d4389..52fa551 100644 --- a/ffmap/web/templates/user.html +++ b/ffmap/web/templates/user.html @@ -107,7 +107,7 @@ {%- if router.reset %} - Reset!{%- endif %}{%- if router.blocked and not router.v2 %} - Blocked!{%- endif %} {{ router.status }} - {{ router.hood }} + {{ router.hood }} {{ router.firmware }} {{ router.get("hardware", "") }} {{ router.created|utc2local|format_dt_date }} diff --git a/install.sh b/install.sh index e298528..0bd5ad1 100755 --- a/install.sh +++ b/install.sh @@ -5,9 +5,9 @@ mkdir -vp /var/lib/ffmap/csv chown -R www-data:www-data /var/lib/ffmap mkdir -vp /usr/share/ffmap -cp -v ffmap/mapnik/{hoods,hoods_v2,routers,routers_v2}.xml /usr/share/ffmap -sed -i -e 's#>csv/#>/var/lib/ffmap/csv/#' /usr/share/ffmap/{hoods,hoods_v2,routers,routers_v2}.xml -chown www-data:www-data /usr/share/ffmap/{hoods,hoods_v2,routers,routers_v2}.xml +cp -v ffmap/mapnik/{hoods,hoods_v2,routers,routers_v2,routers_local}.xml /usr/share/ffmap +sed -i -e 's#>csv/#>/var/lib/ffmap/csv/#' /usr/share/ffmap/{hoods,hoods_v2,routers,routers_v2,routers_local}.xml +chown www-data:www-data /usr/share/ffmap/{hoods,hoods_v2,routers,routers_v2,routers_local}.xml cp -v ffmap/mapnik/tilestache.cfg /usr/share/ffmap cp -rv ffmap/web/static /usr/share/ffmap