<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);

        return offset;
    }

});

module.exports = Vertex;
<commit_msg>Added cameraZ parameter<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.
     * @param {number} cameraZ - The z position of the MeshCamera.
     */
    transformCoordinatesLocal: function (transformMatrix, width, height, cameraZ)
    {
        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;

        if (cameraZ <= 0)
        {
            this.vz = (tz / tw);
        }
        else
        {
            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>const _ = require('underscore-plus')
const Grim = require('grim')
const FirstMate = require('first-mate')
const {Disposable, CompositeDisposable} = require('event-kit')
const TextMateLanguageMode = require('./text-mate-language-mode')
const Token = require('./token')
const fs = require('fs-plus')
const {Point, Range} = require('text-buffer')

const GRAMMAR_SELECTION_RANGE = Range(Point.ZERO, Point(10, 0)).freeze()
const PATH_SPLIT_REGEX = new RegExp('[/.]')

// Extended: This class holds the grammars used for tokenizing.
//
// An instance of this class is always available as the `atom.grammars` global.
module.exports =
class GrammarRegistry extends FirstMate.GrammarRegistry {
  constructor ({config} = {}) {
    super({maxTokensPerLine: 100, maxLineLength: 1000})
    this.config = config
    this.subscriptions = new CompositeDisposable()
  }

  clear () {
    super.clear()
    if (this.subscriptions) this.subscriptions.dispose()
    this.subscriptions = new CompositeDisposable()
    this.languageOverridesByBufferId = new Map()
    this.grammarScoresByBuffer = new Map()

    const grammarAddedOrUpdated = this.grammarAddedOrUpdated.bind(this)
    this.onDidAddGrammar(grammarAddedOrUpdated)
    this.onDidUpdateGrammar(grammarAddedOrUpdated)
  }

  serialize () {
    const languageOverridesByBufferId = {}
    this.languageOverridesByBufferId.forEach((languageId, bufferId) => {
      languageOverridesByBufferId[bufferId] = languageId
    })
    return {languageOverridesByBufferId}
  }

  deserialize (params) {
    for (const bufferId in params.languageOverridesByBufferId || {}) {
      this.languageOverridesByBufferId.set(
        bufferId,
        params.languageOverridesByBufferId[bufferId]
      )
    }
  }

  createToken (value, scopes) {
    return new Token({value, scopes})
  }

  // Extended: set a {TextBuffer}'s language mode based on its path and content,
  // and continue to update its language mode as grammars are added or updated, or
  // the buffer's file path changes.
  //
  // * `buffer` The {TextBuffer} whose language mode will be maintained.
  //
  // Returns a {Disposable} that can be used to stop updating the buffer's
  // language mode.
  maintainLanguageMode (buffer) {
    this.grammarScoresByBuffer.set(buffer, null)

    const languageOverride = this.languageOverridesByBufferId.get(buffer.id)
    if (languageOverride) {
      this.assignLanguageMode(buffer, languageOverride)
    } else {
      this.autoAssignLanguageMode(buffer)
    }

    const pathChangeSubscription = buffer.onDidChangePath(() => {
      this.grammarScoresByBuffer.delete(buffer)
      if (!this.languageOverridesByBufferId.has(buffer.id)) {
        this.autoAssignLanguageMode(buffer)
      }
    })

    const destroySubscription = buffer.onDidDestroy(() => {
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
      this.subscriptions.remove(destroySubscription)
      this.subscriptions.remove(pathChangeSubscription)
    })

    this.subscriptions.add(pathChangeSubscription, destroySubscription)

    return new Disposable(() => {
      destroySubscription.dispose()
      pathChangeSubscription.dispose()
      this.subscriptions.remove(pathChangeSubscription)
      this.subscriptions.remove(destroySubscription)
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
    })
  }

  // Extended: Force a {TextBuffer} to use a different grammar than the
  // one that would otherwise be selected for it.
  //
  // * `buffer` The {TextBuffer} whose gramamr will be set.
  // * `languageId` The {String} id of the desired language.
  //
  // Returns a {Boolean} that indicates whether the language was successfully
  // found.
  assignLanguageMode (buffer, languageId) {
    if (buffer.getBuffer) buffer = buffer.getBuffer()

    let grammar = null
    if (languageId != null) {
      grammar = this.grammarForScopeName(languageId)
      if (!grammar) return false
      this.languageOverridesByBufferId.set(buffer.id, languageId)
    } else {
      this.languageOverridesByBufferId.set(buffer.id, null)
      grammar = this.nullGrammar
    }

    this.grammarScoresByBuffer.set(buffer, null)
    if (grammar.scopeName !== buffer.getLanguageMode().getLanguageId()) {
      buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
    }

    return true
  }

  // Extended: Remove any language mode override that has been set for the
  // given {TextBuffer}. This will assign to the buffer the best language
  // mode available.
  //
  // * `buffer` The {TextBuffer}.
  autoAssignLanguageMode (buffer) {
    const result = this.selectGrammarWithScore(
      buffer.getPath(),
      buffer.getTextInRange(GRAMMAR_SELECTION_RANGE)
    )
    this.languageOverridesByBufferId.delete(buffer.id)
    this.grammarScoresByBuffer.set(buffer, result.score)
    if (result.grammar.scopeName !== buffer.getLanguageMode().getLanguageId()) {
      buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(result.grammar, buffer))
    }
  }

  languageModeForGrammarAndBuffer (grammar, buffer) {
    return new TextMateLanguageMode({grammar, buffer, config: this.config})
  }

  // Extended: Select a grammar for the given file path and file contents.
  //
  // This picks the best match by checking the file path and contents against
  // each grammar.
  //
  // * `filePath` A {String} file path.
  // * `fileContents` A {String} of text for the file path.
  //
  // Returns a {Grammar}, never null.
  selectGrammar (filePath, fileContents) {
    return this.selectGrammarWithScore(filePath, fileContents).grammar
  }

  selectGrammarWithScore (filePath, fileContents) {
    let bestMatch = null
    let highestScore = -Infinity
    for (let grammar of this.grammars) {
      const score = this.getGrammarScore(grammar, filePath, fileContents)
      if ((score > highestScore) || (bestMatch == null)) {
        bestMatch = grammar
        highestScore = score
      }
    }
    return {grammar: bestMatch, score: highestScore}
  }

  // Extended: Returns a {Number} representing how well the grammar matches the
  // `filePath` and `contents`.
  getGrammarScore (grammar, filePath, contents) {
    if ((contents == null) && fs.isFileSync(filePath)) {
      contents = fs.readFileSync(filePath, 'utf8')
    }

    let score = this.getGrammarPathScore(grammar, filePath)
    if ((score > 0) && !grammar.bundledPackage) {
      score += 0.125
    }
    if (this.grammarMatchesContents(grammar, contents)) {
      score += 0.25
    }
    return score
  }

  getGrammarPathScore (grammar, filePath) {
    if (!filePath) { return -1 }
    if (process.platform === 'win32') { filePath = filePath.replace(/\\/g, '/') }

    const pathComponents = filePath.toLowerCase().split(PATH_SPLIT_REGEX)
    let pathScore = -1

    let customFileTypes
    if (this.config.get('core.customFileTypes')) {
      customFileTypes = this.config.get('core.customFileTypes')[grammar.scopeName]
    }

    let { fileTypes } = grammar
    if (customFileTypes) {
      fileTypes = fileTypes.concat(customFileTypes)
    }

    for (let i = 0; i < fileTypes.length; i++) {
      const fileType = fileTypes[i]
      const fileTypeComponents = fileType.toLowerCase().split(PATH_SPLIT_REGEX)
      const pathSuffix = pathComponents.slice(-fileTypeComponents.length)
      if (_.isEqual(pathSuffix, fileTypeComponents)) {
        pathScore = Math.max(pathScore, fileType.length)
        if (i >= grammar.fileTypes.length) {
          pathScore += 0.5
        }
      }
    }

    return pathScore
  }

  grammarMatchesContents (grammar, contents) {
    if ((contents == null) || (grammar.firstLineRegex == null)) { return false }

    let escaped = false
    let numberOfNewlinesInRegex = 0
    for (let character of grammar.firstLineRegex.source) {
      switch (character) {
        case '\\':
          escaped = !escaped
          break
        case 'n':
          if (escaped) { numberOfNewlinesInRegex++ }
          escaped = false
          break
        default:
          escaped = false
      }
    }
    const lines = contents.split('\n')
    return grammar.firstLineRegex.testSync(lines.slice(0, numberOfNewlinesInRegex + 1).join('\n'))
  }

  // Deprecated: Get the grammar override for the given file path.
  //
  // * `filePath` A {String} file path.
  //
  // Returns a {String} such as `"source.js"`.
  grammarOverrideForPath (filePath) {
    Grim.deprecate('Use buffer.getLanguageMode().getLanguageId() instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) return this.languageOverridesByBufferId.get(buffer.id)
  }

  // Deprecated: Set the grammar override for the given file path.
  //
  // * `filePath` A non-empty {String} file path.
  // * `languageId` A {String} such as `"source.js"`.
  //
  // Returns undefined.
  setGrammarOverrideForPath (filePath, languageId) {
    Grim.deprecate('Use atom.grammars.assignLanguageMode(buffer, languageId) instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) {
      const grammar = this.grammarForScopeName(languageId)
      if (grammar) this.languageOverridesByBufferId.set(buffer.id, grammar.name)
    }
  }

  // Remove the grammar override for the given file path.
  //
  // * `filePath` A {String} file path.
  //
  // Returns undefined.
  clearGrammarOverrideForPath (filePath) {
    Grim.deprecate('Use atom.grammars.autoAssignLanguageMode(buffer) instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) this.languageOverridesByBufferId.delete(buffer.id)
  }

  grammarAddedOrUpdated (grammar) {
    this.grammarScoresByBuffer.forEach((score, buffer) => {
      const languageMode = buffer.getLanguageMode()
      if (grammar.injectionSelector) {
        if (languageMode.hasTokenForSelector(grammar.injectionSelector)) {
          languageMode.retokenizeLines()
        }
        return
      }

      const languageOverride = this.languageOverridesByBufferId.get(buffer.id)

      if ((grammar.scopeName === buffer.getLanguageMode().getLanguageId() ||
           grammar.scopeName === languageOverride)) {
        buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
      } else if (!languageOverride) {
        const score = this.getGrammarScore(
          grammar,
          buffer.getPath(),
          buffer.getTextInRange(GRAMMAR_SELECTION_RANGE)
        )

        const currentScore = this.grammarScoresByBuffer.get(buffer)
        if (currentScore == null || score > currentScore) {
          buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
          this.grammarScoresByBuffer.set(buffer, score)
        }
      }
    })
  }
}
<commit_msg>Remove GrammarRegistry's inheritance from first-mate's registry<commit_after>const _ = require('underscore-plus')
const Grim = require('grim')
const FirstMate = require('first-mate')
const {Disposable, CompositeDisposable} = require('event-kit')
const TextMateLanguageMode = require('./text-mate-language-mode')
const Token = require('./token')
const fs = require('fs-plus')
const {Point, Range} = require('text-buffer')

const GRAMMAR_SELECTION_RANGE = Range(Point.ZERO, Point(10, 0)).freeze()
const PATH_SPLIT_REGEX = new RegExp('[/.]')

// Extended: This class holds the grammars used for tokenizing.
//
// An instance of this class is always available as the `atom.grammars` global.
module.exports =
class GrammarRegistry {
  constructor ({config} = {}) {
    this.config = config
    this.subscriptions = new CompositeDisposable()
    this.textmateRegistry = new FirstMate.GrammarRegistry({maxTokensPerLine: 100, maxLineLength: 1000})
    this.clear()
  }

  clear () {
    this.textmateRegistry.clear()
    if (this.subscriptions) this.subscriptions.dispose()
    this.subscriptions = new CompositeDisposable()
    this.languageOverridesByBufferId = new Map()
    this.grammarScoresByBuffer = new Map()

    const grammarAddedOrUpdated = this.grammarAddedOrUpdated.bind(this)
    this.textmateRegistry.onDidAddGrammar(grammarAddedOrUpdated)
    this.textmateRegistry.onDidUpdateGrammar(grammarAddedOrUpdated)
  }

  serialize () {
    const languageOverridesByBufferId = {}
    this.languageOverridesByBufferId.forEach((languageId, bufferId) => {
      languageOverridesByBufferId[bufferId] = languageId
    })
    return {languageOverridesByBufferId}
  }

  deserialize (params) {
    for (const bufferId in params.languageOverridesByBufferId || {}) {
      this.languageOverridesByBufferId.set(
        bufferId,
        params.languageOverridesByBufferId[bufferId]
      )
    }
  }

  createToken (value, scopes) {
    return new Token({value, scopes})
  }

  // Extended: set a {TextBuffer}'s language mode based on its path and content,
  // and continue to update its language mode as grammars are added or updated, or
  // the buffer's file path changes.
  //
  // * `buffer` The {TextBuffer} whose language mode will be maintained.
  //
  // Returns a {Disposable} that can be used to stop updating the buffer's
  // language mode.
  maintainLanguageMode (buffer) {
    this.grammarScoresByBuffer.set(buffer, null)

    const languageOverride = this.languageOverridesByBufferId.get(buffer.id)
    if (languageOverride) {
      this.assignLanguageMode(buffer, languageOverride)
    } else {
      this.autoAssignLanguageMode(buffer)
    }

    const pathChangeSubscription = buffer.onDidChangePath(() => {
      this.grammarScoresByBuffer.delete(buffer)
      if (!this.languageOverridesByBufferId.has(buffer.id)) {
        this.autoAssignLanguageMode(buffer)
      }
    })

    const destroySubscription = buffer.onDidDestroy(() => {
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
      this.subscriptions.remove(destroySubscription)
      this.subscriptions.remove(pathChangeSubscription)
    })

    this.subscriptions.add(pathChangeSubscription, destroySubscription)

    return new Disposable(() => {
      destroySubscription.dispose()
      pathChangeSubscription.dispose()
      this.subscriptions.remove(pathChangeSubscription)
      this.subscriptions.remove(destroySubscription)
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
    })
  }

  // Extended: Force a {TextBuffer} to use a different grammar than the
  // one that would otherwise be selected for it.
  //
  // * `buffer` The {TextBuffer} whose gramamr will be set.
  // * `languageId` The {String} id of the desired language.
  //
  // Returns a {Boolean} that indicates whether the language was successfully
  // found.
  assignLanguageMode (buffer, languageId) {
    if (buffer.getBuffer) buffer = buffer.getBuffer()

    let grammar = null
    if (languageId != null) {
      grammar = this.textmateRegistry.grammarForScopeName(languageId)
      if (!grammar) return false
      this.languageOverridesByBufferId.set(buffer.id, languageId)
    } else {
      this.languageOverridesByBufferId.set(buffer.id, null)
      grammar = this.textmateRegistry.nullGrammar
    }

    this.grammarScoresByBuffer.set(buffer, null)
    if (grammar.scopeName !== buffer.getLanguageMode().getLanguageId()) {
      buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
    }

    return true
  }

  // Extended: Remove any language mode override that has been set for the
  // given {TextBuffer}. This will assign to the buffer the best language
  // mode available.
  //
  // * `buffer` The {TextBuffer}.
  autoAssignLanguageMode (buffer) {
    const result = this.selectGrammarWithScore(
      buffer.getPath(),
      buffer.getTextInRange(GRAMMAR_SELECTION_RANGE)
    )
    this.languageOverridesByBufferId.delete(buffer.id)
    this.grammarScoresByBuffer.set(buffer, result.score)
    if (result.grammar.scopeName !== buffer.getLanguageMode().getLanguageId()) {
      buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(result.grammar, buffer))
    }
  }

  languageModeForGrammarAndBuffer (grammar, buffer) {
    return new TextMateLanguageMode({grammar, buffer, config: this.config})
  }

  // Extended: Select a grammar for the given file path and file contents.
  //
  // This picks the best match by checking the file path and contents against
  // each grammar.
  //
  // * `filePath` A {String} file path.
  // * `fileContents` A {String} of text for the file path.
  //
  // Returns a {Grammar}, never null.
  selectGrammar (filePath, fileContents) {
    return this.selectGrammarWithScore(filePath, fileContents).grammar
  }

  selectGrammarWithScore (filePath, fileContents) {
    let bestMatch = null
    let highestScore = -Infinity
    for (let grammar of this.textmateRegistry.grammars) {
      const score = this.getGrammarScore(grammar, filePath, fileContents)
      if ((score > highestScore) || (bestMatch == null)) {
        bestMatch = grammar
        highestScore = score
      }
    }
    return {grammar: bestMatch, score: highestScore}
  }

  // Extended: Returns a {Number} representing how well the grammar matches the
  // `filePath` and `contents`.
  getGrammarScore (grammar, filePath, contents) {
    if ((contents == null) && fs.isFileSync(filePath)) {
      contents = fs.readFileSync(filePath, 'utf8')
    }

    let score = this.getGrammarPathScore(grammar, filePath)
    if ((score > 0) && !grammar.bundledPackage) {
      score += 0.125
    }
    if (this.grammarMatchesContents(grammar, contents)) {
      score += 0.25
    }
    return score
  }

  getGrammarPathScore (grammar, filePath) {
    if (!filePath) { return -1 }
    if (process.platform === 'win32') { filePath = filePath.replace(/\\/g, '/') }

    const pathComponents = filePath.toLowerCase().split(PATH_SPLIT_REGEX)
    let pathScore = -1

    let customFileTypes
    if (this.config.get('core.customFileTypes')) {
      customFileTypes = this.config.get('core.customFileTypes')[grammar.scopeName]
    }

    let { fileTypes } = grammar
    if (customFileTypes) {
      fileTypes = fileTypes.concat(customFileTypes)
    }

    for (let i = 0; i < fileTypes.length; i++) {
      const fileType = fileTypes[i]
      const fileTypeComponents = fileType.toLowerCase().split(PATH_SPLIT_REGEX)
      const pathSuffix = pathComponents.slice(-fileTypeComponents.length)
      if (_.isEqual(pathSuffix, fileTypeComponents)) {
        pathScore = Math.max(pathScore, fileType.length)
        if (i >= grammar.fileTypes.length) {
          pathScore += 0.5
        }
      }
    }

    return pathScore
  }

  grammarMatchesContents (grammar, contents) {
    if ((contents == null) || (grammar.firstLineRegex == null)) { return false }

    let escaped = false
    let numberOfNewlinesInRegex = 0
    for (let character of grammar.firstLineRegex.source) {
      switch (character) {
        case '\\':
          escaped = !escaped
          break
        case 'n':
          if (escaped) { numberOfNewlinesInRegex++ }
          escaped = false
          break
        default:
          escaped = false
      }
    }
    const lines = contents.split('\n')
    return grammar.firstLineRegex.testSync(lines.slice(0, numberOfNewlinesInRegex + 1).join('\n'))
  }

  // Deprecated: Get the grammar override for the given file path.
  //
  // * `filePath` A {String} file path.
  //
  // Returns a {String} such as `"source.js"`.
  grammarOverrideForPath (filePath) {
    Grim.deprecate('Use buffer.getLanguageMode().getLanguageId() instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) return this.languageOverridesByBufferId.get(buffer.id)
  }

  // Deprecated: Set the grammar override for the given file path.
  //
  // * `filePath` A non-empty {String} file path.
  // * `languageId` A {String} such as `"source.js"`.
  //
  // Returns undefined.
  setGrammarOverrideForPath (filePath, languageId) {
    Grim.deprecate('Use atom.grammars.assignLanguageMode(buffer, languageId) instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) {
      const grammar = this.grammarForScopeName(languageId)
      if (grammar) this.languageOverridesByBufferId.set(buffer.id, grammar.name)
    }
  }

  // Remove the grammar override for the given file path.
  //
  // * `filePath` A {String} file path.
  //
  // Returns undefined.
  clearGrammarOverrideForPath (filePath) {
    Grim.deprecate('Use atom.grammars.autoAssignLanguageMode(buffer) instead')
    const buffer = atom.project.findBufferForPath(filePath)
    if (buffer) this.languageOverridesByBufferId.delete(buffer.id)
  }

  grammarAddedOrUpdated (grammar) {
    this.grammarScoresByBuffer.forEach((score, buffer) => {
      const languageMode = buffer.getLanguageMode()
      if (grammar.injectionSelector) {
        if (languageMode.hasTokenForSelector(grammar.injectionSelector)) {
          languageMode.retokenizeLines()
        }
        return
      }

      const languageOverride = this.languageOverridesByBufferId.get(buffer.id)

      if ((grammar.scopeName === buffer.getLanguageMode().getLanguageId() ||
           grammar.scopeName === languageOverride)) {
        buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
      } else if (!languageOverride) {
        const score = this.getGrammarScore(
          grammar,
          buffer.getPath(),
          buffer.getTextInRange(GRAMMAR_SELECTION_RANGE)
        )

        const currentScore = this.grammarScoresByBuffer.get(buffer)
        if (currentScore == null || score > currentScore) {
          buffer.setLanguageMode(this.languageModeForGrammarAndBuffer(grammar, buffer))
          this.grammarScoresByBuffer.set(buffer, score)
        }
      }
    })
  }

  // Extended: Invoke the given callback when a grammar is added to the registry.
  //
  // * `callback` {Function} to call when a grammar is added.
  //   * `grammar` {Grammar} that was added.
  //
  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidAddGrammar (callback) {
    return this.textmateRegistry.onDidAddGrammar(callback)
  }

  // Extended: Invoke the given callback when a grammar is updated due to a grammar
  // it depends on being added or removed from the registry.
  //
  // * `callback` {Function} to call when a grammar is updated.
  //   * `grammar` {Grammar} that was updated.
  //
  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidUpdateGrammar (callback) {
    return this.textmateRegistry.onDidUpdateGrammar(callback)
  }

  get nullGrammar () {
    return this.textmateRegistry.nullGrammar
  }

  decodeTokens () {
    return this.textmateRegistry.decodeTokens.apply(this.textmateRegistry, arguments)
  }

  grammarForScopeName (scopeName) {
    return this.textmateRegistry.grammarForScopeName(scopeName)
  }

  addGrammar (grammar) {
    return this.textmateRegistry.addGrammar(grammar)
  }

  removeGrammar (grammar) {
    return this.textmateRegistry.removeGrammar(grammar)
  }

  removeGrammarForScopeName (scopeName) {
    return this.textmateRegistry.removeGrammarForScopeName(scopeName)
  }

  // Extended: Read a grammar asynchronously and add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  // * `callback` A {Function} to call when loaded with the following arguments:
  //   * `error` An {Error}, may be null.
  //   * `grammar` A {Grammar} or null if an error occured.
  loadGrammar (grammarPath, callback) {
    return this.textmateRegistry.loadGrammar(grammarPath, callback)
  }

  // Extended: Read a grammar synchronously and add it to this registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  //
  // Returns a {Grammar}.
  loadGrammarSync (grammarPath) {
    return this.textmateRegistry.loadGrammarSync(grammarPath)
  }

  // Extended: Read a grammar asynchronously but don't add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  // * `callback` A {Function} to call when read with the following arguments:
  //   * `error` An {Error}, may be null.
  //   * `grammar` A {Grammar} or null if an error occured.
  //
  // Returns undefined.
  readGrammar (grammarPath, callback) {
    return this.textmateRegistry.readGrammar(grammarPath, callback)
  }

  // Extended: Read a grammar synchronously but don't add it to the registry.
  //
  // * `grammarPath` A {String} absolute file path to a grammar file.
  //
  // Returns a {Grammar}.
  readGrammarSync (grammarPath) {
    return this.textmateRegistry.readGrammarSync(grammarPath)
  }

  createGrammar (grammarPath, params) {
    return this.textmateRegistry.createGrammar(grammarPath, params)
  }

  // Extended: Get all the grammars in this registry.
  //
  // Returns a non-empty {Array} of {Grammar} instances.
  getGrammars () {
    return this.textmateRegistry.getGrammars()
  }

  scopeForId (id) {
    return this.textmateRegistry.scopeForId(id)
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * @todo (imlucas) Figure out how to make nodemon or another
 * proc monitor work under electron.
 */
require('./scout-server-worker');
<commit_msg>:art: default NODE_ENV to production<commit_after>#!/usr/bin/env node
if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = 'production';
}

/**
 * @todo (imlucas) Figure out how to make nodemon or another
 * proc monitor work under electron.
 */
require('./scout-server-worker');
<|endoftext|>


<commit_before>/*
 * Default CKEditor preset and connector
 */

var ckeditorClasses = Array();
ckeditorClasses['editor'] = 'Full'; // Full editor
ckeditorClasses['medieditor'] = 'Medium'; // Medium editor
ckeditorClasses['minieditor'] = 'Basic'; // Mini editor

function ckeditorReplace() {
	var textareas = document.getElementsByTagName('textarea');
	for (var i = 0; i < textareas.length; i++) {
		if (ckeditorClasses[textareas[i].getAttribute('class')] !== undefined) {
			var textareasStyle = getComputedStyle(textareas[i], null) || textareas[i].currentStyle;
			CKEDITOR.replace(textareas[i], {height:textareasStyle.height, width:'100%', toolbar: ckeditorClasses[textareas[i].getAttribute('class')]});
		}
	}
}

if (typeof jQuery == 'undefined') {
	if (window.addEventListener) {
		window.addEventListener('load', ckeditorReplace, false);
	} else if (window.attachEvent) {
		window.attachEvent('onload', ckeditorReplace);
	} else {
		window.onload = ckeditorReplace;
	}
} else {
	$(document).ready(ckeditorReplace);
	ajaxSuccessHandlers.push(ckeditorReplace);
}
<commit_msg>Fix #1440: CKEditor initialization fail<commit_after>/*
 * Default CKEditor preset and connector
 */

var ckeditorClasses = Array();
ckeditorClasses['editor'] = 'Full'; // Full editor
ckeditorClasses['medieditor'] = 'Medium'; // Medium editor
ckeditorClasses['minieditor'] = 'Basic'; // Mini editor

function ckeditorReplace() {
	var textareas = document.getElementsByTagName('textarea');
	for (var i = 0; i < textareas.length; i++) {
		var classStr = textareas[i].getAttribute('class');
		if (classStr) {
			var classes = classStr.split(" ");
			for (var k = 0; k < classes.length; k++) {
				textareaClass = classes[k];
				if (ckeditorClasses[textareaClass] !== undefined) {
					var textareasStyle = getComputedStyle(textareas[i], null) || textareas[i].currentStyle;
					CKEDITOR.replace(textareas[i], {height:textareasStyle.height, width:'100%', toolbar: ckeditorClasses[textareaClass]});
				}
			}
		}
	}
}

if (typeof jQuery == 'undefined') {
	if (window.addEventListener) {
		window.addEventListener('load', ckeditorReplace, false);
	} else if (window.attachEvent) {
		window.attachEvent('onload', ckeditorReplace);
	} else {
		window.onload = ckeditorReplace;
	}
} else {
	$(document).ready(ckeditorReplace);
	ajaxSuccessHandlers.push(ckeditorReplace);
}
<|endoftext|>


<commit_before>var gulp         = require('gulp');
var browserSync  = require('browser-sync');
var autoprefixer = require('autoprefixer');
var concat       = require('gulp-concat');
var csscomb      = require('postcss-csscomb');
var cssnano      = require('cssnano');
var eslint       = require('gulp-eslint');
var imagemin     = require('gulp-imagemin');
var notify       = require('gulp-notify');
var plumber      = require('gulp-plumber');
var postcss      = require('gulp-postcss');
var sass         = require('gulp-sass');
var sourcemaps   = require('gulp-sourcemaps');
var uglify       = require('gulp-uglify');

var onError = function(err) {
  notify.onError({
    title:    "Error",
    message:  "<%= error %>",
  })(err);
  this.emit('end');
};

var plumberOptions = {
  errorHandler: onError,
};

gulp.task('css', function() {
  var sassOptions = {
    includePaths: [
      // 'node_modules/',
    ]
  };

  var postCSSOptions = require('./config.postcss.json');
  var postCSSProcessors = [
    autoprefixer(postCSSOptions.autoprefixer),
  ];

  return gulp.src('assets/_sass/**/*.scss')
    .pipe(plumber(plumberOptions))
    .pipe(sourcemaps.init())
    .pipe(sass(sassOptions))
    .pipe(postcss(postCSSProcessors))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('assets/css'));
});

gulp.task('dist:css', function() {
  var postCSSOptions = require('./config.postcss.dist.json');
  var postCSSProcessors = [
    csscomb(postCSSOptions['postcss-csscomb']),
    cssnano()
  ];

  return gulp.src('assets/css/**/*.css')
    .pipe(postcss(postCSSProcessors))
    .pipe(gulp.dest('dist/assets/css'));
});

gulp.task('eslint', function() {
  return gulp.src('assets/_js/**/*.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
});

gulp.task('js', ['eslint'], function() {
  return gulp.src([
      'assets/_js/app.js',
    ])
    .pipe(sourcemaps.init())
    .pipe(concat('app.js'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('assets/js'));
});

gulp.task('dist:js', function() {
  return gulp.src([
      'assets/js/**/*.js',
    ])
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'));
});

gulp.task('imagemin', function() {
  return gulp.src([
      'assets/images/*'
    ])
    .pipe(imagemin())
    .pipe(gulp.dest('dist/assets/images'));
});

gulp.task('watch', function() {
  var browserSyncConfig = require('./bs-config.js');

  browserSync.init(browserSyncConfig);

  gulp.watch('assets/_sass/**/*.scss', ['css']);
  gulp.watch('assets/_js/**/*.js', ['js']);
});

gulp.task('build', ['css', 'js']);

gulp.task('dist', ['build'], function() {
  gulp.start('dist:css');
  gulp.start('dist:js');
  gulp.start('imagemin');
});

gulp.task('default', ['build', 'watch']);
<commit_msg>gulp dist task does not include build.<commit_after>var gulp         = require('gulp');
var browserSync  = require('browser-sync');
var autoprefixer = require('autoprefixer');
var concat       = require('gulp-concat');
var csscomb      = require('postcss-csscomb');
var cssnano      = require('cssnano');
var eslint       = require('gulp-eslint');
var imagemin     = require('gulp-imagemin');
var notify       = require('gulp-notify');
var plumber      = require('gulp-plumber');
var postcss      = require('gulp-postcss');
var sass         = require('gulp-sass');
var sourcemaps   = require('gulp-sourcemaps');
var uglify       = require('gulp-uglify');

var onError = function(err) {
  notify.onError({
    title:    "Error",
    message:  "<%= error %>",
  })(err);
  this.emit('end');
};

var plumberOptions = {
  errorHandler: onError,
};

gulp.task('css', function() {
  var sassOptions = {
    includePaths: [
      // 'node_modules/',
    ]
  };

  var postCSSOptions = require('./config.postcss.json');
  var postCSSProcessors = [
    autoprefixer(postCSSOptions.autoprefixer),
  ];

  return gulp.src('assets/_sass/**/*.scss')
    .pipe(plumber(plumberOptions))
    .pipe(sourcemaps.init())
    .pipe(sass(sassOptions))
    .pipe(postcss(postCSSProcessors))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('assets/css'));
});

gulp.task('dist:css', function() {
  var postCSSOptions = require('./config.postcss.dist.json');
  var postCSSProcessors = [
    csscomb(postCSSOptions['postcss-csscomb']),
    cssnano()
  ];

  return gulp.src('assets/css/**/*.css')
    .pipe(postcss(postCSSProcessors))
    .pipe(gulp.dest('dist/assets/css'));
});

gulp.task('eslint', function() {
  return gulp.src('assets/_js/**/*.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
});

gulp.task('js', ['eslint'], function() {
  return gulp.src([
      'assets/_js/app.js',
    ])
    .pipe(sourcemaps.init())
    .pipe(concat('app.js'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('assets/js'));
});

gulp.task('dist:js', function() {
  return gulp.src([
      'assets/js/**/*.js',
    ])
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'));
});

gulp.task('imagemin', function() {
  return gulp.src([
      'assets/images/*'
    ])
    .pipe(imagemin())
    .pipe(gulp.dest('dist/assets/images'));
});

gulp.task('watch', function() {
  var browserSyncConfig = require('./bs-config.js');

  browserSync.init(browserSyncConfig);

  gulp.watch('assets/_sass/**/*.scss', ['css']);
  gulp.watch('assets/_js/**/*.js', ['js']);
});

gulp.task('build', ['css', 'js']);

gulp.task('dist', function() {
  gulp.start('dist:css');
  gulp.start('dist:js');
  gulp.start('imagemin');
});

gulp.task('default', ['build', 'watch']);
<|endoftext|>


<commit_before>'use strict';
var ip = require('ip');
var dns = require('dns');
var publicIp = require('public-ip');
var _ = require('lodash');

/**
 * Check whether or not an hostname refers to a private IP
 * @param  {String} hostname
 * @param  {Function} f(err: {error,null}, isPrivate: {boolean})
 */
var isPrivate = _.curry(function (checker, hostname, f) {
  try {
    dns.resolve(hostname, function (err, addresses) {
      if (err) {
        return setImmediate(f, err);
      }

      return checker(addresses, f);
    });
  } catch (err) {
    setImmediate(f, err);
  }
});

function IPisPrivate(ipAddr) {
  return ipAddr === '0.0.0.0' || ip.isPrivate(ipAddr);
}

/**
 * @param  {Array} addresses array of ip addr
 * @param  {Function} f(err, isPrivate) isPrivate will be `true` if at least one addr is private
 */
function checkIfAddressesArePrivate(addresses, f) {
  setImmediate(f, null, addresses.some(IPisPrivate));
}

/**
 * @param  {Array} addresses array of ip addr
 * @param  {Function} f(err, isPrivate) isPrivate will be `true` if at least one addr is private or is the public server IP
 */
function checkIfAddressesArePrivateIncludingPublicIp(addresses, f) {
  checkIfAddressesArePrivate(addresses, function (err, isPrivate) {
    if (err) {
      return setImmediate(f, err);
    }

    if (isPrivate === true) {
      // no need to check further, the IP is private
      return setImmediate(f, null, isPrivate);
    }

    // retrieve the Public IP
    getPublicIP(function (err, publicIp) {
      if (err) {
        return setImmediate(f, err);
      }

      f(null, addresses.some(function (ip) {
        return ip === publicIp;
      }));
    });
  });
}

function getPublicIP(f) {
  if (getPublicIP.PUBLIC_IP) {
    f(null, getPublicIP.PUBLIC_IP);
  }

  publicIp(function (err, ip) {
    if (err) {
      return f(err);
    }
    getPublicIP.PUBLIC_IP = ip;
    getPublicIP(f);
  });
}

getPublicIP.PUBLIC_IP = null;

module.exports = {
  isPrivate: isPrivate(checkIfAddressesArePrivate),
  isPrivateIncludingPublicIp: isPrivate(checkIfAddressesArePrivateIncludingPublicIp)
};
<commit_msg>fix(hostname-is-private): add return<commit_after>'use strict';
var ip = require('ip');
var dns = require('dns');
var publicIp = require('public-ip');
var _ = require('lodash');

/**
 * Check whether or not an hostname refers to a private IP
 * @param  {String} hostname
 * @param  {Function} f(err: {error,null}, isPrivate: {boolean})
 */
var isPrivate = _.curry(function (checker, hostname, f) {
  try {
    dns.resolve(hostname, function (err, addresses) {
      if (err) {
        return setImmediate(f, err);
      }

      return checker(addresses, f);
    });
  } catch (err) {
    setImmediate(f, err);
  }
});

function IPisPrivate(ipAddr) {
  return ipAddr === '0.0.0.0' || ip.isPrivate(ipAddr);
}

/**
 * @param  {Array} addresses array of ip addr
 * @param  {Function} f(err, isPrivate) isPrivate will be `true` if at least one addr is private
 */
function checkIfAddressesArePrivate(addresses, f) {
  setImmediate(f, null, addresses.some(IPisPrivate));
}

/**
 * @param  {Array} addresses array of ip addr
 * @param  {Function} f(err, isPrivate) isPrivate will be `true` if at least one addr is private or is the public server IP
 */
function checkIfAddressesArePrivateIncludingPublicIp(addresses, f) {
  checkIfAddressesArePrivate(addresses, function (err, isPrivate) {
    if (err) {
      return setImmediate(f, err);
    }

    if (isPrivate === true) {
      // no need to check further, the IP is private
      return setImmediate(f, null, isPrivate);
    }

    // retrieve the Public IP
    getPublicIP(function (err, publicIp) {
      if (err) {
        return setImmediate(f, err);
      }

      f(null, addresses.some(function (ip) {
        return ip === publicIp;
      }));
    });
  });
}

function getPublicIP(f) {
  if (getPublicIP.PUBLIC_IP) {
    return f(null, getPublicIP.PUBLIC_IP);
  }

  publicIp(function (err, ip) {
    if (err) {
      return f(err);
    }

    getPublicIP.PUBLIC_IP = ip;
    getPublicIP(f);
  });
}

getPublicIP.PUBLIC_IP = null;

module.exports = {
  isPrivate: isPrivate(checkIfAddressesArePrivate),
  isPrivateIncludingPublicIp: isPrivate(checkIfAddressesArePrivateIncludingPublicIp)
};
<|endoftext|>


<commit_before>var q = require('q');
require('mocha-as-promised')();

var chai=require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

function libPath(libFilePath){
  var pathToLib = '../lib/'
  return(pathToLib + libFilePath);
}

var auth = require(libPath('auth.js'));

var expect = require('chai').expect;

describe('auth', function(){
  var config;
  var configValidationFail;

  var modelStubSync = function(){
    var _modelData = {};
    return {
      save: function(key, values){
        _modelData[key] = values;
        return key;
      },
      get:  function(key){
        return _modelData[key];
      },
      all: function(){
        return _modelData;
      }
    };
  }();

  beforeEach(function(){
    config = {
      validator: function(email) { return email }
    };
    configValidationFail = {
      validator: function(email) { return null }
    }
  });

  it('sanity check', function(){
    expect(auth).to.exist;
  });

  it('is a function', function(){
    expect(auth).to.be.a('function');
  });

  // how to clone functions? until then clobbering occurs
//  it('can be configured without clobbering', function(){
//    var a = auth(config);
//    expect(a.config).to.eql(config);
//    expect(a.config).to.not.equal(config);
//  });

  it('is not a singleton', function(){
    var a1 = auth(config);
    var a2 = auth(configValidationFail);
    expect(a1.config).to.not.eql(a2.config);
  });

  describe('.request', function(){
    var req1, opts1;

    beforeEach(function(){
      var email1 = "email1";

      opts1 = {
        challenge: "who goes there?",
        response: "tis me.",
        listener: {}
      };

      req1 = {
        email: email1,
        challenge: opts1.challenge,
        response: opts1.response,
        listener: opts1.listener
      }
    });

    it('is a function', function(){
      expect(auth(config).request).to.be.a('function');
    });

    it('returns error if email is not a string', function(){
      var email = 32;
      expect( auth(config).request(email) ).to.be.instanceof(Error)
        .and.have.property('message', 'Invalid email, not a string');
    });

    describe('reqReceived', function(){

      it('returns email to  callback if request is valid', function(){
        var email = 'my_email';
        var callbackSpy = false;

        req1.listener.reqReceived = function(err, status) {
          callbackSpy = true;
          expect(status).to.eql(email);
        };

        expect( auth(config).request(email, req1) ).to.not.be.instanceof(Error)
        expect( callbackSpy).to.equal(true);
      });

      it('returns error to callback if email is not a string', function(){
        var email = 32;
        var errorMessage = 'Invalid email, not a string';
        var callbackSpy = false;

        req1.listener.reqReceived = function(err, status) {
          callbackSpy = true;
          expect(err).to.eql({error: errorMessage});
        };

        expect( auth(config).request(email, req1) ).to.be.instanceof(Error)
          .and.have.property('message', 'Invalid email, not a string');
        expect( callbackSpy).to.equal(true);

      });
    });

    describe('reqValidated', function() {

      describe('call validator', function(){

        it('calls the validator in the config options', function(){
          var avalidEmail = 'my_email';
          var aspy=false;

          var vConfig = {
            validator: function(email) {
              aspy=true;
              expect(email).to.eql(avalidEmail);
              return email
            }
          };

          expect( auth(vConfig).request(avalidEmail, req1)).to.not.be.instanceof(Error);
          expect( aspy).to.be.equal(true);
        });
      });

      describe('sync', function(){
        it('returns email to  callback if request is valid', function(done){
          var validEmail = 'my_valid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email) {
              spy=true;
              expect(email).to.eql(validEmail);
              return email
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve(true);
            expect(err).to.be.equal(null);
            expect(status).to.eql(validEmail);
          };

          expect( auth(vConfig).request(validEmail, req1) ).to.not.be.instanceof(Error)
          expect( spy).to.equal(true);
          statusPromise.then(function(result){
            expect(result).to.equal(true);
            done();
          });
        });

        it('returns error to  listener if email does not validate', function(done){
          var inValidEmail = 'my_invalid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email) {
              spy=true;
              expect(email).to.eql(inValidEmail);
              return null
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve(true);
            expect(err).to.be.eql({error: 'failed validation'});
            expect(status).to.eql(undefined);
          };

          expect( auth(vConfig).request(inValidEmail, req1) ).to.not.be.instanceof(Error)
          statusPromise.then(function(result){
            expect(result).to.equal(true);
            done();
          });
        });
      });

      describe('async', function(){
        it('returns email to  callback if request is valid', function(){
          var validEmail = 'my_valid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;
          var statusResult = false;

          var vConfig = {
            validator: function(email, cb) {
              spy=true;
              expect(email).to.eql(validEmail);
              cb(null, email);
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve([err, status]);
          };

          expect( auth(vConfig).request(validEmail, req1) ).to.not.be.instanceof(Error)
          statusPromise.then(function(result){
            statusResult = true;
            //expect(false).to.equal(true);
            //expect(result[1]).to.equal(validEmail);
            done();
          });
        });

        it('returns error to  listener if email does not validate', function(){
          var inValidEmail = 'my_invalid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email, cb) {
              spy=true;
              expect(email).to.eql(inValidEmail);
              cb({error: 'Email rejected'});
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve([err, status]);
            done();
          };

          expect( auth(vConfig).request(inValidEmail, req1) ).to.not.be.instanceof(Error)

          //a bit of a hack to get the assertions to be called
          return q.all([
            expect(statusPromise).to.eventually.be.an('Array'),
            expect(statusPromise.get(0)).to.eventually.eql({ error: 'Email rejected' }),
            expect(statusPromise.get(1)).to.eventually.be.undefined
          ]);
        });
      });
    });

    describe('model', function() {
      describe('sync', function(){
        describe('saving', function(){
          var validEmail;
          var mConfig;
          var authResp;

          beforeEach(function(){
            validEmail = 'email_to_persist'
            mConfig = {
              validator: function(email) {
                return email
              },
              model: modelStubSync
            };

            //create the request
            authResp = auth(mConfig).request(validEmail, req1)
          });

          it('does not error when requesting', function(){
            expect( authResp ).to.not.be.instanceof(Error);
          });

          it('saves email to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.email ).to.eql(validEmail);
          });

          it('saves challenge/response to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.challenge ).to.eql(req1.challenge);
            expect( record.response ).to.eql(req1.response);
          });

          it('saves a randomStr to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( typeof record.randomStr ).to.equal('string');
            expect( record.randomStr.length).to.equal(64);
          });

          it('saves a staleVerification to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.staleVerification).to.be.within(0, Infinity);
          });

          it('returns email to reqSaved callback when record saved', function(){
            var email = 'saved_email';
            var spy = false;
            var statusChecked = q.defer();
            var statusPromise = statusChecked.promise;

            req1.listener.reqSaved = function(err, status) {
              console.log('reqSaved called', err, status);
              statusChecked.resolve([err, status]);
              done();
            };

            console.log(req1.listener.reqSaved.toString());
            expect( auth(mConfig).request(email, req1) ).to.not.be.instanceof(Error)

            return q.all([
              expect(statusPromise).to.eventually.be.an('Array'),
              expect(statusPromise.get(0)).to.eventually.eql(null),
              expect(statusPromise.get(1)).to.eventually.eql(email)
            ]);
          });
        });
      });
    });
  });
});

<commit_msg>test for sync and async model passing<commit_after>var q = require('q');
require('mocha-as-promised')();

var chai=require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

function libPath(libFilePath){
  var pathToLib = '../lib/'
  return(pathToLib + libFilePath);
}

var auth = require(libPath('auth.js'));

var expect = require('chai').expect;

describe('auth', function(){
  var config;
  var configValidationFail;

  var modelStubSync = function(){
    var _modelData = {};
    return {
      save: function(key, values){
        _modelData[key] = values;
        return key;
      },
      get:  function(key){
        return _modelData[key];
      },
      all: function(){
        return _modelData;
      }
    };
  }();

  var modelStubAsync = function(){
    var _modelData = {};
    return {
      save: function(key, values, cb){
        _modelData[key] = values;
        cb(null, key);
      },
      get:  function(key, cb){
        cb(null, _modelData[key]);
      },
      all: function(cb){
        cb(null, _modelData);
      }
    };
  }();

  beforeEach(function(){
    config = {
      validator: function(email) { return email }
    };
    configValidationFail = {
      validator: function(email) { return null }
    }
  });

  it('sanity check', function(){
    expect(auth).to.exist;
  });

  it('is a function', function(){
    expect(auth).to.be.a('function');
  });

  // how to clone functions? until then clobbering occurs
//  it('can be configured without clobbering', function(){
//    var a = auth(config);
//    expect(a.config).to.eql(config);
//    expect(a.config).to.not.equal(config);
//  });

  it('is not a singleton', function(){
    var a1 = auth(config);
    var a2 = auth(configValidationFail);
    expect(a1.config).to.not.eql(a2.config);
  });

  describe('.request', function(){
    var req1, opts1;

    beforeEach(function(){
      var email1 = "email1";

      opts1 = {
        challenge: "who goes there?",
        response: "tis me.",
        listener: {}
      };

      req1 = {
        email: email1,
        challenge: opts1.challenge,
        response: opts1.response,
        listener: opts1.listener
      }
    });

    it('is a function', function(){
      expect(auth(config).request).to.be.a('function');
    });

    it('returns error if email is not a string', function(){
      var email = 32;
      expect( auth(config).request(email) ).to.be.instanceof(Error)
        .and.have.property('message', 'Invalid email, not a string');
    });

    describe('reqReceived', function(){

      it('returns email to  callback if request is valid', function(){
        var email = 'my_email';
        var callbackSpy = false;

        req1.listener.reqReceived = function(err, status) {
          callbackSpy = true;
          expect(status).to.eql(email);
        };

        expect( auth(config).request(email, req1) ).to.not.be.instanceof(Error)
        expect( callbackSpy).to.equal(true);
      });

      it('returns error to callback if email is not a string', function(){
        var email = 32;
        var errorMessage = 'Invalid email, not a string';
        var callbackSpy = false;

        req1.listener.reqReceived = function(err, status) {
          callbackSpy = true;
          expect(err).to.eql({error: errorMessage});
        };

        expect( auth(config).request(email, req1) ).to.be.instanceof(Error)
          .and.have.property('message', 'Invalid email, not a string');
        expect( callbackSpy).to.equal(true);

      });
    });

    describe('reqValidated', function() {

      describe('call validator', function(){

        it('calls the validator in the config options', function(){
          var avalidEmail = 'my_email';
          var aspy=false;

          var vConfig = {
            validator: function(email) {
              aspy=true;
              expect(email).to.eql(avalidEmail);
              return email
            }
          };

          expect( auth(vConfig).request(avalidEmail, req1)).to.not.be.instanceof(Error);
          expect( aspy).to.be.equal(true);
        });
      });

      describe('sync', function(){
        it('returns email to  callback if request is valid', function(done){
          var validEmail = 'my_valid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email) {
              spy=true;
              expect(email).to.eql(validEmail);
              return email
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve(true);
            expect(err).to.be.equal(null);
            expect(status).to.eql(validEmail);
          };

          expect( auth(vConfig).request(validEmail, req1) ).to.not.be.instanceof(Error)
          expect( spy).to.equal(true);
          statusPromise.then(function(result){
            expect(result).to.equal(true);
            done();
          });
        });

        it('returns error to  listener if email does not validate', function(done){
          var inValidEmail = 'my_invalid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email) {
              spy=true;
              expect(email).to.eql(inValidEmail);
              return null
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve(true);
            expect(err).to.be.eql({error: 'failed validation'});
            expect(status).to.eql(undefined);
          };

          expect( auth(vConfig).request(inValidEmail, req1) ).to.not.be.instanceof(Error)
          statusPromise.then(function(result){
            expect(result).to.equal(true);
            done();
          });
        });
      });

      describe('async', function(){
        it('returns email to  callback if request is valid', function(){
          var validEmail = 'my_valid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;
          var statusResult = false;

          var vConfig = {
            validator: function(email, cb) {
              spy=true;
              expect(email).to.eql(validEmail);
              cb(null, email);
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve([err, status]);
          };

          expect( auth(vConfig).request(validEmail, req1) ).to.not.be.instanceof(Error)
          statusPromise.then(function(result){
            statusResult = true;
            //expect(false).to.equal(true);
            //expect(result[1]).to.equal(validEmail);
            done();
          });
        });

        it('returns error to  listener if email does not validate', function(){
          var inValidEmail = 'my_invalid_email';
          var spy = false;
          var statusChecked = q.defer();
          var statusPromise = statusChecked.promise;

          var vConfig = {
            validator: function(email, cb) {
              spy=true;
              expect(email).to.eql(inValidEmail);
              cb({error: 'Email rejected'});
            }
          };

          req1.listener.reqValidated = function(err, status) {
            statusChecked.resolve([err, status]);
            done();
          };

          expect( auth(vConfig).request(inValidEmail, req1) ).to.not.be.instanceof(Error)

          //a bit of a hack to get the assertions to be called
          return q.all([
            expect(statusPromise).to.eventually.be.an('Array'),
            expect(statusPromise.get(0)).to.eventually.eql({ error: 'Email rejected' }),
            expect(statusPromise.get(1)).to.eventually.be.undefined
          ]);
        });
      });
    });

    describe('model', function() {
      describe('sync', function(){
        describe('saving', function(){
          var validEmail;
          var mConfig;
          var authResp;

          beforeEach(function(){
            validEmail = 'email_to_persist'
            mConfig = {
              validator: function(email) {
                return email
              },
              model: modelStubSync
            };

            //create the request
            authResp = auth(mConfig).request(validEmail, req1)
          });

          it('does not error when requesting', function(){
            expect( authResp ).to.not.be.instanceof(Error);
          });

          it('saves email to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.email ).to.eql(validEmail);
          });

          it('saves challenge/response to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.challenge ).to.eql(req1.challenge);
            expect( record.response ).to.eql(req1.response);
          });

          it('saves a randomStr to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( typeof record.randomStr ).to.equal('string');
            expect( record.randomStr.length).to.equal(64);
          });

          it('saves a staleVerification to the model', function(){
            var record = mConfig.model.get(validEmail);
            expect( record.staleVerification).to.be.within(0, Infinity);
          });

          it('returns email to reqSaved callback when record saved', function(){
            var email = 'saved_email';
            var spy = false;
            var statusChecked = q.defer();
            var statusPromise = statusChecked.promise;

            req1.listener.reqSaved = function(err, status) {
              console.log('reqSaved called', err, status);
              statusChecked.resolve([err, status]);
              done();
            };

            console.log(req1.listener.reqSaved.toString());
            expect( auth(mConfig).request(email, req1) ).to.not.be.instanceof(Error)

            return q.all([
              expect(statusPromise).to.eventually.be.an('Array'),
              expect(statusPromise.get(0)).to.eventually.eql(null),
              expect(statusPromise.get(1)).to.eventually.eql(email)
            ]);
          });
        });
      });

      //convert to async model for testing
      describe('async', function(){
        describe('saving', function(){
          var validEmail;
          var mConfig;
          var authResp;

          beforeEach(function(){
            validEmail = 'email_to_persist'
            mConfig = {
              validator: function(email) {
                return email
              },
              model: modelStubAsync
            };

            //create the request
            auth(mConfig).request(validEmail, req1);
          });

          it('does not error when requesting', function(){
            expect( authResp ).to.not.be.instanceof(Error);
          });

          it('saves email to the model', function(){
            mConfig.model.get(validEmail, function(err, record){
              expect(err).to.equal(null);
              expect(record.email).to.equal(validEmail);
            });
          });

          it('saves challenge/response to the model', function(){
            mConfig.model.get(validEmail, function(err, record){
              expect( record.challenge ).to.eql(req1.challenge);
              expect( record.response ).to.eql(req1.response);
            });
          });

          it('saves a randomStr to the model', function(){
            mConfig.model.get(validEmail, function(err, record){
              expect( typeof record.randomStr ).to.equal('string');
              expect( record.randomStr.length).to.equal(64);
            });
          });

          it('saves a staleVerification to the model', function(){
            mConfig.model.get(validEmail, function(err, record){
              expect( record.staleVerification).to.be.within(0, Infinity);
            });
          });

          it('returns email to reqSaved callback when record saved', function(){
            var email = 'saved_email';
            var spy = false;
            var statusChecked = q.defer();
            var statusPromise = statusChecked.promise;

            req1.listener.reqSaved = function(err, status) {
              console.log('reqSaved called', err, status);
              statusChecked.resolve([err, status]);
              done();
            };

            console.log(req1.listener.reqSaved.toString());
            expect( auth(mConfig).request(email, req1) ).to.not.be.instanceof(Error)

            return q.all([
              expect(statusPromise).to.eventually.be.an('Array'),
              expect(statusPromise.get(0)).to.eventually.eql(null),
              expect(statusPromise.get(1)).to.eventually.eql(email)
            ]);
          });
        });
      });

    });
  });
});

<|endoftext|>


<commit_before>/* global Canvasimo */

'use strict';

(function () {

  function setupRequestAnimationFrame () {
    var lastTime = 0;
    var vendors = ['webkit', 'moz', 'ms', 'o'];

    for (var i = 0; !window.requestAnimationFrame && i < vendors.length; i += 1) {
      var vendor = vendors[i];
      window.requestAnimationFrame = window[vendor + 'RequestAnimationFrame'];
      window.cancelAnimationFrame = window[vendor + 'CancelAnimationFrame'] ||
        window[vendor + 'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = function (callback) {
        var now = new Date().getTime();
        var nextTime = Math.max(0, 16 - (now - lastTime));

        var id = window.setTimeout(function () {
          callback(now + nextTime);
        }, nextTime);

        lastTime = now + nextTime;
        return id;
      };
    }

    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = function (id) {
        clearTimeout(id);
      };
    }
  }

  setupRequestAnimationFrame();

  var element = document.getElementById('canvas');
  var parent = element.parentNode;
  var canvas = new Canvasimo(element);

  var raf;
  var lastPos;
  var velocity = 0;
  var tree;

  function createTree () {
    return {
      length: 0,
      targetLength: 30 + Math.random() * 5,
      angle: canvas.getRadiansFromDegrees(-90 + Math.random() * 10 - 5),
      children: null
    };
  }

  function drawBranch (branch, depth, maxBranchDepth) {
    var treeDone;
    var strokeWidth = Math.max(maxBranchDepth / (depth + 1) / 2, 0.1);

    if (branch.length < branch.targetLength) {
      branch.length = Math.min(branch.length + branch.targetLength / 20, branch.targetLength);
    } else if (!branch.children && depth === maxBranchDepth && branch.length === branch.targetLength) {
      treeDone = true;
    } else if (!branch.children && depth < maxBranchDepth) {
      branch.children = [];
      var childCount = 2 + Math.floor(Math.random() * 2);

      for (var c = 0; c < childCount; c += 1) {
        branch.children.push({
          length: 0,
          targetLength: branch.targetLength * 0.75 + Math.random() * branch.targetLength * 0.25,
          angle: canvas.getRadiansFromDegrees(Math.random() * 90 - 45),
          children: null
        });
      }
    }

    canvas
      .save()
      .rotate(branch.angle + canvas.getRadiansFromDegrees(velocity * 0.01))
      .setStrokeWidth(strokeWidth)
      .beginPath()
      .plotClosedPath([
        0, -strokeWidth / 4,
        branch.length, 0,
        branch.length, 0,
        0, strokeWidth / 4
      ])
      .fill('black')
      .stroke('black')
      .closePath()
      .translate(branch.length, 0);

    if (branch.children) {
      for (var i = 0; i < branch.children.length; i += 1) {
        var child = branch.children[i];

        var branchDone = drawBranch(child, depth + 1, maxBranchDepth);

        if (treeDone !== false || branchDone === false) {
          treeDone = branchDone;
        }
      }
    }

    canvas.restore();

    return treeDone;
  }

  function draw () {
    window.cancelAnimationFrame(raf);

    canvas
      .clearCanvas()
      .setStrokeCap('round')
      .setStrokeJoin('round')
      .translate(canvas.getWidth() / 2, canvas.getHeight());

    var treeDone = drawBranch(tree, 0, 7);

    if (!treeDone || Math.abs(velocity) > 0.5) {
      raf = window.requestAnimationFrame(draw);
    }

    velocity *= 0.95;
  }

  function setCanvasSize () {
    canvas
      .setWidth(parent.clientWidth);

    window.requestAnimationFrame(draw);
  }

  function mouseMove (event) {
    var thisPos = event.clientX;

    if (typeof lastPos !== 'undefined') {
      velocity += (thisPos - lastPos) * (event.type.indexOf('touch') >= 0 ? 2 : 1);
    }

    lastPos = thisPos;

    raf = window.requestAnimationFrame(draw);
  }

  function touchMove (event) {
    if (event.touches[0]) {
      event.clientX = event.touches[0].clientX;
      event.clientY = event.touches[0].clientY;
      mouseMove(event);
    }
  }

  function touchEnd () {
    lastPos = undefined;
  }

  function reset () {
    tree = createTree();
    window.requestAnimationFrame(draw);
  }

  element.addEventListener('click', reset);
  element.addEventListener('mousemove', mouseMove);
  element.addEventListener('touchmove', touchMove);
  element.addEventListener('touchend', touchEnd);
  window.addEventListener('resize', setCanvasSize);

  tree = createTree();
  setCanvasSize();

})();
<commit_msg>Add some smaller trees<commit_after>/* global Canvasimo */

'use strict';

(function () {

  function setupRequestAnimationFrame () {
    var lastTime = 0;
    var vendors = ['webkit', 'moz', 'ms', 'o'];

    for (var i = 0; !window.requestAnimationFrame && i < vendors.length; i += 1) {
      var vendor = vendors[i];
      window.requestAnimationFrame = window[vendor + 'RequestAnimationFrame'];
      window.cancelAnimationFrame = window[vendor + 'CancelAnimationFrame'] ||
        window[vendor + 'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = function (callback) {
        var now = new Date().getTime();
        var nextTime = Math.max(0, 16 - (now - lastTime));

        var id = window.setTimeout(function () {
          callback(now + nextTime);
        }, nextTime);

        lastTime = now + nextTime;
        return id;
      };
    }

    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = function (id) {
        clearTimeout(id);
      };
    }
  }

  setupRequestAnimationFrame();

  var element = document.getElementById('canvas');
  var parent = element.parentNode;
  var canvas = new Canvasimo(element);

  var raf;
  var lastPos;
  var velocity = 0;
  var tree, tree1, tree2;

  function createTree (length) {
    return {
      length: 0,
      targetLength: length + Math.random() * 5,
      angle: canvas.getRadiansFromDegrees(-90 + Math.random() * 10 - 5),
      children: null
    };
  }

  function drawBranch (branch, depth, maxBranchDepth) {
    var treeDone;
    var strokeWidth = Math.max(maxBranchDepth / (depth + 1) / 2, 0.1);

    if (branch.length < branch.targetLength) {
      branch.length = Math.min(branch.length + branch.targetLength / 20, branch.targetLength);
    } else if (!branch.children && depth === maxBranchDepth && branch.length === branch.targetLength) {
      treeDone = true;
    } else if (!branch.children && depth < maxBranchDepth) {
      branch.children = [];
      var childCount = 2 + Math.floor(Math.random() * 2);

      for (var c = 0; c < childCount; c += 1) {
        branch.children.push({
          length: 0,
          targetLength: branch.targetLength * 0.75 + Math.random() * branch.targetLength * 0.25,
          angle: canvas.getRadiansFromDegrees(Math.random() * 90 - 45),
          children: null
        });
      }
    }

    canvas
      .save()
      .rotate(branch.angle + canvas.getRadiansFromDegrees(velocity * 0.01))
      .setStrokeWidth(strokeWidth)
      .beginPath()
      .plotClosedPath([
        0, -strokeWidth / 4,
        branch.length, 0,
        branch.length, 0,
        0, strokeWidth / 4
      ])
      .fill('black')
      .stroke('black')
      .closePath()
      .translate(branch.length, 0);

    if (branch.children) {
      for (var i = 0; i < branch.children.length; i += 1) {
        var child = branch.children[i];

        var branchDone = drawBranch(child, depth + 1, maxBranchDepth);

        if (treeDone !== false || branchDone === false) {
          treeDone = branchDone;
        }
      }
    }

    canvas.restore();

    return treeDone;
  }

  function draw () {
    window.cancelAnimationFrame(raf);

    canvas
      .clearCanvas()
      .setStrokeCap('round')
      .setStrokeJoin('round')
      .translate(canvas.getWidth() / 2, canvas.getHeight());

    var treeDone = drawBranch(tree, 0, 7);
    canvas.translate(- canvas.getWidth() / 4, 0)
    var tree1Done = drawBranch(tree1, 0, 4);
    canvas.translate(canvas.getWidth() / 2, 0)
    var tree2Done = drawBranch(tree2, 0, 4);

    if (!treeDone || !tree1Done || !tree2Done || Math.abs(velocity) > 0.5) {
      raf = window.requestAnimationFrame(draw);
    }

    velocity *= 0.95;
  }

  function setCanvasSize () {
    canvas
      .setWidth(parent.clientWidth);

    window.requestAnimationFrame(draw);
  }

  function mouseMove (event) {
    var thisPos = event.clientX;

    if (typeof lastPos !== 'undefined') {
      velocity += (thisPos - lastPos) * (event.type.indexOf('touch') >= 0 ? 2 : 1);
    }

    lastPos = thisPos;

    raf = window.requestAnimationFrame(draw);
  }

  function touchMove (event) {
    if (event.touches[0]) {
      event.clientX = event.touches[0].clientX;
      event.clientY = event.touches[0].clientY;
      mouseMove(event);
    }
  }

  function touchEnd () {
    lastPos = undefined;
  }

  function reset () {
    tree = createTree(30);
    tree1 = createTree(20);
    tree2 = createTree(20);
    window.requestAnimationFrame(draw);
  }

  element.addEventListener('click', reset);
  element.addEventListener('mousemove', mouseMove);
  element.addEventListener('touchmove', touchMove);
  element.addEventListener('touchend', touchEnd);
  window.addEventListener('resize', setCanvasSize);

  tree = createTree(30);
  tree1 = createTree(20);
  tree2 = createTree(20);
  setCanvasSize();

})();
<|endoftext|>