<commit_before>const path = require("path");
const exec = require("child_process").exec;
const fs = require("fs");
const colors = require("colors");
const minimatch = require("minimatch");

const findContracts = require("@truffle/contract-sources");
const Profiler = require("@truffle/compile-solidity/profiler");

const compiler = {
  name: "vyper",
  version: null
};

const VYPER_PATTERN = "**/*.{vy,v.py,vyper.py}";

// Check that vyper is available, save its version
function checkVyper() {
  return new Promise((resolve, reject) => {
    exec("vyper --version", function (err, stdout, stderr) {
      if (err) {
        return reject(`${colors.red("Error executing vyper:")}\n${stderr}`);
      }
      compiler.version = stdout.trim();
      resolve();
    });
  });
}

// Execute vyper for single source file
function execVyper(options, sourcePath, callback) {
  const formats = ["abi", "bytecode", "bytecode_runtime"];
  if (
    options.compilers.vyper.settings &&
    options.compilers.vyper.settings.sourceMap
  ) {
    formats.push("source_map");
  }
  const command = `vyper -f ${formats.join(",")} ${sourcePath}`;

  exec(command, {maxBuffer: 600 * 1024}, function (err, stdout, stderr) {
    if (err)
      return callback(
        `${stderr}\n${colors.red(
          `Compilation of ${sourcePath} failed. See above.`
        )}`
      );

    var outputs = stdout.split(/\r?\n/);

    const compiledContract = outputs.reduce((contract, output, index) => {
      return Object.assign(contract, {[formats[index]]: output});
    }, {});

    callback(null, compiledContract);
  });
}

/**
 *
 * read source contents from sourcePath
 */
function readSource(sourcePath) {
  const sourceBuffer = fs.readFileSync(sourcePath);
  return sourceBuffer.toString();
}

/**
 * aggregate source information based on compiled output;
 * this can include sources that are not contracts
 */
function processAllSources(sources) {
  if (!sourcePaths.length) return [];
  return sources.map(sourcePath => ({
    sourcePath: sourcePath,
    contents: readSource(sourcePath),
    language: sourcePath.split(".").pop()
  }));
}

// compile all sources
async function compileAll({sources, options}) {
  options.logger = options.logger || console;

  Compile.display(sources, options);

  const promises = [];
  sources.forEach(sourcePath => {
    promises.push(
      new Promise((resolve, reject) => {
        execVyper(options, sourcePath, function (error, compiledContract) {
          if (error) return reject(error);

          // remove first extension from filename
          const extension = path.extname(sourcePath);
          const basename = path.basename(sourcePath, extension);

          // if extension is .py, remove second extension from filename
          const contractName =
            extension !== ".py"
              ? basename
              : path.basename(basename, path.extname(basename));

          const sourceContents = readSource(sourcePath);

          const contractDefinition = {
            contractName: contractName,
            sourcePath: sourcePath,
            source: sourceContents,
            abi: compiledContract.abi,
            bytecode: compiledContract.bytecode,
            deployedBytecode: compiledContract.bytecode_runtime,
            sourceMap: compiledContract.source_map,
            compiler
          };

          resolve(contractDefinition);
        });
      })
    );
  });
  const contracts = await Promise.all(promises);

  const compilerInfo = {name: "vyper", version: compiler.version};
  return {
    sources: processAllSources(sources),
    compilations: [
      {
        compiler: compilerInfo,
        contracts,
        sourceIndexes: sources
      }
    ]
  };
}

const Compile = {
  // Check that vyper is available then forward to internal compile function
  async sources({sources = [], options}) {
    // filter out non-vyper paths
    const vyperFiles = sources.filter(path => minimatch(path, VYPER_PATTERN));

    // no vyper files found, no need to check vyper
    if (vyperFiles.length === 0) {
      return {compilations: []};
    }

    await checkVyper();
    return await compileAll({
      sources: vyperFiles,
      options
    });
  },

  async sourcesWithDependencies({paths = [], options}) {
    return await Compile.sources({
      sources: paths,
      options
    });
  },

  // contracts_directory: String. Directory where contract files can be found.
  // quiet: Boolean. Suppress output. Defaults to false.
  // strict: Boolean. Return compiler warnings as errors. Defaults to false.
  async all(options) {
    const fileSearchPattern = path.join(
      options.contracts_directory,
      VYPER_PATTERN
    );
    const files = await findContracts(fileSearchPattern);

    return await Compile.sources({
      sources: files,
      options
    });
  },

  // contracts_directory: String. Directory where contract files can be found.
  // all: Boolean. Compile all sources found. Defaults to true. If false, will compare sources against built files
  //      in the build directory to see what needs to be compiled.
  // quiet: Boolean. Suppress output. Defaults to false.
  // strict: Boolean. Return compiler warnings as errors. Defaults to false.
  async necessary(options) {
    options.logger = options.logger || console;
    const updated = await Profiler.updated(options);

    if (updated.length === 0 && options.quiet !== true) {
      return {compilations: []};
    }

    // filter out only Vyper files
    const updatedVyperPaths = updated.filter(path => {
      return path.match(/\.vy$|\.v.py$|\.vyper.py$/);
    });
    return await Compile.sources({
      sources: updatedVyperPaths,
      options
    });
  },

  async display(paths, options) {
    if (!Array.isArray(paths)) {
      paths = Object.keys(paths);
    }

    const sourceFileNames = paths.sort().map(contract => {
      if (path.isAbsolute(contract)) {
        return `.${path.sep}${path.relative(
          options.working_directory,
          contract
        )}`;
      }

      return contract;
    });
    options.events.emit("compile:sourcesToCompile", {sourceFileNames});
  }
};

module.exports = {
  Compile
};
<commit_msg>Account for multiple dots in file ext<commit_after>const path = require("path");
const exec = require("child_process").exec;
const fs = require("fs");
const colors = require("colors");
const minimatch = require("minimatch");

const findContracts = require("@truffle/contract-sources");
const Profiler = require("@truffle/compile-solidity/profiler");

const compiler = {
  name: "vyper",
  version: null
};

const VYPER_PATTERN = "**/*.{vy,v.py,vyper.py}";

// Check that vyper is available, save its version
function checkVyper() {
  return new Promise((resolve, reject) => {
    exec("vyper --version", function (err, stdout, stderr) {
      if (err) {
        return reject(`${colors.red("Error executing vyper:")}\n${stderr}`);
      }
      compiler.version = stdout.trim();
      resolve();
    });
  });
}

// Execute vyper for single source file
function execVyper(options, sourcePath, callback) {
  const formats = ["abi", "bytecode", "bytecode_runtime"];
  if (
    options.compilers.vyper.settings &&
    options.compilers.vyper.settings.sourceMap
  ) {
    formats.push("source_map");
  }
  const command = `vyper -f ${formats.join(",")} ${sourcePath}`;

  exec(command, {maxBuffer: 600 * 1024}, function (err, stdout, stderr) {
    if (err)
      return callback(
        `${stderr}\n${colors.red(
          `Compilation of ${sourcePath} failed. See above.`
        )}`
      );

    var outputs = stdout.split(/\r?\n/);

    const compiledContract = outputs.reduce((contract, output, index) => {
      return Object.assign(contract, {[formats[index]]: output});
    }, {});

    callback(null, compiledContract);
  });
}

/**
 *
 * read source contents from sourcePath
 */
function readSource(sourcePath) {
  const sourceBuffer = fs.readFileSync(sourcePath);
  return sourceBuffer.toString();
}

/**
 * aggregate source information based on compiled output;
 * this can include sources that are not contracts
 */
function processAllSources(sources) {
  if (!sourcePaths.length) return [];
  return sources.map(sourcePath => ({
    sourcePath: sourcePath,
    contents: readSource(sourcePath),
    language: sourcePath.substr(sourcePath.indexOf("."))
  }));
}

// compile all sources
async function compileAll({sources, options}) {
  options.logger = options.logger || console;

  Compile.display(sources, options);

  const promises = [];
  sources.forEach(sourcePath => {
    promises.push(
      new Promise((resolve, reject) => {
        execVyper(options, sourcePath, function (error, compiledContract) {
          if (error) return reject(error);

          // remove first extension from filename
          const extension = path.extname(sourcePath);
          const basename = path.basename(sourcePath, extension);

          // if extension is .py, remove second extension from filename
          const contractName =
            extension !== ".py"
              ? basename
              : path.basename(basename, path.extname(basename));

          const sourceContents = readSource(sourcePath);

          const contractDefinition = {
            contractName: contractName,
            sourcePath: sourcePath,
            source: sourceContents,
            abi: compiledContract.abi,
            bytecode: compiledContract.bytecode,
            deployedBytecode: compiledContract.bytecode_runtime,
            sourceMap: compiledContract.source_map,
            compiler
          };

          resolve(contractDefinition);
        });
      })
    );
  });
  const contracts = await Promise.all(promises);

  const compilerInfo = {name: "vyper", version: compiler.version};
  return {
    sources: processAllSources(sources),
    compilations: [
      {
        compiler: compilerInfo,
        contracts,
        sourceIndexes: sources
      }
    ]
  };
}

const Compile = {
  // Check that vyper is available then forward to internal compile function
  async sources({sources = [], options}) {
    // filter out non-vyper paths
    const vyperFiles = sources.filter(path => minimatch(path, VYPER_PATTERN));

    // no vyper files found, no need to check vyper
    if (vyperFiles.length === 0) {
      return {compilations: []};
    }

    await checkVyper();
    return await compileAll({
      sources: vyperFiles,
      options
    });
  },

  async sourcesWithDependencies({paths = [], options}) {
    return await Compile.sources({
      sources: paths,
      options
    });
  },

  // contracts_directory: String. Directory where contract files can be found.
  // quiet: Boolean. Suppress output. Defaults to false.
  // strict: Boolean. Return compiler warnings as errors. Defaults to false.
  async all(options) {
    const fileSearchPattern = path.join(
      options.contracts_directory,
      VYPER_PATTERN
    );
    const files = await findContracts(fileSearchPattern);

    return await Compile.sources({
      sources: files,
      options
    });
  },

  // contracts_directory: String. Directory where contract files can be found.
  // all: Boolean. Compile all sources found. Defaults to true. If false, will compare sources against built files
  //      in the build directory to see what needs to be compiled.
  // quiet: Boolean. Suppress output. Defaults to false.
  // strict: Boolean. Return compiler warnings as errors. Defaults to false.
  async necessary(options) {
    options.logger = options.logger || console;
    const updated = await Profiler.updated(options);

    if (updated.length === 0 && options.quiet !== true) {
      return {compilations: []};
    }

    // filter out only Vyper files
    const updatedVyperPaths = updated.filter(path => {
      return path.match(/\.vy$|\.v.py$|\.vyper.py$/);
    });
    return await Compile.sources({
      sources: updatedVyperPaths,
      options
    });
  },

  async display(paths, options) {
    if (!Array.isArray(paths)) {
      paths = Object.keys(paths);
    }

    const sourceFileNames = paths.sort().map(contract => {
      if (path.isAbsolute(contract)) {
        return `.${path.sep}${path.relative(
          options.working_directory,
          contract
        )}`;
      }

      return contract;
    });
    options.events.emit("compile:sourcesToCompile", {sourceFileNames});
  }
};

module.exports = {
  Compile
};
<|endoftext|>


<commit_before>var tv = require('intervalometer/time-value.js');
var interpolate = require('intervalometer/interpolate.js');

var exp = {};
var local = {};
exp.status = {};
exp.config = {};

exp.init = function(minEv, maxEv, nightCompensation) {
    if (nightCompensation === null) nightCompensation = -1;

    nightCompensation = parseFloat(nightCompensation);

    local = {
        lumArray: [],
        evArray: [],
        historyArray: [],
        rateHistoryArray: [],
        targetLum: null,
        first: true
    };

    exp.status = {
        rampEv: null,
        rate: null,
        direction: null
    };

    exp.config = {
        sunrise: {
            p: 0.9,
            i: 0.4,
            d: 0.6,
            targetTimeSeconds: 300,
            evIntegrationSeconds: 300,
            historyIntegrationSeconds: 480,
        },
        sunset: {
            p: 1.1,
            i: 0.6,
            d: 0.4,
            targetTimeSeconds: 480,
            evIntegrationSeconds: 480,
            historyIntegrationSeconds: 480,
        },
        maxEv: maxEv,
        minEv: minEv,
        maxRate: 30,
        hysteresis: 0.4,
        evScale: [{
            ev: -2,
            offset: nightCompensation
        }, {
            ev: 10,
            offset: 0
        }]
    };

    return exp.config;
}

exp.calculate = function(algorithm, currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    if(minEv != null) exp.config.minEv = minEv;
    if(maxEv != null) exp.config.maxEv = maxEv;

    if(algorithm == "lrt") {
        return exp.calculate_LRTtimelapse(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv);
    } else {
        return exp.calculate_TLPAuto(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv);
    }
}

exp.calculate_LRTtimelapse = function(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    var lum = 0;
    for(var i = 0; i < 256; i++) {
        lum += Math.pow(i, i / 256) / 256 * lastPhotoHistogram[i];
    }
    local.lumArray.push(lum);
    if(local.lumArray.length > 3) {
        local.lumArray.slice(0, 3);
    }
    var averageLum = local.lumArray.reduce(function(sum, val){
        return sum + val;
    }, 0) / local.lumArray.length;

    if(targetLum === null) {
        exp.status.rampEv = currentEv;
        targetLum = averageLum;
    }

    if(averageLum >= targetLum + targetLum * 0.1) {
        exp.status.rampEv = currentEv - 1/3;
    }
    if(averageLum <= targetLum - targetLum * 0.1) {
        exp.status.rampEv = currentEv + 1/3;
    }

    return exp.status.rampEv;
}

exp.calculate_TLPAuto = function(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    // measure the interval
    exp.status.intervalSeconds = 0;
    var thisPhotoTime = new Date();
    if (local.lastPhotoTime) {
        exp.status.intervalSeconds = (thisPhotoTime - local.lastPhotoTime) / 1000;
    }
    local.lastPhotoTime = thisPhotoTime;

    // get config based on rate up/down
    var config = exp.config.sunset;
    if (exp.status.direction && exp.status.direction > 0) {
        config = exp.config.sunrise;
    }

    // get the current rate of change
    exp.status.rate = calculateRate(currentEv, lastPhotoLum, config);
    console.log("rate: ", exp.status.rate);

    // don't change if within hysteresis setting
    if (Math.abs(exp.status.rate) < exp.config.hysteresis) exp.status.rate = 0;

    // limit to max rate
    if(exp.status.rate > exp.config.maxRate) exp.status.rate = exp.config.maxRate;
    if(exp.status.rate < -exp.config.maxRate) exp.status.rate = -exp.config.maxRate;

    // don't swing quickly past zero (stops oscillation)
    if (exp.status.rate > 3 && exp.status.direction < -0.5) exp.status.rate = 0;
    if (exp.status.rate < -3 && exp.status.direction > 0.5) exp.status.rate = 0;

    // adjust exposure according to rate in stops/hour
    exp.status.rampEv += (exp.status.rate / 3600) * exp.status.intervalSeconds;

    console.log("status: ", exp.status);
    //console.log("local: ", local);

    return exp.status.rampEv;
}

// ******* Private Functions ******* //

function filteredMean(tvArr, trim) {
    if (!trim) trim = 1;
    return tv.mean(tv.insideArray(tvArr, trim));
}

function filteredSlope(tvArr, trim) {
    if (!trim) trim = 1;
    return tv.mean(tv.insideArray(tv.slopes(tvArr), trim));
}

function calculateRate(currentEv, lastPhotoLum, config) {
    var diff = calculateDelta(currentEv, lastPhotoLum, config);
    exp.status.targetEv = currentEv + diff;
    if (exp.status.targetEv < exp.config.minEv) exp.status.targetEv = exp.config.minEv;
    if (exp.status.targetEv > exp.config.maxEv) exp.status.targetEv = exp.config.maxEv;
    if (exp.status.rampEv === null) exp.status.rampEv = exp.status.targetEv;
    var delta = exp.status.targetEv - exp.status.rampEv;
    local.historyArray.push({
        val: delta,
        time: new Date()
    });
    local.historyArray = tv.purgeArray(local.historyArray, config.historyIntegrationSeconds);

    exp.status.pastError = tv.mean(local.historyArray);

    exp.status.pComponent = delta * config.p;
    exp.status.iComponent = exp.status.pastError * config.i;
    exp.status.dComponent = exp.status.evSlope * config.d;

    delta *= config.p;
    delta += exp.status.pastError * config.i;
    delta += exp.status.evSlope * config.d;

    var rate = delta * (3600 / config.targetTimeSeconds);

    local.rateHistoryArray.push({
        val: rate,
        time: new Date()
    });
    local.rateHistoryArray = tv.purgeArray(local.rateHistoryArray, config.historyIntegrationSeconds);
    exp.status.direction = tv.mean(local.rateHistoryArray);

    return rate;
}

function calculateDelta(currentEv, lastPhotoLum, config) {
    local.lumArray.push({
        val: lastPhotoLum,
        time: new Date()
    });

    local.evArray.push({
        val: currentEv + lastPhotoLum,
        time: new Date()
    });

    if (local.first) {
        exp.status.offsetEv = lastPhotoLum - getEvOffsetScale(currentEv);
        local.first = false;
    }

    local.lumArray = tv.purgeArray(local.lumArray, config.evIntegrationSeconds);
    local.evArray = tv.purgeArray(local.evArray, config.evIntegrationSeconds);

    var trim = 1;
    if (exp.status.intervalSeconds) {
        trim = Math.ceil((config.evIntegrationSeconds / exp.status.intervalSeconds) * 0.2); // trim outer 20% from sorted array
    }

    exp.status.evMean = filteredMean(local.lumArray, trim);
    exp.status.evSlope = filteredSlope(local.evArray, trim) * config.targetTimeSeconds;

    return lastPhotoLum - exp.status.offsetEv - getEvOffsetScale(currentEv);
}

function getEvOffsetScale(ev) {
    var values = exp.config.evScale.map(function(item) {
        return {
            x: item.ev,
            y: item.offset
        }
    });
    return interpolate.linear(values, ev);
}

module.exports = exp;<commit_msg>bugfix<commit_after>var tv = require('intervalometer/time-value.js');
var interpolate = require('intervalometer/interpolate.js');

var exp = {};
var local = {};
exp.status = {};
exp.config = {};

exp.init = function(minEv, maxEv, nightCompensation) {
    if (nightCompensation === null) nightCompensation = -1;

    nightCompensation = parseFloat(nightCompensation);

    local = {
        lumArray: [],
        evArray: [],
        historyArray: [],
        rateHistoryArray: [],
        targetLum: null,
        first: true
    };

    exp.status = {
        rampEv: null,
        rate: null,
        direction: null
    };

    exp.config = {
        sunrise: {
            p: 0.9,
            i: 0.4,
            d: 0.6,
            targetTimeSeconds: 300,
            evIntegrationSeconds: 300,
            historyIntegrationSeconds: 480,
        },
        sunset: {
            p: 1.1,
            i: 0.6,
            d: 0.4,
            targetTimeSeconds: 480,
            evIntegrationSeconds: 480,
            historyIntegrationSeconds: 480,
        },
        maxEv: maxEv,
        minEv: minEv,
        maxRate: 30,
        hysteresis: 0.4,
        evScale: [{
            ev: -2,
            offset: nightCompensation
        }, {
            ev: 10,
            offset: 0
        }]
    };

    return exp.config;
}

exp.calculate = function(algorithm, currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    if(minEv != null) exp.config.minEv = minEv;
    if(maxEv != null) exp.config.maxEv = maxEv;

    if(algorithm == "lrt") {
        return exp.calculate_LRTtimelapse(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv);
    } else {
        return exp.calculate_TLPAuto(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv);
    }
}

exp.calculate_LRTtimelapse = function(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    var lum = 0;
    for(var i = 0; i < 256; i++) {
        lum += Math.pow(i, i / 256) / 256 * lastPhotoHistogram[i];
    }
    local.lumArray.push(lum);
    if(local.lumArray.length > 3) {
        local.lumArray.slice(0, 3);
    }
    var averageLum = local.lumArray.reduce(function(sum, val){
        return sum + val;
    }, 0) / local.lumArray.length;

    if(local.targetLum === null) {
        exp.status.rampEv = currentEv;
        local.targetLum = averageLum;
    }

    if(averageLum >= local.targetLum + local.targetLum * 0.1) {
        exp.status.rampEv = currentEv - 1/3;
    }
    if(averageLum <= local.targetLum - local.targetLum * 0.1) {
        exp.status.rampEv = currentEv + 1/3;
    }

    return exp.status.rampEv;
}

exp.calculate_TLPAuto = function(currentEv, lastPhotoLum, lastPhotoHistogram, minEv, maxEv) {
    // measure the interval
    exp.status.intervalSeconds = 0;
    var thisPhotoTime = new Date();
    if (local.lastPhotoTime) {
        exp.status.intervalSeconds = (thisPhotoTime - local.lastPhotoTime) / 1000;
    }
    local.lastPhotoTime = thisPhotoTime;

    // get config based on rate up/down
    var config = exp.config.sunset;
    if (exp.status.direction && exp.status.direction > 0) {
        config = exp.config.sunrise;
    }

    // get the current rate of change
    exp.status.rate = calculateRate(currentEv, lastPhotoLum, config);
    console.log("rate: ", exp.status.rate);

    // don't change if within hysteresis setting
    if (Math.abs(exp.status.rate) < exp.config.hysteresis) exp.status.rate = 0;

    // limit to max rate
    if(exp.status.rate > exp.config.maxRate) exp.status.rate = exp.config.maxRate;
    if(exp.status.rate < -exp.config.maxRate) exp.status.rate = -exp.config.maxRate;

    // don't swing quickly past zero (stops oscillation)
    if (exp.status.rate > 3 && exp.status.direction < -0.5) exp.status.rate = 0;
    if (exp.status.rate < -3 && exp.status.direction > 0.5) exp.status.rate = 0;

    // adjust exposure according to rate in stops/hour
    exp.status.rampEv += (exp.status.rate / 3600) * exp.status.intervalSeconds;

    console.log("status: ", exp.status);
    //console.log("local: ", local);

    return exp.status.rampEv;
}

// ******* Private Functions ******* //

function filteredMean(tvArr, trim) {
    if (!trim) trim = 1;
    return tv.mean(tv.insideArray(tvArr, trim));
}

function filteredSlope(tvArr, trim) {
    if (!trim) trim = 1;
    return tv.mean(tv.insideArray(tv.slopes(tvArr), trim));
}

function calculateRate(currentEv, lastPhotoLum, config) {
    var diff = calculateDelta(currentEv, lastPhotoLum, config);
    exp.status.targetEv = currentEv + diff;
    if (exp.status.targetEv < exp.config.minEv) exp.status.targetEv = exp.config.minEv;
    if (exp.status.targetEv > exp.config.maxEv) exp.status.targetEv = exp.config.maxEv;
    if (exp.status.rampEv === null) exp.status.rampEv = exp.status.targetEv;
    var delta = exp.status.targetEv - exp.status.rampEv;
    local.historyArray.push({
        val: delta,
        time: new Date()
    });
    local.historyArray = tv.purgeArray(local.historyArray, config.historyIntegrationSeconds);

    exp.status.pastError = tv.mean(local.historyArray);

    exp.status.pComponent = delta * config.p;
    exp.status.iComponent = exp.status.pastError * config.i;
    exp.status.dComponent = exp.status.evSlope * config.d;

    delta *= config.p;
    delta += exp.status.pastError * config.i;
    delta += exp.status.evSlope * config.d;

    var rate = delta * (3600 / config.targetTimeSeconds);

    local.rateHistoryArray.push({
        val: rate,
        time: new Date()
    });
    local.rateHistoryArray = tv.purgeArray(local.rateHistoryArray, config.historyIntegrationSeconds);
    exp.status.direction = tv.mean(local.rateHistoryArray);

    return rate;
}

function calculateDelta(currentEv, lastPhotoLum, config) {
    local.lumArray.push({
        val: lastPhotoLum,
        time: new Date()
    });

    local.evArray.push({
        val: currentEv + lastPhotoLum,
        time: new Date()
    });

    if (local.first) {
        exp.status.offsetEv = lastPhotoLum - getEvOffsetScale(currentEv);
        local.first = false;
    }

    local.lumArray = tv.purgeArray(local.lumArray, config.evIntegrationSeconds);
    local.evArray = tv.purgeArray(local.evArray, config.evIntegrationSeconds);

    var trim = 1;
    if (exp.status.intervalSeconds) {
        trim = Math.ceil((config.evIntegrationSeconds / exp.status.intervalSeconds) * 0.2); // trim outer 20% from sorted array
    }

    exp.status.evMean = filteredMean(local.lumArray, trim);
    exp.status.evSlope = filteredSlope(local.evArray, trim) * config.targetTimeSeconds;

    return lastPhotoLum - exp.status.offsetEv - getEvOffsetScale(currentEv);
}

function getEvOffsetScale(ev) {
    var values = exp.config.evScale.map(function(item) {
        return {
            x: item.ev,
            y: item.offset
        }
    });
    return interpolate.linear(values, ev);
}

module.exports = exp;<|endoftext|>


<commit_before>
var message = null
var methodMatch = {
    "setOption": createAPI,
    "preparePayment": preparePayment,
    "disconnect": disconnect
}
window.addEventListener('message', onMessage);

var api={}

function onMessage(event) {
       console.log("received fom scala")
       console.log(event)
    var method = event.data.method_name;
    var call_id = event.data.call_id;
    var parameters = (JSON.parse(event.data.parameters));
    var result = methodMatch[method](parameters)
    result.then(function (message) {
        console.log("message from api")
        console.log(message)
        var toScala = {call_id: event.data.call_id, response: JSON.stringify(message)};
        if(method == "setOption"){
            toScala.response = JSON.stringify({connected: true, info: "success"})
        }
         parent.postMessage(toScala, "*");
        }).catch(function (message) {
            console.log("exception caught")
            var toScala = {call_id: event.data.call_id, response: JSON.stringify(message)};
            if(method == "setOption"){
                        toScala.response = JSON.stringify({connected: false, info: "error"})
                    }
            parent.postMessage(toScala, "*");
        })
    console.log("onMessage terminated")
    }

function disconnect(){
    return api.disconnect()
}

function preparePayment(parameters) {
    return api.preparePayment(parameters)
}

function createAPI(options){
    api = new RippleAPI(options);
    api.on('error', (errorCode, errorMessage) => {
      console.log(errorCode + ': ' + errorMessage);
    });
    api.on('connected', function () {
      console.log('connected');
    });
    api.on('disconnected', function (code) {
      // code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
      // will be 1000 if this was normal closure
      console.log('disconnected, code:', code);
    });
    return api.connect()
}
<commit_msg>sign and submit complete<commit_after>
var message = null
var methodMatch = {
    "setOption": createAPI,
    "preparePayment": preparePayment,
    "disconnect": disconnect,
    "submit": submit,
    "sign": sign
}
window.addEventListener('message', onMessage);

var api={}

function onMessage(event) {
       console.log("received fom scala")
       console.log(event)
    var method = event.data.method_name;
    var call_id = event.data.call_id;
    var parameters = (JSON.parse(event.data.parameters));
    var result = methodMatch[method](parameters)
    result.then(function (message) {
        console.log("message from api")
        console.log(message)
        var toScala = {
                        call_id: event.data.call_id,
                        response: JSON.stringify(message)
                      };
        if(method == "setOption"){
            toScala.response = JSON.stringify({
                                                connected: true,
                                                info: "success"
                                              })
        }
        parent.postMessage(toScala, "*");
        }).catch(function (message) {
            console.log("exception caught")
            var toScala = {
                            call_id: event.data.call_id,
                            response: JSON.stringify(message)
                          };
            if(method == "setOption"){
              toScala.response = JSON.stringify({
                                                  connected: false,
                                                  info: "error"
                                                 })
            }
            parent.postMessage(toScala, "*");
        })
    console.log("onMessage terminated")
    }

function disconnect(){     //not used yet
    return api.disconnect()
}

function sign(parameters) {
    return new Promise((resolve, reject) => {
        resolve(api.sign(parameters))
    }
}

function submit(parameters) {
    return api.submit(parameters)
}

function preparePayment(parameters) {
    return api.preparePayment(parameters)
}

function createAPI(options){
    api = new RippleAPI(options);
    api.on('error', (errorCode, errorMessage) => {
      console.log(errorCode + ': ' + errorMessage);
    });
    api.on('connected', function () {
      console.log('connected');
    });
    api.on('disconnected', function (code) {
      // code - [close code](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) sent by the server
      // will be 1000 if this was normal closure
      console.log('disconnected, code:', code);
    });
    return api.connect()
}
<|endoftext|>


<commit_before>var $ = require('jquery');
require('sticky');
require('jquery-easing');
require('jquery.scrollto');
require('cf-expandables');
var debounce = require('debounce');

// Constants. These variables should not change.
var $WRAPPER, $TABS, $PAGINATION, $WINDOW, TOTAL;

// Keys to sections on page.
var termsList = '.explain_terms';

// TODO: define category list in calling page, and
// also pass it to form-explainer.html to construct tabs
var CATEGORIES = ['checklist', 'definitions'];
var DEFAULT_TYPE = 'checklist';
var $INITIAL_TAB;

var resized;

var stickBottom = 'js-sticky-bottom';

/**
 * Get the currently displayed form page as a number.
 * Grabs the number from the currently displayed .explain_page element ID.
 * @return {number}
 */
function getCurrentPageNum() {
  return parseInt( $WRAPPER.find('.explain_page:visible').attr('id').replace( 'explain_page-', '' ), 10 );
}

function getPageEl (pageNum) {
  return $WRAPPER.find('#explain_page-' + pageNum);
}

function getPageElements (pageNum) {
  var $page = getPageEl(pageNum);
  return {
    $page:             $page,
    $imageMap:         $page.find('.image-map'),
    $imageMapImage:    $page.find('.image-map_image'),
    $imageMapWrapper:  $page.find('.image-map_wrapper'),
    $terms:            $page.find('.terms')
  }
}

function calculateNewImageWidth (imageWidth, imageHeight) {
  var imageMapImageRatio = (imageWidth + 2) / (imageHeight + 2);
  return ($WINDOW.height() - 60) * imageMapImageRatio + 30;
}

function resizeImage (els, windowResize) {
  var pageWidth = els.$page.width();
  var $image = els.$imageMapImage;
  var currentHeight = $image.height();
  var currentWidth = $image.width();
  var actualWidth = $image.data("actual-width");
  var actualHeight = $image.data("actual-height");
  var windowHeight = $WINDOW.innerHeight() - 60;
  var newWidth;
  var newWidthPercentage;

  // If the image is too tall for the window, resize it proportionally,
  // then update the adjacent terms column width to fit.
  // On window resize, also check if image is now too small & resize,
  // but only if we've stored the actual image dimensions for comparison.
  if ( currentHeight > windowHeight || (windowResize && actualWidth && actualHeight)) {
    // determine new width
    newWidth = calculateNewImageWidth(currentWidth, currentHeight);
    if (newWidth > actualWidth) {
      newWidth = actualWidth;
    }
    // update element widths
    newWidthPercentage = newWidth / pageWidth * 100;
    // on screen less than 800px wide, the terms need a minimum 33%
    // width or they become too narrow to read
    if ($WINDOW.width() <= 800 && newWidthPercentage > 67) {
      newWidthPercentage = 67;
    }
    els.$imageMap.css( 'width', newWidthPercentage + '%' );
    $PAGINATION.css( 'width', newWidthPercentage + '%' );
    els.$terms.css( 'width', (100 - newWidthPercentage) + '%' );
  }
}

function setImageElementWidths (els) {
  // When the sticky plugin is applied to the image, it adds position fixed,
  // and the image's width is no longer constrained to its parent.
  // To fix this we will give it its own width that is equal to the parent.
  // (IE8 wants a width on the wrapper too)
  var containerWidth = els.$imageMap.width();
  els.$imageMapWrapper.width(containerWidth);
  els.$imageMapImage.width(containerWidth);
}

function storeImageDimensions ($image) {
  $image.data('actual-width', $image.width());
  $image.data('actual-height', $image.height());
}

function stickImage($el) {
  $el.sticky({ topSpacing: 30 });
}

/**
 * Limit .image-map_image to the height of the window and then adjust the two
 * columns to match.
 * @return {null}
 */
function fitAndStickToWindow(els, pageNum) {
  // http://stackoverflow.com/questions/318630/get-real-image-width-and-height-with-javascript-in-safari-chrome
  $('')
    .load( function() {
      // store image width for use in calculations on window resize
      if (pageNum) {
        storeImageDimensions(els.$imageMapImage);
      }

      // if image is too tall/small, fit it to window dimensions
      resizeImage(els, !pageNum);

      // set width values on image elements
      setImageElementWidths(els);

      if (pageNum || els.$imageMapImage.closest('.sticky-wrapper').length == 0) {
        // stick image to window
        stickImage(els.$imageMapWrapper);
      } else {
        updateStickiness()
      }
      // hide pages except for first
      if (pageNum > 1) {
          els.$page.hide();
      }
    })
    // This order is necessary so that IE8 doesn't fire the onload event
    // before the src is set for cached images
    // http://stackoverflow.com/questions/14429656/onload-callback-on-image-not-called-in-ie8
    .attr( 'src', els.$imageMapImage.attr('src') );
}

/**
 * Override sticky() if the viewport has been scrolled past $currentPage so that
 * the sticky element does not overlap content that comes after $currentPage.
 * @return {null}
 */
function updateStickiness() {
  var els =  getPageElements(getCurrentPageNum());
  var max = els.$page.offset().top + els.$page.height() - els.$imageMapWrapper.height();
  if ($WINDOW.scrollTop() >= max && !els.$imageMapWrapper.hasClass(stickBottom)) {
    els.$imageMapWrapper.addClass(stickBottom);
  } else if ($WINDOW.scrollTop() < max && els.$imageMapWrapper.hasClass(stickBottom)) {
    els.$imageMapWrapper.removeClass(stickBottom);
  }
}

/**
 * Paginate through the various form pages.
 * @return {null}
 */
function paginate( direction ) {
  var currentPage = getCurrentPageNum(), newCurrentPage;
  if ( direction === 'next' ) {
    newCurrentPage = currentPage + 1;
  } else if ( direction === 'prev' ) {
    newCurrentPage = currentPage - 1;
  }
  // Move to the next or previous page if it's not the first or last page.
  if ( direction === 'next' && newCurrentPage <= TOTAL ||
       direction === 'prev' && newCurrentPage >= 1 ) {
    // Scroll the window up to the tabs.
    $.scrollTo( $TABS, {
      duration: 600,
      offset: -30
    });
    // After scrolling the window, fade out the current page.
    var fadeOutTimeout = window.setTimeout(function () {
      getPageEl(getCurrentPageNum()).fadeOut( 450 );
      window.clearTimeout( fadeOutTimeout );
    }, 600);
    // After fading out the current page, fade in the new page.
    var fadeInTimeout = window.setTimeout(function () {
      getPageEl(newCurrentPage).fadeIn( 700 );
      stickyHack();
      window.clearTimeout( fadeInTimeout );
      if (resized ) {
        setupImage(newCurrentPage);
      }
    }, 1050);
  }
  // Update the pagination numbers.
  $WRAPPER.find('.explain_pagination .pagination_current').text( newCurrentPage );
  // Update the previous/next buttons if the new page is the first or last.
  $('.explain_pagination .pagination_prev, .explain_pagination .pagination_next').removeClass('btn__disabled');
  if ( newCurrentPage === 1 ) {
    $WRAPPER.find('.explain_pagination .pagination_prev').addClass('btn__disabled');
  } else if ( newCurrentPage === TOTAL ) {
    $WRAPPER.find('.explain_pagination .pagination_next').addClass('btn__disabled');
  }
}

function setupImage (pageNum, pageLoad) {
  var pageEls = getPageElements(pageNum);
  if ($WINDOW.width() >= 600) {
    // update widths & stickiness on larger screens
    // we only pass in the pageNum on pageLoad, when
    // pages after the first will be hidden once they're
    // fully loaded & we've calculated their widths
    fitAndStickToWindow(pageEls, pageLoad ? pageNum : null);
  } else if (!pageLoad) {
    // if this is called on screen resize instead of page load,
    // remove width values & call unstick on the imageWrapper
    pageEls.$imageMapWrapper.width('').removeClass(stickBottom);
    pageEls.$imageMap.width('');
    pageEls.$imageMapImage.width('');
    pageEls.$terms.width('');
    pageEls.$imageMapWrapper.unstick();
  } else if (pageNum > 1) {
    // on page load, hide pages except first
    pageEls.$page.hide();
  }
}

function initForm () {
  // Loop through each page, setting its dimensions properly and activating the
  // sticky() plugin.
  $WRAPPER.find('.explain_page').each(function( index ) {
    initPage(index + 1);
  });
}

/**
 * Initialize a page.
 * @return {null}
 */
function initPage(id) {
  setupImage(id, true);
  setCategoryPlaceholders(id);
}

/**
 * Weird hack to get sticky() to update properly.
 * We're basically jinggling the window to force a sticky() repaint.
 * Sometimes it just needs a push I guess?
 * @return {null}
 */
function stickyHack() {
  $WINDOW.scrollTop( $WINDOW.scrollTop() + 1 );
  $WINDOW.scrollTop( $WINDOW.scrollTop() - 1 );
}

/**
 * Set category placeholders
 * @return {null}
 */
function setCategoryPlaceholders( id ) {
  var $page = getPageEl(id), placeholder;
  for (var i = 0; i < CATEGORIES.length; i++) {
    var category = CATEGORIES[i];
    if (!categoryHasContent($page, category)) {
      placeholder = generatePlaceholderHtml(category);
      $page.find('.explain_terms').append(placeholder);
    }
  }
}

function generatePlaceholderHtml (category) {
  return '' +
  '
' +
    '' +
      'No ' + category + ' on this page. ' +
      'Filter by another category above or page ahead to continue exploring ' +
      category + '.' +
    '' +
  '
';
}

function categoryHasContent ($page, category) {
  return $page.find('.expandable__form-explainer-' + category).length;
}

function filterExplainers ($currentTab, type) {
    // Update the tab state
    $('.explain_tabs .tab-list').removeClass('active-tab');
    $currentTab.addClass('active-tab');

    // Filter the expandables
    $WRAPPER.find('.expandable__form-explainer').hide();
    $WRAPPER.find('.image-map_overlay').hide();
    $WRAPPER.find('.expandable__form-explainer-' + type).show();
    $WRAPPER.find('.image-map_overlay__' + type).show();
}

function toggleScrollWatch() {
  $WINDOW.off('scroll.stickiness');
  if ($WINDOW.width() >= 600) {
    $WINDOW.on('scroll.stickiness', debounce(updateStickiness, 20));
  }
}

// Kick things off on document ready.
$(document).ready(function(){
  // cache elements
  $WRAPPER =    $('.explain'),
  $TABS =       $WRAPPER.find('.explain_tabs'),
  $PAGINATION = $WRAPPER.find('.explain_pagination'),
  $WINDOW =     $( window ),
  TOTAL =       parseInt( $PAGINATION.find('.pagination_total').text(), 10 );
  $INITIAL_TAB = $('.tab-link[data-target="' + DEFAULT_TYPE + '"]').closest('.tab-list');

  // set up the form pages for display
  initForm();

  // filter initial state
  filterExplainers($INITIAL_TAB, DEFAULT_TYPE);

  // add scroll listener for larger windows
  toggleScrollWatch();

  // add resize listener
  var prevWindowWidth = $WINDOW.width();
  var prevWindowHeight = $WINDOW.height();
  var isIE = $('html').hasClass('lt-ie9');

  $(window).on("resize",debounce(function(){
    //resize things
    // apparently IE fires a window resize event when anything in the page
    // resizes, so for IE we need to check that the window dimensions have
    // actually changed
    if (isIE) {
      var currWindowHeight = $WINDOW.height();
      var currWindowWidth = $WINDOW.width();
      if (currWindowHeight === prevWindowHeight && currWindowWidth === prevWindowWidth) {
        return;
      } else {
        prevWindowWidth = currWindowWidth;
        prevWindowHeight = currWindowHeight;
      }
    }
    resized = true;
    setupImage(getCurrentPageNum());
    toggleScrollWatch();
  }));

  // Pagination events
  $WRAPPER.find( '.explain_pagination .pagination_next' ).on( 'click', function( event ) {
    if ( !$( event.currentTarget ).hasClass('btn__disabled') ) {
      paginate('next');
    }
  });
  $WRAPPER.find( '.explain_pagination .pagination_prev' ).on( 'click', function( event ) {
    if ( !$( event.currentTarget ).hasClass('btn__disabled') ) {
      paginate('prev');
    }
  });

  // Filter the expandables via the tabs
  $WRAPPER.on( 'click', '.explain_tabs .tab-list', function( event ) {
    var $selectedTab = $(this);
    var explainerType = $selectedTab.find('[data-target]').data('target');

    filterExplainers($selectedTab, explainerType);

    $.scrollTo( $TABS, {
      duration: 200,
      offset: -30
    });
  });

  // When an overlay is clicked, toggle the corresponding expandable and scroll
  // the page until it is in view.
  $WRAPPER.on( 'click', '.image-map_overlay', function( event ) {
    event.preventDefault();
    var itemID = $( this ).attr('href');
    $.scrollTo( $(itemID), {
      duration: 200,
      offset: -30
    });
    $( itemID )
      .attr('tabindex', '0').attr('aria-hidden', 'false')
      .get(0).toggle();

  });

  // Add tabindex to links inside of expandables, so they are tabbable in the correct order.
  $WRAPPER.on( 'focus', '.expandable__form-explainer .expandable_target', function (event) {
    var $this = $(this),
        $content = $this.siblings('.expandable_content'),
        $tabindex = $content.attr('tabindex');
    $content.find('a').attr('tabindex', $tabindex);
  });

  // When mousing over a term or highlighted area of the image map,
  // call attention to the associated map area or term, respectively.
  $WRAPPER.on( 'mouseenter mouseleave', '.image-map_overlay, .expandable__form-explainer', function( event ) {
    event.preventDefault();
    var $target;
    if ( typeof $( this ).attr('href') !== 'undefined' ) {
      $target = $( $(this).attr('href') );
    } else  if ( typeof $( this ).attr('id') !== 'undefined' ) {
      $target = $('[href=#'+$( this ).attr('id')+']');
    }
    if ( typeof $target !== 'undefined' ) {
      if ( $target.hasClass('has-attention') ) {
        $target.removeClass('has-attention');
      } else {
        $target.addClass('has-attention');
      }
    }
  });

});
<commit_msg>cleanup js to add tabindex<commit_after>var $ = require('jquery');
require('sticky');
require('jquery-easing');
require('jquery.scrollto');
require('cf-expandables');
var debounce = require('debounce');

// Constants. These variables should not change.
var $WRAPPER, $TABS, $PAGINATION, $WINDOW, TOTAL;

// Keys to sections on page.
var termsList = '.explain_terms';

// TODO: define category list in calling page, and
// also pass it to form-explainer.html to construct tabs
var CATEGORIES = ['checklist', 'definitions'];
var DEFAULT_TYPE = 'checklist';
var $INITIAL_TAB;

var resized;

var stickBottom = 'js-sticky-bottom';

/**
 * Get the currently displayed form page as a number.
 * Grabs the number from the currently displayed .explain_page element ID.
 * @return {number}
 */
function getCurrentPageNum() {
  return parseInt( $WRAPPER.find('.explain_page:visible').attr('id').replace( 'explain_page-', '' ), 10 );
}

function getPageEl (pageNum) {
  return $WRAPPER.find('#explain_page-' + pageNum);
}

function getPageElements (pageNum) {
  var $page = getPageEl(pageNum);
  return {
    $page:             $page,
    $imageMap:         $page.find('.image-map'),
    $imageMapImage:    $page.find('.image-map_image'),
    $imageMapWrapper:  $page.find('.image-map_wrapper'),
    $terms:            $page.find('.terms')
  }
}

function calculateNewImageWidth (imageWidth, imageHeight) {
  var imageMapImageRatio = (imageWidth + 2) / (imageHeight + 2);
  return ($WINDOW.height() - 60) * imageMapImageRatio + 30;
}

function resizeImage (els, windowResize) {
  var pageWidth = els.$page.width();
  var $image = els.$imageMapImage;
  var currentHeight = $image.height();
  var currentWidth = $image.width();
  var actualWidth = $image.data("actual-width");
  var actualHeight = $image.data("actual-height");
  var windowHeight = $WINDOW.innerHeight() - 60;
  var newWidth;
  var newWidthPercentage;

  // If the image is too tall for the window, resize it proportionally,
  // then update the adjacent terms column width to fit.
  // On window resize, also check if image is now too small & resize,
  // but only if we've stored the actual image dimensions for comparison.
  if ( currentHeight > windowHeight || (windowResize && actualWidth && actualHeight)) {
    // determine new width
    newWidth = calculateNewImageWidth(currentWidth, currentHeight);
    if (newWidth > actualWidth) {
      newWidth = actualWidth;
    }
    // update element widths
    newWidthPercentage = newWidth / pageWidth * 100;
    // on screen less than 800px wide, the terms need a minimum 33%
    // width or they become too narrow to read
    if ($WINDOW.width() <= 800 && newWidthPercentage > 67) {
      newWidthPercentage = 67;
    }
    els.$imageMap.css( 'width', newWidthPercentage + '%' );
    $PAGINATION.css( 'width', newWidthPercentage + '%' );
    els.$terms.css( 'width', (100 - newWidthPercentage) + '%' );
  }
}

function setImageElementWidths (els) {
  // When the sticky plugin is applied to the image, it adds position fixed,
  // and the image's width is no longer constrained to its parent.
  // To fix this we will give it its own width that is equal to the parent.
  // (IE8 wants a width on the wrapper too)
  var containerWidth = els.$imageMap.width();
  els.$imageMapWrapper.width(containerWidth);
  els.$imageMapImage.width(containerWidth);
}

function storeImageDimensions ($image) {
  $image.data('actual-width', $image.width());
  $image.data('actual-height', $image.height());
}

function stickImage($el) {
  $el.sticky({ topSpacing: 30 });
}

/**
 * Limit .image-map_image to the height of the window and then adjust the two
 * columns to match.
 * @return {null}
 */
function fitAndStickToWindow(els, pageNum) {
  // http://stackoverflow.com/questions/318630/get-real-image-width-and-height-with-javascript-in-safari-chrome
  $('')
    .load( function() {
      // store image width for use in calculations on window resize
      if (pageNum) {
        storeImageDimensions(els.$imageMapImage);
      }

      // if image is too tall/small, fit it to window dimensions
      resizeImage(els, !pageNum);

      // set width values on image elements
      setImageElementWidths(els);

      if (pageNum || els.$imageMapImage.closest('.sticky-wrapper').length == 0) {
        // stick image to window
        stickImage(els.$imageMapWrapper);
      } else {
        updateStickiness()
      }
      // hide pages except for first
      if (pageNum > 1) {
          els.$page.hide();
      }
    })
    // This order is necessary so that IE8 doesn't fire the onload event
    // before the src is set for cached images
    // http://stackoverflow.com/questions/14429656/onload-callback-on-image-not-called-in-ie8
    .attr( 'src', els.$imageMapImage.attr('src') );
}

/**
 * Override sticky() if the viewport has been scrolled past $currentPage so that
 * the sticky element does not overlap content that comes after $currentPage.
 * @return {null}
 */
function updateStickiness() {
  var els =  getPageElements(getCurrentPageNum());
  var max = els.$page.offset().top + els.$page.height() - els.$imageMapWrapper.height();
  if ($WINDOW.scrollTop() >= max && !els.$imageMapWrapper.hasClass(stickBottom)) {
    els.$imageMapWrapper.addClass(stickBottom);
  } else if ($WINDOW.scrollTop() < max && els.$imageMapWrapper.hasClass(stickBottom)) {
    els.$imageMapWrapper.removeClass(stickBottom);
  }
}

/**
 * Paginate through the various form pages.
 * @return {null}
 */
function paginate( direction ) {
  var currentPage = getCurrentPageNum(), newCurrentPage;
  if ( direction === 'next' ) {
    newCurrentPage = currentPage + 1;
  } else if ( direction === 'prev' ) {
    newCurrentPage = currentPage - 1;
  }
  // Move to the next or previous page if it's not the first or last page.
  if ( direction === 'next' && newCurrentPage <= TOTAL ||
       direction === 'prev' && newCurrentPage >= 1 ) {
    // Scroll the window up to the tabs.
    $.scrollTo( $TABS, {
      duration: 600,
      offset: -30
    });
    // After scrolling the window, fade out the current page.
    var fadeOutTimeout = window.setTimeout(function () {
      getPageEl(getCurrentPageNum()).fadeOut( 450 );
      window.clearTimeout( fadeOutTimeout );
    }, 600);
    // After fading out the current page, fade in the new page.
    var fadeInTimeout = window.setTimeout(function () {
      getPageEl(newCurrentPage).fadeIn( 700 );
      stickyHack();
      window.clearTimeout( fadeInTimeout );
      if (resized ) {
        setupImage(newCurrentPage);
      }
    }, 1050);
  }
  // Update the pagination numbers.
  $WRAPPER.find('.explain_pagination .pagination_current').text( newCurrentPage );
  // Update the previous/next buttons if the new page is the first or last.
  $('.explain_pagination .pagination_prev, .explain_pagination .pagination_next').removeClass('btn__disabled');
  if ( newCurrentPage === 1 ) {
    $WRAPPER.find('.explain_pagination .pagination_prev').addClass('btn__disabled');
  } else if ( newCurrentPage === TOTAL ) {
    $WRAPPER.find('.explain_pagination .pagination_next').addClass('btn__disabled');
  }
}

function setupImage (pageNum, pageLoad) {
  var pageEls = getPageElements(pageNum);
  if ($WINDOW.width() >= 600) {
    // update widths & stickiness on larger screens
    // we only pass in the pageNum on pageLoad, when
    // pages after the first will be hidden once they're
    // fully loaded & we've calculated their widths
    fitAndStickToWindow(pageEls, pageLoad ? pageNum : null);
  } else if (!pageLoad) {
    // if this is called on screen resize instead of page load,
    // remove width values & call unstick on the imageWrapper
    pageEls.$imageMapWrapper.width('').removeClass(stickBottom);
    pageEls.$imageMap.width('');
    pageEls.$imageMapImage.width('');
    pageEls.$terms.width('');
    pageEls.$imageMapWrapper.unstick();
  } else if (pageNum > 1) {
    // on page load, hide pages except first
    pageEls.$page.hide();
  }
}

function initForm () {
  // Loop through each page, setting its dimensions properly and activating the
  // sticky() plugin.
  $WRAPPER.find('.explain_page').each(function( index ) {
    initPage(index + 1);
  });
}

/**
 * Initialize a page.
 * @return {null}
 */
function initPage(id) {
  setupImage(id, true);
  setCategoryPlaceholders(id);
}

/**
 * Weird hack to get sticky() to update properly.
 * We're basically jinggling the window to force a sticky() repaint.
 * Sometimes it just needs a push I guess?
 * @return {null}
 */
function stickyHack() {
  $WINDOW.scrollTop( $WINDOW.scrollTop() + 1 );
  $WINDOW.scrollTop( $WINDOW.scrollTop() - 1 );
}

/**
 * Set category placeholders
 * @return {null}
 */
function setCategoryPlaceholders( id ) {
  var $page = getPageEl(id), placeholder;
  for (var i = 0; i < CATEGORIES.length; i++) {
    var category = CATEGORIES[i];
    if (!categoryHasContent($page, category)) {
      placeholder = generatePlaceholderHtml(category);
      $page.find('.explain_terms').append(placeholder);
    }
  }
}

function generatePlaceholderHtml (category) {
  return '' +
  '
' +
    '' +
      'No ' + category + ' on this page. ' +
      'Filter by another category above or page ahead to continue exploring ' +
      category + '.' +
    '' +
  '
';
}

function categoryHasContent ($page, category) {
  return $page.find('.expandable__form-explainer-' + category).length;
}

function filterExplainers ($currentTab, type) {
    // Update the tab state
    $('.explain_tabs .tab-list').removeClass('active-tab');
    $currentTab.addClass('active-tab');

    // Filter the expandables
    $WRAPPER.find('.expandable__form-explainer').hide();
    $WRAPPER.find('.image-map_overlay').hide();
    $WRAPPER.find('.expandable__form-explainer-' + type).show();
    $WRAPPER.find('.image-map_overlay__' + type).show();
}

function toggleScrollWatch() {
  $WINDOW.off('scroll.stickiness');
  if ($WINDOW.width() >= 600) {
    $WINDOW.on('scroll.stickiness', debounce(updateStickiness, 20));
  }
}

function addTabindex() {
  var $link = $('.expandable__form-explainer .expandable_content a');
  $link.attr('tabindex', 0);
}

// Kick things off on document ready.
$(document).ready(function(){
  // cache elements
  $WRAPPER =    $('.explain'),
  $TABS =       $WRAPPER.find('.explain_tabs'),
  $PAGINATION = $WRAPPER.find('.explain_pagination'),
  $WINDOW =     $( window ),
  TOTAL =       parseInt( $PAGINATION.find('.pagination_total').text(), 10 );
  $INITIAL_TAB = $('.tab-link[data-target="' + DEFAULT_TYPE + '"]').closest('.tab-list');

  // set up the form pages for display
  initForm();

  // filter initial state
  filterExplainers($INITIAL_TAB, DEFAULT_TYPE);

  // add scroll listener for larger windows
  toggleScrollWatch();

  // set tabindex for links in expandables content
  addTabindex();

  // add resize listener
  var prevWindowWidth = $WINDOW.width();
  var prevWindowHeight = $WINDOW.height();
  var isIE = $('html').hasClass('lt-ie9');

  $(window).on("resize",debounce(function(){
    //resize things
    // apparently IE fires a window resize event when anything in the page
    // resizes, so for IE we need to check that the window dimensions have
    // actually changed
    if (isIE) {
      var currWindowHeight = $WINDOW.height();
      var currWindowWidth = $WINDOW.width();
      if (currWindowHeight === prevWindowHeight && currWindowWidth === prevWindowWidth) {
        return;
      } else {
        prevWindowWidth = currWindowWidth;
        prevWindowHeight = currWindowHeight;
      }
    }
    resized = true;
    setupImage(getCurrentPageNum());
    toggleScrollWatch();
  }));

  // Pagination events
  $WRAPPER.find( '.explain_pagination .pagination_next' ).on( 'click', function( event ) {
    if ( !$( event.currentTarget ).hasClass('btn__disabled') ) {
      paginate('next');
    }
  });
  $WRAPPER.find( '.explain_pagination .pagination_prev' ).on( 'click', function( event ) {
    if ( !$( event.currentTarget ).hasClass('btn__disabled') ) {
      paginate('prev');
    }
  });

  // Filter the expandables via the tabs
  $WRAPPER.on( 'click', '.explain_tabs .tab-list', function( event ) {
    var $selectedTab = $(this);
    var explainerType = $selectedTab.find('[data-target]').data('target');

    filterExplainers($selectedTab, explainerType);

    $.scrollTo( $TABS, {
      duration: 200,
      offset: -30
    });
  });

  // When an overlay is clicked, toggle the corresponding expandable and scroll
  // the page until it is in view.
  $WRAPPER.on( 'click', '.image-map_overlay', function( event ) {
    event.preventDefault();
    var itemID = $( this ).attr('href');
    $.scrollTo( $(itemID), {
      duration: 200,
      offset: -30
    });
  });

  // When mousing over a term or highlighted area of the image map,
  // call attention to the associated map area or term, respectively.
  $WRAPPER.on( 'mouseenter mouseleave', '.image-map_overlay, .expandable__form-explainer', function( event ) {
    event.preventDefault();
    var $target;
    if ( typeof $( this ).attr('href') !== 'undefined' ) {
      $target = $( $(this).attr('href') );
    } else  if ( typeof $( this ).attr('id') !== 'undefined' ) {
      $target = $('[href=#'+$( this ).attr('id')+']');
    }
    if ( typeof $target !== 'undefined' ) {
      if ( $target.hasClass('has-attention') ) {
        $target.removeClass('has-attention');
      } else {
        $target.addClass('has-attention');
      }
    }
  });

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'CSVSink',
  extends: 'foam.dao.AbstractSink',
  implements: [ 'foam.core.Serializable' ],

  documentation: 'Sink runs the csv outputter, and contains the resulting string in this.csv',

  javaImports: [
    'foam.core.PropertyInfo',
    'java.util.List'
  ],

  properties: [
    {
      class: 'String',
      name: 'csv',
      view: 'foam.u2.tag.TextArea'
    },
    {
      class: 'Class',
      name: 'of',
      visibility: 'HIDDEN'
    },
    {
      class: 'FObjectArray',
      of: 'foam.core.PropertyInfo',
      name: 'props',
      getter: function(of) {
        if ( !! this.props ) return this.props;
        if ( this.axioms.length == 0 ) {
          return of ? of.getAxiomsByClass(foam.core.Property)
          .filter( (p) => ! p.networkTransient ) : [];
        }
        return this.axioms.map((tableCol) => {
          return of.getAxiomByName(tableCol);
        });
      },
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isHeadersOutput',
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isNewLine',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'StringArray',
      name: 'axioms',
      getter: function(of) {
        if ( !! this.axioms ) return this.axioms;
        return of ? of.getAxiomByName('tableColumns').columns : [];
      }
    }
  ],

  methods: [
    {
      name: 'output',
      args: [
        { name: 'value' }
      ],
      code: function(value) {
        console.log('in output @csvSink - js');
        console.log(`this.CSV ${this.csv} - js`);
        if ( ! this.isNewLine ) this.csv += ',';
        this.isNewLine = false;
        this.output_(value);
      },
      javaCode: `
      System.out.println("in output @csvSink");
      System.out.println("in output @csvSink csv = " + getCsv());
        StringBuilder sb = new StringBuilder();
        if ( ! getIsNewLine() ) {
          sb.append(getCsv());
          sb.append(",");
          setCsv(sb.toString());
        }
        setIsNewLine(false);
        output_(value);
      `
    },
    {
      name: 'output_',
      args: [
        { type: 'Any', name: 'value' }
      ],
      code:
        foam.mmethod(
          {
            String: function(value) {
              this.csv += `"${value.replace(/\"/g, '""')}"`;
            },
            Number: function(value) {
              this.csv += value.toString();
            },
            Boolean: function(value) {
              this.csv += value.toString();
            },
            Date: function(value) {
              this.output_(value.toDateString());
            },
            FObject: function(value) {
              this.output_(foam.json.Pretty.stringify(value));
            },
            Array: function(value) {
              this.output_(foam.json.Pretty.stringify(value));
            },
            Undefined: function(value) {},
            Null: function(value) {}
          }, function(value) {
            this.output_(value.toString());
        }),
      javaCode: `
        System.out.println("in output_ @csvSink");
        StringBuilder sb = new StringBuilder();
        String s = value.toString();
        if (s.indexOf("\\"") != -1) {
          sb.append("\\"");
          sb.append(s);
          sb.append("\\"");
        }
        else {
          sb.append(s);
        }
        setCsv(sb.toString());
      `
    },
    {
      name: 'newLine_',
      code: function() {
        this.csv += '\n';
        this.isNewLine = true;
      },
      javaCode: `
      System.out.println("in newLine_ @csvSink");
        StringBuilder sb = new StringBuilder();
        sb.append(getCsv());
        sb.append("\\n");
        setCsv(sb.toString());
        sb.setLength(0);
        setIsNewLine(true);
      `
    },
    {
      name: 'put',
      code: function(obj) {
        console.log('in the put of the CSvsink - js');
        if ( ! this.of ) this.of = obj.cls_;

        if ( ! this.isHeadersOutput ) {
          this.props.forEach((element) => {
            element.toCSVLabel(this, element);
          });
          this.newLine_();
          this.isHeadersOutput = true;
        }

        this.props.forEach((element) => {
          element.toCSV(obj, this, element);
        });
        this.newLine_();
      },
      javaCode: `
        System.out.println("in the put of the CSvsink");
        if ( ! isPropertySet("of") ) setOf(((foam.core.FObject)obj).getClassInfo());
        PropertyInfo[] columns = getProps();
        if ( ! getIsHeadersOutput() ) {
          for (PropertyInfo element : columns) {
            // element.toCSVLabel(this, element);
          }
          newLine_();
          setIsHeadersOutput(true);
        }

        for (PropertyInfo element : columns) {
          // element.toCSV(obj, this, element);
        }
        newLine_();
      `
    },
    {
      name: 'reset',
      code: function() {
        ['csv', 'isNewLine', 'isHeadersOutput']
          .forEach( (s) => this.clearProperty(s) );
      },
      javaCode: `
      System.out.println("in reset of the CSvsink");
        clearCsv();
        clearIsNewLine();
        clearIsHeadersOutput();
      `
    }
  ]
});

foam.CLASS({
  package: 'foam.dao',
  name: 'PropertyCSVRefinement',

  documentation: `Refinement on Properties to handle toCSV() and toCSVLabel().`,

  refines: 'foam.core.Property',

  properties: [
    {
      name: 'toCSV',
      class: 'Function',
      value: function(obj, outputter, prop) {
        outputter.output(obj ? obj[prop.name] : null);
      }
    },
    {
      name: 'toCSVLabel',
      class: 'Function',
      value: function(outputter, prop) {
        outputter.output(prop.name);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.dao',
  name: 'FObjectPropertyCSVRefinement',

  documentation: `Refinement on FObjects to override toCSV() and toCSVLabel().
  Purpose is to output a dot annotated format, to handle the nested properties on the FObject.`,

  refines: 'foam.core.FObjectProperty',

  properties: [
    {
      name: 'toCSV',
      class: 'Function',
      value: function(obj, outputter, prop) {
        if ( ! prop.of ) {
          outputter.output(obj ? obj[prop.name] : null);
          return;
        }
        prop.of.getAxiomsByClass(foam.core.Property)
          .forEach((axiom) => {
            axiom.toCSV(obj ? obj[prop.name] : null, outputter, axiom);
          });
      }
    },
    {
      name: 'toCSVLabel',
      class: 'Function',
      value: function(outputter, prop) {
        if ( ! prop.of ) {
          outputter.output(prop.name);
          return;
        }
        // mini decorator
        var prefixedOutputter = {
          output: function(value) {
            outputter.output(prop.name + '.' + value);
          }
        };
        prop.of.getAxiomsByClass(foam.core.Property)
          .forEach((axiom) => {
            axiom.toCSVLabel(prefixedOutputter, axiom);
          });
      }
    }
  ]
});
<commit_msg>change prop type csvSink.props<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'CSVSink',
  extends: 'foam.dao.AbstractSink',
  implements: [ 'foam.core.Serializable' ],

  documentation: 'Sink runs the csv outputter, and contains the resulting string in this.csv',

  javaImports: [
    'foam.core.PropertyInfo',
    'java.util.List'
  ],

  properties: [
    {
      class: 'String',
      name: 'csv',
      view: 'foam.u2.tag.TextArea'
    },
    {
      class: 'Class',
      name: 'of',
      visibility: 'HIDDEN'
    },
    {
      class: 'Array',
      javaType: 'foam.core.PropertyInfo[]',
      name: 'props',
      getter: function(of) {
        if ( !! this.props ) return this.props;
        if ( this.axioms.length == 0 ) {
          return of ? of.getAxiomsByClass(foam.core.Property)
          .filter( (p) => ! p.networkTransient ) : [];
        }
        return this.axioms.map((tableCol) => {
          return of.getAxiomByName(tableCol);
        });
      },
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isHeadersOutput',
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isNewLine',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'StringArray',
      name: 'axioms',
      getter: function(of) {
        if ( !! this.axioms ) return this.axioms;
        return of ? of.getAxiomByName('tableColumns').columns : [];
      }
    }
  ],

  methods: [
    {
      name: 'output',
      args: [
        { name: 'value' }
      ],
      code: function(value) {
        console.log('in output @csvSink - js');
        console.log(`this.CSV ${this.csv} - js`);
        if ( ! this.isNewLine ) this.csv += ',';
        this.isNewLine = false;
        this.output_(value);
      },
      javaCode: `
      System.out.println("in output @csvSink");
      System.out.println("in output @csvSink csv = " + getCsv());
        StringBuilder sb = new StringBuilder();
        if ( ! getIsNewLine() ) {
          sb.append(getCsv());
          sb.append(",");
          setCsv(sb.toString());
        }
        setIsNewLine(false);
        output_(value);
      `
    },
    {
      name: 'output_',
      args: [
        { type: 'Any', name: 'value' }
      ],
      code:
        foam.mmethod(
          {
            String: function(value) {
              this.csv += `"${value.replace(/\"/g, '""')}"`;
            },
            Number: function(value) {
              this.csv += value.toString();
            },
            Boolean: function(value) {
              this.csv += value.toString();
            },
            Date: function(value) {
              this.output_(value.toDateString());
            },
            FObject: function(value) {
              this.output_(foam.json.Pretty.stringify(value));
            },
            Array: function(value) {
              this.output_(foam.json.Pretty.stringify(value));
            },
            Undefined: function(value) {},
            Null: function(value) {}
          }, function(value) {
            this.output_(value.toString());
        }),
      javaCode: `
        System.out.println("in output_ @csvSink");
        StringBuilder sb = new StringBuilder();
        String s = value.toString();
        if (s.indexOf("\\"") != -1) {
          sb.append("\\"");
          sb.append(s);
          sb.append("\\"");
        }
        else {
          sb.append(s);
        }
        setCsv(sb.toString());
      `
    },
    {
      name: 'newLine_',
      code: function() {
        this.csv += '\n';
        this.isNewLine = true;
      },
      javaCode: `
      System.out.println("in newLine_ @csvSink");
        StringBuilder sb = new StringBuilder();
        sb.append(getCsv());
        sb.append("\\n");
        setCsv(sb.toString());
        sb.setLength(0);
        setIsNewLine(true);
      `
    },
    {
      name: 'put',
      code: function(obj) {
        console.log('in the put of the CSvsink - js');
        if ( ! this.of ) this.of = obj.cls_;

        if ( ! this.isHeadersOutput ) {
          this.props.forEach((element) => {
            element.toCSVLabel(this, element);
          });
          this.newLine_();
          this.isHeadersOutput = true;
        }

        this.props.forEach((element) => {
          element.toCSV(obj, this, element);
        });
        this.newLine_();
      },
      javaCode: `
        System.out.println("in the put of the CSvsink");
        if ( ! isPropertySet("of") ) setOf(((foam.core.FObject)obj).getClassInfo());
        PropertyInfo[] columns = getProps();
        if ( ! getIsHeadersOutput() ) {
          for (PropertyInfo element : columns) {
            // element.toCSVLabel(this, element);
          }
          newLine_();
          setIsHeadersOutput(true);
        }

        for (PropertyInfo element : columns) {
          // element.toCSV(obj, this, element);
        }
        newLine_();
      `
    },
    {
      name: 'reset',
      code: function() {
        ['csv', 'isNewLine', 'isHeadersOutput']
          .forEach( (s) => this.clearProperty(s) );
      },
      javaCode: `
      System.out.println("in reset of the CSvsink");
        clearCsv();
        clearIsNewLine();
        clearIsHeadersOutput();
      `
    }
  ]
});

foam.CLASS({
  package: 'foam.dao',
  name: 'PropertyCSVRefinement',

  documentation: `Refinement on Properties to handle toCSV() and toCSVLabel().`,

  refines: 'foam.core.Property',

  properties: [
    {
      name: 'toCSV',
      class: 'Function',
      value: function(obj, outputter, prop) {
        outputter.output(obj ? obj[prop.name] : null);
      }
    },
    {
      name: 'toCSVLabel',
      class: 'Function',
      value: function(outputter, prop) {
        outputter.output(prop.name);
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.dao',
  name: 'FObjectPropertyCSVRefinement',

  documentation: `Refinement on FObjects to override toCSV() and toCSVLabel().
  Purpose is to output a dot annotated format, to handle the nested properties on the FObject.`,

  refines: 'foam.core.FObjectProperty',

  properties: [
    {
      name: 'toCSV',
      class: 'Function',
      value: function(obj, outputter, prop) {
        if ( ! prop.of ) {
          outputter.output(obj ? obj[prop.name] : null);
          return;
        }
        prop.of.getAxiomsByClass(foam.core.Property)
          .forEach((axiom) => {
            axiom.toCSV(obj ? obj[prop.name] : null, outputter, axiom);
          });
      }
    },
    {
      name: 'toCSVLabel',
      class: 'Function',
      value: function(outputter, prop) {
        if ( ! prop.of ) {
          outputter.output(prop.name);
          return;
        }
        // mini decorator
        var prefixedOutputter = {
          output: function(value) {
            outputter.output(prop.name + '.' + value);
          }
        };
        prop.of.getAxiomsByClass(foam.core.Property)
          .forEach((axiom) => {
            axiom.toCSVLabel(prefixedOutputter, axiom);
          });
      }
    }
  ]
});
<|endoftext|>


<commit_before>window.fbAsyncInit = function() {
    FB.init({
        appId      : '1109487575831651',
        xfbml      : true,
        version    : 'v2.6'
    });
};

(function(d, s, id){
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

function checkLoginState() {
    FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
    });
}

function statusChangeCallback(response) {
    console.log('statusChangeCallback');
    console.log(response);
    // The response object is returned with a status field that lets the
    // app know the current login status of the person.
    // Full docs on the response object can be found in the documentation
    // for FB.getLoginStatus().
    if (response.status === 'connected') {
        // Logged into your app and Facebook.
        testAPI();
    } else if (response.status === 'not_authorized') {
        // The person is logged into Facebook, but not your app.
        document.getElementById('status').innerHTML = 'Please log ' +
            'into this app.';
    } else {
        // The person is not logged into Facebook, so we're not sure if
        // they are logged into this app or not.
        document.getElementById('status').innerHTML = 'Please log ' +
            'into Facebook.';
    }
}

function checkLoginState() {
    FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
    });
}
<commit_msg>Add test API for fb button<commit_after>window.fbAsyncInit = function() {
    FB.init({
        appId      : '1109487575831651',
        xfbml      : true,
        version    : 'v2.6'
    });
};

(function(d, s, id){
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.id = id;
    js.src = "//connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

function checkLoginState() {
    FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
    });
}

function statusChangeCallback(response) {
    console.log('statusChangeCallback');
    console.log(response);
    // The response object is returned with a status field that lets the
    // app know the current login status of the person.
    // Full docs on the response object can be found in the documentation
    // for FB.getLoginStatus().
    if (response.status === 'connected') {
        // Logged into your app and Facebook.
        testAPI();
    } else if (response.status === 'not_authorized') {
        // The person is logged into Facebook, but not your app.
        document.getElementById('status').innerHTML = 'Please log ' +
            'into this app.';
    } else {
        // The person is not logged into Facebook, so we're not sure if
        // they are logged into this app or not.
        document.getElementById('status').innerHTML = 'Please log ' +
            'into Facebook.';
    }
}

function testAPI() {
    console.log('Welcome!  Fetching your information.... ');
    FB.api('/me', function(response) {
        console.log('Successful login for: ' + response.name);
        document.getElementById('status').innerHTML =
            'Thanks for logging in, ' + response.name + '!';
    });
}

function checkLoginState() {
    FB.getLoginStatus(function(response) {
        statusChangeCallback(response);
        console.log(response);
    });
}

<|endoftext|>


<commit_before>function dealmd(path) {
    debugger;
    $.get(path, function(data) {
        var html_content = markdown.toHTML(data);
        $(".markdown-body").html(html_content);
        //html自动编号
        var h1Index = 0;
        $("h1,h2,h3,h4").each(function(i, val) {
        	if("H1" == val.tagName){
        		h1Index += 1;
		        var h2Index = 0;
        		$(val).prepend(h1Index+".");
        	}

        	if("H2" == val.tagName){
        		h2Index += 1;
		        var h3Index = 0;
        		$(val).prepend(h1Index+"." + h2Index + ".");
        	}

        	if("H3" == val.tagName){
        		h3Index += 1;
		        var h4Index = 0;
        		$(val).prepend(h1Index+"." + h2Index + "." + h3Index + ".");
        	}
        });
    });
}

$("#js").on("click", function(event) {
    var value = event.target.text;
    var path = "./frontend/js/" + value + ".md";
    dealmd(path);
});
<commit_msg>Update current.js<commit_after>function dealmd(path) {
    debugger;
    $.get(path, function(data) {
        var html_content = markdown.toHTML(data);
        $(".markdown-body").html(html_content);
        //html自动编号
        var h1Index = 0;
        var h2Index = 0;
        var h3Index = 0;
        var h4Index = 0;
        $("h1,h2,h3,h4").each(function(i, val) {
        	if("H1" == val.tagName){
        		h1Index += 1;
		        h2Index = 0;
        		$(val).prepend(h1Index+".");
        	}

        	if("H2" == val.tagName){
        		h2Index += 1;
		        h3Index = 0;
        		$(val).prepend(h1Index+"." + h2Index + ".");
        	}

        	if("H3" == val.tagName){
        		h3Index += 1;
		        h4Index = 0;
        		$(val).prepend(h1Index+"." + h2Index + "." + h3Index + ".");
        	}
        });
    });
}

$("#js").on("click", function(event) {
    var value = event.target.text;
    var path = "./frontend/js/" + value + ".md";
    dealmd(path);
});
<|endoftext|>


<commit_before>'use strict'

/**
 * Dependencies
 * @ignore
 */
const moment = require('moment')

/**
 * Module Dependencies
 * @ignore
 */
const Events = require('../../events')
const Manager = require('../../common/Manager')
const Mail = require('./Mail')

/**
 * Mail Type Constants
 */
const PRIVATE_MESSAGE = 'PRIVATE_MESSAGE'
const mail_types = {
  PRIVATE_MESSAGE,
}

/**
 * Query Constants
 */
const MAX_MAIL = 10

/**
 * Mail Manager
 * @class
 */
class MailManager extends Manager {

  /**
   * constructor
   */
  constructor (system, user) {
    super(system)
    this.user = user
  }

  static get type () {
    return Mail
  }

  static get unsafeFields () {
    return []
  }

  privateMessage (data) {
    let { message, sender: sender_id } = data
    let { user: { id: user_id, socket } } = this

    if (!sender_id) {
      sender_id = 'SYSTEM'
    }

    let body = {
      user_id,
      delivered: false,
      timestamp: moment().valueOf(),
      type: PRIVATE_MESSAGE,
      data: { message, sender_id }
    }

    if (socket) {
      socket.emit('message', {
        timestamp: moment(),
        type: 'MAIL',
        data: body
      })
      body.delivered = true
    }

    return this.store({ body })
      .then(response => {
        let { _id: id } = response
        body.id = id
        return new Mail(this, body)
      })
      .catch(error => Promise.reject(error))
  }

  getMessages (data) {
    let { user: { id: user_id } } = this
    let { page=0 } = data

    return this.search({
      query: {
        match: { user_id }
      },
      sort: [
        { delivered: { order: 'asc' } },
        { timestamp: { order: 'desc' } },
        '_score'
      ],
      from: page * MAX_MAIL,
      size: MAX_MAIL,
      safe: true
    })
  }
}

/**
 * Export
 * @ignore
 */
module.exports = MailManager
<commit_msg>feat(MailManager): generalize mailing function<commit_after>'use strict'

/**
 * Dependencies
 * @ignore
 */
const moment = require('moment')

/**
 * Module Dependencies
 * @ignore
 */
const Events = require('../../events')
const Manager = require('../../common/Manager')
const Mail = require('./Mail')

/**
 * Mail Type Constants
 */
const PRIVATE_MESSAGE = 'PRIVATE_MESSAGE'
const mail_types = {
  PRIVATE_MESSAGE,
}

/**
 * Query Constants
 */
const MAX_MAIL = 10

/**
 * Mail Manager
 * @class
 */
class MailManager extends Manager {

  /**
   * constructor
   */
  constructor (system, user) {
    super(system)
    this.user = user
  }

  static get type () {
    return Mail
  }

  static get unsafeFields () {
    return []
  }

  mail (body) {
    let { user: { id: user_id }, socket } = this
    let mail_body = { timestamp: moment(), type: 'MAIL', data: body }

    if (socket) {
      socket.emit('message', mail_body)
      body.delivered = true
    } else {
      body.delivered = false
    }

    return this.store({ body })
      .then(response => {
        let { _id: id } = response
        body.id = id
        return new Mail(this, body)
      })
      .catch(error => Promise.reject(error))
  }

  privateMessage (data) {
    let { message, sender: sender_id } = data
    let { user: { id: user_id, socket } } = this

    if (!sender_id) {
      sender_id = 'SYSTEM'
    }

    let body = {
      user_id,
      timestamp: moment(),
      type: PRIVATE_MESSAGE,
      data: { message, sender_id }
    }

    return this.mail(body)
  }

  getUnread (data) {
    let { user: { id: user_id } } = this
    let { page=0 } = data

    return this.search({
      query: {
        bool: {
          must: [
            { match: { user_id } }
            { match: { delivered: false } }
          ]
        }
      },
      sort: [
        { timestamp: { order: 'desc' } },
        '_score'
      ]
      from: page * MAX_MAIL,
      size: MAX_MAIL,
      safe: true
    })
  }

  getMessages (data) {
    let { user: { id: user_id } } = this
    let { page=0 } = data

    return this.search({
      query: {
        match: { user_id }
      },
      sort: [
        { delivered: { order: 'asc' } },
        { timestamp: { order: 'desc' } },
        '_score'
      ],
      from: page * MAX_MAIL,
      size: MAX_MAIL,
      safe: true
    })
  }
}

/**
 * Export
 * @ignore
 */
module.exports = MailManager
<|endoftext|>


<commit_before>import React from "react";
import Button from "@material-ui/core/Button";
import classNames from "classnames";
import Tooltip from "@material-ui/core/Tooltip";
import TextField from "@material-ui/core/TextField";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import { withStyles } from "@material-ui/core/styles";

import colors from "libs/colors";
import { ReactComponent as ExportButton } from "libs/icons/export_to_terra.svg";

const styles = {
  dialogButtonBase: {
    boxShadow: "unset",
    color: colors.green[0],
    fontSize: 16,
    margin: "0 25px 26px 0",
    padding: "10px 20px 8px 20px"
  },
  dialogButtonCancel: {
    // Add an invisible border so the button doesn't move when we click it
    border: "1px solid white",
    "&:hover": {
      backgroundColor: "#e9edf1",
      border: "1px solid #babdc0",
      borderRadius: 3
    },
    "&:active": {
      backgroundColor: "#e9edf1",
      border: "1px solid #babdc0",
      borderRadius: 3
    }
  },
  dialogButtonSend: {
    backgroundColor: colors.green[1],
    border: "1px solid #5c8b35",
    borderRadius: 3,
    color: "white",
    "&:hover": {
      backgroundColor: "#7cb24e",
      border: "1px solid #638e3e"
    },
    "&:active": {
      backgroundColor: "#63953a",
      border: "1px solid #638e3e"
    }
  },
  dialogButtonSendDisabled: {
    backgroundColor: "#e9edf1",
    border: "1px solid #babdc0",
    color: "#babdc0"
  },
  dialogDesc: {
    color: colors.gray[0],
    fontSize: 14
  },
  dialogInputInput: {
    color: colors.gray[0],
    fontSize: 14,
    padding: "10px 12px 6px 12px"
  },
  dialogInputRoot: {
    margin: "22px 0 30px 0",
    "&:hover $dialogInputNotchedOutline": {
      borderColor: "#ced0da !important"
    },
    "&$dialogInputCssFocused $dialogInputNotchedOutline": {
      borderColor: colors.green[1] + " !important"
    }
  },
  dialogInputCssFocused: {},
  dialogInputNotchedOutline: {
    borderColor: "#dfe3e9 !important",
    borderWidth: "1px !important"
  },
  dialogTitle: {
    color: colors.gray[0],
    fontSize: 18,
    fontWeight: 600
  },
  exportFab: {
    bottom: 45,
    position: "fixed",
    right: 35
  },
  exportButton: {
    filter: "drop-shadow( 0 2px 2px rgba(0,0,0,0.63))",
    height: 89,
    width: 81,
    "&:hover :first-child": {
      cursor: "pointer",
      fill: "#7cb24e"
    },
    "&:active :first-child": {
      fill: "#63953a"
    }
  }
};

class ExportFab extends React.Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
    this.handleClick = this.handleClick.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleCancel = this.handleCancel.bind(this);
    this.setTextValue = this.setTextValue.bind(this);
  }

  render() {
    const { classes } = this.props;

    var filter = this.props.filter;
    var defaultTextValue = "";
    if (typeof filter === "undefined" || filter.length == "") {
      defaultTextValue = "all participants";
      // Set state so Send button is not disabled
      this.state.cohortName = defaultTextValue;
    }
    return (

        {/*
          Style div instead of button itself, to prevent button from moving to
          the right when cohort dialog is shown. See
          https://github.com/mui-org/material-ui/issues/9275#issuecomment-350479467
        */}

          <Tooltip title="Save in Terra">
            <ExportButton
              className={classes.exportButton}
              onClick={() => this.handleClick()}
            />
          </Tooltip>

          <Dialog
            className={classes.dialogRoot}
            open={this.state.open}
            onClose={this.handleClose}
          >
            <DialogTitle className={classes.dialogTitle} disableTypography>
              Save in Terra
            </DialogTitle>
            <DialogContent>

                A cohort with this name will be created in Terra

              <TextField
                autoFocus
                defaultValue={defaultTextValue}
                fullWidth
                id="name"
                InputProps={{
                  classes: {
                    root: classes.dialogInputRoot,
                    focused: classes.dialogInputCssFocused,
                    input: classes.dialogInputInput,
                    notchedOutline: classes.dialogInputNotchedOutline
                  }
                }}
                onChange={this.setTextValue}
                onKeyPress={ev => {
                  if (ev.key === "Enter") {
                    this.handleSave();
                  }
                }}
                placeholder="cohort name"
                type="text"
                variant="outlined"
              />
            </DialogContent>
            <DialogActions>
              <Button
                className={classNames(
                  classes.dialogButtonBase,
                  classes.dialogButtonCancel
                )}
                onClick={this.handleCancel}
                color="primary"
              >
                Cancel
              </Button>
              <Button
                classes={{
                  root: classNames(
                    classes.dialogButtonBase,
                    classes.dialogButtonSend
                  ),
                  disabled: classNames(
                    classes.dialogButtonBase,
                    classes.dialogButtonSendDisabled
                  )
                }}
                disabled={
                  !("cohortName" in this.state) || this.state.cohortName == ""
                }
                variant="contained"
                id="save"
                onClick={this.handleSave}
              >
                Send
              </Button>
            </DialogActions>
          </Dialog>

    );
  }

  setTextValue(event) {
    this.setState({ cohortName: event.target.value });
  }

  handleClick() {
    this.setState(state => ({ open: true }));
  }

  handleCancel() {
    this.setState(state => ({ open: false }));
  }

  handleSave() {
    this.setState(state => ({ open: false }));
    let exportUrlCallback = function(error, data) {
      if (error) {
        alert(error.response.body.detail);
      } else {
        let importUrl =
          "https://app.terra.bio/#import-data?format=entitiesJson";
        if (data.authorization_domain) {
          importUrl += "&ad=" + data.authorization_domain;
        }
        importUrl += "&url=" + data.url;
        window.location.assign(importUrl);
      }
    }.bind(this);
    let cohortName = this.state.cohortName;
    let filter = this.props.filter;
    if (filter == null) {
      filter = [];
    }
    if (cohortName == null) {
      cohortName = "all participants";
    }
    let params = new Object();
    params.cohortName = cohortName;
    params.filter = filter;
    this.props.exportUrlApi.exportUrlPost(
      { exportUrlRequest: params },
      exportUrlCallback
    );
  }
}

export default withStyles(styles)(ExportFab);
<commit_msg>Change Send button to Save (#317)<commit_after>import React from "react";
import Button from "@material-ui/core/Button";
import classNames from "classnames";
import Tooltip from "@material-ui/core/Tooltip";
import TextField from "@material-ui/core/TextField";
import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import { withStyles } from "@material-ui/core/styles";

import colors from "libs/colors";
import { ReactComponent as ExportButton } from "libs/icons/export_to_terra.svg";

const styles = {
  dialogButtonBase: {
    boxShadow: "unset",
    color: colors.green[0],
    fontSize: 16,
    margin: "0 25px 26px 0",
    padding: "10px 20px 8px 20px"
  },
  dialogButtonCancel: {
    // Add an invisible border so the button doesn't move when we click it
    border: "1px solid white",
    "&:hover": {
      backgroundColor: "#e9edf1",
      border: "1px solid #babdc0",
      borderRadius: 3
    },
    "&:active": {
      backgroundColor: "#e9edf1",
      border: "1px solid #babdc0",
      borderRadius: 3
    }
  },
  dialogButtonSave: {
    backgroundColor: colors.green[1],
    border: "1px solid #5c8b35",
    borderRadius: 3,
    color: "white",
    "&:hover": {
      backgroundColor: "#7cb24e",
      border: "1px solid #638e3e"
    },
    "&:active": {
      backgroundColor: "#63953a",
      border: "1px solid #638e3e"
    }
  },
  dialogButtonSaveDisabled: {
    backgroundColor: "#e9edf1",
    border: "1px solid #babdc0",
    color: "#babdc0"
  },
  dialogDesc: {
    color: colors.gray[0],
    fontSize: 14
  },
  dialogInputInput: {
    color: colors.gray[0],
    fontSize: 14,
    padding: "10px 12px 6px 12px"
  },
  dialogInputRoot: {
    margin: "22px 0 30px 0",
    "&:hover $dialogInputNotchedOutline": {
      borderColor: "#ced0da !important"
    },
    "&$dialogInputCssFocused $dialogInputNotchedOutline": {
      borderColor: colors.green[1] + " !important"
    }
  },
  dialogInputCssFocused: {},
  dialogInputNotchedOutline: {
    borderColor: "#dfe3e9 !important",
    borderWidth: "1px !important"
  },
  dialogTitle: {
    color: colors.gray[0],
    fontSize: 18,
    fontWeight: 600
  },
  exportFab: {
    bottom: 45,
    position: "fixed",
    right: 35
  },
  exportButton: {
    filter: "drop-shadow( 0 2px 2px rgba(0,0,0,0.63))",
    height: 89,
    width: 81,
    "&:hover :first-child": {
      cursor: "pointer",
      fill: "#7cb24e"
    },
    "&:active :first-child": {
      fill: "#63953a"
    }
  }
};

class ExportFab extends React.Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
    this.handleClick = this.handleClick.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleCancel = this.handleCancel.bind(this);
    this.setTextValue = this.setTextValue.bind(this);
  }

  render() {
    const { classes } = this.props;

    var filter = this.props.filter;
    var defaultTextValue = "";
    if (typeof filter === "undefined" || filter.length == "") {
      defaultTextValue = "all participants";
      // Set state so Save button is not disabled
      this.state.cohortName = defaultTextValue;
    }
    return (

        {/*
          Style div instead of button itself, to prevent button from moving to
          the right when cohort dialog is shown. See
          https://github.com/mui-org/material-ui/issues/9275#issuecomment-350479467
        */}

          <Tooltip title="Save in Terra">
            <ExportButton
              className={classes.exportButton}
              onClick={() => this.handleClick()}
            />
          </Tooltip>

          <Dialog
            className={classes.dialogRoot}
            open={this.state.open}
            onClose={this.handleClose}
          >
            <DialogTitle className={classes.dialogTitle} disableTypography>
              Save in Terra
            </DialogTitle>
            <DialogContent>

                A cohort with this name will be created in Terra

              <TextField
                autoFocus
                defaultValue={defaultTextValue}
                fullWidth
                id="name"
                InputProps={{
                  classes: {
                    root: classes.dialogInputRoot,
                    focused: classes.dialogInputCssFocused,
                    input: classes.dialogInputInput,
                    notchedOutline: classes.dialogInputNotchedOutline
                  }
                }}
                onChange={this.setTextValue}
                onKeyPress={ev => {
                  if (ev.key === "Enter") {
                    this.handleSave();
                  }
                }}
                placeholder="cohort name"
                type="text"
                variant="outlined"
              />
            </DialogContent>
            <DialogActions>
              <Button
                className={classNames(
                  classes.dialogButtonBase,
                  classes.dialogButtonCancel
                )}
                onClick={this.handleCancel}
                color="primary"
              >
                Cancel
              </Button>
              <Button
                classes={{
                  root: classNames(
                    classes.dialogButtonBase,
                    classes.dialogButtonSave
                  ),
                  disabled: classNames(
                    classes.dialogButtonBase,
                    classes.dialogButtonSaveDisabled
                  )
                }}
                disabled={
                  !("cohortName" in this.state) || this.state.cohortName == ""
                }
                variant="contained"
                id="save"
                onClick={this.handleSave}
              >
                Save
              </Button>
            </DialogActions>
          </Dialog>

    );
  }

  setTextValue(event) {
    this.setState({ cohortName: event.target.value });
  }

  handleClick() {
    this.setState(state => ({ open: true }));
  }

  handleCancel() {
    this.setState(state => ({ open: false }));
  }

  handleSave() {
    this.setState(state => ({ open: false }));
    let exportUrlCallback = function(error, data) {
      if (error) {
        alert(error.response.body.detail);
      } else {
        let importUrl =
          "https://app.terra.bio/#import-data?format=entitiesJson";
        if (data.authorization_domain) {
          importUrl += "&ad=" + data.authorization_domain;
        }
        importUrl += "&url=" + data.url;
        window.location.assign(importUrl);
      }
    }.bind(this);
    let cohortName = this.state.cohortName;
    let filter = this.props.filter;
    if (filter == null) {
      filter = [];
    }
    if (cohortName == null) {
      cohortName = "all participants";
    }
    let params = new Object();
    params.cohortName = cohortName;
    params.filter = filter;
    this.props.exportUrlApi.exportUrlPost(
      { exportUrlRequest: params },
      exportUrlCallback
    );
  }
}

export default withStyles(styles)(ExportFab);
<|endoftext|>


<commit_before>import { withSeriesType } from 'react-jsx-highcharts';
export {
  Chart,
  Credits,
  Debug,
  Loading,
  Legend,
  Series,
  Subtitle,
  Title,
  Tooltip,
  useHighcharts,
  useChart,
  useAxis,
  useSeries,
  useModifiedProps,
  withHighcharts as withHighmaps,
  withSeriesType
} from 'react-jsx-highcharts';

// Charts
export { default as HighchartsMapChart } from './components/HighchartsMapChart';

// Graph Parts
export { default as MapNavigation } from './components/MapNavigation';
export { default as XAxis } from './components/XAxis';
export { default as YAxis } from './components/YAxis';

// Series
const parentAxisId = { axisId: 'yAxis' };
export const MapBubbleSeries = withSeriesType('MapBubble', parentAxisId);
export const MapLineSeries = withSeriesType('MapLine', parentAxisId);
export const MapPointSeries = withSeriesType('MapPoint', parentAxisId);
export const MapSeries = withSeriesType('Map', parentAxisId);
<commit_msg>Export ColorAxis for highmaps<commit_after>import { withSeriesType } from 'react-jsx-highcharts';
export {
  Chart,
  ColorAxis,
  Credits,
  Debug,
  Loading,
  Legend,
  Series,
  Subtitle,
  Title,
  Tooltip,
  useHighcharts,
  useChart,
  useAxis,
  useSeries,
  useModifiedProps,
  withHighcharts as withHighmaps,
  withSeriesType
} from 'react-jsx-highcharts';

// Charts
export { default as HighchartsMapChart } from './components/HighchartsMapChart';

// Graph Parts
export { default as MapNavigation } from './components/MapNavigation';
export { default as XAxis } from './components/XAxis';
export { default as YAxis } from './components/YAxis';

// Series
const parentAxisId = { axisId: 'yAxis' };
export const MapBubbleSeries = withSeriesType('MapBubble', parentAxisId);
export const MapLineSeries = withSeriesType('MapLine', parentAxisId);
export const MapPointSeries = withSeriesType('MapPoint', parentAxisId);
export const MapSeries = withSeriesType('Map', parentAxisId);
<|endoftext|>