<commit_before>import { createContext } from 'expression-expander';
import { value } from 'jsonpath';
import micromatch from 'micromatch';

import { Travis } from './travis';
import { Readme } from './readme';
import { Package } from './package';
import { Rollup } from './rollup';
import { License } from './license';
import { MergeAndRemoveLineSet } from './merge-and-remove-line-set';
import { MergeLineSet } from './merge-line-set';
import { NpmIgnore } from './npm-ignore';
import { ReplaceIfEmpty } from './replace-if-empty';
import { Replace } from './replace';
import { JSONFile } from './json-file';
import { JSDoc } from './jsdoc';
import { Context } from './context';

/**
 * context prepared to execute one package
 * @param {Context} context
 * @param {string} targetBranchName
 *
 * @property {Object} ctx
 * @property {Map<string,Object>} files
 */
export class PreparedContext {
  static get mergers() {
    return [
      Rollup,
      Travis,
      Readme,
      Package,
      JSONFile,
      JSDoc,
      Travis,
      MergeAndRemoveLineSet,
      MergeLineSet,
      NpmIgnore,
      License,
      ReplaceIfEmpty,
      Replace
    ];
  }

  static async from(context, targetBranchName) {
    const pc = new PreparedContext(context, targetBranchName);
    await pc.initialize();
    return pc;
  }

  static async execute(context, targetBranchName) {
    const pc = new PreparedContext(context, targetBranchName);
    await pc.initialize();
    return pc.execute();
  }

  constructor(context, targetBranchName) {
    Object.defineProperties(this, {
      ctx: {
        value: createContext({
          properties: Object.assign({}, context.properties),
          keepUndefinedValues: true,
          leftMarker: '{{',
          rightMarker: '}}',
          markerRegexp: '{{([^}]+)}}',
          evaluate: (expression, context, path) =>
            value(this.properties, expression)
        })
      },
      files: {
        value: new Map()
      },
      context: { value: context },
      targetBranchName: { value: targetBranchName }
    });
  }

  get mergers() {
    return this.constructor.mergers;
  }

  get provider() {
    return this.context.provider;
  }

  get templateBranchName() {
    return this.context.templateBranchName;
  }

  get properties() {
    return this.ctx.properties;
  }

  expand(...args) {
    return this.ctx.expand(...args);
  }

  evaluate(expression) {
    return value(this.properties, expression);
  }

  error(...args) {
    return this.context.error(...args);
  }

  warn(...args) {
    return this.context.warn(...args);
  }

  debug(...args) {
    return this.context.debug(...args);
  }

  info(...args) {
    return this.context.info(...args);
  }

  async initialize() {
    const context = this.context;
    const targetBranch = await context.provider.branch(this.targetBranchName);

    if (targetBranch.provider.name === 'GithubProvider') {
      this.properties.github = {
        user: targetBranch.owner.name,
        repo: targetBranch.repository.condensedName
      };
    }

    if (targetBranch.repository.owner !== undefined) {
      Object.assign(this.properties.license, {
        owner: targetBranch.owner.name
      });
    }

    if (
      targetBranch.repository.description !== undefined &&
      this.properties.description === undefined
    ) {
      this.properties.description = targetBranch.repository.description;
    }

    const pkg = new Package('package.json');

    Object.assign(this.properties, await pkg.properties(targetBranch));

    if (this.properties.usedBy !== undefined) {
      Object.defineProperties(this, {
        templateBranch: { value: targetBranch }
      });

      return;
    }

    let templateBranch;

    if (context.templateBranchName === undefined) {
      try {
        templateBranch = await context.provider.branch(
          this.properties.templateRepo
        );
      } catch (e) {}

      if (templateBranch === undefined) {
        throw new Error(
          `Unable to extract template repo url from ${targetBranch.name} ${
            pkg.path
          }`
        );
      }
    } else {
      templateBranch = await context.provider.branch(this.templateBranchName);
    }

    Object.defineProperties(this, {
      templateBranch: { value: templateBranch },
      targetBranch: { value: targetBranch }
    });
  }

  static async createFiles(branch, mapping = Context.defaultMapping) {
    const files = await branch.list();

    let alreadyPresent = new Set();

    return mapping
      .map(m => {
        const found = micromatch(
          files.filter(f => f.type === 'blob').map(f => f.path),
          m.pattern
        );

        const notAlreadyProcessed = found.filter(f => !alreadyPresent.has(f));

        alreadyPresent = new Set([...Array.from(alreadyPresent), ...found]);

        return notAlreadyProcessed.map(f => {
          const merger =
            this.mergers.find(merger => merger.name === m.merger) ||
            ReplaceIfEmpty;
          return new merger(f, m.options);
        });
      })
      .reduce((last, current) => Array.from([...last, ...current]), []);
  }

  addFile(file) {
    this.files.set(file.path, file);
  }

  /**
   * all used dev modules
   * @return {Set<string>}
   */
  async usedDevModules() {
    const usedModuleSets = await Promise.all(
      Array.from(this.files.values()).map(async file => {
        if (file.path === 'package.json') {
          return file.usedDevModules(
            file.targetContent(this, { ignoreMissing: true })
          );
        } else {
          const m = await file.merge(this);
          return file.usedDevModules(m.content);
        }
      })
    );

    return usedModuleSets.reduce(
      (sum, current) => new Set([...sum, ...current]),
      new Set()
    );
  }

  optionalDevModules(modules) {
    return Array.from(this.files.values())
      .map(file => file.optionalDevModules(modules))
      .reduce((sum, current) => new Set([...sum, ...current]), new Set());
  }

  async trackUsedModule(targetBranch) {
    const templateBranch = this.templateBranch;

    let templatePullRequest;
    let newTemplatePullRequest = false;
    let templatePRBranch = await templateBranch.repository.branch(
      'template-add-used-1'
    );

    const pkg = new Package('package.json');

    const templatePackage = await (templatePRBranch
      ? templatePRBranch
      : templateBranch
    ).content(pkg.path, { ignoreMissing: true });

    const templatePackageContent = templatePackage.content;

    const templatePackageJson =
      templatePackageContent === undefined || templatePackageContent === ''
        ? {}
        : JSON.parse(templatePackageContent);

    if (this.context.trackUsedByModule) {
      const name = targetBranch.fullCondensedName;

      if (templatePackageJson.template === undefined) {
        templatePackageJson.template = {};
      }
      if (!Array.isArray(templatePackageJson.template.usedBy)) {
        templatePackageJson.template.usedBy = [];
      }

      if (!templatePackageJson.template.usedBy.find(n => n === name)) {
        templatePackageJson.template.usedBy.push(name);
        templatePackageJson.template.usedBy = templatePackageJson.template.usedBy.sort();

        if (templatePRBranch === undefined) {
          templatePRBranch = await templateBranch.repository.createBranch(
            'template-add-used-1',
            templateBranch
          );
          newTemplatePullRequest = true;
        }

        await templatePRBranch.commit(`fix: add ${name}`, [
          {
            path: 'package.json',
            content: JSON.stringify(templatePackageJson, undefined, 2)
          }
        ]);

        if (newTemplatePullRequest) {
          templatePullRequest = await templateBranch.createPullRequest(
            templatePRBranch,
            {
              title: `add ${name}`,
              body: `add tracking info for ${name}`
            }
          );
        }
      }
    }

    return { templatePackageJson, templatePRBranch, templatePullRequest };
  }

  async execute() {
    if (this.properties.usedBy !== undefined) {
      for (const r of this.properties.usedBy) {
        try {
          await PreparedContext.execute(context, r);
        } catch (e) {
          this.error(e);
        }
      }
    } else {
      return this.executeSingleRepo();
    }
  }

  /**
   * @return {Promise<PullRequest>}
   */
  async executeSingleRepo() {
    const templateBranch = this.templateBranch;
    const targetBranch = this.targetBranch;

    const {
      templatePackageJson,
      templatePRBranch,
      templatePullRequest
    } = await this.trackUsedModule(targetBranch);

    const files = await PreparedContext.createFiles(
      templateBranch,
      templatePackageJson.template && templatePackageJson.template.files
    );

    files.forEach(f => this.addFile(f));

    const merges = (await Promise.all(
      files.map(async f => f.merge(this))
    )).filter(m => m !== undefined && m.changed);

    if (merges.length === 0) {
      this.info(`${targetBranch.fullCondensedName}: -`);
      return;
    }

    this.info(
      merges
        .map(m => `${targetBranch.fullCondensedName}: ${m.messages[0]}`)
        .join(',')
    );

    if (this.dry) {
      this.info(`${targetBranch.fullCondensedName}: dry run`);
      return;
    }

    let newPullRequestRequired = false;
    const prBranchName = 'template-sync-1';
    let prBranch = (await this.targetBranch.repository.branches()).get(
      prBranchName
    );

    if (prBranch === undefined) {
      newPullRequestRequired = true;
      prBranch = await this.targetBranch.repository.createBranch(
        prBranchName,
        targetBranch
      );
    }

    const messages = merges.reduce((result, merge) => {
      merge.messages.forEach(m => result.push(m));
      return result;
    }, []);

    await prBranch.commit(messages.join('\n'), merges);

    if (newPullRequestRequired) {
      try {
        const pullRequest = await targetBranch.createPullRequest(prBranch, {
          title: `merge package from ${templateBranch.fullCondensedName}`,
          body: merges
            .map(
              m =>
                `${m.path}
---
- ${m.messages.join('\n- ')}
`
            )
            .join('\n')
        });
        this.info(`${targetBranch.fullCondensedName}: ${pullRequest.name}`);

        return pullRequest;
      } catch (err) {
        this.error(err);
      }
    } else {
      const pullRequest = new targetBranch.provider.pullRequestClass(
        targetBranch.repository,
        'old'
      );

      this.info(
        `${targetBranch.fullCondensedName}: update PR ${pullRequest.name}`
      );
      return pullRequest;
    }
  }
}
<commit_msg>fix: missing context when looping over usedBy<commit_after>import { createContext } from "expression-expander";
import { value } from "jsonpath";
import micromatch from "micromatch";

import { Travis } from "./travis";
import { Readme } from "./readme";
import { Package } from "./package";
import { Rollup } from "./rollup";
import { License } from "./license";
import { MergeAndRemoveLineSet } from "./merge-and-remove-line-set";
import { MergeLineSet } from "./merge-line-set";
import { NpmIgnore } from "./npm-ignore";
import { ReplaceIfEmpty } from "./replace-if-empty";
import { Replace } from "./replace";
import { JSONFile } from "./json-file";
import { JSDoc } from "./jsdoc";
import { Context } from "./context";

/**
 * context prepared to execute one package
 * @param {Context} context
 * @param {string} targetBranchName
 *
 * @property {Object} ctx
 * @property {Map<string,Object>} files
 */
export class PreparedContext {
  static get mergers() {
    return [
      Rollup,
      Travis,
      Readme,
      Package,
      JSONFile,
      JSDoc,
      Travis,
      MergeAndRemoveLineSet,
      MergeLineSet,
      NpmIgnore,
      License,
      ReplaceIfEmpty,
      Replace
    ];
  }

  static async from(context, targetBranchName) {
    const pc = new PreparedContext(context, targetBranchName);
    await pc.initialize();
    return pc;
  }

  static async execute(context, targetBranchName) {
    const pc = new PreparedContext(context, targetBranchName);
    await pc.initialize();
    return pc.execute();
  }

  constructor(context, targetBranchName) {
    Object.defineProperties(this, {
      ctx: {
        value: createContext({
          properties: Object.assign({}, context.properties),
          keepUndefinedValues: true,
          leftMarker: "{{",
          rightMarker: "}}",
          markerRegexp: "{{([^}]+)}}",
          evaluate: (expression, context, path) =>
            value(this.properties, expression)
        })
      },
      files: {
        value: new Map()
      },
      context: { value: context },
      targetBranchName: { value: targetBranchName }
    });
  }

  get mergers() {
    return this.constructor.mergers;
  }

  get provider() {
    return this.context.provider;
  }

  get templateBranchName() {
    return this.context.templateBranchName;
  }

  get properties() {
    return this.ctx.properties;
  }

  expand(...args) {
    return this.ctx.expand(...args);
  }

  evaluate(expression) {
    return value(this.properties, expression);
  }

  error(...args) {
    return this.context.error(...args);
  }

  warn(...args) {
    return this.context.warn(...args);
  }

  debug(...args) {
    return this.context.debug(...args);
  }

  info(...args) {
    return this.context.info(...args);
  }

  async initialize() {
    const context = this.context;
    const targetBranch = await context.provider.branch(this.targetBranchName);

    if (targetBranch.provider.name === "GithubProvider") {
      this.properties.github = {
        user: targetBranch.owner.name,
        repo: targetBranch.repository.condensedName
      };
    }

    if (targetBranch.repository.owner !== undefined) {
      Object.assign(this.properties.license, {
        owner: targetBranch.owner.name
      });
    }

    if (
      targetBranch.repository.description !== undefined &&
      this.properties.description === undefined
    ) {
      this.properties.description = targetBranch.repository.description;
    }

    const pkg = new Package("package.json");

    Object.assign(this.properties, await pkg.properties(targetBranch));

    if (this.properties.usedBy !== undefined) {
      Object.defineProperties(this, {
        templateBranch: { value: targetBranch }
      });

      return;
    }

    let templateBranch;

    if (context.templateBranchName === undefined) {
      try {
        templateBranch = await context.provider.branch(
          this.properties.templateRepo
        );
      } catch (e) {}

      if (templateBranch === undefined) {
        throw new Error(
          `Unable to extract template repo url from ${targetBranch.name} ${
            pkg.path
          }`
        );
      }
    } else {
      templateBranch = await context.provider.branch(this.templateBranchName);
    }

    Object.defineProperties(this, {
      templateBranch: { value: templateBranch },
      targetBranch: { value: targetBranch }
    });
  }

  static async createFiles(branch, mapping = Context.defaultMapping) {
    const files = await branch.list();

    let alreadyPresent = new Set();

    return mapping
      .map(m => {
        const found = micromatch(
          files.filter(f => f.type === "blob").map(f => f.path),
          m.pattern
        );

        const notAlreadyProcessed = found.filter(f => !alreadyPresent.has(f));

        alreadyPresent = new Set([...Array.from(alreadyPresent), ...found]);

        return notAlreadyProcessed.map(f => {
          const merger =
            this.mergers.find(merger => merger.name === m.merger) ||
            ReplaceIfEmpty;
          return new merger(f, m.options);
        });
      })
      .reduce((last, current) => Array.from([...last, ...current]), []);
  }

  addFile(file) {
    this.files.set(file.path, file);
  }

  /**
   * all used dev modules
   * @return {Set<string>}
   */
  async usedDevModules() {
    const usedModuleSets = await Promise.all(
      Array.from(this.files.values()).map(async file => {
        if (file.path === "package.json") {
          return file.usedDevModules(
            file.targetContent(this, { ignoreMissing: true })
          );
        } else {
          const m = await file.merge(this);
          return file.usedDevModules(m.content);
        }
      })
    );

    return usedModuleSets.reduce(
      (sum, current) => new Set([...sum, ...current]),
      new Set()
    );
  }

  optionalDevModules(modules) {
    return Array.from(this.files.values())
      .map(file => file.optionalDevModules(modules))
      .reduce((sum, current) => new Set([...sum, ...current]), new Set());
  }

  async trackUsedModule(targetBranch) {
    const templateBranch = this.templateBranch;

    let templatePullRequest;
    let newTemplatePullRequest = false;
    let templatePRBranch = await templateBranch.repository.branch(
      "template-add-used-1"
    );

    const pkg = new Package("package.json");

    const templatePackage = await (templatePRBranch
      ? templatePRBranch
      : templateBranch
    ).content(pkg.path, { ignoreMissing: true });

    const templatePackageContent = templatePackage.content;

    const templatePackageJson =
      templatePackageContent === undefined || templatePackageContent === ""
        ? {}
        : JSON.parse(templatePackageContent);

    if (this.context.trackUsedByModule) {
      const name = targetBranch.fullCondensedName;

      if (templatePackageJson.template === undefined) {
        templatePackageJson.template = {};
      }
      if (!Array.isArray(templatePackageJson.template.usedBy)) {
        templatePackageJson.template.usedBy = [];
      }

      if (!templatePackageJson.template.usedBy.find(n => n === name)) {
        templatePackageJson.template.usedBy.push(name);
        templatePackageJson.template.usedBy = templatePackageJson.template.usedBy.sort();

        if (templatePRBranch === undefined) {
          templatePRBranch = await templateBranch.repository.createBranch(
            "template-add-used-1",
            templateBranch
          );
          newTemplatePullRequest = true;
        }

        await templatePRBranch.commit(`fix: add ${name}`, [
          {
            path: "package.json",
            content: JSON.stringify(templatePackageJson, undefined, 2)
          }
        ]);

        if (newTemplatePullRequest) {
          templatePullRequest = await templateBranch.createPullRequest(
            templatePRBranch,
            {
              title: `add ${name}`,
              body: `add tracking info for ${name}`
            }
          );
        }
      }
    }

    return { templatePackageJson, templatePRBranch, templatePullRequest };
  }

  async execute() {
    if (this.properties.usedBy !== undefined) {
      for (const r of this.properties.usedBy) {
        try {
          await PreparedContext.execute(this.context, r);
        } catch (e) {
          console.log(`execute ${r} done ${e}`);

          this.error(e);
        }
      }
    } else {
      return this.executeSingleRepo();
    }
  }

  /**
   * @return {Promise<PullRequest>}
   */
  async executeSingleRepo() {
    const templateBranch = this.templateBranch;
    const targetBranch = this.targetBranch;

    const {
      templatePackageJson,
      templatePRBranch,
      templatePullRequest
    } = await this.trackUsedModule(targetBranch);

    const files = await PreparedContext.createFiles(
      templateBranch,
      templatePackageJson.template && templatePackageJson.template.files
    );

    files.forEach(f => this.addFile(f));

    const merges = (await Promise.all(
      files.map(async f => f.merge(this))
    )).filter(m => m !== undefined && m.changed);

    if (merges.length === 0) {
      this.info(`${targetBranch.fullCondensedName}: -`);
      return;
    }

    this.info(
      merges
        .map(m => `${targetBranch.fullCondensedName}: ${m.messages[0]}`)
        .join(",")
    );

    if (this.dry) {
      this.info(`${targetBranch.fullCondensedName}: dry run`);
      return;
    }

    let newPullRequestRequired = false;
    const prBranchName = "template-sync-1";
    let prBranch = (await this.targetBranch.repository.branches()).get(
      prBranchName
    );

    if (prBranch === undefined) {
      newPullRequestRequired = true;
      prBranch = await this.targetBranch.repository.createBranch(
        prBranchName,
        targetBranch
      );
    }

    const messages = merges.reduce((result, merge) => {
      merge.messages.forEach(m => result.push(m));
      return result;
    }, []);

    await prBranch.commit(messages.join("\n"), merges);

    if (newPullRequestRequired) {
      try {
        const pullRequest = await targetBranch.createPullRequest(prBranch, {
          title: `merge package from ${templateBranch.fullCondensedName}`,
          body: merges
            .map(
              m =>
                `${m.path}
---
- ${m.messages.join("\n- ")}
`
            )
            .join("\n")
        });
        this.info(`${targetBranch.fullCondensedName}: ${pullRequest.name}`);

        return pullRequest;
      } catch (err) {
        this.error(err);
      }
    } else {
      const pullRequest = new targetBranch.provider.pullRequestClass(
        targetBranch.repository,
        "old"
      );

      this.info(
        `${targetBranch.fullCondensedName}: update PR ${pullRequest.name}`
      );
      return pullRequest;
    }
  }
}
<|endoftext|>


<commit_before>import Check from "../Core/Check.js";
import defined from "../Core/defined.js";
import Resource from "../Core/Resource.js";
import RuntimeError from "../Core/RuntimeError.js";
import ImplicitSubdivisionScheme from "./ImplicitSubdivisionScheme.js";

/**
 * An ImplicitTileset is a simple struct that stores information about the
 * structure of a single implicit tileset. This includes template URIs for
 * locating resources, details from the implicit root tile (bounding volume,
 * geometricError, etc.). and details about the subtrees (e.g. subtreeLevels,
 * subdivisionScheme).
 *
 * @alias ImplicitTileset
 * @constructor
 *
 * @param {Resource} baseResource The base resource for the tileset
 * @param {Object} tileJson The JSON header of the tile with the 3DTILES_implicit_tiling extension.
 * @private
 */
export default function ImplicitTileset(baseResource, tileJson) {
  var extension = tileJson.extensions["3DTILES_implicit_tiling"];
  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.object(
    'tileJson.extensions["3DTILES_implicit_tiling"]',
    extension
  );
  //>>includeEnd('debug');

  /**
   * The base resource for the tileset. This is stored here as it is needed
   * later when expanding Implicit3DTileContents so tile URLs are relative
   * to the tileset, not the subtree file.
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.baseResource = baseResource;

  /**
   * The geometric error of the root tile
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.geometricError = tileJson.geometricError;

  if (
    !defined(tileJson.boundingVolume.box) &&
    !defined(tileJson.boundingVolume.region)
  ) {
    throw new RuntimeError(
      "Only box and region are supported for implicit tiling"
    );
  }

  /**
   * The JSON representation of a bounding volume. This is either a box or a
   * region.
   *
   * @type {Object}
   * @readonly
   * @private
   */
  this.boundingVolume = tileJson.boundingVolume;

  /**
   * The refine strategy as a string, either 'ADD' or 'REPLACE'
   *
   * @type {String}
   * @readonly
   * @private
   */
  this.refine = tileJson.refine;

  /**
   * Template URI for the subtree resources, e.g.
   * https://example.com/{level}/{x}/{y}.subtree
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.subtreeUriTemplate = new Resource({ url: extension.subtrees.uri });

  /**
   * Template URI for locating content resources, e.g.
   * https://example.com/{level}/{x}/{y}.b3dm
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.contentUriTemplate = undefined;
  if (defined(tileJson.content)) {
    this.contentUriTemplate = new Resource({ url: tileJson.content.uri });
  }

  /**
   * The subdivision scheme for this implicit tileset; either OCTREE or QUADTREE
   *
   * @type {ImplicitSubdivisionScheme}
   * @readonly
   * @private
   */
  this.subdivisionScheme =
    ImplicitSubdivisionScheme[extension.subdivisionScheme];

  /**
   * The branching factor for this tileset. Either 4 for quadtrees or 8 for
   * octrees.
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.branchingFactor = ImplicitSubdivisionScheme.getBranchingFactor(
    this.subdivisionScheme
  );

  /**
   * How many distinct levels within each subtree. For example, a quadtree
   * with subtreeLevels = 2 will have 5 nodes per quadtree (1 root + 4 children)
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.subtreeLevels = extension.subtreeLevels;

  /**
   * The deepest level of any available tile in the entire tileset.
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.maximumLevel = extension.maximumLevel;
}
<commit_msg>Another small doc fix<commit_after>import Check from "../Core/Check.js";
import defined from "../Core/defined.js";
import Resource from "../Core/Resource.js";
import RuntimeError from "../Core/RuntimeError.js";
import ImplicitSubdivisionScheme from "./ImplicitSubdivisionScheme.js";

/**
 * An ImplicitTileset is a simple struct that stores information about the
 * structure of a single implicit tileset. This includes template URIs for
 * locating resources, details from the implicit root tile (bounding volume,
 * geometricError, etc.), and details about the subtrees (e.g. subtreeLevels,
 * subdivisionScheme).
 *
 * @alias ImplicitTileset
 * @constructor
 *
 * @param {Resource} baseResource The base resource for the tileset
 * @param {Object} tileJson The JSON header of the tile with the 3DTILES_implicit_tiling extension.
 * @private
 */
export default function ImplicitTileset(baseResource, tileJson) {
  var extension = tileJson.extensions["3DTILES_implicit_tiling"];
  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.object(
    'tileJson.extensions["3DTILES_implicit_tiling"]',
    extension
  );
  //>>includeEnd('debug');

  /**
   * The base resource for the tileset. This is stored here as it is needed
   * later when expanding Implicit3DTileContents so tile URLs are relative
   * to the tileset, not the subtree file.
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.baseResource = baseResource;

  /**
   * The geometric error of the root tile
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.geometricError = tileJson.geometricError;

  if (
    !defined(tileJson.boundingVolume.box) &&
    !defined(tileJson.boundingVolume.region)
  ) {
    throw new RuntimeError(
      "Only box and region are supported for implicit tiling"
    );
  }

  /**
   * The JSON representation of a bounding volume. This is either a box or a
   * region.
   *
   * @type {Object}
   * @readonly
   * @private
   */
  this.boundingVolume = tileJson.boundingVolume;

  /**
   * The refine strategy as a string, either 'ADD' or 'REPLACE'
   *
   * @type {String}
   * @readonly
   * @private
   */
  this.refine = tileJson.refine;

  /**
   * Template URI for the subtree resources, e.g.
   * https://example.com/{level}/{x}/{y}.subtree
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.subtreeUriTemplate = new Resource({ url: extension.subtrees.uri });

  /**
   * Template URI for locating content resources, e.g.
   * https://example.com/{level}/{x}/{y}.b3dm
   *
   * @type {Resource}
   * @readonly
   * @private
   */
  this.contentUriTemplate = undefined;
  if (defined(tileJson.content)) {
    this.contentUriTemplate = new Resource({ url: tileJson.content.uri });
  }

  /**
   * The subdivision scheme for this implicit tileset; either OCTREE or QUADTREE
   *
   * @type {ImplicitSubdivisionScheme}
   * @readonly
   * @private
   */
  this.subdivisionScheme =
    ImplicitSubdivisionScheme[extension.subdivisionScheme];

  /**
   * The branching factor for this tileset. Either 4 for quadtrees or 8 for
   * octrees.
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.branchingFactor = ImplicitSubdivisionScheme.getBranchingFactor(
    this.subdivisionScheme
  );

  /**
   * How many distinct levels within each subtree. For example, a quadtree
   * with subtreeLevels = 2 will have 5 nodes per quadtree (1 root + 4 children)
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.subtreeLevels = extension.subtreeLevels;

  /**
   * The deepest level of any available tile in the entire tileset.
   *
   * @type {Number}
   * @readonly
   * @private
   */
  this.maximumLevel = extension.maximumLevel;
}
<|endoftext|>


<commit_before>/**
 * Created by Heorhi_Vilkitski on 4/11/14.
 */

function moduleProgressController($scope, $resource, $window, $filter) {
    var moduleDataResource = $resource('/moduledata');

    /* ------------------------------------------------------ Init/Reinit -------------------------------*/
    $scope.init = function () {
        $scope.common = {};
        $scope.dataLoad();
        $scope.sortByDate = false;
        $scope.filterEod = false;
        $scope.filterQ1 = false;
        $scope.filterQ2 = false;
        $scope.showTeamTable = false;
        $scope.showStreams = false;
        $scope.showModules = false;
        $scope.showCompletedModules = false;
    };

    $scope.reInit = function () {
        $scope.dataLoad();
    };

    $scope.dataLoad = function () {
        $scope.filteredSme = $scope.allSMEs[0].id;
        $scope.filteredMG = $scope.allModuleGroups[0].id;
        $scope.filteredTeam = $scope.allTeams[0].id;
        $scope.filteredVersion = $scope.allVersions[0].id;
        $scope.isTotalWasCalculated = false;
        $scope.reInitTotal();
        $scope.getModuleData().done($scope.processWithRowSpans);
        $scope.updatedModuleProgressData = $filter('orderBy')($scope.updatedModuleProgressData, $scope.sortingModel.dueDate.getter, !$scope.sortingModel.isASC);
        $scope.teamLoadData = [];
    };

    $scope.reInitTotal = function(){
        $scope.total = new $scope.statuses();
        $scope.total.all = {isChecked :true};
        $scope.total.total = 0;
        $scope.allSMEs = [{id: "All", name: "All"}];
        $scope.allModuleGroups = [{id: "All", name: "All"}];
        $scope.allVersions = [{id: "All", name: "All"}];
        $scope.showVersions = [];
    };

    $scope.processWithRowSpans = function () {
        $scope.total.doneSP = 0;
        $scope.total.summSP = 0;
        $scope.updatedModuleProgressData=[];
        $scope.teamLoadData = [];
        //fill in Versions combo
        _.each($scope.moduleProgressData.module, function(module) {
            var found = false;
            _.each($scope.allVersions, function(version) {
                if(version.name == module.fixVersions) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allVersions.push({id: module.fixVersions, name: module.fixVersions});
                $scope.showVersions.push(module.fixVersions);
            }
        });
        //fill in groups and sme combos
        _.each($scope.moduleProgressData.module, function(module) {
            var found = false;
            _.each($scope.allModuleGroups, function(it_group) {
                if(it_group.name == module.moduleGroup) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allModuleGroups.push({id: module.moduleGroup, name: module.moduleGroup});
            }
        });
        _.each($scope.moduleProgressData.module, function(item) {
            var found = false;
            _.each($scope.allSMEs, function(sme) {
                if(sme.name == item.smename) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allSMEs.push({id: item.smename, name: item.smename});
            }
        });
        $scope.allModuleGroups.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.allSMEs.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.allVersions.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.showVersions.sort(function (a, b) {
            return a > b ? 1 : a < b ? -1 : 0;
        });

        _.each($scope.moduleProgressData.module, function(moduleProgressItem) {
            if($scope.filteredMG != $scope.allModuleGroups[0].id && moduleProgressItem.moduleGroup != $scope.filteredMG){
                return;
            }
            if($scope.filteredVersion != $scope.allVersions[0].id && moduleProgressItem.fixVersions != $scope.filteredVersion){
                return;
            }
            if($scope.filteredSme != $scope.allSMEs[0].id && moduleProgressItem.smename != $scope.filteredSme){
                return;
            }
            if($scope.filteredTeam != $scope.allTeams[0].id) {
                var found = false;
                _.each(moduleProgressItem.teamnames, function(teamName) {
                    if(teamName.indexOf($scope.filteredTeam) > -1) {
                        found = true;
                    }
                });
                if(!found) {
                    return;
                }
            }
            if($scope.filterEod && !moduleProgressItem.endOfYearDelivery) {
                return;
            }
            if($scope.filterQ1 && !moduleProgressItem.q1Delivery) {
                return;
            }
            if($scope.filterQ2 && !moduleProgressItem.q2Delivery) {
                return;
            }

            moduleProgressItem.progress = Math.round(moduleProgressItem.progress);
            moduleProgressItem.progress2 = moduleProgressItem.progress.toString() + "%";

            moduleProgressItem.duedate2 = moduleProgressItem.duedate;
            moduleProgressItem.acceptedName = moduleProgressItem.accepted ? "Yes" : "No";

            var accepted = moduleProgressItem.status == "Accepted";
            var readyForQa = moduleProgressItem.status == "Ready for QA" || moduleProgressItem.status == "Testing in Progress";
            var resolved = moduleProgressItem.status == "Resolved";
            var cancelled = moduleProgressItem.modulestatus == "Closed" && moduleProgressItem.moduleresolution == "Out of Scope";
            var notApplicable = moduleProgressItem.modulestatus == "Closed" && moduleProgressItem.moduleresolution == "Done" && moduleProgressItem.pagescount < 1;

            moduleProgressItem.cancelled = cancelled || notApplicable;
            moduleProgressItem.readyForQA = readyForQa;
            moduleProgressItem.readyForAcceptance = resolved;

            if(cancelled) {
                var cancelledEntity = $scope.total.getStatusByName("Cancelled");
                processEntity(cancelledEntity, moduleProgressItem);
            }
            else if(notApplicable) {
                var notApplicableEntity = $scope.total.getStatusByName("Not Applicable");
                processEntity(notApplicableEntity, moduleProgressItem);
            }
            else if(accepted) {
                var acceptedEntity = $scope.total.getStatusByName("Accepted");
                processEntity(acceptedEntity, moduleProgressItem);
            }
            else if(readyForQa) {
                var readyForQaEntity = $scope.total.getStatusByName("Ready for QA");
                processEntity(readyForQaEntity, moduleProgressItem);
            }
            else if(resolved) {
                var resolvedEntity = $scope.total.getStatusByName("Resolved");
                processEntity(resolvedEntity, moduleProgressItem);
            }
            else {
                var inProgressEntity = $scope.total.getStatusByName("In Progress");
                processEntity(inProgressEntity, moduleProgressItem);
            }

            if(!$scope.isTotalWasCalculated) {
                $scope.total.total++;
            }

            //calculating data for top table
            _.each(moduleProgressItem.teamnames, function(teamName) {
                var teamobj = getTeamObj(teamName);
                _.each(teamobj.versions, function(version) {
                    if(version.name == moduleProgressItem.fixVersions) {
                        version.done += moduleProgressItem.reportedSP;
                        version.total += moduleProgressItem.summarySP;
                        var moduleName = $scope.showModules ? getCleanModuleName(moduleProgressItem.name) : moduleProgressItem.smename;
                        var reportedSP = Math.floor(moduleProgressItem.reportedSP);
                        var summarySP = Math.floor(moduleProgressItem.summarySP);
                        fillSmeNames(version.smeNames, moduleName, reportedSP, summarySP);
                    }
                });
            });
        });

        $scope.teamLoadData.sort(function (a, b) {
            a = a.name;
            b = b.name;
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.onSortingClick();
        $scope.isTotalWasCalculated = true;
    };

    function fillSmeNames(smeNames, name, reportedSP, summarySP) {
        var found = false;
        _.each(smeNames, function (smename) {
            if(smename.name == name) {
                found = true;
            }
        });
        if(!found) {
            var completed = reportedSP == summarySP;
            var card = { name: name, completed: completed, reportedSP: reportedSP, summarySP: summarySP};
            if($scope.showCompletedModules ||
                !$scope.showCompletedModules && !completed) {
                smeNames.push(card);
            }
        }
    }

    function getTeamObj(teamName) {
        var teamobj = null;
        var teamNameCorrected = teamName;
        if(!$scope.showStreams){
            teamNameCorrected = getCleanTeamName(teamName);
        }
        _.each($scope.teamLoadData, function (team) {
            if (team.name == teamNameCorrected) {
                teamobj = team;
            }
        });
        if (teamobj == null) {
            var team = {
                name: teamNameCorrected,
                versions: []
            };
            _.each($scope.showVersions, function(version) {
               team.versions.push( {name:version, done: 0, total: 0, smeNames: [], completed: false});
            });
            $scope.teamLoadData.push(team);
            teamobj = team;
        }
        return teamobj;
    }

    function getCleanTeamName(teamName) {
        var index = teamName.indexOf(":");
        if(index < 0) {
            return teamName;
        }

        return teamName.substring(0,index);
    }

    function getCleanModuleName(moduleName) {
        var index = moduleName.indexOf("Module");
        if(index < 0) {
            return moduleName;
        }

        return moduleName.substring(0,index);
    }

    function processEntity(entity, moduleProgressItem) {
        if (entity.isChecked) {
            if (!$scope.isTotalWasCalculated) {
                entity.count++;
            }
            $scope.total.doneSP += moduleProgressItem.reportedSP;
            $scope.total.summSP += moduleProgressItem.summarySP;
            $scope.updatedModuleProgressData.push(moduleProgressItem);
        }
    }

    function sortModuleProgressData() {
        var getter =  $scope.sortingModel[$scope.sortingModel.selected].getter;
        $scope.updatedModuleProgressData = $filter('orderBy')($scope.updatedModuleProgressData, getter, !$scope.sortingModel.isASC);
    }

    /* -------------------------------------------------------Event handlers ------------------------ */
    /* --------------------------------------------- Actions ------------------------------*/
    $scope.getModuleData = function () {
        var loadingDfrd = $.Deferred();

        var getModuleSuccess = function (data) {
            $scope.moduleProgressData = data;
            loadingDfrd.resolve();
        };

        var getModuleFail = function (err) {
            $scope.errMessage = err;
            loadingDfrd.reject(err);
        };

        moduleDataResource.get($scope.common, getModuleSuccess, getModuleFail);
        return loadingDfrd.promise();
    };

    /* ------------------------------------------- DOM/Angular events --------------------------------------*/
    $scope.onDateChange = function()
    {
        $scope.reInit();
    };

    $scope.onSelectDeselectAll = function()
    {
        $scope.total.accepted.isChecked = $scope.total.all.isChecked;
        $scope.total.resolved.isChecked = $scope.total.all.isChecked;
        $scope.total.inProgress.isChecked = $scope.total.all.isChecked;
        $scope.total.readyForQA.isChecked = $scope.total.all.isChecked;
        $scope.total.cancelled.isChecked = $scope.total.all.isChecked;
        $scope.total.notApplicable.isChecked = $scope.total.all.isChecked;

        $scope.processWithRowSpans();
    };

    $scope.onSortingClick = function(sortName){
        if(sortName == $scope.sortingModel.selected){
            $scope.sortingModel.isASC = !$scope.sortingModel.isASC;
        }
        else if(sortName != null) {
                $scope.sortingModel.selected = sortName;
                $scope.sortingModel.isASC = true;
        }

        sortModuleProgressData();
    };

    $scope.onFilterEod = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    $scope.onFilterQ1 = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    $scope.onFilterQ2 = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    /* ----------------------------------------- Helpers/Angular Filters and etc-----------------------------------*/

    $scope.filterModule = function()
    {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    };

    $scope.isUnknownExist = function(item)
    {
        return item.indexOf("Unknown") > -1;
    };

    $scope.sortingModel = {
        selected: "dueDate",
        isASC : true,

        progress:{
            getter: function(item){ return item.progress; }
        },

        dueDate:{
            getter: function(item){ return item.duedate2; }
        },

        moduleGroup:{
            getter: function(item){ return item.name; }
        },

        smeName:{
            getter: function(item){ return item.smename; }
        }
    };

    $scope.init();
}

<commit_msg>fix for calculations<commit_after>/**
 * Created by Heorhi_Vilkitski on 4/11/14.
 */

function moduleProgressController($scope, $resource, $window, $filter) {
    var moduleDataResource = $resource('/moduledata');

    /* ------------------------------------------------------ Init/Reinit -------------------------------*/
    $scope.init = function () {
        $scope.common = {};
        $scope.dataLoad();
        $scope.sortByDate = false;
        $scope.filterEod = false;
        $scope.filterQ1 = false;
        $scope.filterQ2 = false;
        $scope.showTeamTable = false;
        $scope.showStreams = false;
        $scope.showModules = false;
        $scope.showCompletedModules = false;
    };

    $scope.reInit = function () {
        $scope.dataLoad();
    };

    $scope.dataLoad = function () {
        $scope.filteredSme = $scope.allSMEs[0].id;
        $scope.filteredMG = $scope.allModuleGroups[0].id;
        $scope.filteredTeam = $scope.allTeams[0].id;
        $scope.filteredVersion = $scope.allVersions[0].id;
        $scope.isTotalWasCalculated = false;
        $scope.reInitTotal();
        $scope.getModuleData().done($scope.processWithRowSpans);
        $scope.updatedModuleProgressData = $filter('orderBy')($scope.updatedModuleProgressData, $scope.sortingModel.dueDate.getter, !$scope.sortingModel.isASC);
        $scope.teamLoadData = [];
    };

    $scope.reInitTotal = function(){
        $scope.total = new $scope.statuses();
        $scope.total.all = {isChecked :true};
        $scope.total.total = 0;
        $scope.allSMEs = [{id: "All", name: "All"}];
        $scope.allModuleGroups = [{id: "All", name: "All"}];
        $scope.allVersions = [{id: "All", name: "All"}];
        $scope.showVersions = [];
    };

    $scope.processWithRowSpans = function () {
        $scope.total.doneSP = 0;
        $scope.total.summSP = 0;
        $scope.updatedModuleProgressData=[];
        $scope.teamLoadData = [];
        //fill in Versions combo
        _.each($scope.moduleProgressData.module, function(module) {
            var found = false;
            _.each($scope.allVersions, function(version) {
                if(version.name == module.fixVersions) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allVersions.push({id: module.fixVersions, name: module.fixVersions});
                $scope.showVersions.push(module.fixVersions);
            }
        });
        //fill in groups and sme combos
        _.each($scope.moduleProgressData.module, function(module) {
            var found = false;
            _.each($scope.allModuleGroups, function(it_group) {
                if(it_group.name == module.moduleGroup) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allModuleGroups.push({id: module.moduleGroup, name: module.moduleGroup});
            }
        });
        _.each($scope.moduleProgressData.module, function(item) {
            var found = false;
            _.each($scope.allSMEs, function(sme) {
                if(sme.name == item.smename) {
                    found = true;
                }
            });
            if(!found) {
                $scope.allSMEs.push({id: item.smename, name: item.smename});
            }
        });
        $scope.allModuleGroups.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.allSMEs.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.allVersions.sort(function (a, b) {
            a = a.name;
            b = b.name;
            if(a == "All") {
                return -1;
            }
            if(b == "All") {
                return 1;
            }
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.showVersions.sort(function (a, b) {
            return a > b ? 1 : a < b ? -1 : 0;
        });

        _.each($scope.moduleProgressData.module, function(moduleProgressItem) {
            if($scope.filteredMG != $scope.allModuleGroups[0].id && moduleProgressItem.moduleGroup != $scope.filteredMG){
                return;
            }
            if($scope.filteredVersion != $scope.allVersions[0].id && moduleProgressItem.fixVersions != $scope.filteredVersion){
                return;
            }
            if($scope.filteredSme != $scope.allSMEs[0].id && moduleProgressItem.smename != $scope.filteredSme){
                return;
            }
            if($scope.filteredTeam != $scope.allTeams[0].id) {
                var found = false;
                _.each(moduleProgressItem.teamnames, function(teamName) {
                    if(teamName.indexOf($scope.filteredTeam) > -1) {
                        found = true;
                    }
                });
                if(!found) {
                    return;
                }
            }
            if($scope.filterEod && !moduleProgressItem.endOfYearDelivery) {
                return;
            }
            if($scope.filterQ1 && !moduleProgressItem.q1Delivery) {
                return;
            }
            if($scope.filterQ2 && !moduleProgressItem.q2Delivery) {
                return;
            }

            moduleProgressItem.progress = Math.round(moduleProgressItem.progress);
            moduleProgressItem.progress2 = moduleProgressItem.progress.toString() + "%";

            moduleProgressItem.duedate2 = moduleProgressItem.duedate;
            moduleProgressItem.acceptedName = moduleProgressItem.accepted ? "Yes" : "No";

            var accepted = moduleProgressItem.status == "Accepted";
            var readyForQa = moduleProgressItem.status == "Ready for QA" || moduleProgressItem.status == "Testing in Progress";
            var resolved = moduleProgressItem.status == "Resolved";
            var cancelled = moduleProgressItem.modulestatus == "Closed" && moduleProgressItem.moduleresolution == "Out of Scope";
            var notApplicable = moduleProgressItem.modulestatus == "Closed" && moduleProgressItem.moduleresolution == "Done" && moduleProgressItem.pagescount < 1;

            moduleProgressItem.cancelled = cancelled || notApplicable;
            moduleProgressItem.readyForQA = readyForQa;
            moduleProgressItem.readyForAcceptance = resolved;

            if(cancelled) {
                var cancelledEntity = $scope.total.getStatusByName("Cancelled");
                processEntity(cancelledEntity, moduleProgressItem);
            }
            else if(notApplicable) {
                var notApplicableEntity = $scope.total.getStatusByName("Not Applicable");
                processEntity(notApplicableEntity, moduleProgressItem);
            }
            else if(accepted) {
                var acceptedEntity = $scope.total.getStatusByName("Accepted");
                processEntity(acceptedEntity, moduleProgressItem);
            }
            else if(readyForQa) {
                var readyForQaEntity = $scope.total.getStatusByName("Ready for QA");
                processEntity(readyForQaEntity, moduleProgressItem);
            }
            else if(resolved) {
                var resolvedEntity = $scope.total.getStatusByName("Resolved");
                processEntity(resolvedEntity, moduleProgressItem);
            }
            else {
                var inProgressEntity = $scope.total.getStatusByName("In Progress");
                processEntity(inProgressEntity, moduleProgressItem);
            }

            if(!$scope.isTotalWasCalculated) {
                $scope.total.total++;
            }

            //calculating data for top table
            _.each(moduleProgressItem.teamnames, function(teamName) {
                var teamobj = getTeamObj(teamName);
                _.each(teamobj.versions, function(version) {
                    if(version.name == moduleProgressItem.fixVersions) {
                        version.done += moduleProgressItem.reportedSP;
                        version.total += moduleProgressItem.summarySP;
                        var moduleName = $scope.showModules ? getCleanModuleName(moduleProgressItem.name) : moduleProgressItem.smename;
                        var reportedSP = Math.floor(moduleProgressItem.reportedSP);
                        var summarySP = Math.floor(moduleProgressItem.summarySP);
                        fillSmeNames(version.smeNames, moduleName, reportedSP, summarySP);
                    }
                });
            });
        });

        $scope.teamLoadData.sort(function (a, b) {
            a = a.name;
            b = b.name;
            return a > b ? 1 : a < b ? -1 : 0;
        });
        $scope.onSortingClick();
        $scope.isTotalWasCalculated = true;
    };

    function fillSmeNames(smeNames, name, reportedSP, summarySP) {
        var found = false;
        _.each(smeNames, function (card) {
            if(card.name == name) {
                card.reportedSP += reportedSP;
                card.summarySP += summarySP;
                card.completed = card.reportedSP == card.summarySP;
                found = true;
            }
        });
        if(!found) {
            var completed = reportedSP == summarySP;
            var card = { name: name, completed: completed, reportedSP: reportedSP, summarySP: summarySP};
            if($scope.showCompletedModules ||
                !$scope.showCompletedModules && !completed) {
                smeNames.push(card);
            }
        }
    }

    function getTeamObj(teamName) {
        var teamobj = null;
        var teamNameCorrected = teamName;
        if(!$scope.showStreams){
            teamNameCorrected = getCleanTeamName(teamName);
        }
        _.each($scope.teamLoadData, function (team) {
            if (team.name == teamNameCorrected) {
                teamobj = team;
            }
        });
        if (teamobj == null) {
            var team = {
                name: teamNameCorrected,
                versions: []
            };
            _.each($scope.showVersions, function(version) {
               team.versions.push( {name:version, done: 0, total: 0, smeNames: [], completed: false});
            });
            $scope.teamLoadData.push(team);
            teamobj = team;
        }
        return teamobj;
    }

    function getCleanTeamName(teamName) {
        var index = teamName.indexOf(":");
        if(index < 0) {
            return teamName;
        }

        return teamName.substring(0,index);
    }

    function getCleanModuleName(moduleName) {
        var index = moduleName.indexOf("Module");
        if(index < 0) {
            return moduleName;
        }

        return moduleName.substring(0,index);
    }

    function processEntity(entity, moduleProgressItem) {
        if (entity.isChecked) {
            if (!$scope.isTotalWasCalculated) {
                entity.count++;
            }
            $scope.total.doneSP += moduleProgressItem.reportedSP;
            $scope.total.summSP += moduleProgressItem.summarySP;
            $scope.updatedModuleProgressData.push(moduleProgressItem);
        }
    }

    function sortModuleProgressData() {
        var getter =  $scope.sortingModel[$scope.sortingModel.selected].getter;
        $scope.updatedModuleProgressData = $filter('orderBy')($scope.updatedModuleProgressData, getter, !$scope.sortingModel.isASC);
    }

    /* -------------------------------------------------------Event handlers ------------------------ */
    /* --------------------------------------------- Actions ------------------------------*/
    $scope.getModuleData = function () {
        var loadingDfrd = $.Deferred();

        var getModuleSuccess = function (data) {
            $scope.moduleProgressData = data;
            loadingDfrd.resolve();
        };

        var getModuleFail = function (err) {
            $scope.errMessage = err;
            loadingDfrd.reject(err);
        };

        moduleDataResource.get($scope.common, getModuleSuccess, getModuleFail);
        return loadingDfrd.promise();
    };

    /* ------------------------------------------- DOM/Angular events --------------------------------------*/
    $scope.onDateChange = function()
    {
        $scope.reInit();
    };

    $scope.onSelectDeselectAll = function()
    {
        $scope.total.accepted.isChecked = $scope.total.all.isChecked;
        $scope.total.resolved.isChecked = $scope.total.all.isChecked;
        $scope.total.inProgress.isChecked = $scope.total.all.isChecked;
        $scope.total.readyForQA.isChecked = $scope.total.all.isChecked;
        $scope.total.cancelled.isChecked = $scope.total.all.isChecked;
        $scope.total.notApplicable.isChecked = $scope.total.all.isChecked;

        $scope.processWithRowSpans();
    };

    $scope.onSortingClick = function(sortName){
        if(sortName == $scope.sortingModel.selected){
            $scope.sortingModel.isASC = !$scope.sortingModel.isASC;
        }
        else if(sortName != null) {
                $scope.sortingModel.selected = sortName;
                $scope.sortingModel.isASC = true;
        }

        sortModuleProgressData();
    };

    $scope.onFilterEod = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    $scope.onFilterQ1 = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    $scope.onFilterQ2 = function() {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    }
    /* ----------------------------------------- Helpers/Angular Filters and etc-----------------------------------*/

    $scope.filterModule = function()
    {
        $scope.reInitTotal();
        $scope.isTotalWasCalculated = false;
        $scope.processWithRowSpans();
    };

    $scope.isUnknownExist = function(item)
    {
        return item.indexOf("Unknown") > -1;
    };

    $scope.sortingModel = {
        selected: "dueDate",
        isASC : true,

        progress:{
            getter: function(item){ return item.progress; }
        },

        dueDate:{
            getter: function(item){ return item.duedate2; }
        },

        moduleGroup:{
            getter: function(item){ return item.name; }
        },

        smeName:{
            getter: function(item){ return item.smename; }
        }
    };

    $scope.init();
}

<|endoftext|>


<commit_before>
'use strict';

var helper = require('./helpers');

describe('Add and view Campaign', function() {
  beforeEach(function() {
    helper.loadApp('/');

  });
  //***********buttons************/
  var signInButton = element(by.id('signIn'));
  var myCampaign = element(by.id('myCampaign'));

  /****TESTS*********/
  it('should load the addCampaign page', function() {
    helper.logoutifLoggedIn();
    helper.login();
    //var myCampaign = browser.driver.findElement(by.id('myCampaign'));
    myCampaign.click();
    // console.log(element(by.id('title')));
     expect(element(by.id('title')).isDisplayed()).toBe(true);
  });

    it('should not accept Title with Less Than 5 Characters or', function(){
       // helper.logoutifLoggedIn();
       // helper.login();
       var title =element(by.model('campaign.title'));
       myCampaign.click();
       title.sendKeys('TEST');
       browser.sleep(2000);
       expect(element(by.id('lessThan5')).isDisplayed()).toBe(true);
       browser.driver.sleep(2000);
       title.clear();
       //sending an a string of empty characters
       title.sendKeys('         ');
       browser.driver.sleep(2000);
       expect(element(by.id('campaignIsRequired')).isDisplayed()).toBe(true);
       //   expect(element(by.id('addCampaignBtn'))).toBeFalsy();
    });

    it('should not accept description with Less Than 20 Characters', function(){
       // helper.logoutifLoggedIn();
       // helper.login();
       myCampaign.click();
       var description =element(by.model('campaign.description'));
       description.sendKeys('These Characters');
       browser.driver.sleep(2000);
       expect(element(by.id('lessThan20')).isDisplayed()).toBe(true);
       browser.driver.sleep(2000);
       description.clear();
       browser.driver.sleep(2000);
       //sending an a string of empty characters
       description.sendKeys('                                   ');
       browser.driver.sleep(1000);
       expect(element(by.id('descriptionErr')).isDisplayed()).toBe(true);
      });

    it('should accept only numbers', function(){
        //TYPE NUMBER FIELD NOT CLEARING PROBLEM WITH PROTRACTOR https://github.com/angular/protractor/issues/1583
      myCampaign.click();
      var amount = element(by.model('campaign.amount'));
      amount.sendKeys('asdfghjkl');
      expect(element(by.id('isInvalidErr')).isDisplayed()).toBe(true);
    });
});<commit_msg>resolving merge conflicts<commit_after>
'use strict';

var helper = require('./helpers');

describe('Add and view Campaign', function() {
  beforeEach(function() {
    helper.loadApp('/');

  });
  //***********buttons************/
  var signInButton = element(by.id('signIn'));
  var myCampaign = element(by.id('myCampaign'));

  /****TESTS*********/
  it('should load the addCampaign page', function() {
    helper.logoutifLoggedIn();
    helper.login();
    //var myCampaign = browser.driver.findElement(by.id('myCampaign'));
    myCampaign.click();
    // console.log(element(by.id('title')));
     expect(element(by.id('title')).isDisplayed()).toBe(true);
  });

    it('should not accept Title with Less Than 5 Characters or', function(){
       // helper.logoutifLoggedIn();
       // helper.login();
       var title =element(by.model('campaign.title'));
       myCampaign.click();
       title.sendKeys('TEST');
       browser.sleep(2000);
       expect(element(by.id('lessThan5')).isDisplayed()).toBe(true);
       browser.driver.sleep(2000);
       title.clear();
       //sending an a string of empty characters
       title.sendKeys('         ');
       browser.driver.sleep(2000);
       expect(element(by.id('campaignIsRequired')).isDisplayed()).toBe(true);
       //   expect(element(by.id('addCampaignBtn'))).toBeFalsy();
    });

    it('should not accept description with Less Than 20 Characters', function(){
       // helper.logoutifLoggedIn();
       // helper.login();
       myCampaign.click();
       var description =element(by.model('campaign.description'));
       description.sendKeys('These Characters');
       browser.driver.sleep(2000);
       expect(element(by.id('lessThan20')).isDisplayed()).toBe(true);
       browser.driver.sleep(2000);
       description.clear();
       browser.driver.sleep(2000);
       //sending an a string of empty characters
       description.sendKeys('                                   ');
       browser.driver.sleep(1000);
       expect(element(by.id('descriptionErr')).isDisplayed()).toBe(true);
      });

    it('should accept only numbers', function(){

        //TYPE NUMBER FIELD NOT CLEARING PROBLEM WITH PROTRACTOR https://github.com/angular/protractor/issues/1583
      myCampaign.click();
      var amount = element(by.model('campaign.amount'));
      amount.sendKeys('asdfghjkl');
      expect(element(by.id('isInvalidErr')).isDisplayed()).toBe(true);
    });
});<|endoftext|>


<commit_before>define(function(require) {
  var FILE_SYSTEM_NAME = require('src/constants').FILE_SYSTEM_NAME;

  // Based on https://github.com/caolan/async/blob/master/lib/async.js
  var nextTick = (function() {
    if (typeof process === 'undefined' || !(process.nextTick)) {
      if (typeof setImmediate === 'function') {
        return function (fn) {
          // not a direct alias for IE10 compatibility
          setImmediate(fn);
        };
      } else {
        return function (fn) {
          setTimeout(fn, 0);
        };
      }
    }
    return process.nextTick;
  }());

  function asyncCallback(callback) {
    nextTick(callback);
  }

  function MemoryContext(db, readOnly) {
    this.readOnly = readOnly;
    this.objectStore = db;
  }
  MemoryContext.prototype.clear = function(callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    var objectStore = this.objectStore;
    Object.keys(objectStore).forEach(function(key){
      delete objectStore[key];
    });
    asyncCallback(callback);
  };
  MemoryContext.prototype.get = function(key, callback) {
    var that = this;
    asyncCallback(function() {
      callback(null, that.objectStore[key]);
    });
  };
  MemoryContext.prototype.put = function(key, value, callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    this.objectStore[key] = value;
    asyncCallback(callback);
  };
  MemoryContext.prototype.delete = function(key, callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    delete this.objectStore[key];
    asyncCallback(callback);
  };

  function Memory(name) {
    this.name = name || FILE_SYSTEM_NAME;
    this.db = {};
  }
  Memory.isSupported = function() {
    return true;
  };

  Memory.prototype.open = function(callback) {
    asyncCallback(function() {
      callback(null, true);
    });
  };
  Memory.prototype.getReadOnlyContext = function() {
    return new MemoryContext(this.db, true);
  };
  Memory.prototype.getReadWriteContext = function() {
    return new MemoryContext(this.db, false);
  };

  return Memory;
});
<commit_msg>Share code from lib/async.js instead of inlining nextTick in Memory provider<commit_after>define(function(require) {
  var FILE_SYSTEM_NAME = require('src/constants').FILE_SYSTEM_NAME;

  var asyncCallback = require('async').nextTick;

  function MemoryContext(db, readOnly) {
    this.readOnly = readOnly;
    this.objectStore = db;
  }
  MemoryContext.prototype.clear = function(callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    var objectStore = this.objectStore;
    Object.keys(objectStore).forEach(function(key){
      delete objectStore[key];
    });
    asyncCallback(callback);
  };
  MemoryContext.prototype.get = function(key, callback) {
    var that = this;
    asyncCallback(function() {
      callback(null, that.objectStore[key]);
    });
  };
  MemoryContext.prototype.put = function(key, value, callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    this.objectStore[key] = value;
    asyncCallback(callback);
  };
  MemoryContext.prototype.delete = function(key, callback) {
    if(this.readOnly) {
      asyncCallback(function() {
        callback("[MemoryContext] Error: write operation on read only context");
      });
      return;
    }
    delete this.objectStore[key];
    asyncCallback(callback);
  };

  function Memory(name) {
    this.name = name || FILE_SYSTEM_NAME;
    this.db = {};
  }
  Memory.isSupported = function() {
    return true;
  };

  Memory.prototype.open = function(callback) {
    asyncCallback(function() {
      callback(null, true);
    });
  };
  Memory.prototype.getReadOnlyContext = function() {
    return new MemoryContext(this.db, true);
  };
  Memory.prototype.getReadWriteContext = function() {
    return new MemoryContext(this.db, false);
  };

  return Memory;
});
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var $ = require('preconditions').singleton();
var log = require('npmlog');
log.debug = log.verbose;
var io = require('socket.io-client');
var requestList = require('./request-list');

function Insight(opts) {
  $.checkArgument(opts);
  $.checkArgument(_.contains(['livenet', 'testnet'], opts.network));
  $.checkArgument(opts.url);

  this.apiPrefix = opts.apiPrefix || '/api';
  this.network = opts.network || 'livenet';
  this.hosts = opts.url;
  this.userAgent = opts.userAgent || 'bws';
};

var _parseErr = function(err, res) {
  if (err) {
    log.warn('Insight error: ', err);
    return "Insight Error";
  }
  log.warn("Insight " + res.request.href + " Returned Status: " + res.statusCode);
  return "Error querying the blockchain";
};

Insight.prototype._doRequest = function(args, cb) {
  var opts = {
    hosts: this.hosts,
    headers: {
      'User-Agent': this.userAgent,
    }
  };
  requestList(_.defaults(args, opts), cb);
};

Insight.prototype.getConnectionInfo = function() {
  return 'Insight (' + this.network + ') @ ' + this.hosts;
};

/**
 * Retrieve a list of unspent outputs associated with an address or set of addresses
 */
Insight.prototype.getUtxos = function(addresses, cb) {
  var url = this.url + this.apiPrefix + '/addrs/utxo';
  var args = {
    method: 'POST',
    path: this.apiPrefix + '/addrs/utxo',
    json: {
      addrs: [].concat(addresses).join(',')
    },
  };

  this._doRequest(args, function(err, res, unspent) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, unspent);
  });
};

/**
 * Broadcast a transaction to the bitcoin network
 */
Insight.prototype.broadcast = function(rawTx, cb) {
  var args = {
    method: 'POST',
    path: this.apiPrefix + '/tx/send',
    json: {
      rawtx: rawTx
    },
  };

  this._doRequest(args, function(err, res, body) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, body ? body.txid : null);
  });
};

Insight.prototype.getTransaction = function(txid, cb) {
  var args = {
    method: 'GET',
    path: this.apiPrefix + '/tx/' + txid,
    json: true,
  };

  this._doRequest(args, function(err, res, tx) {
    if (res && res.statusCode == 404) return cb();
    if (err || res.statusCode !== 200)
      return cb(_parseErr(err, res));

    return cb(null, tx);
  });
};

Insight.prototype.getTransactions = function(addresses, from, to, cb) {
  var qs = [];
  if (_.isNumber(from)) qs.push('from=' + from);
  if (_.isNumber(to)) qs.push('to=' + to);

  // Trim output
  qs.push('noAsm=1');
  qs.push('noScriptSig=1');
  qs.push('noSpent=1');

  var args = {
    method: 'POST',
    path: this.apiPrefix + '/addrs/txs' + (qs.length > 0 ? '?' + qs.join('&') : ''),
    json: {
      addrs: [].concat(addresses).join(',')
    },
  };

  this._doRequest(args, function(err, res, txs) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));

    if (_.isObject(txs) && txs.items)
      txs = txs.items;

    // NOTE: Whenever Insight breaks communication with bitcoind, it returns invalid data but no error code.
    if (!_.isArray(txs) || (txs.length != _.compact(txs).length)) return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args)));

    return cb(null, txs);
  });
};

Insight.prototype.getAddressActivity = function(address, cb) {
  var self = this;

  var args = {
    method: 'GET',
    path: self.apiPrefix + '/addr/' + address,
    json: true,
  };

  this._doRequest(args, function(err, res, result) {
    if (res && res.statusCode == 404) return cb();
    if (err || res.statusCode !== 200)
      return cb(_parseErr(err, res));

    var nbTxs = result.unconfirmedTxApperances + result.txApperances;
    return cb(null, nbTxs > 0);
  });
};

Insight.prototype.estimateFee = function(nbBlocks, cb) {
  var path = this.apiPrefix + '/utils/estimatefee';
  if (nbBlocks) {
    path += '?nbBlocks=' + [].concat(nbBlocks).join(',');
  }

  var args = {
    method: 'GET',
    path: path,
    json: true,
  };
  this._doRequest(args, function(err, res, body) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, body);
  });
};

Insight.prototype.initSocket = function() {

  // sockets always use the first server on the pull
  var socket = io.connect(_.first([].concat(this.hosts)), {
    'reconnection': true,
  });
  return socket;
};

module.exports = Insight;
<commit_msg>blockchain height endpoint<commit_after>'use strict';

var _ = require('lodash');
var $ = require('preconditions').singleton();
var log = require('npmlog');
log.debug = log.verbose;
var io = require('socket.io-client');
var requestList = require('./request-list');

function Insight(opts) {
  $.checkArgument(opts);
  $.checkArgument(_.contains(['livenet', 'testnet'], opts.network));
  $.checkArgument(opts.url);

  this.apiPrefix = opts.apiPrefix || '/api';
  this.network = opts.network || 'livenet';
  this.hosts = opts.url;
  this.userAgent = opts.userAgent || 'bws';
};

var _parseErr = function(err, res) {
  if (err) {
    log.warn('Insight error: ', err);
    return "Insight Error";
  }
  log.warn("Insight " + res.request.href + " Returned Status: " + res.statusCode);
  return "Error querying the blockchain";
};

Insight.prototype._doRequest = function(args, cb) {
  var opts = {
    hosts: this.hosts,
    headers: {
      'User-Agent': this.userAgent,
    }
  };
  requestList(_.defaults(args, opts), cb);
};

Insight.prototype.getConnectionInfo = function() {
  return 'Insight (' + this.network + ') @ ' + this.hosts;
};

/**
 * Retrieve a list of unspent outputs associated with an address or set of addresses
 */
Insight.prototype.getUtxos = function(addresses, cb) {
  var url = this.url + this.apiPrefix + '/addrs/utxo';
  var args = {
    method: 'POST',
    path: this.apiPrefix + '/addrs/utxo',
    json: {
      addrs: [].concat(addresses).join(',')
    },
  };

  this._doRequest(args, function(err, res, unspent) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, unspent);
  });
};

/**
 * Broadcast a transaction to the bitcoin network
 */
Insight.prototype.broadcast = function(rawTx, cb) {
  var args = {
    method: 'POST',
    path: this.apiPrefix + '/tx/send',
    json: {
      rawtx: rawTx
    },
  };

  this._doRequest(args, function(err, res, body) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, body ? body.txid : null);
  });
};

Insight.prototype.getTransaction = function(txid, cb) {
  var args = {
    method: 'GET',
    path: this.apiPrefix + '/tx/' + txid,
    json: true,
  };

  this._doRequest(args, function(err, res, tx) {
    if (res && res.statusCode == 404) return cb();
    if (err || res.statusCode !== 200)
      return cb(_parseErr(err, res));

    return cb(null, tx);
  });
};

Insight.prototype.getTransactions = function(addresses, from, to, cb) {
  var qs = [];
  if (_.isNumber(from)) qs.push('from=' + from);
  if (_.isNumber(to)) qs.push('to=' + to);

  // Trim output
  qs.push('noAsm=1');
  qs.push('noScriptSig=1');
  qs.push('noSpent=1');

  var args = {
    method: 'POST',
    path: this.apiPrefix + '/addrs/txs' + (qs.length > 0 ? '?' + qs.join('&') : ''),
    json: {
      addrs: [].concat(addresses).join(',')
    },
  };

  this._doRequest(args, function(err, res, txs) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));

    if (_.isObject(txs) && txs.items)
      txs = txs.items;

    // NOTE: Whenever Insight breaks communication with bitcoind, it returns invalid data but no error code.
    if (!_.isArray(txs) || (txs.length != _.compact(txs).length)) return cb(new Error('Could not retrieve transactions from blockchain. Request was:' + JSON.stringify(args)));

    return cb(null, txs);
  });
};

Insight.prototype.getAddressActivity = function(address, cb) {
  var self = this;

  var args = {
    method: 'GET',
    path: self.apiPrefix + '/addr/' + address,
    json: true,
  };

  this._doRequest(args, function(err, res, result) {
    if (res && res.statusCode == 404) return cb();
    if (err || res.statusCode !== 200)
      return cb(_parseErr(err, res));

    var nbTxs = result.unconfirmedTxApperances + result.txApperances;
    return cb(null, nbTxs > 0);
  });
};

Insight.prototype.estimateFee = function(nbBlocks, cb) {
  var path = this.apiPrefix + '/utils/estimatefee';
  if (nbBlocks) {
    path += '?nbBlocks=' + [].concat(nbBlocks).join(',');
  }

  var args = {
    method: 'GET',
    path: path,
    json: true,
  };
  this._doRequest(args, function(err, res, body) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, body);
  });
};

Insight.prototype.getBlockchainHeight = function(cb) {
  var path = this.apiPrefix + '/sync';

  var args = {
    method: 'GET',
    path: path,
    json: true,
  };
  this._doRequest(args, function(err, res, body) {
    if (err || res.statusCode !== 200) return cb(_parseErr(err, res));
    return cb(null, body.blockChainHeight);
  });
};

Insight.prototype.initSocket = function() {

  // sockets always use the first server on the pull
  var socket = io.connect(_.first([].concat(this.hosts)), {
    'reconnection': true,
  });
  return socket;
};

module.exports = Insight;
<|endoftext|>


<commit_before>/*******************************************************
 * todo-mvc implementation
 * siren representor (server)
 * June 2015
 * Mike Amundsen (@mamund)
 * Soundtrack : Motown Classics Gold (2005)
 *******************************************************/

/* NOTE:
  - has fatal dependency on:
    - uritemplate.js
    - dom-help.js
  - uses no other external libs/frameworks

  - built/tested for chrome browser (YMMV on other browsers)
  - designed to act as a "validator" for a human-driven HAL client.
  - not production robust (missing error-handling, perf-tweaking, etc.)
  - report issues to https://github.com/lchbook/
*/

function siren() {

  var d = domHelp();
  var g = {};

  g.url = '';
  g.siren = null;
  g.ctype = "application/vnd.siren+json";
  g.title = "";

  // init library and start
  function init(url, title) {

    g.title = title||"Siren Client";

    if(!url || url==='') {
      alert('*** ERROR:\n\nMUST pass starting URL to the library');
    }
    else {
      g.url = url;
      req(g.url,"get");
    }
  }

  // primary loop
  function parseSiren() {
    sirenClear();
    title();
    dump();
    links();
    entities();
    actions();
    properties();
  }

  // handle title for page
  // HAL offers no title so we use our own
  function title() {
    var elm = d.find("title");
    elm.innerText = g.title;
  }

  // handle response dump
  // just for debugging help
  function dump() {
    var elm = d.find("dump");
    elm.innerText = JSON.stringify(g.siren, null, 2);
  }

  // links
  function links() {
    var elm, coll;

    elm = d.find("links");
    d.clear(elm);

    if(g.siren.links) {
      ul = d.node("ul");
      ul.onclick = httpGet;
      coll = g.siren.links;
      for(var link of coll) {
        li = d.node("li");
        a = d.anchor({
          rel:link.rel.join(" "),
          href:link.href,
          text:link.title||link.href,
          className:link.class.join(" "),
          type:link.type||""
        });
        d.push(a, li);
        d.push(li,ul);
      }
      d.push(ul, elm);
    }
  }

  // _entities
  function entities() {
  }

  // actions
  function actions() {
  }

  // properties
  function properties() {
  }

  // ***************************
  // siren helpers
  // ***************************

  // clear out the page
  function sirenClear() {
    var elm;

    elm = d.find("dump");
    d.clear(elm);
    elm = d.find("links");
    d.clear(elm);
    elm = d.find("actions");
    d.clear(elm);
    elm = d.find("entities");
    d.clear(elm);
    elm = d.find("properties");
    d.clear(elm);
  }

  // ********************************
  // ajax helpers
  // ********************************

  // mid-level HTTP handlers
  function httpGet(e) {
    req(e.target.href, "get", null);
    return false;
  }

  // low-level HTTP stuff
  function req(url, method, body, content, accept) {
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function(){rsp(ajax)};
    ajax.open(method, url);
    ajax.setRequestHeader("accept",accept||g.ctype);
    if(body && body!==null) {
      ajax.setRequestHeader("content-type", content||g.ctype);
    }
    ajax.send(body);
  }

  function rsp(ajax) {
    if(ajax.readyState===4) {
      g.siren = JSON.parse(ajax.responseText);
      parseSiren();
    }
  }

  // export function
  var that = {};
  that.init = init;
  return that;
}

// *** EOD ***
<commit_msg>refactor names<commit_after>/*******************************************************
 * todo-mvc implementation
 * siren representor (server)
 * June 2015
 * Mike Amundsen (@mamund)
 * Soundtrack : Motown Classics Gold (2005)
 *******************************************************/

/* NOTE:
  - has fatal dependency on:
    - uritemplate.js
    - dom-help.js
  - uses no other external libs/frameworks

  - built/tested for chrome browser (YMMV on other browsers)
  - designed to act as a "validator" for a human-driven HAL client.
  - not production robust (missing error-handling, perf-tweaking, etc.)
  - report issues to https://github.com/lchbook/
*/

function siren() {

  var d = domHelp();
  var g = {};

  g.url = '';
  g.msg = null;
  g.ctype = "application/vnd.siren+json";
  g.title = "";

  // init library and start
  function init(url, title) {

    g.title = title||"Siren Client";

    if(!url || url==='') {
      alert('*** ERROR:\n\nMUST pass starting URL to the library');
    }
    else {
      g.url = url;
      req(g.url,"get");
    }
  }

  // primary loop
  function parseMsg() {
    sirenClear();
    title();
    dump();
    links();
    entities();
    actions();
    properties();
  }

  // handle title for page
  // HAL offers no title so we use our own
  function title() {
    var elm = d.find("title");
    elm.innerText = g.title;
  }

  // handle response dump
  // just for debugging help
  function dump() {
    var elm = d.find("dump");
    elm.innerText = JSON.stringify(g.msg, null, 2);
  }

  // links
  function links() {
    var elm, coll;

    elm = d.find("links");
    d.clear(elm);

    if(g.msg.links) {
      ul = d.node("ul");
      ul.onclick = httpGet;
      coll = g.msg.links;
      for(var link of coll) {
        li = d.node("li");
        a = d.anchor({
          rel:link.rel.join(" "),
          href:link.href,
          text:link.title||link.href,
          className:link.class.join(" "),
          type:link.type||""
        });
        d.push(a, li);
        d.push(li,ul);
      }
      d.push(ul, elm);
    }
  }

  // _entities
  function entities() {
  }

  // actions
  function actions() {
  }

  // properties
  function properties() {
  }

  // ***************************
  // siren helpers
  // ***************************

  // clear out the page
  function sirenClear() {
    var elm;

    elm = d.find("dump");
    d.clear(elm);
    elm = d.find("links");
    d.clear(elm);
    elm = d.find("actions");
    d.clear(elm);
    elm = d.find("entities");
    d.clear(elm);
    elm = d.find("properties");
    d.clear(elm);
  }

  // ********************************
  // ajax helpers
  // ********************************

  // mid-level HTTP handlers
  function httpGet(e) {
    req(e.target.href, "get", null);
    return false;
  }

  // low-level HTTP stuff
  function req(url, method, body, content, accept) {
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function(){rsp(ajax)};
    ajax.open(method, url);
    ajax.setRequestHeader("accept",accept||g.ctype);
    if(body && body!==null) {
      ajax.setRequestHeader("content-type", content||g.ctype);
    }
    ajax.send(body);
  }

  function rsp(ajax) {
    if(ajax.readyState===4) {
      g.msg = JSON.parse(ajax.responseText);
      parseMsg();
    }
  }

  // export function
  var that = {};
  that.init = init;
  return that;
}

// *** EOD ***
<|endoftext|>