<commit_before>// TODO rename to file driver
// TODO support ttyrec (via opts.format == 'ttyrec')

import Stream from '../stream';

function asciicast(src, { feed, now, setTimeout, onFinish }, { idleTimeLimit, startAt }) {
  let cols;
  let rows;
  let frames;
  let duration;
  let effectiveStartAt;
  let timeoutId;
  let nextFrameIndex = 0;
  let elapsedVirtualTime = 0;
  let startTime;
  let pauseElapsedTime;

  async function load() {
    if (frames) return;

    const asciicast = parseAsciicast(await doFetch(src));
    cols = asciicast.cols;
    rows = asciicast.rows;
    idleTimeLimit = idleTimeLimit ?? asciicast.idleTimeLimit
    const result = prepareFrames(asciicast.frames, idleTimeLimit, startAt);
    frames = result.frames;
    effectiveStartAt = result.effectiveStartAt;
    duration = frames[frames.length - 1][0];
  }

  async function doFetch({ url, data, fetchOpts = {} }) {
    if (url !== undefined) {
      const response = await fetch(url, fetchOpts);

      if (!response.ok) {
        throw `failed fetching asciicast file: ${response.statusText} (${response.status})`;
      }

      return await response.text();
    } else if (data !== undefined) {
      if (typeof data === 'function') {
        data = data();
      }

      return await data;
    } else {
      throw 'failed fetching asciicast file: url/data missing in src';
    }
  }

  function scheduleNextFrame() {
    const nextFrame = frames[nextFrameIndex];

    if (nextFrame) {
      const t = nextFrame[0] * 1000;
      const elapsedWallTime = now() - startTime;
      let timeout = t - elapsedWallTime;

      if (timeout < 0) {
        timeout = 0;
      }

      timeoutId = setTimeout(runFrame, timeout);
    } else {
      timeoutId = null;
      pauseElapsedTime = duration * 1000;
      onFinish();
    }
  }

  function runFrame() {
    let frame = frames[nextFrameIndex];
    let elapsedWallTime;

    do {
      feed(frame[1]);
      elapsedVirtualTime = frame[0] * 1000;
      frame = frames[++nextFrameIndex];
      elapsedWallTime = now() - startTime;
    } while (frame && (elapsedWallTime > frame[0] * 1000));

    scheduleNextFrame();
  }

  function pause() {
    clearTimeout(timeoutId);
    timeoutId = null;
    pauseElapsedTime = now() - startTime;
  }

  function resume() {
    startTime = now() - pauseElapsedTime;
    pauseElapsedTime = null;
    scheduleNextFrame();
  }

  function seek(where) {
    const isPlaying = !!timeoutId;

    if (isPlaying) {
      pause();
    }

    if (typeof where === 'string') {
      const currentTime = (pauseElapsedTime ?? 0) / 1000;

      if (where === '<<') {
        where = currentTime - 5;
      } else if (where === '>>') {
        where = currentTime + 5;
      } else if (where === '<<<') {
        where = currentTime - (0.1 * duration);
      } else if (where === '>>>') {
        where = currentTime + (0.1 * duration);
      } else if (where[where.length - 1] === '%') {
        where = (parseFloat(where.substring(0, where.length - 1)) / 100) * duration;
      }
    }

    const targetTime = Math.min(Math.max(where, 0), duration) * 1000;

    if (targetTime < elapsedVirtualTime) {
      feed('\x1bc'); // reset terminal
      nextFrameIndex = 0;
      elapsedVirtualTime = 0;
    }

    let frame = frames[nextFrameIndex];

    while (frame && (frame[0] * 1000 < targetTime)) {
      feed(frame[1]);
      elapsedVirtualTime = frame[0] * 1000;
      frame = frames[++nextFrameIndex];
    }

    pauseElapsedTime = targetTime;

    if (isPlaying) {
      resume();
    }
  }

  function getPoster(time) {
    const posterTime = time * 1000;
    const poster = [];
    let nextFrameIndex = 0;
    let frame = frames[0];

    while (frame && (frame[0] * 1000 < posterTime)) {
      poster.push(frame[1]);
      frame = frames[++nextFrameIndex];
    }

    return poster;
  }

  return {
    init: async () => {
      await load();

      return { cols, rows, duration };
    },

    start: async () => {
      seek(effectiveStartAt);
      resume();
    },

    stop: () => {
      clearTimeout(timeoutId);
    },

    pauseOrResume: () => {
      if (timeoutId) {
        pause();
        return false;
      } else {
        resume();
        return true;
      }
    },

    seek: where => {
      return seek(where);
    },

    getPoster: t => {
      return getPoster(t);
    },

    getCurrentTime: () => {
      if (timeoutId) {
        return (now() - startTime) / 1000;
      } else {
        return (pauseElapsedTime ?? 0) / 1000;
      }
    }
  }
}

function parseAsciicast(json) {
  try {
    return parseAsciicastV2(json);
  } catch (_error) {
    // not a v2 format - let's try parsing as v1
    return parseAsciicastV1(json);
  }
}

function parseAsciicastV1(json) {
  const asciicast = JSON.parse(json);
  let time = 0;

  const frames = new Stream(asciicast.stdout).map(e => {
    time += e[0];
    return [time, e[1]];
  });

  return {
    cols: asciicast.width,
    rows: asciicast.height,
    frames: frames
  }
}

function parseAsciicastV2(jsonl) {
  const lines = jsonl.split('\n');
  const header = JSON.parse(lines[0]);

  if (header.version !== 2) {
    throw 'not asciicast v2 format';
  }

  const frames = new Stream(lines)
    .drop(1)
    .filter(l => l[0] === '[')
    .map(l => JSON.parse(l))
    .filter(e => e[1] === 'o')
    .map(e => [e[0], e[2]]);

  return {
    cols: header.width,
    rows: header.height,
    idleTimeLimit: header.idle_time_limit,
    frames: frames
  }
}

function batchFrames(frames) {
  const maxFrameTime = 1.0 / 60;
  let prevFrame;

  return frames.transform(emit => {
    let ic = 0;
    let oc = 0;

    return {
      step: frame => {
        ic++;

        if (prevFrame === undefined) {
          prevFrame = frame;
          return;
        }

        if (frame[0] - prevFrame[0] < maxFrameTime) {
          prevFrame[1] += frame[1];
        } else {
          emit(prevFrame);
          prevFrame = frame;
          oc++;
        }
      },

      flush: () => {
        if (prevFrame !== undefined) {
          emit(prevFrame);
          oc++;
        }

        console.debug(`batched ${ic} frames to ${oc} frames`);
      }
    }
  });
}

function prepareFrames(frames, idleTimeLimit = Infinity, startAt = 0) {
  let prevT = 0;
  let shift = 0;
  let effectiveStartAt = startAt;

  const fs = Array.from(batchFrames(frames).map(e => {
    const delay = e[0] - prevT;
    const delta = delay - idleTimeLimit;
    prevT = e[0];

    if (delta > 0) {
      shift += delta;

      if (e[0] < startAt) {
        effectiveStartAt -= delta;
      }
    }

    return [e[0] - shift, e[1]];
  }));

  return {
    frames: fs,
    effectiveStartAt: effectiveStartAt
  }
}

export { asciicast };
<commit_msg>Support passing array (asciicast v2) and object (asciicast v1) as src.data<commit_after>// TODO rename to file driver
// TODO support ttyrec (via opts.format == 'ttyrec')

import Stream from '../stream';

function asciicast(src, { feed, now, setTimeout, onFinish }, { idleTimeLimit, startAt }) {
  let cols;
  let rows;
  let frames;
  let duration;
  let effectiveStartAt;
  let timeoutId;
  let nextFrameIndex = 0;
  let elapsedVirtualTime = 0;
  let startTime;
  let pauseElapsedTime;

  async function load() {
    if (frames) return;

    const asciicast = loadAsciicast(await doFetch(src));
    cols = asciicast.cols;
    rows = asciicast.rows;
    idleTimeLimit = idleTimeLimit ?? asciicast.idleTimeLimit
    const result = prepareFrames(asciicast.frames, idleTimeLimit, startAt);
    frames = result.frames;

    if (frames.length === 0) {
      throw 'asciicast is missing events';
    }

    effectiveStartAt = result.effectiveStartAt;
    duration = frames[frames.length - 1][0];
  }

  async function doFetch({ url, data, fetchOpts = {} }) {
    if (url !== undefined) {
      const response = await fetch(url, fetchOpts);

      if (!response.ok) {
        throw `failed fetching asciicast file: ${response.statusText} (${response.status})`;
      }

      return await response.text();
    } else if (data !== undefined) {
      if (typeof data === 'function') {
        data = data();
      }

      return await data;
    } else {
      throw 'failed fetching asciicast file: url/data missing in src';
    }
  }

  function scheduleNextFrame() {
    const nextFrame = frames[nextFrameIndex];

    if (nextFrame) {
      const t = nextFrame[0] * 1000;
      const elapsedWallTime = now() - startTime;
      let timeout = t - elapsedWallTime;

      if (timeout < 0) {
        timeout = 0;
      }

      timeoutId = setTimeout(runFrame, timeout);
    } else {
      timeoutId = null;
      pauseElapsedTime = duration * 1000;
      onFinish();
    }
  }

  function runFrame() {
    let frame = frames[nextFrameIndex];
    let elapsedWallTime;

    do {
      feed(frame[1]);
      elapsedVirtualTime = frame[0] * 1000;
      frame = frames[++nextFrameIndex];
      elapsedWallTime = now() - startTime;
    } while (frame && (elapsedWallTime > frame[0] * 1000));

    scheduleNextFrame();
  }

  function pause() {
    clearTimeout(timeoutId);
    timeoutId = null;
    pauseElapsedTime = now() - startTime;
  }

  function resume() {
    startTime = now() - pauseElapsedTime;
    pauseElapsedTime = null;
    scheduleNextFrame();
  }

  function seek(where) {
    const isPlaying = !!timeoutId;

    if (isPlaying) {
      pause();
    }

    if (typeof where === 'string') {
      const currentTime = (pauseElapsedTime ?? 0) / 1000;

      if (where === '<<') {
        where = currentTime - 5;
      } else if (where === '>>') {
        where = currentTime + 5;
      } else if (where === '<<<') {
        where = currentTime - (0.1 * duration);
      } else if (where === '>>>') {
        where = currentTime + (0.1 * duration);
      } else if (where[where.length - 1] === '%') {
        where = (parseFloat(where.substring(0, where.length - 1)) / 100) * duration;
      }
    }

    const targetTime = Math.min(Math.max(where, 0), duration) * 1000;

    if (targetTime < elapsedVirtualTime) {
      feed('\x1bc'); // reset terminal
      nextFrameIndex = 0;
      elapsedVirtualTime = 0;
    }

    let frame = frames[nextFrameIndex];

    while (frame && (frame[0] * 1000 < targetTime)) {
      feed(frame[1]);
      elapsedVirtualTime = frame[0] * 1000;
      frame = frames[++nextFrameIndex];
    }

    pauseElapsedTime = targetTime;

    if (isPlaying) {
      resume();
    }
  }

  function getPoster(time) {
    const posterTime = time * 1000;
    const poster = [];
    let nextFrameIndex = 0;
    let frame = frames[0];

    while (frame && (frame[0] * 1000 < posterTime)) {
      poster.push(frame[1]);
      frame = frames[++nextFrameIndex];
    }

    return poster;
  }

  return {
    init: async () => {
      await load();

      return { cols, rows, duration };
    },

    start: async () => {
      seek(effectiveStartAt);
      resume();
    },

    stop: () => {
      clearTimeout(timeoutId);
    },

    pauseOrResume: () => {
      if (timeoutId) {
        pause();
        return false;
      } else {
        resume();
        return true;
      }
    },

    seek: where => {
      return seek(where);
    },

    getPoster: t => {
      return getPoster(t);
    },

    getCurrentTime: () => {
      if (timeoutId) {
        return (now() - startTime) / 1000;
      } else {
        return (pauseElapsedTime ?? 0) / 1000;
      }
    }
  }
}

function loadAsciicast(data) {
  let header;
  let events = new Stream([]);

  if (typeof data === 'string') {
    const result = parseJsonl(data);;

    if (result !== undefined) {
      header = result.header;
      events = result.events;
    } else {
      header = JSON.parse(data);
    }
  } else if (typeof data === 'object' && typeof data.version === 'number') {
    header = data;
  } else if (Array.isArray(data)) {
    header = data[0];
    events = (new Stream(data)).drop(1);
  } else {
    throw 'invalid data';
  }

  if (header.version === 1) {
    return buildAsciicastV1(header);
  } else if (header.version === 2) {
    return buildAsciicastV2(header, events);
  } else {
    throw `asciicast v${header.version} format not supported`;
  }
}

function parseJsonl(jsonl) {
  const lines = jsonl.split('\n');
  let header;

  try {
    header = JSON.parse(lines[0]);
  } catch (_error) {
    return;
  }

  const events = new Stream(lines)
    .drop(1)
    .filter(l => l[0] === '[')
    .map(l => JSON.parse(l));

  return { header, events };
}

function buildAsciicastV1(data) {
  let time = 0;

  const frames = new Stream(data.stdout).map(e => {
    time += e[0];
    return [time, e[1]];
  });

  return {
    cols: data.width,
    rows: data.height,
    frames: frames
  }
}

function buildAsciicastV2(header, events) {
  const frames = events
    .filter(e => e[1] === 'o')
    .map(e => [e[0], e[2]]);

  return {
    cols: header.width,
    rows: header.height,
    idleTimeLimit: header.idle_time_limit,
    frames: frames
  }
}

function batchFrames(frames) {
  const maxFrameTime = 1.0 / 60;
  let prevFrame;

  return frames.transform(emit => {
    let ic = 0;
    let oc = 0;

    return {
      step: frame => {
        ic++;

        if (prevFrame === undefined) {
          prevFrame = frame;
          return;
        }

        if (frame[0] - prevFrame[0] < maxFrameTime) {
          prevFrame[1] += frame[1];
        } else {
          emit(prevFrame);
          prevFrame = frame;
          oc++;
        }
      },

      flush: () => {
        if (prevFrame !== undefined) {
          emit(prevFrame);
          oc++;
        }

        console.debug(`batched ${ic} frames to ${oc} frames`);
      }
    }
  });
}

function prepareFrames(frames, idleTimeLimit = Infinity, startAt = 0) {
  let prevT = 0;
  let shift = 0;
  let effectiveStartAt = startAt;

  const fs = Array.from(batchFrames(frames).map(e => {
    const delay = e[0] - prevT;
    const delta = delay - idleTimeLimit;
    prevT = e[0];

    if (delta > 0) {
      shift += delta;

      if (e[0] < startAt) {
        effectiveStartAt -= delta;
      }
    }

    return [e[0] - shift, e[1]];
  }));

  return {
    frames: fs,
    effectiveStartAt: effectiveStartAt
  }
}

export { asciicast };
<|endoftext|>


<commit_before>'use strict';

const BaseEmbed = require('./BaseEmbed.js');

/**
 * Generates news embeds
 */
class NewsEmbed extends BaseEmbed {
  /**
   * @param {Genesis} bot - An instance of Genesis
   * @param {Array.<News>} news - The news to be included in the embed
   * @param {string} type - [Optional] type of embed between news, updates,
   *                        or prime access. Not provided for news.
   */
  constructor(bot, news, type) {
    super();

    news.sort((a, b) => {
      const date1 = new Date(a.endDate || a.date);
      const date2 = new Date(b.endDate || b.date);

      return date2.getTime() - date1.getTime();
    });

    this.color = news.length > 0 ? 0x779ecb : 0xff6961;
    let value = news.map(n => n.asString).join('\n');
    if (type) {
      if (type === 'update') {
        value = value.length > 0 ? value : 'No Update News Currently';
      } else {
        value = value.length > 0 ? value : 'No Prime Access Currently';
      }
    } else {
      value = value.length > 0 ? value : 'No News Currently';
    }
    this.fields = [{ name: '_ _', value }];
  }
}

module.exports = NewsEmbed;
<commit_msg>add image link to news embed<commit_after>'use strict';

const BaseEmbed = require('./BaseEmbed.js');

/**
 * Generates news embeds
 */
class NewsEmbed extends BaseEmbed {
  /**
   * @param {Genesis} bot - An instance of Genesis
   * @param {Array.<News>} news - The news to be included in the embed
   * @param {string} type - [Optional] type of embed between news, updates,
   *                        or prime access. Not provided for news.
   */
  constructor(bot, news, type) {
    super();

    news.sort((a, b) => {
      const date1 = new Date(a.endDate || a.date);
      const date2 = new Date(b.endDate || b.date);

      return date2.getTime() - date1.getTime();
    });

    this.color = news.length > 0 ? 0x779ecb : 0xff6961;
    let value = news.map(n => n.asString).join('\n');
    if (type) {
      if (type === 'update') {
        value = value.length > 0 ? value : 'No Update News Currently';
      } else {
        value = value.length > 0 ? value : 'No Prime Access Currently';
      }
    } else {
      value = value.length > 0 ? value : 'No News Currently';
    }
    this.fields = [{ name: '_ _', value }];
    this.image = { url: news[0] ? news[0].imageLink : ''};
  }
}

module.exports = NewsEmbed;
<|endoftext|>


<commit_before>var Timer = require('../util/timer');
var Thread = require('./thread');
var execute = require('./execute.js');

function Sequencer (runtime) {
    /**
     * A utility timer for timing thread sequencing.
     * @type {!Timer}
     */
    this.timer = new Timer();

    /**
     * Reference to the runtime owning this sequencer.
     * @type {!Runtime}
     */
    this.runtime = runtime;
}

/**
 * The sequencer does as much work as it can within WORK_TIME milliseconds,
 * then yields. This is essentially a rate-limiter for blocks.
 * In Scratch 2.0, this is set to 75% of the target stage frame-rate (30fps).
 * @const {!number}
 */
Sequencer.WORK_TIME = 10;

/**
 * Step through all threads in `this.threads`, running them in order.
 * @param {Array.<Thread>} threads List of which threads to step.
 * @return {Array.<Thread>} All threads which have finished in this iteration.
 */
Sequencer.prototype.stepThreads = function (threads) {
    // Start counting toward WORK_TIME
    this.timer.start();
    // List of threads which have been killed by this step.
    var inactiveThreads = [];
    // If all of the threads are yielding, we should yield.
    var numYieldingThreads = 0;
    // Clear all yield statuses that were for the previous frame.
    for (var t = 0; t < threads.length; t++) {
        if (threads[t].status === Thread.STATUS_YIELD_FRAME) {
            threads[t].setStatus(Thread.STATUS_RUNNING);
        }
    }

    // While there are still threads to run and we are within WORK_TIME,
    // continue executing threads.
    while (threads.length > 0 &&
           threads.length > numYieldingThreads &&
           this.timer.timeElapsed() < Sequencer.WORK_TIME) {
        // New threads at the end of the iteration.
        var newThreads = [];
        // Reset yielding thread count.
        numYieldingThreads = 0;
        // Attempt to run each thread one time
        for (var i = 0; i < threads.length; i++) {
            var activeThread = threads[i];
            if (activeThread.status === Thread.STATUS_RUNNING) {
                // Normal-mode thread: step.
                this.startThread(activeThread);
            } else if (activeThread.status === Thread.STATUS_YIELD ||
                       activeThread.status === Thread.STATUS_YIELD_FRAME) {
                // Yielding thread: do nothing for this step.
                numYieldingThreads++;
            }
            if (activeThread.stack.length === 0 &&
                activeThread.status === Thread.STATUS_DONE) {
                // Finished with this thread - tell runtime to clean it up.
                inactiveThreads.push(activeThread);
            } else {
                // Keep this thead in the loop.
                newThreads.push(activeThread);
            }
        }
        // Effectively filters out threads that have stopped.
        threads = newThreads;
    }
    return inactiveThreads;
};

/**
 * Step the requested thread
 * @param {!Thread} thread Thread object to step
 */
Sequencer.prototype.startThread = function (thread) {
    var currentBlockId = thread.peekStack();
    if (!currentBlockId) {
        // A "null block" - empty branch.
        // Yield for the frame.
        thread.popStack();
        thread.setStatus(Thread.STATUS_YIELD_FRAME);
        return;
    }
    // Execute the current block
    execute(this, thread);
    // If the block executed without yielding and without doing control flow,
    // move to done.
    if (thread.status === Thread.STATUS_RUNNING &&
        thread.peekStack() === currentBlockId) {
        this.proceedThread(thread);
    }
};

/**
 * Step a thread into a block's branch.
 * @param {!Thread} thread Thread object to step to branch.
 * @param {Number} branchNum Which branch to step to (i.e., 1, 2).
 */
Sequencer.prototype.stepToBranch = function (thread, branchNum) {
    if (!branchNum) {
        branchNum = 1;
    }
    var currentBlockId = thread.peekStack();
    var branchId = thread.target.blocks.getBranch(
        currentBlockId,
        branchNum
    );
    if (branchId) {
        // Push branch ID to the thread's stack.
        thread.pushStack(branchId);
    } else {
        // Push null, so we come back to the current block.
        thread.pushStack(null);
    }
};

/**
 * Step a procedure.
 * @param {!Thread} thread Thread object to step to procedure.
 * @param {!string} procedureName Name of procedure defined in this target.
 */
Sequencer.prototype.stepToProcedure = function (thread, procedureName) {
    var definition = thread.target.blocks.getProcedureDefinition(procedureName);
    thread.pushStack(definition);
};

/**
 * Step a thread into an input reporter, and manage its status appropriately.
 * @param {!Thread} thread Thread object to step to reporter.
 * @param {!string} blockId ID of reporter block.
 * @param {!string} inputName Name of input on parent block.
 * @return {boolean} True if yielded, false if it finished immediately.
 */
Sequencer.prototype.stepToReporter = function (thread, blockId, inputName) {
    var currentStackFrame = thread.peekStackFrame();
    // Push to the stack to evaluate the reporter block.
    thread.pushStack(blockId);
    // Save name of input for `Thread.pushReportedValue`.
    currentStackFrame.waitingReporter = inputName;
    // Actually execute the block.
    this.startThread(thread);
    // If a reporter yielded, caller must wait for it to unyield.
    // The value will be populated once the reporter unyields,
    // and passed up to the currentStackFrame on next execution.
    return thread.status === Thread.STATUS_YIELD;
};

/**
 * Finish stepping a thread and proceed it to the next block.
 * @param {!Thread} thread Thread object to proceed.
 */
Sequencer.prototype.proceedThread = function (thread) {
    var currentBlockId = thread.peekStack();
    // Mark the status as done and proceed to the next block.
    // Pop from the stack - finished this level of execution.
    thread.popStack();
    // Push next connected block, if there is one.
    var nextBlockId = thread.target.blocks.getNextBlock(currentBlockId);
    if (nextBlockId) {
        thread.pushStack(nextBlockId);
    }
    // If we can't find a next block to run, mark the thread as done.
    if (!thread.peekStack()) {
        thread.setStatus(Thread.STATUS_DONE);
    }
};

/**
 * Retire a thread in the middle, without considering further blocks.
 * @param {!Thread} thread Thread object to retire.
 */
Sequencer.prototype.retireThread = function (thread) {
    thread.stack = [];
    thread.stackFrame = [];
    thread.requestScriptGlowInFrame = false;
    thread.setStatus(Thread.STATUS_DONE);
};

module.exports = Sequencer;
<commit_msg>Return Procedure Stack Frame<commit_after>var Timer = require('../util/timer');
var Thread = require('./thread');
var execute = require('./execute.js');

function Sequencer (runtime) {
    /**
     * A utility timer for timing thread sequencing.
     * @type {!Timer}
     */
    this.timer = new Timer();

    /**
     * Reference to the runtime owning this sequencer.
     * @type {!Runtime}
     */
    this.runtime = runtime;
}

/**
 * The sequencer does as much work as it can within WORK_TIME milliseconds,
 * then yields. This is essentially a rate-limiter for blocks.
 * In Scratch 2.0, this is set to 75% of the target stage frame-rate (30fps).
 * @const {!number}
 */
Sequencer.WORK_TIME = 10;

/**
 * Step through all threads in `this.threads`, running them in order.
 * @param {Array.<Thread>} threads List of which threads to step.
 * @return {Array.<Thread>} All threads which have finished in this iteration.
 */
Sequencer.prototype.stepThreads = function (threads) {
    // Start counting toward WORK_TIME
    this.timer.start();
    // List of threads which have been killed by this step.
    var inactiveThreads = [];
    // If all of the threads are yielding, we should yield.
    var numYieldingThreads = 0;
    // Clear all yield statuses that were for the previous frame.
    for (var t = 0; t < threads.length; t++) {
        if (threads[t].status === Thread.STATUS_YIELD_FRAME) {
            threads[t].setStatus(Thread.STATUS_RUNNING);
        }
    }

    // While there are still threads to run and we are within WORK_TIME,
    // continue executing threads.
    while (threads.length > 0 &&
           threads.length > numYieldingThreads &&
           this.timer.timeElapsed() < Sequencer.WORK_TIME) {
        // New threads at the end of the iteration.
        var newThreads = [];
        // Reset yielding thread count.
        numYieldingThreads = 0;
        // Attempt to run each thread one time
        for (var i = 0; i < threads.length; i++) {
            var activeThread = threads[i];
            if (activeThread.status === Thread.STATUS_RUNNING) {
                // Normal-mode thread: step.
                this.startThread(activeThread);
            } else if (activeThread.status === Thread.STATUS_YIELD ||
                       activeThread.status === Thread.STATUS_YIELD_FRAME) {
                // Yielding thread: do nothing for this step.
                numYieldingThreads++;
            }
            if (activeThread.stack.length === 0 &&
                activeThread.status === Thread.STATUS_DONE) {
                // Finished with this thread - tell runtime to clean it up.
                inactiveThreads.push(activeThread);
            } else {
                // Keep this thead in the loop.
                newThreads.push(activeThread);
            }
        }
        // Effectively filters out threads that have stopped.
        threads = newThreads;
    }
    return inactiveThreads;
};

/**
 * Step the requested thread
 * @param {!Thread} thread Thread object to step
 */
Sequencer.prototype.startThread = function (thread) {
    var currentBlockId = thread.peekStack();
    if (!currentBlockId) {
        // A "null block" - empty branch.
        // Yield for the frame.
        thread.popStack();
        thread.setStatus(Thread.STATUS_YIELD_FRAME);
        return;
    }
    // Execute the current block
    execute(this, thread);
    // If the block executed without yielding and without doing control flow,
    // move to done.
    if (thread.status === Thread.STATUS_RUNNING &&
        thread.peekStack() === currentBlockId) {
        this.proceedThread(thread);
    }
};

/**
 * Step a thread into a block's branch.
 * @param {!Thread} thread Thread object to step to branch.
 * @param {Number} branchNum Which branch to step to (i.e., 1, 2).
 */
Sequencer.prototype.stepToBranch = function (thread, branchNum) {
    if (!branchNum) {
        branchNum = 1;
    }
    var currentBlockId = thread.peekStack();
    var branchId = thread.target.blocks.getBranch(
        currentBlockId,
        branchNum
    );
    if (branchId) {
        // Push branch ID to the thread's stack.
        thread.pushStack(branchId);
    } else {
        // Push null, so we come back to the current block.
        thread.pushStack(null);
    }
};

/**
 * Step a procedure.
 * @param {!Thread} thread Thread object to step to procedure.
 * @param {!string} procedureName Name of procedure defined in this target.
 */
Sequencer.prototype.stepToProcedure = function (thread, procedureName) {
    var definition = thread.target.blocks.getProcedureDefinition(procedureName);
    return thread.pushStack(definition);
};

/**
 * Step a thread into an input reporter, and manage its status appropriately.
 * @param {!Thread} thread Thread object to step to reporter.
 * @param {!string} blockId ID of reporter block.
 * @param {!string} inputName Name of input on parent block.
 * @return {boolean} True if yielded, false if it finished immediately.
 */
Sequencer.prototype.stepToReporter = function (thread, blockId, inputName) {
    var currentStackFrame = thread.peekStackFrame();
    // Push to the stack to evaluate the reporter block.
    thread.pushStack(blockId);
    // Save name of input for `Thread.pushReportedValue`.
    currentStackFrame.waitingReporter = inputName;
    // Actually execute the block.
    this.startThread(thread);
    // If a reporter yielded, caller must wait for it to unyield.
    // The value will be populated once the reporter unyields,
    // and passed up to the currentStackFrame on next execution.
    return thread.status === Thread.STATUS_YIELD;
};

/**
 * Finish stepping a thread and proceed it to the next block.
 * @param {!Thread} thread Thread object to proceed.
 */
Sequencer.prototype.proceedThread = function (thread) {
    var currentBlockId = thread.peekStack();
    // Mark the status as done and proceed to the next block.
    // Pop from the stack - finished this level of execution.
    thread.popStack();
    // Push next connected block, if there is one.
    var nextBlockId = thread.target.blocks.getNextBlock(currentBlockId);
    if (nextBlockId) {
        thread.pushStack(nextBlockId);
    }
    // If we can't find a next block to run, mark the thread as done.
    if (!thread.peekStack()) {
        thread.setStatus(Thread.STATUS_DONE);
    }
};

/**
 * Retire a thread in the middle, without considering further blocks.
 * @param {!Thread} thread Thread object to retire.
 */
Sequencer.prototype.retireThread = function (thread) {
    thread.stack = [];
    thread.stackFrame = [];
    thread.requestScriptGlowInFrame = false;
    thread.setStatus(Thread.STATUS_DONE);
};

module.exports = Sequencer;
<|endoftext|>


<commit_before>function EveLensflare()
{
    this.name = '';
    this.display = true;
    this.update = true;
    this.doOcclusionQueries = true;
    this.cameraFactor = 20;
    this.position = vec3.create();
    this.flares = [];
    this.occluders = [];
    this.backgroundOccluders = [];
    this.occlusionIntensity = 1;
    this.backgroundOcclusionIntensity = 1;

    this.distanceToEdgeCurves = [];
    this.distanceToCenterCurves = [];
    this.radialAngleCurves = [];
    this.xDistanceToCenter = [];
    this.yDistanceToCenter = [];
    this.bindings = [];
    this.curveSets = [];

    this.mesh = null;

    this._directionVar = variableStore.RegisterVariable( "LensflareFxDirectionScale", quat4.create());
    this._occlusionVar = variableStore.RegisterVariable( "LensflareFxOccScale", quat4.create([1, 1, 0, 0]));
    this._direction = vec3.create();
    this._transform = mat4.create();

    if (!EveLensflare.backBuffer)
    {
        EveLensflare.backBuffer = new Tw2TextureRes();
        EveLensflare.backBuffer.width = 0;
        EveLensflare.backBuffer.height = 0;
        EveLensflare.backBuffer.hasMipMaps = false;
        EveLensflare.occluderLevels = [new Tw2RenderTarget(), new Tw2RenderTarget(), new Tw2RenderTarget(), new Tw2RenderTarget()];
        EveLensflare.occludedLevelIndex = 0;
    }
}

EveLensflare.prototype.MatrixArcFromForward = function(out, v)
{
	var norm = vec3.normalize(v, norm);
    mat4.identity(out);
	if (norm[2] < -0.99999)
	{
		return;
	}
	if (norm[2] > 0.99999)
	{
		out[5] = -1.0;
		out[10] = -1.0;
		return;
	}
	var h = (1 + norm[2]) / (norm[0] * norm[0] + norm[1] * norm[1]);
	out[0] = h * norm[1] * norm[1] - norm[2];
	out[1] = -h * norm[0] * norm[1];
	out[2] = norm[0];

	out[4] = out[1];
	out[5] = h * norm[0] * norm[0] - norm[2];
	out[6] = norm[1];

	out[8] = -norm[0];
	out[9] = -norm[1];
	out[10] = -norm[2];
};

EveLensflare.prototype.PrepareRender = function ()
{
    if (!this.display)
    {
        return;
    }
    var cameraPos = mat4.multiplyVec3(device.viewInv, vec3.create());
    if (vec3.length(this.position) == 0)
    {
        var curPos = vec3.negate(cameraPos, vec3.create());
        var distScale = vec3.length(curPos);
        if (distScale > 1.5)
        {
            distScale = 1 / Math.log(distScale);
        }
        else
        {
            distScale = 2.5;
        }
        vec3.normalize(curPos, this._direction);
    }
    else
    {
        var invPos = vec3.negate(this.position, vec3.create());
        vec3.normalize(invPos, this._direction);
    }
    var viewDir = mat4.multiplyVec4(device.viewInv, quat4.create([0, 0, 1, 0]));
    var cameraSpacePos = vec3.create();
    cameraSpacePos[0] = -this.cameraFactor * viewDir[0] + cameraPos[0];
    cameraSpacePos[1] = -this.cameraFactor * viewDir[1] + cameraPos[1];
    cameraSpacePos[2] = -this.cameraFactor * viewDir[2] + cameraPos[2];

    var negDirVec = vec3.negate(this._direction, vec3.create());
    this.MatrixArcFromForward(this._transform, negDirVec);
    this._transform[12] = cameraSpacePos[0];
    this._transform[13] = cameraSpacePos[1];
    this._transform[14] = cameraSpacePos[2];

    var scaleMat = mat4.scale(mat4.identity(mat4.create()), [this.occlusionIntensity, this.occlusionIntensity, 1]);
    //mat4.multiply(this._transform, scaleMat);
    this._directionVar.value[0] = this._direction[0];
    this._directionVar.value[1] = this._direction[1];
    this._directionVar.value[2] = this._direction[2];
    this._directionVar.value[3] = 1;

    var d = quat4.create([this._direction[0], this._direction[1], this._direction[2], 0]);
    mat4.multiplyVec4(device.view, d);
    mat4.multiplyVec4(device.projection, d);
    d[0] /= d[3];
    d[1] /= d[3];
    var distanceToEdge = 1 - Math.min(1 - Math.abs(d[0]), 1 - Math.abs(d[1]));
    var distanceToCenter = Math.sqrt(d[0] * d[0] + d[1] * d[1]);
    var radialAngle = Math.atan2(d[1], d[0]) + Math.PI;

    for (var i = 0; i < this.distanceToEdgeCurves.length; ++i) {
        this.distanceToEdgeCurves[i].UpdateValue(distanceToEdge);
    }
    for (i = 0; i < this.distanceToCenterCurves.length; ++i) {
        this.distanceToCenterCurves[i].UpdateValue(distanceToCenter);
    }
    for (i = 0; i < this.radialAngleCurves.length; ++i) {
        this.radialAngleCurves[i].UpdateValue(radialAngle);
    }
    for (i = 0; i < this.xDistanceToCenter.length; ++i) {
        this.xDistanceToCenter[i].UpdateValue(d[0] + 10);
    }
    for (i = 0; i < this.yDistanceToCenter.length; ++i) {
        this.yDistanceToCenter[i].UpdateValue(d[1] + 10);
    }
    for (i = 0; i < this.bindings.length; ++i) {
        this.bindings[i].CopyValue();
    }
    for (i = 0; i < this.flares.length; ++i)
    {
        this.flares[i].UpdateViewDependentData(this._transform);
    }

};

EveLensflare.prototype.UpdateOccluders = function ()
{
    if (!this.doOcclusionQueries)
    {
        return;
    }
    this.occlusionIntensity = 1;
    this.backgroundOcclusionIntensity = 1;

    if (!EveLensflare.occluderLevels[0].texture || EveLensflare.occluderLevels[0].width < this.occluders.length * 2)
    {
        for (var i = 0; i < EveLensflare.occluderLevels.length; ++i) {
            EveLensflare.occluderLevels[i].Create(this.occluders.length * 2, 1, false);
        }
    }
    for (var j = 0; j < this.flares.length; ++j)
    {
        if ('_backBuffer' in this.flares[j])
        {
            this.flares[j]._backBuffer.textureRes = EveLensflare.occluderLevels.texture;
        }
    }

    EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Set();
    device.SetStandardStates(device.RM_OPAQUE);
    device.gl.clearColor(0.0, 0.0, 0.0, 1.0);
    device.gl.clear(device.gl.COLOR_BUFFER_BIT);
    EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Unset();

    var samples = 1;
    if (device.antialiasing)
    {
        samples = device.msaaSamples;
        device.gl.sampleCoverage(1. / samples, false);
    }
    for (var i = 0; i < this.occluders.length; ++i)
    {
        device.SetRenderState(device.RS_COLORWRITEENABLE, 8);
        device.gl.colorMask(false, false, false, true);
        device.gl.clearColor(0.0, 0.0, 0.0, 0.0);
        device.gl.clear(device.gl.COLOR_BUFFER_BIT);

        if (device.antialiasing)
        {
            // Turn off antialiasing
            device.gl.enable(device.gl.SAMPLE_COVERAGE);
            device.gl.sampleCoverage(0.25, false);
        }
        this.occluders[i].UpdateValue(this._transform, i);
        if (device.antialiasing)
        {
            device.gl.disable(device.gl.SAMPLE_COVERAGE);
        }

        // Copy back buffer into a texture
        if (!EveLensflare.backBuffer.texture)
        {
            EveLensflare.backBuffer.Attach(device.gl.createTexture());
        }
        device.gl.bindTexture(device.gl.TEXTURE_2D, EveLensflare.backBuffer.texture);
        if (EveLensflare.backBuffer.width != device.viewportWidth || EveLensflare.backBuffer.height != device.viewportHeight)
        {
            device.gl.texImage2D(device.gl.TEXTURE_2D, 0, device.gl.RGBA, device.viewportWidth, device.viewportHeight, 0, device.gl.RGBA, device.gl.UNSIGNED_BYTE, null);
            device.gl.texParameteri(device.gl.TEXTURE_2D, device.gl.TEXTURE_MAG_FILTER, device.gl.LINEAR);
            device.gl.texParameteri(device.gl.TEXTURE_2D, device.gl.TEXTURE_MIN_FILTER, device.gl.LINEAR);
            EveLensflare.backBuffer.width = device.viewportWidth;
            EveLensflare.backBuffer.height = device.viewportHeight;
        }
        device.gl.copyTexImage2D(device.gl.TEXTURE_2D, 0, device.alphaBlendBackBuffer ? device.gl.RGBA : device.gl.RGB, 0, 0, EveLensflare.backBuffer.width, EveLensflare.backBuffer.height, 0);
        device.gl.bindTexture(device.gl.TEXTURE_2D, null);

        // Collect samples
        EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Set();
        this.occluders[i].CollectSamples(EveLensflare.backBuffer, i, EveLensflare.occluderLevels[0].width / 2, samples);
        EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Unset();
    }
    if (device.antialiasing)
    {
        device.gl.sampleCoverage(1, false);
    }

    EveLensflare.occluderLevels[(EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length].Set();
    var pixels = new Uint8Array(EveLensflare.occluderLevels[0].width * 4);
    device.gl.readPixels(0, 0, 2, 1, device.gl.RGBA, device.gl.UNSIGNED_BYTE, pixels);
    EveLensflare.occluderLevels[(EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length].Unset();

    this.occlusionIntensity = 1;
    for (i = 0; i < EveLensflare.occluderLevels[0].width * 2; i += 4) {
        this.occlusionIntensity *= pixels[i + 1] ? pixels[i] / pixels[i + 1] : 1;
    }

    this.backgroundOcclusionIntensity = this.occlusionIntensity;
    this._occlusionVar.value[0] = this.occlusionIntensity;
    this._occlusionVar.value[1] = this._occlusionVar.value[0];
    EveLensflare.occludedLevelIndex = (EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length;
};

EveLensflare.prototype.GetBatches = function (mode, accumulator, perObjectData)
{
    if (!this.display)
    {
        return;
    }
    var viewDir = mat4.multiplyVec4(device.viewInv, quat4.create([0, 0, 1, 0]));
    if (vec3.dot(viewDir, this._direction) < 0) {
        return;
    }

    for (var i = 0; i < this.flares.length; ++i)
    {
        this.flares[i].GetBatches(mode, accumulator, perObjectData);
    }
    if (this.mesh) {
        this.mesh.GetBatches(mode, accumulator, perObjectData);
    }
};
<commit_msg>Added basic docs EveLensFlare<commit_after>/**
 * EveLensFlare
 * @property {String} [name='']
 * @property {boolean} display
 * @property {boolean} update
 * @property {boolean} doOcclusionQueries
 * @property {number} cameraFactor
 * @property {vec3} position
 * @property {Array} flares
 * @property {Array.<EveOccluder>} occluders
 * @property {Array.<EveOccluder>} backgroundOccluders
 * @property {number} occlusionIntensity
 * @property {number} backgroundOcclusionIntensity
 * @property {Array} distanceToEdgeCurves
 * @property {Array} distanceToCenterCurves
 * @property {Array} radialAngleCurves
 * @property {Array} xDistanceToCenter
 * @property {Array} yDistanceToCenter
 * @property {Array} bindings
 * @property {Array.<Tw2CurveSet> curveSets
 * @property {null|Tw2Mesh} mesh
 * @property {quat4} _directionVar
 * @property {quat4} _occlusionVar
 * @property {vec3} _direction
 * @property {mat4} _transform
 * @constructor
 */
function EveLensflare()
{
    this.name = '';
    this.display = true;
    this.update = true;
    this.doOcclusionQueries = true;
    this.cameraFactor = 20;
    this.position = vec3.create();
    this.flares = [];
    this.occluders = [];
    this.backgroundOccluders = [];
    this.occlusionIntensity = 1;
    this.backgroundOcclusionIntensity = 1;

    this.distanceToEdgeCurves = [];
    this.distanceToCenterCurves = [];
    this.radialAngleCurves = [];
    this.xDistanceToCenter = [];
    this.yDistanceToCenter = [];
    this.bindings = [];
    this.curveSets = [];

    this.mesh = null;

    this._directionVar = variableStore.RegisterVariable("LensflareFxDirectionScale", quat4.create());
    this._occlusionVar = variableStore.RegisterVariable("LensflareFxOccScale", quat4.create([1, 1, 0, 0]));
    this._direction = vec3.create();
    this._transform = mat4.create();

    if (!EveLensflare.backBuffer)
    {
        EveLensflare.backBuffer = new Tw2TextureRes();
        EveLensflare.backBuffer.width = 0;
        EveLensflare.backBuffer.height = 0;
        EveLensflare.backBuffer.hasMipMaps = false;
        EveLensflare.occluderLevels = [new Tw2RenderTarget(), new Tw2RenderTarget(), new Tw2RenderTarget(), new Tw2RenderTarget()];
        EveLensflare.occludedLevelIndex = 0;
    }
}

/**
 * Internal helper function
 * @param out
 * @param v
 */
EveLensflare.prototype.MatrixArcFromForward = function(out, v)
{
    var norm = vec3.normalize(v, norm);
    mat4.identity(out);
    if (norm[2] < -0.99999)
    {
        return;
    }
    if (norm[2] > 0.99999)
    {
        out[5] = -1.0;
        out[10] = -1.0;
        return;
    }
    var h = (1 + norm[2]) / (norm[0] * norm[0] + norm[1] * norm[1]);
    out[0] = h * norm[1] * norm[1] - norm[2];
    out[1] = -h * norm[0] * norm[1];
    out[2] = norm[0];

    out[4] = out[1];
    out[5] = h * norm[0] * norm[0] - norm[2];
    out[6] = norm[1];

    out[8] = -norm[0];
    out[9] = -norm[1];
    out[10] = -norm[2];
};

/**
 * Prepares the lensflare for rendering
 */
EveLensflare.prototype.PrepareRender = function()
{
    if (!this.display)
    {
        return;
    }

    var cameraPos = mat4.multiplyVec3(device.viewInv, vec3.create());
    if (vec3.length(this.position) == 0)
    {
        var curPos = vec3.negate(cameraPos, vec3.create());
        var distScale = vec3.length(curPos);
        if (distScale > 1.5)
        {
            distScale = 1 / Math.log(distScale);
        }
        else
        {
            distScale = 2.5;
        }
        vec3.normalize(curPos, this._direction);
    }
    else
    {
        var invPos = vec3.negate(this.position, vec3.create());
        vec3.normalize(invPos, this._direction);
    }
    var viewDir = mat4.multiplyVec4(device.viewInv, quat4.create([0, 0, 1, 0]));
    var cameraSpacePos = vec3.create();
    cameraSpacePos[0] = -this.cameraFactor * viewDir[0] + cameraPos[0];
    cameraSpacePos[1] = -this.cameraFactor * viewDir[1] + cameraPos[1];
    cameraSpacePos[2] = -this.cameraFactor * viewDir[2] + cameraPos[2];

    var negDirVec = vec3.negate(this._direction, vec3.create());
    this.MatrixArcFromForward(this._transform, negDirVec);
    this._transform[12] = cameraSpacePos[0];
    this._transform[13] = cameraSpacePos[1];
    this._transform[14] = cameraSpacePos[2];

    var scaleMat = mat4.scale(mat4.identity(mat4.create()), [this.occlusionIntensity, this.occlusionIntensity, 1]);
    //mat4.multiply(this._transform, scaleMat);
    this._directionVar.value[0] = this._direction[0];
    this._directionVar.value[1] = this._direction[1];
    this._directionVar.value[2] = this._direction[2];
    this._directionVar.value[3] = 1;

    var d = quat4.create([this._direction[0], this._direction[1], this._direction[2], 0]);
    mat4.multiplyVec4(device.view, d);
    mat4.multiplyVec4(device.projection, d);
    d[0] /= d[3];
    d[1] /= d[3];
    var distanceToEdge = 1 - Math.min(1 - Math.abs(d[0]), 1 - Math.abs(d[1]));
    var distanceToCenter = Math.sqrt(d[0] * d[0] + d[1] * d[1]);
    var radialAngle = Math.atan2(d[1], d[0]) + Math.PI;

    for (var i = 0; i < this.distanceToEdgeCurves.length; ++i)
    {
        this.distanceToEdgeCurves[i].UpdateValue(distanceToEdge);
    }
    for (i = 0; i < this.distanceToCenterCurves.length; ++i)
    {
        this.distanceToCenterCurves[i].UpdateValue(distanceToCenter);
    }
    for (i = 0; i < this.radialAngleCurves.length; ++i)
    {
        this.radialAngleCurves[i].UpdateValue(radialAngle);
    }
    for (i = 0; i < this.xDistanceToCenter.length; ++i)
    {
        this.xDistanceToCenter[i].UpdateValue(d[0] + 10);
    }
    for (i = 0; i < this.yDistanceToCenter.length; ++i)
    {
        this.yDistanceToCenter[i].UpdateValue(d[1] + 10);
    }
    for (i = 0; i < this.bindings.length; ++i)
    {
        this.bindings[i].CopyValue();
    }
    for (i = 0; i < this.flares.length; ++i)
    {
        this.flares[i].UpdateViewDependentData(this._transform);
    }

};

/**
 * Updates Occluders
 */
EveLensflare.prototype.UpdateOccluders = function()
{
    if (!this.doOcclusionQueries)
    {
        return;
    }
    this.occlusionIntensity = 1;
    this.backgroundOcclusionIntensity = 1;

    if (!EveLensflare.occluderLevels[0].texture || EveLensflare.occluderLevels[0].width < this.occluders.length * 2)
    {
        for (var i = 0; i < EveLensflare.occluderLevels.length; ++i)
        {
            EveLensflare.occluderLevels[i].Create(this.occluders.length * 2, 1, false);
        }
    }
    for (var j = 0; j < this.flares.length; ++j)
    {
        if ('_backBuffer' in this.flares[j])
        {
            this.flares[j]._backBuffer.textureRes = EveLensflare.occluderLevels.texture;
        }
    }

    EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Set();
    device.SetStandardStates(device.RM_OPAQUE);
    device.gl.clearColor(0.0, 0.0, 0.0, 1.0);
    device.gl.clear(device.gl.COLOR_BUFFER_BIT);
    EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Unset();

    var samples = 1;
    if (device.antialiasing)
    {
        samples = device.msaaSamples;
        device.gl.sampleCoverage(1. / samples, false);
    }
    for (var i = 0; i < this.occluders.length; ++i)
    {
        device.SetRenderState(device.RS_COLORWRITEENABLE, 8);
        device.gl.colorMask(false, false, false, true);
        device.gl.clearColor(0.0, 0.0, 0.0, 0.0);
        device.gl.clear(device.gl.COLOR_BUFFER_BIT);

        if (device.antialiasing)
        {
            // Turn off antialiasing
            device.gl.enable(device.gl.SAMPLE_COVERAGE);
            device.gl.sampleCoverage(0.25, false);
        }
        this.occluders[i].UpdateValue(this._transform, i);
        if (device.antialiasing)
        {
            device.gl.disable(device.gl.SAMPLE_COVERAGE);
        }

        // Copy back buffer into a texture
        if (!EveLensflare.backBuffer.texture)
        {
            EveLensflare.backBuffer.Attach(device.gl.createTexture());
        }
        device.gl.bindTexture(device.gl.TEXTURE_2D, EveLensflare.backBuffer.texture);
        if (EveLensflare.backBuffer.width != device.viewportWidth || EveLensflare.backBuffer.height != device.viewportHeight)
        {
            device.gl.texImage2D(device.gl.TEXTURE_2D, 0, device.gl.RGBA, device.viewportWidth, device.viewportHeight, 0, device.gl.RGBA, device.gl.UNSIGNED_BYTE, null);
            device.gl.texParameteri(device.gl.TEXTURE_2D, device.gl.TEXTURE_MAG_FILTER, device.gl.LINEAR);
            device.gl.texParameteri(device.gl.TEXTURE_2D, device.gl.TEXTURE_MIN_FILTER, device.gl.LINEAR);
            EveLensflare.backBuffer.width = device.viewportWidth;
            EveLensflare.backBuffer.height = device.viewportHeight;
        }
        device.gl.copyTexImage2D(device.gl.TEXTURE_2D, 0, device.alphaBlendBackBuffer ? device.gl.RGBA : device.gl.RGB, 0, 0, EveLensflare.backBuffer.width, EveLensflare.backBuffer.height, 0);
        device.gl.bindTexture(device.gl.TEXTURE_2D, null);

        // Collect samples
        EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Set();
        this.occluders[i].CollectSamples(EveLensflare.backBuffer, i, EveLensflare.occluderLevels[0].width / 2, samples);
        EveLensflare.occluderLevels[EveLensflare.occludedLevelIndex].Unset();
    }
    if (device.antialiasing)
    {
        device.gl.sampleCoverage(1, false);
    }

    EveLensflare.occluderLevels[(EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length].Set();
    var pixels = new Uint8Array(EveLensflare.occluderLevels[0].width * 4);
    device.gl.readPixels(0, 0, 2, 1, device.gl.RGBA, device.gl.UNSIGNED_BYTE, pixels);
    EveLensflare.occluderLevels[(EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length].Unset();

    this.occlusionIntensity = 1;
    for (i = 0; i < EveLensflare.occluderLevels[0].width * 2; i += 4)
    {
        this.occlusionIntensity *= pixels[i + 1] ? pixels[i] / pixels[i + 1] : 1;
    }

    this.backgroundOcclusionIntensity = this.occlusionIntensity;
    this._occlusionVar.value[0] = this.occlusionIntensity;
    this._occlusionVar.value[1] = this._occlusionVar.value[0];
    EveLensflare.occludedLevelIndex = (EveLensflare.occludedLevelIndex + 1) % EveLensflare.occluderLevels.length;
};

/**
 * Gets render batches
 * @param {RenderMode} mode
 * @param {Tw2BatchAccumulator} accumulator
 * @param {Tw2PerObjectData} perObjectData
 */
EveLensflare.prototype.GetBatches = function(mode, accumulator, perObjectData)
{
    if (!this.display)
    {
        return;
    }
    var viewDir = mat4.multiplyVec4(device.viewInv, quat4.create([0, 0, 1, 0]));
    if (vec3.dot(viewDir, this._direction) < 0)
    {
        return;
    }

    for (var i = 0; i < this.flares.length; ++i)
    {
        this.flares[i].GetBatches(mode, accumulator, perObjectData);
    }
    if (this.mesh)
    {
        this.mesh.GetBatches(mode, accumulator, perObjectData);
    }
};
<|endoftext|>


<commit_before>const data = require("sdk/self").data;
const tabs = require("sdk/tabs");
const { ToggleButton } = require("sdk/ui/button/toggle");
var btn_config = {};
var btn;

function tabToggle(tab) {
  if (btn.state('window').checked) {
    tab.attach({
      contentScriptFile: data.url('embed.js')
    });
  } else {
    tab.attach({
      contentScript: [
        'var s = document.createElement("script");',
        's.setAttribute("src", "' + data.url('destroy.js') + '");',
        'document.body.appendChild(s);'
      ]
    });
  }
}

btn_config = {
  id: "hypothesis",
  label: "Annotate",
  icon: {
    "18": './images/sleeping_18.png',
    "32": './images/sleeping_32.png',
    "36": './images/sleeping_36.png',
    "64": './images/sleeping_64.png'
  },
  onClick: function(state) {
    tabToggle(tabs.activeTab)
  }
};

if (undefined === ToggleButton) {
  btn = require("sdk/widget").Widget(btn_config);
} else {
  btn = ToggleButton(btn_config);
}

tabs.on('ready', tabToggle);
<commit_msg>Pageshow beats aces over Ready any day<commit_after>const data = require("sdk/self").data;
const tabs = require("sdk/tabs");
const { ToggleButton } = require("sdk/ui/button/toggle");
var btn_config = {};
var btn;

function tabToggle(tab) {
  if (btn.state('window').checked) {
    tab.attach({
      contentScriptFile: data.url('embed.js')
    });
  } else {
    tab.attach({
      contentScript: [
        'var s = document.createElement("script");',
        's.setAttribute("src", "' + data.url('destroy.js') + '");',
        'document.body.appendChild(s);'
      ]
    });
  }
}

btn_config = {
  id: "hypothesis",
  label: "Annotate",
  icon: {
    "18": './images/sleeping_18.png',
    "32": './images/sleeping_32.png',
    "36": './images/sleeping_36.png',
    "64": './images/sleeping_64.png'
  },
  onClick: function(state) {
    tabToggle(tabs.activeTab)
  }
};

if (undefined === ToggleButton) {
  btn = require("sdk/widget").Widget(btn_config);
} else {
  btn = ToggleButton(btn_config);
}

tabs.on('pageshow', tabToggle);
<|endoftext|>


<commit_before>import L from 'leaflet';
import { getJSON } from '../util';

export var Photon = L.Class.extend({
  options: {
    serviceUrl: 'https://photon.komoot.de/api/',
    reverseUrl: 'https://photon.komoot.de/reverse/',
    nameProperties: ['name', 'street', 'suburb', 'hamlet', 'town', 'city', 'state', 'country']
  },

  initialize: function(options) {
    L.setOptions(this, options);
  },

  geocode: function(query, cb, context) {
    var params = L.extend(
      {
        q: query
      },
      this.options.geocodingQueryParams
    );

    getJSON(
      this.options.serviceUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  suggest: function(query, cb, context) {
    return this.geocode(query, cb, context);
  },

  reverse: function(latLng, scale, cb, context) {
    var params = L.extend(
      {
        lat: latLng.lat,
        lon: latLng.lng
      },
      this.options.reverseQueryParams
    );

    getJSON(
      this.options.reverseUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  _decodeFeatures: function(data) {
    var results = [],
      i,
      f,
      c,
      latLng,
      extent,
      bbox;

    if (data && data.features) {
      for (i = 0; i < data.features.length; i++) {
        f = data.features[i];
        c = f.geometry.coordinates;
        latLng = L.latLng(c[1], c[0]);
        extent = f.properties.extent;

        if (extent) {
          bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]);
        } else {
          bbox = L.latLngBounds(latLng, latLng);
        }

        results.push({
          name: this._decodeFeatureName(f),
          html: this.options.htmlTemplate ? this.options.htmlTemplate(f) : undefined,
          center: latLng,
          bbox: bbox,
          properties: f.properties
        });
      }
    }

    return results;
  },

  _decodeFeatureName: function(f) {
    return (this.options.nameProperties || [])
      .map(function(p) {
        return f.properties[p];
      })
      .filter(function(v) {
        return !!v;
      })
      .join(', ');
  }
});

export function photon(options) {
  return new Photon(options);
}
<commit_msg>Update photon.js<commit_after>import L from 'leaflet';
import { getJSON } from '../util';

export var Photon = L.Class.extend({
  options: {
    serviceUrl: 'https://photon.komoot.io/api/',
    reverseUrl: 'https://photon.komoot.io/reverse/',
    nameProperties: ['name', 'street', 'suburb', 'hamlet', 'town', 'city', 'state', 'country']
  },

  initialize: function(options) {
    L.setOptions(this, options);
  },

  geocode: function(query, cb, context) {
    var params = L.extend(
      {
        q: query
      },
      this.options.geocodingQueryParams
    );

    getJSON(
      this.options.serviceUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  suggest: function(query, cb, context) {
    return this.geocode(query, cb, context);
  },

  reverse: function(latLng, scale, cb, context) {
    var params = L.extend(
      {
        lat: latLng.lat,
        lon: latLng.lng
      },
      this.options.reverseQueryParams
    );

    getJSON(
      this.options.reverseUrl,
      params,
      L.bind(function(data) {
        cb.call(context, this._decodeFeatures(data));
      }, this)
    );
  },

  _decodeFeatures: function(data) {
    var results = [],
      i,
      f,
      c,
      latLng,
      extent,
      bbox;

    if (data && data.features) {
      for (i = 0; i < data.features.length; i++) {
        f = data.features[i];
        c = f.geometry.coordinates;
        latLng = L.latLng(c[1], c[0]);
        extent = f.properties.extent;

        if (extent) {
          bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]);
        } else {
          bbox = L.latLngBounds(latLng, latLng);
        }

        results.push({
          name: this._decodeFeatureName(f),
          html: this.options.htmlTemplate ? this.options.htmlTemplate(f) : undefined,
          center: latLng,
          bbox: bbox,
          properties: f.properties
        });
      }
    }

    return results;
  },

  _decodeFeatureName: function(f) {
    return (this.options.nameProperties || [])
      .map(function(p) {
        return f.properties[p];
      })
      .filter(function(v) {
        return !!v;
      })
      .join(', ');
  }
});

export function photon(options) {
  return new Photon(options);
}
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Utils = require('../../renderer/webgl/Utils');
var Vector3 = require('../../math/Vector3');

/**
 * @classdesc
 * A Vertex Geometry Object.
 *
 * This class consists of all the information required for a single vertex within a Face Geometry Object.
 *
 * Faces, and thus Vertex objects, are used by the Mesh Game Object in order to render objects in WebGL.
 *
 * @class Vertex
 * @memberof Phaser.Geom.Mesh
 * @constructor
 * @extends Phaser.Math.Vector3
 * @since 3.50.0
 *
 * @param {number} x - The x position of the vertex.
 * @param {number} y - The y position of the vertex.
 * @param {number} z - The z position of the vertex.
 * @param {number} u - The UV u coordinate of the vertex.
 * @param {number} v - The UV v coordinate of the vertex.
 * @param {number} [color=0xffffff] - The color value of the vertex.
 * @param {number} [alpha=1] - The alpha value of the vertex.
 */
var Vertex = new Class({

    Extends: Vector3,

    initialize:

    function Vertex (x, y, z, u, v, color, alpha)
    {
        if (color === undefined) { color = 0xffffff; }
        if (alpha === undefined) { alpha = 1; }

        Vector3.call(this, x, y, z);

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.vx = 0;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.vy = 0;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.vz = 0;

        /**
         * UV u coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#u
         * @type {number}
         * @since 3.50.0
         */
        this.u = u;

        /**
         * UV v coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#v
         * @type {number}
         * @since 3.50.0
         */
        this.v = v;

        /**
         * The color value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#color
         * @type {number}
         * @since 3.50.0
         */
        this.color = color;

        /**
         * The alpha value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#alpha
         * @type {number}
         * @since 3.50.0
         */
        this.alpha = alpha;
    },

    /**
     * Transforms this vertex by the given matrix, storing the results in `vx`, `vy` and `vz`.
     *
     * @method Phaser.Geom.Mesh.Vertex#transformCoordinatesLocal
     * @since 3.50.0
     *
     * @param {Phaser.Math.Matrix4} transformMatrix - The transform matrix to apply to this vertex.
     * @param {number} width - The width of the parent Mesh.
     * @param {number} height - The height of the parent Mesh.
     */
    transformCoordinatesLocal: function (transformMatrix, width, height)
    {
        var x = this.x;
        var y = this.y;
        var z = this.z;

        var m = transformMatrix.val;

        var tx = (x * m[0]) + (y * m[4]) + (z * m[8]) + m[12];
        var ty = (x * m[1]) + (y * m[5]) + (z * m[9]) + m[13];
        var tz = (x * m[2]) + (y * m[6]) + (z * m[10]) + m[14];
        var tw = (x * m[3]) + (y * m[7]) + (z * m[11]) + m[15];

        this.vx = (tx / tw) * width;
        this.vy = -(ty / tw) * height;
        this.vz = (tz / tw);
    },

    /**
     * Loads the data from this Vertex into the given Typed Arrays.
     *
     * @method Phaser.Geom.Mesh.Vertex#load
     * @since 3.50.0
     *
     * @param {Float32Array} F32 - A Float32 Array to insert the position, UV and unit data in to.
     * @param {Uint32Array} U32 - A Uint32 Array to insert the color and alpha data in to.
     * @param {number} offset - The index of the array to insert this Vertex to.
     * @param {number} textureUnit - The texture unit currently in use.
     * @param {number} alpha - The alpha of the parent object.
     * @param {number} a - The parent transform matrix data a component.
     * @param {number} b - The parent transform matrix data b component.
     * @param {number} c - The parent transform matrix data c component.
     * @param {number} d - The parent transform matrix data d component.
     * @param {number} e - The parent transform matrix data e component.
     * @param {number} f - The parent transform matrix data f component.
     * @param {boolean} roundPixels - Round the vertex position or not?
     *
     * @return {number} The new array offset.
     */
    load: function (F32, U32, offset, textureUnit, tintEffect, alpha, a, b, c, d, e, f, roundPixels)
    {
        var tx = this.vx * a + this.vy * c + e;
        var ty = this.vx * b + this.vy * d + f;

        if (roundPixels)
        {
            tx = Math.round(tx);
            ty = Math.round(ty);
        }

        F32[++offset] = tx;
        F32[++offset] = ty;
        F32[++offset] = this.u;
        F32[++offset] = this.v;
        F32[++offset] = textureUnit;
        F32[++offset] = tintEffect;
        // U32[++offset] = Utils.getTintAppendFloatAlpha(this.color, alpha * this.alpha);
        U32[++offset] = Utils.getTintAppendFloatAlpha(0xffffff, 1);

        return offset;
    }

});

module.exports = Vertex;
<commit_msg>Update Vertex.js<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../utils/Class');
var Utils = require('../../renderer/webgl/Utils');
var Vector3 = require('../../math/Vector3');

/**
 * @classdesc
 * A Vertex Geometry Object.
 *
 * This class consists of all the information required for a single vertex within a Face Geometry Object.
 *
 * Faces, and thus Vertex objects, are used by the Mesh Game Object in order to render objects in WebGL.
 *
 * @class Vertex
 * @memberof Phaser.Geom.Mesh
 * @constructor
 * @extends Phaser.Math.Vector3
 * @since 3.50.0
 *
 * @param {number} x - The x position of the vertex.
 * @param {number} y - The y position of the vertex.
 * @param {number} z - The z position of the vertex.
 * @param {number} u - The UV u coordinate of the vertex.
 * @param {number} v - The UV v coordinate of the vertex.
 * @param {number} [color=0xffffff] - The color value of the vertex.
 * @param {number} [alpha=1] - The alpha value of the vertex.
 */
var Vertex = new Class({

    Extends: Vector3,

    initialize:

    function Vertex (x, y, z, u, v, color, alpha)
    {
        if (color === undefined) { color = 0xffffff; }
        if (alpha === undefined) { alpha = 1; }

        Vector3.call(this, x, y, z);

        /**
         * The projected x coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vx
         * @type {number}
         * @since 3.50.0
         */
        this.vx = 0;

        /**
         * The projected y coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vy
         * @type {number}
         * @since 3.50.0
         */
        this.vy = 0;

        /**
         * The projected z coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#vz
         * @type {number}
         * @since 3.50.0
         */
        this.vz = 0;

        /**
         * UV u coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#u
         * @type {number}
         * @since 3.50.0
         */
        this.u = u;

        /**
         * UV v coordinate of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#v
         * @type {number}
         * @since 3.50.0
         */
        this.v = v;

        /**
         * The color value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#color
         * @type {number}
         * @since 3.50.0
         */
        this.color = color;

        /**
         * The alpha value of this vertex.
         *
         * @name Phaser.Geom.Mesh.Vertex#alpha
         * @type {number}
         * @since 3.50.0
         */
        this.alpha = alpha;
    },

    /**
     * Transforms this vertex by the given matrix, storing the results in `vx`, `vy` and `vz`.
     *
     * @method Phaser.Geom.Mesh.Vertex#transformCoordinatesLocal
     * @since 3.50.0
     *
     * @param {Phaser.Math.Matrix4} transformMatrix - The transform matrix to apply to this vertex.
     * @param {number} width - The width of the parent Mesh.
     * @param {number} height - The height of the parent Mesh.
     */
    transformCoordinatesLocal: function (transformMatrix, width, height)
    {
        var x = this.x;
        var y = this.y;
        var z = this.z;

        var m = transformMatrix.val;

        var tx = (x * m[0]) + (y * m[4]) + (z * m[8]) + m[12];
        var ty = (x * m[1]) + (y * m[5]) + (z * m[9]) + m[13];
        var tz = (x * m[2]) + (y * m[6]) + (z * m[10]) + m[14];
        var tw = (x * m[3]) + (y * m[7]) + (z * m[11]) + m[15];

        this.vx = (tx / tw) * width;
        this.vy = -(ty / tw) * height;
        this.vz = (tz / tw);
    },

    /**
     * Loads the data from this Vertex into the given Typed Arrays.
     *
     * @method Phaser.Geom.Mesh.Vertex#load
     * @since 3.50.0
     *
     * @param {Float32Array} F32 - A Float32 Array to insert the position, UV and unit data in to.
     * @param {Uint32Array} U32 - A Uint32 Array to insert the color and alpha data in to.
     * @param {number} offset - The index of the array to insert this Vertex to.
     * @param {number} textureUnit - The texture unit currently in use.
     * @param {number} alpha - The alpha of the parent object.
     * @param {number} a - The parent transform matrix data a component.
     * @param {number} b - The parent transform matrix data b component.
     * @param {number} c - The parent transform matrix data c component.
     * @param {number} d - The parent transform matrix data d component.
     * @param {number} e - The parent transform matrix data e component.
     * @param {number} f - The parent transform matrix data f component.
     * @param {boolean} roundPixels - Round the vertex position or not?
     *
     * @return {number} The new array offset.
     */
    load: function (F32, U32, offset, textureUnit, tintEffect, alpha, a, b, c, d, e, f, roundPixels)
    {
        var tx = this.vx * a + this.vy * c + e;
        var ty = this.vx * b + this.vy * d + f;

        if (roundPixels)
        {
            tx = Math.round(tx);
            ty = Math.round(ty);
        }

        F32[++offset] = tx;
        F32[++offset] = ty;
        F32[++offset] = this.u;
        F32[++offset] = this.v;
        F32[++offset] = textureUnit;
        F32[++offset] = tintEffect;
        U32[++offset] = Utils.getTintAppendFloatAlpha(this.color, alpha * this.alpha);

        return offset;
    }

});

module.exports = Vertex;
<|endoftext|>


<commit_before>/*
 ***** 已使用的子域名
 * ***********************
 *
 * 目前以下子域名已经启用
 * 提交一个 PR， 添加你想使用的的域名
 *
 *
 **** 说明
 * ***********
 *
 * KEY:         你提交的域名（如：`foo` 表示自定义子域名为 `foo.js.cool`）
 *
 * VALUE:       以 Github 为例，`foo.github.io` 表示用户/组织的主页，
 *              或 `foo.github.io/bar` 表示项目主页，也可以绑定 Gitee、 CODING.NET 等其它开源托管服务商。
 *
 * CLOUDFLARE:  目前 JS.COOL 使用的 DNS 服务商为 CloudFlare。默认情况下代理状态为自动（支持 SSL），
 *              通过 HTTPS 链接（如： https://foo.js.cool ）进行访问。
 *              但如果你不希望通过 CloudFlare 加速，可以选择 `仅限 DNS` 选项，
 *              只需要在你提交的代码后面添加 `// noCF` 注释即可。
 */
module.exports = {
  // 请在此处区域内添加自定义域名
  "color-ui": "colorui-kit.github.io",
  "icns": "icnskit.github.io",
  "j2me_games": "waifu-project.github.io",
  'cnchar': 'theajack.github.io',
  'leader': 'willin.github.io',
  'codewars': 'js-cool.github.io',
  'dataloader': 'shiwangme.github.io',
  'hyperapp': 'willin.github.io',
  'anime': 'js-cool.github.io',
  'learn': 'hosting.gitbook.com',
  'vchart': 'willin.github.io',
  'graphql': 'willin.github.io',
  'speech': 'willin.github.io',
  'blockchain': 'willin.github.io',
  'antiadblock': 'js-cool.github.io',
  'noho': 'willin.github.io',
  //'jen': 'dirkhe1051931999.github.io',
  'uiw': 'uiwjs.github.io',
  'xrkffgg': 'xrkffgg.github.io',
  'interview': 'front-end-interview.netlify.app',
  'xiaomeiwu':'xiaomeiwu.github.io',
  'ip': 'ipip.vercel.app', // noCF
  'mingyan': 'lehs8n.coding-pages.com', //noCf
  'na': 'qq.mcust.cn',
  'rx': 'willin.github.io',
  'bbx': 'appser.gitee.io',
  'mengd': 'cname.vercel-dns.com',
  'kali': '551kdx.coding-pages.com',
  'zwt': 'zwtdyhm.github.io',
  'zwtdwz': 'zwtdzh.github.io',
  'zwtdwlzd': 'zwtdwlid.github.io',
  'histcat': 'jessejeson.github.io',
  'wangdabao-resume': 'wangdabaoqq.github.io',
  'wangdabao': 'wangdabaoqq.github.io',
  'resources': 'willin.github.io',
  'zwtdwzym': 'zwtduserid.github.io',
  'kaodan': 'kaodan.github.io',
  'gatsby-demo': 'whitematrix.github.io',
  'box': 'qikaile.github.io',
  'hualin': 'liaochenlanruo.github.io',
  'authing-next': 'cname.vercel-dns.com',
  // 请在此行之上新增一行并提交 Pull Request
  // 示例：
  // 'youarname': 'username.github.io' // noCF
  // 以下为已启用的保留域名，请勿修改
  '@': 'js-cool.github.io',
  'www': 'kv6xcc.coding-pages.com', // 国内镜像
  'logo': 'js-cool.github.io'
};
<commit_msg>Update active_cname.js<commit_after>/*
 ***** 已使用的子域名
 * ***********************
 *
 * 目前以下子域名已经启用
 * 提交一个 PR， 添加你想使用的的域名
 *
 *
 **** 说明
 * ***********
 *
 * KEY:         你提交的域名（如：`foo` 表示自定义子域名为 `foo.js.cool`）
 *
 * VALUE:       以 Github 为例，`foo.github.io` 表示用户/组织的主页，
 *              或 `foo.github.io/bar` 表示项目主页，也可以绑定 Gitee、 CODING.NET 等其它开源托管服务商。
 *
 * CLOUDFLARE:  目前 JS.COOL 使用的 DNS 服务商为 CloudFlare。默认情况下代理状态为自动（支持 SSL），
 *              通过 HTTPS 链接（如： https://foo.js.cool ）进行访问。
 *              但如果你不希望通过 CloudFlare 加速，可以选择 `仅限 DNS` 选项，
 *              只需要在你提交的代码后面添加 `// noCF` 注释即可。
 */
module.exports = {
  // 请在此处区域内添加自定义域名
  "color-ui": "colorui-kit.github.io",
  "icns": "icnskit.github.io",
  "j2me_games": "waifu-project.github.io",
  'cnchar': 'theajack.github.io',
  'leader': 'willin.github.io',
  'codewars': 'js-cool.github.io',
  'dataloader': 'shiwangme.github.io',
  'hyperapp': 'willin.github.io',
  'anime': 'js-cool.github.io',
  'learn': 'hosting.gitbook.com',
  'vchart': 'willin.github.io',
  'graphql': 'willin.github.io',
  'speech': 'willin.github.io',
  'blockchain': 'willin.github.io',
  'antiadblock': 'js-cool.github.io',
  'noho': 'willin.github.io',
  //'jen': 'dirkhe1051931999.github.io',
  'uiw': 'uiwjs.github.io',
  'xrkffgg': 'xrkffgg.github.io',
  'interview': 'front-end-interview.netlify.app',
  'xiaomeiwu':'xiaomeiwu.github.io',
  'ip': 'ipip.vercel.app', // noCF
  'mingyan': 'lehs8n.coding-pages.com', //noCf
  'na': 'qq.mcust.cn',
  'rx': 'willin.github.io',
  'bbx': 'appser.gitee.io',
  'mengd': 'cname.vercel-dns.com',
  'kali': '551kdx.coding-pages.com',
  'zwt': 'zwtdyhm.github.io',
  'zwtdwz': 'zwtdzh.github.io',
  'zwtdwlzd': 'zwtdwlid.github.io',
  // 'histcat': 'jessejeson.github.io',
  'wangdabao-resume': 'wangdabaoqq.github.io',
  'wangdabao': 'wangdabaoqq.github.io',
  'resources': 'willin.github.io',
  'zwtdwzym': 'zwtduserid.github.io',
  'kaodan': 'kaodan.github.io',
  'gatsby-demo': 'whitematrix.github.io',
  'box': 'qikaile.github.io',
  'hualin': 'liaochenlanruo.github.io',
  'authing-next': 'cname.vercel-dns.com',
  // 请在此行之上新增一行并提交 Pull Request
  // 示例：
  // 'youarname': 'username.github.io' // noCF
  // 以下为已启用的保留域名，请勿修改
  '@': 'js-cool.github.io',
  'www': 'kv6xcc.coding-pages.com', // 国内镜像
  'logo': 'js-cool.github.io'
};
<|endoftext|>


<commit_before>sigma.classes.Graph = function() {
  sigma.classes.EventDispatcher.call(this);

  this.nodes = [];
  this.nodesIndex = {};
  this.edges = [];
  this.edgesIndex = {};
};

sigma.classes.Graph.prototype.addNode = function(id, params) {
  if (this.nodesIndex[id]) {
    throw new Error('Node "' + id + '" already exists.');
  }

  params = params || {};
  var n = {
    'x': 0,
    'y': 0,
    'dx': 0,
    'dy': 0,
    'degree': 0,
    'old_dx': 0,
    'old_dy': 0,
    'displayX': 0,
    'displayY': 0,
    'size': 1,
    'displaySize': 1,
    'color': '#fff',
    'label': id,
    'id': id,
    'attr': {}
  };

  for (var k in params) {
    switch (k) {
      case 'x':
      case 'y':
      case 'size':
        n[k] = +params[k];
        break;
      case 'color':
        n[k] = params[k];
        break;
      case 'label':
        n[k] = params[k];
        break;
      default:
        n['attr'][k] = params[k];
    }
  }

  this.nodes.push(n);
  this.nodesIndex[id] = n;

  return this;
};

sigma.classes.Graph.prototype.addEdge = function(id, source, target, params) {
  if (this.edgesIndex[id]) {
    throw new Error('Edge "' + id + '" already exists.');
  }

  if (!this.nodesIndex[source]) {
    var s = 'Edge\'s source "' + source + '" does not exist yet.';
    throw new Error(s);
  }

  if (!this.nodesIndex[target]) {
    var s = 'Edge\'s target "' + target + '" does not exist yet.';
    throw new Error(s);
  }

  params = params || {};
  var e = {
    'source': this.nodesIndex[source],
    'target': this.nodesIndex[target],
    'size': 1,
    'weight': 1,
    'displaySize': 0.5,
    'color': this.nodesIndex[source]['color'],
    'label': id,
    'id': id,
    'attr': {}
  };
  e['source']['degree']++;
  e['target']['degree']++;

  for (var k in params) {
    switch (k) {
      case 'size':
        e[k] = +params[k];
        break;
      case 'color':
        e[k] = Color.hex(params[k]);
        break;
      case 'label':
        e[k] = params[k];
        break;
      default:
        e['attr'][k] = params[k];
    }
  }

  this.edges.push(e);
  this.edgesIndex[id] = e;

  return this;
};

sigma.classes.Graph.prototype.rescale = function(w, h, sMin, sMax, tMin, tMax) {
  var weightMax = 0, sizeMax = 0;
  var self = this;

  this.nodes.forEach(function(node) {
    sizeMax = Math.max(node['size'], sizeMax);
  });

  this.edges.forEach(function(edge) {
    weightMax = Math.max(edge['size'], weightMax);
  });

  if (sizeMax == 0) {
    return;
  }

  if (weightMax == 0) {
    return;
  }

  // Recenter the nodes:
  var xMin, xMax, yMin, yMax;
  this.nodes.forEach(function(node) {
    xMax = Math.max(node['x'], xMax || node['x']);
    xMin = Math.min(node['x'], xMin || node['x']);
    yMax = Math.max(node['y'], yMax || node['y']);
    yMin = Math.min(node['y'], yMin || node['y']);
  });

  var scale = Math.min(0.9 * w / (xMax - xMin),
                       0.9 * h / (yMax - yMin));

  // Size homothetic parameters:
  var a, b;
  if (!sMax && !sMin) {
    a = 1;
    b = 0;
  }else if (sMax == sMin) {
    a = 0;
    b = sMax;
  }else {
    a = (sMax - sMin) / sizeMax;
    b = sMin;
  }

  var c, d;
  if (!tMax && !tMin) {
    c = 1;
    d = 0;
  }else if (tMax == tMin) {
    c = 0;
    d = tMin;
  }else {
    c = (tMax - tMin) / weightMax;
    d = tMin;
  }

  // Rescale the nodes:
  this.nodes.forEach(function(node) {
    node['displaySize'] = node['size'] * a + b;

    if (!node['isFixed']) {
      node['displayX'] = (node['x'] - (xMax + xMin) / 2) * scale + w / 2;
      node['displayY'] = (node['y'] - (yMax + yMin) / 2) * scale + h / 2;
    }
  });

  this.edges.forEach(function(edge) {
    edge['displaySize'] = edge['size'] * c + d;
  });
};
<commit_msg>added translate method (nodes position now depending of stage position/ratio)<commit_after>sigma.classes.Graph = function() {
  sigma.classes.EventDispatcher.call(this);

  this.nodes = [];
  this.nodesIndex = {};
  this.edges = [];
  this.edgesIndex = {};
};

sigma.classes.Graph.prototype.addNode = function(id, params) {
  if (this.nodesIndex[id]) {
    throw new Error('Node "' + id + '" already exists.');
  }

  params = params || {};
  var n = {
    'x': 0,
    'y': 0,
    'dx': 0,
    'dy': 0,
    'degree': 0,
    'old_dx': 0,
    'old_dy': 0,
    'displayX': 0,
    'displayY': 0,
    'size': 1,
    'displaySize': 1,
    'color': '#fff',
    'label': id,
    'id': id,
    'attr': {}
  };

  for (var k in params) {
    switch (k) {
      case 'x':
      case 'y':
      case 'size':
        n[k] = +params[k];
        break;
      case 'color':
        n[k] = params[k];
        break;
      case 'label':
        n[k] = params[k];
        break;
      default:
        n['attr'][k] = params[k];
    }
  }

  this.nodes.push(n);
  this.nodesIndex[id] = n;

  return this;
};

sigma.classes.Graph.prototype.addEdge = function(id, source, target, params) {
  if (this.edgesIndex[id]) {
    throw new Error('Edge "' + id + '" already exists.');
  }

  if (!this.nodesIndex[source]) {
    var s = 'Edge\'s source "' + source + '" does not exist yet.';
    throw new Error(s);
  }

  if (!this.nodesIndex[target]) {
    var s = 'Edge\'s target "' + target + '" does not exist yet.';
    throw new Error(s);
  }

  params = params || {};
  var e = {
    'source': this.nodesIndex[source],
    'target': this.nodesIndex[target],
    'size': 1,
    'weight': 1,
    'displaySize': 0.5,
    'color': this.nodesIndex[source]['color'],
    'label': id,
    'id': id,
    'attr': {}
  };
  e['source']['degree']++;
  e['target']['degree']++;

  for (var k in params) {
    switch (k) {
      case 'size':
        e[k] = +params[k];
        break;
      case 'color':
        e[k] = Color.hex(params[k]);
        break;
      case 'label':
        e[k] = params[k];
        break;
      default:
        e['attr'][k] = params[k];
    }
  }

  this.edges.push(e);
  this.edgesIndex[id] = e;

  return this;
};

sigma.classes.Graph.prototype.rescale = function(w, h, sMin, sMax, tMin, tMax) {
  var weightMax = 0, sizeMax = 0;
  var self = this;

  this.nodes.forEach(function(node) {
    sizeMax = Math.max(node['size'], sizeMax);
  });

  this.edges.forEach(function(edge) {
    weightMax = Math.max(edge['size'], weightMax);
  });

  if (sizeMax == 0) {
    return;
  }

  if (weightMax == 0) {
    return;
  }

  // Recenter the nodes:
  var xMin, xMax, yMin, yMax;
  this.nodes.forEach(function(node) {
    xMax = Math.max(node['x'], xMax || node['x']);
    xMin = Math.min(node['x'], xMin || node['x']);
    yMax = Math.max(node['y'], yMax || node['y']);
    yMin = Math.min(node['y'], yMin || node['y']);
  });

  var scale = Math.min(0.9 * w / (xMax - xMin),
                       0.9 * h / (yMax - yMin));

  // Size homothetic parameters:
  var a, b;
  if (!sMax && !sMin) {
    a = 1;
    b = 0;
  }else if (sMax == sMin) {
    a = 0;
    b = sMax;
  }else {
    a = (sMax - sMin) / sizeMax;
    b = sMin;
  }

  var c, d;
  if (!tMax && !tMin) {
    c = 1;
    d = 0;
  }else if (tMax == tMin) {
    c = 0;
    d = tMin;
  }else {
    c = (tMax - tMin) / weightMax;
    d = tMin;
  }

  // Rescale the nodes:
  this.nodes.forEach(function(node) {
    node['displaySize'] = node['size'] * a + b;

    if (!node['isFixed']) {
      node['displayX'] = (node['x'] - (xMax + xMin) / 2) * scale + w / 2;
      node['displayY'] = (node['y'] - (yMax + yMin) / 2) * scale + h / 2;
    }
  });

  this.edges.forEach(function(edge) {
    edge['displaySize'] = edge['size'] * c + d;
  });
};

sigma.classes.Graph.prototype.translate = function(sceneX, sceneY, ratio, pow) {
  var sizeRatio = Math.pow(ratio, pow || 1 / 2);

  this.nodes.forEach(function(node) {
    if (!node['isFixed']) {
      node['displayX'] = node['displayX'] * ratio + sceneX;
      node['displayY'] = node['displayY'] * ratio + sceneY;
    }

    node['displaySize'] = node['displaySize'] * sizeRatio;
  });
};
<|endoftext|>