(function($){
  
  var img = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFAAAAAAAApWe5zwAAAAF0Uk5TAEDm2GYAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=";
  
 /********
  F'n - A few utilities
  ****/
  var shape_to_str = function(arr, scale){
    var str = "", a = arr.slice(), s = scale || 1;
    
    for(i=0; i<a.length; i++)
      for(j=0; j<a[i].length; j++){
        str+= Math.round(a[i][j] * scale) + ', ';
      }
    return str.replace(/,\s*$/g,'');
  };
  
  var sort_points = function(arr){
    if (typeof arr == 'undefined') return new Array();
    var left = 5000, top = 5000,
        leftmost = [], topmost = [],
        nu = [];
    for(i=0; i<arr.length; i++){
      var p = arr[i][0];
      if(p < left){
        left = p;
        leftmost = [i];
      }
      else if(p == left) leftmost.push(i);
    }
    for(i=0; i<leftmost.length; i++){
      var p = arr[leftmost[i]][1];
      if(p < top){
        topmost = [i];
        top = p;
      }
      else if(p == top) topmost.push(i);
    }
    var n = leftmost[topmost[0]];
    if(n==0) nu = arr.slice();
    else nu = nu.concat(arr.slice(n)).concat(arr.slice(0,n));
    return nu;
  };
  
 /********
  Map Object - Serious Business, &c.
  ****/
  var Mappu = function(){
    return new mp.init(Array.prototype.slice.call(arguments));
  },
  mp = Mappu.prototype = function() {
    /*********** Private **************/
    // Build <map> and associated <img> and <area>s for each level and zoom
    var build_maps = function() {
      var _ = this;
      
      var chunk_count = 4,
          chunk_done = 0;
      
      for(l in _.levels)
        // Build a set of stuff for each zoom level
        for(z = 0; z < _.zoom_levels; z++) {
          if(!_.maps['level-'+l]) _.maps['level-'+l] = {};
          var off = { x: ((z==0) ? -267 : -883),
                      y: ((z==0) ? -187 : -487) };
          var wrap = $('<div class="level-zoom-wrap"></div>')
            .css({'position':'absolute', 'top':0, 'left':0})
            .appendTo(_.con).hide();
          
          var map = {
            wrap: wrap,
            mnts: $('<div id="amenities-f'+l+'-z'+z+'" class="amenity-overlay"></div>')
              .appendTo(wrap).css({position:'absolute', top:0, left:0}),
            hov: $('<div id="map-hover-f'+l+'-z'+z+'"></div>')
              .appendTo(wrap).css({'position':'absolute', top:0, left:0}),
            img: $('<img class="clear-map" src="' + _.clear_img + '" usemap="#map-f'+l+'-z'+z+'" />')
              .appendTo(wrap).css({'position':'absolute', 'top':'0px', 'left':'0px', 'z-index':750}),
              // .appendTo(wrap),
            areas: [],
            hovers: [],
            offset: {x:off.x, y:off.y}
          };
          
          var amenities = "information-center, taxi, mailbox, security-station, wifi, atm, restroom, public-telephone, elevator, escalator, stairs".split(', ');
          // Build amenities layers
          for (n=0; n<amenities.length; n++) {
            var mnt = amenities[n];
            $('<img />').hide()
              .addClass('amenity amenity-'+mnt)
              .attr('src', image_root+'amenities-f'+l+'-z'+z+'-'+mnt+'.png')
              .appendTo(map.mnts);
          }
          
          map.map = $('<map id="map-f'+l+'-z'+z+'" name="map-f'+l+'-z'+z+'"></map>')
            .appendTo(map.wrap);
          
          // Go through stores and build <area>s
          for(n in _.levels[l]) {
            (function(){
              var lev = l, zoom = z,
                  scale = (1 / Math.pow(2,(_.zoom_levels-1-z))),
                  store = _.levels[l][n],
                  num = store.n,
                  // num_all = _.ice_all[l] - store.n_all,
                  // num_all = store.n_all - 4,
                  // Build <area>, and attach event handlers to it
                  num_nuts = store.n_all,
                  area = $("<area />").attr({shape:'poly', coords:shape_to_str(store.shape, scale), href:'#'})
                    .appendTo(map.map)
                    .click(function(){ alert('hay'); });
                  
                  var hov_left = Math.round((store.shape[0][0] - store.ref[0]) * scale)-1,
                      hov_top = Math.round((store.shape[0][1] - store.ref[1]) * scale),
                      bg_left = - (num_nuts % 10) * Math.round(_.sprite.w * scale),
                      bg_top = - Math.floor(num_nuts /10) * Math.round(_.sprite.h * scale);
                      
                  
                  hov = $('<div class="map-hover-tile" />')
                    .attr('id', 'map-hover-f'+l+'-z'+z+'-n'+num)
                    .css({position: 'absolute',
                          top: hov_top,
                          left:  hov_left,
                          width: Math.round(_.sprite.w * scale),
                          height: Math.round(_.sprite.h * scale),
                          background: 'url('+image_root+'big-sprite-l'+l+'-z'+z+'.png) no-repeat',
                          'background-position': bg_left+'px ' + bg_top+'px' })
                    .appendTo(map.hov).hide();
              map.areas.push(area);
              map.hovers.push(hov);
            })();
          }
          _.maps['level-'+l]['zoom-'+z] = map;
        }
    };
    // Build tooltip <div> &c.
    var build_tooltip = function(){
      var _ = this;
      _.tooltip = $('<div id="mappu-tooltip"></div>')
        .html('<span>Gucci</span>')
        // .appendTo(_.con)
        .appendTo('body')
        .hover(function(){
            _.keep_tooltip.apply(_);
          }, function(){
            _.hide_tooltip.apply(_);
          })
        .click(function(e){
          e.stopPropagation();
        });
    };
    // Take an array of coordinates and find the extrema
    var extrema = function(arr){
      var most ={ l: {val: arr[0][0], n:0},
                  r: {val: arr[0][0], n:0},
                  t: {val: arr[0][1], n:0},
                  b: {val: arr[0][1], n:0} };
      for(n=0; n<arr.length; n++){
        var x = arr[n][0], y = arr[n][1];
        if(x < most.l.val)
          most.l = {val:x, n:n};
        if(x > most.r.val)
          most.r = {val:x, n:n};
        if(y < most.t.val)
          most.t = {val:y, n:n};
        if(y > most.b.val)
          most.b = {val:y, n:n};
      }
      return most;
    }
    // Take a list of coordinates and find the mid-point
    var center = function(arr, scale){
      var s = scale || 1,
          most = extrema(arr);
      return [((most.r.val - most.l.val)/2 + most.l.val) * s, ((most.b.val - most.t.val)/2 + most.t.val) * s];
    };
    /*********** Public ************/
    return { 
      stores: [],
      levels: {},
      clear_img: $.browser.msie ? image_root + 'clear.png' : img,
      zoom_levels : 2,
      maps: {},
      hold_ups: 0,
      init: function(args) {
        var ops = args[0],
            _ = this;
            
        // Containing <div>
        _.con = $(ops.container);
        // Get Map settings
        if (input = _.con.find('input[type=hidden]'), input.size()) {
          try {
            var json = eval('(' + input.val() + ')');
            if(!json) return;
            _.specs = json;
          } catch(e) {}
        }
        
        this.sprite = window.map_presets.sprite;
        
        
        this.init_runner(
          function(){
            var _ = this;
            // Parse all the Stores from HTML
            _.store_els = $(ops.stores);

            var ice = {}, ice_all = {}, level;
            _.store_els.each(function(i,tem){
              if (!$(tem).hasClass('pass')) {
                var json = eval('(' + $(tem).find('input.store-json').val() + ')');
                if (json){
                  level = json.level;
                  if(typeof ice_all[level] == 'undefined') ice_all[level] = -1;
                  ice_all[level]++;
                  // json.n_all = ice_all[level];
                  json.n_all = json.index;

                  if(typeof ice[json.level] == 'undefined') ice[json.level] = -1;
                  ice[json.level]++;
                  json.n = ice[json.level];

                  json.shape = eval(json.shape);
                  json.ref_point = eval(json.ref_point);
                  json.ref = eval(json.ref);
                  json.url = $(tem).find('a.learn-more').attr('href');
                  json.shape = sort_points(json.shape);
                  _.stores.push(json);
                }
              } else {
                var shape = eval('(' + $(tem).find('input.store-json').val() + ')');
                level = shape.floor;
                if(typeof ice_all[level] == 'undefined') ice_all[level] = -1;
                ice_all[level]++;
              }
              _.ice = ice; _.ice_all = ice_all;

            });
          },
          _.level_up,
          build_maps,
          build_tooltip,
          _.load_background,
          _.bind_events,
          function(){
            var _ = this;
            _.current_level = 0;
            _.current_zoom = 0;
            _.swap_level(0);
          }
        );
        return _;
      },
      
      init_runner: function(){
        if (!arguments.length) return this;
        var args = Array.prototype.slice.call(arguments);
        
        if (args[0] === true) {
          args.shift();
          $('#progress').css({ width: Math.round(this.init_n / this.init_count * 200) });
        } else {
          this.init_count = args.length;
          this.init_n = 1;
        }
        
        args.shift().call( this );
        args.unshift( true );
        
        var kore = this;
        if (arguments.length > 2)
          setTimeout(function(){
            kore.init_runner.apply( kore, args );
          }, 0);
        else
          $('#map-loading').fadeOut(function(){ $(this).remove(); });
        
        this.init_n++;
      },
      
      // Dig through Stores and sort them into Levels (floors)
      level_up: function() {
        for(n in this.stores) {
          var s = this.stores[n];
          if(!this.levels[s.level]) this.levels[s.level] = [];
          this.levels[s.level].push(s);
        }
      },

      // Load up the background images
      load_background: function() {
        var _ = this;
        for(l in _.maps)
          for(z in _.maps[l]){
            (function(){
              var map = _.maps[l][z],
                  lev = parseInt(l.replace('level-','')),
                  zoom = parseInt(z.replace('zoom-','')),
                  kore = _;
               
              map.bg = $('<img class="map-bg" />')
                .prependTo(map.wrap)
                .hide()
                .css({position:'absolute', top:0, left:0})
                .load(function(){
                  var dis = $(this).fadeIn(),
                      dup = dis.clone().css({'position':'absolute', 'left':'-50000'}).appendTo('body').show(),
                      big = (dup.outerWidth() > 1500),
                      wd = dup.outerWidth(), ht = dup.outerHeight();
                      view = kore.get_view(lev, zoom);
                  map.img.attr('width', wd).attr('height', ht);
                  view.size = { width:wd, height:ht };
                  kore.offset_view(view, kore.con.width() / 2 - wd / 2, kore.con.height() / 2 - ht / 2);
                  dup.remove();
                })
                .attr({src: (zoom == 0) ?
                              _.specs.background_images[lev] :
                              _.specs.zoomed_background_images[lev] });
            })();
          }

        return true;
      },
      // Bind them events, mang
      bind_events: function(){
        var _ = this;
        for(level in this.maps){
          this.maps[level]['zoom-1'].bg
            .dblclick(function(e){ _.zoom_out(); })
            .mousedown(function(e){ _.drag_start.apply(_, [e]); });
          this.maps[level]['zoom-0'].bg
            .dblclick(function(e){ _.zoom_in(); })
            .mousedown(function(e){ _.drag_start.apply(_, [e]); });
          this.maps[level]['zoom-1'].img
            .dblclick(function(e){ _.zoom_out(); })
            .mousedown(function(e){ _.drag_start.apply(_, [e]); });
          this.maps[level]['zoom-0'].img
            .dblclick(function(e){ _.zoom_in(); })
            .mousedown(function(e){ _.drag_start.apply(_, [e]); });
          // for(zoom in this.maps[level]){
            // this.maps[level][zoom].img
          $(document).mouseup(function(e){ _.drag_stop.apply(_, [e]); });
          // }
        }
      },
      // Swap out mall levels
      swap_level: function(n) {
        if(this.held_up()) return;
        var _ = this,
            map = _.get_view(n, _.current_zoom),
            old = _.current_view();
        old.wrap.hide();
        map.wrap.show();
        _.current_level = n;
      },
      // Zoomin' stuff
      zoom_out: function() {
        if(this.held_up()) return;
        if (this.current_zoom < 1) return;
        this.zoom_to(this.current_zoom - 1);
      },
      zoom_in: function() {
        if (this.held_up()) return;
        if (this.current_zoom >= this.zoom_levels-1) return;
        this.zoom_to(this.current_zoom + 1);
      },
      zoom_to: function(n){
        // return true;
        if(this.held_up()) return;
        if(typeof n == 'undefined') return;
        var map = this.get_view(this.current_level, n),
            old = this.current_view(),
            out = (this.current_zoom > n);
        if(!map) return;
        this.hold_up();
        this.current_zoom = n;
        if(old){
          var kore = this,
              img = old.bg,
              w = img.outerWidth() * (out ? 0.5 : 2), h = img.outerHeight() * (out ? 0.5 : 2),
              x = Math.round(this.con.width() / 2 - w / 2),
              y = Math.round(this.con.height() / 2 - h / 2);
              
          // console.log('nw: '+nw+' / nh:'+nh);
          old.wrap.animate({ left: x, top:y }, 192);
          img.animate({width: w, height: h},
                       192,
                       function(){
                         map.bg.css({width: w, height: h});
                         kore.offset_view(map, x, y);
                         old.wrap.hide();
                         map.wrap.show();
                         kore.ok_go();
                       });
        } 
      },
      // Show highlighted tile for an area
      highlight: function(level, zoom, n) {
        $('#map-hover-f'+level+'-z'+zoom+'-n'+n).stop(true, true).fadeIn(96);
      },
      halflight: function(level, zoom, n) {
        var el = $('#map-hover-f'+level+'-z'+zoom+'-n'+n);
        // if(!el.hasClass('sticky')) el.show().css({opacity:0.2});
        // if(!el.hasClass('sticky')) el.show().css({opacity:1});
        $('#map-hover-f'+level+'-z'+zoom+'-n'+n).stop(true, true).fadeIn(96);
      },
      // Hide the highlighted tile for an area
      lowlight: function(level, zoom, n) {
        var el = $('#map-hover-f'+level+'-z'+zoom+'-n'+n);
        if(!el.hasClass('sticky')) el.fadeOut();
      },
      stick: function(level, zoom, n) {
        $('#map-hover-f'+level+'-z'+zoom+'-n'+n).addClass('sticky');
      },
      unstick: function(level, zoom, n) {
        $('#map-hover-f'+level+'-z'+zoom+'-n'+n).removeClass('sticky');
      },
      // Finds a store by slug, then highlights it
      show: function(slug) {
        var store = this.get_store(slug);
        for(z=0; z<this.zoom_levels; z++){
          this.stick(store.level, z, store.n);
          this.highlight(store.level, z, store.n);
        }
      },
      // Finds a store by slug, then lowlights it
      hide: function(slug) {
        var store = this.get_store(slug);
        for(z=0; z<this.zoom_levels; z++){
          this.unstick(store.level, z, store.n);
          this.lowlight(store.level, z, store.n);
        }
      },
      hide_all: function(slug) {
        var l = 0, z = 0;
        for(var level in this.maps){
          var lev = this.maps[level];
          for(var zoom in lev){
            for(n=0; n < this.ice[l]; n++) {
              this.unstick(l, z, n);
              this.lowlight(l, z, n);
            }
            z++;
          }
          l++; z = 0;
        }
      },
      // Events for <area>s
      area_over: function(e, level, zoom, n) {
        if(this.held_up()) return;
        this.halflight(level, zoom, n);
        var store = this.get_store(parseInt(level), parseInt(n));
        this.show_tooltip(store.slug);
      },
      area_out: function(e, level, zoom, n) {
        // if(this.held_up()) return;
        this.lowlight(level, zoom, n);
        this.hide_tooltip();
      },
      area_click: function(e, level, zoom, n) {
        if (this.held_up()) return;
        var store = this.get_store(parseInt(level), parseInt(n));
        
        window.location = store.url;
        return true
        
        if (this.tooltip_expanded) {
          var _ = this;
          this.collapse_tooltip();
          setTimeout(function(){
            _.show_tooltip(store.slug);
          }, 100);
        } else {
          this.show_tooltip(store.slug);
          this.expand_tooltip(e);
        }
      },
      area_down: function(e, level, zoom, n) {
        if(this.held_up()) return;
      },
      area_up: function(e, level, zoom, n){
        if(e) e.preventDefault();
        if(this.held_up()) return;
      },
      // Show the tooltip
      show_tooltip: function(slug){
        if(this.tooltip_expanded) return;
        var _ = this,
            store = _.get_store(slug),
            scale = (1 / Math.pow(2, (_.zoom_levels - 1 - _.current_zoom) )),
            c = center(store.shape, scale),
            co = _.con.offset(),
            mo = _.current_view().offset,
            // dmo = { x: ((_.current_zoom==0) ? -267 : -883 / 2 - 115),
            //         y: ((_.current_zoom==0) ? -187 : -487 + 109) };
            dmo = {x:0, y:0};
        _.keep_tooltip();
        if(!_.tip_on) _.tooltip.fadeIn(98);
        _.tooltip.css({left:c[0] + co.left + mo.x - dmo.x , top:c[1] + co.top + mo.y - dmo.y - 20 }).find('span').html(store.name);
        
        // var colors=[[ 200000, 'rgba(177, 62, 53, 0.86)' ],
        //             [ 28000, 'rgba(214, 87, 135, 0.86)' ],
        //             [ 23000, 'rgba(100, 70, 137, 0.86)' ],
        //             [ 21000, 'rgba(105, 72, 227, 0.86)' ],
        //             [ 15000, 'rgba(16, 171, 215, 0.86)' ],
        //             [ 13000, 'rgba(16, 215, 156, 0.86)' ],
        //             [ 7300, 'rgba(165, 165, 165, 0.86)' ],
        //             [ 0, 'rgba(165, 165, 165, 0.86)' ]];
        // 
        // var color_no = 0;
        // while (colors[color_no][0] > store.pop) color_no++;
        // console.log('color_no: '+color_no);
        // _.tooltip.css({background:colors[color_no][1]});
        
        _.tooltip[0].store = store;
        _.tip_on = true;
      },
      
      // Start timer for hiding tooltip
      hide_tooltip: function(){
        if(this.tooltip_expanded) return;
        var _ = this;
        _.tip_timer = setTimeout(function(){ _.really_hide_tooltip.apply(_,[]); }, 400);
      },
      // Cancel the hiding of the tooltip
      keep_tooltip: function(){
        if(this.tip_timer) clearTimeout(this.tip_timer);
      },
      // Actually hide the tooltip
      really_hide_tooltip: function(){
        if(this.tooltip_expanded) this.collapse_tooltip();
        this.tooltip.fadeOut(98);
        this.tip_on = false;
      },
      // Make the tooltip the only thing you can interact with
      stick_tooltip: function(e){
        if(e) e.preventDefault();
        var _ = this;
        this.tooltip_stuck = true;
        // this.hold_up();
        if(e) e.stopPropagation();
        this.con.click(function(e){ _.unstick_tooltip.apply(_, [e]); });
        this.tooltip.css('z-index',1000);
      },
      unstick_tooltip: function(e){
        if(e) e.preventDefault();
        if(!this.tooltip_stuck) return;
        this.tooltip_stuck = false;
        this.ok_go();
        this.hide_tooltip();
        this.tooltip.css('z-index',500);
        if(this.tooltip_expanded) this.collapse_tooltip();
      },
      expand_tooltip: function(e){
        if(e) e.preventDefault();
        this.tooltip[0].natural_width = this.tooltip.outerWidth();
        this.tooltip[0].natural_height = this.tooltip.outerHeight();
        // this.tooltip.animate({width:200}, 96);
        this.tooltip.css({width:120});
        this.tooltip_expanded = true;
        this.stick_tooltip(e);
        this.tooltip.find('.content').remove();
        if (this.tooltip[0].store)
          this.tooltip.append('<div class="content"><span class="tooltip-phone">' + this.tooltip[0].store.phone + '</span><a class="tooltip-learn-more" href="' + this.tooltip[0].store.url + '">Store Details</a></div>');
        else
          this.tooltip.append('<div class="content" />');
      },
      collapse_tooltip: function(e){
        if(e) e.preventDefault();
        var _ = this;
        this.tooltip_expanded = false;
        // this.tooltip.animate({width:this.tooltip[0].natural_width, height:this.tooltip[0].natural_height}, 96, function(){
        this.tooltip.animate({width:this.tooltip[0].natural_width, height:this.tooltip[0].natural_height}, 0, function(){  
          this.style.width = null;
          this.style.height = null;
          _.tooltip.find('.content').remove();
        });
        if(this.tooltip_stuck) this.unstick_tooltip();
      },
      // Adds to the number of blocking processes, to
      // i.e. prevent dragging while zooming
      hold_up: function(){
        this.hold_ups++;
      },
      // Reduces blocks
      ok_go: function(){
        if(this.hold_ups < 1) return;
        this.hold_ups--;
      },
      // Returns true if there are any blocks
      held_up: function(){
        return (this.hold_ups > 0);
      },
      // Moves all the pieces of a specific view (zoom, level)
      // to given coordinates, i.e. when zooming or dragging
      offset_view: function(view, x, y){
        var zoomed = parseInt(view.hov.attr('id').replace(/map-hover-f([0-9]+)-z([0-9]+)/gim, '$2')) > 0,
            size = { w: this.con.width() - view.size.width,
                     h: this.con.height() - view.size.height },
            x = (x > 0)? 0 : (x < size.w)? size.w : x,
            y = (y > 0)? 0 : (y < size.h)? size.h : y;
            
        view.offset = {x:x, y:y};
        view.wrap.css({left:x, top:y});
        
        // if (this.tip_on) this.show_tooltip();
        
      },
      // Returns a View for a given level and zoom
      get_view: function(level, zoom){
        return (this.maps['level-'+level] && this.maps['level-'+level]['zoom-'+zoom]) ? this.maps['level-'+level]['zoom-'+zoom] : null;
      },
      // Returns the View for current level and zoom
      current_view: function(){
        return this.get_view(this.current_level, this.current_zoom);
      },
      // Returns
      get_store: function(a,b){
        var store = null;
        // Find it by slug
        if(typeof a == 'string') {
          for(n=0; n<this.stores.length; n++)
            if(this.stores[n].slug == a) { store = this.stores[n]; break; }
        // Find it by level, and number within that level 
        } else if((typeof a == 'number') && (typeof b == 'number')) {
          var x = 0;
          for(n=0; n<this.stores.length; n++)
            if(this.stores[n].level == a) {
              if(x == b) { store = this.stores[n]; break; }
              x++;
            }
        }
        return store;
      },
      // Records starting point for dragging; fired on mousedown of a View's img
      drag_start: function(e){
        e.preventDefault();
        this.dragging = true;
        var current = this.current_view(), fn_a;
        this.drag_origin = {x:e.pageX, y:e.pageY};
        this.map_origin = current.offset;
        if (this.tooltip_expanded) {
          this.collapse_tooltip();
          this.really_hide_tooltip(); 
        }
        // Need globally accessible reference to bound function to unbind it
        // (without unbinding all window mousemove); admittedly nasty
        (function(kore){
          var _ = kore;
          window.flaghaljksjfasdfljl = fn_a = function(e){
            _.drag_move.apply(_,[e]);
          };
        })(this);
        $(document).mousemove(fn_a);
        e.stopPropagation();
        return false;
      },
      // Stops dragging; fired on mouseup anywhere in document
      drag_stop: function(e){
        if(this.dragging) $(document).unbind('mousemove', window.flaghaljksjfasdfljl);
        this.dragging = false;
      },
      // Makes stuff happend on document mousemove if the mouse is held down
      drag_move: function(e){
        if(!this.dragging) return;
        e.preventDefault();
        if(this.held_up()) return;
        var current = this.current_view(),
            delta = {x:e.pageX - this.drag_origin.x, y:e.pageY - this.drag_origin.y};
        this.offset_view(current, delta.x + this.map_origin.x, delta.y + this.map_origin.y);
      }
    }
  }();
  
  mp.init.prototype = mp;
  
 /********
  Search Jockey - Handles matters of filtering, diplaying results &c.
  ****/
  var SearchJockey = function(){
    return new sj.init(Array.prototype.slice.call(arguments));
  },
  sj = SearchJockey.prototype = {
    tags: {},
    enabled_tags: {},
    init: function(args){
      var _ = this,
          ops = args[0];
      // Hook-up the Mappu for integration sake
      _.mappu = ops.mappu;
      if(!_.mappu) return false;
      // Divide stores into tags
      _.stores = _.mappu.stores;
      _.tag_em();
      // Build lists of tags in menu &c.
      // _.tag_con = $(ops.tags);
      // _.build_tags();
      // Owatta!
    
      return _;
    },
    // This goes through all the stores and
    // adds a tag to the list for each new one
    tag_em: function(){
      var _ = this;
      for(n in _.stores) {
        var s = _.stores[n],
            tags = s.tags.split(/,\s?/gmi);
        for(i=0; i<tags.length; i++){
          var t = tags[i];
          if(!_.tags[t] || !(_.tags[t] instanceof Array)) _.tags[t] = [];
          try { _.tags[t].push(s); } catch(foo){}
        }
        _.tags[s.name] = [s];

      }
    },
    // Adds <li> elements to the specified container
    // for each tag found in the stores
    build_tags: function(){
      var _ = this;
      for(t in _.tags)
        (function(){
          var tag = t;
          $('<li class="tag">' + t + '</li>')
            .appendTo(_.tag_con)
            .click(function(e){
              _.go_tag.apply(_,[tag, this]);
            });
          })();
    },
    // This enables or disables a tag in the list
    // Fired whenever a tag <li> element is clicked
    go_tag: function(tag, el){
      // Add it and true-ify it and/or falsify it
      if(typeof this.enabled_tags[tag] == 'undefined')
        this.enabled_tags[tag] = true;
      else
        this.enabled_tags[tag] = !this.enabled_tags[tag];
      // Toggle class on element
      // if(this.enabled_tags[tag]) $(el).addClass('enabled');
      // else $(el).removeClass('enabled');
      
        
      this.apply_tags();
    },
    // Returns a list of unique Stores for the given tag(s)
    get_stores_by_tag: function(ttt){
      var tags = (typeof ttt == 'string') ? [ttt] : ttt,
          stores = [],
          on = [];
      for(n=0; n<tags.length; n++)
        on = on.concat(this.tags[tags[n]]);
      
      for(n=0; n<this.stores.length; n++){
        var sto = this.stores[n];
        for(i=0; i<on.length; i++)
          if(sto == on[i]) { stores.push(sto); break; }
      }
      return stores;
    },
    // Returns a list of Stores whose tag(s) is enabled
    enabled_stores: function(){
      var list = [];
      for(tag in this.enabled_tags)
        if(this.enabled_tags[tag]) list.push(tag);
      return this.get_stores_by_tag(list);
    },
    // Interfaces with the Mappu to actually display the stores on the map
    apply_tags: function(){
      this.mappu.hide_all();
      var stores = this.enabled_stores();
      for(var n=0; n<stores.length; n++){
        this.mappu.show(stores[n].slug);
      }
    },
    // Type-ahead find
    quick_search: function(text){
      var sterilize = function(t){ return t.toLowerCase().replace(/[^a-z ]+/gm,''); },
          term = sterilize(text),
          tags = [];
      
      for (tag in this.tags)
        if( sterilize(tag.toString()).slice(0, term.length) == term )
          tags.push(tag);
          
      return tags;
    }
  };
  sj.init.prototype = sj;
  
 /********
  Info Jockey - Handles all matters of "More Info" &c.
  ****/
  var InfoJockey = function(){
    return new ij.init(Array.prototype.slice.call(arguments));
  },
  ij = InfoJockey.prototype = {
    init: function(){
      
      return this;
    }
  };
  ij.init.prototype = ij;
  
  
  window.Mappu = Mappu;
  window.SearchJockey = SearchJockey;
  window.InfoJockey = InfoJockey;
  
 /********
  Document Ready - Standard fare
  ****/
  $(document).ready(function(){
    // if(!$('#map-wrap #map').size()) return;
  });
  
  $(window).load(function(){
    $('#mappu-tooltip').append('<div class="point"></div>');
  });
  
})(jQuery);