<commit_before>// ==========================================
// RECESS
// CORE: The core class definition
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under the Apache License v2.0
// http://www.apache.org/licenses/LICENSE-2.0
// ==========================================

'use strict'

var _ = require('underscore')
  , colors = require('colors')
  , less = require('less')
  , util = require('./util')
  , path = require('path')
  , fs = require('fs')

// core class defintion
function RECESS(path, options, callback) {
  this.path = path
  this.output = []
  this.errors = []
  this.options = _.extend({}, RECESS.DEFAULTS, options)
  path && this.read()
  this.callback = callback
}

// instance methods
RECESS.prototype = {

  constructor: RECESS

, log: function (str, force) {

    if (this.options.stripColors) str = str.stripColors

    // if compiling only write with force flag
    if (!this.options.compile || force) {
      this.options.cli ? console.log(str) : this.output.push(str)
    }

  }

, read: function () {
    var that = this

    // try to read data from path
    fs.readFile(this.path, 'utf8', function (err, data) {

      //  if err, exit with could not read message
      if (err) {
        that.errors.push(err)
        that.log('Error reading file: '.red + that.path.grey + '\n', true)
        return that.callback && that.callback()
      }

      // set instance data
      that.data = data

      // parse data
      that.parse()

    })
  }

, parse: function () {
    var that = this
      , options = {
          paths: [path.dirname(this.path)]
        , optimization: 0
        , filename: this.path && this.path.replace(/.*(?=\/)\//, '')
        }

    // try to parse with less parser
    try {

      // instantiate new parser with options
      new less.Parser(options)

        // parse data into tree
        .parse(this.data, function (err, tree) {

          if (err) {
            // push to errors array
            that.errors.push(err)

            if (err.type == 'Parse') {
              // parse error
              that.log("Parser error".red + (err.filename ? ' in ' + err.filename : '') + '\n')
            } else {
              // other exception
              that.log(err.name.red + ": " + err.message + ' of ' + err.filename.yellow + '\n')
            }

            // if extract - then log it
            err.extract && err.extract.forEach(function (line, index) {
              that.log(util.padLine(err.line + index) + line)
            })

            // add extra line for readability after error log
            that.log(" ")

            // exit with callback if present
            return that.callback && that.callback()
          }

          // test to see if file has a less extension
          if (/less$/.test(that.path) && !that.parsed) {

            // if it's a LESS file, we flatten it
            that.data = tree.toCSS({})

            // set parse to true so as to not infinitely reparse less files
            that.parsed = true

            // reparse less file
            return that.parse()
          }

          // set definitions to parse tree
          that.definitions = tree.rules

          // validation defintions
          that.options.compile ? that.compile() : that.validate()
        })

    } catch (err) {

      // less exploded trying to parse the file (╯°□°）╯︵ ┻━┻
      // push to errors array
      that.errors.push(err)

      // log a message trying to explain why
      that.log(
          "Parse error".red
        + ": "
        + err.message
        + " on line "
        + util.getLine(err.index, this.data)
      )

      // exit with callback if present
      this.callback && this.callback()
    }
  }

, compile: function () {
    var that = this
      , key
      , css

    // activate all relevant compilers
    Object.keys(this.options).forEach(function (key) {
      that.options[key]
        && RECESS.COMPILERS[key]
        && RECESS.COMPILERS[key].on.call(that)
    })

    // iterate over defintions and compress them (join with new lines)
    css = this.definitions.map(function (def) {
      return def.toCSS([[]], { data: that.data, compress: that.options.compress })
    }).join(this.options.compress ? '' : '\n')

    // minify with cssmin
    if (that.options.compress) css = require('./min').compressor.cssmin(css)

    // deactivate all relevant compilers
    Object.keys(this.options).reverse().forEach(function (key) {
      that.options[key]
        && RECESS.COMPILERS[key]
        && RECESS.COMPILERS[key].off()
    })

    // cleanup trailing newlines
    css = css.replace(/[\n\s\r]*$/, '')

    // output css
    this.log(css, true)

    // callback and exit
    this.callback && this.callback()
  }

, validate: function () {
    var failed
      , key

    // iterate over instance options
    for (key in this.options) {

      // if option has a validation, then we test it
      this.options[key]
        && RECESS.RULES[key]
        && !this.test(RECESS.RULES[key])
        && (failed = true)

    }

    // exit with failed flag to validateStatus
    this.validateStatus(failed)
  }

, test: function (validation) {
    var l = this.definitions.length
      , i = 0
      , isValid = true
      , rule
      , def
      , j
      , k

    // test each definition against a given validation
    for (; i < l; i++) {
      def = this.definitions[i]
      if (!validation(def, this.data)) isValid = false
    }

    // return valid state
    return isValid
  }

, validateStatus: function (failed) {
    var that = this
      , fails

    if (failed) {

      // count errors
      fails = util.countErrors(this.definitions)

      // log file overview
      this.log('FILE: ' + this.path.cyan)
      this.log('STATUS: ' + 'Busted'.magenta)
      this.log('FAILURES: ' + (fails + ' failure' + (fails > 1 ? 's' : '')).magenta + '\n')

      // iterate through each definition
      this.definitions.forEach(function (def) {

        // if there's an error, log the error and optional err.extract
        def.errors
          && def.errors.length
          && def.errors.forEach(function (err) {
               that.log(err.message)
               err.extract && that.log(err.extract + '\n')
             })
      })

    } else {
      // it was a success - let the user know!
      this.log('FILE: ' + this.path.cyan)
      this.log('STATUS: ' + 'Perfect!\n'.yellow)
    }

    // callback and exit
    this.callback && this.callback()
  }

}

// import validation rules
RECESS.RULES = {}

fs.readdirSync(path.join(__dirname, 'lint')).forEach(function (name) {
  var camelName = name
    .replace(/(\-[a-z])/gi, function ($1) { return $1.toUpperCase().replace('-', '') })
    .replace(/\.js$/, '')
  RECESS.RULES[camelName] = require(path.join(__dirname, 'lint', name))
})

// import compilers
RECESS.COMPILERS = {}

fs.readdirSync(path.join(__dirname, 'compile')).forEach(function (name) {
  var camelName = name
    .replace(/(\-[a-z])/gi, function ($1) { return $1.toUpperCase().replace('-', '') })
    .replace(/\.js$/, '')
  RECESS.COMPILERS[camelName] = require(path.join(__dirname, 'compile', name))
})

// export class
module.exports = RECESS<commit_msg>Forked solution for #64<commit_after>// ==========================================
// RECESS
// CORE: The core class definition
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under the Apache License v2.0
// http://www.apache.org/licenses/LICENSE-2.0
// ==========================================

'use strict'

var _ = require('underscore')
  , colors = require('colors')
  , less = require('less')
  , util = require('./util')
  , path = require('path')
  , fs = require('fs')

// core class defintion
function RECESS(path, options, callback) {
  this.path = path
  this.output = []
  this.errors = []
  this.options = _.extend({}, RECESS.DEFAULTS, options)
  path && this.read()
  this.callback = callback
}

// instance methods
RECESS.prototype = {

  constructor: RECESS

, log: function (str, force) {

    if (this.options.stripColors) str = str.stripColors

    // if compiling only write with force flag
    if (!this.options.compile || force) {
      this.options.cli ? that.log(str) : this.output.push(str)
    }

  }

, read: function () {
    var that = this

    // try to read data from path
    fs.readFile(this.path, 'utf8', function (err, data) {

      //  if err, exit with could not read message
      if (err) {
        that.errors.push(err)
        that.log('Error reading file: '.red + String(that.path).grey + '\n', true)
        return that.callback && that.callback()
      }

      // set instance data
      that.data = data

      // parse data
      that.parse()

    })
  }

, parse: function () {
    var that = this
      , options = {
          paths: [path.dirname(this.path)]
        , optimization: 0
        , filename: this.path && this.path.replace(/.*(?=\/)\//, '')
        }

    // try to parse with less parser
    try {

      // instantiate new parser with options
      new less.Parser(options)

        // parse data into tree
        .parse(this.data, function (err, tree) {

          if (err) {
            // push to errors array
            that.errors.push(err)

            if (err.type == 'Parse') {
              // parse error
              that.log("Parser error".red + (err.filename ? ' in ' + err.filename : '') + '\n')
            } else {
              // other exception
              that.log(String(err.name).red + ": " + err.message + ' of ' + String(err.filename).yellow + '\n')
            }

            // if extract - then log it
            err.extract && err.extract.forEach(function (line, index) {
              that.log(util.padLine(err.line + index) + line)
            })

            // add extra line for readability after error log
            that.log(" ")

            // exit with callback if present
            return that.callback && that.callback()
          }

          // test to see if file has a less extension
          if (/less$/.test(that.path) && !that.parsed) {

            // if it's a LESS file, we flatten it
            that.data = tree.toCSS({})

            // set parse to true so as to not infinitely reparse less files
            that.parsed = true

            // reparse less file
            return that.parse()
          }

          // set definitions to parse tree
          that.definitions = tree.rules

          // validation defintions
          that.options.compile ? that.compile() : that.validate()
        })

    } catch (err) {

      // less exploded trying to parse the file (╯°□°）╯︵ ┻━┻
      // push to errors array
      that.errors.push(err)

      // log a message trying to explain why
      that.log(
          "Parse error".red
        + ": "
        + err.message
        + " on line "
        + util.getLine(err.index, this.data)
      )

      // exit with callback if present
      this.callback && this.callback()
    }
  }

, compile: function () {
    var that = this
      , key
      , css

    // activate all relevant compilers
    Object.keys(this.options).forEach(function (key) {
      that.options[key]
        && RECESS.COMPILERS[key]
        && RECESS.COMPILERS[key].on.call(that)
    })

    // iterate over defintions and compress them (join with new lines)
    css = this.definitions.map(function (def) {
      return def.toCSS([[]], { data: that.data, compress: that.options.compress })
    }).join(this.options.compress ? '' : '\n')

    // minify with cssmin
    if (that.options.compress) css = require('./min').compressor.cssmin(css)

    // deactivate all relevant compilers
    Object.keys(this.options).reverse().forEach(function (key) {
      that.options[key]
        && RECESS.COMPILERS[key]
        && RECESS.COMPILERS[key].off()
    })

    // cleanup trailing newlines
    css = css.replace(/[\n\s\r]*$/, '')

    // output css
    this.log(css, true)

    // callback and exit
    this.callback && this.callback()
  }

, validate: function () {
    var failed
      , key

    // iterate over instance options
    for (key in this.options) {

      // if option has a validation, then we test it
      this.options[key]
        && RECESS.RULES[key]
        && !this.test(RECESS.RULES[key])
        && (failed = true)

    }

    // exit with failed flag to validateStatus
    this.validateStatus(failed)
  }

, test: function (validation) {
    var l = this.definitions.length
      , i = 0
      , isValid = true
      , rule
      , def
      , j
      , k

    // test each definition against a given validation
    for (; i < l; i++) {
      def = this.definitions[i]
      if (!validation(def, this.data)) isValid = false
    }

    // return valid state
    return isValid
  }

, validateStatus: function (failed) {
    var that = this
      , fails

    if (failed) {

      // count errors
      fails = util.countErrors(this.definitions)

      // log file overview
      this.log('FILE: ' + this.path.cyan)
      this.log('STATUS: ' + 'Busted'.magenta)
      this.log('FAILURES: ' + (fails + ' failure' + (fails > 1 ? 's' : '')).magenta + '\n')

      // iterate through each definition
      this.definitions.forEach(function (def) {

        // if there's an error, log the error and optional err.extract
        def.errors
          && def.errors.length
          && def.errors.forEach(function (err) {
               that.log(err.message)
               err.extract && that.log(err.extract + '\n')
             })
      })

    } else {
      // it was a success - let the user know!
      this.log('FILE: ' + this.path.cyan)
      this.log('STATUS: ' + 'Perfect!\n'.yellow)
    }

    // callback and exit
    this.callback && this.callback()
  }

}

// import validation rules
RECESS.RULES = {}

fs.readdirSync(path.join(__dirname, 'lint')).forEach(function (name) {
  var camelName = name
    .replace(/(\-[a-z])/gi, function ($1) { return $1.toUpperCase().replace('-', '') })
    .replace(/\.js$/, '')
  RECESS.RULES[camelName] = require(path.join(__dirname, 'lint', name))
})

// import compilers
RECESS.COMPILERS = {}

fs.readdirSync(path.join(__dirname, 'compile')).forEach(function (name) {
  var camelName = name
    .replace(/(\-[a-z])/gi, function ($1) { return $1.toUpperCase().replace('-', '') })
    .replace(/\.js$/, '')
  RECESS.COMPILERS[camelName] = require(path.join(__dirname, 'compile', name))
})

// export class
module.exports = RECESS<|endoftext|>


<commit_before>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // Are regexes type function?
  var regexIsFunction = typeof /x/ === 'function';

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  var isBoolean  = buildPrimitiveClassCheck('boolean', ClassNames[0]);
  var isNumber   = buildPrimitiveClassCheck('number',  ClassNames[1]);
  var isString   = buildPrimitiveClassCheck('string',  ClassNames[2]);

  var isArray    = buildClassCheck(ClassNames[3]);
  var isDate     = buildClassCheck(ClassNames[4]);
  var isRegExp   = buildClassCheck(ClassNames[5]);

  var isFunction = function(obj) {
    // Extra check for environments where regexes are type "function".
    return typeof obj === 'function' && (!regexIsFunction || !isRegExp(obj));
  };

  typeChecks[ClassNames[6]] = isFunction;

  function isClass(obj, klass, cached) {
    var k = cached || className(obj);
    return k === '[object '+klass+']';
  }

  function buildClassCheck(klass) {
    var fn = (klass === 'Array' && array.isArray) || function(obj, cached) {
      return isClass(obj, klass, cached);
    };
    typeChecks[klass] = fn;
    return fn;
  }

  function buildPrimitiveClassCheck(type, klass) {
    var fn = function(obj) {
      if(isObjectType(obj)) {
        return isClass(obj, klass);
      }
      return typeof obj === type;
    }
    typeChecks[klass] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(isFunction(override)) {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function hasProperty(obj, prop) {
    return !isPrimitiveType(obj) && prop in obj;
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  function isObjectType(obj) {
    // 1. Check for null
    // 2. Check for regexes in environments where they are "functions".
    return !!obj && (typeof obj === 'object' || (regexIsFunction && isRegExp(obj)));
  }

  function isPrimitiveType(obj) {
    var type = typeof obj;
    return obj == null || type === 'string' || type === 'number' || type === 'boolean';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    var result = '';
    if(isUndefined(times)) {
      times = 1;
    }
    while(times-- > 0) {
      result += str;
    }
    return result;
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/\'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(a === b) {
      // Return quickly up front when matching by reference,
      // but be careful about 0 !== -0.
      return a !== 0 || 1 / a === 1 / b;
    } else if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    }
    return false;
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<commit_msg>adding an optional target for sugarRestore<commit_after>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // Are regexes type function?
  var regexIsFunction = typeof /x/ === 'function';

  // Internal hasOwnProperty
  var internalHasOwnProperty = object.prototype.hasOwnProperty;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Boolean,Number,String,Array,Date,RegExp,Function'.split(',');

  var isBoolean  = buildPrimitiveClassCheck('boolean', ClassNames[0]);
  var isNumber   = buildPrimitiveClassCheck('number',  ClassNames[1]);
  var isString   = buildPrimitiveClassCheck('string',  ClassNames[2]);

  var isArray    = buildClassCheck(ClassNames[3]);
  var isDate     = buildClassCheck(ClassNames[4]);
  var isRegExp   = buildClassCheck(ClassNames[5]);

  var isFunction = function(obj) {
    // Extra check for environments where regexes are type "function".
    return typeof obj === 'function' && (!regexIsFunction || !isRegExp(obj));
  };

  typeChecks[ClassNames[6]] = isFunction;

  function isClass(obj, klass, cached) {
    var k = cached || className(obj);
    return k === '[object '+klass+']';
  }

  function buildClassCheck(klass) {
    var fn = (klass === 'Array' && array.isArray) || function(obj, cached) {
      return isClass(obj, klass, cached);
    };
    typeChecks[klass] = fn;
    return fn;
  }

  function buildPrimitiveClassCheck(type, klass) {
    var fn = function(obj) {
      if(isObjectType(obj)) {
        return isClass(obj, klass);
      }
      return typeof obj === type;
    }
    typeChecks[klass] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(this, klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(this, klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(isFunction(override)) {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(target, klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? target.prototype : target, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function hasProperty(obj, prop) {
    return !isPrimitiveType(obj) && prop in obj;
  }

  function hasOwnProperty(obj, prop) {
    return !!obj && internalHasOwnProperty.call(obj, prop);
  }

  function isObjectType(obj) {
    // 1. Check for null
    // 2. Check for regexes in environments where they are "functions".
    return !!obj && (typeof obj === 'object' || (regexIsFunction && isRegExp(obj)));
  }

  function isPrimitiveType(obj) {
    var type = typeof obj;
    return obj == null || type === 'string' || type === 'number' || type === 'boolean';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    var result = '';
    if(isUndefined(times)) {
      times = 1;
    }
    while(times-- > 0) {
      result += str;
    }
    return result;
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/\'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(a === b) {
      // Return quickly up front when matching by reference,
      // but be careful about 0 !== -0.
      return a !== 0 || 1 / a === 1 / b;
    } else if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    }
    return false;
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DocumentView = this.DocumentView = Base.extend({
	beans: true,

	// TODO: Add bounds parameter that defines position within canvas?
	// Find a good name for these bounds, since #bounds is already the artboard
	// bounds of the visible area.
	initialize: function(canvas) {
		// To go with the convention of never passing document to constructors,
		// in all items, associate the view with the currently active document.
		this._document = paper.document;
		// Push it onto document.views and set index:
		this._index = this._document.views.push(this) - 1;
		// Handle canvas argument
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this._canvas = canvas;
			var offset = DomElement.getOffset(canvas);
			// If the canvas has the resize attribute, resize the it to fill the
			// window and resize it again whenever the user resizes the window.
			if (canvas.attributes.resize) {
				this._size = DomElement.getWindowSize().subtract(offset);
				canvas.width = this._size.width;
				canvas.height = this._size.height;
				var that = this;
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(canvas).equals([0, 0]))
							offset = DomElement.getOffset(canvas);
						that.setSize(DomElement.getWindowSize().subtract(offset));
						that.draw();
					}
				});
			} else {
				this._size = Size.create(
						canvas.offsetWidth, canvas.offsetHeight);
			}
			// TODO: Test this on IE:
			if (canvas.attributes.stats) {
				this._stats = new Stats();
				// Align top-left to the canvas
				var element = this._stats.domElement,
					style = element.style;
				style.position = 'absolute';
				style.left = offset.x + 'px';
				style.top = offset.y + 'px';
				document.body.appendChild(element);
			}
		} else {
			// 2nd argument onwards could be view size, otherwise use default:
			this._size = Size.read(arguments, 1);
			if (this._size.isZero())
				this._size = new Size(1024, 768);
			this._canvas = CanvasProvider.getCanvas(this._size);
		}
		this._context = this._canvas.getContext('2d');
		this._matrix = new Matrix();
		this._zoom = 1;
		this._events = this._createEvents();
		DomEvent.add(this._canvas, this._events);
	},

	getDocument: function() {
		return this._document;
	},

	getSize: function() {
		return LinkedSize.create(this, 'setSize',
				this._size.width, this._size.height);
	},

	setSize: function(size) {
		var old = this._size;
		this._size = Size.read(arguments);
		this._canvas.width = this._size.width;
		this._canvas.height = this._size.height;
		// Call onResize handler on any size change
		if (this.onResize) {
			this.onResize({
				size: this._size,
				delta: this._size.subtract(old)
			});
		}
	},

	getBounds: function() {
		return this._bounds;
	},

	getCenter: function() {
	},

	setCenter: function(center) {
	},

	getZoom: function() {
		return this._zoom;
	},

	setZoom: function(zoom) {
		// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
		var mx = new Matrix();
		mx.scale(zoom / this._zoom, this._center);
		this.transform(mx);
		this._zoom = zoom;
	},

	scrollBy: function(point) {
		this.transform(new Matrix().translate(Point.read(arguments).negate()));
	},

	draw: function() {
		if (this._stats)
			this._stats.update();
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		this._context.clearRect(0, 0, this._size.width + 1, this._size.height + 1);
		this._document.draw(this._context);
	},

	activate: function() {
		this._document.activeView = this;
	},

	remove: function() {
		var res = Base.splice(this._document.views, null, this._index, 1);
		// Uninstall event handlers again for this view.
		DomEvent.remove(this._canvas, this._events);
		this._document = this._canvas = this._events = null;
		return !!res.length;
	},

	transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		this._bounds = null;
		this._inverse = null;
	},

	_getInverse: function() {
		if (!this._inverse)
			this._inverse = this._matrix.createInverse();
		return this._inverse;
	},

	// TODO: getInvalidBounds
	// TODO: invalidate(rect)
	// TODO: style: artwork / preview / raster / opaque / ink
	// TODO: getShowGrid
	// TODO: getMousePoint
	// TODO: artworkToView(rect)
	artworkToView: function(point) {
		return this._matrix._transformPoint(Point.read(arguments));
	},

	viewToArtwork: function(point) {
		return this._getInverse()._transformPoint(Point.read(arguments));
	},

	/**
	 * Handler to be called whenever a view gets resized.
	 */
	onResize: null,

	setOnFrame: function(onFrame) {
		this._onFrame = onFrame;
		var that = this,
			running = false,
			before,
			time = 0,
			count = 0;
		function frame(dontSwitch) {
			if (!that._onFrame) {
				running = false;
				return;
			}
			if (!dontSwitch)
				paper = that._document._scope;
			// Request next frame already
			DomEvent.requestAnimationFrame(frame, that._canvas);
			running = true;
			var now = Date.now() / 1000,
			 	delta = before ? now - before : 0;
			that._onFrame({
				delta: delta, // Time elapsed since last redraw in seconds
				time: time += delta, // Time since first call of frame() in seconds
				count: count++
			});
			before = now;
			// Automatically draw view on each frame.
			that.draw();
		};
		// Call the onFrame handler straight away, initializing the sequence
		// of onFrame calls.
		if (!running)
			frame(true);
	},

	getOnFrame: function() {
		return this._onFrame;
	},

	_createEvents: function() {
		var that = this,
			scope = this._document._scope,
			tool,
			timer,
			curPoint,
			dragging = false;

		function viewToArtwork(event) {
			return that.viewToArtwork(DomEvent.getOffset(event));
		}

		function mousedown(event) {
			if (!(tool = scope.tool))
				return;
			curPoint = viewToArtwork(event);
			tool.onHandleEvent('mousedown', curPoint, event);
			if (tool.onMouseDown)
				that.draw();
			if (tool.eventInterval != null)
				timer = setInterval(events.mousemove, tool.eventInterval);
			dragging = true;
		}

		function mousemove(event) {
			if (!(tool = scope.tool))
				return;
			// If the event was triggered by a touch screen device, prevent the
			// default behaviour, as it will otherwise scroll the page:
			if (event && event.targetTouches)
				DomEvent.preventDefault(event);
			var point = event && viewToArtwork(event);
			var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove);
			if (dragging && !onlyMove) {
				curPoint = point || curPoint;
				if (curPoint)
					tool.onHandleEvent('mousedrag', curPoint, event);
				if (tool.onMouseDrag)
					that.draw();
			// PORT: If there is only an onMouseMove handler, also call it when
			// the user is dragging:
			} else if (!dragging || onlyMove) {
				tool.onHandleEvent('mousemove', point, event);
				if (tool.onMouseMove)
					that.draw();
			}
		}

		function mouseup(event) {
			if (!dragging)
				return;
			dragging = false;
			curPoint = null;
			if (tool) {
				if (tool.eventInterval != null)
					timer = clearInterval(timer);
				tool.onHandleEvent('mouseup', viewToArtwork(event), event);
				if (tool.onMouseUp)
					that.draw();
			}
		}

		return {
			mousedown: mousedown,
			mousemove: mousemove,
			mouseup: mouseup,
			touchstart: mousedown,
			touchmove: mousemove,
			touchend: mouseup
		};
	}
});
<commit_msg>Add documentation and remove dontSwitch parameter, since it will also receive the time as defined for requestAnimationFrame() callback.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var DocumentView = this.DocumentView = Base.extend({
	beans: true,

	// TODO: Add bounds parameter that defines position within canvas?
	// Find a good name for these bounds, since #bounds is already the artboard
	// bounds of the visible area.
	initialize: function(canvas) {
		// To go with the convention of never passing document to constructors,
		// in all items, associate the view with the currently active document.
		this._document = paper.document;
		// Push it onto document.views and set index:
		this._index = this._document.views.push(this) - 1;
		// Handle canvas argument
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this._canvas = canvas;
			var offset = DomElement.getOffset(canvas);
			// If the canvas has the resize attribute, resize the it to fill the
			// window and resize it again whenever the user resizes the window.
			if (canvas.attributes.resize) {
				this._size = DomElement.getWindowSize().subtract(offset);
				canvas.width = this._size.width;
				canvas.height = this._size.height;
				var that = this;
				DomEvent.add(window, {
					resize: function(event) {
						// Only get canvas offset if it's not invisible (size is
						// 0, 0), as otherwise the offset would be wrong.
						if (!DomElement.getSize(canvas).equals([0, 0]))
							offset = DomElement.getOffset(canvas);
						that.setSize(DomElement.getWindowSize().subtract(offset));
						that.draw();
					}
				});
			} else {
				this._size = Size.create(
						canvas.offsetWidth, canvas.offsetHeight);
			}
			// TODO: Test this on IE:
			if (canvas.attributes.stats) {
				this._stats = new Stats();
				// Align top-left to the canvas
				var element = this._stats.domElement,
					style = element.style;
				style.position = 'absolute';
				style.left = offset.x + 'px';
				style.top = offset.y + 'px';
				document.body.appendChild(element);
			}
		} else {
			// 2nd argument onwards could be view size, otherwise use default:
			this._size = Size.read(arguments, 1);
			if (this._size.isZero())
				this._size = new Size(1024, 768);
			this._canvas = CanvasProvider.getCanvas(this._size);
		}
		this._context = this._canvas.getContext('2d');
		this._matrix = new Matrix();
		this._zoom = 1;
		this._events = this._createEvents();
		DomEvent.add(this._canvas, this._events);
	},

	getDocument: function() {
		return this._document;
	},

	getSize: function() {
		return LinkedSize.create(this, 'setSize',
				this._size.width, this._size.height);
	},

	setSize: function(size) {
		var old = this._size;
		this._size = Size.read(arguments);
		this._canvas.width = this._size.width;
		this._canvas.height = this._size.height;
		// Call onResize handler on any size change
		if (this.onResize) {
			this.onResize({
				size: this._size,
				delta: this._size.subtract(old)
			});
		}
	},

	getBounds: function() {
		return this._bounds;
	},

	getCenter: function() {
	},

	setCenter: function(center) {
	},

	getZoom: function() {
		return this._zoom;
	},

	setZoom: function(zoom) {
		// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
		var mx = new Matrix();
		mx.scale(zoom / this._zoom, this._center);
		this.transform(mx);
		this._zoom = zoom;
	},

	scrollBy: function(point) {
		this.transform(new Matrix().translate(Point.read(arguments).negate()));
	},

	draw: function() {
		if (this._stats)
			this._stats.update();
		// Initial tests conclude that clearing the canvas using clearRect
		// is always faster than setting canvas.width = canvas.width
		// http://jsperf.com/clearrect-vs-setting-width/7
		this._context.clearRect(0, 0, this._size.width + 1, this._size.height + 1);
		this._document.draw(this._context);
	},

	activate: function() {
		this._document.activeView = this;
	},

	remove: function() {
		var res = Base.splice(this._document.views, null, this._index, 1);
		// Uninstall event handlers again for this view.
		DomEvent.remove(this._canvas, this._events);
		this._document = this._canvas = this._events = null;
		return !!res.length;
	},

	transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		this._bounds = null;
		this._inverse = null;
	},

	_getInverse: function() {
		if (!this._inverse)
			this._inverse = this._matrix.createInverse();
		return this._inverse;
	},

	// TODO: getInvalidBounds
	// TODO: invalidate(rect)
	// TODO: style: artwork / preview / raster / opaque / ink
	// TODO: getShowGrid
	// TODO: getMousePoint
	// TODO: artworkToView(rect)
	artworkToView: function(point) {
		return this._matrix._transformPoint(Point.read(arguments));
	},

	viewToArtwork: function(point) {
		return this._getInverse()._transformPoint(Point.read(arguments));
	},

	/**
	 * Handler to be called whenever a view gets resized.
	 */
	onResize: null,

	/**
	 * Handler to be called on each frame of an animation.
	 */
	getOnFrame: function() {
		return this._onFrame;
	},

	setOnFrame: function(onFrame) {
		this._onFrame = onFrame;
		var that = this,
			running = false,
			before,
			time = 0,
			count = 0;
		function frame() {
			if (!that._onFrame) {
				running = false;
				return;
			}
			// Set the global paper object to the current scope
			paper = that._document._scope;
			// Request next frame already
			DomEvent.requestAnimationFrame(frame, that._canvas);
			running = true;
			var now = Date.now() / 1000,
			 	delta = before ? now - before : 0;
			that._onFrame({
				delta: delta, // Time elapsed since last redraw in seconds
				time: time += delta, // Time since first call of frame() in seconds
				count: count++
			});
			before = now;
			// Automatically draw view on each frame.
			that.draw();
		};
		// Call the onFrame handler straight away, initializing the sequence
		// of onFrame calls.
		if (!running)
			frame();
	},

	_createEvents: function() {
		var that = this,
			scope = this._document._scope,
			tool,
			timer,
			curPoint,
			dragging = false;

		function viewToArtwork(event) {
			return that.viewToArtwork(DomEvent.getOffset(event));
		}

		function mousedown(event) {
			if (!(tool = scope.tool))
				return;
			curPoint = viewToArtwork(event);
			tool.onHandleEvent('mousedown', curPoint, event);
			if (tool.onMouseDown)
				that.draw();
			if (tool.eventInterval != null)
				timer = setInterval(events.mousemove, tool.eventInterval);
			dragging = true;
		}

		function mousemove(event) {
			if (!(tool = scope.tool))
				return;
			// If the event was triggered by a touch screen device, prevent the
			// default behaviour, as it will otherwise scroll the page:
			if (event && event.targetTouches)
				DomEvent.preventDefault(event);
			var point = event && viewToArtwork(event);
			var onlyMove = !!(!tool.onMouseDrag && tool.onMouseMove);
			if (dragging && !onlyMove) {
				curPoint = point || curPoint;
				if (curPoint)
					tool.onHandleEvent('mousedrag', curPoint, event);
				if (tool.onMouseDrag)
					that.draw();
			// PORT: If there is only an onMouseMove handler, also call it when
			// the user is dragging:
			} else if (!dragging || onlyMove) {
				tool.onHandleEvent('mousemove', point, event);
				if (tool.onMouseMove)
					that.draw();
			}
		}

		function mouseup(event) {
			if (!dragging)
				return;
			dragging = false;
			curPoint = null;
			if (tool) {
				if (tool.eventInterval != null)
					timer = clearInterval(timer);
				tool.onHandleEvent('mouseup', viewToArtwork(event), event);
				if (tool.onMouseUp)
					that.draw();
			}
		}

		return {
			mousedown: mousedown,
			mousemove: mousemove,
			mouseup: mouseup,
			touchstart: mousedown,
			touchmove: mousemove,
			touchend: mouseup
		};
	}
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014-present, San Wei Ju Yuan Tech Ltd. <https://www.3vjuyuan.com>
 * All rights reserved.
 *
 * This file is part of node-dev-tools, licensed under the MIT license (MIT) found
 * in the LICENSE file in the root directory of this source tree.
 *
 * For more details:
 * https://www.3vjuyuan.com/licenses/mit.html
 *
 * @author Team Fancy <fancy@3vjuyuan.com>
 * @author Team Delta <delta@3vjuyuan.com>
 */

'use strict';

import cached from 'gulp-cached';
import sassLint from 'gulp-sass-lint';

module.exports = {
    fn: function (gulp, configuration) {
        return gulp.src(configuration.style.path.src.sass + '/**/*.{scss, sass}')
            .pipe(cached('sassLint'))
            .pipe(sassLint({
                config: configuration.style.path.lint,
                endless: true
            }))
            .pipe(sassLint.format())
            .pipe(sassLint.failOnError());
    }
};<commit_msg>[TASK]Support for custom Sass Lint rule configuration<commit_after>/**
 * Copyright (c) 2014-present, San Wei Ju Yuan Tech Ltd. <https://www.3vjuyuan.com>
 * All rights reserved.
 *
 * This file is part of node-dev-tools, licensed under the MIT license (MIT) found
 * in the LICENSE file in the root directory of this source tree.
 *
 * For more details:
 * https://www.3vjuyuan.com/licenses/mit.html
 *
 * @author Team Fancy <fancy@3vjuyuan.com>
 * @author Team Delta <delta@3vjuyuan.com>
 */

'use strict';

import cached from 'gulp-cached';
import sassLint from 'gulp-sass-lint';

module.exports = {
    fn: function (gulp, configuration) {
        return gulp.src(configuration.style.path.src.sass + '/**/*.{scss, sass}')
            .pipe(cached('sassLint'))
            .pipe(sassLint({
                rules:{
                    'bem-depth':[{'max-depth':2}],
                    'class-name-format':[{'allow-leading-underscore':false},{'convention':'hyphenatedbem'}],
                    'mixins-before-declarations':[1,{'exclude':['tablet','desktop']}],
                    'force-attribute-nesting':0,
                    'force-element-nesting':0,
                    'force-pseudo-nesting':0,
                    'no-attribute-selectors':1,
                    'no-ids':0,
                    'no-qualifying-elements':0,
                    'no-universal-selectors':1,
                    'property-sort-order':[1,{'order':'concentric'}]
                },
                configFile: configuration.style.path.lint
            }))
            .pipe(sassLint.format())
            .pipe(sassLint.failOnError());
    }
};<|endoftext|>


<commit_before>NCI.nciHistogram = (function(){
	var me = $('#nciHistogram');

	var internalEndpointsCheckbox = $('#histogramDetailsInternal');
	var barWidth = 4;
	var chart = d3.select("#nciHistogram");
	var chartDetails = d3.select("#nciHistogramDetails");
	var margin = {top: 40, right: 60, bottom: 40, left:40},
	    width = 600,
	    height = 350;
	var color = d3.scale.category10();
	var notNetworkColor = "#000000";
	var detailsGraphForce;
	var force;

	me.show = function(){
		chart.text("");
		var endpointsMax = d3.max(NCI.Communities, function(d) { return d.Size; });
		var endpointsMin;
		var endpointsScale;
		if (endpointsMax > 100) {
			endpointsMin = 0.5;
			endpointsScale = d3.scale.log();
		} else {
			endpointsMin = 0;
			endpointsScale = d3.scale.linear();
		}
		endpointsScale.domain([endpointsMax, endpointsMin])
				.range([0, height - margin.top - margin.bottom]);

		var activitiesScale = d3.scale.linear();
		var activitiesMin = 0;
		if (NCI.Communities.length < 800){
			activitiesScale = d3.scale.linear();
			activitiesMin = 0;
		} else{
			activitiesScale = d3.scale.log();
			activitiesMin = 0.5;
		};
		activitiesScale.domain([NCI.Communities.length + 1, activitiesMin])
					    .range([width - margin.right - margin.left, margin.left]);

		var activitiesAxis = d3.svg.axis()
		    .scale(activitiesScale)
		    .orient('bottom')
		    .tickSize(0)
			.ticks(Math.min(NCI.Communities.length + 2, 10),  d3.format("d"))
		    .tickPadding(8);

		var endpointsAxis = d3.svg.axis()
		    .scale(endpointsScale)
		    .orient('left')
			.tickSize(0)
			.ticks(10,  d3.format("d"))
		    .tickPadding(10);

		var barChartSvg = chart.append('svg')
		    .attr('width', width)
		    .attr('height', height)
		    .append('g')
		    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

        //draw bars
        var index = 0;
		barChartSvg.selectAll('g')
		    .data(NCI.Communities)
		    .enter().append('rect')
		    .attr('x', function(d) { return activitiesScale(NCI.Communities.length - index++) - barWidth/2})
		    .attr('y', function(d) { return endpointsScale(d.Size)}) //- selfwidth
		    .attr('width', function(d) { return barWidth})
		    .attr('height',function(d) { return height - margin.top - margin.bottom - endpointsScale(d.Size) })
			.on("click", function(d) {
				if (NCI.nciHistogram.selectedBar)
				NCI.nciHistogram.selectedBar.setAttribute("fill", "black");
				NCI.nciHistogram.selectedBar = this;
				this.setAttribute("fill", "rgb(31, 119, 180)");
				me.showDetails(d);
			 });

		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 6);
	    barChartSvg.append("circle").attr("cy", endpointsScale(endpointsMin))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 4);
		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(activitiesMin) ).style("fill", "red").attr("r", 4);
		//draw axis
		barChartSvg.append('g')
		    .attr('class', 'x axis')
			.attr('transform', 'translate(0,' + (height - margin.top - margin.bottom) + ')')
			.call(activitiesAxis);
		barChartSvg.append('g')
			.attr('class', 'y axis')
			.attr('transform', 'translate(' + margin.left + ')')
			.call(endpointsAxis);
		//draw axis labels
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Activities Sorted by Size     j').attr('x', width/2 - 100).attr('y', height - 45);
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Number of Endpoints per Activity      X[j]').attr('x', -height/2 - 70).attr('y', -10)
		.attr('transform', 'rotate(-90)');

	};

	me.showDetails = function(d){
		chartDetails.text("");
		var detailsDim = 320;
		var activityDetails = chartDetails.append('svg')
			.attr('width',  $("#nciHistogramDetails").width())
		    .attr('height', detailsDim);

	    var graph = NCI.prepareDataForForceGraph([d]);

		force = d3.layout.force()
			.charge(-60)
			.linkDistance(30)
			.size([detailsDim, detailsDim])
			.linkStrength(1).nodes(graph.nodes).links(graph.links).start();

		var link = activityDetails.selectAll(".link")
		    .data(graph.links)
			.enter().append("line")
			.attr("class", "activities_link")
			.style("stroke-width", function(d) { return Math.sqrt(d.value); });

		chartDetails.node = activityDetails.selectAll(".node")
		    .data(graph.nodes)
		    .enter().append("circle")
			.call(force.drag)
		    .attr("r", 5)
			.style("fill", function(d) {
				return me.colorifyEndpoint(internalEndpointsCheckbox[0].checked, d);
			 });

		chartDetails.node.append("title").html(function(d) {
			var info = d.name;
			if (d.external){
				info += "
doesn't belong activity";
			};
			info += "
" + d.connections + " connections";
			return info;
		});

		force.on("tick", function() {
			link.attr("x1", function(d) { return d.source.x; })
			    .attr("y1", function(d) { return d.source.y; })
				.attr("x2", function(d) { return d.target.x; })
				.attr("y2", function(d) { return d.target.y; });

			chartDetails.node.attr("cx", function(d) { return d.x; })
			    .attr("cy", function(d) { return d.y; });
		});
	};

	me.colorifyEndpoint = function(devided, endpoint){
		if (endpoint.external)
		    return "#ff0000";
		if ( devided && !endpoint.name.indexOf("10.") == 0 && !name.indexOf("192.168") == 0){
			return notNetworkColor;
		}
		return color(0);
	};

	me.clean = function(){
		chartDetails.text("");
		chart.text("");
	};

	internalEndpointsCheckbox.on('click', function(event){
		var checked = this.checked;
		chartDetails.node.style("fill", function(d) {
			return me.colorifyEndpoint(checked, d);
		});
	});

	return me;
}());
<commit_msg>Change popover message<commit_after>NCI.nciHistogram = (function(){
	var me = $('#nciHistogram');

	var internalEndpointsCheckbox = $('#histogramDetailsInternal');
	var barWidth = 4;
	var chart = d3.select("#nciHistogram");
	var chartDetails = d3.select("#nciHistogramDetails");
	var margin = {top: 40, right: 60, bottom: 40, left:40},
	    width = 600,
	    height = 350;
	var color = d3.scale.category10();
	var notNetworkColor = "#000000";
	var detailsGraphForce;
	var force;

	me.show = function(){
		chart.text("");
		var endpointsMax = d3.max(NCI.Communities, function(d) { return d.Size; });
		var endpointsMin;
		var endpointsScale;
		if (endpointsMax > 100) {
			endpointsMin = 0.5;
			endpointsScale = d3.scale.log();
		} else {
			endpointsMin = 0;
			endpointsScale = d3.scale.linear();
		}
		endpointsScale.domain([endpointsMax, endpointsMin])
				.range([0, height - margin.top - margin.bottom]);

		var activitiesScale = d3.scale.linear();
		var activitiesMin = 0;
		if (NCI.Communities.length < 800){
			activitiesScale = d3.scale.linear();
			activitiesMin = 0;
		} else{
			activitiesScale = d3.scale.log();
			activitiesMin = 0.5;
		};
		activitiesScale.domain([NCI.Communities.length + 1, activitiesMin])
					    .range([width - margin.right - margin.left, margin.left]);

		var activitiesAxis = d3.svg.axis()
		    .scale(activitiesScale)
		    .orient('bottom')
		    .tickSize(0)
			.ticks(Math.min(NCI.Communities.length + 2, 10),  d3.format("d"))
		    .tickPadding(8);

		var endpointsAxis = d3.svg.axis()
		    .scale(endpointsScale)
		    .orient('left')
			.tickSize(0)
			.ticks(10,  d3.format("d"))
		    .tickPadding(10);

		var barChartSvg = chart.append('svg')
		    .attr('width', width)
		    .attr('height', height)
		    .append('g')
		    .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

        //draw bars
        var index = 0;
		barChartSvg.selectAll('g')
		    .data(NCI.Communities)
		    .enter().append('rect')
		    .attr('x', function(d) { return activitiesScale(NCI.Communities.length - index++) - barWidth/2})
		    .attr('y', function(d) { return endpointsScale(d.Size)}) //- selfwidth
		    .attr('width', function(d) { return barWidth})
		    .attr('height',function(d) { return height - margin.top - margin.bottom - endpointsScale(d.Size) })
			.on("click", function(d) {
				if (NCI.nciHistogram.selectedBar)
				NCI.nciHistogram.selectedBar.setAttribute("fill", "black");
				NCI.nciHistogram.selectedBar = this;
				this.setAttribute("fill", "rgb(31, 119, 180)");
				me.showDetails(d);
			 });

		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 6);
	    barChartSvg.append("circle").attr("cy", endpointsScale(endpointsMin))
		    .attr("cx", activitiesScale(NCI.timestampNCI) ).style("fill", "red").attr("r", 4);
		barChartSvg.append("circle").attr("cy", endpointsScale(NCI.timestampNCI))
		    .attr("cx", activitiesScale(activitiesMin) ).style("fill", "red").attr("r", 4);
		//draw axis
		barChartSvg.append('g')
		    .attr('class', 'x axis')
			.attr('transform', 'translate(0,' + (height - margin.top - margin.bottom) + ')')
			.call(activitiesAxis);
		barChartSvg.append('g')
			.attr('class', 'y axis')
			.attr('transform', 'translate(' + margin.left + ')')
			.call(endpointsAxis);
		//draw axis labels
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Activities Sorted by Size     j').attr('x', width/2 - 100).attr('y', height - 45);
		barChartSvg.append('text').
		attr('style', 'font-weight:bold').
		html('Number of Endpoints per Activity      X[j]').attr('x', -height/2 - 70).attr('y', -10)
		.attr('transform', 'rotate(-90)');

	};

	me.showDetails = function(d){
		chartDetails.text("");
		var detailsDim = 320;
		var activityDetails = chartDetails.append('svg')
			.attr('width',  $("#nciHistogramDetails").width())
		    .attr('height', detailsDim);

	    var graph = NCI.prepareDataForForceGraph([d]);

		force = d3.layout.force()
			.charge(-60)
			.linkDistance(30)
			.size([detailsDim, detailsDim])
			.linkStrength(1).nodes(graph.nodes).links(graph.links).start();

		var link = activityDetails.selectAll(".link")
		    .data(graph.links)
			.enter().append("line")
			.attr("class", "activities_link")
			.style("stroke-width", function(d) { return Math.sqrt(d.value); });

		chartDetails.node = activityDetails.selectAll(".node")
		    .data(graph.nodes)
		    .enter().append("circle")
			.call(force.drag)
		    .attr("r", 5)
			.style("fill", function(d) {
				return me.colorifyEndpoint(internalEndpointsCheckbox[0].checked, d);
			 });

		chartDetails.node.append("title").html(function(d) {
			var info = d.name;
			if (d.external){
				info += "
doesn't belong to activity";
			};
			info += "
" + d.connections + " connections";
			return info;
		});

		force.on("tick", function() {
			link.attr("x1", function(d) { return d.source.x; })
			    .attr("y1", function(d) { return d.source.y; })
				.attr("x2", function(d) { return d.target.x; })
				.attr("y2", function(d) { return d.target.y; });

			chartDetails.node.attr("cx", function(d) { return d.x; })
			    .attr("cy", function(d) { return d.y; });
		});
	};

	me.colorifyEndpoint = function(devided, endpoint){
		if (endpoint.external)
		    return "#ff0000";
		if ( devided && !endpoint.name.indexOf("10.") == 0 && !name.indexOf("192.168") == 0){
			return notNetworkColor;
		}
		return color(0);
	};

	me.clean = function(){
		chartDetails.text("");
		chart.text("");
	};

	internalEndpointsCheckbox.on('click', function(event){
		var checked = this.checked;
		chartDetails.node.style("fill", function(d) {
			return me.colorifyEndpoint(checked, d);
		});
	});

	return me;
}());
<|endoftext|>


<commit_before>/**
 * Shopware 4.0
 * Copyright © 2012 shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Customer
 * @subpackage Detail
 * @copyright  Copyright (c) 2012, shopware AG (http://www.shopware.de)
 * @version    $Id$
 * @author shopware AG
 */

//{namespace name=backend/customer/view/detail}

/**
 * Shopware UI - Customer detail page
 *
 * The base field set contains the base data of the customer
 * which is stored in the base model and filled over the s_user table
 *
 */
//{block name="backend/customer/view/detail/base"}
Ext.define('Shopware.apps.Customer.view.detail.Base', {
    /**
     * Define that the base field set is an extension of the Ext.form.FieldSet
     * @string
     */
    extend:'Ext.form.FieldSet',
    /**
     * List of short aliases for class names. Most useful for defining xtypes for widgets.
     * @string
     */
    alias:'widget.customer-base-field-set',

    /**
     * Set css class for this component
     * @string
     */
    cls: Ext.baseCSSPrefix + 'base-field-set',

    /**
     * Layout type for the component.
     * @string
     */
    layout: 'column',

    /**
     * Contains all snippets for the view component
     * @object
     */
    snippets:{
        title:'{s name=base/title}Base data{/s}',
        email:{
            message:'{s name=base/validate_email_message}Email address is already in use{/s}',
            label:'{s name=base/email}Email{/s}'
        },
        confirm:{
            label:'{s name=base/password_confirm}Confirm password{/s}',
            support:'{s name=base/confirm_support}Please confirm the password you have entered{/s}',
            helpTitle:'{s name=base/confirm_help_title}Password confirmation{/s}',
            helpText:'{s name=base/confirm_help_text}For security reasons, please enter the password again.{/s}'
        },
        active:{
            box:'{s name=base/active_box_label}Mark the account as active{/s}',
            field:'{s name=base/active_field_label}Active{/s}'
        },
        password:{
            label:'{s name=base/password}Password{/s}',
            support:'{s name=base/password_support}To automatically create the password, use the button on the right side.{/s}',
            button:'{s name=base/password_generate}Generate password{/s}',
            message:'{s name=base/password_error}The passwords do not match.{/s}'
        },
        group:'{s name=base/customer_group}Customer group{/s}',
        shop:'{s name=base/shop}Shop{/s}',
        number: {
            label:'{s name=base/customer_number}Customer number{/s}',
            helpTitle: '{s name=base/customer_number_help_title}Customer number generation{/s}',
            helpText: '{s name=base/customer_number_help_text}If the parameter sShopwareManagedCustomerNumbers is set to 1 in the shopware configuration, the customer number will be set automatically when the customer is saved and the field is not editable.{/s}'
        }
    },

    /**
     * Component event method which is fired when the component
     * is initials. The component is initials when the user
     * want to create a new customer or edit an existing customer
     * @return void
     */
    initComponent:function () {
        var me = this;
        me.title = me.snippets.title;
        me.registerEvents();

        me.items = me.createBaseForm();

        me.callParent(arguments);
    },

    /**
     * Registers the generatePassword event which is fired when the
     * user clicks on the generatePassword button.
     *
     * @return void
     */
    registerEvents:function () {
        this.addEvents(
            /**
             * Event will be fired when the user clicks the button to
             * generate a new password
             *
             * @event generatePassword
             * @param [object] passwordField - Associated password field
             * @param [object] confirmField - Associated confirm password field
             */
            'generatePassword'
        );
    },

    /**
     * Creates the both containers for the field set
     * to display the form fields in two columns.
     *
     * @return [Array] Contains the left and right container
     */
    createBaseForm:function () {
        var leftContainer, rightContainer, me = this;

        leftContainer = Ext.create('Ext.container.Container', {
            columnWidth:0.5,
            border:false,
            cls: Ext.baseCSSPrefix + 'field-set-container',
            layout:'anchor',
            defaults:{
                anchor:'95%',
                labelWidth:150,
                minWidth:250,
                xtype:'textfield'
            },
            items:me.createBaseFormLeft()
        });

        rightContainer = Ext.create('Ext.container.Container', {
            columnWidth:0.5,
            border:false,
            layout:'anchor',
            cls: Ext.baseCSSPrefix + 'field-set-container',
            defaults:{
                labelWidth:150,
                xtype:'textfield'
            },
            items: me.createBaseFormRight()
        });

        return [ leftContainer, rightContainer ];
    },

    /**
     * Creates the left container of the base field set.
     * Contains the email field and the combo boxes for
     * the shop and customer group
     *
     * @return [Array] Contains the different form field of the left container
     */
    createBaseFormLeft:function () {
        var me = this;

        me.customerGroupCombo = Ext.create('Ext.form.field.ComboBox', {
            triggerAction:'all',
            queryMode: 'local',
            name:'groupKey',
            fieldLabel:me.snippets.group,
            valueField:'key',
            displayField:'name',
            allowBlank:false,
            anchor:'95%',
            labelWidth:150,
            minWidth:250
        });

        me.shopStoreCombo = Ext.create('Ext.form.field.ComboBox', {
            triggerAction:'all',
            name:'shopId',
            queryMode: 'local',
            fieldLabel:me.snippets.shop,
            valueField:'id',
            displayField:'name',
            allowBlank:false,
            editable:false,
            anchor:'95%',
            labelWidth:150,
            minWidth:250
        });

        return [{
            fieldLabel:me.snippets.email.label,
            name:'email',
            allowBlank:false,
            required:true,
            enableKeyEvents:true,
            checkChangeBuffer:700,
            vtype:'remote',
            validationUrl: '{url action="validateEmail"}',
            validationRequestParams:{ 'param' : me.record.get('id'),'subshopId' : me.record.get('shopId')},
            validationErrorMsg:me.snippets.email.message
        },
            me.customerGroupCombo,
            me.shopStoreCombo,
        {
            /*{if {config name=shopwareManagedCustomerNumbers}==1}*/
            xtype: 'displayfield',
            /*{/if}*/
            name: 'billing[number]',
            fieldLabel: me.snippets.number.label,
            helpText: me.snippets.number.helpText,
            helpWidth: 360,
            helpTitle: me.snippets.number.helpTitle
        }];
    },

    /**
     * Creates the right container of the base field set.
     * Contains the active checkbox and the two text fields
     * for the password
     *
     * @return [Array] Contains the three form fields
     */
    createBaseFormRight:function () {
        var me = this,
            pwRequired = false;

        if ( me.record.data.id === 0 ) {
            pwRequired = true;
        }

        //create the confirm password field to get access in the create password
        //button handler to pass the field to the generate password event
        me.confirmField = Ext.create('Ext.form.field.Text', {
            name:'confirm',
            inputType:'password',
            anchor: '95%',
            allowBlank:!pwRequired,
            required:pwRequired,
            fieldLabel:me.snippets.confirm.label,
            supportText:me.snippets.confirm.support,
            helpTitle:me.snippets.confirm.helpTitle,
            helpText:me.snippets.confirm.helpText,
            validator:function (value) {
                if ( Ext.String.trim(value) == Ext.String.trim(me.passwordField.getValue()) ) {
                    me.passwordField.clearInvalid();
                    return true;
                } else {
                    return me.snippets.password.message;
                }
            }
        });

        me.passwordContainer = me.createPasswordContainer();

        return [{
            name:'active',
            boxLabel:me.snippets.active.box,
            fieldLabel:me.snippets.active.field,
            xtype:'checkbox',
            value: true,
            labelWidth:100,
            uncheckedValue:false,
            inputValue:true
        },  me.passwordContainer, me.confirmField ];
    },

    /**
     * Creates the container for the password field and the generatePassword button.
     * @return [Ext.container.Container] - Contains the text field and the button
     */
    createPasswordContainer:function () {
        var me = this,
            pwRequired = false;

        if ( me.record.data.id === 0 ) {
            pwRequired = true;
        }

        //create the password generation button
        me.passwordButton = Ext.create('Ext.button.Button', {
            cls: Ext.baseCSSPrefix + 'password-button',
            iconCls:'sprite-license-key',
            action:'create-password',
            tooltip:me.snippets.password.button,
            style: {
                display: 'inline-block'
            },
            /**
             * Add button handler to fire the generatePassword event which is handled
             * in the detail controller. The detail controller generates a password and set it into the password field
             */
            handler:function () {
                me.fireEvent('generatePassword', me.passwordField, me.confirmField);
            }
        });

        //create the password field to get access in the create password
        //button handler to pass the field to the generate password event
        me.passwordField = Ext.create('Ext.form.field.Text', {
            name:'newPassword',
            anchor: '92%',
            inputType:'password',
            allowBlank:!pwRequired,
            required:pwRequired,
            fieldLabel:me.snippets.password.label,
            supportText:me.snippets.password.support,
            cls: Ext.baseCSSPrefix + 'password-field',
            //can't be set in sass.. extJs don't resize the password field.
            style:{
                display: 'inline-block',
                margin: '0 8px 0 0 !important'
            },
            validator:function (value) {
                if ( Ext.String.trim(value) == Ext.String.trim(me.confirmField.getValue()) ) {
                    me.confirmField.clearInvalid();
                    return true;
                } else {
                    return me.snippets.password.message;
                }
            }
        });

        //create a container for the password field to append the generate password button
        return Ext.create('Ext.container.Container', {
            layout:'anchor',
            cls: Ext.baseCSSPrefix + 'password-container',
            defaults:{
                labelWidth:150,
                validateOnBlur:true,
                validateOnChange:false
            },
            height:70,
            items:[ me.passwordField, me.passwordButton ]
        });
    }

});
//{/block}
<commit_msg>SW-4012 - Fix trivial js alert if some text was entered in customergroup selection while adding new customers through backend<commit_after>/**
 * Shopware 4.0
 * Copyright © 2012 shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Customer
 * @subpackage Detail
 * @copyright  Copyright (c) 2012, shopware AG (http://www.shopware.de)
 * @version    $Id$
 * @author shopware AG
 */

//{namespace name=backend/customer/view/detail}

/**
 * Shopware UI - Customer detail page
 *
 * The base field set contains the base data of the customer
 * which is stored in the base model and filled over the s_user table
 *
 */
//{block name="backend/customer/view/detail/base"}
Ext.define('Shopware.apps.Customer.view.detail.Base', {
    /**
     * Define that the base field set is an extension of the Ext.form.FieldSet
     * @string
     */
    extend:'Ext.form.FieldSet',
    /**
     * List of short aliases for class names. Most useful for defining xtypes for widgets.
     * @string
     */
    alias:'widget.customer-base-field-set',

    /**
     * Set css class for this component
     * @string
     */
    cls: Ext.baseCSSPrefix + 'base-field-set',

    /**
     * Layout type for the component.
     * @string
     */
    layout: 'column',

    /**
     * Contains all snippets for the view component
     * @object
     */
    snippets:{
        title:'{s name=base/title}Base data{/s}',
        email:{
            message:'{s name=base/validate_email_message}Email address is already in use{/s}',
            label:'{s name=base/email}Email{/s}'
        },
        confirm:{
            label:'{s name=base/password_confirm}Confirm password{/s}',
            support:'{s name=base/confirm_support}Please confirm the password you have entered{/s}',
            helpTitle:'{s name=base/confirm_help_title}Password confirmation{/s}',
            helpText:'{s name=base/confirm_help_text}For security reasons, please enter the password again.{/s}'
        },
        active:{
            box:'{s name=base/active_box_label}Mark the account as active{/s}',
            field:'{s name=base/active_field_label}Active{/s}'
        },
        password:{
            label:'{s name=base/password}Password{/s}',
            support:'{s name=base/password_support}To automatically create the password, use the button on the right side.{/s}',
            button:'{s name=base/password_generate}Generate password{/s}',
            message:'{s name=base/password_error}The passwords do not match.{/s}'
        },
        group:'{s name=base/customer_group}Customer group{/s}',
        shop:'{s name=base/shop}Shop{/s}',
        number: {
            label:'{s name=base/customer_number}Customer number{/s}',
            helpTitle: '{s name=base/customer_number_help_title}Customer number generation{/s}',
            helpText: '{s name=base/customer_number_help_text}If the parameter sShopwareManagedCustomerNumbers is set to 1 in the shopware configuration, the customer number will be set automatically when the customer is saved and the field is not editable.{/s}'
        }
    },

    /**
     * Component event method which is fired when the component
     * is initials. The component is initials when the user
     * want to create a new customer or edit an existing customer
     * @return void
     */
    initComponent:function () {
        var me = this;
        me.title = me.snippets.title;
        me.registerEvents();

        me.items = me.createBaseForm();

        me.callParent(arguments);
    },

    /**
     * Registers the generatePassword event which is fired when the
     * user clicks on the generatePassword button.
     *
     * @return void
     */
    registerEvents:function () {
        this.addEvents(
            /**
             * Event will be fired when the user clicks the button to
             * generate a new password
             *
             * @event generatePassword
             * @param [object] passwordField - Associated password field
             * @param [object] confirmField - Associated confirm password field
             */
            'generatePassword'
        );
    },

    /**
     * Creates the both containers for the field set
     * to display the form fields in two columns.
     *
     * @return [Array] Contains the left and right container
     */
    createBaseForm:function () {
        var leftContainer, rightContainer, me = this;

        leftContainer = Ext.create('Ext.container.Container', {
            columnWidth:0.5,
            border:false,
            cls: Ext.baseCSSPrefix + 'field-set-container',
            layout:'anchor',
            defaults:{
                anchor:'95%',
                labelWidth:150,
                minWidth:250,
                xtype:'textfield'
            },
            items:me.createBaseFormLeft()
        });

        rightContainer = Ext.create('Ext.container.Container', {
            columnWidth:0.5,
            border:false,
            layout:'anchor',
            cls: Ext.baseCSSPrefix + 'field-set-container',
            defaults:{
                labelWidth:150,
                xtype:'textfield'
            },
            items: me.createBaseFormRight()
        });

        return [ leftContainer, rightContainer ];
    },

    /**
     * Creates the left container of the base field set.
     * Contains the email field and the combo boxes for
     * the shop and customer group
     *
     * @return [Array] Contains the different form field of the left container
     */
    createBaseFormLeft:function () {
        var me = this;

        me.customerGroupCombo = Ext.create('Ext.form.field.ComboBox', {
            triggerAction:'all',
            queryMode: 'local',
            name:'groupKey',
            fieldLabel:me.snippets.group,
            valueField:'key',
            displayField:'name',
            editable:false,
            allowBlank:false,
            anchor:'95%',
            labelWidth:150,
            minWidth:250
        });

        me.shopStoreCombo = Ext.create('Ext.form.field.ComboBox', {
            triggerAction:'all',
            name:'shopId',
            queryMode: 'local',
            fieldLabel:me.snippets.shop,
            valueField:'id',
            displayField:'name',
            allowBlank:false,
            editable:false,
            anchor:'95%',
            labelWidth:150,
            minWidth:250
        });

        return [{
            fieldLabel:me.snippets.email.label,
            name:'email',
            allowBlank:false,
            required:true,
            enableKeyEvents:true,
            checkChangeBuffer:700,
            vtype:'remote',
            validationUrl: '{url action="validateEmail"}',
            validationRequestParams:{ 'param' : me.record.get('id'),'subshopId' : me.record.get('shopId')},
            validationErrorMsg:me.snippets.email.message
        },
            me.customerGroupCombo,
            me.shopStoreCombo,
        {
            /*{if {config name=shopwareManagedCustomerNumbers}==1}*/
            xtype: 'displayfield',
            /*{/if}*/
            name: 'billing[number]',
            fieldLabel: me.snippets.number.label,
            helpText: me.snippets.number.helpText,
            helpWidth: 360,
            helpTitle: me.snippets.number.helpTitle
        }];
    },

    /**
     * Creates the right container of the base field set.
     * Contains the active checkbox and the two text fields
     * for the password
     *
     * @return [Array] Contains the three form fields
     */
    createBaseFormRight:function () {
        var me = this,
            pwRequired = false;

        if ( me.record.data.id === 0 ) {
            pwRequired = true;
        }

        //create the confirm password field to get access in the create password
        //button handler to pass the field to the generate password event
        me.confirmField = Ext.create('Ext.form.field.Text', {
            name:'confirm',
            inputType:'password',
            anchor: '95%',
            allowBlank:!pwRequired,
            required:pwRequired,
            fieldLabel:me.snippets.confirm.label,
            supportText:me.snippets.confirm.support,
            helpTitle:me.snippets.confirm.helpTitle,
            helpText:me.snippets.confirm.helpText,
            validator:function (value) {
                if ( Ext.String.trim(value) == Ext.String.trim(me.passwordField.getValue()) ) {
                    me.passwordField.clearInvalid();
                    return true;
                } else {
                    return me.snippets.password.message;
                }
            }
        });

        me.passwordContainer = me.createPasswordContainer();

        return [{
            name:'active',
            boxLabel:me.snippets.active.box,
            fieldLabel:me.snippets.active.field,
            xtype:'checkbox',
            value: true,
            labelWidth:100,
            uncheckedValue:false,
            inputValue:true
        },  me.passwordContainer, me.confirmField ];
    },

    /**
     * Creates the container for the password field and the generatePassword button.
     * @return [Ext.container.Container] - Contains the text field and the button
     */
    createPasswordContainer:function () {
        var me = this,
            pwRequired = false;

        if ( me.record.data.id === 0 ) {
            pwRequired = true;
        }

        //create the password generation button
        me.passwordButton = Ext.create('Ext.button.Button', {
            cls: Ext.baseCSSPrefix + 'password-button',
            iconCls:'sprite-license-key',
            action:'create-password',
            tooltip:me.snippets.password.button,
            style: {
                display: 'inline-block'
            },
            /**
             * Add button handler to fire the generatePassword event which is handled
             * in the detail controller. The detail controller generates a password and set it into the password field
             */
            handler:function () {
                me.fireEvent('generatePassword', me.passwordField, me.confirmField);
            }
        });

        //create the password field to get access in the create password
        //button handler to pass the field to the generate password event
        me.passwordField = Ext.create('Ext.form.field.Text', {
            name:'newPassword',
            anchor: '92%',
            inputType:'password',
            allowBlank:!pwRequired,
            required:pwRequired,
            fieldLabel:me.snippets.password.label,
            supportText:me.snippets.password.support,
            cls: Ext.baseCSSPrefix + 'password-field',
            //can't be set in sass.. extJs don't resize the password field.
            style:{
                display: 'inline-block',
                margin: '0 8px 0 0 !important'
            },
            validator:function (value) {
                if ( Ext.String.trim(value) == Ext.String.trim(me.confirmField.getValue()) ) {
                    me.confirmField.clearInvalid();
                    return true;
                } else {
                    return me.snippets.password.message;
                }
            }
        });

        //create a container for the password field to append the generate password button
        return Ext.create('Ext.container.Container', {
            layout:'anchor',
            cls: Ext.baseCSSPrefix + 'password-container',
            defaults:{
                labelWidth:150,
                validateOnBlur:true,
                validateOnChange:false
            },
            height:70,
            items:[ me.passwordField, me.passwordButton ]
        });
    }

});
//{/block}
<|endoftext|>


<commit_before>var replace = require("gulp-replace")
,   forEach = require("gulp-foreach")
,   loggerSpec = require("react-server-module-tagger")

// This pattern matches either of these:
//   - "__LOGGER__"
//   - "__LOGGER__({ /* options */ })"
var isWindows = ('win32' === process.platform)
,   REPLACE_TOKEN = /(?:__LOGGER__|__CHANNEL__|__CACHE__)(?:\(\s*(\{[\s\S]*?\})\s*\))?/g
,   THIS_MODULE   = isWindows
	? /(?:[^\\]+\\node_modules\\)?react-server-gulp-module-tagger\\index\.js$/
	: /(?:[^\/]+\/node_modules\/)?react-server-gulp-module-tagger\/index\.js$/

module.exports = function(config) {
	config || (config = {});
	config.basePath = module.filename.replace(THIS_MODULE,'');
	return forEach(function(stream, file){
		return stream.pipe(replace(REPLACE_TOKEN, loggerSpec.bind({file, config})));
	});
}
<commit_msg>Update react-server-gulp-module-tagger to use new interface<commit_after>var replace = require("gulp-replace")
,   forEach = require("gulp-foreach")
,   loggerSpec = require("react-server-module-tagger")

// This pattern matches either of these:
//   - "__LOGGER__"
//   - "__LOGGER__({ /* options */ })"
var isWindows = ('win32' === process.platform)
,   REPLACE_TOKEN = /(?:__LOGGER__|__CHANNEL__|__CACHE__)(?:\(\s*(\{[\s\S]*?\})\s*\))?/g
,   THIS_MODULE   = isWindows
	? /(?:[^\\]+\\node_modules\\)?react-server-gulp-module-tagger\\index\.js$/
	: /(?:[^\/]+\/node_modules\/)?react-server-gulp-module-tagger\/index\.js$/

module.exports = function(config) {
	config || (config = {});
	config.basePath = module.filename.replace(THIS_MODULE,'');
	return forEach(function(stream, file){
		return stream.pipe(replace(REPLACE_TOKEN, (match, optString) => {
			return loggerSpec({
				filePath: file.path,
				basePath: config.basePath,
				trim: config.trim, optString,
			});
		}));
	});
}
<|endoftext|>