<commit_before>// @flow

import fs from 'mz/fs';
import fsExtra from 'fs-extra';
import noop from 'lodash/noop';
import inquirer from 'inquirer';
import semver from 'semver';
import { chalkNok, chalkNpmDep, chalkOk } from '../../../shared/chalk';
import { resolveProject, resolveRoot } from '../../util/resolve-util';
import logger from '../../../shared/logger';
import { execSync } from '../../util/process-util';

// TODO: handle NPM install crashes if module not found
// TODO: while running, print that the task is running
// TODO init git if package.json contains a repo ?
// TODO: Hide NPM's STDOUT if verbosity isn't debug.

export default function registerCommand(commander) {

  commander
    .command('init', 'Setups your project', noop, () => {
      runInitScripts();
    });
}

const scripts = {
  'Install peer dependencies': {
    isReady() {
      return false;
    },

    async run() {
      const { peerDependencies } = await fsExtra.readJson(resolveRoot('package.json'));
      const projectPkg = await fsExtra.readJson(resolveProject('package.json'));

      const installed = projectPkg.dependencies || {};

      const toInstall = [];
      for (const depName of Object.keys(peerDependencies)) {
        const depVersionRange = peerDependencies[depName];

        if (!installed[depName] || !semver.satisfies(semver.clean(installed[depName]), depVersionRange)) {
          toInstall.push(`${depName}@${depVersionRange}`);
        }
      }

      if (toInstall.length > 0) {
        logger.info(`Installing peer dependencies ${toInstall.map(dep => chalkNpmDep(dep)).join(', ')}`);
        execSync(`npm install --save ${toInstall.join(' ')}`);
      }
    },
  },

  'Add npm scripts': {
    async isReady() {
      const projectPkg = await fsExtra.readJson(resolveProject('package.json'));

      if (projectPkg.scripts) {
        return false;
      }

      if (!projectPkg.scripts.build && projectPkg.scripts['start:dev']) {
        return false;
      }

      if (!projectPkg.devDependencies['check-engines']) {
        return false;
      }

      return true;
    },

    async run() {
      const pkgPath = resolveProject('package.json');

      const projectPkg = await fsExtra.readJson(pkgPath);

      projectPkg.scripts = projectPkg.scripts || {};
      const pkgScripts = projectPkg.scripts;

      pkgScripts['start:dev'] = pkgScripts['start:dev'] || 'check-engines && NODE_ENV=development rjs start --port 3000';
      pkgScripts.build = pkgScripts.build || 'NODE_ENV=production rjs build client server';

      await fsExtra.writeJson(pkgPath, projectPkg);
      execSync(`npm install --save-dev check-engines`);
    },
  },

  'Install .gitignore': {

    /**
     * Check that the project contains a .gitignore file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.gitignore'));
    },

    run() {
      return fsExtra.copy(
        resolveRoot('resources/.gitignore.raw'),
        resolveProject('.gitignore'),
      );
    },
  },

  'Install .browserslistrc': {

    /**
     * Check that the project contains a .browserslistrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.browserslistrc'));
    },

    run() {
      return fsExtra.copy(
        resolveRoot('resources/.browserslistrc.raw'),
        resolveProject('.browserslistrc'),
      );
    },
  },

  'Install eslint': {

    /**
     * Check that the project contains a .eslintrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.eslintrc'));
    },

    async run() {
      const { preset } = await inquirer.prompt([{
        type: 'input',
        message: 'What ESLint preset do you want to use ? (blank for none).',
        name: 'preset',
        default() {
          return '';
        },
      }]);

      if (!preset) {
        return;
      }

      execSync(`npm install --save-dev eslint ${preset}`);

      await fs.writeFile(
        resolveProject('.eslintrc'),
        `{
  "extends": "${preset}"
}`,
      );
    },
  },

  'Install stylelint': {

    /**
     * Check that the project contains a .stylelintrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.stylelintrc'));
    },

    async run() {
      const { preset } = await inquirer.prompt([{
        type: 'input',
        message: 'What Stylelint preset do you want to use ? (blank for none).',
        name: 'preset',
        default() {
          return '';
        },
      }]);

      if (!preset) {
        return;
      }

      execSync(`npm install --save-dev stylelint ${preset}`);

      await fs.writeFile(
        resolveProject('.stylelintrc'),
        `{
  "extends": "${preset}"
}`,
      );
    },
  },

  'Install lint-staged': {
    async isReady() {

      const pck = await fsExtra.readJson(resolveProject('package.json'));

      // pre-commit disabled
      if (pck['pre-commit'] === false) {
        return true;
      }

      if (!pck.devDependencies['lint-staged']) {
        return false;
      }

      return pck.devDependencies.husky !== void 0;
    },

    async run() {
      execSync('npm install --save-dev husky lint-staged');

      // lint-staged config
      const lintStagedRc = resolveProject('.lintstagedrc');
      if (!await fs.exists(lintStagedRc)) {
        await fsExtra.copy(
          resolveRoot('resources/.lintstagedrc.raw'),
          lintStagedRc,
        );
      }

      const huskyJson = resolveProject('.huskyrc.json');
      if (!await fs.exists(huskyJson)) {
        await fsExtra.copy(
          resolveRoot('resources/.huskyrc.json'),
          huskyJson,
        );
      }
    },
  },

  'Configure PostCss': {
    isReady() {
      return fs.exists(resolveProject('postcss.config.js'));
    },

    async run() {
      execSync('npm install --save-dev @reworkjs/postcss-preset-reworkjs');

      await fsExtra.copy(
        resolveRoot('resources/postcss.config.js.raw'),
        resolveProject('postcss.config.js'),
      );
    },
  },

  // 'Add README': {
  //   isReady() {
  //     // check there is a README file
  //   },
  //
  //   run() {
  //     /*
  //      - Add README.md
  //      */
  //   },
  // },
};

const emptyPromise = Promise.resolve();

function runInitScripts() {

  let promise = emptyPromise;
  for (const scriptName of Object.keys(scripts)) {
    // run sequentially, don't Promise.all this.
    promise = promise.then(() => {
      return runScript(scriptName, scripts[scriptName]);
    });
  }

  /*
   - print "Project ready, use `rjs start --env dev` to launch your project. Read more at <getting started doc url>"
   */
}

async function runScript(scriptName, script) {
  try {
    if (typeof script.isReady === 'function') {
      const isReady = await script.isReady();
      if (typeof isReady !== 'boolean') {
        logger.info(`${chalkNok('✘')} ${scriptName} - Script has a bug.`);

        return;
      }

      if (isReady) {
        logger.info(`${chalkOk('✓')} ${scriptName}`);

        return;
      }
    }

    await script.run();

    logger.info(`${chalkOk('✓')} ${scriptName}`);
  } catch (e) {
    logger.info(`${chalkNok('✘')} ${scriptName} - Script crashed.`);
    throw e;
  }
}
<commit_msg>fix: fix husky init crash<commit_after>// @flow

import fs from 'mz/fs';
import fsExtra from 'fs-extra';
import noop from 'lodash/noop';
import inquirer from 'inquirer';
import semver from 'semver';
import { chalkNok, chalkNpmDep, chalkOk } from '../../../shared/chalk';
import { resolveProject, resolveRoot } from '../../util/resolve-util';
import logger from '../../../shared/logger';
import { execSync } from '../../util/process-util';

// TODO: handle NPM install crashes if module not found
// TODO: while running, print that the task is running
// TODO init git if package.json contains a repo ?
// TODO: Hide NPM's STDOUT if verbosity isn't debug.

export default function registerCommand(commander) {

  commander
    .command('init', 'Setups your project', noop, () => {
      runInitScripts();
    });
}

const scripts = {
  'Install peer dependencies': {
    isReady() {
      return false;
    },

    async run() {
      const { peerDependencies } = await fsExtra.readJson(resolveRoot('package.json'));
      const projectPkg = await fsExtra.readJson(resolveProject('package.json'));

      const installed = projectPkg.dependencies || {};

      const toInstall = [];
      for (const depName of Object.keys(peerDependencies)) {
        const depVersionRange = peerDependencies[depName];

        if (!installed[depName] || !semver.satisfies(semver.clean(installed[depName]), depVersionRange)) {
          toInstall.push(`${depName}@${depVersionRange}`);
        }
      }

      if (toInstall.length > 0) {
        logger.info(`Installing peer dependencies ${toInstall.map(dep => chalkNpmDep(dep)).join(', ')}`);
        execSync(`npm install --save ${toInstall.join(' ')}`);
      }
    },
  },

  'Add npm scripts': {
    async isReady() {
      const projectPkg = await fsExtra.readJson(resolveProject('package.json'));

      if (projectPkg.scripts) {
        return false;
      }

      if (!projectPkg.scripts.build && projectPkg.scripts['start:dev']) {
        return false;
      }

      if (!projectPkg.devDependencies['check-engines']) {
        return false;
      }

      return true;
    },

    async run() {
      const pkgPath = resolveProject('package.json');

      const projectPkg = await fsExtra.readJson(pkgPath);

      projectPkg.scripts = projectPkg.scripts || {};
      const pkgScripts = projectPkg.scripts;

      pkgScripts['start:dev'] = pkgScripts['start:dev'] || 'check-engines && NODE_ENV=development rjs start --port 3000';
      pkgScripts.build = pkgScripts.build || 'NODE_ENV=production rjs build client server';

      await fsExtra.writeJson(pkgPath, projectPkg);
      execSync(`npm install --save-dev check-engines`);
    },
  },

  'Install .gitignore': {

    /**
     * Check that the project contains a .gitignore file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.gitignore'));
    },

    run() {
      return fsExtra.copy(
        resolveRoot('resources/.gitignore.raw'),
        resolveProject('.gitignore'),
      );
    },
  },

  'Install .browserslistrc': {

    /**
     * Check that the project contains a .browserslistrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.browserslistrc'));
    },

    run() {
      return fsExtra.copy(
        resolveRoot('resources/.browserslistrc.raw'),
        resolveProject('.browserslistrc'),
      );
    },
  },

  'Install eslint': {

    /**
     * Check that the project contains a .eslintrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.eslintrc'));
    },

    async run() {
      const { preset } = await inquirer.prompt([{
        type: 'input',
        message: 'What ESLint preset do you want to use ? (blank for none).',
        name: 'preset',
        default() {
          return '';
        },
      }]);

      if (!preset) {
        return;
      }

      execSync(`npm install --save-dev eslint ${preset}`);

      await fs.writeFile(
        resolveProject('.eslintrc'),
        `{
  "extends": "${preset}"
}`,
      );
    },
  },

  'Install stylelint': {

    /**
     * Check that the project contains a .stylelintrc file.
     * @async
     * @returns {!boolean}
     */
    isReady() {
      return fs.exists(resolveProject('.stylelintrc'));
    },

    async run() {
      const { preset } = await inquirer.prompt([{
        type: 'input',
        message: 'What Stylelint preset do you want to use ? (blank for none).',
        name: 'preset',
        default() {
          return '';
        },
      }]);

      if (!preset) {
        return;
      }

      execSync(`npm install --save-dev stylelint ${preset}`);

      await fs.writeFile(
        resolveProject('.stylelintrc'),
        `{
  "extends": "${preset}"
}`,
      );
    },
  },

  'Install lint-staged': {
    async isReady() {

      const pck = await fsExtra.readJson(resolveProject('package.json'));

      // pre-commit disabled
      if (pck['pre-commit'] === false) {
        return true;
      }

      if (!pck.devDependencies['lint-staged']) {
        return false;
      }

      return pck.devDependencies.husky !== void 0;
    },

    async run() {
      execSync('npm install --save-dev husky lint-staged');

      // lint-staged config
      const lintStagedRc = resolveProject('.lintstagedrc');
      if (!await fs.exists(lintStagedRc)) {
        await fsExtra.copy(
          resolveRoot('resources/.lintstagedrc.raw'),
          lintStagedRc,
        );
      }

      const huskyJson = resolveProject('.huskyrc.json');
      if (!await fs.exists(huskyJson)) {
        await fsExtra.copy(
          resolveRoot('resources/.huskyrc.json.raw'),
          huskyJson,
        );
      }
    },
  },

  'Configure PostCss': {
    isReady() {
      return fs.exists(resolveProject('postcss.config.js'));
    },

    async run() {
      execSync('npm install --save-dev @reworkjs/postcss-preset-reworkjs');

      await fsExtra.copy(
        resolveRoot('resources/postcss.config.js.raw'),
        resolveProject('postcss.config.js'),
      );
    },
  },

  // 'Add README': {
  //   isReady() {
  //     // check there is a README file
  //   },
  //
  //   run() {
  //     /*
  //      - Add README.md
  //      */
  //   },
  // },
};

const emptyPromise = Promise.resolve();

function runInitScripts() {

  let promise = emptyPromise;
  for (const scriptName of Object.keys(scripts)) {
    // run sequentially, don't Promise.all this.
    promise = promise.then(() => {
      return runScript(scriptName, scripts[scriptName]);
    });
  }

  /*
   - print "Project ready, use `rjs start --env dev` to launch your project. Read more at <getting started doc url>"
   */
}

async function runScript(scriptName, script) {
  try {
    if (typeof script.isReady === 'function') {
      const isReady = await script.isReady();
      if (typeof isReady !== 'boolean') {
        logger.info(`${chalkNok('✘')} ${scriptName} - Script has a bug.`);

        return;
      }

      if (isReady) {
        logger.info(`${chalkOk('✓')} ${scriptName}`);

        return;
      }
    }

    await script.run();

    logger.info(`${chalkOk('✓')} ${scriptName}`);
  } catch (e) {
    logger.info(`${chalkNok('✘')} ${scriptName} - Script crashed.`);
    throw e;
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import Document, { Head, Main, NextScript } from 'next/document'

export default class MyDocument extends Document {
  render() {
    return (
      <html>
        <Head>
          <meta charSet='utf-8' />
          <meta name='viewport' content='initial-scale=1.0, width=device-width' />
          <meta name='author' content='BanManager-WebUI' />
          <link rel="stylesheet" href="/_next/static/style.css" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}
<commit_msg>chore(accessibility): added lang to <html><commit_after>import React from 'react'
import Document, { Head, Main, NextScript } from 'next/document'

export default class MyDocument extends Document {
  render() {
    return (
      <html lang='en'>
        <Head>
          <meta charSet='utf-8' />
          <meta name='viewport' content='initial-scale=1.0, width=device-width' />
          <meta name='author' content='BanManager-WebUI' />
          <link rel="stylesheet" href="/_next/static/style.css" />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}
<|endoftext|>


<commit_before><commit_msg>dashboard.js updated<commit_after>$.getJSON("../syllabus.json", function(json) {
    syllabus = json; // this will show the info it in firebug console
    $("#side-menu").append(get_menu_html());
    $('#side-menu').metisMenu();
});
function get_func_val(fx, values)
{

    for (key in values) {
        if (values.hasOwnProperty(key)) {
            fx = fx.replace(new RegExp(key, 'g'),values[key]);
        }
    }
    return eval(fx);
}
function get_input(form_id)
{
    var inputs = $("#"+form_id+" input");
    var form_data = {};
    for(var i=0;i<inputs.length;i++)
    {
        var input = $(inputs[i]);
        var input_name = input.attr("name");
        var input_type = input.attr("data-type");
        var input_value = input.val();
        if(input_type == "float")
        {
            processed_value = parseFloat(input_value);
        }
        else if(input_type == "int")
        {
            processed_value = parseInt(input_value);
        }
        else
        {
            processed_value = input_value;
        }
        form_data[input_name] = processed_value;
    }
    return form_data;
}
function get_menu_html()
{

    var chapters = syllabus.chapters;
    var html_str = "";
    for(var i = 0; i < chapters.length; i++)
    {
        var name = chapters[i].name;
        var topics = chapters[i].topics;

        html_str += "
";
        html_str += '#'+(i+1) +". "+name+'';
        if(topics!=undefined && topics.length>0)
        {
            html_str += '
';
            for(var j = 0;j<topics.length;j++)
            {
                html_str += '
';
                html_str += ''+topics[j]+'';
                html_str += '
';
            }
            html_str += '
';

        }

        html_str += "
";
    }
    return html_str;
}

$("#side-menu").on("click",".topics_link",function(){
var chapter_id = $(this).attr("data-chapter");
var topic_id = $(this).attr("data-topic");
var chapter_name = syllabus.chapters[chapter_id].name;
var topic_name = syllabus.chapters[chapter_id].topics[topic_id];
var code_demo = '
';
  code_demo += '<button type="button"  class="btn btn-default code_demo" data-action="code">Code</button>';
  code_demo += '<button type="button" class="btn btn-default btn-success code_demo" data-action="demo">Demo</button>';
code_demo += '
';
$("#index_content").hide();
$("#page_title").html(topic_name+code_demo);
$.get("chapter"+(parseInt(chapter_id)+1)+"/"+String.fromCharCode(97+parseInt(topic_id))+".html", function(html_content) {
    current_html = html_content;
    $("#content_area").html(current_html);
}).fail(function() {
    $("#content_area").html("This topic is still under construction. Please contribute :)");
  });
});

$("#page_title").on("click",".code_demo",function(){
$(".code_demo").removeClass("btn-success");
$(this).addClass("btn-success");
var action = $(this).attr("data-action");
if(action == "code")
{
    var safe_html = $('
').text(current_html).html();

    $("#content_area").html("<textarea class='col-lg-12' rows='22' disabled>"+safe_html+"</textarea>");
}
else
{
     $("#content_area").html(current_html);
}
});<|endoftext|>


<commit_before>import * as THREE from 'three';
import 'whatwg-fetch';
import Helpers from '../../utils/helpers';

export default class SoundZone {
  constructor(main, points) {
    this.type = 'SoundZone';
    this.isActive = true;
    this.audio = main.audio;

    this.mouse = main.mouse;
    this.scene = main.scene;

    this.points = points;
    this.splinePoints = points;
    this.pointObjects;
    this.spline;
    this.shape;
    this.sound;
    this.loaded = false;
    this.isPlaying = false;
    this.selectedPoint;
    this.mouseOffsetX = 0, this.mouseOffsetY = 0;
    this.volume = 1;

    this.containerObject = new THREE.Group();
    this.cursor = new THREE.Mesh(
      new THREE.SphereGeometry(15),
      new THREE.MeshBasicMaterial({
        color: 0xff1169,
        transparent: true,
        opacity: 0.5,
      })
    );
    this.cursor.visible = false;
    this.containerObject.add(this.cursor);

    this.isInitialized = false;

    this.renderPath();
  }

  underUser(audio) {
    if (this.sound && !this.isPlaying && this.loaded) {

      this.sound.source = audio.context.createBufferSource();
      this.sound.source.buffer = this.sound.buffer;
      this.sound.source.loop = true;
      this.sound.source.volume = audio.context.createGain();
      this.sound.source.volume.gain.value = this.volume;
      this.sound.source.connect(this.sound.source.volume);
      this.sound.source.volume.connect(this.sound.volume);

      this.sound.source.start(audio.context.currentTime);

      this.sound.volume.gain.setTargetAtTime(1.0, audio.context.currentTime + 0.1, 0.1);
      this.isPlaying = true;
    }
  }

  notUnderUser(audio) {
    if (this.sound && this.isPlaying && this.loaded) {
      this.sound.volume.gain.setTargetAtTime(0.0, audio.context.currentTime, 0.02);
      this.sound.source.stop(audio.context.currentTime + 0.1);
      this.isPlaying = false;
    }
  }

  // remove sound file
  clear() {
    // stop audio stream if currently playing
    if (this.isPlaying) {
      this.sound.source.stop();
    }
    this.isPlaying = false;
    this.loaded = false;
    this.mainMixer = null;
    this.sound = {};
  }

  loadSound(soundFileName, audio, mute) {
    const context = audio.context;
    this.filename = soundFileName;

    let promise = fetch(soundFileName)
      .then(response => response.arrayBuffer())
      .then(buffer => context.decodeAudioData(buffer, (decodedData) => {
        this.clear();
        this.sound.name = soundFileName;
        this.sound.source = context.createBufferSource();
        this.mainMixer = context.createGain();
        this.sound.volume = context.createGain();
        this.sound.source.volume = context.createGain();
        this.sound.source.connect(this.sound.source.volume);
        this.sound.source.volume.connect(this.sound.volume);
        this.sound.volume.connect(this.mainMixer);
        this.mainMixer.connect(audio.destination);
        this.mainMixer.gain.value = mute ? 0 : 1;
        this.sound.volume.gain.value = 0.0;
        this.sound.buffer = decodedData;
        this.loaded = true;
      }));

    promise
      .catch(err => {
        alert('could not load file');
        console.log(err);
      });

    return promise;
  }

  renderPath(args) {
    // splinePoints control the curve of the path
    const points = this.splinePoints;

    // setup
    const sphere = new THREE.SphereGeometry(10);
    const sphereMat = new THREE.MeshBasicMaterial({ color: 0xff1169 });

    const collider = new THREE.SphereGeometry(15);
    const colliderMat = new THREE.MeshBasicMaterial({
      color: 0xff1169,
      transparent: true,
      opacity: 0,
      depthWrite: false,
    });

    const colliderMesh = new THREE.Mesh(collider, colliderMat);

    if (!this.isInitialized) {
      this.pointObjects = [];
      // place a meshgroup at each point in array
      points.forEach((point) => {
        const sphereMesh = new THREE.Mesh(sphere, sphereMat.clone());
        const group = new THREE.Object3D();

        group.add(sphereMesh, colliderMesh.clone());
        group.position.copy(point);

        this.pointObjects.push(group);
      });
      this.splinePoints = this.pointObjects.map( pt => pt.position );
    }
    else if (args) {
      if (args.updateType === "delete") {
        let splicedPoint = this.pointObjects.splice(args.index, 1);
        this.containerObject.remove(splicedPoint[0], true);
      }
      else if (args.updateType === "add") {
        let insertedPoint = new THREE.Object3D();
        insertedPoint.add(
          new THREE.Mesh(sphere, sphereMat.clone()),
          colliderMesh.clone()
        );
        insertedPoint.position.copy(this.splinePoints[args.index]);
        this.pointObjects.splice(args.index, 0, insertedPoint);
        this.containerObject.add(insertedPoint);
      }
      this.splinePoints = this.pointObjects.map( pt => pt.position );
    }

    this.spline = new THREE.CatmullRomCurve3(this.splinePoints);
    this.spline.type = 'centripetal';
    this.spline.closed = true;

    const geometry = new THREE.Geometry();
    geometry.vertices = this.spline.getPoints(200);
    let material = new THREE.LineBasicMaterial({
      color: 0xff1169,
      linewidth: 1,
      transparent: true,
      opacity: 0.4,
    });

    this.spline.mesh = new THREE.Line(geometry, material);

    // fill the path
    const rotatedPoints = this.spline.getPoints(200);
    rotatedPoints.forEach((vertex) => {
      vertex.y = vertex.z;
      vertex.z = 0.0;
    });
    const shapeFill = new THREE.Shape();
    shapeFill.fromPoints(rotatedPoints);
    const shapeGeometry = new THREE.ShapeGeometry(shapeFill);
    shapeGeometry.rotateX(Math.PI / 2);
    material = new THREE.MeshLambertMaterial({
      color: 0xff1169,
      transparent: true,
      opacity: Helpers.mapRange(this.volume, 0, 2, 0.05, 0.35),
      side: THREE.BackSide,
      premultipliedAlpha: true
    });

    this.shape = new THREE.Mesh(shapeGeometry, material);
  }

  get objects() {
    return [].concat(this.pointObjects, this.spline.mesh, this.shape);
  }

  addToScene() {
    if (!this.isInitialized) {
      this.isInitialized = true;

      var box = new THREE.Box3().setFromObject( this.shape );
      box.getCenter( this.containerObject.position );
      this.scene.add(this.containerObject);
      this.objects.forEach((obj) => {
        obj.translateX(-this.containerObject.position.x);
        obj.translateZ(-this.containerObject.position.z);
        this.containerObject.add(obj);
      });
    }
    else {
      this.containerObject.add(this.shape);
      this.containerObject.add(this.spline.mesh);
    }
  }

  removeFromScene(scene) {
    this.scene.remove(this.containerObject, true);
  }

  // raycast to this soundzone
  isUnderMouse(raycaster) {
    if (this.isActive) {
      return raycaster.intersectObjects(this.objects).length > 0;
    }

    return raycaster.intersectObject(this.shape).length > 0;
  }

  objectUnderMouse(raycaster) {
    const intersects = raycaster.intersectObjects(this.objects, true);

    if (intersects.length > 0) {
      if (intersects[0].object.type === 'Line' || intersects[0].object === this.shape) {
        return intersects[Math.floor(intersects.length / 2)];
      }

      return intersects[0];
    }

    return null;
  }

  hideCursor() {
    this.cursor.visible = false;
  }
  showCursor(object, point) {
    if (object !== this.shape) {
      this.cursor.visible = true;
      if (object === this.spline.mesh) {
        const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
        this.cursor.position.copy(point.applyMatrix4(minv));
      }
      else {
        this.cursor.position.copy(object.parent.position);
      }
    }
    else {
      this.hideCursor();
    }
  }

  setMouseOffset(point) {
    this.mouseOffsetX = point.x;
    this.mouseOffsetY = point.z;
  }

  updateZone(args) {
    const scene = this.spline.mesh.parent;
    this.containerObject.remove(this.spline.mesh, true);
    this.containerObject.remove(this.shape, true);
    this.renderPath(args);
    this.addToScene(scene);
  }

  move(main) {
    if (!main.perspectiveView) {
      const dx = main.mouse.x - this.mouseOffsetX;
      const dy = main.mouse.z - this.mouseOffsetY;
      this.mouseOffsetX = main.mouse.x;
      this.mouseOffsetY = main.mouse.z;
      this.hideCursor();

      if (this.selectedPoint) {
        // move selected point
        const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
        this.selectedPoint.position.copy(main.mouse.applyMatrix4(minv));
        this.updateZone();
      } else {
        // move entire shape

        this.containerObject.position.x += dx;
        this.containerObject.position.z += dy;
      }
    }
  }

  setActive(main) {
    this.setMouseOffset(main.mouse);
    this.isActive = true;
    this.pointObjects.forEach(obj => (obj.visible = true));
    this.spline.mesh.visible = true;
  }

  setInactive() {
    this.hideCursor();
    this.deselectPoint();
    this.isActive = false;
    this.pointObjects.forEach(obj => (obj.visible = false));
    this.spline.mesh.visible = false;
  }

  select(intersect) {
    if (!intersect) return;

    // obj can be the curve, a spline point, or the shape mesh
    const obj = intersect.object;

    if (obj.type === 'Line') {
      // add a point to the line
      this.addPoint(intersect.point);
    } else if (obj.parent.type === 'Object3D') {
      // select an existing point on line
      this.selectPoint(obj.parent);
    } else {
      this.deselectPoint();
      this.setMouseOffset(intersect.point);
    }
  }

  removePoint() {
    // find point in array
    const i = this.pointObjects.indexOf(this.selectedPoint);
    this.splinePoints.splice(i, 1);
    this.deselectPoint();
    this.updateZone({index: i, updateType: "delete"});
  }

  addPoint(point) {
    const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
    const position = point.applyMatrix4(minv);

    let closestSplinePoint = 0;
    let prevDistToSplinePoint = -1;
    let minDistance = Number.MAX_VALUE;
    let minPoint = 1;

    // search for point on spline
    for (let t = 0; t < 1; t += 1 / 200.0) {
      const pt = this.spline.getPoint(t);

      const distToSplinePoint = this.splinePoints[closestSplinePoint].distanceToSquared(pt);
      if (distToSplinePoint > prevDistToSplinePoint) {
        closestSplinePoint += 1;

        if (closestSplinePoint >= this.splinePoints.length) {
          closestSplinePoint = 0;
        }
      }
      prevDistToSplinePoint = this.splinePoints[closestSplinePoint].distanceToSquared(pt);
      const distToPoint = pt.distanceToSquared(position);
      if (distToPoint < minDistance) {
        minDistance = distToPoint;
        minPoint = closestSplinePoint;
      }
    }

    this.splinePoints.splice(minPoint, 0, position);
    this.updateZone({index: minPoint, updateType: "add"});
    this.selectPoint(this.pointObjects[minPoint]);
  }

  selectPoint(obj) {
    this.deselectPoint();
    this.selectedPoint = obj;
    obj.children[0].material.color.set('blue');
  }

  deselectPoint() {
    if (this.selectedPoint) {
      this.selectedPoint.children[0].material.color.set('red');
      this.selectedPoint = null;
    }
  }

  mute(main) {
    this.isMuted = true;
    this.checkMuteState(main);
  }
  unmute(main) {
    this.isMuted = false;
    this.checkMuteState(main);
  }

  checkMuteState(main) {
    if (this.mainMixer) {
      if (main.isMuted || this.isMuted) {
        this.mainMixer.gain.value = 0;
      }
      else {
        this.mainMixer.gain.value = 1;
      }
    }
  }

  toJSON() {
    console.log(this.points);
    return JSON.stringify({
      position: this.containerObject.position,
      points: this.splinePoints,
      filename: this.filename
    });
  }

  fromJSON(json) {
    let object = JSON.parse(json);
    this.containerObject.position.copy(object.position);

    this.loadSound(object.filename, this.audio, false);
  }
}
<commit_msg>remove altitude restriction on moving soundzones<commit_after>import * as THREE from 'three';
import 'whatwg-fetch';
import Helpers from '../../utils/helpers';

export default class SoundZone {
  constructor(main, points) {
    this.type = 'SoundZone';
    this.isActive = true;
    this.audio = main.audio;

    this.mouse = main.mouse;
    this.scene = main.scene;

    this.points = points;
    this.splinePoints = points;
    this.pointObjects;
    this.spline;
    this.shape;
    this.sound;
    this.loaded = false;
    this.isPlaying = false;
    this.selectedPoint;
    this.mouseOffsetX = 0, this.mouseOffsetY = 0;
    this.volume = 1;

    this.containerObject = new THREE.Group();
    this.cursor = new THREE.Mesh(
      new THREE.SphereGeometry(15),
      new THREE.MeshBasicMaterial({
        color: 0xff1169,
        transparent: true,
        opacity: 0.5,
      })
    );
    this.cursor.visible = false;
    this.containerObject.add(this.cursor);

    this.isInitialized = false;

    this.renderPath();
  }

  underUser(audio) {
    if (this.sound && !this.isPlaying && this.loaded) {

      this.sound.source = audio.context.createBufferSource();
      this.sound.source.buffer = this.sound.buffer;
      this.sound.source.loop = true;
      this.sound.source.volume = audio.context.createGain();
      this.sound.source.volume.gain.value = this.volume;
      this.sound.source.connect(this.sound.source.volume);
      this.sound.source.volume.connect(this.sound.volume);

      this.sound.source.start(audio.context.currentTime);

      this.sound.volume.gain.setTargetAtTime(1.0, audio.context.currentTime + 0.1, 0.1);
      this.isPlaying = true;
    }
  }

  notUnderUser(audio) {
    if (this.sound && this.isPlaying && this.loaded) {
      this.sound.volume.gain.setTargetAtTime(0.0, audio.context.currentTime, 0.02);
      this.sound.source.stop(audio.context.currentTime + 0.1);
      this.isPlaying = false;
    }
  }

  // remove sound file
  clear() {
    // stop audio stream if currently playing
    if (this.isPlaying) {
      this.sound.source.stop();
    }
    this.isPlaying = false;
    this.loaded = false;
    this.mainMixer = null;
    this.sound = {};
  }

  loadSound(soundFileName, audio, mute) {
    const context = audio.context;
    this.filename = soundFileName;

    let promise = fetch(soundFileName)
      .then(response => response.arrayBuffer())
      .then(buffer => context.decodeAudioData(buffer, (decodedData) => {
        this.clear();
        this.sound.name = soundFileName;
        this.sound.source = context.createBufferSource();
        this.mainMixer = context.createGain();
        this.sound.volume = context.createGain();
        this.sound.source.volume = context.createGain();
        this.sound.source.connect(this.sound.source.volume);
        this.sound.source.volume.connect(this.sound.volume);
        this.sound.volume.connect(this.mainMixer);
        this.mainMixer.connect(audio.destination);
        this.mainMixer.gain.value = mute ? 0 : 1;
        this.sound.volume.gain.value = 0.0;
        this.sound.buffer = decodedData;
        this.loaded = true;
      }));

    promise
      .catch(err => {
        alert('could not load file');
        console.log(err);
      });

    return promise;
  }

  renderPath(args) {
    // splinePoints control the curve of the path
    const points = this.splinePoints;

    // setup
    const sphere = new THREE.SphereGeometry(10);
    const sphereMat = new THREE.MeshBasicMaterial({ color: 0xff1169 });

    const collider = new THREE.SphereGeometry(15);
    const colliderMat = new THREE.MeshBasicMaterial({
      color: 0xff1169,
      transparent: true,
      opacity: 0,
      depthWrite: false,
    });

    const colliderMesh = new THREE.Mesh(collider, colliderMat);

    if (!this.isInitialized) {
      this.pointObjects = [];
      // place a meshgroup at each point in array
      points.forEach((point) => {
        const sphereMesh = new THREE.Mesh(sphere, sphereMat.clone());
        const group = new THREE.Object3D();

        group.add(sphereMesh, colliderMesh.clone());
        group.position.copy(point);

        this.pointObjects.push(group);
      });
      this.splinePoints = this.pointObjects.map( pt => pt.position );
    }
    else if (args) {
      if (args.updateType === "delete") {
        let splicedPoint = this.pointObjects.splice(args.index, 1);
        this.containerObject.remove(splicedPoint[0], true);
      }
      else if (args.updateType === "add") {
        let insertedPoint = new THREE.Object3D();
        insertedPoint.add(
          new THREE.Mesh(sphere, sphereMat.clone()),
          colliderMesh.clone()
        );
        insertedPoint.position.copy(this.splinePoints[args.index]);
        this.pointObjects.splice(args.index, 0, insertedPoint);
        this.containerObject.add(insertedPoint);
      }
      this.splinePoints = this.pointObjects.map( pt => pt.position );
    }

    this.spline = new THREE.CatmullRomCurve3(this.splinePoints);
    this.spline.type = 'centripetal';
    this.spline.closed = true;

    const geometry = new THREE.Geometry();
    geometry.vertices = this.spline.getPoints(200);
    let material = new THREE.LineBasicMaterial({
      color: 0xff1169,
      linewidth: 1,
      transparent: true,
      opacity: 0.4,
    });

    this.spline.mesh = new THREE.Line(geometry, material);

    // fill the path
    const rotatedPoints = this.spline.getPoints(200);
    rotatedPoints.forEach((vertex) => {
      vertex.y = vertex.z;
      vertex.z = 0.0;
    });
    const shapeFill = new THREE.Shape();
    shapeFill.fromPoints(rotatedPoints);
    const shapeGeometry = new THREE.ShapeGeometry(shapeFill);
    shapeGeometry.rotateX(Math.PI / 2);
    material = new THREE.MeshLambertMaterial({
      color: 0xff1169,
      transparent: true,
      opacity: Helpers.mapRange(this.volume, 0, 2, 0.05, 0.35),
      side: THREE.BackSide,
      premultipliedAlpha: true
    });

    this.shape = new THREE.Mesh(shapeGeometry, material);
  }

  get objects() {
    return [].concat(this.pointObjects, this.spline.mesh, this.shape);
  }

  addToScene() {
    if (!this.isInitialized) {
      this.isInitialized = true;

      var box = new THREE.Box3().setFromObject( this.shape );
      box.getCenter( this.containerObject.position );
      this.scene.add(this.containerObject);
      this.objects.forEach((obj) => {
        obj.translateX(-this.containerObject.position.x);
        obj.translateZ(-this.containerObject.position.z);
        this.containerObject.add(obj);
      });
    }
    else {
      this.containerObject.add(this.shape);
      this.containerObject.add(this.spline.mesh);
    }
  }

  removeFromScene(scene) {
    this.scene.remove(this.containerObject, true);
  }

  // raycast to this soundzone
  isUnderMouse(raycaster) {
    if (this.isActive) {
      return raycaster.intersectObjects(this.objects).length > 0;
    }

    return raycaster.intersectObject(this.shape).length > 0;
  }

  objectUnderMouse(raycaster) {
    const intersects = raycaster.intersectObjects(this.objects, true);

    if (intersects.length > 0) {
      if (intersects[0].object.type === 'Line' || intersects[0].object === this.shape) {
        return intersects[Math.floor(intersects.length / 2)];
      }

      return intersects[0];
    }

    return null;
  }

  hideCursor() {
    this.cursor.visible = false;
  }
  showCursor(object, point) {
    if (object !== this.shape) {
      this.cursor.visible = true;
      if (object === this.spline.mesh) {
        const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
        this.cursor.position.copy(point.applyMatrix4(minv));
      }
      else {
        this.cursor.position.copy(object.parent.position);
      }
    }
    else {
      this.hideCursor();
    }
  }

  setMouseOffset(point) {
    this.mouseOffsetX = point.x;
    this.mouseOffsetY = point.z;
  }

  updateZone(args) {
    const scene = this.spline.mesh.parent;
    this.containerObject.remove(this.spline.mesh, true);
    this.containerObject.remove(this.shape, true);
    this.renderPath(args);
    this.addToScene(scene);
  }

  move(main) {
    // if (!main.perspectiveView) {
      const dx = main.mouse.x - this.mouseOffsetX;
      const dy = main.mouse.z - this.mouseOffsetY;
      this.mouseOffsetX = main.mouse.x;
      this.mouseOffsetY = main.mouse.z;
      this.hideCursor();

      if (this.selectedPoint) {
        // move selected point
        const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
        this.selectedPoint.position.copy(main.mouse.applyMatrix4(minv));
        this.updateZone();
      } else {
        // move entire shape

        this.containerObject.position.x += dx;
        this.containerObject.position.z += dy;
      }
    // }
  }

  setActive(main) {
    this.setMouseOffset(main.mouse);
    this.isActive = true;
    this.pointObjects.forEach(obj => (obj.visible = true));
    this.spline.mesh.visible = true;
  }

  setInactive() {
    this.hideCursor();
    this.deselectPoint();
    this.isActive = false;
    this.pointObjects.forEach(obj => (obj.visible = false));
    this.spline.mesh.visible = false;
  }

  select(intersect) {
    if (!intersect) return;

    // obj can be the curve, a spline point, or the shape mesh
    const obj = intersect.object;

    if (obj.type === 'Line') {
      // add a point to the line
      this.addPoint(intersect.point);
    } else if (obj.parent.type === 'Object3D') {
      // select an existing point on line
      this.selectPoint(obj.parent);
    } else {
      this.deselectPoint();
      this.setMouseOffset(intersect.point);
    }
  }

  removePoint() {
    // find point in array
    const i = this.pointObjects.indexOf(this.selectedPoint);
    this.splinePoints.splice(i, 1);
    this.deselectPoint();
    this.updateZone({index: i, updateType: "delete"});
  }

  addPoint(point) {
    const minv = new THREE.Matrix4().getInverse(this.containerObject.matrix);
    const position = point.applyMatrix4(minv);

    let closestSplinePoint = 0;
    let prevDistToSplinePoint = -1;
    let minDistance = Number.MAX_VALUE;
    let minPoint = 1;

    // search for point on spline
    for (let t = 0; t < 1; t += 1 / 200.0) {
      const pt = this.spline.getPoint(t);

      const distToSplinePoint = this.splinePoints[closestSplinePoint].distanceToSquared(pt);
      if (distToSplinePoint > prevDistToSplinePoint) {
        closestSplinePoint += 1;

        if (closestSplinePoint >= this.splinePoints.length) {
          closestSplinePoint = 0;
        }
      }
      prevDistToSplinePoint = this.splinePoints[closestSplinePoint].distanceToSquared(pt);
      const distToPoint = pt.distanceToSquared(position);
      if (distToPoint < minDistance) {
        minDistance = distToPoint;
        minPoint = closestSplinePoint;
      }
    }

    this.splinePoints.splice(minPoint, 0, position);
    this.updateZone({index: minPoint, updateType: "add"});
    this.selectPoint(this.pointObjects[minPoint]);
  }

  selectPoint(obj) {
    this.deselectPoint();
    this.selectedPoint = obj;
    obj.children[0].material.color.set('blue');
  }

  deselectPoint() {
    if (this.selectedPoint) {
      this.selectedPoint.children[0].material.color.set('red');
      this.selectedPoint = null;
    }
  }

  mute(main) {
    this.isMuted = true;
    this.checkMuteState(main);
  }
  unmute(main) {
    this.isMuted = false;
    this.checkMuteState(main);
  }

  checkMuteState(main) {
    if (this.mainMixer) {
      if (main.isMuted || this.isMuted) {
        this.mainMixer.gain.value = 0;
      }
      else {
        this.mainMixer.gain.value = 1;
      }
    }
  }

  toJSON() {
    console.log(this.points);
    return JSON.stringify({
      position: this.containerObject.position,
      points: this.splinePoints,
      filename: this.filename
    });
  }

  fromJSON(json) {
    let object = JSON.parse(json);
    this.containerObject.position.copy(object.position);

    this.loadSound(object.filename, this.audio, false);
  }
}
<|endoftext|>


<commit_before>import classNames from 'classnames';
import {Dropdown} from 'reactjs-components';
import React from 'react';
import ReactDOM from 'react-dom';

import FilterInputText from './FilterInputText';
import IconDownload from './icons/IconDownload';
import MesosLogView from './MesosLogView';
import TaskDirectoryActions from '../events/TaskDirectoryActions';

const METHODS_TO_BIND = [
  'handleSearchStringChange',
  'handleCountChange',
  'handleKeyDown'
];

class TaskDebugView extends React.Component {
  constructor() {
    super();

    this.state = {
      currentFile: null,
      watching: 0,
      totalFound: 0
    };

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this.refs.filterInput)
      .addEventListener('keydown', this.handleKeyDown);
  }

  componentWillReceiveProps(nextProps, nextState) {
    let {searchString, totalFound} = nextState;
    let updatedState = {};

    if (totalFound === 0) {
      updatedState.watching = 0;
    } else if (this.state.watching === 0 ||
      this.state.searchString !== searchString && searchString != null) {
      updatedState.watching = 1;
    }

    this.setState(updatedState);
  }

  componentWillUnmount() {
    ReactDOM.findDOMNode(this.refs.filterInput)
      .removeEventListener('keydown', this.handleKeyDown);
  }

  handleKeyDown(event) {
    let {keyCode} = event;
    if (keyCode === 13) {
      this.changeWatching('next');
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    let {props, state} = this;
    let directory = props.directory;
    let nextDirectory = nextProps.directory;
    let task = state.task;
    let nextTask = nextState.task;

    return !!(
      // Check task
      (props.task !== nextProps.task) ||
      (task && nextTask && task.slave_id !== nextTask.slave_id) ||
      // Check current view
      (state.currentFile !== nextState.currentFile) ||
      // Check searchString
      (state.searchString !== nextState.searchString) ||
      // Check directory
      (directory !== nextDirectory) || (directory && nextDirectory &&
        directory.getItems().length !== nextDirectory.getItems().length) ||
      // Check watching
      (state.watching !== nextState.watching)
    );
  }

  handleSearchStringChange(searchString) {
    this.setState({searchString});
  }

  handleViewChange(currentFile) {
    this.setState({
      currentFile,
      watching: 0,
      searchString: '',
      totalFound: 0
    });
  }

  handleCountChange(totalFound) {
    this.setState({totalFound});
  }

  changeWatching(direction) {
    let {totalFound, watching} = this.state;
    if (direction === 'next') {
      watching += 1;
      if (watching > totalFound) {
        watching = 1;
      }
    }

    if (direction === 'previous') {
      watching -= 1;
      if (watching < 1) {
        watching = totalFound;
      }
    }

    this.setState({watching});
  }

  getLogView(logName, filePath, task) {
    let {state} = this;

    return (
      <MesosLogView
        filePath={filePath}
        highlightText={state.searchString}
        onCountChange={this.handleCountChange}
        task={task}
        logName={logName}
        watching={state.watching} />
    );
  }

  getLogFiles() {
    let {directory} = this.props;
    let logViews = [];
    if (!directory) {
      return logViews;
    }

    directory.getItems().forEach((item) => {
      if (!item.isLogFile()) {
        return;
      }

      logViews.push(item);
    });

    return logViews;
  }

  getLogSelectionAsButtons(logFiles, selectedName) {
    let buttons = logFiles.map((item, index) => {
      let name = item.getName();

      let classes = classNames({
        'button button-stroke': true,
        'active': name === selectedName
      });

      return (
        <button
          className={classes}
          key={index}
          onClick={this.handleViewChange.bind(this, item)}>
          {item.getDisplayName()}
        </button>
      );
    });

    return (

        {buttons}

    );
  }

  onItemSelection(obj) {
    this.handleViewChange(obj.value);
  }

  getItemHtml(displayName) {
    return (
      {displayName}
    );
  }

  getDropdownItems(logFiles) {
    return logFiles.map(function (item) {
      let displayName = item.getDisplayName();
      let selectedHtml = this.getItemHtml(displayName);
      let dropdownHtml = ({selectedHtml});

      return {
        id: item.getName(),
        name: displayName,
        html: dropdownHtml,
        selectedHtml,
        value: item
      };
    }, this);
  }

  getSelectedFile() {
    let {props, state} = this;
    return state.currentFile ||
      props.selectedLogFile || this.getLogFiles()[0];
  }

  getSelectionComponent() {
    let selectedLogFile = this.getSelectedFile();
    let selectedName = selectedLogFile && selectedLogFile.getName();
    let logFiles = this.getLogFiles();
    if (logFiles.length < 3) {
      return this.getLogSelectionAsButtons(logFiles, selectedName);
    }

    return (
      <Dropdown
        buttonClassName="button dropdown-toggle"
        dropdownMenuClassName="dropdown-menu"
        dropdownMenuListClassName="dropdown-menu-list"
        dropdownMenuListItemClassName="clickable"
        initialID={selectedName}
        items={this.getDropdownItems(logFiles)}
        onItemSelection={this.onItemSelection.bind(this)}
        transition={true}
        transitionName="dropdown-menu"
        wrapperClassName="dropdown form-group" />
      );
  }

  getSearchCount() {
    let {searchString, totalFound, watching} = this.state;

    if (totalFound === 0 && !searchString) {
      return null;
    }

    if (totalFound === 0 && searchString) {
      watching = 0;
    }

    return (
      {`${watching} out of ${totalFound}`}
    );
  }

  getSearchButtons() {
    if (this.state.totalFound === 0) {
      return null;
    }

    return (

    );
  }

  render() {
    let task = this.props.task;

    // Only try to get path if file exists
    let selectedLogFile = this.getSelectedFile();
    let selectedName = selectedLogFile && selectedLogFile.getName();
    let filePath = selectedLogFile && selectedLogFile.get('path');

    let inputContainerClassSet = classNames({
      'filter-input-text-group-wide': this.state.searchString
    });

    return (

              <FilterInputText
                ref="filterInput"
                className="flex-grow flex-box"
                placeholder="Search"
                searchString={this.state.searchString}
                sideText={this.getSearchCount()}
                handleFilterChange={this.handleSearchStringChange}
                inverseStyle={false}
                inputContainerClass={inputContainerClassSet} />

              {this.getSearchButtons()}

              {this.getSelectionComponent(selectedLogFile)}

                <IconDownload />

        {this.getLogView(selectedName, filePath, task)}

    );
  }
}

TaskDebugView.propTypes = {
  directory: React.PropTypes.object,
  selectedLogFile: React.PropTypes.object,
  showExpandButton: React.PropTypes.func,
  task: React.PropTypes.object
};

TaskDebugView.defaultProps = {
  showExpandButton: function () {},
  task: {}
};

module.exports = TaskDebugView;
<commit_msg>Bring dropdown threshold back to 4<commit_after>import classNames from 'classnames';
import {Dropdown} from 'reactjs-components';
import React from 'react';
import ReactDOM from 'react-dom';

import FilterInputText from './FilterInputText';
import IconDownload from './icons/IconDownload';
import MesosLogView from './MesosLogView';
import TaskDirectoryActions from '../events/TaskDirectoryActions';

const METHODS_TO_BIND = [
  'handleSearchStringChange',
  'handleCountChange',
  'handleKeyDown'
];

class TaskDebugView extends React.Component {
  constructor() {
    super();

    this.state = {
      currentFile: null,
      watching: 0,
      totalFound: 0
    };

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this.refs.filterInput)
      .addEventListener('keydown', this.handleKeyDown);
  }

  componentWillReceiveProps(nextProps, nextState) {
    let {searchString, totalFound} = nextState;
    let updatedState = {};

    if (totalFound === 0) {
      updatedState.watching = 0;
    } else if (this.state.watching === 0 ||
      this.state.searchString !== searchString && searchString != null) {
      updatedState.watching = 1;
    }

    this.setState(updatedState);
  }

  componentWillUnmount() {
    ReactDOM.findDOMNode(this.refs.filterInput)
      .removeEventListener('keydown', this.handleKeyDown);
  }

  handleKeyDown(event) {
    let {keyCode} = event;
    if (keyCode === 13) {
      this.changeWatching('next');
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    let {props, state} = this;
    let directory = props.directory;
    let nextDirectory = nextProps.directory;
    let task = state.task;
    let nextTask = nextState.task;

    return !!(
      // Check task
      (props.task !== nextProps.task) ||
      (task && nextTask && task.slave_id !== nextTask.slave_id) ||
      // Check current view
      (state.currentFile !== nextState.currentFile) ||
      // Check searchString
      (state.searchString !== nextState.searchString) ||
      // Check directory
      (directory !== nextDirectory) || (directory && nextDirectory &&
        directory.getItems().length !== nextDirectory.getItems().length) ||
      // Check watching
      (state.watching !== nextState.watching)
    );
  }

  handleSearchStringChange(searchString) {
    this.setState({searchString});
  }

  handleViewChange(currentFile) {
    this.setState({
      currentFile,
      watching: 0,
      searchString: '',
      totalFound: 0
    });
  }

  handleCountChange(totalFound) {
    this.setState({totalFound});
  }

  changeWatching(direction) {
    let {totalFound, watching} = this.state;
    if (direction === 'next') {
      watching += 1;
      if (watching > totalFound) {
        watching = 1;
      }
    }

    if (direction === 'previous') {
      watching -= 1;
      if (watching < 1) {
        watching = totalFound;
      }
    }

    this.setState({watching});
  }

  getLogView(logName, filePath, task) {
    let {state} = this;

    return (
      <MesosLogView
        filePath={filePath}
        highlightText={state.searchString}
        onCountChange={this.handleCountChange}
        task={task}
        logName={logName}
        watching={state.watching} />
    );
  }

  getLogFiles() {
    let {directory} = this.props;
    let logViews = [];
    if (!directory) {
      return logViews;
    }

    directory.getItems().forEach((item) => {
      if (!item.isLogFile()) {
        return;
      }

      logViews.push(item);
    });

    return logViews;
  }

  getLogSelectionAsButtons(logFiles, selectedName) {
    let buttons = logFiles.map((item, index) => {
      let name = item.getName();

      let classes = classNames({
        'button button-stroke': true,
        'active': name === selectedName
      });

      return (
        <button
          className={classes}
          key={index}
          onClick={this.handleViewChange.bind(this, item)}>
          {item.getDisplayName()}
        </button>
      );
    });

    return (

        {buttons}

    );
  }

  onItemSelection(obj) {
    this.handleViewChange(obj.value);
  }

  getItemHtml(displayName) {
    return (
      {displayName}
    );
  }

  getDropdownItems(logFiles) {
    return logFiles.map(function (item) {
      let displayName = item.getDisplayName();
      let selectedHtml = this.getItemHtml(displayName);
      let dropdownHtml = ({selectedHtml});

      return {
        id: item.getName(),
        name: displayName,
        html: dropdownHtml,
        selectedHtml,
        value: item
      };
    }, this);
  }

  getSelectedFile() {
    let {props, state} = this;
    return state.currentFile ||
      props.selectedLogFile || this.getLogFiles()[0];
  }

  getSelectionComponent() {
    let selectedLogFile = this.getSelectedFile();
    let selectedName = selectedLogFile && selectedLogFile.getName();
    let logFiles = this.getLogFiles();
    if (logFiles.length < 4) {
      return this.getLogSelectionAsButtons(logFiles, selectedName);
    }

    return (
      <Dropdown
        buttonClassName="button dropdown-toggle"
        dropdownMenuClassName="dropdown-menu"
        dropdownMenuListClassName="dropdown-menu-list"
        dropdownMenuListItemClassName="clickable"
        initialID={selectedName}
        items={this.getDropdownItems(logFiles)}
        onItemSelection={this.onItemSelection.bind(this)}
        transition={true}
        transitionName="dropdown-menu"
        wrapperClassName="dropdown form-group" />
      );
  }

  getSearchCount() {
    let {searchString, totalFound, watching} = this.state;

    if (totalFound === 0 && !searchString) {
      return null;
    }

    if (totalFound === 0 && searchString) {
      watching = 0;
    }

    return (
      {`${watching} out of ${totalFound}`}
    );
  }

  getSearchButtons() {
    if (this.state.totalFound === 0) {
      return null;
    }

    return (

    );
  }

  render() {
    let task = this.props.task;

    // Only try to get path if file exists
    let selectedLogFile = this.getSelectedFile();
    let selectedName = selectedLogFile && selectedLogFile.getName();
    let filePath = selectedLogFile && selectedLogFile.get('path');

    let inputContainerClassSet = classNames({
      'filter-input-text-group-wide': this.state.searchString
    });

    return (

              <FilterInputText
                ref="filterInput"
                className="flex-grow flex-box"
                placeholder="Search"
                searchString={this.state.searchString}
                sideText={this.getSearchCount()}
                handleFilterChange={this.handleSearchStringChange}
                inverseStyle={false}
                inputContainerClass={inputContainerClassSet} />

              {this.getSearchButtons()}

              {this.getSelectionComponent(selectedLogFile)}

                <IconDownload />

        {this.getLogView(selectedName, filePath, task)}

    );
  }
}

TaskDebugView.propTypes = {
  directory: React.PropTypes.object,
  selectedLogFile: React.PropTypes.object,
  showExpandButton: React.PropTypes.func,
  task: React.PropTypes.object
};

TaskDebugView.defaultProps = {
  showExpandButton: function () {},
  task: {}
};

module.exports = TaskDebugView;
<|endoftext|>


<commit_before>import React from "react"
import { connect } from "react-redux"
import { Exchange } from "../../containers/Exchange"
import { Transfer } from "../../containers/Transfer"
import { LimitOrder } from "../../containers/LimitOrder"
import { ExchangeHistory } from "../../containers/CommonElements/"
import constanst from "../../services/constants"
import history from "../../history"
import { clearSession, changeLanguage, setOnMobileOnly, initAnalytics, switchTheme } from "../../actions/globalActions"
import { openInfoModal } from "../../actions/utilActions"
import { createNewConnectionInstance } from "../../actions/connectionActions"
import { throttle } from 'underscore';
import { LayoutView } from "../../components/Layout"
import { getTranslate } from 'react-localize-redux'
import * as common from "../../utils/common"
import {isMobile} from '../../utils/common'
import Language from "../../../../lang"
import AnalyticFactory from "../../services/analytics"
import BLOCKCHAIN_INFO from "../../../../env";

@connect((store) => {
  var locale = store.locale
  var code
  if(Array.isArray(locale.languages)) {
    code = locale.languages[0].code
  }

  var langClass
  switch(code) {
    case "en":
      langClass = "swap-en"
      break
    case "cn":
      langClass = "swap-cn"
      break
    case "kr":
      langClass = "swap-kr"
      break
    case "ru":
      langClass = "swap-ru"
      break
    case "vi":
      langClass = "swap-vi"
      break
    default:
      langClass = ""
  }

  const exchange = store.exchange
  const transfer = store.transfer
  const limitOrder = store.limitOrder

  var exchangeLink = constanst.BASE_HOST + "/swap/" + exchange.sourceTokenSymbol.toLowerCase() + "-" + exchange.destTokenSymbol.toLowerCase()
  var transferLink = constanst.BASE_HOST + "/transfer/" + transfer.tokenSymbol.toLowerCase()
  var orderLink = constanst.BASE_HOST + `/${constanst.LIMIT_ORDER_CONFIG.path}/` + limitOrder.sourceTokenSymbol.toLowerCase() + "-" + limitOrder.destTokenSymbol.toLowerCase()

  return {
    ethereumNode: store.connection.ethereum,
    currentBlock: store.global.currentBlock,
    connected: store.global.connected,
    showBalance: store.global.showBalance,
    utils: store.utils,
    account: store.account,
    translate: getTranslate(store.locale),
    locale: locale,
    tokens: store.tokens.tokens,
    analytics: store.global.analytics,
    langClass: langClass,
    theme: store.global.theme,
    exchangeLink, transferLink, orderLink,
  }
})

export default class Layout extends React.Component {
  constructor() {
    super();
    this.idleTime = 0;
    this.timeoutEndSession = constanst.IDLE_TIME_OUT / 10;    // x10 seconds
    this.idleMode = false;
    this.intervalIdle = null;
  }

  componentWillMount() {
    document.onload = this.resetTimmer;
    document.onmousemove = this.resetTimmer;
    document.onmousedown = this.resetTimmer; // touchscreen presses
    document.ontouchstart = this.resetTimmer;
    document.onclick = this.resetTimmer;     // touchpad clicks
    document.onscroll = this.resetTimmer;    // scrolling with arrow keys
    document.onkeypress = this.resetTimmer;

    this.intervalIdle = setInterval(this.checkTimmer.bind(this), 10000)
    this.props.dispatch(createNewConnectionInstance())

    const analytic = new AnalyticFactory({ listWorker: ['mix'], network: BLOCKCHAIN_INFO.chainName })
    this.props.dispatch(initAnalytics(analytic))
  }

  componentDidMount = () => {
    this.props.analytics.callTrack("trackAccessToSwap");

    window.addEventListener("beforeunload", this.handleCloseWeb)
    if (isMobile.iOS() || isMobile.Android()) {
      this.props.dispatch(setOnMobileOnly())
    }

    if (window.kyberBus) {
      window.kyberBus.on('go.to.swap', () => {console.log('swap'); history.push(this.props.exchangeLink)});
      window.kyberBus.on('go.to.transfer', () =>{console.log('transfer'); history.push(this.props.transferLink)});
      window.kyberBus.on('go.to.limit_order', () => {console.log('limit_order'); history.push(this.props.orderLink)});
    }
  }

  switchTheme = (theme) => {
    this.props.dispatch(switchTheme(theme));
  };

  handleCloseWeb = () => {
    this.props.analytics.callTrack("exitSwap");
  }

  checkTimmer() {
    if (!this.props.account.account) return;
    if (this.props.utils.infoModal && this.props.utils.infoModal.open) return;
    if (this.idleTime >= this.timeoutEndSession) {
      let timeOut = constanst.IDLE_TIME_OUT/60
      let titleModal = this.props.translate('error.time_out') || 'Time out'
      let contentModal = this.props.translate('error.clear_data_timeout', {time: timeOut}) || `We've cleared all your data because your session is timed out ${timeOut} minutes`
      this.props.dispatch(openInfoModal(titleModal, contentModal));
      this.endSession();
    } else {
      this.idleTime++;
    }
  }

  resetTimmer = throttle(this.doResetTimer.bind(this), 5000)

  doResetTimer() {
    this.idleTime = 0;
  }

  endSession() {
    this.props.dispatch(clearSession());
  }

  setActiveLanguage = (language) => {
    this.props.dispatch(changeLanguage(this.props.ethereumNode, language, this.props.locale))
  }
  render() {
    var currentLanguage = common.getActiveLanguage(this.props.locale.languages)
    return (
      <LayoutView
          history={history}
          Exchange={Exchange}
          Transfer={Transfer}
          LimitOrder = {LimitOrder}
          supportedLanguages={Language.supportLanguage}
          setActiveLanguage={this.setActiveLanguage}
          currentLanguage = {currentLanguage}
          tokens = {this.props.tokens}
          langClass = {this.props.langClass}
      />
    )
  }
}

<commit_msg>enable standalone theme switch<commit_after>import React from "react"
import { connect } from "react-redux"
import { Exchange } from "../../containers/Exchange"
import { Transfer } from "../../containers/Transfer"
import { LimitOrder } from "../../containers/LimitOrder"
import { ExchangeHistory } from "../../containers/CommonElements/"
import constanst from "../../services/constants"
import history from "../../history"
import { clearSession, changeLanguage, setOnMobileOnly, initAnalytics, switchTheme } from "../../actions/globalActions"
import { openInfoModal } from "../../actions/utilActions"
import { createNewConnectionInstance } from "../../actions/connectionActions"
import { throttle } from 'underscore';
import { LayoutView } from "../../components/Layout"
import { getTranslate } from 'react-localize-redux'
import * as common from "../../utils/common"
import {isMobile} from '../../utils/common'
import Language from "../../../../lang"
import AnalyticFactory from "../../services/analytics"
import BLOCKCHAIN_INFO from "../../../../env";

@connect((store) => {
  var locale = store.locale
  var code
  if(Array.isArray(locale.languages)) {
    code = locale.languages[0].code
  }

  var langClass
  switch(code) {
    case "en":
      langClass = "swap-en"
      break
    case "cn":
      langClass = "swap-cn"
      break
    case "kr":
      langClass = "swap-kr"
      break
    case "ru":
      langClass = "swap-ru"
      break
    case "vi":
      langClass = "swap-vi"
      break
    default:
      langClass = ""
  }

  const exchange = store.exchange
  const transfer = store.transfer
  const limitOrder = store.limitOrder

  var exchangeLink = constanst.BASE_HOST + "/swap/" + exchange.sourceTokenSymbol.toLowerCase() + "-" + exchange.destTokenSymbol.toLowerCase()
  var transferLink = constanst.BASE_HOST + "/transfer/" + transfer.tokenSymbol.toLowerCase()
  var orderLink = constanst.BASE_HOST + `/${constanst.LIMIT_ORDER_CONFIG.path}/` + limitOrder.sourceTokenSymbol.toLowerCase() + "-" + limitOrder.destTokenSymbol.toLowerCase()

  return {
    ethereumNode: store.connection.ethereum,
    currentBlock: store.global.currentBlock,
    connected: store.global.connected,
    showBalance: store.global.showBalance,
    utils: store.utils,
    account: store.account,
    translate: getTranslate(store.locale),
    locale: locale,
    tokens: store.tokens.tokens,
    analytics: store.global.analytics,
    langClass: langClass,
    theme: store.global.theme,
    exchangeLink, transferLink, orderLink,
  }
})

export default class Layout extends React.Component {
  constructor() {
    super();
    this.idleTime = 0;
    this.timeoutEndSession = constanst.IDLE_TIME_OUT / 10;    // x10 seconds
    this.idleMode = false;
    this.intervalIdle = null;
    this.state= {isStandalone: true}
  }

  componentWillMount() {
    document.onload = this.resetTimmer;
    document.onmousemove = this.resetTimmer;
    document.onmousedown = this.resetTimmer; // touchscreen presses
    document.ontouchstart = this.resetTimmer;
    document.onclick = this.resetTimmer;     // touchpad clicks
    document.onscroll = this.resetTimmer;    // scrolling with arrow keys
    document.onkeypress = this.resetTimmer;

    this.intervalIdle = setInterval(this.checkTimmer.bind(this), 10000)
    this.props.dispatch(createNewConnectionInstance())

    const analytic = new AnalyticFactory({ listWorker: ['mix'], network: BLOCKCHAIN_INFO.chainName })
    this.props.dispatch(initAnalytics(analytic))
  }

  componentDidMount = () => {
    this.props.analytics.callTrack("trackAccessToSwap");

    window.addEventListener("beforeunload", this.handleCloseWeb)
    if (isMobile.iOS() || isMobile.Android()) {
      this.props.dispatch(setOnMobileOnly())
    }

    if (window.kyberBus) {
      window.kyberBus.on('set.theme.light', () => {if (this.state.isStandalone) this.setState({isStandalone: false})});
      window.kyberBus.on('set.theme.dark', () => {if (this.state.isStandalone) this.setState({isStandalone: false})});
      window.kyberBus.on('go.to.swap', () => {console.log('swap'); history.push(this.props.exchangeLink)});
      window.kyberBus.on('go.to.transfer', () =>{console.log('transfer'); history.push(this.props.transferLink)});
      window.kyberBus.on('go.to.limit_order', () => {console.log('limit_order'); history.push(this.props.orderLink)});
    }
  }

  switchTheme = (theme) => {
    this.props.dispatch(switchTheme(theme));
  };

  handleCloseWeb = () => {
    this.props.analytics.callTrack("exitSwap");
  }

  checkTimmer() {
    if (!this.props.account.account) return;
    if (this.props.utils.infoModal && this.props.utils.infoModal.open) return;
    if (this.idleTime >= this.timeoutEndSession) {
      let timeOut = constanst.IDLE_TIME_OUT/60
      let titleModal = this.props.translate('error.time_out') || 'Time out'
      let contentModal = this.props.translate('error.clear_data_timeout', {time: timeOut}) || `We've cleared all your data because your session is timed out ${timeOut} minutes`
      this.props.dispatch(openInfoModal(titleModal, contentModal));
      this.endSession();
    } else {
      this.idleTime++;
    }
  }

  resetTimmer = throttle(this.doResetTimer.bind(this), 5000)

  doResetTimer() {
    this.idleTime = 0;
  }

  endSession() {
    this.props.dispatch(clearSession());
  }

  setActiveLanguage = (language) => {
    this.props.dispatch(changeLanguage(this.props.ethereumNode, language, this.props.locale))
  }
  render() {
    var currentLanguage = common.getActiveLanguage(this.props.locale.languages)
    return (
      <div className={this.state.isStandalone ? `theme theme--${this.props.theme}` : ""}>
        <LayoutView
            history={history}
            Exchange={Exchange}
            Transfer={Transfer}
            LimitOrder = {LimitOrder}
            supportedLanguages={Language.supportLanguage}
            setActiveLanguage={this.setActiveLanguage}
            currentLanguage = {currentLanguage}
            tokens = {this.props.tokens}
            langClass = {this.props.langClass}
        />
      </div>
    )
  }
}

<|endoftext|>


<commit_before>/**
 * @license Serializer module for Rangy.
 * Serializes Ranges and Selections. An example use would be to store a user's selection on a particular page in a
 * cookie or local storage and restore it on the user's next visit to the same page.
 *
 * Part of Rangy, a cross-browser JavaScript range and selection library
 * http://code.google.com/p/rangy/
 *
 * Depends on Rangy core.
 *
 * Copyright %%build:year%%, Tim Down
 * Licensed under the MIT license.
 * Version: %%build:version%%
 * Build date: %%build:date%%
 */
rangy.createModule("Serializer", function(api, module) {
    api.requireModules( ["WrappedSelection", "WrappedRange"] );
    var UNDEF = "undefined";

    // encodeURIComponent and decodeURIComponent are required for cookie handling
    if (typeof encodeURIComponent == UNDEF || typeof decodeURIComponent == UNDEF) {
        module.fail("Global object is missing encodeURIComponent and/or decodeURIComponent method");
    }

    // Checksum for checking whether range can be serialized
    var crc32 = (function() {
        function utf8encode(str) {
            var utf8CharCodes = [];

            for (var i = 0, len = str.length, c; i < len; ++i) {
                c = str.charCodeAt(i);
                if (c < 128) {
                    utf8CharCodes.push(c);
                } else if (c < 2048) {
                    utf8CharCodes.push((c >> 6) | 192, (c & 63) | 128);
                } else {
                    utf8CharCodes.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128);
                }
            }
            return utf8CharCodes;
        }

        var cachedCrcTable = null;

        function buildCRCTable() {
            var table = [];
            for (var i = 0, j, crc; i < 256; ++i) {
                crc = i;
                j = 8;
                while (j--) {
                    if ((crc & 1) == 1) {
                        crc = (crc >>> 1) ^ 0xEDB88320;
                    } else {
                        crc >>>= 1;
                    }
                }
                table[i] = crc >>> 0;
            }
            return table;
        }

        function getCrcTable() {
            if (!cachedCrcTable) {
                cachedCrcTable = buildCRCTable();
            }
            return cachedCrcTable;
        }

        return function(str) {
            var utf8CharCodes = utf8encode(str), crc = -1, crcTable = getCrcTable();
            for (var i = 0, len = utf8CharCodes.length, y; i < len; ++i) {
                y = (crc ^ utf8CharCodes[i]) & 0xFF;
                crc = (crc >>> 8) ^ crcTable[y];
            }
            return (crc ^ -1) >>> 0;
        };
    })();

    var dom = api.dom;

    function escapeTextForHtml(str) {
        return str.replace(/</g, "<").replace(/>/g, ">");
    }

    function nodeToInfoString(node, infoParts) {
        infoParts = infoParts || [];
        var nodeType = node.nodeType, children = node.childNodes, childCount = children.length;
        var nodeInfo = [nodeType, node.nodeName, childCount].join(":");
        var start = "", end = "";
        switch (nodeType) {
            case 3: // Text node
                start = escapeTextForHtml(node.nodeValue);
                break;
            case 8: // Comment
                start = "<!--" + escapeTextForHtml(node.nodeValue) + "-->";
                break;
            default:
                start = "<" + nodeInfo + ">";
                end = "</>";
                break;
        }
        if (start) {
            infoParts.push(start);
        }
        for (var i = 0; i < childCount; ++i) {
            nodeToInfoString(children[i], infoParts);
        }
        if (end) {
            infoParts.push(end);
        }
        return infoParts;
    }

    // Creates a string representation of the specified element's contents that is similar to innerHTML but omits all
    // attributes and comments and includes child node counts. This is done instead of using innerHTML to work around
    // IE <= 8's policy of including element properties in attributes, which ruins things by changing an element's
    // innerHTML whenever the user changes an input within the element.
    function getElementChecksum(el) {
        var info = nodeToInfoString(el).join("");
        return crc32(info).toString(16);
    }

    function serializePosition(node, offset, rootNode) {
        var pathBits = [], n = node;
        rootNode = rootNode || dom.getDocument(node).documentElement;
        while (n && n != rootNode) {
            pathBits.push(dom.getNodeIndex(n, true));
            n = n.parentNode;
        }
        return pathBits.join("/") + ":" + offset;
    }

    function deserializePosition(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var bits = serialized.split(":");
        var node = rootNode;
        var nodeIndices = bits[0] ? bits[0].split("/") : [], i = nodeIndices.length, nodeIndex;

        while (i--) {
            nodeIndex = parseInt(nodeIndices[i], 10);
            if (nodeIndex < node.childNodes.length) {
                node = node.childNodes[parseInt(nodeIndices[i], 10)];
            } else {
                throw module.createError("deserializePosition failed: node " + dom.inspectNode(node) +
                        " has no child with index " + nodeIndex + ", " + i);
            }
        }

        return new dom.DomPosition(node, parseInt(bits[1], 10));
    }

    function serializeRange(range, omitChecksum, rootNode) {
        rootNode = rootNode || api.DomRange.getRangeDocument(range).documentElement;
        if (!dom.isAncestorOf(rootNode, range.commonAncestorContainer, true)) {
            throw new Error("serializeRange: range is not wholly contained within specified root node");
        }
        var serialized = serializePosition(range.startContainer, range.startOffset, rootNode) + "," +
            serializePosition(range.endContainer, range.endOffset, rootNode);
        if (!omitChecksum) {
            serialized += "{" + getElementChecksum(rootNode) + "}";
        }
        return serialized;
    }

    function deserializeRange(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var result = /^([^,]+),([^,\{]+)({([^}]+)})?$/.exec(serialized);
        var checksum = result[4], rootNodeChecksum = getElementChecksum(rootNode);
        if (checksum && checksum !== getElementChecksum(rootNode)) {
            throw new Error("deserializeRange: checksums of serialized range root node (" + checksum +
                    ") and target root node (" + rootNodeChecksum + ") do not match");
        }
        var start = deserializePosition(result[1], rootNode, doc), end = deserializePosition(result[2], rootNode, doc);
        var range = api.createRange(doc);
        range.setStart(start.node, start.offset);
        range.setEnd(end.node, end.offset);
        return range;
    }

    function canDeserializeRange(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var result = /^([^,]+),([^,]+)({([^}]+)})?$/.exec(serialized);
        var checksum = result[3];
        return !checksum || checksum === getElementChecksum(rootNode);
    }

    function serializeSelection(selection, omitChecksum, rootNode) {
        selection = selection || rangy.getSelection();
        var ranges = selection.getAllRanges(), serializedRanges = [];
        for (var i = 0, len = ranges.length; i < len; ++i) {
            serializedRanges[i] = serializeRange(ranges[i], omitChecksum, rootNode);
        }
        return serializedRanges.join("|");
    }

    function deserializeSelection(serialized, rootNode, win) {
        if (rootNode) {
            win = win || dom.getWindow(rootNode);
        } else {
            win = win || window;
            rootNode = win.document.documentElement;
        }
        var serializedRanges = serialized.split("|");
        var sel = api.getSelection(win);
        var ranges = [];

        for (var i = 0, len = serializedRanges.length; i < len; ++i) {
            ranges[i] = deserializeRange(serializedRanges[i], rootNode, win.document);
        }
        sel.setRanges(ranges);

        return sel;
    }

    function canDeserializeSelection(serialized, rootNode, win) {
        var doc;
        if (rootNode) {
            doc = win ? win.document : dom.getDocument(rootNode);
        } else {
            win = win || window;
            rootNode = win.document.documentElement;
        }
        var serializedRanges = serialized.split("|");

        for (var i = 0, len = serializedRanges.length; i < len; ++i) {
            if (!canDeserializeRange(serializedRanges[i], rootNode, doc)) {
                return false;
            }
        }

        return true;
    }

    var cookieName = "rangySerializedSelection";

    function getSerializedSelectionFromCookie(cookie) {
        var parts = cookie.split(/[;,]/);
        for (var i = 0, len = parts.length, nameVal, val; i < len; ++i) {
            nameVal = parts[i].split("=");
            if (nameVal[0].replace(/^\s+/, "") == cookieName) {
                val = nameVal[1];
                if (val) {
                    return decodeURIComponent(val.replace(/\s+$/, ""));
                }
            }
        }
        return null;
    }

    function restoreSelectionFromCookie(win) {
        win = win || window;
        var serialized = getSerializedSelectionFromCookie(win.document.cookie);
        if (serialized) {
            deserializeSelection(serialized, win.doc)
        }
    }

    function saveSelectionCookie(win, props) {
        win = win || window;
        props = (typeof props == "object") ? props : {};
        var expires = props.expires ? ";expires=" + props.expires.toUTCString() : "";
        var path = props.path ? ";path=" + props.path : "";
        var domain = props.domain ? ";domain=" + props.domain : "";
        var secure = props.secure ? ";secure" : "";
        var serialized = serializeSelection(rangy.getSelection(win));
        win.document.cookie = encodeURIComponent(cookieName) + "=" + encodeURIComponent(serialized) + expires + path + domain + secure;
    }

    api.serializePosition = serializePosition;
    api.deserializePosition = deserializePosition;

    api.serializeRange = serializeRange;
    api.deserializeRange = deserializeRange;
    api.canDeserializeRange = canDeserializeRange;

    api.serializeSelection = serializeSelection;
    api.deserializeSelection = deserializeSelection;
    api.canDeserializeSelection = canDeserializeSelection;

    api.restoreSelectionFromCookie = restoreSelectionFromCookie;
    api.saveSelectionCookie = saveSelectionCookie;

    api.getElementChecksum = getElementChecksum;
});
<commit_msg>Fix for two rogue references to rangy variable. See issue 51.<commit_after>/**
 * @license Serializer module for Rangy.
 * Serializes Ranges and Selections. An example use would be to store a user's selection on a particular page in a
 * cookie or local storage and restore it on the user's next visit to the same page.
 *
 * Part of Rangy, a cross-browser JavaScript range and selection library
 * http://code.google.com/p/rangy/
 *
 * Depends on Rangy core.
 *
 * Copyright %%build:year%%, Tim Down
 * Licensed under the MIT license.
 * Version: %%build:version%%
 * Build date: %%build:date%%
 */
rangy.createModule("Serializer", function(api, module) {
    api.requireModules( ["WrappedSelection", "WrappedRange"] );
    var UNDEF = "undefined";

    // encodeURIComponent and decodeURIComponent are required for cookie handling
    if (typeof encodeURIComponent == UNDEF || typeof decodeURIComponent == UNDEF) {
        module.fail("Global object is missing encodeURIComponent and/or decodeURIComponent method");
    }

    // Checksum for checking whether range can be serialized
    var crc32 = (function() {
        function utf8encode(str) {
            var utf8CharCodes = [];

            for (var i = 0, len = str.length, c; i < len; ++i) {
                c = str.charCodeAt(i);
                if (c < 128) {
                    utf8CharCodes.push(c);
                } else if (c < 2048) {
                    utf8CharCodes.push((c >> 6) | 192, (c & 63) | 128);
                } else {
                    utf8CharCodes.push((c >> 12) | 224, ((c >> 6) & 63) | 128, (c & 63) | 128);
                }
            }
            return utf8CharCodes;
        }

        var cachedCrcTable = null;

        function buildCRCTable() {
            var table = [];
            for (var i = 0, j, crc; i < 256; ++i) {
                crc = i;
                j = 8;
                while (j--) {
                    if ((crc & 1) == 1) {
                        crc = (crc >>> 1) ^ 0xEDB88320;
                    } else {
                        crc >>>= 1;
                    }
                }
                table[i] = crc >>> 0;
            }
            return table;
        }

        function getCrcTable() {
            if (!cachedCrcTable) {
                cachedCrcTable = buildCRCTable();
            }
            return cachedCrcTable;
        }

        return function(str) {
            var utf8CharCodes = utf8encode(str), crc = -1, crcTable = getCrcTable();
            for (var i = 0, len = utf8CharCodes.length, y; i < len; ++i) {
                y = (crc ^ utf8CharCodes[i]) & 0xFF;
                crc = (crc >>> 8) ^ crcTable[y];
            }
            return (crc ^ -1) >>> 0;
        };
    })();

    var dom = api.dom;

    function escapeTextForHtml(str) {
        return str.replace(/</g, "<").replace(/>/g, ">");
    }

    function nodeToInfoString(node, infoParts) {
        infoParts = infoParts || [];
        var nodeType = node.nodeType, children = node.childNodes, childCount = children.length;
        var nodeInfo = [nodeType, node.nodeName, childCount].join(":");
        var start = "", end = "";
        switch (nodeType) {
            case 3: // Text node
                start = escapeTextForHtml(node.nodeValue);
                break;
            case 8: // Comment
                start = "<!--" + escapeTextForHtml(node.nodeValue) + "-->";
                break;
            default:
                start = "<" + nodeInfo + ">";
                end = "</>";
                break;
        }
        if (start) {
            infoParts.push(start);
        }
        for (var i = 0; i < childCount; ++i) {
            nodeToInfoString(children[i], infoParts);
        }
        if (end) {
            infoParts.push(end);
        }
        return infoParts;
    }

    // Creates a string representation of the specified element's contents that is similar to innerHTML but omits all
    // attributes and comments and includes child node counts. This is done instead of using innerHTML to work around
    // IE <= 8's policy of including element properties in attributes, which ruins things by changing an element's
    // innerHTML whenever the user changes an input within the element.
    function getElementChecksum(el) {
        var info = nodeToInfoString(el).join("");
        return crc32(info).toString(16);
    }

    function serializePosition(node, offset, rootNode) {
        var pathBits = [], n = node;
        rootNode = rootNode || dom.getDocument(node).documentElement;
        while (n && n != rootNode) {
            pathBits.push(dom.getNodeIndex(n, true));
            n = n.parentNode;
        }
        return pathBits.join("/") + ":" + offset;
    }

    function deserializePosition(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var bits = serialized.split(":");
        var node = rootNode;
        var nodeIndices = bits[0] ? bits[0].split("/") : [], i = nodeIndices.length, nodeIndex;

        while (i--) {
            nodeIndex = parseInt(nodeIndices[i], 10);
            if (nodeIndex < node.childNodes.length) {
                node = node.childNodes[parseInt(nodeIndices[i], 10)];
            } else {
                throw module.createError("deserializePosition failed: node " + dom.inspectNode(node) +
                        " has no child with index " + nodeIndex + ", " + i);
            }
        }

        return new dom.DomPosition(node, parseInt(bits[1], 10));
    }

    function serializeRange(range, omitChecksum, rootNode) {
        rootNode = rootNode || api.DomRange.getRangeDocument(range).documentElement;
        if (!dom.isAncestorOf(rootNode, range.commonAncestorContainer, true)) {
            throw new Error("serializeRange: range is not wholly contained within specified root node");
        }
        var serialized = serializePosition(range.startContainer, range.startOffset, rootNode) + "," +
            serializePosition(range.endContainer, range.endOffset, rootNode);
        if (!omitChecksum) {
            serialized += "{" + getElementChecksum(rootNode) + "}";
        }
        return serialized;
    }

    function deserializeRange(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var result = /^([^,]+),([^,\{]+)({([^}]+)})?$/.exec(serialized);
        var checksum = result[4], rootNodeChecksum = getElementChecksum(rootNode);
        if (checksum && checksum !== getElementChecksum(rootNode)) {
            throw new Error("deserializeRange: checksums of serialized range root node (" + checksum +
                    ") and target root node (" + rootNodeChecksum + ") do not match");
        }
        var start = deserializePosition(result[1], rootNode, doc), end = deserializePosition(result[2], rootNode, doc);
        var range = api.createRange(doc);
        range.setStart(start.node, start.offset);
        range.setEnd(end.node, end.offset);
        return range;
    }

    function canDeserializeRange(serialized, rootNode, doc) {
        if (rootNode) {
            doc = doc || dom.getDocument(rootNode);
        } else {
            doc = doc || document;
            rootNode = doc.documentElement;
        }
        var result = /^([^,]+),([^,]+)({([^}]+)})?$/.exec(serialized);
        var checksum = result[3];
        return !checksum || checksum === getElementChecksum(rootNode);
    }

    function serializeSelection(selection, omitChecksum, rootNode) {
        selection = selection || api.getSelection();
        var ranges = selection.getAllRanges(), serializedRanges = [];
        for (var i = 0, len = ranges.length; i < len; ++i) {
            serializedRanges[i] = serializeRange(ranges[i], omitChecksum, rootNode);
        }
        return serializedRanges.join("|");
    }

    function deserializeSelection(serialized, rootNode, win) {
        if (rootNode) {
            win = win || dom.getWindow(rootNode);
        } else {
            win = win || window;
            rootNode = win.document.documentElement;
        }
        var serializedRanges = serialized.split("|");
        var sel = api.getSelection(win);
        var ranges = [];

        for (var i = 0, len = serializedRanges.length; i < len; ++i) {
            ranges[i] = deserializeRange(serializedRanges[i], rootNode, win.document);
        }
        sel.setRanges(ranges);

        return sel;
    }

    function canDeserializeSelection(serialized, rootNode, win) {
        var doc;
        if (rootNode) {
            doc = win ? win.document : dom.getDocument(rootNode);
        } else {
            win = win || window;
            rootNode = win.document.documentElement;
        }
        var serializedRanges = serialized.split("|");

        for (var i = 0, len = serializedRanges.length; i < len; ++i) {
            if (!canDeserializeRange(serializedRanges[i], rootNode, doc)) {
                return false;
            }
        }

        return true;
    }

    var cookieName = "rangySerializedSelection";

    function getSerializedSelectionFromCookie(cookie) {
        var parts = cookie.split(/[;,]/);
        for (var i = 0, len = parts.length, nameVal, val; i < len; ++i) {
            nameVal = parts[i].split("=");
            if (nameVal[0].replace(/^\s+/, "") == cookieName) {
                val = nameVal[1];
                if (val) {
                    return decodeURIComponent(val.replace(/\s+$/, ""));
                }
            }
        }
        return null;
    }

    function restoreSelectionFromCookie(win) {
        win = win || window;
        var serialized = getSerializedSelectionFromCookie(win.document.cookie);
        if (serialized) {
            deserializeSelection(serialized, win.doc)
        }
    }

    function saveSelectionCookie(win, props) {
        win = win || window;
        props = (typeof props == "object") ? props : {};
        var expires = props.expires ? ";expires=" + props.expires.toUTCString() : "";
        var path = props.path ? ";path=" + props.path : "";
        var domain = props.domain ? ";domain=" + props.domain : "";
        var secure = props.secure ? ";secure" : "";
        var serialized = serializeSelection(api.getSelection(win));
        win.document.cookie = encodeURIComponent(cookieName) + "=" + encodeURIComponent(serialized) + expires + path + domain + secure;
    }

    api.serializePosition = serializePosition;
    api.deserializePosition = deserializePosition;

    api.serializeRange = serializeRange;
    api.deserializeRange = deserializeRange;
    api.canDeserializeRange = canDeserializeRange;

    api.serializeSelection = serializeSelection;
    api.deserializeSelection = deserializeSelection;
    api.canDeserializeSelection = canDeserializeSelection;

    api.restoreSelectionFromCookie = restoreSelectionFromCookie;
    api.saveSelectionCookie = saveSelectionCookie;

    api.getElementChecksum = getElementChecksum;
});
<|endoftext|>