Skip to content

Instantly share code, notes, and snippets.

@kimardenmiller
Created August 19, 2014 19:53
Show Gist options
  • Save kimardenmiller/99871f99132616c7b669 to your computer and use it in GitHub Desktop.
Save kimardenmiller/99871f99132616c7b669 to your computer and use it in GitHub Desktop.
Vote Forking in Spokenvote
// Generated by CoffeeScript 1.6.3
(function() {
var FireCtrl;
FireCtrl = function($sce, $scope, $interval) {
var timer;
$scope.options = {
initialID: 1,
width: 960,
height: 440,
exitAnimateStyle: {
opacity: 0
},
enterAnimateStyle: {
opacity: 1
},
animateExit: {
msToFade: 750
},
enterAtParent: true,
enterCenterJitter: 10,
min: 0,
currentNode: 0,
headLabel: 'fa-play',
currentTs: void 0,
sliderReset: true,
radiusMeasure: 7,
force: {
charge: function(n) {
return n.forceViewCharge || -200;
},
linkDistance: function(l) {
return l.linkDistance || 200;
}
}
};
$scope.message = $sce.trustAsHtml('Press <b><em>Play</em></b> and <b><em>Pause</em></b> controls on left to start and stop,\
or you may scrub the visualization using the <b><em>Slider</em></b>.');
$scope.hovered = function(d) {
if (d === 'leave') {
$scope.hover = 'Hover, click or Drag any Node to see more.';
} else {
$scope.hover = d.type.charAt(0).toUpperCase() + d.type.substr(1).toLowerCase() + ': ' + (function() {
switch (false) {
case d.type !== 'voter':
return d.name;
case d.type !== 'hub':
return 'This would be your group';
default:
return d.text;
}
})();
}
return $scope.$apply();
};
timer = void 0;
$scope.play = function() {
var curVal, dir, forward, tick;
$scope.message = null;
$scope.hover = 'Hover, click or Drag any Node to see more.';
if (angular.isDefined(timer)) {
return $scope.pauseSlider();
} else {
$scope.options.headLabel = 'fa-pause';
forward = true;
curVal = void 0;
dir = 1;
tick = ($scope.options.max - $scope.options.min) / 200;
return timer = $interval(function() {
curVal = Number($scope.options.currentNode) || $scope.options.min;
if (curVal - tick < $scope.options.min) {
dir = 1;
$scope.options.sliderReset = true;
}
$scope.options.currentNode = curVal + dir * tick;
if (curVal + tick > $scope.options.max) {
return $scope.pauseSlider();
}
}, 400);
}
};
$scope.pauseSlider = function() {
if (angular.isDefined(timer)) {
$interval.cancel(timer);
$scope.options.headLabel = 'fa-play';
return timer = undefined;
}
};
return $scope.$on("$destroy", function() {
return $scope.pauseSlider();
});
};
window.App = angular.module('spokenvote', ['spokenvote.services', 'spokenvote.directives', 'ui.bootstrap']);
App.Directives = angular.module('spokenvote.directives', []);
App.Services = angular.module('spokenvote.services', ['ngResource']);
App.controller('FireCtrl', FireCtrl);
}).call(this);
// Generated by CoffeeScript 1.6.3
(function() {
var forceChart;
forceChart = function($compile, NodeEmitter, CollapsibleTreeLoader, FlattenVotingTree, AnimatingExperiments) {
return {
restrict: "EA",
replace: true,
scope: {
options: '=',
hovered: '&hovered'
},
link: function(scope, element, attrs) {
var forceHeight, forceWidth, fvID, links, nodes, root, update;
root = [];
nodes = [];
links = [];
fvID = "_fv" + scope.options.initialID++;
forceWidth = scope.options.width || angular.element(window)[0].innerWidth;
forceHeight = scope.options.height || angular.element(window)[0].innerHeight * .7;
scope._tick = function() {
scope.link.attr({
x1: function(d) {
return d.source.x;
},
y1: function(d) {
return d.source.y;
},
x2: function(d) {
return d.target.x;
},
y2: function(d) {
return d.target.y;
}
});
return scope.node.attr({
transform: function(d) {
return "translate(" + d.x + "," + d.y + ")";
}
}).exit().attr({
cx: function(d) {
return d.x;
},
cy: function(d) {
return d.y;
}
});
};
scope._setSelectionRadius = function(selection) {
return selection.attr("r", function(d) {
return scope.options.radiusMeasure || 7;
});
};
scope._colorNode = function(d) {
if (d.isDemo) {
return "#82b446";
} else {
return "steelblue";
}
};
scope.collapseClick = function(d) {
if (!d3.event.defaultPrevented) {
d.hidden = !d.hidden;
FlattenVotingTree(scope, root);
return update();
}
};
window.onresize = function() {
if (!scope.options.width) {
forceWidth = angular.element(window)[0].innerWidth;
}
if (!scope.options.height) {
forceHeight = angular.element(window)[0].innerHeight;
}
scope.force.size([forceWidth, forceHeight]);
scope.visSvg.selectAll('.node').remove();
if (nodes.length > 0) {
return scope.render();
}
};
scope.visSvg = d3.select(element[0]).append("svg").attr({
width: forceWidth,
height: forceHeight
});
scope.visSvg.append("clipPath").attr("id", "clip").append("circle").attr({
cx: 0,
cy: 0,
r: 15
});
scope.force = d3.layout.force().size([forceWidth, forceHeight]).linkDistance(scope.options.force.linkDistance).charge(scope.options.force.charge).linkStrength(.35).friction(.85).theta(.9).gravity(.06).on('tick', scope._tick);
CollapsibleTreeLoader().then(function(json) {
root = json;
FlattenVotingTree(scope, root);
return scope.$watch('options.currentNode', function() {
return update();
});
});
update = function() {
NodeEmitter(scope);
if (scope.nodesAndLinks) {
if (scope.nodesAndLinks.nodes) {
nodes = scope.nodesAndLinks.nodes;
}
if (scope.nodesAndLinks.links) {
links = scope.nodesAndLinks.links;
}
if (scope.nodesAndLinks.nodes.length > 0) {
return scope.render();
}
}
};
scope.link = scope.visSvg.selectAll("line.link");
return scope.render = function() {
var enterLinks, enterNodes;
if (scope.options.sliderReset) {
scope.visSvg.selectAll('.node').remove();
scope.options.sliderReset = false;
}
if (!nodes || nodes.length < 1) {
console.log("No nodes present.");
return;
}
scope.force.nodes(nodes).links(links).start();
scope.node = scope.visSvg.selectAll("g.node").data(nodes, function(d) {
return d.id;
}).attr({
"transform": function(d) {
return "translate(" + d.x + "," + d.y + ")";
}
});
if (scope.options.animateExit) {
scope.node.each(function(d) {
return delete d[fvID].isExitting;
}).interrupt().transition().duration(scope.options.animateExit.msToFade / 2).style(scope.options.enterAnimateStyle);
}
enterNodes = scope.node.enter().append('svg:g').each(function(d) {
if (!d[fvID]) {
d[fvID] = {};
}
if (scope.options.enterAtParent && d.parent && d.parent.x) {
d.x = d.px = d.parent.x;
d.y = d.py = d.parent.y;
} else if (scope.options.enterCenterJitter && d.type !== 'hub' && scope.node[0][0].__data__.x) {
d.x = d.px = scope.node[0][0].__data__.x + 2 * scope.options.enterCenterJitter * Math.random() - scope.options.enterCenterJitter;
d.y = d.py = scope.node[0][0].__data__.y + 2 * scope.options.enterCenterJitter * Math.random() - scope.options.enterCenterJitter;
} else if (d.type === 'hub') {
d.x = d.px = 50;
d.y = d.py = 50;
} else {
d.x = d.px = forceWidth / 2;
d.y = d.py = forceHeight / 2;
}
return delete d[fvID].isExitting;
}).attr({
id: function(d) {
return d.id;
},
"class": 'node'
}).call(scope._setSelectionRadius).call(scope.force.drag).filter(function(d) {
return !d.isDemo;
}).on({
mouseover: function(d) {
return scope.hovered({
args: d
});
},
mouseleave: function() {
return scope.hovered({
args: 'leave'
});
}
});
enterNodes.filter(function(d) {
return d.type === 'hub';
}).append('circle').attr({
"class": 'hub'
}).style({
fill: 'DarkGray'
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'hub';
}).selectAll('circle').attr({
r: function(d) {
d.size = nodes.length;
return d.size * .8 + 15;
}
});
enterNodes.filter(function(d) {
return d.type === 'hub';
}).append("text").attr({
"class": 'hub label',
dy: .5 + 'em'
}).text(function(d) {
return d.name;
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'hub';
}).selectAll('text').style({
'font-size': function(d) {
return d.size * .4 + 5 + 'px';
},
color: 'black'
});
enterNodes.filter(function(d) {
return d.type === 'topic';
}).append('circle').attr({
"class": 'topic'
}).style({
fill: 'Chocolate'
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'topic';
}).selectAll('circle').attr({
r: function(d) {
var pLks, vLks;
pLks = links.filter(function(l) {
return l.source.id === d.id;
});
d.size = pLks.length;
vLks = [];
pLks.forEach(function(pl) {
return vLks = links.filter(function(l) {
return l.source.id === pl.target.id;
});
});
d.size = (d.size + vLks.length) / 2 + 15;
return d.size;
}
});
enterNodes.filter(function(d) {
return d.type === 'topic';
}).append("text").attr({
"class": 'topic label',
dy: .35 + 'em'
}).text(function(d) {
return d.name;
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'topic';
}).selectAll('text').style({
'font-size': function(d) {
return Math.sqrt(d.size) * 2 + 'px';
}
});
enterNodes.filter(function(d) {
return d.type === 'proposal';
}).append('circle').attr({
"class": 'proposal'
}).style({
fill: scope._colorNode
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'proposal';
}).selectAll('circle').attr({
r: function(d) {
var pLks;
pLks = links.filter(function(l) {
return l.source.id === d.id;
});
d.size = pLks.length * 3 + 10;
return d.size;
}
});
enterNodes.filter(function(d) {
return d.type === 'proposal';
}).append("text").text(function(d) {
return d.name;
}).attr({
"class": 'proposal label',
dy: .35 + 'em'
}).on({
click: scope.collapseClick
});
scope.node.filter(function(d) {
return d.type === 'proposal';
}).selectAll('text').style({
'font-size': function(d) {
return Math.sqrt(d.size) * 2 + 'px';
}
});
enterNodes.filter(function(d) {
return d.type === 'voter';
}).append('image').attr({
'xlink:href': function(d) {
return 'http://graph.facebook.com/' + d.name + '/picture?';
},
x: -20,
y: -20,
width: 40,
height: 40
}).style({
'clip-path': 'url(#clip)'
});
enterNodes.filter(function(d) {
return d.type === 'voter';
}).append('circle').attr({
"class": 'voter-ring',
r: 15
}).style({
stroke: 'DarkOliveGreen ',
'stroke-width': '.75',
fill: 'none'
});
scope.link = scope.link.data(links, function(d) {
return d.target.id;
});
enterLinks = scope.link.enter().insert("svg:line", ".node").attr({
"class": 'link',
x1: function(d) {
return d.source.x;
},
y1: function(d) {
return d.source.y;
},
x2: function(d) {
return d.source.x;
},
y2: function(d) {
return d.source.x;
}
});
AnimatingExperiments(scope, enterNodes, scope.node, enterLinks, scope.link);
if (!scope.options.animateExit) {
console.log('no animate exit: ');
scope.node.exit().remove();
scope.node.exit().remove();
} else {
}
scope.node.exit().filter(function(d) {
return !d[fvID].isExitting;
}).each(function(d) {
d[fvID].isExitting = true;
return nodes.push(d);
}).interrupt().transition().duration(scope.options.animateExit.msToFade).style(scope.options.exitAnimateStyle).each('end', function(d) {
return delete d[fvID].isExitting;
}).remove();
scope.link.exit().remove();
return scope.force.nodes(nodes).links(links).start();
};
}
};
};
App.Directives.directive('forceChart', forceChart);
}).call(this);
// Generated by CoffeeScript 1.6.3
(function() {
var AnimatingExperiments, CollapsibleTree, CollapsibleTreeLoader, FlattenVotingTree, NodeEmitter,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
CollapsibleTree = function($resource) {
return $resource('z_collapsible.json');
};
CollapsibleTreeLoader = function(CollapsibleTree, $q) {
return function() {
var delay;
delay = $q.defer();
CollapsibleTree.get({}, function(root) {
return delay.resolve(root);
}, function() {
return delay.reject('Unable to locate CollapsibleTree ');
});
return delay.promise;
};
};
FlattenVotingTree = function() {
return function(scope, json) {
var i, l, links, nodes, recurse;
recurse = function(h) {
if (h.type === 'hub') {
if (!h.id) {
h.id = i++;
}
if (!h.hidden) {
h.hidden = false;
}
h.forceViewCharge = -900;
nodes.push(h);
if (h.children) {
return h.children.forEach(function(t) {
var link;
if (!t.id) {
t.id = i++;
}
if (!t.hidden) {
t.hidden = false;
}
t.hiddenParent = h.hidden;
t.forceViewCharge = -400;
nodes.push(t);
link = {
id: ++l,
source: h,
target: t,
linkDistance: 133
};
links.push(link);
if (t.children) {
return t.children.forEach(function(p) {
if (!p.id) {
p.id = i++;
}
if (!p.hidden) {
p.hidden = false;
}
if (t.hidden === true || t.hiddenParent === true) {
p.hiddenParent = true;
} else {
p.hiddenParent = false;
}
p.forceViewCharge = -200;
nodes.push(p);
link = {
id: ++l,
source: t,
target: p,
linkDistance: 100
};
links.push(link);
if (p.children) {
return p.children.forEach(function(v) {
v.type = 'voter';
v.topicVoterId = t.id + '-' + v.name;
v.parent = {};
if (!v.id) {
v.id = i++;
}
if (!v.hidden) {
v.hidden = false;
}
if (p.hidden === true || p.hiddenParent === true) {
v.hiddenParent = true;
} else {
v.hiddenParent = false;
}
v.forceViewCharge = -150;
nodes.push(v);
link = {
id: ++l,
source: p,
target: v,
topicVoterId: t.id + '-' + v.name,
linkDistance: 40
};
return links.push(link);
});
}
});
}
});
}
}
};
nodes = [];
links = [];
i = 0;
l = 0;
recurse(json);
scope.options.max = links.length + 1;
scope.flattenedNodesAndLinks = {
nodes: nodes,
links: links
};
return console.log("Initialized nodes And Links: ", scope.flattenedNodesAndLinks);
};
};
NodeEmitter = function() {
return function(scope) {
var i, l, links, linksBytopicVoterId, nodes, nodesAndLinks, targets, ts, uniqLinksByTopic;
ts = scope.options.currentNode;
nodesAndLinks = scope.flattenedNodesAndLinks;
links = nodesAndLinks.links.filter(function(l) {
return l.id < ts;
});
linksBytopicVoterId = _.chain(links).sortBy(['topicVoterId', 'id']).value();
uniqLinksByTopic = [];
i = 0;
l = links.length;
while (i < (l - 1)) {
if (linksBytopicVoterId[i + 1].topicVoterId && linksBytopicVoterId[i + 1].topicVoterId === linksBytopicVoterId[i].topicVoterId) {
if (linksBytopicVoterId[i + 1].hidden === void 0 && linksBytopicVoterId[i].hidden === void 0 && nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent) {
nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent.x = nodesAndLinks.nodes[linksBytopicVoterId[i].target.id].x;
nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent.y = nodesAndLinks.nodes[linksBytopicVoterId[i].target.id].y;
}
} else {
if (!(nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hidden === true || nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hiddenParent === true)) {
uniqLinksByTopic.push(linksBytopicVoterId[i]);
}
}
i++;
}
if (!(i === 0 || nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hidden === true || nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hiddenParent === true)) {
uniqLinksByTopic.push(linksBytopicVoterId[i]);
}
targets = _.chain(uniqLinksByTopic).pluck('target').pluck('id').value();
nodes = nodesAndLinks.nodes.filter(function(d) {
var _ref;
if (targets.length > 0) {
return (_ref = d.id, __indexOf.call(targets, _ref) >= 0) || d.id === 0;
} else if (ts > 0) {
return d.type === 'hub';
}
});
return scope.nodesAndLinks = {
nodes: nodes,
links: uniqLinksByTopic
};
};
};
AnimatingExperiments = function() {
return function(scope, enterNodes, nodes, enterLinks, links) {
var i;
i = 0;
return enterLinks.style({
stroke: "red",
opacity: 0
}).transition().delay(function(d) {
if (d) {
return (i++) * 50;
}
}).duration(0).each("end", function(d) {
d3.select("svg").selectAll('.voter-ring').data([d.target], function(d) {
return d.id;
}).style({
stroke: '#DC143C',
'stroke-width': '2',
opacity: .9
}).transition().duration(3500).style({
stroke: '#556B2F',
'stroke-width': '1'
}).transition().duration(250).style({
opacity: 1
});
return d3.select(this).style({
opacity: 1
}).transition().duration(750).style({
stroke: "#ddd",
opacity: 1
});
});
};
};
App.Services.factory('CollapsibleTree', CollapsibleTree);
App.Services.factory('CollapsibleTreeLoader', CollapsibleTreeLoader);
App.Services.factory('FlattenVotingTree', FlattenVotingTree);
App.Services.factory('NodeEmitter', NodeEmitter);
App.Services.factory('AnimatingExperiments', AnimatingExperiments);
}).call(this);
FireCtrl = ( $sce, $scope, $interval ) ->
$scope.options =
initialID: 1
width: 960 # 960 Bl.ocks Default
height: 440 # 600 Bl.ocks Default
exitAnimateStyle: #When nodes animate out of the force view, we animate them to these css params
opacity: 0
enterAnimateStyle: #Opposite state of the exitAnimateStyle
opacity: 1
animateExit:
msToFade: 750
enterAtParent: true
enterCenterJitter: 10
min: 0
currentNode: 0
headLabel: 'fa-play'
currentTs: undefined
sliderReset: true
radiusMeasure: 7
force:
charge: (n) ->
n.forceViewCharge or -200
linkDistance: (l) ->
l.linkDistance or 200
$scope.message = $sce.trustAsHtml('Press <b><em>Play</em></b> and <b><em>Pause</em></b> controls on left to start and stop,
or you may scrub the visualization using the <b><em>Slider</em></b>.')
$scope.hovered = (d) ->
if d is 'leave'
$scope.hover = 'Hover, click or Drag any Node to see more.'
else
$scope.hover = d.type.charAt(0).toUpperCase() + d.type.substr(1).toLowerCase() + ': ' +
switch
when d.type is 'voter' then d.name
when d.type is 'hub' then 'This would be your group'
else d.text
$scope.$apply()
timer = undefined
$scope.play = ->
$scope.message = null
$scope.hover = 'Hover, click or Drag any Node to see more.'
if angular.isDefined(timer)
$scope.pauseSlider()
else
$scope.options.headLabel = 'fa-pause'
forward = true
curVal = undefined
dir = 1
tick = ($scope.options.max - $scope.options.min) / 200
timer = $interval(->
curVal = Number($scope.options.currentNode) or $scope.options.min
#dir = -6 if curVal + tick > $scope.options.max # Logic to run the slider in reverse if you want it.
if curVal - tick < $scope.options.min
dir = 1
$scope.options.sliderReset = true
$scope.options.currentNode = curVal + dir * tick
$scope.pauseSlider() if curVal + tick > $scope.options.max
, 400) # must be larger than debounce!
$scope.pauseSlider = ->
if angular.isDefined(timer)
$interval.cancel timer
$scope.options.headLabel = 'fa-play'
timer = `undefined`
$scope.$on "$destroy", ->
$scope.pauseSlider()
window.App = angular.module('spokenvote', [ 'spokenvote.services', 'spokenvote.directives', 'ui.bootstrap' ])
App.Directives = angular.module('spokenvote.directives', [])
App.Services = angular.module('spokenvote.services', ['ngResource'])
App.controller 'FireCtrl', FireCtrl
forceChart = ( $compile, NodeEmitter, CollapsibleTreeLoader, FlattenVotingTree, AnimatingExperiments ) ->
restrict: "EA"
replace: true
scope:
options: '='
hovered: '&hovered'
link: (scope, element, attrs) ->
root = []
nodes = []
links = []
# Every force view gets its own ID. This is used to scope ForceView instance-specific state onto the node Objects
fvID = "_fv" + scope.options.initialID++
# Set default size
forceWidth = scope.options.width or angular.element(window)[0].innerWidth
forceHeight = scope.options.height or angular.element(window)[0].innerHeight * .7
scope._tick = ->
scope.link
.attr
x1: (d) ->
d.source.x
y1: (d) ->
d.source.y
x2: (d) ->
d.target.x
y2: (d) ->
d.target.y
scope.node
.attr
transform: (d) ->
"translate(" + d.x + "," + d.y + ")"
.exit()
.attr
cx: (d) ->
d.x
cy: (d) ->
d.y
scope._setSelectionRadius = (selection) ->
selection.attr "r", (d) ->
return scope.options.radiusMeasure or 7
scope._colorNode = (d) ->
if d.isDemo then "#82b446" else "steelblue"
# Toggle children on click.
scope.collapseClick = (d) ->
unless d3.event.defaultPrevented
d.hidden = !d.hidden
FlattenVotingTree scope, root
update()
window.onresize = ->
forceWidth = angular.element(window)[0].innerWidth unless scope.options.width
forceHeight = angular.element(window)[0].innerHeight unless scope.options.height
scope.force.size([ forceWidth, forceHeight ])
scope.visSvg
.selectAll('.node')
.remove()
scope.render() if nodes.length > 0
scope.visSvg = d3.select(element[0])
.append("svg")
.attr
width: forceWidth
height: forceHeight
scope.visSvg
.append("clipPath")
.attr("id", "clip")
.append("circle")
.attr
cx: 0
cy: 0
r: 15
scope.force = d3
.layout.force()
.size([ forceWidth, forceHeight ])
.linkDistance(scope.options.force.linkDistance)
.charge(scope.options.force.charge)
.linkStrength(.35)
.friction(.85)
.theta(.9)
.gravity(.06)
.on 'tick', scope._tick
CollapsibleTreeLoader().then (json) ->
root = json
FlattenVotingTree scope, root
scope.$watch 'options.currentNode', ->
update()
update = ->
NodeEmitter scope
if scope.nodesAndLinks
nodes = scope.nodesAndLinks.nodes if scope.nodesAndLinks.nodes
links = scope.nodesAndLinks.links if scope.nodesAndLinks.links
scope.render() if scope.nodesAndLinks.nodes.length > 0
scope.link = scope.visSvg
.selectAll("line.link")
scope.render = ->
if scope.options.sliderReset
scope.visSvg
.selectAll('.node')
.remove()
scope.options.sliderReset = false
if !nodes or nodes.length < 1
console.log "No nodes present."
return
scope.force
.nodes(nodes)
.links(links)
.start()
# -------------------
# Update the nodes...
scope.node = scope.visSvg
.selectAll("g.node")
.data nodes, (d) ->
d.id
.attr
"transform": (d) ->
"translate(" + d.x + "," + d.y + ")"
# If we're animating things out, they could be in the middle of their outbound animations. Animate them back in.
if scope.options.animateExit
scope.node.each (d) ->
delete d[fvID].isExitting
.interrupt()
.transition()
.duration( scope.options.animateExit.msToFade / 2 )
.style scope.options.enterAnimateStyle
# Some may have already exitted but now they're back in the game. Adjust their states.
enterNodes = scope.node
.enter()
.append('svg:g')
.each (d) ->
d[fvID] = {} unless d[fvID]
if scope.options.enterAtParent and d.parent and d.parent.x
d.x = d.px = d.parent.x
d.y = d.py = d.parent.y
else if scope.options.enterCenterJitter and d.type isnt 'hub' and scope.node[0][0].__data__.x
d.x = d.px = scope.node[0][0].__data__.x + 2 * scope.options.enterCenterJitter * Math.random() - scope.options.enterCenterJitter
d.y = d.py = scope.node[0][0].__data__.y + 2 * scope.options.enterCenterJitter * Math.random() - scope.options.enterCenterJitter
else if d.type is 'hub'
d.x = d.px = 50
d.y = d.py = 50
else
d.x = d.px = forceWidth / 2
d.y = d.py = forceHeight / 2
delete d[fvID].isExitting
.attr
id: (d) ->
d.id
class: 'node'
#'tooltip-append-to-body': true
#tooltip: (d) ->
#d.name
#.call ->
#$compile(this[0].parentNode)(scope)
#console.log 'compile: '
.call(scope._setSelectionRadius)
.call(scope.force.drag).filter (d) ->
not d.isDemo
.on
mouseover: (d) ->
scope.hovered args: d
mouseleave: ->
scope.hovered args: 'leave'
# append newly entering hub circles
enterNodes
.filter (d) ->
d.type is 'hub'
.append('circle')
.attr
class: 'hub'
.style
fill: 'DarkGray'
.on
click: scope.collapseClick
# adjust the all hub circles
scope.node
.filter (d) ->
d.type is 'hub'
.selectAll('circle')
.attr
r: (d) ->
d.size = nodes.length
d.size * .8 + 15
# newly entering hub labels
enterNodes
.filter (d) ->
d.type is 'hub'
.append("text")
.attr
class: 'hub label'
dy: .5 + 'em'
.text (d) ->
d.name
.on
click: scope.collapseClick
# adjust the all hub labels
scope.node
.filter (d) ->
d.type is 'hub'
.selectAll('text')
.style
'font-size': (d) ->
d.size * .4 + 5 + 'px'
color: 'black'
# append newly entering topic circles
enterNodes
.filter (d) ->
d.type is 'topic'
.append('circle')
.attr
class: 'topic'
.style
fill: 'Chocolate'
.on
click: scope.collapseClick
# adjust the all topic circles
scope.node
.filter (d) ->
d.type is 'topic'
.selectAll('circle')
.attr
r: (d) ->
pLks = links.filter (l) ->
l.source.id is d.id
d.size = pLks.length
vLks = []
pLks.forEach (pl) ->
vLks = links.filter (l) ->
l.source.id is pl.target.id
d.size = (d.size + vLks.length) / 2 + 15
d.size
# newly entering topic labels
enterNodes
.filter (d) ->
d.type is 'topic'
.append("text")
.attr
class: 'topic label'
dy: .35 + 'em'
.text (d) ->
d.name
.on
click: scope.collapseClick
# adjust the all topic labels
scope.node
.filter (d) ->
d.type is 'topic'
.selectAll('text')
.style
'font-size': (d) ->
Math.sqrt(d.size) * 2 + 'px'
# append newly entering proposal circles
enterNodes
.filter (d) ->
d.type is 'proposal'
.append('circle')
.attr
class: 'proposal'
.style
fill: scope._colorNode
.on
click: scope.collapseClick
# adjust the all proposal circles
scope.node
.filter (d) ->
d.type is 'proposal'
.selectAll('circle')
.attr
r: (d) ->
pLks = links.filter (l) ->
l.source.id is d.id
d.size = pLks.length * 3 + 10
d.size
# append newly entering proposal labels
enterNodes
.filter (d) ->
d.type is 'proposal'
.append("text")
.text (d) ->
d.name
.attr
class: 'proposal label'
dy: .35 + 'em'
.on
click: scope.collapseClick
# adjust the all proposal labels
scope.node
.filter (d) ->
d.type is 'proposal'
.selectAll('text')
.style
'font-size': (d) ->
Math.sqrt(d.size) * 2 + 'px'
#voter
enterNodes
.filter (d) ->
d.type is 'voter'
.append('image')
.attr
'xlink:href': (d) ->
'http://graph.facebook.com/' + d.name + '/picture?'
x: -20
y: -20
width: 40
height: 40
.style
'clip-path': 'url(#clip)'
#voter ring
enterNodes
.filter (d) ->
d.type is 'voter'
.append('circle')
.attr
class: 'voter-ring'
r: 15
.style
stroke: 'DarkOliveGreen '
'stroke-width': '.75'
fill: 'none'
# -------------------
# Update the links...
scope.link = scope.link
.data links, (d) ->
d.target.id
# Enter any new links.
enterLinks = scope.link
.enter()
.insert( "svg:line", ".node" )
.attr
class: 'link'
x1: (d) ->
d.source.x
y1: (d) ->
d.source.y
x2: (d) ->
d.source.x
y2: (d) ->
d.source.x
# ------------------
AnimatingExperiments scope, enterNodes, scope.node, enterLinks, scope.link
# ------------------
# Exits
# Exit any old nodes.
unless scope.options.animateExit
console.log 'no animate exit: '
scope.node.exit().remove()
scope.node.exit().remove()
else
# Some exit nodes may have already started the exit animation. Let them be, they'll be removed.
# They're in the exit selection because they weren't in the list of nodes.
# However, we still want them as part of the force view until they leave for sure.
scope.node
.exit()
.filter (d) -> # remove the els when transition is done
not d[fvID].isExitting
.each (d) ->
d[fvID].isExitting = true
nodes.push d
.interrupt()
.transition()
.duration(scope.options.animateExit.msToFade)
.style(scope.options.exitAnimateStyle)
.each 'end', (d) ->
delete d[fvID].isExitting
.remove()
# Exit any old links.
scope.link.exit().remove()
scope.force
.nodes(nodes)
.links(links)
.start()
App.Directives.directive 'forceChart', forceChart
.hub, .topic, .proposal {
cursor: pointer;
}
line.link {
fill: none;
stroke: #ddd; /*#9ecae1;*/
stroke-width: 1.5px;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
body {
font: 14px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis path{
fill: none;
stroke: none;
}
.bar {
fill: steelblue;
}
.label {
text-anchor: middle;
font-size: .6em;
}
.box {
width: 945px;
margin-left: 10px;
/*background-color: #F8F8FF;*/
border-radius: 6px;
height: 40px;
line-height: 40px;
text-align: center;
}
.text {
display: inline-block;
vertical-align: middle;
line-height: normal;
margin: 0;
}
.play {
font-weight: bold;
vertical-align: middle;
}
.block .play {
display: inline-block;
width: 42px;
text-align: right;
padding-right: 7px;
}
.block input {
display: inline-block;
width: 895px;
vertical-align: middle;
}
.fa-pause {
color: darkred;
}
<!DOCTYPE html>
<html ng-app="spokenvote">
<head>
<meta charset="utf-8" />
<title>Vote Forking in Spokenvote</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" href="fire.css"/>
<script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="d3@*" data-semver="3.4.6" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js"></script>
<script data-require="angular.js@*" data-semver="1.2.9" src="http://code.angularjs.org/1.2.9/angular.js"></script>
<script data-require="angular-resource@*" data-semver="1.2.9" src="http://code.angularjs.org/1.2.9/angular-resource.js"></script>
<script data-require="lodash.js@*" data-semver="2.4.1" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script data-require="ui-bootstrap@*" data-semver="0.10.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
<script src="README.controller.js"></script> <!-- README prefix hides files on Bl.ocks.org -->
<script src="README.directive.js"></script>
<script src="README.services.js"></script>
</head>
<body>
<!--<body class="well">-->
<div ng-controller="FireCtrl">
<div style="width: 85%;">
<div style="width: 960px;">
<force-chart options='options' hovered='hovered(args)' ></force-chart>
<div class="form block" >
<a href='#' class="play" ng-click='play()' tooltip-placement='right' tooltip='Click to start and stop the conversation, or use the slider to scrub the timeline.'>
<i class="fa {{ options.headLabel }} fa-lg"></i>
</a>
<input type="range" ng-model="options.currentNode" min='0' max='78' >
</div>
<div class="box">
<h4 class='text' ng-show='hover'> {{ hover }}</h4>
<h4 class='text' ng-show='message' ng-bind-html='message' ></h4>
</div>
</div>
</div>
</div>
</body>
</html>
CollapsibleTree = ($resource) ->
$resource 'z_collapsible.json'
CollapsibleTreeLoader = (CollapsibleTree, $q) ->
->
delay = $q.defer()
CollapsibleTree.get {}
, (root) ->
# Returns a list of all nodes under the root.
delay.resolve root
, ->
delay.reject 'Unable to locate CollapsibleTree '
delay.promise
FlattenVotingTree = ->
( scope, json ) ->
recurse = (h) ->
if h.type is 'hub'
h.id = i++ unless h.id
h.hidden = false unless h.hidden
h.forceViewCharge = -900
nodes.push h
if h.children
h.children.forEach (t) ->
t.id = i++ unless t.id
t.hidden = false unless t.hidden
t.hiddenParent = h.hidden
t.forceViewCharge = -400
nodes.push t
link =
id: ++l
source: h
target: t
linkDistance: 133
links.push link
if t.children
t.children.forEach (p) ->
p.id = i++ unless p.id
p.hidden = false unless p.hidden
if t.hidden is true or t.hiddenParent is true
p.hiddenParent = true
else
p.hiddenParent = false
p.forceViewCharge = -200
nodes.push p
link =
id: ++l
source: t
target: p
linkDistance: 100
links.push link
if p.children
p.children.forEach (v) ->
v.type = 'voter'
v.topicVoterId = t.id + '-' + v.name
v.parent = {}
v.id = i++ unless v.id
v.hidden = false unless v.hidden
if p.hidden is true or p.hiddenParent is true
v.hiddenParent = true
else
v.hiddenParent = false
v.forceViewCharge = -150
nodes.push v
link =
id: ++l
source: p
target: v
topicVoterId: t.id + '-' + v.name
linkDistance: 40
links.push link
nodes = []
links = []
i = 0
l = 0
recurse json
scope.options.max = links.length + 1
scope.flattenedNodesAndLinks =
nodes: nodes
links: links
console.log "Initialized nodes And Links: ", scope.flattenedNodesAndLinks
NodeEmitter = ->
( scope ) ->
ts = scope.options.currentNode
nodesAndLinks = scope.flattenedNodesAndLinks
links = nodesAndLinks.links.filter (l) ->
l.id < ts
linksBytopicVoterId = _.chain(links)
.sortBy(['topicVoterId', 'id'])
.value()
uniqLinksByTopic = []
i = 0
l = links.length
while i < (l - 1)
if linksBytopicVoterId[i + 1].topicVoterId and linksBytopicVoterId[i + 1].topicVoterId is linksBytopicVoterId[i].topicVoterId
if linksBytopicVoterId[i + 1].hidden is undefined and linksBytopicVoterId[i].hidden is undefined and nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent
nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent.x = nodesAndLinks.nodes[linksBytopicVoterId[i].target.id].x
nodesAndLinks.nodes[linksBytopicVoterId[i + 1].target.id].parent.y = nodesAndLinks.nodes[linksBytopicVoterId[i].target.id].y
else
unless nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hidden is true or nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hiddenParent is true
uniqLinksByTopic.push linksBytopicVoterId[i]
i++
unless i is 0 or nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hidden is true or nodesAndLinks.nodes[linksBytopicVoterId[i].source.id].hiddenParent is true
uniqLinksByTopic.push linksBytopicVoterId[i]
targets = _.chain(uniqLinksByTopic).pluck('target').pluck('id').value()
nodes =
nodesAndLinks.nodes.filter (d) ->
if targets.length > 0
d.id in targets or d.id is 0
else if ts > 0
d.type is 'hub'
scope.nodesAndLinks =
nodes: nodes
links: uniqLinksByTopic
# experiments in animating
AnimatingExperiments = ->
(scope, enterNodes, nodes, enterLinks, links) ->
# ANIMATE NEW LINKS:
# All new links: three step animation
# 1) Initialize new links to red/transparent
# 2) Transition, each with its staggered delay (but 0 transition length... just want the delay)
# 3) When these end, suddenly make transparent, then create a new transition that fades in
# (Note that transition.transition() doesn't work when the first transition is delayed... overrides it)
i = 0
enterLinks
.style
stroke: "red"
opacity: 0
.transition().delay (d) ->
# In the enter selection, some elements are undefined. Don't want to use argument[1] as i b/c it still
# counts the undefineds. Make our own i counter to get accurate "this is the i-th entering item" counts
(i++) * 50 if d
.duration( 0 )
.each "end", (d) ->
d3.select( "svg" )
.selectAll( '.voter-ring' )
.data [ d.target ], (d) ->
d.id
.style
stroke: '#DC143C'
'stroke-width': '2'
opacity: .9
.transition()
.duration( 3500 )
.style
stroke: '#556B2F'
'stroke-width': '1'
.transition()
.duration( 250 )
.style
opacity: 1
d3.select( this )
.style
opacity: 1
.transition()
.duration( 750 )
.style
stroke: "#ddd"
opacity: 1
#.transition().each (d) -> # My force charges pretty good, but could expiriment with this method later
#d.source.nodeForceViewCharge = -1600
#scope.force.start() # restart force view to make attractor change stick
App.Services.factory 'CollapsibleTree', CollapsibleTree
App.Services.factory 'CollapsibleTreeLoader', CollapsibleTreeLoader
App.Services.factory 'FlattenVotingTree', FlattenVotingTree
App.Services.factory 'NodeEmitter', NodeEmitter
App.Services.factory 'AnimatingExperiments', AnimatingExperiments
�PNG

IHDR�xid�
�iCCPICC ProfileH ��wT�����Ko��H'�&��^(��JH %�@�+�
��!�"
��� ,,�
�� �(��b����K���������>�Ν;w��=�@�d�D��q��#6.��{ p��
�9�"���`��}/���wͥ����O(ry��Pd:����@�sD�P|D�[�#�r)�41 ��2È=�%��i��po�f<���@EtF.'�C�#l%�
�3v���\������)�Z�����'��f'�|��)2�9 ���G�-Jg�O���侦�2���p䫂�YuZf���I Bfur�Y�K�f������Z.�'h�%iQ���#��� �9���p�a����cɘ��1�' �X�\�����\A�Y�N���P����bI�,�d�����ʿ�尿�Ï �չ<�Y� �d�r�d~D���{:~^��L�΍���G��Tv���NۋrBew|�/F~ `��p1�����w�w�(_,H��0<�L�1XB��\����Ҽ����?�O���w-Y�a ��]�]@=�o�����
��h����sg� ���T������<��A�q`1�>�b�,k@([�P ���08N�fp\W�Mp�~0F� 0ރI�p�B��6d�A6r�|�`(���HI���:�*�*��P�3t�]����4��>�(� �`M�����'G‹�8 .� �Mp\�����M��_�(�"��(�9���F���Q�(1j%�U��A5�ZQ���A�K�'4ME3��ht:
�Ag�W�Kѕ���&�e�]�z� C�h`�0�&��Y�)”cbNc�`z0#��X,��5�:b�q�T�2l)v7�ۆ��c'p8�*� � ��q9�"�.�Q����#���������x!~-�� ?IP � !.!���PKh%�"�&��D#�+1��J\C� 6��oI$�.ɉF�V�*H�I�HC�Od%�)ٛ�@��7�����o)�!ŃOɡl��Q.QS>�Q�,�Xr\�UrUrMrw�^�� �=��ȗ˟��%�R��`���VX�P�pF�OaB��h����X�xD��N�P�W��T�t@��0EգzS9�u�Z�� K3��h���1Zm\YI�N9Z9O�J�� E7��������^��9�s<���l��0�Μ*�**<�b�F��Ϫ U_�4խ�ͪ���j�jajK���]Q{�NSwQ���P�k�j�k,�8�ѩ1����)�ܥyI�]�C+Uk��y�1m����@{���� e�'#�Q������ Б����ҙ�5ҍ�]�ۨ�H����K�ۮ׮7���?_�~��C�Ӏo�Ӡ�����a��z�f�Q##�Q�Q�р1���8˸�� քi�f���)ljo�7�2�e�9� �v�u���u�+�[3�Ϝl�i�k^o>dA��Xk�l��R�2�r�e��7+{�t�Z�~k%�@�֭�olLm86U6�l)�~��l[l_ۙ�����ݷ��Ϸ_o�n����A���0���X��Ǥ1C���kN'/�UNg�>9;8�8�p����%����<�y�y��]u]ٮ�]�n�n���u���5�O<�<�=�y�x�z�|�e�%�:�����{�w���ߧا�W�7ʷ�����_�_�߸���2��L@P�ր>�&�êc�:��D�� zl,n����m�����! ��-�Q�QhV�/aذа��������;"�K"�D�����e%�j���N�����S3k�"�f�Z� �%0~b��� G��z-�[t}�������/a/9��I�I<��®aO$�����9ޜ��\�v�ϕW�{��\�<�⚲-e���/�x *�SR��~H I;�6��ޘ��H�8#T� /gje�ev��DE��,�Y�� ��l({QvK )p:%ƒ$C�n�U��F/=���'���7�ߘ�����e�e�e��u��Y>��s����ʤ���V�Y���⚴5���Z[��ݺ�u����� �����H�H\Է�e�� � � ]m7���[|�Ī���K)��Ə�?V�8�)yS�f��{�`���nu�z�L���lx��mM�ۋ��۱d��r��;�;%;+�+Zv��ڲ�K%���ʫ��Z�zc�����w�x�iث��d��}�}����o�1�)?�=�{�imtm�O̟��,9��������×���h�\�K�ǎ&�}��XK�y��Fzc�qp\r��ω?��:�~�y���������MPS~�x3�y�%���L���V��ӿX�r��٪s��6�'�/<?u���D����Ŕ���K��/�^�w9�rו�+׮�]����q�뵳ם������|��fS�}��_�=����t��V�m�ۭ����q�s��ݫ�X�n�,����ߗ�7x�{�A��sN��� ?RxT�X�q�o&�5: ���|��3����߿�>�<-��n�f������ �����|Y��կ�_������������SoJߪ�=���]�D�����'?T�x��S����&�~�}��j��[з����)[̞�P�''#5�!(qPo@�����-��Za��.���gjg�RC�m� =�ի0@:�@d�mmeQ�-;��f 2R;c�SSo����Ugjj�����v�~����L=.�V8��@t�U[��������׼7� pHYs  ��diTXtXML:com.adobe.xmp<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
xmlns:exif="http://ns.adobe.com/exif/1.0/">
<photoshop:DateCreated>2014-08-19T12:48:14</photoshop:DateCreated>
<photoshop:Instructions>gjome6YuQBi9yNCSpijoNw</photoshop:Instructions>
<xmp:ModifyDate>2014-08-19T12:48:14</xmp:ModifyDate>
<xmp:CreatorTool>iPhoto 9.5.1</xmp:CreatorTool>
<xmp:CreateDate>2014-08-19T12:48:14</xmp:CreateDate>
<tiff:Orientation>1</tiff:Orientation>
<tiff:ResolutionUnit>2</tiff:ResolutionUnit>
<tiff:YResolution>72</tiff:YResolution>
<tiff:XResolution>72</tiff:XResolution>
<exif:PixelXDimension>230</exif:PixelXDimension>
<exif:PixelYDimension>120</exif:PixelYDimension>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
���@IDATx��]Gu���e�{�k�v�%K�������`0ء�$�B !!��J ��bz�� 0��ے�$˲zYi%m������̽w߮��J+-�G���Ν9s��Μ)w��P(���v� 2rF>շg�_��a�����б�+W���,���nlZU���4���9�\��;��3>��4�7:=�T:�t:]'����B�p܆3�MC�c-�o\�\[m�B�E�����:.��y;W�[�b�c������b�ꙺ��%�saI����K5:���{��>�{�O:�������W��z�ߛ�e\.�&�Ad���cdz��'�zOg�XyE����dS.�G"���w��u/�ț��Dֆ3�u"1���r�+��)�wc�T��G�ž�I��U�����я~tƉ��Б�;���zz����~��NTE�˖.O�{����~]?�i݆˺��"Q��n
���)x%a�����*����l6�t����pA���JX�<��>_<���رu{]uÊƨ_r*� <�OX�9E�`��u'���D�r*�%�)���D��ʥ<�Ǽ����~�������n{�^r}i�_ZV������/�|x��r;P��0����ڏN�U�σ\6��r� �l:�tTV��۳3;۸f��0ܦ<�N�Qs �ʼn�%�+y�J�P�I�v
�<3'miV��)-L�A_�hk9�PR��5k�VW-�����9�֟H;��w��'��R�����N�����t<�so��*�C��\N�K�'�Et�B>�"�3��z\�t�QѰ��-Ϗ�EU� �zr
eU-������w>���;F�� �J����S"q�c�a�Et��WXl���������W-o�:��o�4��^�~���凟ݺEz��S��邑soٳuok�z~: D3N��ҖA,2��Tr���?yt�c{���!�C�nG�ßHU�]A%}T�P�F��5�>A�H�V`�4�N<� ��f�;��WW�{z������X���C��W\���|�g?��W��vZ�t)hY`딮��}-%��B6O�����d2" �{�] $�_�\�˝����{�뛷���6�� g�v=�g?�Kdž�ۖ._*��t� W�p��ᓬ��b��+��RW%��ҠPi��<y��'��\��{�eƺz%%c��X_w����˟۱u�˝?T����9fl~vO]]3`�QG.W6� �<�l&�˸��|.�$����lޓ��a�U@R4
hU:�[��@�(Z�l��Uʹ�E�f�Vhv�וB
z����C�'���$�wddlxxxե+~���ޮx268:8�M Ѭ���[NtGCaO>�ɥ#}��!�����!f�9���Ń��M�ecH����y�� ��`#�5�胿ٴ~ci!�����菗Ϋi���o>�/�Kw��b4� �KN�J�@���0@s�xf~�����Nz���� ��>��EMC}=]�=9#��&��t:���i���)��#}��eFz=F�H'r�ݘ�t<�ll$�F���� �wz����Ƣ�Q6-'O�&��R��N�k�X�Z*�9\f]���m���Hفᱵ�/�jݻ�`scs2��,��h+) TVV��B"I7�����c��X��(q�L:����2���H$�Je����30PYY�q����Y,[x�jQ�F.�J��.
M�v���_~����-����}~W�$��r����C+W����A7=#uuR�Ť&[��G0���Iw\(��6m9P:o^rd�D�x!�ˤbyi4���c�c�1*"�H������7�)T���=-{����D�+0���x6��WW��=���M�6��C�#�X,nDC.�J��#�D`e��&e�E��,�+q���9Jg�!��E*�bjҕ/Z����T_:�{���ɴ���9܎���C�����Q[[O�J�A)���B%�B[4_@����ޮ���^��ѧ.�H<�.$k�j�*+���2�9\�d&��9��n���Gddq͕��{:�����v��d3�~�����+/������i%����or����)�eg���]�ѲO�����t�/��=�X���V����w���i�¥P�|���"o��F�$Ā ��]�E����|.��u?��f�DJ3�lIi4K|��ty]7H�
@^�yx!TCb���=�J1tɤ u���J�J��y5πAr�˜u�b�*.���������M�$���•�c�>��O>��[���;^�"���nș���� ���g].����khl�??-g�e��/����bu�JK�1�dmm��� r�d&��y�Fr8�k�.�r4�t<V_�8:2t�`�/\�X]�s붱��HY�����c�s�y���j��%��8�����1�O�p�������J"۞��?~��2���ШnW&�-��vbʃ-G!]]M&��Uu�g�ƍ"�IU���WD"36�)��cdz����t���**\.0���H��j�@T� �^��(emF�\"�Y�WP�dPp�\�q����Ŀ���3��,��������7�F�9�Q=• L�H40�ʢ�݉t�� ��.Kg��Z�`�a��Ձ�?�� V�u�=D�sd���ںp��
F�==i�6�wuu ��4���jj^�9���7�)���Țz}@T�̅;+)Qj���ˬ����w���/���dz,��i�j������^}�F4��R�Q_�^PW~d,�,�22]"#�/P6/X`�/�gΑ��<cM ��������zA��� u��<����ȯ��WTWV/�of�/��2� �0�X�L��$�'�d�7���u���oT�ҕ+��sw������}�س��
�XE�A���S��+�p�o��`L��^��t.GG^��|���,����l�@�liз����B�'ϼ�KV�������vxׯ/���L<��9���� �_
E$k�1MC���X� � UI�E�9ǵ/��ǿ��{���ή�xz$�_�~����?���M��*�Z��
�]������v)�*4y� �v"E�j02�\9;����7^~{e��Lf�FG�>o>;z�hOG����=|�Y �O���{��Q��������_D�� =$��A����CV���V�y񹂁КK�a�)i��U��8�n5��{a���ҥ��Φs~�����ٺ�$@�������PY1��nG�� ��^�vUC�OzA�E����ȪW��ٳo��yU��c�Ν�5UG:�v����ns� Ui"��!17|�5"�j�Z��s�`,�t�_�����up`8RZ^>���������X�Jҁ���(�˛�\��Σ�Ot���#I7�UW��2#�@���o{� W. Q.o��3�frǎw1�9о�@�?��GB�| ���[�_�X��pˏ��߻��u�\kxd(a�Ϟ�(g�V@��\�V��T��� -�E
���bكE��1�@7? 1 cYc�57_�}x���5菰�^�u`* �xԪX�޿�-�v�v�g3BBy��|�{��Ճ��$F0�6<؟ʹ��<�����[U]�2�iA��r�!�W��)"WF�pd��5�]uݲ��V�W�)�Q�r��5E�'��k��-���+�8����v9r������\���?j�_yU��I���7����Jc�< M�^���2��ܴv�w�Y_����N �Bn�K�sp��` k��'k�`V�&�2m��d�YJ"ʖ?��!*�EEѼ�c�@ne�HoO���`ye6��
+��g���e3n��k���%�V�A�l�V�X�|�����uI%�����G+�����������1z���$s���^l'}�jU—��� ���3rK�E��t2���(����(B�����†��]�쑖C��c�C�D<624��Q�˿���~ۦJ�!%1t��b��#9:zt�_�� ����|x������Ã}c�ܯ�o�ʽ����7�X�B 8aItҹ TT��V�t�+&�eNJ0 ��q+�P,PΞ8zd�3Ouw���5��n�� �M� �;�̌���hi۠�/_�w��c������҉�_Y���I�F::��䍯y�K�Ÿ`�'�V ��]ǎ;�=0�ί�aA�0� �8kw�j
0����z&�\`�L*Ť�6�F�!A�F���*�cҫt2�HO�BF Ə'�86��0]�<ncMŪ�u�� 7f}!�u[[jh$22q� l{��mO�������t�3�ܸ�ᱧ���1�����֬[O^8s��� ��.�o���HM�
�����_�Q�G~�S����`h~mӼ��ͻ�m{����yNJ��W4\�E�Ta����x�g�oO:��P�y ش�Lldxd�{ES����7ll��Y��2�.�����㺫kU��7�+_GP@� �����4X��ԕђp�T�n�+��y�+@�r9�jM,E�L����Mj��X�XZ�S� �XU��a�)^�j$jAp8��*�z�ե��3n8�����Kڼ�����'�V,%�\N�\V��Q�.n����N<��5 �'DxV��G~���}���������n�<��_�3�����wl��� �]twN�6�`ˑ�ӻ>z���?��1��M�5+/Y|���a�'���zIr!ge�Q���RY��0,��r�&����t� �ʗϳ�B؎��WL�p�.�����Q�v�� ��E$/�|"#V��'���� �Ӣ��b�O���&��$z�;���o�_��==#�UM�l�b�%����z��G�nnnZ��Ψ�Dt��*�].dM�,��+*A0=����|���������P�� ����Ԗ'~U��������Z-\��|�x�_,a����FG�5X]Q)u�O���p��Ujg:�T*���tR^��g��Te�����upp0��ԴζoO�2��?�租��'w��]S^�ƻ�i�w�[^_U_k�+dj|�(�\NEj�a�n���?�B�1���l�j�Dw���_�b㶭O�;^W[[RR:�78444����Q]; ϳ��2\�b��1�\]�H��튒q
t����J5���D�ɝ���O&���,'A'�NcM�Ŵ���_��7^���{13***k�7�:�L�]l_�1|��1�?��O�D-;<�H����Pat�W�f�����pp���ҵ�A���`-���)�,�ͫ�:,���嗩Be{(����x�/�N+�Q�@Vf���5����꺆�y U-���Nѫ�u��{�
��Ť��fqR��
�&�.�Ti��v¼j��oX�n8���x���•Ob�=C�"G��m!�)��X�B�W�E�Z���/�%%2�:-'��T� �T�� +@�5��[�͚��SE�u�j���'tObȂ[�Q^]�+-���,��)����r82Nv�����co����20�!���ʖB�?�����`U
\���ej��&�L�,5B��M�uL�( MlV �<U 0m���s�X`t�x�� �Uy(D��o�x��{Nt���ͥ� �փ�x<�s��[�x]IU5�d ?�i)�~G��6�@-nB�oN%�b)a\��u�?U�ӆ�� �>�*eZA,6�^��z�S��:�u-+�2��[JB���w�M�����K�<��� <.��;����e7��B��Ⱥ��SH)<�#�)^�[�����$�!�*��jCy*�Tu+� ]��W�G����f���Sb�ԑ.�$��8�i< Ā�T��cIg���u�h���-Zl��j�Y��,e�9$"���A�
�*���!dT|��Eߩ$�e�� �`0Ȗ�SE�R��״�J*������ٹ��BAc@�� ��$�%\ڦ���^e���4(��Y7Q����s���"����pii�n�*��˔$`7o^�X�xFvJ�u�q������������6{V����rŨ�)`t9����)`� vxeK�J�r�-XR��΃h��3x��m��x�ɾ��99թBL����
# +�!�n��SU�0c��SU�[����X���N��E�:)
Î�g��v���m�N1��QARGŎ�Z����f�u-���v�55�l��INIdP吽T�T�z-V�H�� �E,�S�x��LX3�ş�H@�Z���e���ǝuȞ̢�`ai[�̎p��(��������I��
��b�Oz���%���f>����*�Z��A��������CV�pr�d�*�R�*�D�y[���r1�� �!k�f��N���t�^��Y]ũ!&8俨OV[EZSW�
�)��JT�)&�<� LM����v/��K���tA �~R3��:S�v=�P�0�|����Ɵ�O��A�5zz�Ũ#>Xe,�O����N�e��U��N����'�_�ӆ,�� Y̺�5� S[$,�0g5�"yI�Ԫ �A�W����J��jq�}+�a���%*�n,Vv*�����j��H�P��C�%����2M�aR����p��s:�Q�L��������{Ak��� �-ݜ�T�Ss˴��yP��z�=�3��<j�9kvf���n�
er@�hɉ3`|>�۴eu�-� �e�&��R�":A��%欄(
j�;�Wޮ�XC���g�.����VrV��3�6�����J�J,H����G&gx׍6�˻��LCJ��Uܹ+��Y-'%8��jU�������CՅ
�� ��Z{e��j�����zĠ[8�G;s�ݍr��B�� ���ѳ� :V�(5'kMd��e�����r�� ii
�z�A��,�S�3\�ZDS��_q�R� �/kt1��0m�.����( s,��\��9/�9�e'��gBP͕�j`���T�/9���B��*u�j@���ʘP��u##*�k ���۲��_{�1�>�ȸ�euKV]yS�U7;|��=���|�> t.�N�s����}[ �xU/��#�I&�9�KR!ȴLa�C����������l�8����H�s�a�� p��Û��C�����_�#R�w�f� ��}.sN�*�`UP�pLZ�{�T�j�|8��;ܟI�e_�p�8kR�E[����^�α,�|r)c��߹;q|ϲ�@>�a��l.Ù%��!��#��éf�x˞{�c�r���Ք��@s�ە2b��{������JJ���_{�c�u��Df!�L��T|%Z��3��ԓN�4�)�G���y������j��~N*�����q�)��fKj��qæ�Mk��lV��#��Y ���*z�t��.�N��=��_?���Q_�ĝ�3 �u<��3��撗�a�mw9J*BU� �LޞϺ�a��ڷxp2?�b���H���v.L�BS��W��b�Y�c��Gz��Q�Pb� ��x3��M��>�Jq�y��~�@c�
��Y�sڢ�s��f^-][�Z&��BX��m������������cg��!��!_�ӳ��_��F���nG�JL_U��
�� 62lp؈)~dGց��MF<�bΘ9� �h�9����`'G�v�b|�㾐�%^#������n}����~lh��� $9����%ϥ��L�SWT�OK�=���=[� ��B*�]�JGE�ңFbpU}h��?��$_�0��JB#A&���� J4P�Z���#����ϝ��͆Έ�f ���l8����4�33�y}��+*�>?�����7紬)3�>q�l�~Ք+��w��r_c�#�cV��ޠw;�Y�d��|a%Up�y�W�,_iD�Nup8�V�9? ��4P����~��$�_��q:3��tZ;#��w0XMy�A��R,�D�ᐯ�x ��ގ+V7qD*�հ�|Jife9s��Y�5�h��#��"�3�a���ў���V_8��U]NL�c��\_�X|$�?d���:9*Y�����[Ǣg�N��&? ˕GUv8�
G��AV��i�/.��D����'�l/s;}�/�� �B6� �2ՕF�^eC3��(��Q�SИ[��AkK��J}2�*������|:�y�)g�{0ul�-�NNܬ��8 �E˖��ybk�-7W)z:�uԂ���zu缡V�B��h���� ����a7*�F�>�k>������0�4�l�)J3��t �D��U����y�`e����ھm�kgc�K�er��9:��g����ɵ��>����c�ͼ0gLy!{^tD��(���Z�c �++��t�h�g {�Q�$��5|@�!���a�.t��,
HU����!k�@�o�>>��9H� U���a}��!�lhhX�dIUU��3�x���+1��M#�,��B8�Dto>c�5������i�,+-e��G�la$���6n�i�U�p���u�dt�� �f�&��` �R�(!�~h���(�-��y5�'R E���^U�Xŝȁ�I=���'�:N#VS�:
�����:�d�.+u�� ʌ`sMtaM���¾y���w.���4�u9¹LΕʤ\9�W�#ï�鐉�Ҭ��j�Ԛ�����>|�`���1�ƹ��v����$�`��&H��p��lG(f�@0�K$�EY��c˶�J��l]~c��W�ſ�~�ޖmO�kd�t��b�[_�|�+���Ѫje3`gtʬ�S�]W�uk&���}��U˱L;3����9 ���"�Kly.�Cʣ.f
�c/؎�H'Q�����F����lAQ{�ռ�d%
L���� Y+\g����r&��s%ª�"�ȓ�Q�ʟ��%/>�G#�oy������
�1%���R�q��;�#�+^�� ��9*G�6 g�f�ҭ�-H�ŕj�s��9]L�+�m˖-��,l U�¤�)��� ��M\[[{�UWa'hԞ���9�D' �::���vv*�R
+���Y,̌�-��|��� ��y�'�o���hЇ�I�l��<&d��Y{A�{_��ƕ0%�=�r��`�$�`�����C
1
%�+E��U {�Px2�<����![�իv68�)"j�TZ�R�[��-��:rR۲�xK�<B����B�#D�ٟ�x族~�3˫��p���s��$�|l L泞C��W}�S��W�x[px2>����p��{�@4�P�.�j�ˆ��6�Qp��"tk�K?�p?ȣ�uL}�LEeD����.���X(z�K^�I-�������O���Z't)�h''�e��4)U�,�w��?���X��[c5>��D�l'�csU8�/�P��jd� F5� "zKIV�u�)�� S����)4���I%�: 1-U��@��'>�Q���܅枹hQl�*v�b:�"
�4/��O�?�x�is�" JU"��L:�h�������d_�O����j���Y�lG�"`q:F�ٞ��w| p�yG���>S}�����9uQ��n�r�k�Q���Y��1�U���G}���%abRID���
:���4^��e���t�M�3hU�8D!2"$�V��ιj�xD�q�N���TQ�_Bd�f%-0��@Bө$ ������O"<)�dV�d�8�
������ ԌށO#�p�
��/����t�s�!��<T�j�(~N��D70��v�����o]mC����T�>��5�PSA �[%*+ �� )�S�#��z�J�a����p�o��V��@�#?}�W?t���4� �o,gj\~��o�����q�=4�����3J�:s���8�~���P�
fR=qk�<۶m۵k��� 83�� )��4Έ�s�Ɏ�566^{��HL"`hA� P�S�ո��TA|�u� *�Y/��jP�O<ʇL�h��a��36 !�(J�
, ��^�G��w��@A$� z�Ąt�� )},1��OO��BhS>;������J�������׾�/|����_��_��;����N���&%i����i�AV�Jj�N|��W�k��������BR J�E+�:�1�w<�%=�G_F��K��� K
���O#�o6�ǩx��2��:�/ �0��U*�8»��z�! S�r ���[��������$䖌�.0j.\hG�(T�!f�
NnK�������p-o�N�*����G��hj��C���y~-�kZ'�*�* Q)*/�B���I6Z�`��N~p����G�g����\�:ZYIi0N�x�A ?*�R�B�t
��&U*ʙ��BwO�׾���?��u�u�uvv?�w�c�k������&i��,�LQ��+Pmh`����������J�*p��d�$���D����4���U`J[ͥ��!#�^��ƙ���fZ�Ҍ�f����d;�l��V�H�}m{Q� H���!sI�q��
Ea����S� �c�[�`��y�
���rդ�'Q>�-��z�:�u@媁��1��d�:�{ģ�䊁j�rʁ�/�Z�S��������<k�N>p���/~񫿼��Z[�y�M��_^r�5bOC@�a�*E3XQ!僠V~:X��Ⅿ~� ?�����75�E"�\�,iX���o7�DW_s5ǍˮaZA]� ��K�<��t&&^���&$ ����YL�xQ�2aԑP�E�ɟ{,Η���@i��5�A��E�����J��E44��������8���>����A��h:f__�s�=��%�h{&�V7�јƣU���C ,H�An���^IB��,&Q��N
/�UR��.�����zL�HH�I�f6P�5_D�$�I@�VT�����ДD����ɏ#�<p�M7����Vێ|��_m����:�lh@{ݴ�i q�j�O��-��Bk�_��'�|�,z��Kz� 9���L_�� ����hd"2)3��UE  �s�"����ܑ?�V�@�j��`b<D�FJC��_�Pvt��G2����X��4P4I�����:#�T�Ԗ���k���i\1����0U9r��C"�;<<̵�� l���Ĵ�+�P?�V#j �+�8!\9������y��h:��c�uF��3?�S D1�Ă��O�3��<d5۔ȲDbG"\�M�P���\���!
SP��ȧs�Ϳ��ȱO����wIM���Sp-��w�r?��Wc�]�G�K}k[��B��ξ����|�PJ<d6��
�U5��Ć��ס��hS}]i���z�D�����z�I�|�)�,���P�#��
�,(�!���L` D�˂�=�&X�∦��):pλ���Z��� UR�!���4�]�:hPK� ��뱶
��f��M"�����'�f���`�[�#�&5#6��H�L�23��+�0��"�6V^^ۘ�@G�N��[Q$��0�H-)}������:�ֲ/�.,k��bå�B�����b���O=~��~�b2� �W��s�x��'��g�3xh��Ő9~����w�ݽu�X&3�N���Y+�&LR0&-J,m���UJZ��5X���"S13O�L��Q�P(�EUh2�,3S&1͞�f0d�'p�+��U�J��S5� �S��V�e�~�KFj���s���#����'�x�Z8hhB�[�U`"��^?�D� �\|��K[���6�� ����B�)�4�F7cu�r�@���X э �^��=�.�[$ ��*��.�*�J*L杌l���Hm]���3� g���r�O��a��2�&d�V�E�C����$�����4Z����gK|����N�5�D���c'�]��h���FZ��J�m'|;��(py,��k a�#�T�\&�,�+\d^_�+�Ȑ�ɠ�H�M�/�"�t"����I��*"�Y,����H'hF�n���DWW* �2�����e�k�ƍ���'e���dekٲe���7���
�Wl�'N�!f�rD^�zMEE��gLZ@��L���Yb���g�'����ѣ�4�,"t�>�^G��?��[!�� ������{��L%3뮾����ˣ W^�|�}�/���Y�C�������Ѷ�,vb�Mp�ͥ�565�^u铏oYT�p�g���2�����`yiw��7�V%�i�{�;_�h�,GF�<����m��/��?~��v��Z28S�e�fr�C��xK4 �F��@I���p��HD(���e�>�e�~o �� ���i���0�L���VA٦5-���J���=j�,���[���b�-��/~���;v�]���Ȩϧ�~�?~|���۷ogJ멧�߶�ĜX�i�x��v�D��Ԇ�+4IKƔ�;���N�j)/������
N@��Uu���>�A��� g��=ÉO}�[]���E�ݬ ��U,Y^���n�+�u�ܼ��a��)���B#��a��������?������]���No�h��������隚���X:�e �p��v� g�06���o��x_ =�p'����~��3W��׽�)b8R|�.��i�/�c5�-�R�"-%>��C��FIRbj�[�@Q��<U��X�w�>;�N?�+��B9m�j��;uF�����?��7�� (o��V��0 Щ8,3��u�H�-������lCj� љN�dzEԼ+�L�*��k�S͕JS�b�c0Ld<J�'4PW2��Z�,�V<�KFʡ�yw�����QӼ����b^u����,�9���e W� Jف x�2-�3�$�ߓ��OA�D2�B��k���k�o����w�ii�����]���O��…K��Ǭ�Xg�d"�H�]?Ӛ���[Z]]���+�~_$)������G�+�8Rq���XtTJ�I6����J�r˝���0/~��%r2���JW�"�LE�_�
+4�k�?�c �);�5�VEߢ ��Q���JŁK �K.�d~��e����t:u� 7����n�J�Os�l>�s�.�־��+��(��%K��2ͬ3�2����@�����\�O#��r�G�8�d�r��\��.�4ZYY�Ϸ��i�Ic���eL.�GF��ټl劊y����p4TQQ�r�/OUW�{����=H���i�L:KI^���W�����'�N>�Ь�SV=o���@P:1]�����H}����1\^ZN�P��L�8B���l��7��W�����7�̖+6`E��L`��H|Ӟ��BL�aix����[MZ���`�Z������l��P? �y����BТ \'G�>��c���կy-Cr� ���[n))_��1�vB[���k?��^�� ���V�:��y�?�'�i�:^S���;��ٙ�gK�%�/Z�B��Q!�N
;cODII�$�߻�����7�q�\�`(Rv٦+y3�$���[����E,���vPZT8�3nZ��?�4ܪ Z���t.�С�'2���X8�b!���@��ȵ���
+b��܂�ES΄���U=�+�/�S���,t=��\Q�d�?�q�{�<`Ҁ3�"��R��D�,�v>є� �'~���e�]ƔVDY4�˦�.' �c�$�@3]&�㟹���(�6֩�T�0C�t���L�=��O�g_��J�3,���6�������U����!$*a�"* V\v�M}�=�#1�4.����R�x��+�Q�
[��$[v��P�3�E٫�Վl�
���������� ��J���x��4T�3���1�2<b�hg{j��3����z�f�r<`�}���c�6�hq�Zm����o����#�X8<�EC��$���k1� �/�d���ƈ�m�
�]WK��G>��`��%k3t?�R�G�|�'8��w�|e�剆��8I$�d�eEE}e���eK��
=}�-&N��NG�"W��i�' lZ�cs ,��`ieUm$�����/�Jh�دz&Ţl[ �)��'x:%�}���<]� �� M��u^H �KŞ��9@$��T�SB�,��y��4��9�"��Z��B�p���ї5���SeUu��2N>��^�L�Y�\�t��{do�`���R�ȆC��k$`;N�D>��%�?��b�c�XY^��C�_F���Q�I%s,����g���#�DBJ�'y�)�o�J���QBRIB�g����>� &��ve��r��yJbv�֠��l}����7uZuIOIjV5����g��� 3d��s��ݕq�$�m쉠f��e�?�`����y��u���y��Yd��G��݈.��; Ț�2�$-O���>���}���_-�tC��)j$�y �+�4b��5��H�/�*F�Z��ʯ M�y+�.Z�M�]N�p^n���ŋYmئZS��2 ùƴ6U��=H��U�V�:�qg uA��5+f�MI��t.��2�9�����/���M�+�_�������70�J!7���&��2ݣ���V_u�Y�Ӈlɢ)K��|�M��o�����/aӪ���K*1z����z�ꅥnY�R��A���3r�$�򰼺T���!�Z��h��_�GW�aÆGy�y��up�<�o�A ^u�cˆͲzUI���� ��EmF)�G(����!=� -��dv$6�X�s@�>_Ue 1y��U��f�አ����ѷS/��!�2�i�eK~a�y�z��o�eAu�7O>�5�J�s��\T}�{^�����UcT�,��k��$a�T�� ���^�������/��E,� ogF-H�]��c�r�ʥK�����3.� Z,]?�"$c V� RO2ɿ|���4TD�[�դ�nO ��h6A/�p�+�<�B������%e�D��Io׽*ڤ۳���==�����Q �pÁ#XljC�׿�7��M�ƒ���q��>`��TX�jQL�$�y���K|��Tȩ.�:c�S=��aa˗/G��ܹ�,���Y��<�i�sKdfvY}X�� D�]y��d:(�4ۊr�j�[�7�[\�lŒ_o;4o�J*���7�����ˡ����V.^��rˊ�J�Oj!Dy��~�hgs���iH�R�+�~���ѥ�k.�\���Ɛ�@���Id���h8Vv���f
�BJ#Vc��
�B�Y�?k֬A˲m��te���֬��ǏL v�6a�v��"�&��®Z�L�͌��.�B��_y�ޣm��õ 2 ��Y��'�m?���ox�� "��-j���x���Gr0qpj�&���/�[�*[�h �m�^mbSy��qrN(X"/i .�SΌ.�Wb1���Z� ��,�y�\� � ]�=�^�W�7�Sػw/��4�4�~�fն,V ��g
�s7�"�Vm]�B�Y;@�KeI��h"+[q���3���g�������Uּ��k9"6� �cN�յ
��e��U ���E�xaG�8�$��M~l$*���AT����,��X�g�- gNX�-N�_��p���>��5?�Ow�`Q�+�=�5FvDz� t�R���� Ų0SZ<E�N*��mb���W*��:u�^6{�a�}8k�i�����������5KKѯr���9��Ppn��>d�F���8'2i�p$���*�^lr5�\��+;I���j�!��!�#�!G�_��~lL�D��+{ �m0U�E`�c��r� 4���0���ւ��-
}ʅ����a�M$���JKm��$#���X�˚�G�W$jY��Vf;��78�B�֖=-]fTѪ�1 �"QE���z�\�ˊ�HR��)�z6�u'>8�ݤ�-������[A�lh�r�# M� Lp��=�Y"�MaV�<7�eP-p��*�%������j��hU4Vx�3�G��qBrFDdJ�PpprNn���
�,�Ӵdn�)W�l��-Y�e��T�
ʧ+ ��,�/�&i��%���Ilhj��#"��լlU��co���� �Gm�
�Eu�*�5~��X �ԟTK>�������…�d�/I*�ss�ֲ�;Y��L��!�`EUm����D�,&��A�ҋ���PdӨb�2��t�B����FXP�[_O���Il��N0�5����N�c'��N7 ���T��e�R-zQo���9�E[�SlA#u(��ٽ��\%�^V��y��T�N)�g� Y�'Gv������O�|v���pI0�|����^�a� �����%Rh�Gn�ַٰꪺ"^����H��!�mQE�X^ M��c3c�R�8n5��+���$�\n�!IDATs�#lR[&H��S�`�Dҙ0
��Vn��M�m\���MXm%Q�����Dձ���{���~�K_�P���rY�U��O}�O������*CMk�Y�����[�aG���#�ڕL!��'���[Z��8>�7-��tgs>:�SpFAg���ӓ�6�3ķ�\,�]�JH�,�G��Gp)����E���p��eST<��K���'t �!� '��L3)y�[�<s�g�~�kߐO��\b$�����*����o���4��� ��Sd6� x�v����y���ʏ���ڶg׾��U���l "��`I:!�)�ύ q�mh��2d'� [2.�QP��2���T �����]���ׇ�G�%�Q�G=��,���Y�zt>!���X���1%�tg���}��ߙ_���-���o��vc|�7;�qú���m�� ��U��kA����Я�q㿿{�����U�W �ܟ���țF��y1�nN�P
��$�ӼN�9�-�n��Ĉ ��l}����§Nع���+�˪�C#��J'FP�f/
B�@~�2�d��������k�\z�z�7�;�Dr��,��%��8�҂
tq���#1�1��5����=��) E���8�AY�����2�H��^g ����Գը��LVDy+��߷���|��L��KV,��|�����_��O����)��ܿFB[ 6v���4 ��1]éj���Mi�g���^zM]Myi8��h��[Q�����h|2 7͙W��{�W��t&�G��<�Ǟ���;�H�d
4k;�ꯦRҋ����gZ�t�Y?c�j�J�@��d��~~W(m����d�J����XDZ���L|���m'�E������%s�|�Nc������n�ꎮ�N��� U{��,�,?����{ho�U����t�x�g����`VH�ޞ_]~�e�S�`��&Κe�.Y� �jx'���J�c���\��ͧ��q���ؾ����6J���aɪ��D(. G�_}c]��pwg�j��6]�Ӫ��iYM��B��}��>�Lƪk8 �{w�������]��d�� �n�Lf�+\��;ڻ:�����o?��7߹~~Pڙ�|�VQ/.`��/.'�9w�T�㜛�p,(���Ɨ��]^Ѱ8��75/^pɚ���X��Ϳ��8�̉�,�� jpZV�5/�L��uwny���-�t<R���t ѢF�}~�w���EK�)V>fZ��2��7�ZS����jg~zEcͺ��U%�mM"��:�r3���a�|S#�ͺ������h�����x+#�heU�����ܟ��U�؈�gGZ�N���6d���QSU������=��:�K+2�ܑ��������wn�kF��9LRA��H�)��T++깅[�%\���k���f�PDӭ��\"�7�/�L:ÈDK�ZZ�������T&��y[{�ZzG ���u -��*��<-�Hl�Ĕ<l��L99�5��i9xpp`$�L%r_�r)_:F ��f�d1`F��ԧv�5�M�@?U²���_�� {�1��
�T� ?d�\�\K��X2�t��DR֥����n��5��qEm��o�x��SN*W�Q�ϴm�ikY�cy��|� PZ�j#fpr�~�ˉ&��Ua�~�RJ2eg�U��v�*Us�V �گ#��+��H�Y5\6��� �ŋ���=��z����<�kl����V_q��n�8%�7n+iO��e�V��� ַ���1�,G����I/>EN&E��{2"�[ 3$;)� z��!v��y�/ G%�C�V(���G˜h����根�vl��8���߲n�F:`^�0���lZ�Sɴ!�g�$*:~yOX2�Ł� ԺQt�Թ����3�`;3kk�x\;������9��YS0e�!N)K��UI�̖��vD��d�AbE�0W-)��m(X����k0���f��s��h(PO���(z��@����/�o�����S[vz�v��8#�T�c>Y���Y��T *5�F΀D�#j��l
�P>+�T�f?�>:�KTJvL�xtNc�4{2Ie���; �3�ŏ��^�� �yRb���]�s�ř0G���$�e�㐮W�#�j�ˍ��C��JN�M�J�
$A�=,���v�&�W�u�IiL*R�ɏ&Ŝ�-g"��d���U�<�tV��";SayFqte����PQ3E�fT�Z�j��h좀�؁g�L�0�J�k�X�����Ss[3�j�V�I��z}|ғӗs"�"M3d�R��^ T�����c��5~Hi��e*F��tI��ω+��j��gҫ��MC5 s�:ƙ����B��*��� a���X�ҏ�$Kb�O�����`�*Լ� ��q��4~{V� �i��g�u�, ͜�iS*�i��&|�lFe����E$�[ ] �ۺ;-g�P>m�3<ga��� ��� 9�ΣCvv�9�T�+̢-!'k,U�:�V*��f�Bȶ����d���5��G�h�� ��A*��ON��Q ��C�p�)�޸�L�-H5������<��s�w�r6KB���o���=��M*J��]�#c�9k-�Hvf��*��)�|R��8�P^��9J[ǫ�=�~F9�v��u��:��6�Qa���j�cN~~�{3-QL�i��¼O� �3�үK��0�i[�$xY$��k�B�A�Zj��y(C$迳���_���D�j<�00�g�y>��<U��Vghީ��ȱ�rj��,$�Sh7Oմ��AQ�I�Q�8��qN�}E��� Y]�&�EN=�/�����FW��� 5Z����q$H\:zst�� d��9M�����hݞ�tNU��309�0%mr(EǠ�ż�������Z1���/f�S��|Ƥ�tUYV\�+#�2j4� �壬f3����1�k�bP�rL3��h�V#�l&�ȭh� ����E|zR1."/�!�S˝�PE[�_�%E6���|�b&zUMq�g���Y��v6���~�|��j�#7���$(aU�w[Q�j��B G�Ϋ�g��T�%9���M��3����&�-���e M(�O�� {�Av���.X�᳼��� ����T���8�Ǥk�;�+3Ka��MI�}�i|s^w!�H�1#�p9�l=&3��H��&���� :2��KF�:ů����{>JbLır9�"%p�i�@e�B�Td0����B��!�y��e���r,��W>�]R"G5
��R5�:|Ve�S�b�U���rU�kմ(��p�󵾀�2������4>2'��iEqxO
P�x!�"����C�K���jA���EJ�mN>Vo�Gd�V������9�RR-���(�4��{��o�����]�[����П/Z�D>M��B*U�JZ#qhn��zI#;
��\T�YHc��7۽56Е����hÒ5�.�ј�����L.�q�g�H(!�d}2��l|���}(���cL$�w��Hr��|^����DN�'Ya��w2݋�BҲZ I�9�>Ѣ�@� �����3�=�Mg^u��(�g[>�̳ �����%����~�j�ֈ�V�꾝��������t羭���*p�
�Hg
O�-��K�� _��PG��@�]��ň�<3�XimSYD���,m2۶�3[��f5�W����HS�bq� ���*eA��]|-;�3�,έ_��%�*:E)�Sw���_��������׭�4��_H$����溃-dz�� �]���!=3�e)�C.e ���_�=���*o؝�9��^#��F�y�#���-K��k��9<n-(��J&��í�g�5�KwҤ���-����?���ly�G/Yz����tttVUV�*5�ϴ$�LH�(Y���l;>����2�GӃ�����~�� k.[�`ӂf!] dz��׭_�>��b�J�t�R��:*n SfY�up
�'��`}M$�㣾�l��Ʃ�3�w<��P�����Ţ��X%����' ��F���KD�BKY�H��怰\��c�����к���]w㕗]��}?��%�`s��C��=�2���Չ)j�򂁬.W�DH[����n�000�s�j�#���=^���@i8TUQ�P]]����J ��zBeHN ��'C�l Ŕ�۱㉇���h"Y�����Dz�;�w�_����=����5z"�
4'4E�L8g�5v� ����:w=��W�x͂����+��|��G�����7�������=ݝ�r(�3��y��cfJ�T__S���6]%�7��
txu�!�*uE�a�۹��Bf�і�w=ߝ���+��Gån�95EX4�DfQV���%7�dUK�G�9���ٿu��#�c'�-��=�c�َ���X<���=�������&{1�0� Yu�44� �������" j��fD�(N�*
fl��ܲ��j�…5�RQ��+�_}UG{���O�hK���x5�f�7~~�f �X��)�`R��įϱաR�R�ZG�RA@8n?��K�ͯ�* �T�:o&������=����:ѱ�Y 'ew�$?�IQ�����_zu�I��9��4,�.����iKg �ۨ,��b��+H��U����'�^xVJ\*�BL�f�!��P�� N�Gs��!�LѨD�3G�.$ө' 1M:��p>_Wgﺵ�=���u�6�y�]����$�kJ�(�Bx�h.DF�!�
-D�'uCW���/F$��(p311��*��X�t��^��cO՗�w����Md�tv��7�?v4\Q1�yI����
-!w'1':�je��@
�Gp{�>o�+��6�t^huS��y�5K�]��z墲���{�#^wj��4b�<�O��W�N��š)i�*�4 �Q}f �T:XD#-O��oq2�z,o81��]��T&���4.�F����F 446����މT��]ҲZtR@#�C?�=%�X��f�)|�N��8�q�p`����|���j8[��l���Ϋ����_�p>�mX�4 �A0\UU* ���h(��U8y���uG*���T�y �Ԡ����hpH6�,+���� �*wB
�D��� R���`w9F����UՇ��X�b��wǮ��':j�Տ�3��޾�E�UUU�}<\'dvQo~g&�tEp�"pZ�r�&y��8���R���p[N��d6�Q�W^su��~f��Cm=��C'z���r�翰`�b�O�pѲ��t��dF�%��r T�O.�3���{v�G��l
��l��C���
�/�?� �-��o���cX�l|ȹ<|�D +����`
h�ӢG�Hf��Ӽc�3�B�b���F��{�^��w� ��>p���.�-��K .ǁ��n>�k ��)ZR���!Y��W��&��^�g>�[�:8���{R����X��bÕ���71U��* �ʲ�|)��t�h�����Ǿp��ʗB�S�0+�*��̙U��X"��$AFE���9��g�%ݹ�����g��+��'�b���u���q�M�;�UA�R���8�^�8^�� ��¯t&�%p:p�]�:@-���A� ��e��˦����~��/ ����Gۏ��F�K_�����vb��L�uڦr:Nf)�w����+�0��K���m}��*� v2�d�8�?v���t�M��n!�@6n�l+���4�ʀR���OK�N��T�xbu3��!8ס�b<������+)� �����>�����>۵gs�'���U�`��F~�m^�ኰ�K�֖�DR�,_�g3|(�� �g8d�C�/���-���q�FŤ��_zx�&�O�i��(e޶e�}��w��m$[�h��߾i�&ʥi��@�.�"y1/�3�-��!�'~�[o��?�WM�p6>�FK"�{?��O?�s�%�n��s�p��`y!'Z�@�1��H�1���aQ T�p��k��d1 ����t�C�!?J Lt���*$��Cƶ:w?1�ݚ-dK���� l��h���D���ȧ�e��dYFф�$�e�����zdr�ֽ d8�w`��o�#��iMeE8B��%����LY$�����^�Ē1�"z��ƫ�έ��Y�#t/�IEND�B`�
{
"name": "Voting",
"type": "hub",
"children": [
{
"name": "Topic A",
"type": "topic",
"text": "Sale of postoffice should be restricted to low-income housing uses that balance other needs and some commercial use.",
"children": [
{
"name": "Prop 1",
"type": "proposal",
"text": "Sale of postoffice should be restricted to low-density uses that do not negatively impact existing parking challenges, e.g. a city park.",
"children": [
{"name": "elle.javadi", "size": 3534},
{"name": "hannahymiller", "size": 5731},
{"name": "websandrew", "size": 5731},
{"name": "pratik.khadloya.5", "size": 3938},
{"name": "Go.Leith", "size": 3938},
{"name": "vintimahi", "size": 743}
]
},
{
"name": "Prop 2",
"type": "proposal",
"text": "Sale of postoffice should be restricted to low-density uses that exclude housing and balance other needs.",
"children": [
{"name": "elle.javadi", "size": 3534},
{"name": "hannahymiller", "size": 5731},
{"name": "pratik.khadloya.5", "size": 3938},
{"name": "Go.Leith", "size": 3938},
{"name": "vintimahi", "size": 743},
{"name": "jkhaykin", "size": 3416}
]
},
{
"name": "Prop 3",
"type": "proposal",
"text": "Sale of postoffice should be restricted to low-income housing uses that balance other needs and some commercial use.",
"children": [
{"name": "elle.javadi", "size": 3534},
{"name": "hannahymiller", "size": 5731},
{"name": "websandrew", "size": 5731},
{"name": "pratik.khadloya.5", "size": 3938},
{"name": "vintimahi", "size": 743},
{"name": "eli.miller.16144", "size": 7074}
]
}
]
},
{
"name": "Topic B",
"type": "topic",
"text": "We need real election reform based on public funding of political campaigns, the elimination of political primaries, and ranked order voting.",
"children": [
{
"name": "Prop 4",
"type": "proposal",
"text": "We need real election reform based on the elimination of political primaries, and ranked order voting.",
"children": [
{"name": "Go.Leith", "size": 3938},
{"name": "vintimahi", "size": 743},
{"name": "pratik.khadloya.5", "size": 3938},
{"name": "websandrew", "size": 5731},
{"name": "philipp.pahl.75", "size": 1983},
{"name": "hannahymiller", "size": 2042}
]
},
{
"name": "Prop 4",
"type": "proposal",
"text": "We need real election reform based on public funding of political campaigns, the elimination of political primaries, and ranked order voting.",
"children": [
{"name": "Go.Leith", "size": 3938},
{"name": "websandrew", "size": 5731},
{"name": "philipp.pahl.75", "size": 1983},
{"name": "hannahymiller", "size": 2042}
]
}
]
},
{
"name": "Topic C",
"type": "topic",
"text": "Users should always have to explain why they support a proposal.",
"children": [
{
"name": "Prop 5",
"type": "proposal",
"text": "Users should be able to vote without explaining why they support a proposal.",
"children": [
{"name": "gborchardt1", "size": 593},
{"name": "eli.miller.16144", "size": 277},
{"name": "websandrew", "size": 5731},
{"name": "hannahymiller", "size": 264},
{"name": "philipp.pahl.75", "size": 593},
{"name": "john.bodeau", "size": 277},
{"name": "david.harris.798278", "size": 264}
]
},
{
"name": "Prop 6",
"type": "proposal",
"text": "Users should always have to explain why they support a proposal.",
"children": [
{"name": "philipp.pahl.75", "size": 593},
{"name": "Go.Leith", "size": 3938},
{"name": "websandrew", "size": 5731},
{"name": "john.bodeau", "size": 277},
{"name": "david.harris.798278", "size": 264}
]
}
]
},
{
"name": "Topic D",
"type": "topic",
"text": "Respect each other's time. Attend all team functions unless you give advance notice.",
"children": [
{
"name": "Prop 7",
"type": "proposal",
"text": "Respect each other's time by arriving early to meetings, or call/text ahead. Attend all team functions unless you give advance notice.",
"children": [
{"name": "jkhaykin", "size": 593},
{"name": "gborchardt1", "size": 277},
{"name": "hannahymiller", "size": 264},
{"name": "pratik.khadloya.5", "size": 1983},
{"name": "david.harris.798278", "size": 2042}
]
},
{
"name": "Prop 8",
"type": "proposal",
"text": "Respect each other's time. Attend all team functions unless you give advance notice.",
"children": [
{"name": "pratik.khadloya.5", "size": 1983},
{"name": "websandrew", "size": 5731},
{"name": "Go.Leith", "size": 3938},
{"name": "david.harris.798278", "size": 2042}
]
}
]
},
{
"name": "Topic F",
"type": "topic",
"text": "Kids should be forced to eat anything they say they want to eat.",
"children": [
{
"name": "Prop 9",
"type": "proposal",
"text": "Kids should never be forced to eat anything they don't want to eat. However, to help them make healthy choices, sometimes they should be offered 'nothing' as the alternative to a healthy choice.",
"children": [
{"name": "philipp.pahl.75", "size": 1302},
{"name": "websandrew", "size": 5731},
{"name": "Go.Leith", "size": 3938},
{"name": "jkhaykin", "size": 6703}
]
},
{
"name": "Prop 10",
"type": "proposal",
"text": "Kids should be forced to eat anything they say they want to eat.",
"children": [
{"name": "gborchardt1", "size": 1983},
{"name": "hannahymiller", "size": 2042},
{"name": "jkhaykin", "size": 593},
{"name": "Go.Leith", "size": 3938},
{"name": "gborchardt1", "size": 277},
{"name": "hannahymiller", "size": 264},
{"name": "websandrew", "size": 5731},
{"name": "pratik.khadloya.5", "size": 1983},
{"name": "david.harris.798278", "size": 2042}
]
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment