<commit_before>// @flow
import * as React from 'react'
import {Platform, TextInput, StyleSheet} from 'react-native'
import * as c from '../../components/colors'
import {AllHtmlEntities} from 'html-entities'

const entities = new AllHtmlEntities()

const styles = StyleSheet.create({
	text: {
		color: c.black,
		backgroundColor: c.white,
		paddingHorizontal: 15,
		paddingTop: 10,
		paddingBottom: 10,
		...Platform.select({
			ios: {
				fontWeight: '500',
			},
			android: {
				fontWeight: '600',
			},
		}),
	},
})

export const SelectableCell = ({text}: {text: string}) => (
	<TextInput
		dataDetectorTypes="all"
		editable={false}
		multiline={true}
		style={styles.text}
		value={entities.decode(text)}
	/>
)
<commit_msg>Remove font boldening from selectable text<commit_after>// @flow
import * as React from 'react'
import {TextInput, StyleSheet} from 'react-native'
import * as c from '../../components/colors'
import {AllHtmlEntities} from 'html-entities'

const entities = new AllHtmlEntities()

const styles = StyleSheet.create({
	text: {
		color: c.black,
		backgroundColor: c.white,
		paddingHorizontal: 15,
		paddingTop: 10,
		paddingBottom: 10,
	},
})

export const SelectableCell = ({text}: {text: string}) => (
	<TextInput
		dataDetectorTypes="all"
		editable={false}
		multiline={true}
		style={styles.text}
		value={entities.decode(text)}
	/>
)
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import {Text, StyleSheet} from 'react-native'
import * as c from '../colors'

const styles = StyleSheet.create({
  footer: {
    fontSize: 10,
    color: c.iosDisabledText,
    textAlign: 'center',
  },
  poweredBy: {
    paddingBottom: 20,
  },
})

export class ListFooter extends React.PureComponent {
  props: {
    title: string,
    href: string,
  }

  render() {
    const {title} = this.props
    return (
      <Text selectable={true} style={[styles.footer, styles.poweredBy]}>
        {title}
      </Text>
    )
  }
}
<commit_msg>tweak the padding on the list footer<commit_after>// @flow
import React from 'react'
import {Text, StyleSheet} from 'react-native'
import * as c from '../colors'

const styles = StyleSheet.create({
  footer: {
    fontSize: 10,
    color: c.iosDisabledText,
    textAlign: 'center',
    paddingVertical: 20,
    paddingBottom: 25,
  },
})

export class ListFooter extends React.PureComponent {
  props: {
    title: string,
    href: string,
  }

  render() {
    const {title} = this.props
    return (
      <Text selectable={true} style={[styles.footer]}>
        {title}
      </Text>
    )
  }
}
<|endoftext|>


<commit_before>import Vue from 'vue';
import store from '~/ide/stores';
import ide from '~/ide/components/ide.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers';

describe('ide component', () => {
  let vm;

  beforeEach(() => {
    const Component = Vue.extend(ide);

    vm = createComponentWithStore(Component, store, {
      emptyStateSvgPath: 'svg',
      noChangesStateSvgPath: 'svg',
      committedStateSvgPath: 'svg',
    }).$mount();
  });

  afterEach(() => {
    vm.$destroy();

    resetStore(vm.$store);
  });

  it('does not render panel right when no files open', () => {
    expect(vm.$el.querySelector('.panel-right')).toBeNull();
  });

  it('renders panel right when files are open', done => {
    vm.$store.state.trees['abcproject/mybranch'] = {
      tree: [file()],
    };

    Vue.nextTick(() => {
      expect(vm.$el.querySelector('.panel-right')).toBeNull();

      done();
    });
  });
});
<commit_msg>fixed ide_spec.js<commit_after>import Vue from 'vue';
import store from '~/ide/stores';
import ide from '~/ide/components/ide.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers';
import { projectData } from '../mock_data';

describe('ide component', () => {
  let vm;

  beforeEach(() => {
    const Component = Vue.extend(ide);

    store.state.currentProjectId = 'abcproject';
    store.state.currentBranchId = 'master';
    store.state.projects.abcproject = Object.assign({}, projectData);

    vm = createComponentWithStore(Component, store, {
      emptyStateSvgPath: 'svg',
      noChangesStateSvgPath: 'svg',
      committedStateSvgPath: 'svg',
    }).$mount();
  });

  afterEach(() => {
    vm.$destroy();

    resetStore(vm.$store);
  });

  it('does not render right right when no files open', () => {
    expect(vm.$el.querySelector('.panel-right')).toBeNull();
  });

  it('renders right panel when files are open', done => {
    vm.$store.state.trees['abcproject/mybranch'] = {
      tree: [file()],
    };

    Vue.nextTick(() => {
      expect(vm.$el.querySelector('.panel-right')).toBeNull();

      done();
    });
  });
});
<|endoftext|>


<commit_before>/**
 *
 *  Copyright 2016 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
import * as THREE from 'three';
import GlobalStyles from '../globalStyles';
import NodeView from '../base/nodeView';

class DnsNodeView extends NodeView {
  constructor (service) {
    super(service);
    this.radius = this.object.size;
    this.innerRadius = this.radius * 0.8;
    this.meshes.outerBorder = this.addChildElement(NodeView.getOuterBorderGeometry(this.radius), this.borderMaterial);
    this.meshes.innerCircle = this.addChildElement(NodeView.getInnerCircleGeometry(this.radius), this.innerCircleMaterial);
    this.meshes.innerCircle.position.setZ(-10);

    this.canvasWidth = this.innerRadius * 2;
    this.canvasHeight = this.canvasWidth;

    this.textCanvas = this.createCanvas(this.canvasWidth, this.canvasHeight);
    this.textTexture = new THREE.Texture(this.textCanvas);
    this.textTexture.minFilter = THREE.LinearFilter;
    this.textTexture.needsUpdate = true;

    this.textMaterial = new THREE.MeshBasicMaterial({ map: this.textTexture, side: THREE.DoubleSide, transparent: true });
    const text = new THREE.Mesh(new THREE.PlaneBufferGeometry(this.textCanvas.width, this.textCanvas.height), this.textMaterial);
    this.container.add(text);
    this.addInteractiveChild(text);
    text.position.set(0, 0, this.depth + 1);

    const textContext = this.textCanvas.getContext('2d');
    let top = 0;
    textContext.clearRect(0, 0, this.textCanvas.width, this.textCanvas.height);

    this.headerFontSize = (this.canvasHeight) * 0.2;
    textContext.fillStyle = GlobalStyles.getColorTraffic(this.object.getClass());
    textContext.font = `700 ${this.headerFontSize}px 'Source Sans Pro', sans-serif`;

    top += (this.canvasWidth / 2);
    textContext.fillText(this.object.name, this.textCanvas.width / 2, top);

    this.textTexture.needsUpdate = true;
  }
}

export default DnsNodeView;
<commit_msg>Update dnsNodeView.js<commit_after>/**
 *
 *  Copyright 2016 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
import * as THREE from 'three';
import GlobalStyles from '../globalStyles';
import NodeView from '../base/nodeView';

class DnsNodeView extends NodeView {
  constructor (service) {
    super(service);
    this.radius = this.object.size;
    this.innerRadius = this.radius * 0.8;
    this.meshes.outerBorder = this.addChildElement(NodeView.getOuterBorderGeometry(this.radius), this.borderMaterial);
    this.meshes.innerCircle = this.addChildElement(NodeView.getInnerCircleGeometry(this.radius), this.innerCircleMaterial);
    this.meshes.innerCircle.position.setZ(-10);

    this.canvasWidth = this.innerRadius * 2;
    this.canvasHeight = this.canvasWidth;

    this.textCanvas = this.createCanvas(this.canvasWidth, this.canvasHeight);
    this.textTexture = new THREE.Texture(this.textCanvas);
    this.textTexture.minFilter = THREE.LinearFilter;
    this.textTexture.needsUpdate = true;

    this.textMaterial = new THREE.MeshBasicMaterial({ map: this.textTexture, side: THREE.DoubleSide, transparent: true });
    const text = new THREE.Mesh(new THREE.PlaneBufferGeometry(this.textCanvas.width, this.textCanvas.height), this.textMaterial);
    this.container.add(text);
    this.addInteractiveChild(text);
    text.position.set(0, 0, this.depth + 1);

    const textContext = this.textCanvas.getContext('2d');
    let top = 0;
    textContext.clearRect(0, 0, this.textCanvas.width, this.textCanvas.height);

    this.headerFontSize = (this.canvasHeight) * 0.2;
    textContext.fillStyle = GlobalStyles.getColorTraffic(this.object.getClass());
    textContext.font = `700 ${this.headerFontSize}px 'Source Sans Pro', sans-serif`;

    top += (this.canvasWidth / 2);
    textContext.fillText(this.object.getDisplayName(), this.textCanvas.width / 2, top);

    this.textTexture.needsUpdate = true;
  }
}

export default DnsNodeView;
<|endoftext|>


<commit_before>// the initialisation methods to be called when the document is ready
var initialisations = [];

// the scripts to be appended to the document's head when the document is ready
var scripts = [];

// the links to be appended to the document's head when the document is ready
var links = [];

// indicates whether or not the document has loaded all its resources
var ready = false;

var INDICATOR_CLASSNAME = "cargo-load";
var INDICATOR_CLASSNAME_IDLE = "idle";
var INDICATOR_CLASSNAME_ACTIVE = "active";

var INDICATOR_LABEL_INITIATION = "calling %1()";
var INDICATOR_LABEL_SCRIPT = "loading script %1";
var INDICATOR_LABEL_LINK = "loading resource %1";

// used to store JSON temporarily
var tempJSON = null;

// call all initialisation functions and load all scripts and links when the
// document is ready
window.onload = function() {
	ready = true;

	initialiseIndicators(initialisations.length + scripts.length + links.length);

	for (var i = 0; i < initiations.length; i++) {
		updateIndicators(INDICATOR_LABEL_INITIATION.replace("%1",
				initialisations[i].name));

		initialisations[i]();
	}

	for (var i = 0; i < scripts.length; i++) {
		updateIndicators(INDICATOR_LABEL_SCRIPT.replace("%1", scripts[i].src));

		document.head.appendChild(scripts[i]);
	}

	for (var i = 0; i < links.length; i++) {
		updateIndicators(INDICATOR_LABEL_LINK.replace("%1", links[i].href));

		document.head.appendChild(links[i]);
	}

	finishIndicators();
};

/**
 * The specified function will be called when the document is ready. If the
 * document is already ready it will be called immediately.
 *
 * @param initiate
 *            The function the be called when the document is ready.
 */
function onReady(initialisation) {
	if (ready) {
		initialisation();
	} else {
		initiations.push(initialisation);
	}
}

/**
 * Load the script at the specified source when the document is ready.
 *
 * @param src
 *            The source of the script to be loaded.
 * @param async
 *            Whether or not the script should run asynchronous.
 * @return The loaded script.
 */
function loadScript(src, async) {
	var script = document.createElement("script");

	script.src = src;

	if (async === undefined) {
		script.async = async;
	}

	if (ready) {
		document.head.appendChild(script);
	} else {
		scripts.push(script);
	}

	return script;
}

/**
 * Load the resource with the specified reference, type and relationship.
 *
 * @param href
 *            The reference to the resource to be loaded.
 * @param type
 *            The type of the resource to be loaded.
 * @param rel
 *            The relationship of the resource to be loaded.
 * @return The loaded link.
 */
function loadLink(href, type, rel) {
	var link = document.createElement("link");

	link.href = href;
	link.type = type;
	link.rel = rel;

	if (ready) {
		document.head.appendChild(link);
	} else {
		links.push(link);
	}

	return link;
}

/**
 * Load a JSONP file from the specified source. When loaded the specified
 * callback function will be called with the JSON data as the first parameter.
 *
 * @param src
 *            The source of the JSONP file.
 * @param callback
 *            The function to call when the JSONP file is loaded with the
 *            contained JSON data as the first parameter.
 */
function loadJSONP(src, callback) {
	loadScript(src + "&callback=" + callback.name, true);
}

/**
 * Initialise the indicators in the current document by setting the size and to
 * current step (0).
 *
 * @param size
 *            The size of the indicator.
 */
function initialiseIndicators(size) {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		indicators[i].dataset.cargoSize = size;
		indicators[i].dataset.cargoStep = 0;

		indicators[i].classList.remove(INDICATOR_CLASSNAME_IDLE);
		indicators[i].classList.add(INDICATOR_CLASSNAME_ACTIVE);
	}
}

/**
 * Update the indicator by incrementing the step and assigning it with the
 * specified label.
 *
 * @param label
 *            The label of the next step.
 */
function updateIndicators(label) {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		var step = parseInt(indicators[i].dataset.cargoStep);
		var size = parseInt(indicators[i].dataset.cargoSize);

		step++;

		indicators[i].dataset.cargoStep = step;
		indicators[i].dataset.cargoLabel = label;
		indicators[i].dataset.cargoPercentageDone = (step / size) * 100;
		indicators[i].dataset.cargoPercentageLeft = 100 - (step / size) * 100;
	}
}

/**
 * Finalise the indicators in the current document by removing all data.
 */
function finaliseIndicators() {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		delete indicators[i].dataset.cargoSize;
		delete indicators[i].dataset.cargoStep;
		delete indicators[i].dataset.cargoLabel;
		delete indicators[i].dataset.cargoPercentageDone;
		delete indicators[i].dataset.cargoPercentageLeft;

		indicators[i].classList.remove(INDICATOR_CLASSNAME_ACTIVE);
		indicators[i].classList.add(INDICATOR_CLASSNAME_IDLE);
	}
}<commit_msg>Fixed some functions calling other function by their old name<commit_after>// the initialisation methods to be called when the document is ready
var initialisations = [];

// the scripts to be appended to the document's head when the document is ready
var scripts = [];

// the links to be appended to the document's head when the document is ready
var links = [];

// indicates whether or not the document has loaded all its resources
var ready = false;

var INDICATOR_CLASSNAME = "cargo-load";
var INDICATOR_CLASSNAME_IDLE = "idle";
var INDICATOR_CLASSNAME_ACTIVE = "active";

var INDICATOR_LABEL_INITIATION = "calling %1()";
var INDICATOR_LABEL_SCRIPT = "loading script %1";
var INDICATOR_LABEL_LINK = "loading resource %1";

// used to store JSON temporarily
var tempJSON = null;

// call all initialisation functions and load all scripts and links when the
// document is ready
window.onload = function() {
	ready = true;

	initialiseIndicators(initialisations.length + scripts.length + links.length);

	for (var i = 0; i < initialisations.length; i++) {
		updateIndicators(INDICATOR_LABEL_INITIATION.replace("%1",
				initialisations[i].name));

		initialisations[i]();
	}

	for (var i = 0; i < scripts.length; i++) {
		updateIndicators(INDICATOR_LABEL_SCRIPT.replace("%1", scripts[i].src));

		document.head.appendChild(scripts[i]);
	}

	for (var i = 0; i < links.length; i++) {
		updateIndicators(INDICATOR_LABEL_LINK.replace("%1", links[i].href));

		document.head.appendChild(links[i]);
	}

	finaliseIndicators();
};

/**
 * The specified function will be called when the document is ready. If the
 * document is already ready it will be called immediately.
 *
 * @param initiate
 *            The function the be called when the document is ready.
 */
function onReady(initialisation) {
	if (ready) {
		initialisation();
	} else {
		initialisations.push(initialisation);
	}
}

/**
 * Load the script at the specified source when the document is ready.
 *
 * @param src
 *            The source of the script to be loaded.
 * @param async
 *            Whether or not the script should run asynchronous.
 * @return The loaded script.
 */
function loadScript(src, async) {
	var script = document.createElement("script");

	script.src = src;

	if (async === undefined) {
		script.async = async;
	}

	if (ready) {
		document.head.appendChild(script);
	} else {
		scripts.push(script);
	}

	return script;
}

/**
 * Load the resource with the specified reference, type and relationship.
 *
 * @param href
 *            The reference to the resource to be loaded.
 * @param type
 *            The type of the resource to be loaded.
 * @param rel
 *            The relationship of the resource to be loaded.
 * @return The loaded link.
 */
function loadLink(href, type, rel) {
	var link = document.createElement("link");

	link.href = href;
	link.type = type;
	link.rel = rel;

	if (ready) {
		document.head.appendChild(link);
	} else {
		links.push(link);
	}

	return link;
}

/**
 * Load a JSONP file from the specified source. When loaded the specified
 * callback function will be called with the JSON data as the first parameter.
 *
 * @param src
 *            The source of the JSONP file.
 * @param callback
 *            The function to call when the JSONP file is loaded with the
 *            contained JSON data as the first parameter.
 */
function loadJSONP(src, callback) {
	loadScript(src + "&callback=" + callback.name, true);
}

/**
 * Initialise the indicators in the current document by setting the size and to
 * current step (0).
 *
 * @param size
 *            The size of the indicator.
 */
function initialiseIndicators(size) {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		indicators[i].dataset.cargoSize = size;
		indicators[i].dataset.cargoStep = 0;

		indicators[i].classList.remove(INDICATOR_CLASSNAME_IDLE);
		indicators[i].classList.add(INDICATOR_CLASSNAME_ACTIVE);
	}
}

/**
 * Update the indicator by incrementing the step and assigning it with the
 * specified label.
 *
 * @param label
 *            The label of the next step.
 */
function updateIndicators(label) {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		var step = parseInt(indicators[i].dataset.cargoStep);
		var size = parseInt(indicators[i].dataset.cargoSize);

		step++;

		indicators[i].dataset.cargoStep = step;
		indicators[i].dataset.cargoLabel = label;
		indicators[i].dataset.cargoPercentageDone = (step / size) * 100;
		indicators[i].dataset.cargoPercentageLeft = 100 - (step / size) * 100;
	}
}

/**
 * Finalise the indicators in the current document by removing all data.
 */
function finaliseIndicators() {
	var indicators = document.getElementsByClassName(INDICATOR_CLASSNAME);

	for (var i = 0; i < indicators.length; i++) {
		delete indicators[i].dataset.cargoSize;
		delete indicators[i].dataset.cargoStep;
		delete indicators[i].dataset.cargoLabel;
		delete indicators[i].dataset.cargoPercentageDone;
		delete indicators[i].dataset.cargoPercentageLeft;

		indicators[i].classList.remove(INDICATOR_CLASSNAME_ACTIVE);
		indicators[i].classList.add(INDICATOR_CLASSNAME_IDLE);
	}
}<|endoftext|>


<commit_before>const path = require("path")
const { defaultFrontmatter } = require("./lib/frontmatter")

const PRODUCTION = process.env.NODE_ENV === "production"

const dateRegex = /\d{4}-\d{2}-\d{2}-/
const pageQueryFilter = PRODUCTION
  ? "filter: { frontmatter: { draft: { ne: true } } }"
  : ""
const pageQuery = `
  {
    allMarkdownRemark(${pageQueryFilter}) {
      edges {
        node {
          frontmatter {
            draft
          }
          fields {
            slug
            source
          }
        }
      }
    }
  }
`

exports.onCreateNode = ({ node, getNode, actions: { createNodeField } }) => {
  if (node.internal.type !== "MarkdownRemark") return

  if (node.hasOwnProperty("frontmatter")) {
    for (const property in defaultFrontmatter) {
      if (!node.frontmatter.hasOwnProperty(property)) {
        node.frontmatter[property] = defaultFrontmatter[property]
      }
    }
  }

  const { ext, relativeDirectory, relativePath } = getNode(node.parent)
  const slug = relativePath.replace(dateRegex, "").replace(ext, "")

  createNodeField({ node, name: "slug", value: slug })
  createNodeField({
    node,
    name: "source",
    value: relativeDirectory === "" ? "pages" : relativeDirectory,
  })
}

exports.createPages = async ({ graphql, actions: { createPage } }) => {
  const counts = {
    articles: 0,
  }
  const perPage = {
    articles: 10,
  }

  const {
    data: {
      allMarkdownRemark: { edges: pages },
    },
  } = await graphql(pageQuery)

  pages.forEach(
    ({
      node: {
        frontmatter: { draft },
        fields: { slug, source },
      },
    }) => {
      if (!draft && counts.hasOwnProperty(source)) counts[source] += 1

      createPage({
        path: slug,
        component: path.resolve(`./src/templates/${source}.jsx`),
        context: { slug },
      })
    }
  )

  for (let source in counts) {
    const numPages = Math.ceil(counts[source] / perPage[source])
    const root = source === "articles" ? "/" : `/${source}/`
    Array.from({ length: numPages }).forEach((_, i) => {
      const page = i + 1
      createPage({
        path: i === 0 ? root : `${root}page/${page}`,
        component: path.resolve(`./src/templates/${source}-list.jsx`),
        context: {
          page,
          numPages,
          limit: perPage[source],
          skip: i * perPage[source],
        },
      })
    })
  }
}
<commit_msg>Fix page query in development<commit_after>const path = require("path")
const { defaultFrontmatter } = require("./lib/frontmatter")

const PRODUCTION = process.env.NODE_ENV === "production"

const dateRegex = /\d{4}-\d{2}-\d{2}-/
const pageQueryFilter = PRODUCTION
  ? "(filter: { frontmatter: { draft: { ne: true } } })"
  : ""
const pageQuery = `
  {
    allMarkdownRemark${pageQueryFilter} {
      edges {
        node {
          frontmatter {
            draft
          }
          fields {
            slug
            source
          }
        }
      }
    }
  }
`

exports.onCreateNode = ({ node, getNode, actions: { createNodeField } }) => {
  if (node.internal.type !== "MarkdownRemark") return

  if (node.hasOwnProperty("frontmatter")) {
    for (const property in defaultFrontmatter) {
      if (!node.frontmatter.hasOwnProperty(property)) {
        node.frontmatter[property] = defaultFrontmatter[property]
      }
    }
  }

  const { ext, relativeDirectory, relativePath } = getNode(node.parent)
  const slug = relativePath.replace(dateRegex, "").replace(ext, "")

  createNodeField({ node, name: "slug", value: slug })
  createNodeField({
    node,
    name: "source",
    value: relativeDirectory === "" ? "pages" : relativeDirectory,
  })
}

exports.createPages = async ({ graphql, actions: { createPage } }) => {
  const counts = {
    articles: 0,
  }
  const perPage = {
    articles: 10,
  }

  const {
    data: {
      allMarkdownRemark: { edges: pages },
    },
  } = await graphql(pageQuery)

  pages.forEach(
    ({
      node: {
        frontmatter: { draft },
        fields: { slug, source },
      },
    }) => {
      if (!draft && counts.hasOwnProperty(source)) counts[source] += 1

      createPage({
        path: slug,
        component: path.resolve(`./src/templates/${source}.jsx`),
        context: { slug },
      })
    }
  )

  for (let source in counts) {
    const numPages = Math.ceil(counts[source] / perPage[source])
    const root = source === "articles" ? "/" : `/${source}/`
    Array.from({ length: numPages }).forEach((_, i) => {
      const page = i + 1
      createPage({
        path: i === 0 ? root : `${root}page/${page}`,
        component: path.resolve(`./src/templates/${source}-list.jsx`),
        context: {
          page,
          numPages,
          limit: perPage[source],
          skip: i * perPage[source],
        },
      })
    })
  }
}
<|endoftext|>


<commit_before>/*
 * Portal Module
 */
var PortalModule = (function () {

    // Module classes
    var Portal = function(_portal_id){
        this.portal_id = _portal_id;
    };

    Portal.prototype.AddListener = function(lib_ref, engine_ref, player)
    {
        this.body.createBodyCallback(player, function(body1, body2) {
            engine_ref.maps[this.source_level].Destroy(lib_ref.game);
            engine_ref.maps[this.destination_level].Create(lib_ref.game);
            engine_ref.curr_map = this.destination_level;

            // Check for the bot hitting another object
            for (var i=0; i<engine_ref.maps[engine_ref.curr_map].bots.length; ++i)
                engine_ref.player.body.createBodyCallback(engine_ref.maps[engine_ref.curr_map].bots[i], player.getHit, lib_ref);

            engine_ref.maps[engine_ref.curr_map].ActivatePortals(lib_ref, engine_ref, player);

            this.sprite.destroy();
        }, this);
    };

    Portal.prototype.Create = function(handler, _x, _y, source, destination)
    {
        // Capure handler
        this.handler_ref = handler;

        this.source_level = source;
        this.destination_level = destination;

        // Add the sprite object
        this.sprite = handler.add.sprite(_x, _y, this.portal_id);
        handler.physics.p2.enable(this.sprite);
        this.sprite.body.setZeroDamping();
        this.sprite.body.static = true;

        // add a reference-to-body to this
        this.body = this.sprite.body;

        this.body.portal = this;

    };

    // Public interface
    return {

        // Portal class factory
        CreatePortal: function(_portal_id){
            return new Portal(_portal_id);
        }
    };
})();
<commit_msg>make player collide with world bounds on every map<commit_after>/*
 * Portal Module
 */
var PortalModule = (function () {

    // Module classes
    var Portal = function(_portal_id){
        this.portal_id = _portal_id;
    };

    Portal.prototype.AddListener = function(lib_ref, engine_ref, player)
    {
        this.body.createBodyCallback(player, function(body1, body2) {
            engine_ref.maps[this.source_level].Destroy(lib_ref.game);
            engine_ref.maps[this.destination_level].Create(lib_ref.game);
            engine_ref.curr_map = this.destination_level;

            // Check for the bot hitting another object
            for (var i=0; i<engine_ref.maps[engine_ref.curr_map].bots.length; ++i)
                engine_ref.player.body.createBodyCallback(engine_ref.maps[engine_ref.curr_map].bots[i], player.getHit, lib_ref);

            lib_ref.game.physics.p2.setBoundsToWorld(true, true, true, true, false);
            engine_ref.maps[engine_ref.curr_map].ActivatePortals(lib_ref, engine_ref, player);

            this.sprite.destroy();
        }, this);
    };

    Portal.prototype.Create = function(handler, _x, _y, source, destination)
    {
        // Capure handler
        this.handler_ref = handler;

        this.source_level = source;
        this.destination_level = destination;

        // Add the sprite object
        this.sprite = handler.add.sprite(_x, _y, this.portal_id);
        handler.physics.p2.enable(this.sprite);
        this.sprite.body.setZeroDamping();
        this.sprite.body.static = true;

        // add a reference-to-body to this
        this.body = this.sprite.body;

        this.body.portal = this;

    };

    // Public interface
    return {

        // Portal class factory
        CreatePortal: function(_portal_id){
            return new Portal(_portal_id);
        }
    };
})();
<|endoftext|>


<commit_before>/**
 * @module myModule
 * @summary: This module's purpose is to:
 *
 * @description:
 *
 * Author: Justin Mooser
 * Created On: 2015-06-01.
 * @license Apache-2.0
 */

"use strict";

var util = require('util');

/**
 *
 * @param config
 * @param storage .save(): promise rejects if it should not be retried.
 * @param longTermStorage - .save(): resolves url to saved resource.  Rejects if it should not be retried.
 * @returns {{}}
 */
module.exports = function construct(config, storage, longTermStorage) {
  var m = {};
  config = config ? config : {};
  config = _.defaults(config, {
    saveEventsToLongTermStorage: true
  });

  m.processEvent = function(eventPayload, eventType) {
    var eventRow;
    return p.resolve().then(function() {
      return extractEventRow(eventPayload,eventType);
    })
    .then(function(eventrow) {
      eventRow = eventrow;
      console.log('Saving to S3...', eventRow.local_ts);
      return saveToLongTermStorage(eventRow, eventPayload)
        .then(function(result) {
          console.log('Done saving to S3...', eventRow.local_ts);
          return result;
        })
        .catch(function(err) {
          console.error('Failed to save to S3.', err);
        });
    })
    .then(function(longTermStorageUrl) {
      console.log('Saved to', longTermStorageUrl);
        // the database only allows 100 characters.
      if (eventRow.details.length && eventRow.details.length > 100) {
        eventRow.details = eventRow.details.substr(0, 99);
      }
      if(eventRow.label.length > 24) {
        eventRow.label = eventRow.label.substr(0,24);
      }
      eventRow.url = longTermStorageUrl;
      eventRow.timestamp = new Date().getTime();

      return storage.save('eventlog', eventRow)
        .catch(function(err) {
          console.error('Error saving tracked event to storage.');
          console.error(err);
        });
    })
    .catch(function(err) {
      console.error('Unexpected error processing tracked event.');
      console.error(err);
    });
  };

  function extractEventRow(eventPayload, eventType) {
    eventType = eventType || 'bunyan-v1';
    // you have to extract the payload and the essential details about the logged event.
    if (eventType=='bunyan-v1') {
      var details = extractDetailsObject(eventPayload);

      var eventRow = {
        details: JSON.stringify(details) || '{}',
        local_ts: Math.floor(Date.parse(eventPayload.time)/1000),
        component: eventPayload.name || 'unknown',
        host: eventPayload.hostname || 'unknown',
        label: eventPayload.eventLabel || 'unknown',
        env: eventPayload.env || 'env',
        pid: eventPayload.pid || 'unknown',
        app: (eventPayload.app || 'unknown') + (eventPayload.env || 'env'),
        version: eventType || 'unknown',
        level: eventPayload.level || 'unspecified'
      };

      eventRow.key = util.format('%s-%s', eventRow.app, eventRow.label);

      return eventRow;
    }
  }

  function fixJSON(str) {
    var json = str.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');
    json = json.replace(/\'/g, '"');
    return json;
  }

  function extractDetailsObject(eventPayload) {
    var msg = eventPayload.msg;

    var detailsObjectStart = msg.indexOf('{');
    var parse = false;
    if (detailsObjectStart>=0) {
      parse = true;
    }
    else {
      detailsObjectStart = msg.indexOf('[');
      if (detailsObjectStart >= 0) parse = true;
    }

    if (parse) {
      var json = fixJSON(msg.substr(detailsObjectStart));
      return JSON.parse(json);
    }

    return { details: msg.substr(eventPayload.eventLabel.length+1) };
  }

  /**
   * Container names are per application per environment.
   * @note: In S3 a container name would reference a bucket.
   */
  function chooseStorageContainerName(eventRow) {
    if (!eventRow.app) throw 'chooseStorageContainerName eventRow.app is empty';
    if (!eventRow.env) warn('chooseStorageContainerName eventRow.env is empty');
    return eventRow.app;
  }

  /**
   * Constructs an S3 friendly URL (uses random hash at start of key name to optimize S3 performance)
   * @param eventRow
   */
  function chooseStorageKey(eventRow) {
    return util.format("%s-%s.%s", new Date().toISOString(), eventRow.component, eventRow.version);
  }

  function saveToLongTermStorage(eventRow, eventPayload) {
    var container = chooseStorageContainerName(eventRow);
    var key = chooseStorageKey(eventRow);

    return longTermStorage.save(container, key, eventPayload);
  }

  return m;
};
<commit_msg>bugfix<commit_after>/**
 * @module myModule
 * @summary: This module's purpose is to:
 *
 * @description:
 *
 * Author: Justin Mooser
 * Created On: 2015-06-01.
 * @license Apache-2.0
 */

"use strict";

var util = require('util');

/**
 *
 * @param config
 * @param storage .save(): promise rejects if it should not be retried.
 * @param longTermStorage - .save(): resolves url to saved resource.  Rejects if it should not be retried.
 * @returns {{}}
 */
module.exports = function construct(config, storage, longTermStorage) {
  var m = {};
  config = config ? config : {};
  config = _.defaults(config, {
    saveEventsToLongTermStorage: true
  });

  m.processEvent = function(eventPayload, eventType) {
    var eventRow;
    return p.resolve().then(function() {
      return extractEventRow(eventPayload,eventType);
    })
    .then(function(eventrow) {
      eventRow = eventrow;
      console.log('Saving to S3...', eventRow.local_ts);
      return saveToLongTermStorage(eventRow, eventPayload)
        .then(function(result) {
          console.log('Done saving to S3...', eventRow.local_ts);
          return result;
        })
        .catch(function(err) {
          console.error('Failed to save to S3.', err);
        });
    })
    .then(function(longTermStorageUrl) {
      console.log('Saved to', longTermStorageUrl);
        // the database only allows 100 characters.
      if (eventRow.details.length && eventRow.details.length > 100) {
        eventRow.details = eventRow.details.substr(0, 99);
      }
      if(eventRow.label.length > 24) {
        eventRow.label = eventRow.label.substr(0,24);
      }
      eventRow.url = longTermStorageUrl;
      eventRow.timestamp = new Date().getTime();

      return storage.save('eventlog', eventRow)
        .catch(function(err) {
          console.error('Error saving tracked event to storage.');
          console.error(err);
        });
    })
    .catch(function(err) {
      console.error('Unexpected error processing tracked event.');
      console.error(err);
    });
  };

  function extractEventRow(eventPayload, eventType) {
    eventType = eventType || 'bunyan-v1';
    // you have to extract the payload and the essential details about the logged event.
    if (eventType=='bunyan-v1') {
      var details = extractDetailsObject(eventPayload);

      var eventRow = {
        details: JSON.stringify(details) || '{}',
        local_ts: Math.floor(Date.parse(eventPayload.time)/1000),
        component: eventPayload.name || 'unknown',
        host: eventPayload.hostname || 'unknown',
        label: eventPayload.eventLabel || 'unknown',
        env: eventPayload.env || 'env',
        pid: eventPayload.pid || 'unknown',
        app: (eventPayload.app || 'app') + '-' + (eventPayload.env || 'env'),
        version: eventType || 'unknown',
        level: eventPayload.level || 'unspecified'
      };

      eventRow.key = util.format('%s-%s', eventRow.app, eventRow.label);

      return eventRow;
    }
  }

  function fixJSON(str) {
    var json = str.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ');
    json = json.replace(/\'/g, '"');
    return json;
  }

  function extractDetailsObject(eventPayload) {
    var msg = eventPayload.msg;

    var detailsObjectStart = msg.indexOf('{');
    var parse = false;
    if (detailsObjectStart>=0) {
      parse = true;
    }
    else {
      detailsObjectStart = msg.indexOf('[');
      if (detailsObjectStart >= 0) parse = true;
    }

    if (parse) {
      var json = fixJSON(msg.substr(detailsObjectStart));
      return JSON.parse(json);
    }

    return { details: msg.substr(eventPayload.eventLabel.length+1) };
  }

  /**
   * Container names are per application per environment.
   * @note: In S3 a container name would reference a bucket.
   */
  function chooseStorageContainerName(eventRow) {
    if (!eventRow.app) throw 'chooseStorageContainerName eventRow.app is empty';
    if (!eventRow.env) warn('chooseStorageContainerName eventRow.env is empty');
    return eventRow.app;
  }

  /**
   * Constructs an S3 friendly URL (uses random hash at start of key name to optimize S3 performance)
   * @param eventRow
   */
  function chooseStorageKey(eventRow) {
    return util.format("%s-%s.%s", new Date().toISOString(), eventRow.component, eventRow.version);
  }

  function saveToLongTermStorage(eventRow, eventPayload) {
    var container = chooseStorageContainerName(eventRow);
    var key = chooseStorageKey(eventRow);

    return longTermStorage.save(container, key, eventPayload);
  }

  return m;
};
<|endoftext|>


<commit_before>"use strict";
(function(ADL){

	//Base chart class
	function Chart(opts)
	{
		this.opts = opts || {};

		if(this.opts.child){
			this.child = opts.child;
			this.opts.child.parent = this;
		}
	}

	Chart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum([{'values': obj}])
			.call(chart);
	};

	Chart.prototype.clear = function(container){
		var myNode = ADL.$(container ? container : this.opts.container);
		while (myNode.firstChild) {
			myNode.removeChild(myNode.firstChild);
		}

		if(this.child instanceof Array){
			for(var g = 0; g < this.child.length; g++){
				this.child[g].clear();
			}
		}
		else if(this.child){
			this.child.clear();
		}
	};

	Chart.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : self.opts.container;

		if((!opts.aggregate && !opts.process) || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		//If user specified a process, then call it, pass its results to d3, and return
		if(opts.process){
			addChart(self, opts.process.call(self, event), opts);
			return;
		}

		opts.cb = cb;
		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre.bind(self));
			}
			else{
				opts.pre.call(self, opts.data, event);
			}
		}

		opts.aggregate(opts, event);

		function cb(aggregateData){
			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			addChart(self, aggregateData, opts);
		};
	};

	Chart.prototype.addOptions = function(obj){
		for(var key in obj){
			this.opts[key] = obj[key];
		}
	};
	Chart.prototype.addParent = function(obj){
		this.parent = obj;
		obj.child = this;
	};
	Chart.prototype.addChild = function(obj){
		this.child = obj;
		obj.parent = this;
	};

	function addChart(self, aggregateData, opts){
		nv.addGraph(function(){
			var chart = nv.models[opts.chartType]().options(opts.nvd3Opts);

			if(chart.staggerLabels)
				chart.staggerLabels(false);

			if( opts.customize )
				opts.customize(chart, event);

			var next = self.child || self.parent;
			if(next && opts.eventChartType){

				//Find a way to prevent the addition of click handlers every time this chart is drawn
				chart[opts.eventChartType].dispatch.on("elementClick", function(e) {
					e.in = e.in ? e.in : e.point.in;
					e.out = e.out ? e.out : e.point.out;
					if(next instanceof Array){
						for(var i = 0; i < next.length; i++){
							if(self.opts.container == next[i].opts.container){
								self.clear();
							}

							next[i].event = e;
							next[i].draw();

							if(next[i].child instanceof Array){
								for(var g = 0; g < next[i].child.length; g++){
									next[i].child[g].clear();
								}
							}
							else if(next[i].child){
								next[i].child.clear();
							}
						}
					}
					else if(next){
						//If the containers are the same, then remove all nodes from the container
						if(self.opts.container == next.opts.container){
							var myNode = ADL.$(next.opts.container);
							while (myNode.firstChild) {
								myNode.removeChild(myNode.firstChild);
							}
						}

						if(next != self.parent)
							next.event = e;

						next.draw();
					}
				});
			}

			self.pipeData(aggregateData, chart);
			window.onResize = chart.update;

			//chart.update();
			return chart;
		});
	}

	//BarChart class extends Chart
	function BarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'discreteBarChart';
		this.opts.eventChartType = 'discretebar';

		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d){ return d.in; },
			'y': function(d){ return d.out; },
			'staggerLabels': true,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	BarChart.prototype = new Chart();
	BarChart.prototype.constructor = BarChart;

	//LineChart class extends Chart
	function LineChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'lineChart';
		//this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.accumulate;

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'showLegend': false,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	LineChart.prototype = new Chart();
	LineChart.prototype.constructor = LineChart;

	//PieChart class extends Chart
	function PieChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'pieChart';
		this.opts.eventChartType = 'pie';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in },
			'y': function(d,i){  return d.out },
			'transitionDuration': 250,
			'color': d3.scale.category20().range()
		};
	}

	PieChart.prototype = new Chart();
	PieChart.prototype.constructor = PieChart;

	PieChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//MultiBarChart class extends Chart
	function MultiBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'multiBarChart';
		this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'transitionDuration': 250,
			'groupSpacing': 0.25,
			//'stacked': true,
			'showControls': false,
			'margin': {left: 80, bottom: 100}
		};
	}

	MultiBarChart.prototype = new Chart();
	MultiBarChart.prototype.constructor = MultiBarChart;

	MultiBarChart.prototype.pipeData = function(obj, chart){
		console.log("MultiBar: ", obj);

		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//LinePlusBarChart class extends Chart
	function LinePlusBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'linePlusBarChart';
		//this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			x: function(d,i){ console.log(d.in.split('-')[0]); return d.in.split('-')[0]; },
			y: function(d,i){ console.log(d.out ? d.out : 0); return d.out ? d.out : 0; },
			showXAxis: true,
			showYAxis: true,
			transitionDuration: 250,
			margin: {top: 30, right: 60, bottom: 50, left: 70}
		};
	}

	LinePlusBarChart.prototype = new Chart();
	LinePlusBarChart.prototype.constructor = LinePlusBarChart;

	LinePlusBarChart.prototype.pipeData = function(obj, chart){
		var newArr = [];
		for(var i = 0; i < obj.length; i++){

			delete obj[i].series;
			if(obj[i].key != "groupStart" && obj[i].key != "groupEnd")
				newArr.push(obj[i]);
		}

		newArr[0].bar = true;

		console.log("Line+Bar: ", newArr);

		d3.select(this.opts.container)
			.datum(newArr)
			.call(chart);
	};

	//LinePlusBarChart class extends Chart
	function Table(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'table';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();
	}

	Table.prototype = new Chart();
	Table.prototype.constructor = Table;

	Table.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : this.opts.container;

		if(!opts.aggregate || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		opts.cb = function(aggregateData){

			if(opts.post)
				aggregateData = opts.post(aggregateData, event) || aggregateData;

			var markup = '
';

			if(aggregateData[0] && aggregateData[0].values){
				for(var i = -1; i < aggregateData[0].values.length; i++){

					var g = 0;
					markup += i >= 0 ? '
' + aggregateData[g].values[i].in + '	' : '
' + opts.groupBy +'	';

					for(; g < aggregateData.length; g++){
						if(i >= 0) markup += ''+aggregateData[g].values[i].out+'	';
						else markup += ''+aggregateData[g].key+'	';
					}

					markup += '
';
				}
			}

			else{
				markup += '
'+opts.groupBy+'	'+opts.xpath+'
';
				for(var i = 0; i < aggregateData.length; i++){
					markup += '
'+aggregateData[i].in+'	'+aggregateData[i].out+'
';
				}
			}

			markup += '
';
			ADL.$(container).innerHTML = markup;
		};

		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre(opts.data, event);
			}
		}

		opts.aggregate(opts, event);
	};

	ADL.Chart = Chart;
	ADL.BarChart = BarChart;
	ADL.LineChart = LineChart;
	ADL.MultiBarChart = MultiBarChart;
	ADL.PieChart = PieChart;
	ADL.LinePlusBarChart = LinePlusBarChart;
	ADL.Table = Table;

})(window.ADL = window.ADL || {});
<commit_msg>Fixed event not defined bug<commit_after>"use strict";
(function(ADL){

	//Base chart class
	function Chart(opts)
	{
		this.opts = opts || {};

		if(this.opts.child){
			this.child = opts.child;
			this.opts.child.parent = this;
		}
	}

	Chart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum([{'values': obj}])
			.call(chart);
	};

	Chart.prototype.clear = function(container){
		var myNode = ADL.$(container ? container : this.opts.container);
		while (myNode.firstChild) {
			myNode.removeChild(myNode.firstChild);
		}

		if(this.child instanceof Array){
			for(var g = 0; g < this.child.length; g++){
				this.child[g].clear();
			}
		}
		else if(this.child){
			this.child.clear();
		}
	};

	Chart.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : self.opts.container;

		if((!opts.aggregate && !opts.process) || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		//If user specified a process, then call it, pass its results to d3, and return
		if(opts.process){
			addChart(self, opts.process.call(self, event));
			return;
		}

		opts.cb = cb;
		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre.bind(self));
			}
			else{
				opts.pre.call(self, opts.data, event);
			}
		}

		opts.aggregate(opts, event);

		function cb(aggregateData){
			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			addChart(self, aggregateData, opts);
		};
	};

	Chart.prototype.addOptions = function(obj){
		for(var key in obj){
			this.opts[key] = obj[key];
		}
	};
	Chart.prototype.addParent = function(obj){
		this.parent = obj;
		obj.child = this;
	};
	Chart.prototype.addChild = function(obj){
		this.child = obj;
		obj.parent = this;
	};

	function addChart(self, aggregateData){
		var event = self.event, opts = self.opts;
		nv.addGraph(function(){
			var chart = nv.models[opts.chartType]().options(opts.nvd3Opts);

			if(chart.staggerLabels)
				chart.staggerLabels(false);

			if( opts.customize )
				opts.customize(chart, event);

			var next = self.child || self.parent;
			if(next && opts.eventChartType){

				//Find a way to prevent the addition of click handlers every time this chart is drawn
				chart[opts.eventChartType].dispatch.on("elementClick", function(e) {
					e.in = e.in ? e.in : e.point.in;
					e.out = e.out ? e.out : e.point.out;
					if(next instanceof Array){
						for(var i = 0; i < next.length; i++){
							if(self.opts.container == next[i].opts.container){
								self.clear();
							}

							next[i].event = e;
							next[i].draw();

							if(next[i].child instanceof Array){
								for(var g = 0; g < next[i].child.length; g++){
									next[i].child[g].clear();
								}
							}
							else if(next[i].child){
								next[i].child.clear();
							}
						}
					}
					else if(next){
						//If the containers are the same, then remove all nodes from the container
						if(self.opts.container == next.opts.container){
							var myNode = ADL.$(next.opts.container);
							while (myNode.firstChild) {
								myNode.removeChild(myNode.firstChild);
							}
						}

						if(next != self.parent)
							next.event = e;

						next.draw();
					}
				});
			}

			self.pipeData(aggregateData, chart);
			window.onResize = chart.update;

			//chart.update();
			return chart;
		});
	}

	//BarChart class extends Chart
	function BarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'discreteBarChart';
		this.opts.eventChartType = 'discretebar';

		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d){ return d.in; },
			'y': function(d){ return d.out; },
			'staggerLabels': true,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	BarChart.prototype = new Chart();
	BarChart.prototype.constructor = BarChart;

	//LineChart class extends Chart
	function LineChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'lineChart';
		//this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.accumulate;

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'showLegend': false,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	LineChart.prototype = new Chart();
	LineChart.prototype.constructor = LineChart;

	//PieChart class extends Chart
	function PieChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'pieChart';
		this.opts.eventChartType = 'pie';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in },
			'y': function(d,i){  return d.out },
			'transitionDuration': 250,
			'color': d3.scale.category20().range()
		};
	}

	PieChart.prototype = new Chart();
	PieChart.prototype.constructor = PieChart;

	PieChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//MultiBarChart class extends Chart
	function MultiBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'multiBarChart';
		this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'transitionDuration': 250,
			'groupSpacing': 0.25,
			//'stacked': true,
			'showControls': false,
			'margin': {left: 80, bottom: 100}
		};
	}

	MultiBarChart.prototype = new Chart();
	MultiBarChart.prototype.constructor = MultiBarChart;

	MultiBarChart.prototype.pipeData = function(obj, chart){
		console.log("MultiBar: ", obj);

		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//LinePlusBarChart class extends Chart
	function LinePlusBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'linePlusBarChart';
		//this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			x: function(d,i){ console.log(d.in.split('-')[0]); return d.in.split('-')[0]; },
			y: function(d,i){ console.log(d.out ? d.out : 0); return d.out ? d.out : 0; },
			showXAxis: true,
			showYAxis: true,
			transitionDuration: 250,
			margin: {top: 30, right: 60, bottom: 50, left: 70}
		};
	}

	LinePlusBarChart.prototype = new Chart();
	LinePlusBarChart.prototype.constructor = LinePlusBarChart;

	LinePlusBarChart.prototype.pipeData = function(obj, chart){
		var newArr = [];
		for(var i = 0; i < obj.length; i++){

			delete obj[i].series;
			if(obj[i].key != "groupStart" && obj[i].key != "groupEnd")
				newArr.push(obj[i]);
		}

		newArr[0].bar = true;

		console.log("Line+Bar: ", newArr);

		d3.select(this.opts.container)
			.datum(newArr)
			.call(chart);
	};

	//LinePlusBarChart class extends Chart
	function Table(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'table';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();
	}

	Table.prototype = new Chart();
	Table.prototype.constructor = Table;

	Table.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : this.opts.container;

		if(!opts.aggregate || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		opts.cb = function(aggregateData){

			if(opts.post)
				aggregateData = opts.post(aggregateData, event) || aggregateData;

			var markup = '
';

			if(aggregateData[0] && aggregateData[0].values){
				for(var i = -1; i < aggregateData[0].values.length; i++){

					var g = 0;
					markup += i >= 0 ? '
' + aggregateData[g].values[i].in + '	' : '
' + opts.groupBy +'	';

					for(; g < aggregateData.length; g++){
						if(i >= 0) markup += ''+aggregateData[g].values[i].out+'	';
						else markup += ''+aggregateData[g].key+'	';
					}

					markup += '
';
				}
			}

			else{
				markup += '
'+opts.groupBy+'	'+opts.xpath+'
';
				for(var i = 0; i < aggregateData.length; i++){
					markup += '
'+aggregateData[i].in+'	'+aggregateData[i].out+'
';
				}
			}

			markup += '
';
			ADL.$(container).innerHTML = markup;
		};

		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre(opts.data, event);
			}
		}

		opts.aggregate(opts, event);
	};

	ADL.Chart = Chart;
	ADL.BarChart = BarChart;
	ADL.LineChart = LineChart;
	ADL.MultiBarChart = MultiBarChart;
	ADL.PieChart = PieChart;
	ADL.LinePlusBarChart = LinePlusBarChart;
	ADL.Table = Table;

})(window.ADL = window.ADL || {});
<|endoftext|>


<commit_before>    function log(content) {
      document.body.appendChild(document.createTextNode(content + '\n'));
      console.log.apply(console, arguments);
    }

    window.onerror = function(err) {
      log("Error", err);
    };

    if (navigator.serviceWorker && navigator.serviceWorker.getRegistrations) {
          //启动的时候先反注册所有sw
          navigator.serviceWorker.getRegistration().then(function(registration) {
            if (registration) {
              registration.unregister('./');
            }

          })
      } else {
        setTimeout(function(){log("该浏览器不支持service worker")}, 1000)

      }

    var KTestTime = 32;

    function sendRequest(url, endFunction, index, count) {
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
          if (xhr.readyState == XMLHttpRequest.DONE) {

             if (++index < count) {

                sendRequest(url, endFunction, index, count)

             } else {

                endFunction(xhr)
             }

          }
      }
      xhr.open('GET', url + "&" + new Date().getTime(), true);
      xhr.send(null);

    }

    function startOriginalAjaxTest(){

      var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json?", function(xhr){

          var end = new Date().getTime();
          log("耗时 " +  (end - start));

      }, i , KTestTime);

    }

    function startSWAjaxTest(){

      navigator.serviceWorker.register('sw.js', {
        scope: './'
      }).then(function(sw) {
        log("注册成功", sw);
      }).catch(function(err) {
        log("Error", err);
      });

      var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json?fake", function(xhr){

          var end = new Date().getTime();
          log("SW注册后耗时 " + (end - start));

      }, i , KTestTime);

    }

    function startSWAjaxCacheTest() {

            var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json", function(xhr){

          var end = new Date().getTime();
          log("SW注册后缓存耗时 " + (end - start));

      }, i , KTestTime);

    }<commit_msg>no message<commit_after>    function log(content) {
      document.body.appendChild(document.createTextNode(content + '\n'));
      console.log.apply(console, arguments);
    }

    window.onerror = function(err) {
      log("Error", err);
    };

    if (navigator.serviceWorker && navigator.serviceWorker.getRegistrations) {
          //启动的时候先反注册所有sw
          navigator.serviceWorker.getRegistration().then(function(registration) {
            if (registration) {
              registration.unregister('./');
            }

          })
      } else {
        setTimeout(function(){log("该浏览器不支持service worker")}, 1000)

      }

    var KTestTime = 32;

    function sendRequest(url, endFunction, index, count) {
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
          if (xhr.readyState == XMLHttpRequest.DONE) {

             if (++index < count) {

                sendRequest(url, endFunction, index, count)

             } else {

                endFunction(xhr)
             }

          }
      }
      xhr.open('GET', url + "&" + new Date().getTime(), true);
      xhr.send(null);

    }

    function startOriginalAjaxTest(){

      var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json?", function(xhr){

          var end = new Date().getTime();
          log("耗时 " +  (end - start));

      }, i , KTestTime);

    }

    function startSWAjaxTest(){

      navigator.serviceWorker.register('sw.js', {
        scope: './'
      }).then(function(sw) {
        log("注册成功", sw);
      }).catch(function(err) {
        log("Error", err);
      });

      var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json?", function(xhr){

          var end = new Date().getTime();
          log("SW注册后耗时 " + (end - start));

      }, i , KTestTime);

    }

    function startSWAjaxCacheTest() {

            var start = new Date().getTime();

      var i = 0;

      sendRequest("jsonBig.json?fake", function(xhr){

          var end = new Date().getTime();
          log("SW注册后缓存耗时 " + (end - start));

      }, i , KTestTime);

    }<|endoftext|>


<commit_before>"use strict";
(function(ADL){

	//Base chart class
	function Chart(opts)
	{
		this.opts = opts || {};

		if(this.opts.child){
			this.child = opts.child;
			this.opts.child.parent = this;
		}
	}

	Chart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum([{'values': obj}])
			.call(chart);
	};

	Chart.prototype.clear = function(container){
		var myNode = ADL.$(container ? container : this.opts.container);
		while (myNode.firstChild) {
			myNode.removeChild(myNode.firstChild);
		}

		if(this.child instanceof Array){
			for(var g = 0; g < this.child.length; g++){
				this.child[g].clear();
			}
		}
		else if(this.child){
			this.child.clear();
		}
	};

	Chart.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : self.opts.container;

		if((!opts.aggregate && !opts.process) || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		//If user specified a process, then call it, pass its results to d3, and return
		if(opts.process){
			opts.cb = function(aggregateData){
				addChart(self, aggregateData);
			}
			opts.process.call(self, opts.data, event, opts)
			return;
		}

		opts.cb = cb;
		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre.call(self, opts.data, event);
			}
		}

		opts.aggregate(opts, event);

		function cb(aggregateData){
			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			addChart(self, aggregateData, opts);
		};
	};

	Chart.prototype.addOptions = function(obj){
		for(var key in obj){
			this.opts[key] = obj[key];
		}
	};
	Chart.prototype.addParent = function(obj){
		this.parent = obj;
		obj.child = this;
	};
	Chart.prototype.addChild = function(obj){
		this.child = obj;
		obj.parent = this;
	};
	Chart.prototype.getSVGDataURI = function(){
		return 'data:image/svg+xml;base64,' + btoa('<svg>' + ADL.$(this.opts.container).innerHTML + '</svg>');
	};
	Chart.prototype.getCSVString = function(){
		return this.opts.aggregateData;
	};
	Chart.prototype.getCSVDataURI = function(){
		return 'data:application/octet-stream;charset=utf-8;base64,' + btoa(this.getCSVString());
	};

	function addChart(self, aggregateData){
		var event = self.event, opts = self.opts;

		if(self.opts.chartType != 'multiBarChart'&& !(self.opts.chartType == 'table' && self.isMulti)){
			opts.aggregateData = ADL.CollectionSync.prototype.toCSV.call({contents:aggregateData});
		}
		else{
			opts.aggregateData = aggregateData;
		}

		nv.addGraph(function(){
			var chart = nv.models[opts.chartType]().options(opts.nvd3Opts);

			if(chart.staggerLabels)
				chart.staggerLabels(false);

			if( opts.customize )
				opts.customize(chart, event);

			var next = self.child || self.parent;
			if(next && opts.eventChartType){

				//Find a way to prevent the addition of click handlers every time this chart is drawn
				chart[opts.eventChartType].dispatch.on("elementClick", function(e) {
					e.in = e.in ? e.in : e.point.in;
					e.out = e.out ? e.out : e.point.out;
					if(next instanceof Array){
						for(var i = 0; i < next.length; i++){
							if(self.opts.container == next[i].opts.container){
								self.clear();
							}

							next[i].event = e;
							next[i].draw();

							if(next[i].child instanceof Array){
								for(var g = 0; g < next[i].child.length; g++){
									next[i].child[g].clear();
								}
							}
							else if(next[i].child){
								next[i].child.clear();
							}
						}
					}
					else if(next){
						//If the containers are the same, then remove all nodes from the container
						if(self.opts.container == next.opts.container){
							var myNode = ADL.$(next.opts.container);
							while (myNode.firstChild) {
								myNode.removeChild(myNode.firstChild);
							}
						}

						if(next != self.parent)
							next.event = e;

						next.draw();
					}
				});
			}

			self.pipeData(aggregateData, chart);
			window.onResize = chart.update;

			//chart.update();
			return chart;
		});
	}

	//BarChart class extends Chart
	function BarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'discreteBarChart';
		this.opts.eventChartType = 'discretebar';

		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d){ return d.in; },
			'y': function(d){ return d.out; },
			'staggerLabels': true,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	BarChart.prototype = new Chart();
	BarChart.prototype.constructor = BarChart;

	//LineChart class extends Chart
	function LineChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'lineChart';
		//this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.accumulate;

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'showLegend': false,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	LineChart.prototype = new Chart();
	LineChart.prototype.constructor = LineChart;

	//PieChart class extends Chart
	function PieChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'pieChart';
		this.opts.eventChartType = 'pie';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in },
			'y': function(d,i){  return d.out },
			'transitionDuration': 250,
			'color': d3.scale.category20().range()
		};
	}

	PieChart.prototype = new Chart();
	PieChart.prototype.constructor = PieChart;

	PieChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//MultiBarChart class extends Chart
	function MultiBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'multiBarChart';
		this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'transitionDuration': 250,
			'groupSpacing': 0.25,
			//'stacked': true,
			'showControls': false,
			'margin': {left: 80, bottom: 100}
		};
	}

	MultiBarChart.prototype = new Chart();
	MultiBarChart.prototype.constructor = MultiBarChart;

	MultiBarChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};
	MultiBarChart.prototype.getCSVString = function(){
		if(!Array.isArray(this.opts.aggregateData)){
			return '';
		}

		var str = '"' + this.opts.groupBy + '",', arr = this.opts.aggregateData;
		for(var i = 0; i < arr.length; i++){
			str += i == 0 ? '"' + arr[i].key + '"' : ',"' + arr[i].key + '"';
		}

		str += '\n';

		for(var g = 0; g < arr[0].values.length; g++){
			for(var i = 0; i < arr.length; i++){
				str += i == 0 ? '"' + arr[0].values[g].in + '"' + ',"' + arr[i].values[g].out + '"' :
					',"' + arr[i].values[g].out + '"';
			}
			str += '\n';
		}

		return str;
	};

	//LinePlusBarChart class extends Chart
	function LinePlusBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'linePlusBarChart';
		//this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			x: function(d,i){ console.log(d.in.split('-')[0]); return d.in.split('-')[0]; },
			y: function(d,i){ console.log(d.out ? d.out : 0); return d.out ? d.out : 0; },
			showXAxis: true,
			showYAxis: true,
			transitionDuration: 250,
			margin: {top: 30, right: 60, bottom: 50, left: 70}
		};
	}

	LinePlusBarChart.prototype = new Chart();
	LinePlusBarChart.prototype.constructor = LinePlusBarChart;

	LinePlusBarChart.prototype.pipeData = function(obj, chart){
		var newArr = [];
		for(var i = 0; i < obj.length; i++){

			delete obj[i].series;
			if(obj[i].key != "groupStart" && obj[i].key != "groupEnd")
				newArr.push(obj[i]);
		}

		newArr[0].bar = true;

		console.log("Line+Bar: ", newArr);

		d3.select(this.opts.container)
			.datum(newArr)
			.call(chart);
	};

	//Table class extends Chart
	function Table(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'table';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();
	}

	Table.prototype = new Chart();
	Table.prototype.constructor = Table;

	Table.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : this.opts.container;

		if(!opts.aggregate || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		opts.cb = function(aggregateData){

			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			var markup = '
';

			if(aggregateData[0] && aggregateData[0].values){
				self.isMulti = true;
				for(var i = -1; i < aggregateData[0].values.length; i++){

					var g = 0;
					markup += i >= 0 ? '
' + aggregateData[g].values[i].in + '	' : '
' + opts.groupBy +'	';

					for(; g < aggregateData.length; g++){
						if(i >= 0) markup += ''+aggregateData[g].values[i].out+'	';
						else markup += ''+aggregateData[g].key+'	';
					}

					markup += '
';
				}
			}

			else{
				self.isMulti = false;
				markup += '
'+opts.groupBy+'	'+opts.xpath+'
';
				for(var i = 0; i < aggregateData.length; i++){
					markup += '
'+aggregateData[i].in+'	'+aggregateData[i].out+'
';
				}
			}

			markup += '
';
			ADL.$(container).innerHTML = markup;

			if(!self.isMulti){
				opts.aggregateData = ADL.CollectionSync.prototype.toCSV.call({contents:aggregateData});
			}
			else{
				opts.aggregateData = aggregateData;
			}
		};

		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre(opts.data, event);
			}
		}

		opts.aggregate(opts, event);
	};

	Table.prototype.getCSVString = function(){
		if(this.isMulti){
			return MultiBarChart.prototype.getCSVString.call(this);
		}
		else{
			return Chart.prototype.getCSVString.call(this);
		}
	};
	Table.prototype.getSVGDataURI = function(){
		console.error("Tables do not support SVG Data URIs");
		return '';
	};

	ADL.Chart = Chart;
	ADL.BarChart = BarChart;
	ADL.LineChart = LineChart;
	ADL.MultiBarChart = MultiBarChart;
	ADL.PieChart = PieChart;
	ADL.LinePlusBarChart = LinePlusBarChart;
	ADL.Table = Table;

})(window.ADL = window.ADL || {});
<commit_msg>Always clear child charts before drawing<commit_after>"use strict";
(function(ADL){

	//Base chart class
	function Chart(opts)
	{
		this.opts = opts || {};

		if(this.opts.child){
			this.child = opts.child;
			this.opts.child.parent = this;
		}
	}

	Chart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum([{'values': obj}])
			.call(chart);
	};

	Chart.prototype.clear = function(container){
		var myNode = ADL.$(container ? container : this.opts.container);
		while (myNode.firstChild) {
			myNode.removeChild(myNode.firstChild);
		}

		if(this.child instanceof Array){
			for(var g = 0; g < this.child.length; g++){
				this.child[g].clear();
			}
		}
		else if(this.child){
			this.child.clear();
		}
	};

	Chart.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : self.opts.container;

		if((!opts.aggregate && !opts.process) || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		//If user specified a process, then call it, pass its results to d3, and return
		if(opts.process){
			opts.cb = function(aggregateData){
				addChart(self, aggregateData);
			}
			opts.process.call(self, opts.data, event, opts)
			return;
		}

		opts.cb = cb;
		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre.call(self, opts.data, event);
			}
		}

		opts.aggregate(opts, event);

		function cb(aggregateData){
			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			addChart(self, aggregateData, opts);
		};
	};

	Chart.prototype.addOptions = function(obj){
		for(var key in obj){
			this.opts[key] = obj[key];
		}
	};
	Chart.prototype.addParent = function(obj){
		this.parent = obj;
		obj.child = this;
	};
	Chart.prototype.addChild = function(obj){
		this.child = obj;
		obj.parent = this;
	};
	Chart.prototype.getSVGDataURI = function(){
		return 'data:image/svg+xml;base64,' + btoa('<svg>' + ADL.$(this.opts.container).innerHTML + '</svg>');
	};
	Chart.prototype.getCSVString = function(){
		return this.opts.aggregateData;
	};
	Chart.prototype.getCSVDataURI = function(){
		return 'data:application/octet-stream;charset=utf-8;base64,' + btoa(this.getCSVString());
	};

	function addChart(self, aggregateData){
		var event = self.event, opts = self.opts;

		if(self.opts.chartType != 'multiBarChart'&& !(self.opts.chartType == 'table' && self.isMulti)){
			opts.aggregateData = ADL.CollectionSync.prototype.toCSV.call({contents:aggregateData});
		}
		else{
			opts.aggregateData = aggregateData;
		}

		nv.addGraph(function(){
			var chart = nv.models[opts.chartType]().options(opts.nvd3Opts);

			if(chart.staggerLabels)
				chart.staggerLabels(false);

			if( opts.customize )
				opts.customize(chart, event);

			var next = self.child || self.parent;
			if(next && opts.eventChartType){

				//Find a way to prevent the addition of click handlers every time this chart is drawn
				chart[opts.eventChartType].dispatch.on("elementClick", function(e) {
					e.in = e.in ? e.in : e.point.in;
					e.out = e.out ? e.out : e.point.out;
					if(next instanceof Array){
						for(var i = 0; i < next.length; i++){
							//always clear the next chart before redrawing
							next[i].clear();

							next[i].event = e;
							next[i].draw();

							if(next[i].child instanceof Array){
								for(var g = 0; g < next[i].child.length; g++){
									next[i].child[g].clear();
								}
							}
							else if(next[i].child){
								next[i].child.clear();
							}
						}
					}
					else if(next){
						//always clear the next chart before redrawing
						next.clear();

						if(next != self.parent)
							next.event = e;

						next.draw();
					}
				});
			}

			self.pipeData(aggregateData, chart);
			window.onResize = chart.update;

			//chart.update();
			return chart;
		});
	}

	//BarChart class extends Chart
	function BarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'discreteBarChart';
		this.opts.eventChartType = 'discretebar';

		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d){ return d.in; },
			'y': function(d){ return d.out; },
			'staggerLabels': true,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	BarChart.prototype = new Chart();
	BarChart.prototype.constructor = BarChart;

	//LineChart class extends Chart
	function LineChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'lineChart';
		//this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.accumulate;

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'showLegend': false,
			'transitionDuration': 250,
			'margin': {left: 80, bottom: 100}
		};
	}

	LineChart.prototype = new Chart();
	LineChart.prototype.constructor = LineChart;

	//PieChart class extends Chart
	function PieChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'pieChart';
		this.opts.eventChartType = 'pie';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in },
			'y': function(d,i){  return d.out },
			'transitionDuration': 250,
			'color': d3.scale.category20().range()
		};
	}

	PieChart.prototype = new Chart();
	PieChart.prototype.constructor = PieChart;

	PieChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};

	//MultiBarChart class extends Chart
	function MultiBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'multiBarChart';
		this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			'x': function(d,i){ return d.in; },
			'y': function(d,i){ return d.out; },
			'showXAxis': true,
			'showYAxis': true,
			'transitionDuration': 250,
			'groupSpacing': 0.25,
			//'stacked': true,
			'showControls': false,
			'margin': {left: 80, bottom: 100}
		};
	}

	MultiBarChart.prototype = new Chart();
	MultiBarChart.prototype.constructor = MultiBarChart;

	MultiBarChart.prototype.pipeData = function(obj, chart){
		d3.select(this.opts.container)
			.datum(obj)
			.call(chart);
	};
	MultiBarChart.prototype.getCSVString = function(){
		if(!Array.isArray(this.opts.aggregateData)){
			return '';
		}

		var str = '"' + this.opts.groupBy + '",', arr = this.opts.aggregateData;
		for(var i = 0; i < arr.length; i++){
			str += i == 0 ? '"' + arr[i].key + '"' : ',"' + arr[i].key + '"';
		}

		str += '\n';

		for(var g = 0; g < arr[0].values.length; g++){
			for(var i = 0; i < arr.length; i++){
				str += i == 0 ? '"' + arr[0].values[g].in + '"' + ',"' + arr[i].values[g].out + '"' :
					',"' + arr[i].values[g].out + '"';
			}
			str += '\n';
		}

		return str;
	};

	//LinePlusBarChart class extends Chart
	function LinePlusBarChart(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'linePlusBarChart';
		//this.opts.eventChartType = 'multibar';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();

		this.opts.nvd3Opts = this.opts.nvd3Opts ? this.opts.nvd3Opts : {
			x: function(d,i){ console.log(d.in.split('-')[0]); return d.in.split('-')[0]; },
			y: function(d,i){ console.log(d.out ? d.out : 0); return d.out ? d.out : 0; },
			showXAxis: true,
			showYAxis: true,
			transitionDuration: 250,
			margin: {top: 30, right: 60, bottom: 50, left: 70}
		};
	}

	LinePlusBarChart.prototype = new Chart();
	LinePlusBarChart.prototype.constructor = LinePlusBarChart;

	LinePlusBarChart.prototype.pipeData = function(obj, chart){
		var newArr = [];
		for(var i = 0; i < obj.length; i++){

			delete obj[i].series;
			if(obj[i].key != "groupStart" && obj[i].key != "groupEnd")
				newArr.push(obj[i]);
		}

		newArr[0].bar = true;

		console.log("Line+Bar: ", newArr);

		d3.select(this.opts.container)
			.datum(newArr)
			.call(chart);
	};

	//Table class extends Chart
	function Table(opts){

		Chart.call(this, opts);

		this.opts.chartType = 'table';
		this.opts.aggregate = this.opts.aggregate ? this.opts.aggregate : ADL.count();
	}

	Table.prototype = new Chart();
	Table.prototype.constructor = Table;

	Table.prototype.draw = function(container){
		var	opts = this.opts,
			event = this.event,
			self = this;

		container = container ? container : this.opts.container;

		if(!opts.aggregate || !opts.chartType || !container){
			console.error("Must specify aggregate function, chartType, and container before drawing chart", opts);
			return;
		}

		opts.cb = function(aggregateData){

			if(opts.post){
				var tempCollection = new ADL.CollectionSync(aggregateData);
				var temp = opts.post.call(self, tempCollection, event) || tempCollection;

				//If temp is a collection, assign temp.contents. If not, then it's just an array.
				aggregateData = temp.contents && temp.contents.length >= 0 ? temp.contents : temp;
			}

			var markup = '
';

			if(aggregateData[0] && aggregateData[0].values){
				self.isMulti = true;
				for(var i = -1; i < aggregateData[0].values.length; i++){

					var g = 0;
					markup += i >= 0 ? '
' + aggregateData[g].values[i].in + '	' : '
' + opts.groupBy +'	';

					for(; g < aggregateData.length; g++){
						if(i >= 0) markup += ''+aggregateData[g].values[i].out+'	';
						else markup += ''+aggregateData[g].key+'	';
					}

					markup += '
';
				}
			}

			else{
				self.isMulti = false;
				markup += '
'+opts.groupBy+'	'+opts.xpath+'
';
				for(var i = 0; i < aggregateData.length; i++){
					markup += '
'+aggregateData[i].in+'	'+aggregateData[i].out+'
';
				}
			}

			markup += '
';
			ADL.$(container).innerHTML = markup;

			if(!self.isMulti){
				opts.aggregateData = ADL.CollectionSync.prototype.toCSV.call({contents:aggregateData});
			}
			else{
				opts.aggregateData = aggregateData;
			}
		};

		opts.data = opts.data.save();

		if(opts.pre){
			if(typeof opts.pre === "string"){
				opts.data.where(opts.pre);
			}
			else{
				opts.pre(opts.data, event);
			}
		}

		opts.aggregate(opts, event);
	};

	Table.prototype.getCSVString = function(){
		if(this.isMulti){
			return MultiBarChart.prototype.getCSVString.call(this);
		}
		else{
			return Chart.prototype.getCSVString.call(this);
		}
	};
	Table.prototype.getSVGDataURI = function(){
		console.error("Tables do not support SVG Data URIs");
		return '';
	};

	ADL.Chart = Chart;
	ADL.BarChart = BarChart;
	ADL.LineChart = LineChart;
	ADL.MultiBarChart = MultiBarChart;
	ADL.PieChart = PieChart;
	ADL.LinePlusBarChart = LinePlusBarChart;
	ADL.Table = Table;

})(window.ADL = window.ADL || {});
<|endoftext|>


<commit_before>#!/usr/bin/env node
var firebase = require('firebase'),
    optimist = require('optimist'),
    ProgressBar = require('progress'),
    assert = require('assert'),
    path = require('path'),
    fs = require('fs')
    JSONStream = require('JSONStream')
    util = require('util');

// We try to write data in ~1MB chunks (in reality this often ends up being much smaller, due to the JSON structure).
var CHUNK_SIZE = 1024*1024;

// Keep ~50 writes outstanding at a time (this increases throughput, so we're not delayed by server round-trips).
var OUTSTANDING_WRITE_COUNT = 50;

var argv = require('optimist')
  .usage('Usage: $0')

  .demand('database_url')
  .describe('database_url', 'Firebase database URL (e.g. https://databaseName.firebaseio.com).')
  .alias('d', 'database_url')

  .demand('path')
  .describe('path', 'Database path (e.g. /products).')
  .alias('p', 'path')

  .demand('json')
  .describe('json', 'The JSON file to import.')
  .alias('j', 'json')

  .boolean('merge')
  .describe('merge', 'Write the top-level children without overwriting the whole parent.')
  .alias('m', 'merge')

  .boolean('force')
  .describe('force', 'Don\'t prompt before overwriting data.')

  .describe('service_account', 'Path to a JSON file with your service account credentials.')
  .alias('s', 'service_account')

  .argv;

function main() {
  firebase.initializeApp({
    databaseURL: argv.database_url,
    serviceAccount: argv.service_account,
  });
  var db = firebase.database();
  var ref = db.ref(argv.path);

  var connFailTimeout = setTimeout(function() {
    console.log('Failed to connect to Firebase.');
    process.exit();
  }, 10000);

  function ready() {
    clearTimeout(connFailTimeout);
    promptToContinue(ref, function() { start(ref); });
  }

  var connFunc = db.ref('.info/connected').on('value', function(s) {
    if(s.val() === true) {
      db.ref('.info/connected').off('value', connFunc);
      ready();
    }
  });
}

function promptToContinue(ref, next) {
  if (argv.force) {
    next();
  } else {
    if (argv.merge) {
      console.log('Each top-level child in ' + argv.json + ' will be written under ' + ref.toString() + '.  If a child already exists, it will be overwritten.');
    } else {
      console.log('All data at ' + ref.toString() + ' will be overwritten.');
    }
    console.log('Press <enter> to proceed, Ctrl-C to abort.');
    process.stdin.resume();
    process.stdin.once('data', next);
  }
}

function getJsonFromFile(file, callback) {
  var firstChar;
  var rs = fs.createReadStream(file);
  rs.on('data', function(chunk) {
    var s = chunk.toString().trim();
    if (s !== "") {
      rs.close();
    }
    firstChar = s[0];
  })
  .on('close', function() {
    if (firstChar === "[" || firstChar === "{") {
      var jsonStream;
      var onFunc;
      var json;
      if (firstChar === "[") {
        console.log("Reading json as an array...");
        json = [];
        jsonStream = JSONStream.parse("*");
        onFunc = function(r) {
          json.push(r);
        };
      } else {
        console.log("Reading json as an object...");
        json = {};
        jsonStream = JSONStream.parse("$*");
        onFunc = function(r) {
          json[r.key] = r.value;
        };
      }
      fs.createReadStream(file)
      .pipe(jsonStream)
      .on('data', onFunc)
      .on('error', callback)
      .on('close', function() {
        return callback(null, json);
      });
    } else {
      var json = require(file);
      return callback(null, json);
    }
  });
}

function start(ref) {
  var file = path.resolve(argv.json);
  console.log('Reading ' + file + '... (may take a minute)');

  getJsonFromFile(file, function(err, json) {
    var clearFirst = true, splitTopLevel = false;
    if (argv.merge) {
      clearFirst = false;
      // Need to split into chunks at the top level to ensure we don't overwrite the parent.
      splitTopLevel = true;
    }

    console.log('Preparing JSON for import... (may take a minute)');
    var chunks = createChunks(ref, json, splitTopLevel);

    if (clearFirst) {
      ref.remove(function(error) {
        if (error) throw(error);
        uploadChunks(chunks);
      });
    } else {
      uploadChunks(chunks);
    }
  });
}

function uploadChunks(chunks) {
  var uploader = new ChunkUploader(chunks);
  uploader.go(function() {
    console.log('\nImport completed.');
    process.exit();
  });
}

function createChunks(ref, json, forceSplit) {
  var chunkRes = chunkInternal(ref, json, forceSplit);
  if (!chunkRes.chunks) {
    return [{ref: ref, json: json}];
  } else {
    return chunkRes.chunks;
  }
}

function chunkInternal(ref, json, forceSplit) {
  var size = 0;
  var priority = null;
  var jsonIsObject = json !== null && typeof json === 'object';
  if (jsonIsObject) {
    size += 2; // {}
  }

  if (jsonIsObject && ('.priority' in json)) {
    size += 12; // ".priority":
    priority = json['.priority'];
    size += json['.priority'].toString().length;
  }

  var value = json;
  if (jsonIsObject && ('.value' in json)) {
    size += 9; // ".value":
    value = json['.value'];
  }

  if (value === null || typeof value !== 'object') {
    // It's a leaf, it can't be chunked.
    size += JSON.stringify(value).length;
    return { chunks: null, size: size };
  } else {
    // children node.
    var chunks = [];
    var splitUp = false;
    for(var key in json) {
      if (key !== '.priority') {
        size += key.length + 3;

        var chunkRes = chunkInternal(ref.child(key), json[key]);
        size += chunkRes.size;

        if (chunkRes.chunks) {
          for(var i = 0; i < chunkRes.chunks.length; i++) {
            chunks.push(chunkRes.chunks[i]);
          }
          // One of the children had to be broken into chunks.  We have to break all of them.
          splitUp = true;
        } else {
          chunks.push({ref: ref.child(key), json: json[key]});
        }
      }
    }

    // Add priority last since it must be added after at least one child.
    if (priority !== null) {
      chunks.push({ref: ref, priority: priority});
    }

    if (forceSplit || splitUp || size >= CHUNK_SIZE) {
      return { chunks: chunks, size: size };
    } else {
      return { chunks: null, size: size }
    }
  }
}

function ChunkUploader(chunks) {
  this.next = 0;
  this.chunks = chunks;
  if (process.stdout.isTTY) {
      this.bar = new ProgressBar('Importing [:bar] :percent (:current/:total)', { width: 50, total: chunks.length, incomplete: ' ' });
  } else {
      console.log('Importing... (may take a while)');
  }
}

ChunkUploader.prototype.go = function(onComplete) {
  this.onComplete = onComplete;

  for(var i = 0; i < OUTSTANDING_WRITE_COUNT && i < this.chunks.length; i++) {
    this.uploadNext();
  }
};

ChunkUploader.prototype.uploadNext = function() {
  var chunkNum = this.next, chunk = this.chunks[chunkNum];
  assert(chunkNum < this.chunks.length);
  this.next++;

  var self = this;
  var onComplete = function(error) {
    if (error) {
      console.log('Error uploading to ' + self.chunks[i].ref.toString() + ': ' + util.inspect(json));
      console.error(error);
      throw error;
    }

    if (process.stdout.isTTY && self.bar) {
        self.bar.tick();
    }

    if (chunkNum === self.chunks.length - 1) {
      self.onComplete();
    } else {
      // upload next chunk.
      assert(self.next === self.chunks.length || self.next === chunkNum + OUTSTANDING_WRITE_COUNT);
      if (self.next < self.chunks.length)
        self.uploadNext();
    }
  };

  if ('json' in chunk) {
    chunk.ref.set(chunk.json, onComplete);
  } else {
    assert('priority' in chunk)
    chunk.ref.setPriority(chunk.priority, onComplete);
  }
}

main();
<commit_msg>Adjusted as per review requests.<commit_after>#!/usr/bin/env node
var firebase = require('firebase'),
    optimist = require('optimist'),
    ProgressBar = require('progress'),
    assert = require('assert'),
    path = require('path'),
    fs = require('fs'),
    JSONStream = require('JSONStream'),
    util = require('util');

// We try to write data in ~1MB chunks (in reality this often ends up being much smaller, due to the JSON structure).
var CHUNK_SIZE = 1024*1024;

// Keep ~50 writes outstanding at a time (this increases throughput, so we're not delayed by server round-trips).
var OUTSTANDING_WRITE_COUNT = 50;

var argv = require('optimist')
  .usage('Usage: $0')

  .demand('database_url')
  .describe('database_url', 'Firebase database URL (e.g. https://databaseName.firebaseio.com).')
  .alias('d', 'database_url')

  .demand('path')
  .describe('path', 'Database path (e.g. /products).')
  .alias('p', 'path')

  .demand('json')
  .describe('json', 'The JSON file to import.')
  .alias('j', 'json')

  .boolean('merge')
  .describe('merge', 'Write the top-level children without overwriting the whole parent.')
  .alias('m', 'merge')

  .boolean('force')
  .describe('force', 'Don\'t prompt before overwriting data.')

  .describe('service_account', 'Path to a JSON file with your service account credentials.')
  .alias('s', 'service_account')

  .argv;

function main() {
  firebase.initializeApp({
    databaseURL: argv.database_url,
    serviceAccount: argv.service_account,
  });
  var db = firebase.database();
  var ref = db.ref(argv.path);

  var connFailTimeout = setTimeout(function() {
    console.log('Failed to connect to Firebase.');
    process.exit();
  }, 10000);

  function ready() {
    clearTimeout(connFailTimeout);
    promptToContinue(ref, function() { start(ref); });
  }

  var connFunc = db.ref('.info/connected').on('value', function(s) {
    if(s.val() === true) {
      db.ref('.info/connected').off('value', connFunc);
      ready();
    }
  });
}

function promptToContinue(ref, next) {
  if (argv.force) {
    next();
  } else {
    if (argv.merge) {
      console.log('Each top-level child in ' + argv.json + ' will be written under ' + ref.toString() + '.  If a child already exists, it will be overwritten.');
    } else {
      console.log('All data at ' + ref.toString() + ' will be overwritten.');
    }
    console.log('Press <enter> to proceed, Ctrl-C to abort.');
    process.stdin.resume();
    process.stdin.once('data', next);
  }
}

function readFirstNonWhitespaceChar(file, callback) {
  var firstChar;
  var rs = fs.createReadStream(file);
  rs.on('data', function(chunk) {
      var s = chunk.toString().trim();
      if (s !== "") {
        rs.close();
      }
      firstChar = s[0];
    })
    .on('error', callback)
    .on('close', function() {
      return callback(null, firstChar);
    });
}

function getJsonFromFile(file, callback) {
  readFirstNonWhitespaceChar(file, function(err, firstChar) {
    var json;
    if (firstChar === "[" || firstChar === "{") {
      var jsonStream;
      var onFunc;
      if (firstChar === "[") {
        json = [];
        jsonStream = JSONStream.parse("*");
        onFunc = function(r) {
          json.push(r);
        };
      } else {
        json = {};
        jsonStream = JSONStream.parse("$*");
        onFunc = function(r) {
          json[r.key] = r.value;
        };
      }
      fs.createReadStream(file)
        .pipe(jsonStream)
        .on('data', onFunc)
        .on('error', callback)
        .on('close', function() {
          return callback(null, json);
        });
    } else {
      json = require(file);
      return callback(null, json);
    }
  });
}

function start(ref) {
  var file = path.resolve(argv.json);
  console.log('Reading ' + file + '... (may take a minute)');

  getJsonFromFile(file, function(err, json) {
    var clearFirst = true, splitTopLevel = false;
    if (argv.merge) {
      clearFirst = false;
      // Need to split into chunks at the top level to ensure we don't overwrite the parent.
      splitTopLevel = true;
    }

    console.log('Preparing JSON for import... (may take a minute)');
    var chunks = createChunks(ref, json, splitTopLevel);

    if (clearFirst) {
      ref.remove(function(error) {
        if (error) throw(error);
        uploadChunks(chunks);
      });
    } else {
      uploadChunks(chunks);
    }
  });
}

function uploadChunks(chunks) {
  var uploader = new ChunkUploader(chunks);
  uploader.go(function() {
    console.log('\nImport completed.');
    process.exit();
  });
}

function createChunks(ref, json, forceSplit) {
  var chunkRes = chunkInternal(ref, json, forceSplit);
  if (!chunkRes.chunks) {
    return [{ref: ref, json: json}];
  } else {
    return chunkRes.chunks;
  }
}

function chunkInternal(ref, json, forceSplit) {
  var size = 0;
  var priority = null;
  var jsonIsObject = json !== null && typeof json === 'object';
  if (jsonIsObject) {
    size += 2; // {}
  }

  if (jsonIsObject && ('.priority' in json)) {
    size += 12; // ".priority":
    priority = json['.priority'];
    size += json['.priority'].toString().length;
  }

  var value = json;
  if (jsonIsObject && ('.value' in json)) {
    size += 9; // ".value":
    value = json['.value'];
  }

  if (value === null || typeof value !== 'object') {
    // It's a leaf, it can't be chunked.
    size += JSON.stringify(value).length;
    return { chunks: null, size: size };
  } else {
    // children node.
    var chunks = [];
    var splitUp = false;
    for(var key in json) {
      if (key !== '.priority') {
        size += key.length + 3;

        var chunkRes = chunkInternal(ref.child(key), json[key]);
        size += chunkRes.size;

        if (chunkRes.chunks) {
          for(var i = 0; i < chunkRes.chunks.length; i++) {
            chunks.push(chunkRes.chunks[i]);
          }
          // One of the children had to be broken into chunks.  We have to break all of them.
          splitUp = true;
        } else {
          chunks.push({ref: ref.child(key), json: json[key]});
        }
      }
    }

    // Add priority last since it must be added after at least one child.
    if (priority !== null) {
      chunks.push({ref: ref, priority: priority});
    }

    if (forceSplit || splitUp || size >= CHUNK_SIZE) {
      return { chunks: chunks, size: size };
    } else {
      return { chunks: null, size: size }
    }
  }
}

function ChunkUploader(chunks) {
  this.next = 0;
  this.chunks = chunks;
  if (process.stdout.isTTY) {
      this.bar = new ProgressBar('Importing [:bar] :percent (:current/:total)', { width: 50, total: chunks.length, incomplete: ' ' });
  } else {
      console.log('Importing... (may take a while)');
  }
}

ChunkUploader.prototype.go = function(onComplete) {
  this.onComplete = onComplete;

  for(var i = 0; i < OUTSTANDING_WRITE_COUNT && i < this.chunks.length; i++) {
    this.uploadNext();
  }
};

ChunkUploader.prototype.uploadNext = function() {
  var chunkNum = this.next, chunk = this.chunks[chunkNum];
  assert(chunkNum < this.chunks.length);
  this.next++;

  var self = this;
  var onComplete = function(error) {
    if (error) {
      console.log('Error uploading to ' + self.chunks[i].ref.toString() + ': ' + util.inspect(json));
      console.error(error);
      throw error;
    }

    if (process.stdout.isTTY && self.bar) {
        self.bar.tick();
    }

    if (chunkNum === self.chunks.length - 1) {
      self.onComplete();
    } else {
      // upload next chunk.
      assert(self.next === self.chunks.length || self.next === chunkNum + OUTSTANDING_WRITE_COUNT);
      if (self.next < self.chunks.length)
        self.uploadNext();
    }
  };

  if ('json' in chunk) {
    chunk.ref.set(chunk.json, onComplete);
  } else {
    assert('priority' in chunk)
    chunk.ref.setPriority(chunk.priority, onComplete);
  }
}

main();
<|endoftext|>