@bongos/core 1.21.10 → 1.21.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,14 @@
10
10
  // short matter card a pin opens. No innerHTML anywhere: every node is created,
11
11
  // and every docket string lands as text or an attribute.
12
12
  //
13
+ // INSIDE (task 1004526). When the address names a building or a district the
14
+ // street gives way to its interior (#streetInside): GovInside.buildingModel()
15
+ // or districtModel() (street-inside.js) drawn into the same artboard. Picking a
16
+ // floor moves the lift (a CSS transition on one persistent node) and re-enters
17
+ // the chosen floor's block (the prototype's flip: two blocks, alternating); a
18
+ // table row opens the same short card a pin does; a district reads its goal's
19
+ // tasks once (GET /tasks?goal_id=N) and draws them.
20
+ //
13
21
  // THE FEEDS (all GETs, all gated server-side):
14
22
  // /api/bongos/government/docket buildings, pins, lines, readings (task 1004523)
15
23
  // /api/bongos/goals the open goals: one district each
@@ -38,7 +46,10 @@
38
46
  goals: '/api/bongos/goals',
39
47
  rollups: '/api/bongos/goals/rollups',
40
48
  earnings: function (id) { return '/api/bongos/builders/' + encodeURIComponent(id) + '/earnings'; },
49
+ tasks: function (goalId) { return '/api/bongos/tasks?goal_id=' + encodeURIComponent(goalId); },
41
50
  };
51
+ var NARROW = 900;
52
+ var I = window.GovInside;
42
53
  // The artboard's street band: the prototype's 900-high board less its 64 px
43
54
  // header and 128 px footer, which this page lays out as real rows.
44
55
  var BAND_TOP = 64, BAND_H = 708;
@@ -46,8 +57,8 @@
46
57
 
47
58
  var $ = function (id) { return document.getElementById(id); };
48
59
  var media = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
49
- var data = { docket: null, goals: [], rollups: [], earnings: null, loaded: false };
50
- var view = { open: null, opener: null, model: null, scale: 1, mode: null };
60
+ var data = { docket: null, goals: [], rollups: [], earnings: null, loaded: false, tasks: {} };
61
+ var view = { open: null, opener: null, model: null, scale: 1, mode: null, inside: null, insideModel: null };
51
62
 
52
63
  // ---------- light / dark ----------
53
64
  var chosen = null;
@@ -91,6 +102,7 @@
91
102
  // grows it, a smaller one shrinks it; a phone keeps it near full size and the
92
103
  // street scrolls sideways inside its window, so a pin stays a pin.
93
104
  function fit() {
105
+ fitInside();
94
106
  var win = $('streetWindow'), sizer = $('streetSizer'), board = $('streetBoard');
95
107
  if (!win || !sizer || !board) return;
96
108
  var W = view.model ? view.model.width : S.ARTBOARD_W;
@@ -108,6 +120,32 @@
108
120
  placeCard();
109
121
  }
110
122
 
123
+ // The interior's artboard: 1440 x 708 scaled to the window like the street;
124
+ // under NARROW px the board is a column and only the drawing scales, in its
125
+ // own sideways strip, never under 0.6 so a floor stays a 24 px target.
126
+ function fitInside() {
127
+ var box = $('streetInside'), sizer = $('insideSizer'), board = $('insideBoard'), art = $('insideArt'), artBox = $('insideArtBox'), span = $('insideArtSpan');
128
+ if (!box || !sizer || !board || !art || !artBox || box.hidden) return;
129
+ var win = $('streetWindow');
130
+ var cw = (win && win.clientWidth) || window.innerWidth || 1440, ch = (win && win.clientHeight) || 708;
131
+ var artW = view.inside && view.inside.kind === 'district' ? 1440 : 800;
132
+ if ((window.innerWidth || cw) < NARROW) {
133
+ var a = Math.max(0.6, Math.min(1, Math.round((cw - 32) / artW * 1000) / 1000));
134
+ sizer.style.width = ''; sizer.style.height = '';
135
+ board.style.setProperty('--inside-scale', '1');
136
+ artBox.style.setProperty('--inside-art-scale', String(a));
137
+ art.style.setProperty('--inside-art-h', Math.round(708 * a) + 'px');
138
+ if (span) { span.style.width = Math.round(artW * a) + 'px'; span.style.height = Math.round(708 * a) + 'px'; }
139
+ return;
140
+ }
141
+ var s = Math.max(0.4, Math.round(Math.min(cw / 1440, ch / 708) * 1000) / 1000);
142
+ sizer.style.width = Math.round(1440 * s) + 'px';
143
+ sizer.style.height = Math.round(708 * s) + 'px';
144
+ board.style.setProperty('--inside-scale', String(s));
145
+ artBox.style.setProperty('--inside-art-scale', '1');
146
+ if (span) { span.style.width = '0px'; span.style.height = '0px'; }
147
+ }
148
+
111
149
  // ---------- the feeds ----------
112
150
  function getJson(url) {
113
151
  return fetch(url, { credentials: 'same-origin', headers: { accept: 'application/json' } })
@@ -130,6 +168,18 @@
130
168
  });
131
169
  }
132
170
 
171
+ // A district's work: its goal's tasks, read once per goal and kept
172
+ // (null while reading, false when the read failed).
173
+ function loadTasks(goalId) {
174
+ var k = String(goalId);
175
+ if (Object.prototype.hasOwnProperty.call(data.tasks, k)) return null;
176
+ data.tasks[k] = null;
177
+ return getJson(FEEDS.tasks(k)).then(function (r) {
178
+ data.tasks[k] = r && Array.isArray(r.tasks) ? r.tasks : false;
179
+ draw();
180
+ });
181
+ }
182
+
133
183
  // ---------- drawing ----------
134
184
  function clear(el) { while (el && el.firstChild) el.removeChild(el.firstChild); }
135
185
  function pathEl(p) {
@@ -208,6 +258,11 @@
208
258
  var mode = currentMode();
209
259
  view.mode = mode;
210
260
  paintSwitch(mode);
261
+ var h = here();
262
+ var inside = $('streetInside');
263
+ var sizerEl = $('streetSizer');
264
+ var showInside = !!(h && inside && I);
265
+ if (sizerEl) sizerEl.hidden = showInside;
211
266
  var m = S.streetModel({ docket: data.docket, goals: data.goals, rollups: data.rollups, earnings: data.earnings, mode: mode, now: Date.now(), here: here() });
212
267
  view.model = m;
213
268
  var flat = $('streetFlat'), blds = $('streetBlds');
@@ -258,9 +313,9 @@
258
313
  m.signs.forEach(function (sg) { signs.appendChild(drawSign(sg)); });
259
314
 
260
315
  var hint = $('streetHint');
261
- if (hint) { hint.textContent = m.hint; hint.hidden = !m.hint || !!view.open; }
316
+ if (hint) { hint.textContent = m.hint; hint.hidden = !m.hint || !!view.open || showInside; }
262
317
  var eve = $('streetEvening');
263
- if (eve) eve.hidden = !(m.evening && !view.open);
318
+ if (eve) eve.hidden = !(m.evening && !view.open) || showInside;
264
319
  var eveLine = $('streetEveningLine');
265
320
  if (eveLine) eveLine.textContent = m.eveningLine;
266
321
 
@@ -274,11 +329,264 @@
274
329
  var home = $('streetHome');
275
330
  if (home) home.setAttribute('href', S.HOME_HREF);
276
331
 
332
+ if (showInside) drawInside(h, mode);
333
+ else {
334
+ if (inside) inside.hidden = true;
335
+ view.inside = null;
336
+ view.insideModel = null;
337
+ }
338
+
277
339
  fit();
278
340
  if (view.open) fillCard();
279
341
  return m;
280
342
  }
281
343
 
344
+ // ---------- inside a building or a district ----------
345
+ function svgEl(tag) { return document.createElementNS(SVG_NS, tag); }
346
+ function setText(id, v) { var el = $(id); if (el) el.textContent = v == null ? '' : String(v); return el; }
347
+ function show(id, on) { var el = $(id); if (el) el.hidden = !on; return el; }
348
+ function drawPaths(g, list) { clear(g); list.forEach(function (p) { if (g) g.appendChild(pathEl(p)); }); }
349
+
350
+ function drawInside(h, mode) {
351
+ var box = $('streetInside');
352
+ var same = view.inside && view.inside.kind === h.kind && view.inside.key === h.key;
353
+ if (!same) view.inside = { kind: h.kind, key: h.key, floor: null, drawer: null, picks: 0, note: false };
354
+ var arriving = box.hidden;
355
+ box.hidden = false;
356
+ box.setAttribute('data-kind', h.kind);
357
+ if (h.kind === 'building') drawBuilding(mode);
358
+ else drawDistrict(mode);
359
+ // stepping in through a door moves focus to the interior's name, so a
360
+ // keyboard or a screen reader arrives where the eye does (a page opened
361
+ // straight at the address keeps the browser's own start)
362
+ if ((arriving || !same) && view.navigated) {
363
+ var target = h.kind === 'building' ? $('insideName') : $('insideDName');
364
+ if (target && target.focus) target.focus();
365
+ }
366
+ }
367
+
368
+ function drawBuilding(mode) {
369
+ var st = view.inside;
370
+ var bv = I.buildingModel({ key: st.key, docket: data.docket, goals: data.goals, mode: mode, now: Date.now(), floor: st.floor, drawer: st.drawer, picks: st.picks });
371
+ view.insideModel = bv;
372
+ setText('insideKicker', bv.kicker);
373
+ show('insidePanel', true); show('insideDHead', false); show('insideLegend', false);
374
+ clear($('insideItems'));
375
+ var svg = $('insideSvg');
376
+ if (svg) { svg.setAttribute('width', '800'); svg.setAttribute('viewBox', '0 0 800 708'); svg.setAttribute('aria-label', bv.label); }
377
+ drawPaths($('insideShapes'), bv.shapes);
378
+ var syms = $('insideSyms'); clear(syms);
379
+ bv.syms.forEach(function (sy) {
380
+ var g = svgEl('g');
381
+ g.setAttribute('transform', 'translate(' + sy.x + ' ' + sy.y + ') scale(' + sy.k + ')');
382
+ var a = svgEl('path');
383
+ a.setAttribute('class', 'inside-sym');
384
+ a.setAttribute('d', sy.d); a.setAttribute('stroke', sy.c); a.setAttribute('stroke-width', String(sy.w));
385
+ var b = svgEl('path');
386
+ b.setAttribute('d', sy.f || ''); b.setAttribute('fill', sy.c); b.setAttribute('stroke', 'none');
387
+ g.appendChild(a); g.appendChild(b);
388
+ if (syms) syms.appendChild(g);
389
+ });
390
+ var texts = $('insideTexts'); clear(texts);
391
+ bv.texts.forEach(function (t) {
392
+ var el = svgEl('text');
393
+ el.setAttribute('x', String(t.x)); el.setAttribute('y', String(t.y));
394
+ el.setAttribute('fill', t.c);
395
+ el.setAttribute('font-size', String(t.s)); el.setAttribute('font-weight', String(t.w));
396
+ el.setAttribute('text-anchor', t.a);
397
+ if (t.ls && t.ls !== 'normal') el.setAttribute('letter-spacing', t.ls);
398
+ if (/Mono/.test(t.f)) el.setAttribute('class', 'inside-mono');
399
+ el.textContent = t.v;
400
+ if (texts) texts.appendChild(el);
401
+ });
402
+ var floors = $('insideFloors'); clear(floors);
403
+ bv.floors.forEach(function (f) {
404
+ var b = at(node('button', 'inside-floor'), f.x, f.y, f.w, f.h);
405
+ b.setAttribute('type', 'button');
406
+ b.setAttribute('aria-label', f.aria);
407
+ b.setAttribute('aria-pressed', f.selected ? 'true' : 'false');
408
+ b.setAttribute('data-floor', String(f.index));
409
+ b.addEventListener('click', function () { pickFloor(f.index); });
410
+ if (floors) floors.appendChild(b);
411
+ });
412
+ // the lift is ONE node kept across draws, so its transform transitions
413
+ var lift = $('insideLift');
414
+ if (lift) {
415
+ lift.hidden = false;
416
+ at(lift, bv.lift.x, bv.lift.y, null, bv.lift.h);
417
+ lift.style.transform = 'translateY(' + bv.lift.ty + 'px)';
418
+ }
419
+ var annex = $('insideAnnex');
420
+ if (annex) {
421
+ annex.hidden = !bv.hasAnnex;
422
+ if (bv.hasAnnex) at(annex, bv.annex.x, bv.annex.y, bv.annex.w, bv.annex.h);
423
+ setText('insideAnnexText', bv.annex.text);
424
+ }
425
+
426
+ // the panel
427
+ setText('insideName', bv.name);
428
+ setText('insideHolds', bv.holds);
429
+ var seats = $('insideSeats'); clear(seats);
430
+ bv.seats.forEach(function (sc) {
431
+ var cls = sc.key === 'you' ? ' inside-seat--you' : sc.key === '—' ? ' inside-seat--open' : '';
432
+ if (seats) seats.appendChild(node('span', 'inside-seat' + cls, sc.init));
433
+ });
434
+ setText('insideWho', bv.whoText);
435
+ var gf = $('insideGlyphF'), gl = $('insideGlyphL');
436
+ if (gf) gf.setAttribute('d', bv.gf || '');
437
+ if (gl) gl.setAttribute('d', bv.gl || '');
438
+ setText('insideHow', bv.howText);
439
+ var note = $('insideAmendNote');
440
+ if (note) { note.textContent = st.note ? AMEND_NOTE : ''; note.hidden = !st.note; }
441
+ var fill = $('insideFill');
442
+ if (fill) { fill.style.width = bv.fill + '%'; fill.className = 'inside-meter__fill' + (bv.fill >= 80 ? ' inside-meter__fill--full' : ''); }
443
+ setText('insideGrowth', bv.growth);
444
+ show('insideTableWrap', bv.hasTable);
445
+ var table = $('insideTable'); clear(table);
446
+ bv.table.forEach(function (r) {
447
+ var b = node('button', 'inside-row' + (r.state === 'needs' ? ' inside-row--needs' : ''));
448
+ b.setAttribute('type', 'button');
449
+ b.setAttribute('data-matter', r.matter);
450
+ b.setAttribute('aria-controls', 'streetCard');
451
+ b.setAttribute('aria-expanded', view.open === r.matter ? 'true' : 'false');
452
+ b.appendChild(node('span', 'inside-row__label', r.label));
453
+ b.appendChild(node('span', 'inside-row__status', r.status));
454
+ b.addEventListener('click', function () { openCard(r.matter, b); });
455
+ if (table) table.appendChild(b);
456
+ });
457
+ // the chosen floor: two blocks that take turns, so the block re-enters on every pick
458
+ var on = $(bv.flipA ? 'insideOpenA' : 'insideOpenB'), off = $(bv.flipA ? 'insideOpenB' : 'insideOpenA');
459
+ if (off) { off.hidden = true; clear(off); }
460
+ if (on) { on.hidden = false; fillOpen(on, bv); }
461
+ setText('insideOnFile', bv.onFile);
462
+ var drawers = $('insideDrawers'); clear(drawers);
463
+ bv.drawers.forEach(function (dw) {
464
+ var b = node('button', 'inside-drawer');
465
+ b.setAttribute('type', 'button');
466
+ b.setAttribute('aria-label', dw.aria);
467
+ b.setAttribute('aria-pressed', dw.selected ? 'true' : 'false');
468
+ b.setAttribute('data-drawer', String(dw.index));
469
+ b.appendChild(node('span', 'inside-drawer__handle'));
470
+ b.appendChild(node('span', 'inside-drawer__label', dw.label));
471
+ b.appendChild(node('span', 'inside-drawer__count', dw.count));
472
+ b.addEventListener('click', function () { st.drawer = dw.index; draw(); });
473
+ if (drawers) drawers.appendChild(b);
474
+ });
475
+ var ditems = $('insideDrawerItems'); clear(ditems);
476
+ bv.drawerItems.forEach(function (it) {
477
+ var row = node('div', 'inside-ditem');
478
+ row.appendChild(node('span', '', it.text));
479
+ row.appendChild(node('span', 'inside-ditem__meta', it.meta));
480
+ if (ditems) ditems.appendChild(row);
481
+ });
482
+ }
483
+
484
+ function fillOpen(el, bv) {
485
+ clear(el);
486
+ var head = node('div', 'inside-open__head');
487
+ var plate = node('span', 'inside-plate');
488
+ var svg = svgEl('svg');
489
+ svg.setAttribute('width', '40'); svg.setAttribute('height', '40'); svg.setAttribute('viewBox', '0 0 24 24'); svg.setAttribute('aria-hidden', 'true');
490
+ var a = svgEl('path'); a.setAttribute('d', bv.sym.d || '');
491
+ var b = svgEl('path'); b.setAttribute('d', bv.sym.f || '');
492
+ svg.appendChild(a); svg.appendChild(b);
493
+ plate.appendChild(svg);
494
+ head.appendChild(plate);
495
+ var words = node('div', 'inside-open__words');
496
+ words.appendChild(node('span', 'inside-open__kicker', bv.openKicker));
497
+ words.appendChild(node('h3', 'inside-open__title', bv.openTitle));
498
+ head.appendChild(words);
499
+ el.appendChild(head);
500
+ bv.openLines.forEach(function (l) {
501
+ var row = node('div', 'inside-line');
502
+ row.appendChild(node('span', '', l.text));
503
+ row.appendChild(node('span', 'inside-line__meta', l.meta));
504
+ el.appendChild(row);
505
+ });
506
+ }
507
+
508
+ function pickFloor(i) {
509
+ var st = view.inside;
510
+ if (!st) return;
511
+ st.floor = i;
512
+ st.picks = (st.picks || 0) + 1;
513
+ draw();
514
+ var floors = $('insideFloors');
515
+ var kids = (floors && floors.children) || [];
516
+ for (var k = 0; k < kids.length; k++) if (kids[k].getAttribute('data-floor') === String(i)) { if (kids[k].focus) kids[k].focus(); break; }
517
+ }
518
+
519
+ // Change how this works: drafting the amendment is task 1004530. Until then
520
+ // the button is present and says so, rather than doing nothing silently.
521
+ var AMEND_NOTE = 'Drafting an amendment from here is not built yet. For now, raise it with the council on the board.';
522
+ function amend() {
523
+ if (!view.inside) return;
524
+ view.inside.note = true;
525
+ var note = $('insideAmendNote');
526
+ if (note) { note.textContent = AMEND_NOTE; note.hidden = false; }
527
+ }
528
+
529
+ function drawDistrict(mode) {
530
+ var st = view.inside;
531
+ var k = String(st.key);
532
+ var known = Object.prototype.hasOwnProperty.call(data.tasks, k);
533
+ if (!known) loadTasks(k);
534
+ var dv = I.districtModel({ goalId: k, goals: data.goals, tasks: known ? data.tasks[k] : null, mode: mode });
535
+ view.insideModel = dv;
536
+ var T = S.theme(mode);
537
+ setText('insideKicker', dv.kicker);
538
+ show('insidePanel', false); show('insideDHead', true); show('insideLegend', true);
539
+ show('insideAnnex', false);
540
+ var lift = $('insideLift'); if (lift) lift.hidden = true;
541
+ clear($('insideFloors')); clear($('insideSyms')); clear($('insideTexts'));
542
+ setText('insideDName', dv.name);
543
+ setText('insideDLine', dv.line);
544
+ var svg = $('insideSvg');
545
+ if (svg) { svg.setAttribute('width', '1440'); svg.setAttribute('viewBox', '0 0 1440 708'); svg.setAttribute('aria-label', dv.label); }
546
+ var shapes = $('insideShapes'); clear(shapes);
547
+ var g = svgEl('g');
548
+ g.setAttribute('transform', 'translate(' + dv.tx + ' ' + dv.ty + ') scale(' + dv.s + ')');
549
+ dv.shapes.forEach(function (p) { g.appendChild(pathEl(p)); });
550
+ if (shapes) {
551
+ shapes.appendChild(pathEl({ d: dv.road, f: T.road, s: 'none' }));
552
+ shapes.appendChild(pathEl({ d: dv.ground, f: 'none', s: T.line }));
553
+ shapes.appendChild(g);
554
+ }
555
+ var items = $('insideItems'); clear(items);
556
+ dv.items.forEach(function (it) {
557
+ var el = at(node(it.href ? 'a' : 'div', 'inside-item' + (it.stage === 'shipped' ? ' inside-item--shipped' : '')), it.x, it.y, it.w);
558
+ if (it.href) el.setAttribute('href', it.href);
559
+ var nm = node('span', 'inside-item__name', it.name);
560
+ nm.setAttribute('title', it.name);
561
+ el.appendChild(nm);
562
+ el.appendChild(node('span', 'inside-item__meta', it.meta));
563
+ el.appendChild(node('span', 'inside-item__stage', it.stage));
564
+ if (items) items.appendChild(el);
565
+ });
566
+ var legend = $('insideLegend'); clear(legend);
567
+ dv.legend.forEach(function (l) { if (legend) legend.appendChild(node('span', '', l.text)); });
568
+ if (dv.more && legend) {
569
+ var more = node('a', 'inside-more', dv.more + ' more in this goal');
570
+ more.setAttribute('href', dv.goalHref);
571
+ legend.appendChild(more);
572
+ }
573
+ }
574
+
575
+ // back to the street without a reload: drop the hash, keep the history entry,
576
+ // and give focus back to the door that was used
577
+ function goStreet(e) {
578
+ var was = view.inside;
579
+ if (!(window.history && window.history.pushState)) return;
580
+ if (e && e.preventDefault) e.preventDefault();
581
+ window.history.pushState(null, '', '/builders/street');
582
+ draw();
583
+ if (!was) return;
584
+ var doors = ($('streetDoors') && $('streetDoors').children) || [];
585
+ var key = was.kind === 'building' ? was.key : 'd:' + was.key;
586
+ for (var i = 0; i < doors.length; i++) if (doors[i].getAttribute('data-door') === key) { if (doors[i].focus) doors[i].focus(); break; }
587
+ }
588
+
589
+
282
590
  // ---------- the short matter card ----------
283
591
  function fillCard() {
284
592
  var cv = S.cardFor(data.docket, view.open, Date.now());
@@ -333,9 +641,14 @@
333
641
  // The pins were redrawn, so focus goes back to the new button for the same matter.
334
642
  if (restore !== false && was && was.getAttribute) {
335
643
  var key = was.getAttribute('data-matter');
336
- var pins = $('streetPins').children || [];
337
- for (var i = 0; i < pins.length; i++) {
338
- if (pins[i].getAttribute('data-matter') === key) { if (pins[i].focus) pins[i].focus(); break; }
644
+ // the pins and the table rows were redrawn: focus the new control for the same matter
645
+ // .children is an HTMLCollection, which concat does not spread: copy it first
646
+ var list = function (id) { var el = $(id); return el && el.children ? Array.prototype.slice.call(el.children) : []; };
647
+ var pins = list('streetPins');
648
+ var rows = list('insideTable');
649
+ var pool = view.inside ? [].concat(rows, pins) : [].concat(pins, rows);
650
+ for (var i = 0; i < pool.length; i++) {
651
+ if (pool[i].getAttribute('data-matter') === key) { if (pool[i].focus) pool[i].focus(); break; }
339
652
  }
340
653
  }
341
654
  }
@@ -350,7 +663,12 @@
350
663
  if (close) close.addEventListener('click', function () { closeCard(true); });
351
664
  window.addEventListener('keydown', onKey);
352
665
  window.addEventListener('resize', fit);
353
- window.addEventListener('hashchange', function () { draw(); });
666
+ window.addEventListener('hashchange', function () { view.navigated = true; draw(); });
667
+ window.addEventListener('popstate', function () { view.navigated = true; draw(); });
668
+ var back = $('insideBack');
669
+ if (back) back.addEventListener('click', goStreet);
670
+ var am = $('insideAmend');
671
+ if (am) am.addEventListener('click', amend);
354
672
  var win = $('streetWindow');
355
673
  if (win) win.addEventListener('scroll', placeCard);
356
674
  if (media && media.addEventListener) media.addEventListener('change', function () { if (!storedTheme()) { applyTheme(); draw(); } });
@@ -359,6 +677,6 @@
359
677
  return load();
360
678
  }
361
679
 
362
- window.GovStreetPage = { boot: boot, draw: draw, load: load, fit: fit, openCard: openCard, closeCard: closeCard, FEEDS: FEEDS, THEME_KEY: THEME_KEY };
680
+ window.GovStreetPage = { boot: boot, draw: draw, load: load, fit: fit, openCard: openCard, closeCard: closeCard, pickFloor: pickFloor, goStreet: goStreet, FEEDS: FEEDS, THEME_KEY: THEME_KEY };
363
681
  window.GovStreetPage.ready = boot();
364
682
  }());