Browse files

Fix bug 931042: Redirect /collusion/ to /lightbeam/.

Remove collusion related assets.
  • Loading branch information...
1 parent 32d86a2 commit 03ce3825c8e2b42d176b7d5f271c1918fcdbef0d @pmac pmac committed Oct 25, 2013
View
0 bedrock/collusion/__init__.py
No changes.
View
5 bedrock/collusion/models.py
@@ -1,5 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Create your models here.
View
148 bedrock/collusion/templates/collusion/collusion.html
@@ -1,148 +0,0 @@
-{# This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/. #}
-
-{% extends "base-resp.html" %}
-
-{% block page_title %}Collusion{% endblock %}
-{% block body_id %}collusion{% endblock %}
-{% block body_class %}sand{% endblock %}
-{% block site_header_nav %}
- <span class="toggle" role="button" aria-controls="nav-main-menu" tabindex="0">{{_('Menu')}}</span>
- <nav id="nav-main" role="navigation">
- <ul id="nav-main-menu">
- <li><b>Home</b></li>
- <li><a href="{{ url('collusion.demo') }}">Demo</a></li>
- </ul>
- </nav>
-{% endblock %}
-
-{% block extrahead %}
- {{ css('collusion') }}
-{% endblock %}
-
-{% block js %}
- {{ js('collusion') }}
-{% endblock %}
-
-{% block content %}
-
-<hgroup class="container">
- <h1 class="large">Introducing Collusion</h1>
- <h2>Discover who’s tracking you online</h2>
-</hgroup>
-
-<section id="primary" class="container">
-
- <img src="{{ media('img/collusion/nodes.png') }}" alt="">
-
- <p>
- Collusion is an experimental add-on for Firefox and allows you to
- see all the third parties that are tracking your movements across
- the Web. It will show, in real time, how that data creates a
- spider-web of interaction between companies and other trackers.
- </p>
-
- <div class="buttons">
-
- <a class="button" href="{{ url('collusion.demo') }}">
- View Our Demo
- <small>see how you’re being tracked</small>
- </a>
-
- <a class="button" href="https://addons.mozilla.org/en-US/firefox/addon/collusion/">
- Download
- <small>the Collusion add-on for Firefox</small>
- </a>
-
- </div>
-
-</section>
-
-<section id="secondary" class="container">
-
- <div class="main-content">
-
- <h3>Take control of your data</h3>
- <p>
- We recognize the importance of transparency and our mission is
- all about empowering users — both with tools and with
- information. The Ford Foundation is supporting Mozilla to
- develop the Collusion add-on so it will enable users to not only
- see who is tracking them across the Web, but also to turn that
- tracking off when they want to.
- </p>
-
- <h3>Telling the global tracking story</h3>
- <p>
- Your data can be part of the larger story. When we launch the
- full version of Collusion, it will allow you to opt-in to
- sharing your anonymous data in a global database of web tracker
- data. We’ll combine all that information and make it available
- to help researchers, journalists, and others analyze and explain
- how data is tracked on the web.
- </p>
-
- <h3>Building user awareness</h3>
- <p>
- Through our work with the Ford Foundation, we’ll be building
- outreach campaigns to help people understand online data
- tracking — both the benefits and the issues — so they can make
- their own choices about how they want to be tracked (or choose
- not to be tracked at all).
- </p>
-
- <h3>Collusion is about choice</h3>
- <p>
- Not all tracking is bad. Many services rely on user data to
- provide relevant content and enhance your online experience. But
- most tracking happens without users' consent and without their
- knowledge. That’s not okay. It should be you who decides when,
- how and if you want to be tracked. Collusion will be a powerful
- tool to help you do that.
- </p>
- </div>
-
- <div class="sidebar">
- <form action="https://sendto.mozilla.org/page/s/collusion" method="post" class="box" id="updates">
- <h3>Want to hear more?</h3>
- <p class="intro">Get Mozilla updates:</p>
-
- <div class="field" id="email-field">
- <span id="email-wrapper">
- <label class="hide-me" for="email">your email:</label>
- <input name="email" type="email" id="email" value="" placeholder="Your Email Address" class="required" required aria-required="true">
- </span>
- </div>
-
- <div class="field" id="country-field">
- {% include "foundation/_country_select.html" %}
- </div>
-
- <div class="field" id="privacy-field">
- <label for="privacy-check" id="privacy-check-label" class="">
- <span class="input"><input type="checkbox" name="custom-824" id="privacy-check" value="1" required aria-required="true"></span>
-
- <span class="title">
- I'm okay with you handling this info as you explain in
- your <a href="{{ php_url('/privacy-policy.html') }}">Privacy
- Policy</a>
- </span>
- </label>
- </div>
-
- <div class="field" id="submit-field">
- <button type="submit" class="submit button">Sign me up</button>
- </div>
- <p><small>We will only send you Mozilla-related information.</small></p>
- <input type="hidden" name="submit" value="submit">
- </form>
-
- <h3>Supported by</h3>
- <img src="{{ media('img/collusion/ford-foundation.png') }}" alt="Ford Foundation" />
-
- </div>
-
-</section>
-
-{% endblock %}
View
202 bedrock/collusion/templates/collusion/demo.html
@@ -1,202 +0,0 @@
-{# This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/. #}
-
-{% extends "base-resp.html" %}
-
-{% block page_title %}Collusion Demo{% endblock %}
-{% block body_id %}collusion-demo{% endblock %}
-{% block body_class %}sand{% endblock %}
-{% block site_header_nav %}
- <span class="toggle" role="button" aria-controls="nav-main-menu" tabindex="0">{{_('Menu')}}</span>
- <nav id="nav-main" role="navigation">
- <ul id="nav-main-menu">
- <li><a href="{{ url('collusion.collusion') }}">Home</a></li>
- <li><b>Demo</b></li>
- </ul>
- </nav>
-{% endblock %}
-
-{% block extrahead %}
- {{ css('collusion') }}
- <script src="{{ media('js/collusion/d3.js') }}"></script>
-{% endblock %}
-
-{% block js %}
- {{ js('collusion_demo') }}
-<script>
-// taken from http://stackoverflow.com/questions/2090551/parse-query-string-in-javascript
-function getQueryVariable(variable) {
- var query = window.location.search.substring(1);
- var vars = query.split("&");
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split("=");
- if (pair[0] == variable) {
- return unescape(pair[1]);
- }
- }
-}
-
-function updateGraphViaPostMessage(graph, target) {
- target.postMessage("ready", "*");
- $(window).one("message", function(event) {
- graph.update(JSON.parse(event.originalEvent.data));
- });
-}
-
-$(window).ready(function() {
- var addon = CollusionAddon;
- var graphUrl = getQueryVariable("graph_url");
-
- $("#domain-infos").hide();
-
- // get list of known trackers from trackers.json file hosted on website:
- jQuery.getJSON("{{ MEDIA_URL }}js/collusion/trackers.json", function(trackers) {
- var runner = GraphRunner.Runner({
- width: 640,
- height: 480,
- trackers: trackers,
- hideFavicons: false
- });
- var graph = runner.graph;
-
- // Enable drag-and-drop to import collusion graph data from a json file:
- $(document.body).bind("dragover", function(event) {
- event.preventDefault();
- }).bind("drop", function(event) {
- event.preventDefault();
- var files = event.originalEvent.dataTransfer.files;
- if (files.length == 1) {
- var reader = new FileReader();
- reader.onload = function() {
- if (addon.importGraph) {
- addon.importGraph(reader.result);
- window.location.reload();
- } else
- graph.update(JSON.parse(reader.result));
- };
- reader.readAsText(files[0], "UTF-8");
- }
- });
-
- $("#page").width(runner.width);
-
- if (graphUrl) {
- if (graphUrl == "opener") {
- updateGraphViaPostMessage(graph, window.opener);
- } else if (graphUrl == "parent") {
-
- updateGraphViaPostMessage(graph, window.parent);
- } else
- jQuery.getJSON(graphUrl, function(data) {
- graph.update(data);
- });
- return;
- }
-
-
- Demo.show(graph);
-
- // Display the footer now the page is rendered
- $('section.external').fadeIn();
- });
-});
-
-</script>
-{% endblock %}
-
-
-{% block content %}
-
-<h1 class="container">Collusion Demo</h1>
-<section id="demo-section" class="container">
-
-<div id="page">
-<div id="sidebar" class="box">
- <div class="byline"></a></div>
-
- <div id="sidebar-content">
- <div class="exposition">
- <blockquote>If you're not paying for something, you're not the customer; you're the product being sold.</blockquote><span class="attribution">- Andrew Lewis</span>
- <p>Collusion provides an interactive, real-time visualization of the entities that track your behavior across the web.</p>
- </div> <!-- end of exposition -->
-
- <div class="live-data" style="display: none;">
- <p>Keep browsing the web. As you do so, a graph on this page will change. Each dot represents a website.</p>
- <p>Sites in <span class="tracker">red</span> are confirmed trackers by <a href="http://privacychoice.org">privacychoice.org</a>. Sites in <span class="site">gray</span> are not, but may still track you.</p>
- <p>Sites with a halo are sites that you have visited. Sites without a halo are sites you have not visited.</p>
-
- <p>Hover your mouse over the dots to learn more about them.</p>
- <div class="settings-menu">
- <ul>
- <li id="reset-graph">Reset Graph</li>
- <li id="export-graph">Export Graph</li>
- <li id="hide-ui">Hide UI</li>
- </ul>
-
- </div> <!-- end of settingsmenu -->
- <p class="privacy-policy"><strong>Privacy Policy</strong> When you're using the add-on, we collect information from sites you visit solely to show you how they're connected. This information is stored locally on your computer and you can delete it by resetting the graph. We don't give away this information to anyone except you.</p>
- </div> <!-- end of live-data -->
- <div class="demo" style="display: none;">
- <div class="step 0">
- <p>This page will show you a demo of what you might see if you were surfing the web with Collusion.</p>
-
- <p><span class="next">Click here</span> to see what happens when you start your browser and visit the Internet Movie Database at imdb.com.</p>
- </div>
- <div class="step 1">
- <p>Each dot in this graph represents a website. The gray dot in the middle is imdb.com; the red dots near it are advertising sites that have created <a href="http://en.wikipedia.org/wiki/HTTP_cookie">cookies</a> in your browser and are now tracking your behavior on the IMDB.</p>
- <p>The advertising sites are colored red because <a href="http://privacychoice.org">privacychoice.org</a> has determined that they're behavioral tracking sites. Non-red sites may still track you.</p>
-
- <p>Hover your mouse over any of the sites to learn more about them.</p>
- <p>When you're done, <span class="next">click here</span> to continue your web adventure. Our next stop is the New York Times website.</p>
- </div>
- <div class="step 2">
- <p>It looks like the New York Times is affiliated with some of the same advertising companies as the IMDB.</p>
- <p>Because the same cookies were transmitted to the same advertisers when you visited both sites, those advertisers effectively track you <em>across</em> them. That's valuable data for their market research.</p>
-
- <p>When you're ready, <span class="next">click here</span> to visit our next stop, the Huffington Post.</p>
- </div>
- <div class="step 3">
- <p>Some companies are already using their knowledge about you to determine what you see on the sites they're affiliated with&mdash;not just the ads you see, but the actual content you read. Eli Pariser examines what this could mean for society at large in his book <b>The Filter Bubble</b>. Watch Eli's TED talk on the Filter Bubble <a href="http://www.ted.com/talks/eli_pariser_beware_online_filter_bubbles.html">here</a>.</p>
-
- <p>By the way, if the graph is starting to look a bit confusing, try dragging the dots around with your mouse to get a better view.</p>
- <p>Then, <span class="next">click here</span> to go to our next stop, gamespot.com.</p>
- </div>
- <div class="step 4">
- <p>If you haven't realized it yet, companies are tracking you across most of the sites you visit daily on the web. It's quite likely that these companies know more about you than your government. Some of them might even know more about you than your best friends.</p>
- <p><span class="next">Click here</span> to visit our final stop, reference.com.</p>
-
- </div>
- <div class="step 5">
- <p>Thanks for trying out this demo. If you'd like to see this graph change in real time based on the sites you visit in your own browser, feel free to try the <a href="https://addons.mozilla.org/en-US/firefox/addon/collusion/" class="xpi-download">Collusion Firefox add-on</a>. Even visiting the sites mentioned in the demo will probably give you different visualizations, because some services you may be logged into&mdash;like Facebook&mdash;can also track you across sites.</p>
- <p>If you want to block companies from tracking you on the internet, you can install <a href="http://www.privacychoice.org/trackerblock/firefox">TrackerBlock</a> for Firefox and Internet Explorer.</p>
-
- <p>Collusion was created as a prototype by Atul Varma. For more information about the making of this demo, check out the <a href="http://www.toolness.com/wp/2011/07/collusion/">blog post</a> and <a href="https://github.com/toolness/collusion">code repository</a>.</p>
- </div>
- </div> <!-- End of .demo -->
-
- <a href="https://addons.mozilla.org/en-US/firefox/addon/collusion/" class="button download">Download <small>the Collusion add-on for Firefox</small></a>
-
- <div id="domain-infos">Mouse over any circle to see how that site is involved in tracking.</div> <!-- Templates are copied into here -->
- </div> <!-- End of #sidebar-content -->
-</div> <!-- End of #sidebar -->
-<div id="chart"></div><!-- The d3 layout graph will go inside this div -->
-</div>
-<div id="templates">
- <div class="info" style="display: none;">
- <h2 class="domain"></h2>
-
- <div class="referrees">
- <p>When you visit <a class="domain"></a>, it informs the following websites about your visit.</p>
- <ul></ul>
- </div>
- <div class="referrers">
- <p>The site <a class="domain"></a> tracks your behavior across the following websites.</p>
-
- <ul></ul>
- </div>
- </div>
-</div>
-</section>
-
-{% endblock %}
View
11 bedrock/collusion/urls.py
@@ -1,11 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from django.conf.urls import patterns
-from bedrock.mozorg.util import page
-
-urlpatterns = patterns('',
- page('demo', 'collusion/demo.html'),
- page('', 'collusion/collusion.html'),
-)
View
2 bedrock/foundation/templates/foundation/annualreport/2011.html
@@ -532,7 +532,7 @@ <h2 class="section-title">{{ _('Action') }}</h2>
<img src="{{ media('img/foundation/annualreport/2011/act-collusion.jpg') }}" alt="">
<div class="overlay">
<p>
- {% trans collusion_url=url('collusion.collusion') %}
+ {% trans collusion_url=url('lightbeam.lightbeam') %}
<a href="{{ collusion_url }}" rel="external" hreflang="en-US">Mozilla Collusion</a>
gives consumers a powerful tool to protect their privacy, arming
them with transparency, facts and the power to make their own
View
15 bedrock/settings/base.py
@@ -113,9 +113,6 @@ def JINJA_CONFIG():
'grants': (
'css/grants/grants.less',
),
- 'collusion': (
- 'css/collusion/collusion.less',
- ),
'lightbeam': (
'css/lightbeam/lightbeam.less',
),
@@ -370,17 +367,6 @@ def JINJA_CONFIG():
'site': (
'js/base/site.js', # this is automatically included on every page
),
- 'collusion': (
- 'js/collusion/collusion.js',
- 'js/libs/jquery.validate.js',
- ),
- 'collusion_demo': (
- 'js/collusion/d3.layout.js',
- 'js/collusion/d3.geom.js',
- 'js/collusion/collusion-addon.js',
- 'js/collusion/demo.js',
- 'js/collusion/graphrunner.js',
- ),
'lightbeam': (
'js/lightbeam/d3.v3.min.js',
'js/lightbeam/rAF.js',
@@ -687,7 +673,6 @@ def JINJA_CONFIG():
# Local apps
'%s.base' % PROJECT_MODULE,
- '%s.collusion' % PROJECT_MODULE,
'%s.lightbeam' % PROJECT_MODULE,
'%s.firefox' % PROJECT_MODULE,
'%s.foundation' % PROJECT_MODULE,
View
1 bedrock/urls.py
@@ -19,7 +19,6 @@
urlpatterns = patterns('',
# Main pages
(r'^apps/', include('bedrock.marketplace.urls')),
- (r'^collusion/', include('bedrock.collusion.urls')),
(r'^lightbeam/', include('bedrock.lightbeam.urls')),
(r'^foundation/', include('bedrock.foundation.urls')),
(r'^grants/', include('bedrock.grants.urls')),
View
4 etc/httpd/global.conf
@@ -107,7 +107,9 @@ RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?apps(.*)$ /b/$1apps$2 [PT]
RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?persona(.*)$ /b/$1persona$2 [PT]
RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?b2g(.*)$ /b/$1b2g$2 [PT]
-RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?collusion(.*)$ /b/$1collusion$2 [PT]
+
+# bug 931042
+RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?collusion.*$ /$1lightbeam/ [L,R=301]
# bug 882845
RewriteRule ^/(\w{2,3}(?:-\w{2})?/)?firefox/toolkit/download-to-your-devices(.*)$ /$1firefox/ [L,R=301]
View
6 media/.htaccess
@@ -35,12 +35,6 @@ ExpiresByType application/octet-stream "access plus 0 seconds"
ExpiresByType text/css "access plus 12 hours"
</Files>
-# bug 848527
-<Files trackers.json>
- Header set Access-Control-Allow-Origin "*"
- ExpiresByType application/json "access plus 1 year"
-</Files>
-
FileETag MTime
<FilesMatch "\.txt$">
View
325 media/css/collusion/collusion.less
@@ -1,325 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-@import "../sandstone/lib.less";
-
-
-hgroup {
- text-align: center;
- padding-top: @baseLine * 2;
- padding-bottom: @baseLine * 2;
-
- h2 {
- font-size: 32px;
- }
-}
-
-.hide-me {
- position: absolute;
- left: -9999em;
- height: 1px;
- overflow: hidden;
-}
-
-#primary {
- padding-top: @baseLine * 2;
- padding-bottom: @baseLine * 2;
- @shadow: 0 1px 1px rgba(0,0,0,0.1), 0 0 0 1px #fff;
- .box-shadow(@shadow);
- background: #fff;
- #gradient > .radial(center, 45px, ellipse, farthest-corner, #f5f1e8 0%, #ffffff 100%);
- .clearfix;
- margin-bottom: @baseLine * 3;
-
- img {
- max-width: 50%;
- position: absolute;
- right: -15px;
- top: -80px;
- }
-
- p {
- margin-right: 40%;
- }
-
-}
-
-
-#sidebar .button,
-#primary .button {
- height: auto;
- line-height: @baseLine;
- font-size: 18px;
- padding: @baseLine / 2 @gridGutterWidth;
- width: @gridColumnWidth * 3;
- margin-right: @gridGutterWidth;
- margin-bottom: @baseLine / 2;
- float: left;
- font-weight: normal;
-
- small {
- display: block;
- }
-}
-
-
-#secondary {
- padding-bottom: @baseLine * 3;
-}
-
-#sidebar {
- padding-top: @baseLine;
- position: absolute;
-}
-
-#page {
- min-height: 650px;
-}
-
-#chart {
- margin-left: 250px;
- font-size: 11px;
- font-family: sans-serif;
- color: #666;
-}
-
-.exposition {
- blockquote {
- color: @textColorTertiary;
- font-style: italic;
- }
- .attribution {
- display: block;
- margin-bottom: @baseLine;
- }
-}
-
-#updates {
- margin-bottom: @baseLine * 2;
- p { margin: 0; }
- .field {
- .clearfix;
- padding: @baseLine / 4 0;
-
- input[type=email] {
- width: (@gridColumnWidth * 3) + (@gridGutterWidth * 2) - 18px;
- }
-
- .title {
- font-size: 14px;
- }
-
- small {
- color: @textColorTertiary;
- }
- }
- label.error {
- display: block;
- }
-}
-
-#secondary {
- clear: both;
-}
-
-.main-content {
- .span(7);
-}
-
-.sidebar {
- .span(4);
- .offset(1);
-}
-
-#collusion-demo {
- #outer-wrapper {
- min-width: @widthDesktop;
- }
- #wrapper {
- width: @widthDesktop;
- #masthead,
- #main-feature,
- #main-content,
- .billboard,
- .container {
- width: auto;
- }
- }
- #sidebar {
- .span(3);
- }
- #demo-section {
- }
-}
-
-
-/* {{{ Tablet Layout: 768px */
-@media only screen and (min-width: @widthTablet) and (max-width: @widthDesktop) {
-
- #collusion {
- .main-content {
- .span_narrow(7);
- }
- .sidebar {
- .span_narrow(4);
- .offset_narrow(1);
- }
- }
-
-}
-
-/* }}} */
-/* {{{ Wide Mobile Layout: 480px */
-@media only screen and (max-width: @widthTablet) {
-
- #collusion {
- .main-content {
- .span-all();
- }
-
- .sidebar {
- .span-all();
- }
-
- #primary {
- padding-top: @baseLine;
- padding-bottom: @baseLine;
- p {
- .span-all();
- }
- img {
- display: none;
- }
- .buttons {
- .span-all();
- .button {
- margin: 10px auto;
- width: auto;
- display: block;
- float: none;
- }
- }
- }
- }
-
-}
-
-
-/* }}} */
-
-
-
-g.node.unrelated-domain image {
- display: none;
-}
-
-g.node.unrelated-domain circle.glow {
- display: none;
-}
-
-g.node.unrelated-domain circle.visited {
- stroke: #102050;
-}
-
-g.node.unrelated-domain circle.site {
- stroke: #202020;
-}
-
-g.node.unrelated-domain circle.tracker {
- stroke: #400000;
-}
-
-g.node.unrelated-domain circle.round-border {
- fill: #151515;
-}
-
-.round-border {
- fill: #fff;
- stroke-width: 2px;
-}
-
-marker {
- stroke: none;
- fill: #fff;
- fill-opacity: 1;
-}
-
-line.link {
- stroke: #999;
- stroke-opacity: .6;
-}
-
-line.bold {
- stroke: #fff;
- stroke-opacity: 1;
-}
-
-.hidden {
- .visually-hidden();
-}
-
-
-h2.domain img.favicon {
- width: 16px;
- height: 16px;
- padding-right: 4px;
-}
-
-h2.domain img.tracker {
- height: 30px;
-}
-
-.attribution {
- margin-left: 20px;
-}
-
-.tracker {
- stroke: @linkRed;
-}
-
-.site {
- stroke: #7f7f7f;
-}
-
-.visited {
- stroke: #67A7D0;
-}
-
-.demo span.next {
- cursor: pointer;
- font-weight: bold;
- color: @linkRed;
-}
-
-.demo span.next:hover {
- text-decoration: underline;
-}
-
-
-/* On demo.html, the graph is shown against light background instead of dark
- so make the bold arrows black instead of white. */
-
-line.bold {
- stroke: #000;
-}
-
-marker {
- fill: #000;
-}
-
-g.node.unrelated-domain circle.visited {
- stroke: #a0a0e0;
-}
-
-g.node.unrelated-domain circle.site {
- stroke: #b0b0b0;
-}
-
-g.node.unrelated-domain circle.tracker {
- stroke: #d6a0a0;
-}
-
-g.node.unrelated-domain circle.round-border {
- fill: #e0e0e0;
-}
View
18 media/js/collusion/collusion-addon.js
@@ -1,18 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var CollusionAddon = (function() {
- var self = {
- isInstalled: function() {
- return ('onGraph' in window);
- },
- onGraph: window.onGraph,
- importGraph: window.importGraph,
- resetGraph: window.resetGraph,
- saveGraph: window.saveGraph,
- getSavedGraph: window.getSavedGraph
- };
-
- return self;
-})();
View
17 media/js/collusion/collusion.js
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-$(document).ready(function(){
- $("#updates").validate({
- errorPlacement: function(error, element) {
- $element = $(element);
-
- if ($element.attr('id') == 'privacy-check') {
- error.appendTo($('#privacy-field'));
- } else {
- error.appendTo($('#email-wrapper'));
- }
- }
- });
-});
View
825 media/js/collusion/d3.geom.js
@@ -1,825 +0,0 @@
-(function(){d3.geom = {};
-/**
- * Computes a contour for a given input grid function using the <a
- * href="http://en.wikipedia.org/wiki/Marching_squares">marching
- * squares</a> algorithm. Returns the contour polygon as an array of points.
- *
- * @param grid a two-input function(x, y) that returns true for values
- * inside the contour and false for values outside the contour.
- * @param start an optional starting point [x, y] on the grid.
- * @returns polygon [[x1, y1], [x2, y2], …]
- */
-d3.geom.contour = function(grid, start) {
- var s = start || d3_geom_contourStart(grid), // starting point
- c = [], // contour polygon
- x = s[0], // current x position
- y = s[1], // current y position
- dx = 0, // next x direction
- dy = 0, // next y direction
- pdx = NaN, // previous x direction
- pdy = NaN, // previous y direction
- i = 0;
-
- do {
- // determine marching squares index
- i = 0;
- if (grid(x-1, y-1)) i += 1;
- if (grid(x, y-1)) i += 2;
- if (grid(x-1, y )) i += 4;
- if (grid(x, y )) i += 8;
-
- // determine next direction
- if (i === 6) {
- dx = pdy === -1 ? -1 : 1;
- dy = 0;
- } else if (i === 9) {
- dx = 0;
- dy = pdx === 1 ? -1 : 1;
- } else {
- dx = d3_geom_contourDx[i];
- dy = d3_geom_contourDy[i];
- }
-
- // update contour polygon
- if (dx != pdx && dy != pdy) {
- c.push([x, y]);
- pdx = dx;
- pdy = dy;
- }
-
- x += dx;
- y += dy;
- } while (s[0] != x || s[1] != y);
-
- return c;
-};
-
-// lookup tables for marching directions
-var d3_geom_contourDx = [1, 0, 1, 1,-1, 0,-1, 1,0, 0,0,0,-1, 0,-1,NaN],
- d3_geom_contourDy = [0,-1, 0, 0, 0,-1, 0, 0,1,-1,1,1, 0,-1, 0,NaN];
-
-function d3_geom_contourStart(grid) {
- var x = 0,
- y = 0;
-
- // search for a starting point; begin at origin
- // and proceed along outward-expanding diagonals
- while (true) {
- if (grid(x,y)) {
- return [x,y];
- }
- if (x === 0) {
- x = y + 1;
- y = 0;
- } else {
- x = x - 1;
- y = y + 1;
- }
- }
-}
-/**
- * Computes the 2D convex hull of a set of points using Graham's scanning
- * algorithm. The algorithm has been implemented as described in Cormen,
- * Leiserson, and Rivest's Introduction to Algorithms. The running time of
- * this algorithm is O(n log n), where n is the number of input points.
- *
- * @param vertices [[x1, y1], [x2, y2], …]
- * @returns polygon [[x1, y1], [x2, y2], …]
- */
-d3.geom.hull = function(vertices) {
- if (vertices.length < 3) return [];
-
- var len = vertices.length,
- plen = len - 1,
- points = [],
- stack = [],
- i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
-
- // find the starting ref point: leftmost point with the minimum y coord
- for (i=1; i<len; ++i) {
- if (vertices[i][1] < vertices[h][1]) {
- h = i;
- } else if (vertices[i][1] == vertices[h][1]) {
- h = (vertices[i][0] < vertices[h][0] ? i : h);
- }
- }
-
- // calculate polar angles from ref point and sort
- for (i=0; i<len; ++i) {
- if (i === h) continue;
- y1 = vertices[i][1] - vertices[h][1];
- x1 = vertices[i][0] - vertices[h][0];
- points.push({angle: Math.atan2(y1, x1), index: i});
- }
- points.sort(function(a, b) { return a.angle - b.angle; });
-
- // toss out duplicate angles
- a = points[0].angle;
- v = points[0].index;
- u = 0;
- for (i=1; i<plen; ++i) {
- j = points[i].index;
- if (a == points[i].angle) {
- // keep angle for point most distant from the reference
- x1 = vertices[v][0] - vertices[h][0];
- y1 = vertices[v][1] - vertices[h][1];
- x2 = vertices[j][0] - vertices[h][0];
- y2 = vertices[j][1] - vertices[h][1];
- if ((x1*x1 + y1*y1) >= (x2*x2 + y2*y2)) {
- points[i].index = -1;
- } else {
- points[u].index = -1;
- a = points[i].angle;
- u = i;
- v = j;
- }
- } else {
- a = points[i].angle;
- u = i;
- v = j;
- }
- }
-
- // initialize the stack
- stack.push(h);
- for (i=0, j=0; i<2; ++j) {
- if (points[j].index !== -1) {
- stack.push(points[j].index);
- i++;
- }
- }
- sp = stack.length;
-
- // do graham's scan
- for (; j<plen; ++j) {
- if (points[j].index === -1) continue; // skip tossed out points
- while (!d3_geom_hullCCW(stack[sp-2], stack[sp-1], points[j].index, vertices)) {
- --sp;
- }
- stack[sp++] = points[j].index;
- }
-
- // construct the hull
- var poly = [];
- for (i=0; i<sp; ++i) {
- poly.push(vertices[stack[i]]);
- }
- return poly;
-}
-
-// are three points in counter-clockwise order?
-function d3_geom_hullCCW(i1, i2, i3, v) {
- var t, a, b, c, d, e, f;
- t = v[i1]; a = t[0]; b = t[1];
- t = v[i2]; c = t[0]; d = t[1];
- t = v[i3]; e = t[0]; f = t[1];
- return ((f-b)*(c-a) - (d-b)*(e-a)) > 0;
-}
-// Note: requires coordinates to be counterclockwise and convex!
-d3.geom.polygon = function(coordinates) {
-
- coordinates.area = function() {
- var i = 0,
- n = coordinates.length,
- a = coordinates[n - 1][0] * coordinates[0][1],
- b = coordinates[n - 1][1] * coordinates[0][0];
- while (++i < n) {
- a += coordinates[i - 1][0] * coordinates[i][1];
- b += coordinates[i - 1][1] * coordinates[i][0];
- }
- return (b - a) * .5;
- };
-
- coordinates.centroid = function(k) {
- var i = -1,
- n = coordinates.length - 1,
- x = 0,
- y = 0,
- a,
- b,
- c;
- if (!arguments.length) k = 1 / (6 * coordinates.area());
- while (++i < n) {
- a = coordinates[i];
- b = coordinates[i + 1];
- c = a[0] * b[1] - b[0] * a[1];
- x += (a[0] + b[0]) * c;
- y += (a[1] + b[1]) * c;
- }
- return [x * k, y * k];
- };
-
- // The Sutherland-Hodgman clipping algorithm.
- coordinates.clip = function(subject) {
- var input,
- i = -1,
- n = coordinates.length,
- j,
- m,
- a = coordinates[n - 1],
- b,
- c,
- d;
- while (++i < n) {
- input = subject.slice();
- subject.length = 0;
- b = coordinates[i];
- c = input[(m = input.length) - 1];
- j = -1;
- while (++j < m) {
- d = input[j];
- if (d3_geom_polygonInside(d, a, b)) {
- if (!d3_geom_polygonInside(c, a, b)) {
- subject.push(d3_geom_polygonIntersect(c, d, a, b));
- }
- subject.push(d);
- } else if (d3_geom_polygonInside(c, a, b)) {
- subject.push(d3_geom_polygonIntersect(c, d, a, b));
- }
- c = d;
- }
- a = b;
- }
- return subject;
- };
-
- return coordinates;
-};
-
-function d3_geom_polygonInside(p, a, b) {
- return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
-}
-
-// Intersect two infinite lines cd and ab.
-function d3_geom_polygonIntersect(c, d, a, b) {
- var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0],
- y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1],
- x13 = x1 - x3,
- x21 = x2 - x1,
- x43 = x4 - x3,
- y13 = y1 - y3,
- y21 = y2 - y1,
- y43 = y4 - y3,
- ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21);
- return [x1 + ua * x21, y1 + ua * y21];
-}
-// Adapted from Nicolas Garcia Belmonte's JIT implementation:
-// http://blog.thejit.org/2010/02/12/voronoi-tessellation/
-// http://blog.thejit.org/assets/voronoijs/voronoi.js
-// See lib/jit/LICENSE for details.
-
-/**
- * @param vertices [[x1, y1], [x2, y2], …]
- * @returns polygons [[[x1, y1], [x2, y2], …], …]
- */
-d3.geom.voronoi = function(vertices) {
- var polygons = vertices.map(function() { return []; });
-
- // Note: we expect the caller to clip the polygons, if needed.
- d3_voronoi_tessellate(vertices, function(e) {
- var s1,
- s2,
- x1,
- x2,
- y1,
- y2;
- if (e.a === 1 && e.b >= 0) {
- s1 = e.ep.r;
- s2 = e.ep.l;
- } else {
- s1 = e.ep.l;
- s2 = e.ep.r;
- }
- if (e.a === 1) {
- y1 = s1 ? s1.y : -1e6;
- x1 = e.c - e.b * y1;
- y2 = s2 ? s2.y : 1e6;
- x2 = e.c - e.b * y2;
- } else {
- x1 = s1 ? s1.x : -1e6;
- y1 = e.c - e.a * x1;
- x2 = s2 ? s2.x : 1e6;
- y2 = e.c - e.a * x2;
- }
- var v1 = [x1, y1],
- v2 = [x2, y2];
- polygons[e.region.l.index].push(v1, v2);
- polygons[e.region.r.index].push(v1, v2);
- });
-
- // Reconnect the polygon segments into counterclockwise loops.
- return polygons.map(function(polygon, i) {
- var cx = vertices[i][0],
- cy = vertices[i][1];
- polygon.forEach(function(v) {
- v.angle = Math.atan2(v[0] - cx, v[1] - cy);
- });
- return polygon.sort(function(a, b) {
- return a.angle - b.angle;
- }).filter(function(d, i) {
- return !i || (d.angle - polygon[i - 1].angle > 1e-10);
- });
- });
-};
-
-var d3_voronoi_opposite = {"l": "r", "r": "l"};
-
-function d3_voronoi_tessellate(vertices, callback) {
-
- var Sites = {
- list: vertices
- .map(function(v, i) {
- return {
- index: i,
- x: v[0],
- y: v[1]
- };
- })
- .sort(function(a, b) {
- return a.y < b.y ? -1
- : a.y > b.y ? 1
- : a.x < b.x ? -1
- : a.x > b.x ? 1
- : 0;
- }),
- bottomSite: null
- };
-
- var EdgeList = {
- list: [],
- leftEnd: null,
- rightEnd: null,
-
- init: function() {
- EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
- EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
- EdgeList.leftEnd.r = EdgeList.rightEnd;
- EdgeList.rightEnd.l = EdgeList.leftEnd;
- EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
- },
-
- createHalfEdge: function(edge, side) {
- return {
- edge: edge,
- side: side,
- vertex: null,
- "l": null,
- "r": null
- };
- },
-
- insert: function(lb, he) {
- he.l = lb;
- he.r = lb.r;
- lb.r.l = he;
- lb.r = he;
- },
-
- leftBound: function(p) {
- var he = EdgeList.leftEnd;
- do {
- he = he.r;
- } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
- he = he.l;
- return he;
- },
-
- del: function(he) {
- he.l.r = he.r;
- he.r.l = he.l;
- he.edge = null;
- },
-
- right: function(he) {
- return he.r;
- },
-
- left: function(he) {
- return he.l;
- },
-
- leftRegion: function(he) {
- return he.edge == null
- ? Sites.bottomSite
- : he.edge.region[he.side];
- },
-
- rightRegion: function(he) {
- return he.edge == null
- ? Sites.bottomSite
- : he.edge.region[d3_voronoi_opposite[he.side]];
- }
- };
-
- var Geom = {
-
- bisect: function(s1, s2) {
- var newEdge = {
- region: {"l": s1, "r": s2},
- ep: {"l": null, "r": null}
- };
-
- var dx = s2.x - s1.x,
- dy = s2.y - s1.y,
- adx = dx > 0 ? dx : -dx,
- ady = dy > 0 ? dy : -dy;
-
- newEdge.c = s1.x * dx + s1.y * dy
- + (dx * dx + dy * dy) * .5;
-
- if (adx > ady) {
- newEdge.a = 1;
- newEdge.b = dy / dx;
- newEdge.c /= dx;
- } else {
- newEdge.b = 1;
- newEdge.a = dx / dy;
- newEdge.c /= dy;
- }
-
- return newEdge;
- },
-
- intersect: function(el1, el2) {
- var e1 = el1.edge,
- e2 = el2.edge;
- if (!e1 || !e2 || (e1.region.r == e2.region.r)) {
- return null;
- }
- var d = (e1.a * e2.b) - (e1.b * e2.a);
- if (Math.abs(d) < 1e-10) {
- return null;
- }
- var xint = (e1.c * e2.b - e2.c * e1.b) / d,
- yint = (e2.c * e1.a - e1.c * e2.a) / d,
- e1r = e1.region.r,
- e2r = e2.region.r,
- el,
- e;
- if ((e1r.y < e2r.y) ||
- (e1r.y == e2r.y && e1r.x < e2r.x)) {
- el = el1;
- e = e1;
- } else {
- el = el2;
- e = e2;
- }
- var rightOfSite = (xint >= e.region.r.x);
- if ((rightOfSite && (el.side === "l")) ||
- (!rightOfSite && (el.side === "r"))) {
- return null;
- }
- return {
- x: xint,
- y: yint
- };
- },
-
- rightOf: function(he, p) {
- var e = he.edge,
- topsite = e.region.r,
- rightOfSite = (p.x > topsite.x);
-
- if (rightOfSite && (he.side === "l")) {
- return 1;
- }
- if (!rightOfSite && (he.side === "r")) {
- return 0;
- }
- if (e.a === 1) {
- var dyp = p.y - topsite.y,
- dxp = p.x - topsite.x,
- fast = 0,
- above = 0;
-
- if ((!rightOfSite && (e.b < 0)) ||
- (rightOfSite && (e.b >= 0))) {
- above = fast = (dyp >= e.b * dxp);
- } else {
- above = ((p.x + p.y * e.b) > e.c);
- if (e.b < 0) {
- above = !above;
- }
- if (!above) {
- fast = 1;
- }
- }
- if (!fast) {
- var dxs = topsite.x - e.region.l.x;
- above = (e.b * (dxp * dxp - dyp * dyp)) <
- (dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b));
-
- if (e.b < 0) {
- above = !above;
- }
- }
- } else /* e.b == 1 */ {
- var yl = e.c - e.a * p.x,
- t1 = p.y - yl,
- t2 = p.x - topsite.x,
- t3 = yl - topsite.y;
-
- above = (t1 * t1) > (t2 * t2 + t3 * t3);
- }
- return he.side === "l" ? above : !above;
- },
-
- endPoint: function(edge, side, site) {
- edge.ep[side] = site;
- if (!edge.ep[d3_voronoi_opposite[side]]) return;
- callback(edge);
- },
-
- distance: function(s, t) {
- var dx = s.x - t.x,
- dy = s.y - t.y;
- return Math.sqrt(dx * dx + dy * dy);
- }
- };
-
- var EventQueue = {
- list: [],
-
- insert: function(he, site, offset) {
- he.vertex = site;
- he.ystar = site.y + offset;
- for (var i=0, list=EventQueue.list, l=list.length; i<l; i++) {
- var next = list[i];
- if (he.ystar > next.ystar ||
- (he.ystar == next.ystar &&
- site.x > next.vertex.x)) {
- continue;
- } else {
- break;
- }
- }
- list.splice(i, 0, he);
- },
-
- del: function(he) {
- for (var i=0, ls=EventQueue.list, l=ls.length; i<l && (ls[i] != he); ++i) {}
- ls.splice(i, 1);
- },
-
- empty: function() { return EventQueue.list.length === 0; },
-
- nextEvent: function(he) {
- for (var i=0, ls=EventQueue.list, l=ls.length; i<l; ++i) {
- if (ls[i] == he) return ls[i+1];
- }
- return null;
- },
-
- min: function() {
- var elem = EventQueue.list[0];
- return {
- x: elem.vertex.x,
- y: elem.ystar
- };
- },
-
- extractMin: function() {
- return EventQueue.list.shift();
- }
- };
-
- EdgeList.init();
- Sites.bottomSite = Sites.list.shift();
-
- var newSite = Sites.list.shift(), newIntStar;
- var lbnd, rbnd, llbnd, rrbnd, bisector;
- var bot, top, temp, p, v;
- var e, pm;
-
- while (true) {
- if (!EventQueue.empty()) {
- newIntStar = EventQueue.min();
- }
- if (newSite && (EventQueue.empty()
- || newSite.y < newIntStar.y
- || (newSite.y == newIntStar.y
- && newSite.x < newIntStar.x))) { //new site is smallest
- lbnd = EdgeList.leftBound(newSite);
- rbnd = EdgeList.right(lbnd);
- bot = EdgeList.rightRegion(lbnd);
- e = Geom.bisect(bot, newSite);
- bisector = EdgeList.createHalfEdge(e, "l");
- EdgeList.insert(lbnd, bisector);
- p = Geom.intersect(lbnd, bisector);
- if (p) {
- EventQueue.del(lbnd);
- EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
- }
- lbnd = bisector;
- bisector = EdgeList.createHalfEdge(e, "r");
- EdgeList.insert(lbnd, bisector);
- p = Geom.intersect(bisector, rbnd);
- if (p) {
- EventQueue.insert(bisector, p, Geom.distance(p, newSite));
- }
- newSite = Sites.list.shift();
- } else if (!EventQueue.empty()) { //intersection is smallest
- lbnd = EventQueue.extractMin();
- llbnd = EdgeList.left(lbnd);
- rbnd = EdgeList.right(lbnd);
- rrbnd = EdgeList.right(rbnd);
- bot = EdgeList.leftRegion(lbnd);
- top = EdgeList.rightRegion(rbnd);
- v = lbnd.vertex;
- Geom.endPoint(lbnd.edge, lbnd.side, v);
- Geom.endPoint(rbnd.edge, rbnd.side, v);
- EdgeList.del(lbnd);
- EventQueue.del(rbnd);
- EdgeList.del(rbnd);
- pm = "l";
- if (bot.y > top.y) {
- temp = bot;
- bot = top;
- top = temp;
- pm = "r";
- }
- e = Geom.bisect(bot, top);
- bisector = EdgeList.createHalfEdge(e, pm);
- EdgeList.insert(llbnd, bisector);
- Geom.endPoint(e, d3_voronoi_opposite[pm], v);
- p = Geom.intersect(llbnd, bisector);
- if (p) {
- EventQueue.del(llbnd);
- EventQueue.insert(llbnd, p, Geom.distance(p, bot));
- }
- p = Geom.intersect(bisector, rrbnd);
- if (p) {
- EventQueue.insert(bisector, p, Geom.distance(p, bot));
- }
- } else {
- break;
- }
- }//end while
-
- for (lbnd = EdgeList.right(EdgeList.leftEnd);
- lbnd != EdgeList.rightEnd;
- lbnd = EdgeList.right(lbnd)) {
- callback(lbnd.edge);
- }
-}
-/**
-* @param vertices [[x1, y1], [x2, y2], …]
-* @returns triangles [[[x1, y1], [x2, y2], [x3, y3]], …]
- */
-d3.geom.delaunay = function(vertices) {
- var edges = vertices.map(function() { return []; }),
- triangles = [];
-
- // Use the Voronoi tessellation to determine Delaunay edges.
- d3_voronoi_tessellate(vertices, function(e) {
- edges[e.region.l.index].push(vertices[e.region.r.index]);
- });
-
- // Reconnect the edges into counterclockwise triangles.
- edges.forEach(function(edge, i) {
- var v = vertices[i],
- cx = v[0],
- cy = v[1];
- edge.forEach(function(v) {
- v.angle = Math.atan2(v[0] - cx, v[1] - cy);
- });
- edge.sort(function(a, b) {
- return a.angle - b.angle;
- });
- for (var j = 0, m = edge.length - 1; j < m; j++) {
- triangles.push([v, edge[j], edge[j + 1]]);
- }
- });
-
- return triangles;
-};
-// Constructs a new quadtree for the specified array of points. A quadtree is a
-// two-dimensional recursive spatial subdivision. This implementation uses
-// square partitions, dividing each square into four equally-sized squares. Each
-// point exists in a unique node; if multiple points are in the same position,
-// some points may be stored on internal nodes rather than leaf nodes. Quadtrees
-// can be used to accelerate various spatial operations, such as the Barnes-Hut
-// approximation for computing n-body forces, or collision detection.
-d3.geom.quadtree = function(points, x1, y1, x2, y2) {
- var p,
- i = -1,
- n = points.length;
-
- // Type conversion for deprecated API.
- if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint);
-
- // Allow bounds to be specified explicitly.
- if (arguments.length < 5) {
- if (arguments.length === 3) {
- y2 = x2 = y1;
- y1 = x1;
- } else {
- x1 = y1 = Infinity;
- x2 = y2 = -Infinity;
-
- // Compute bounds.
- while (++i < n) {
- p = points[i];
- if (p.x < x1) x1 = p.x;
- if (p.y < y1) y1 = p.y;
- if (p.x > x2) x2 = p.x;
- if (p.y > y2) y2 = p.y;
- }
-
- // Squarify the bounds.
- var dx = x2 - x1,
- dy = y2 - y1;
- if (dx > dy) y2 = y1 + dx;
- else x2 = x1 + dy;
- }
- }
-
- // Recursively inserts the specified point p at the node n or one of its
- // descendants. The bounds are defined by [x1, x2] and [y1, y2].
- function insert(n, p, x1, y1, x2, y2) {
- if (isNaN(p.x) || isNaN(p.y)) return; // ignore invalid points
- if (n.leaf) {
- var v = n.point;
- if (v) {
- // If the point at this leaf node is at the same position as the new
- // point we are adding, we leave the point associated with the
- // internal node while adding the new point to a child node. This
- // avoids infinite recursion.
- if ((Math.abs(v.x - p.x) + Math.abs(v.y - p.y)) < .01) {
- insertChild(n, p, x1, y1, x2, y2);
- } else {
- n.point = null;
- insertChild(n, v, x1, y1, x2, y2);
- insertChild(n, p, x1, y1, x2, y2);
- }
- } else {
- n.point = p;
- }
- } else {
- insertChild(n, p, x1, y1, x2, y2);
- }
- }
-
- // Recursively inserts the specified point p into a descendant of node n. The
- // bounds are defined by [x1, x2] and [y1, y2].
- function insertChild(n, p, x1, y1, x2, y2) {
- // Compute the split point, and the quadrant in which to insert p.
- var sx = (x1 + x2) * .5,
- sy = (y1 + y2) * .5,
- right = p.x >= sx,
- bottom = p.y >= sy,
- i = (bottom << 1) + right;
-
- // Recursively insert into the child node.
- n.leaf = false;
- n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
-
- // Update the bounds as we recurse.
- if (right) x1 = sx; else x2 = sx;
- if (bottom) y1 = sy; else y2 = sy;
- insert(n, p, x1, y1, x2, y2);
- }
-
- // Create the root node.
- var root = d3_geom_quadtreeNode();
-
- root.add = function(p) {
- insert(root, p, x1, y1, x2, y2);
- };
-
- root.visit = function(f) {
- d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
- };
-
- // Insert all points.
- points.forEach(root.add);
- return root;
-};
-
-function d3_geom_quadtreeNode() {
- return {
- leaf: true,
- nodes: [],
- point: null
- };
-}
-
-function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
- if (!f(node, x1, y1, x2, y2)) {
- var sx = (x1 + x2) * .5,
- sy = (y1 + y2) * .5,
- children = node.nodes;
- if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
- if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
- if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
- if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
- }
-}
-
-function d3_geom_quadtreePoint(p) {
- return {
- x: p[0],
- y: p[1]
- };
-}
-})();
View
3,586 media/js/collusion/d3.js
0 additions, 3,586 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
1,821 media/js/collusion/d3.layout.js
@@ -1,1821 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-(function(){d3.layout = {};
-// Implements hierarchical edge bundling using Holten's algorithm. For each
-// input link, a path is computed that travels through the tree, up the parent
-// hierarchy to the least common ancestor, and then back down to the destination
-// node. Each path is simply an array of nodes.
-d3.layout.bundle = function() {
- return function(links) {
- var paths = [],
- i = -1,
- n = links.length;
- while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
- return paths;
- };
-};
-
-function d3_layout_bundlePath(link) {
- var start = link.source,
- end = link.target,
- lca = d3_layout_bundleLeastCommonAncestor(start, end),
- points = [start];
- while (start !== lca) {
- start = start.parent;
- points.push(start);
- }
- var k = points.length;
- while (end !== lca) {
- points.splice(k, 0, end);
- end = end.parent;
- }
- return points;
-}
-
-function d3_layout_bundleAncestors(node) {
- var ancestors = [],
- parent = node.parent;
- while (parent != null) {
- ancestors.push(node);
- node = parent;
- parent = parent.parent;
- }
- ancestors.push(node);
- return ancestors;
-}
-
-function d3_layout_bundleLeastCommonAncestor(a, b) {
- if (a === b) return a;
- var aNodes = d3_layout_bundleAncestors(a),
- bNodes = d3_layout_bundleAncestors(b),
- aNode = aNodes.pop(),
- bNode = bNodes.pop(),
- sharedNode = null;
- while (aNode === bNode) {
- sharedNode = aNode;
- aNode = aNodes.pop();
- bNode = bNodes.pop();
- }
- return sharedNode;
-}
-d3.layout.chord = function() {
- var chord = {},
- chords,
- groups,
- matrix,
- n,
- padding = 0,
- sortGroups,
- sortSubgroups,
- sortChords;
-
- function relayout() {
- var subgroups = {},
- groupSums = [],
- groupIndex = d3.range(n),
- subgroupIndex = [],
- k,
- x,
- x0,
- i,
- j;
-
- chords = [];
- groups = [];
-
- // Compute the sum.
- k = 0, i = -1; while (++i < n) {
- x = 0, j = -1; while (++j < n) {
- x += matrix[i][j];
- }
- groupSums.push(x);
- subgroupIndex.push(d3.range(n));
- k += x;
- }
-
- // Sort groups…
- if (sortGroups) {
- groupIndex.sort(function(a, b) {
- return sortGroups(groupSums[a], groupSums[b]);
- });
- }
-
- // Sort subgroups…
- if (sortSubgroups) {
- subgroupIndex.forEach(function(d, i) {
- d.sort(function(a, b) {
- return sortSubgroups(matrix[i][a], matrix[i][b]);
- });
- });
- }
-
- // Convert the sum to scaling factor for [0, 2pi].
- // TODO Allow start and end angle to be specified.
- // TODO Allow padding to be specified as percentage?
- k = (2 * Math.PI - padding * n) / k;
-
- // Compute the start and end angle for each group and subgroup.
- x = 0, i = -1; while (++i < n) {
- x0 = x, j = -1; while (++j < n) {
- var di = groupIndex[i],
- dj = subgroupIndex[i][j],
- v = matrix[di][dj];
- subgroups[di + "-" + dj] = {
- index: di,
- subindex: dj,
- startAngle: x,
- endAngle: x += v * k,
- value: v
- };
- }
- groups.push({
- index: di,
- startAngle: x0,
- endAngle: x,
- value: (x - x0) / k
- });
- x += padding;
- }
-
- // Generate chords for each (non-empty) subgroup-subgroup link.
- i = -1; while (++i < n) {
- j = i - 1; while (++j < n) {
- var source = subgroups[i + "-" + j],
- target = subgroups[j + "-" + i];
- if (source.value || target.value) {
- chords.push(source.value < target.value
- ? {source: target, target: source}
- : {source: source, target: target})
- }
- }
- }
-
- if (sortChords) resort();
- }
-
- function resort() {
- chords.sort(function(a, b) {
- return sortChords(a.target.value, b.target.value);
- });
- }
-
- chord.matrix = function(x) {
- if (!arguments.length) return matrix;
- n = (matrix = x) && matrix.length;
- chords = groups = null;
- return chord;
- };
-
- chord.padding = function(x) {
- if (!arguments.length) return padding;
- padding = x;
- chords = groups = null;
- return chord;
- };
-
- chord.sortGroups = function(x) {
- if (!arguments.length) return sortGroups;
- sortGroups = x;
- chords = groups = null;
- return chord;
- };
-
- chord.sortSubgroups = function(x) {
- if (!arguments.length) return sortSubgroups;
- sortSubgroups = x;
- chords = null;
- return chord;
- };
-
- chord.sortChords = function(x) {
- if (!arguments.length) return sortChords;
- sortChords = x;
- if (chords) resort();
- return chord;
- };
-
- chord.chords = function() {
- if (!chords) relayout();
- return chords;
- };
-
- chord.groups = function() {
- if (!groups) relayout();
- return groups;
- };
-
- return chord;
-};
-// A rudimentary force layout using Gauss-Seidel.
-d3.layout.force = function() {
- var force = {},
- event = d3.dispatch("tick"),
- size = [1, 1],
- alpha,
- friction = .9,
- distance = 20,
- charge = -30,
- gravity = .1,
- theta = .8,
- interval,
- nodes = [],
- links = [],
- distances;
-
- function repulse(node, kc) {
- return function(quad, x1, y1, x2, y2) {
- if (quad.point !== node) {
- var dx = quad.cx - node.x,
- dy = quad.cy - node.y,
- dn = 1 / Math.sqrt(dx * dx + dy * dy);
-
- /* Barnes-Hut criterion. */
- if ((x2 - x1) * dn < theta) {
- var k = kc * quad.count * dn * dn;
- node.x += dx * k;
- node.y += dy * k;
- return true;
- }
-
- if (quad.point && isFinite(dn)) {
- var k = kc * dn * dn;
- node.x += dx * k;
- node.y += dy * k;
- }
- }
- };
- }
-
- function tick() {
- var n = nodes.length,
- m = links.length,
- q = d3.geom.quadtree(nodes),
- i, // current index
- o, // current object
- s, // current source
- t, // current target
- l, // current distance
- x, // x-distance
- y; // y-distance
-
- // gauss-seidel relaxation for links
- for (i = 0; i < m; ++i) {
- o = links[i];
- s = o.source;
- t = o.target;
- x = t.x - s.x;
- y = t.y - s.y;
- if (l = (x * x + y * y)) {
- l = alpha * ((l = Math.sqrt(l)) - distance) / l;
- x *= l;
- y *= l;
- t.x -= x;
- t.y -= y;
- s.x += x;
- s.y += y;
- }
- }
-
- // apply gravity forces
- var kg = alpha * gravity;
- x = size[0] / 2;
- y = size[1] / 2;
- i = -1; while (++i < n) {
- o = nodes[i];
- o.x += (x - o.x) * kg;
- o.y += (y - o.y) * kg;
- }
-
- // compute quadtree center of mass
- d3_layout_forceAccumulate(q);
-
- // apply charge forces
- var kc = alpha * charge;
- i = -1; while (++i < n) {
- q.visit(repulse(nodes[i], kc));
- }
-
- // position verlet integration
- i = -1; while (++i < n) {
- o = nodes[i];
- if (o.fixed) {
- o.x = o.px;
- o.y = o.py;
- } else {
- o.x -= (o.px - (o.px = o.x)) * friction;
- o.y -= (o.py - (o.py = o.y)) * friction;
- }
- }
-
- event.tick.dispatch({type: "tick", alpha: alpha});
-
- // simulated annealing, basically
- return (alpha *= .99) < .005;
- }
-
- force.on = function(type, listener) {
- event[type].add(listener);
- return force;
- };
-
- force.nodes = function(x) {
- if (!arguments.length) return nodes;
- nodes = x;
- return force;
- };
-
- force.links = function(x) {
- if (!arguments.length) return links;
- links = x;
- return force;
- };
-
- force.size = function(x) {
- if (!arguments.length) return size;
- size = x;
- return force;
- };
-
- force.distance = function(x) {
- if (!arguments.length) return distance;
- distance = x;
- return force;
- };
-
- force.friction = function(x) {
- if (!arguments.length) return friction;
- friction = x;
- return force;
- };
-
- force.charge = function(x) {
- if (!arguments.length) return charge;
- charge = x;
- return force;
- };
-
- force.gravity = function(x) {
- if (!arguments.length) return gravity;
- gravity = x;
- return force;
- };
-
- force.theta = function(x) {
- if (!arguments.length) return theta;
- theta = x;
- return force;
- };
-
- force.start = function() {
- var i,
- j,
- n = nodes.length,
- m = links.length,
- w = size[0],
- h = size[1],
- neighbors,
- o;
-
- for (i = 0; i < n; ++i) {
- (o = nodes[i]).index = i;
- }
-
- for (i = 0; i < m; ++i) {
- o = links[i];
- if (typeof o.source == "number") o.source = nodes[o.source];
- if (typeof o.target == "number") o.target = nodes[o.target];
- }
-
- for (i = 0; i < n; ++i) {
- o = nodes[i];
- if (isNaN(o.x)) o.x = position("x", w);
- if (isNaN(o.y)) o.y = position("y", h);
- if (isNaN(o.px)) o.px = o.x;
- if (isNaN(o.py)) o.py = o.y;
- }
-
- // initialize node position based on first neighbor
- function position(dimension, size) {
- var neighbors = neighbor(i),
- j = -1,
- m = neighbors.length,
- x;
- while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
- return Math.random() * size;
- }
-
- // initialize neighbors lazily
- function neighbor() {
- if (!neighbors) {
- neighbors = [];
- for (j = 0; j < n; ++j) {
- neighbors[j] = [];
- }
- for (j = 0; j < m; ++j) {
- var o = links[j];
- neighbors[o.source.index].push(o.target);
- neighbors[o.target.index].push(o.source);
- }
- }
- return neighbors[i];
- }
-
- return force.resume();
- };
-
- force.resume = function() {
- alpha = .1;
- d3.timer(tick);
- return force;
- };
-
- force.stop = function() {
- alpha = 0;
- return force;
- };
-
- // use `node.call(force.drag)` to make nodes draggable
- force.drag = function() {
-
- this
- .on("mouseover.force", d3_layout_forceDragOver)
- .on("mouseout.force", d3_layout_forceDragOut)
- .on("mousedown.force", d3_layout_forceDragDown);
-
- d3.select(window)
- .on("mousemove.force", dragmove)
- .on("mouseup.force", dragup, true)
- .on("click.force", d3_layout_forceDragClick, true);
-
- return force;
- };
-
- function dragmove() {
- if (!d3_layout_forceDragNode) return;
- var parent = d3_layout_forceDragElement.parentNode;
-
- // O NOES! The drag element was removed from the DOM.
- if (!parent) {
- d3_layout_forceDragNode.fixed = false;
- d3_layout_forceDragNode = d3_layout_forceDragElement = null;
- return;
- }
-
- var m = d3.svg.mouse(parent);
- d3_layout_forceDragMoved = true;
- d3_layout_forceDragNode.px = m[0];
- d3_layout_forceDragNode.py = m[1];
- force.resume(); // restart annealing
- }
-
- function dragup() {
- if (!d3_layout_forceDragNode) return;
-
- // If the node was moved, prevent the mouseup from propagating.
- // Also prevent the subsequent click from propagating (e.g., for anchors).
- if (d3_layout_forceDragMoved) {
- d3_layout_forceStopClick = true;
- d3_layout_forceCancel();
- }
-
- dragmove();
- d3_layout_forceDragNode.fixed = false;
- d3_layout_forceDragNode = d3_layout_forceDragElement = null;
- }
-
- return force;
-};
-
-var d3_layout_forceDragNode,
- d3_layout_forceDragMoved,
- d3_layout_forceStopClick,
- d3_layout_forceDragElement;
-
-function d3_layout_forceDragOver(d) {
- d.fixed = true;
-}
-
-function d3_layout_forceDragOut(d) {
- if (d !== d3_layout_forceDragNode) {
- d.fixed = false;
- }
-}
-
-function d3_layout_forceDragDown(d, i) {
- (d3_layout_forceDragNode = d).fixed = true;
- d3_layout_forceDragMoved = false;
- d3_layout_forceDragElement = this;
- d3_layout_forceCancel();
-}
-
-function d3_layout_forceDragClick() {
- if (d3_layout_forceStopClick) {
- d3_layout_forceCancel();
- d3_layout_forceStopClick = false;
- }
-}
-
-function d3_layout_forceCancel() {
- d3.event.stopPropagation();
- d3.event.preventDefault();
-}
-
-function d3_layout_forceAccumulate(quad) {
- var cx = 0,
- cy = 0;
- quad.count = 0;
- if (!quad.leaf) {
- quad.nodes.forEach(function(c) {
- d3_layout_forceAccumulate(c);
- quad.count += c.count;
- cx += c.count * c.cx;
- cy += c.count * c.cy;
- });
- }
- if (quad.point) {
- // jitter internal nodes that are coincident
- if (!quad.leaf) {
- quad.point.x += Math.random() - .5;
- quad.point.y += Math.random() - .5;
- }
- quad.count++;
- cx += quad.point.x;
- cy += quad.point.y;
- }
- quad.cx = cx / quad.count;
- quad.cy = cy / quad.count;
-}
-d3.layout.partition = function() {
- var hierarchy = d3.layout.hierarchy(),
- size = [1, 1]; // width, height
-
- function position(node, x, dx, dy) {
- var children = node.children;
- node.x = x;
- node.y = node.depth * dy;
- node.dx = dx;
- node.dy = dy;
- if (children) {
- var i = -1,
- n = children.length,
- c,
- d;
- dx /= node.value;
- while (++i < n) {
- position(c = children[i], x, d = c.value * dx, dy);
- x += d;
- }
- }
- }
-
- function depth(node) {
- var children = node.children,
- d = 0;
- if (children) {
- var i = -1,
- n = children.length;
- while (++i < n) d = Math.max(d, depth(children[i]));
- }
- return 1 + d;
- }
-
- function partition(d, i) {
- var nodes = hierarchy.call(this, d, i);
- position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
- return nodes;
- }
-
- partition.size = function(x) {
- if (!arguments.length) return size;
- size = x;
- return partition;
- };
-
- return d3_layout_hierarchyRebind(partition, hierarchy);
-};
-d3.layout.pie = function() {
- var value = Number,
- sort = null,
- startAngle = 0,
- endAngle = 2 * Math.PI;
-
- function pie(data, i) {
-
- // Compute the start angle.
- var a = +(typeof startAngle === "function"
- ? startAngle.apply(this, arguments)
- : startAngle);
-
- // Compute the angular range (end - start).
- var k = (typeof endAngle === "function"
- ? endAngle.apply(this, arguments)
- : endAngle) - startAngle;
-
- // Optionally sort the data.
- var index = d3.range(data.length);
- if (sort != null) index.sort(function(i, j) {
- return sort(data[i], data[j]);
- });
-
- // Compute the numeric values for each data element.
- var values = data.map(value);
-
- // Convert k into a scale factor from value to angle, using the sum.
- k /= values.reduce(function(p, d) { return p + d; }, 0);
-
- // Compute the arcs!
- var arcs = index.map(function(i) {
- return {
- value: d = values[i],
- startAngle: a,
- endAngle: a += d * k
- };
- });
-
- // Return the arcs in the original data's order.
- return data.map(function(d, i) {
- return arcs[index[i]];
- });
- }
-
- /**
- * Specifies the value function *x*, which returns a nonnegative numeric value
- * for each datum. The default value function is `Number`. The value function
- * is passed two arguments: the current datum and the current index.
- */
- pie.value = function(x) {
- if (!arguments.length) return value;
- value = x;
- return pie;
- };
-
- /**
- * Specifies a sort comparison operator *x*. The comparator is passed two data
- * elements from the data array, a and b; it returns a negative value if a is
- * less than b, a positive value if a is greater than b, and zero if a equals
- * b.
- */
- pie.sort = function(x) {
- if (!arguments.length) return sort;
- sort = x;
- return pie;
- };
-
- /**
- * Specifies the overall start angle of the pie chart. Defaults to 0. The
- * start angle can be specified either as a constant or as a function; in the
- * case of a function, it is evaluated once per array (as opposed to per
- * element).