<commit_before>
/*!
 * Express - view - Partial
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var View = require('./view')
  , basename = require('path').basename
  , stat = require('fs').statSync;

/**
 * Memory cache.
 */

var cache = {};

/**
 * Initialize a new `Partial` for the given `view` and `options`.
 *
 * @param {String} view
 * @param {Object} options
 * @api private
 */

var Partial = exports = module.exports = function Partial(view, options) {
  options = options || {};
  View.call(this, view, options);
  this.path = this.resolvePartialPath(this.dirname);
};

/**
 * Inherit from `View.prototype`.
 */

Partial.prototype.__proto__ = View.prototype;

/**
 * Resolve partial view path.
 *
 * @param {String} dir
 * @return {String}
 * @api public
 */

Partial.prototype.resolvePartialPath = function(dir){
  return dir + '/_' + basename(this.path);
};

/**
 * Resolve partial object name from the view path.
 *
 * Examples:
 *
 *   "user.ejs" becomes "user"
 *   "forum thread.ejs" becomes "forumThread"
 *   "forum/thread/post.ejs" becomes "post"
 *   "blog-post.ejs" becomes "blogPost"
 *
 * @return {String}
 * @api private
 */

exports.resolveObjectName = function(view){
  return cache[view] || (cache[view] = view
    .split('/')
    .slice(-1)[0]
    .split('.')[0]
    .replace(/[^a-zA-Z0-9 ]+/g, ' ')
    .split(/ +/).map(function(word, i){
      return i
        ? word[0].toUpperCase() + word.substr(1)
        : word;
    }).join(''));
};<commit_msg>Removed a require<commit_after>
/*!
 * Express - view - Partial
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var View = require('./view')
  , basename = require('path').basename;

/**
 * Memory cache.
 */

var cache = {};

/**
 * Initialize a new `Partial` for the given `view` and `options`.
 *
 * @param {String} view
 * @param {Object} options
 * @api private
 */

var Partial = exports = module.exports = function Partial(view, options) {
  options = options || {};
  View.call(this, view, options);
  this.path = this.resolvePartialPath(this.dirname);
};

/**
 * Inherit from `View.prototype`.
 */

Partial.prototype.__proto__ = View.prototype;

/**
 * Resolve partial view path.
 *
 * @param {String} dir
 * @return {String}
 * @api public
 */

Partial.prototype.resolvePartialPath = function(dir){
  return dir + '/_' + basename(this.path);
};

/**
 * Resolve partial object name from the view path.
 *
 * Examples:
 *
 *   "user.ejs" becomes "user"
 *   "forum thread.ejs" becomes "forumThread"
 *   "forum/thread/post.ejs" becomes "post"
 *   "blog-post.ejs" becomes "blogPost"
 *
 * @return {String}
 * @api private
 */

exports.resolveObjectName = function(view){
  return cache[view] || (cache[view] = view
    .split('/')
    .slice(-1)[0]
    .split('.')[0]
    .replace(/[^a-zA-Z0-9 ]+/g, ' ')
    .split(/ +/).map(function(word, i){
      return i
        ? word[0].toUpperCase() + word.substr(1)
        : word;
    }).join(''));
};<|endoftext|>


<commit_before>(function($){

  function convertDiff(name, table, pre) {
    var inline = table.className == 'inline';
    var ths = table.tHead.rows[0].cells;
    var afile, bfile;
    if ( inline ) {
        afile = ths[0].title;
        bfile = ths[1].title;
    } else {
        afile = $(ths[0]).find('a').text();
        bfile = $(ths[1]).find('a').text();
    }
    if ( afile.match(/^Revision /) ) {
        afile = 'a/' + name;
        bfile = 'b/' + name;
    }
    var lines = [
      "Index: " + name,
      "===================================================================",
      "--- " + afile.replace(/File /, ''),
      "+++ " + bfile.replace(/File /, ''),
    ];
    var sepIndex = 0;
    var oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
    var title = "";
    if (inline)
      title = $(ths[2]).text();

    for (var i = 0; i
 0) {
          if (!oldOffset && oldLength) oldOffset = 1
          if (!newOffset && newLength) newOffset = 1
          lines[sepIndex] = lines[sepIndex]
            .replace("{1}", oldOffset).replace("{2}", oldLength)
            .replace("{3}", newOffset).replace("{4}", newLength)
            .replace("{5}", title);
        }
        sepIndex = lines.length;
        lines.push("@@ -{1},{2} +{3},{4} @@{5}");
        oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
        if (tBody.className == "skipped") {
          if (inline)
            title = $(tBody.rows[0].cells[2]).text();
          continue;
        }
      }
      var tmpLines = [];
      for (var j = 0; j < tBody.rows.length; j++) {
        var cells = tBody.rows[j].cells;
        var oldLineNo = parseInt($(cells[0]).text());
        var newLineNo = parseInt($(cells[inline ? 1 : 2]).text());
        if (tBody.className == 'unmod') {
          lines.push(" " + $(cells[inline ? 2 : 1]).text());
          oldLength += 1;
          newLength += 1;
          if (!oldOffset) oldOffset = oldLineNo;
          if (!newOffset) newOffset = newLineNo;
        } else {
          var oldLine;
          var newLine;
          var oldTag = "-";
          var newTag = "+";
          if (inline) {
            oldLine = newLine = $(cells[2]).text();
            if ($('em', cells[2]).length) oldTag = newTag = "\\";
          } else {
            oldLine = $(cells[1]).text();
            if ($('em', cells[1]).length) oldTag = "\\";
            newLine = $(cells[3]).text();
            if ($('em', cells[3]).length) newTag = "\\";
          }
          if (!isNaN(oldLineNo)) {
            lines.push(oldTag + oldLine);
            oldLength += 1;
          }
          if (!isNaN(newLineNo)) {
            tmpLines.push(newTag + newLine);
            newLength += 1;
          }
        }
      }
      if (tmpLines.length > 0) {
        lines = lines.concat(tmpLines);
      }
    }

    if (!oldOffset && oldLength) oldOffset = 1;
    if (!newOffset && newLength) newOffset = 1;
    lines[sepIndex] = lines[sepIndex]
      .replace("{1}", oldOffset).replace("{2}", oldLength)
      .replace("{3}", newOffset).replace("{4}", newLength)
      .replace("{5}", title);

    /* remove trailing   and join lines (with CR for IExplorer) */
    var sep = $.browser.msie ? "\r" : "\n";
    for ( var i = 0; i < lines.length; i++ )
        if ( lines[i] )
        {
            var line = lines[i].replace(/\xa0$/, '') + sep;
            if ( lines[i][0] == '+' )
              pre.append($('').text(line));
            else if ( lines[i][0] == '-' )
              pre.append($('').text(line));
            else
              pre.append($('').text(line));
        }
  }

  $(document).ready(function($) {
    $("div.diff h2").each(function() {
      var switcher = $("").prependTo(this);
      var name = $.trim($(this).text());
      var table = $(this).siblings("table").get(0);
      if (! table) return;
      var pre = $('
').hide().insertAfter(table);
      $("Tabular").click(function() {
        $(pre).hide();
        $(table).show();
        $(this).addClass("active").siblings("span").removeClass("active");
        return false;
      }).addClass("active").appendTo(switcher);
      $("Unified").click(function() {
        $(table).hide();
        if (!pre.get(0).firstChild) convertDiff(name, table, pre);
        $(pre).fadeIn("fast")
        $(this).addClass("active").siblings("span").removeClass("active");
        return false;
      }).appendTo(switcher);
    });
  });

})(jQuery);
<commit_msg>Fix js conversion of rendered patch to plain text view.<commit_after>(function($){

  function convertDiff(name, table, pre) {
    var inline = $(table).hasClass('inline');
    var ths = table.tHead.rows[0].cells;
    var afile, bfile;
    if ( inline ) {
        afile = ths[0].title;
        bfile = ths[1].title;
    } else {
        afile = $(ths[0]).find('a').text();
        bfile = $(ths[1]).find('a').text();
    }
    if ( afile.match(/^Revision /) ) {
        afile = 'a/' + name;
        bfile = 'b/' + name;
    }
    var lines = [
      "Index: " + name,
      "===================================================================",
      "--- " + afile.replace(/File /, ''),
      "+++ " + bfile.replace(/File /, ''),
    ];
    var sepIndex = 0;
    var oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
    var title = "";
    if (inline)
      title = $(ths[2]).text();

    for (var i = 0; i
 0) {
          if (!oldOffset && oldLength) oldOffset = 1
          if (!newOffset && newLength) newOffset = 1
          lines[sepIndex] = lines[sepIndex]
            .replace("{1}", oldOffset).replace("{2}", oldLength)
            .replace("{3}", newOffset).replace("{4}", newLength)
            .replace("{5}", title);
        }
        sepIndex = lines.length;
        lines.push("@@ -{1},{2} +{3},{4} @@{5}");
        oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
        if (tBody.className == "skipped") {
          if (inline)
            title = $(tBody.rows[0].cells[2]).text();
          continue;
        }
      }
      var tmpLines = [];
      for (var j = 0; j < tBody.rows.length; j++) {
        var cells = tBody.rows[j].cells;
        var oldLineNo = parseInt($(cells[0]).text());
        var newLineNo = parseInt($(cells[inline ? 1 : 2]).text());
        if (tBody.className == 'unmod') {
          lines.push(" " + $(cells[inline ? 2 : 1]).text());
          oldLength += 1;
          newLength += 1;
          if (!oldOffset) oldOffset = oldLineNo;
          if (!newOffset) newOffset = newLineNo;
        } else {
          var oldLine;
          var newLine;
          var oldTag = "-";
          var newTag = "+";
          if (inline) {
            oldLine = newLine = $(cells[2]).text();
            if ($('em', cells[2]).length) oldTag = newTag = "\\";
          } else {
            oldLine = $(cells[1]).text();
            if ($('em', cells[1]).length) oldTag = "\\";
            newLine = $(cells[3]).text();
            if ($('em', cells[3]).length) newTag = "\\";
          }
          if (!isNaN(oldLineNo)) {
            lines.push(oldTag + oldLine);
            oldLength += 1;
          }
          if (!isNaN(newLineNo)) {
            tmpLines.push(newTag + newLine);
            newLength += 1;
          }
        }
      }
      if (tmpLines.length > 0) {
        lines = lines.concat(tmpLines);
      }
    }

    if (!oldOffset && oldLength) oldOffset = 1;
    if (!newOffset && newLength) newOffset = 1;
    lines[sepIndex] = lines[sepIndex]
      .replace("{1}", oldOffset).replace("{2}", oldLength)
      .replace("{3}", newOffset).replace("{4}", newLength)
      .replace("{5}", title);

    /* remove trailing   and join lines (with CR for IExplorer) */
    var sep = $.browser.msie ? "\r" : "\n";
    for ( var i = 0; i < lines.length; i++ )
        if ( lines[i] )
        {
            var line = lines[i].replace(/\xa0$/, '') + sep;
            if ( lines[i][0] == '+' )
              pre.append($('').text(line));
            else if ( lines[i][0] == '-' )
              pre.append($('').text(line));
            else
              pre.append($('').text(line));
        }
  }

  $(document).ready(function($) {
    $("div.diff h2").each(function() {
      var switcher = $("").prependTo(this);
      var name = $.trim($(this).text());
      var table = $(this).siblings("table").get(0);
      if (! table) return;
      var pre = $('
').hide().insertAfter(table);
      $("Tabular").click(function() {
        $(pre).hide();
        $(table).show();
        $(this).addClass("active").siblings("span").removeClass("active");
        return false;
      }).addClass("active").appendTo(switcher);
      $("Unified").click(function() {
        $(table).hide();
        if (!pre.get(0).firstChild) convertDiff(name, table, pre);
        $(pre).fadeIn("fast")
        $(this).addClass("active").siblings("span").removeClass("active");
        return false;
      }).appendTo(switcher);
    });
  });

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var $ = React.DOM;

var ou = require('../../objectUtils');

var errorClass = function(errors) {
  if(!errors || errors.length === 0) {
    return '';
  }

  return 'error';
};

var makeTitle = function(description, errors) {
  var parts = [];
  if (description && description.length > 0) {
    parts.push(description);
  }
  if (errors && errors.length > 0) {
    parts.push(errors.join('\n'));
  }
  return parts.join('\n\n');
};

var FieldWrapper = React.createClass({
  render: function() {
    var classes = [].concat(errorClass(this.props.errors) || [],
                            'form-element',
                            this.props.classes || []);

    return $.div(
      {
        className: classes.join(' '),
        key      : this.props.label,
        title    : makeTitle(this.props.description, this.props.errors)
      },
      $.label(
        {
          htmlFor: this.props.label
        },
        this.props.title),
      this.props.children);
  }
});

var SectionWrapper = React.createClass({
  render: function() {
    var level = this.props.path.length;
    var classes = [].concat('form-section',
                            (level > 0 ? 'form-subsection' : []),
                            this.props.classes || []);
    var legendClasses = [].concat(errorClass(this.props.errors) || [],
                                  'form-section-title');

    return $.fieldset(
      {
        className: classes.join(' '),
        key      : this.props.label
      },
      $.legend(
        {
          className: legendClasses.join(' '),
          title    : makeTitle(this.props.description, this.props.errors)
        },
        this.props.title),
      this.props.children);
  }
});

var propsForWrapper = function(props, section) {
  var propsFW = {
    key        : props.key,
    label      : props.label,
    path       : props.path,
    errors     : props.errors,
    classes    : ou.getIn(props.schema, ['x-hints', 'form', 'classes']),
    title      : props.schema.title,
    type       : props.schema.type,
    description: props.schema.description
  };

  if(section && props.isArrayItem) {
    propsFW = ou.merge(propsFW, {
      moveUp     : props.moveUp,
      moveDown   : props.moveDown,
      canMoveUp  : props.canMoveUp,
      canMoveDown: props.canMoveDown,
      isArrayItem: props.isArrayItem
    });
  }

  return propsFW;
};

exports.section = function(props, fields) {
  return React.createElement(props.sectionWrapper || SectionWrapper,
    propsForWrapper(props, true),
    fields);
};

exports.field = function(props, field) {
  return React.createElement(props.fieldWrapper || FieldWrapper,
    propsForWrapper(props),
    field);
};
<commit_msg>Use item title for collapsable on arrays<commit_after>'use strict';

var React = require('react');
var $ = React.DOM;

var ou = require('../../objectUtils');

var errorClass = function(errors) {
  if(!errors || errors.length === 0) {
    return '';
  }

  return 'error';
};

var makeTitle = function(description, errors) {
  var parts = [];
  if (description && description.length > 0) {
    parts.push(description);
  }
  if (errors && errors.length > 0) {
    parts.push(errors.join('\n'));
  }
  return parts.join('\n\n');
};

var FieldWrapper = React.createClass({
  render: function() {
    var classes = [].concat(errorClass(this.props.errors) || [],
                            'form-element',
                            this.props.classes || []);

    return $.div(
      {
        className: classes.join(' '),
        key      : this.props.label,
        title    : makeTitle(this.props.description, this.props.errors)
      },
      $.label(
        {
          htmlFor: this.props.label
        },
        this.props.title),
      this.props.children);
  }
});

var SectionWrapper = React.createClass({
  render: function() {
    var level = this.props.path.length;
    var classes = [].concat('form-section',
                            (level > 0 ? 'form-subsection' : []),
                            this.props.classes || []);
    var legendClasses = [].concat(errorClass(this.props.errors) || [],
                                  'form-section-title');

    return $.fieldset(
      {
        className: classes.join(' '),
        key      : this.props.label
      },
      $.legend(
        {
          className: legendClasses.join(' '),
          title    : makeTitle(this.props.description, this.props.errors)
        },
        this.props.title),
      this.props.children);
  }
});

var propsForWrapper = function(props, section) {
  var propsFW = {
    key        : props.key,
    label      : props.label,
    path       : props.path,
    errors     : props.errors,
    classes    : ou.getIn(props.schema, ['x-hints', 'form', 'classes']),
    title      : props.schema.title,
    type       : props.schema.type,
    description: props.schema.description
  };

  if(section && props.isArrayItem) {
    if(props.isArrayItem) {
      var vals = props.getValue(props.path);
      var title = props.title;
      if(vals) {
        var itemHeaderKey = ou.getIn(props.schema, ['x-hints', 'itemHeader', "property"]);
        var itemHeader = (itemHeaderKey && vals[itemHeaderKey]) || vals.title || vals.name;
        title = title && itemHeader ? title + " - " + itemHeader : itemHeader || title;
      }

      propsFW = ou.merge(propsFW, {
        title      : title,
        moveUp     : props.moveUp,
        moveDown   : props.moveDown,
        canMoveUp  : props.canMoveUp,
        canMoveDown: props.canMoveDown
      });
    }

    propsFW = ou.merge(propsFW, {
      isArrayItem: props.isArrayItem
    });
  }

  return propsFW;
};

exports.section = function(props, fields) {
  return React.createElement(props.sectionWrapper || SectionWrapper,
    propsForWrapper(props, true),
    fields);
};

exports.field = function(props, field) {
  return React.createElement(props.fieldWrapper || FieldWrapper,
    propsForWrapper(props),
    field);
};
<|endoftext|>


<commit_before>'use strict';

jest.mock('@strapi/strapi/lib/utils/ee', () => {
  const eeModule = () => false;

  Object.assign(eeModule, {
    features: {
      isEnabled() {
        return false;
      },
      getEnabled() {
        return [];
      },
    },
  });

  return eeModule;
});

const adminController = require('../admin');

describe('Admin Controller', () => {
  describe('init', () => {
    beforeAll(() => {
      global.strapi = {
        config: {
          get: jest.fn(() => 'foo'),
        },
        admin: {
          services: {
            user: {
              exists: jest.fn(() => true),
            },
          },
        },
      };
    });

    test('Returns the uuid and if the app has admins', async () => {
      const result = await adminController.init();

      expect(global.strapi.config.get).toHaveBeenCalledWith('uuid', false);
      expect(global.strapi.admin.services.user.exists).toHaveBeenCalled();
      expect(result.data).toBeDefined();
      expect(result.data).toStrictEqual({
        uuid: 'foo',
        hasAdmin: true,
      });
    });
  });

  describe('information', () => {
    beforeAll(() => {
      global.strapi = {
        config: {
          get: jest.fn(
            (key, value) =>
              ({
                autoReload: undefined,
                'info.strapi': '1.0.0',
                environment: 'development',
              }[key] || value)
          ),
        },
        EE: true,
      };
    });

    test('Returns application information', async () => {
      const result = await adminController.information();

      expect(global.strapi.config.get.mock.calls).toEqual([
        ['environment'],
        ['autoReload', false],
        ['info.strapi', null],
      ]);
      expect(result.data).toBeDefined();
      expect(result.data).toStrictEqual({
        currentEnvironment: 'development',
        autoReload: false,
        strapiVersion: '1.0.0',
        nodeVersion: process.version,
        communityEdition: false,
        useYarn: true,
      });
    });
  });
});
<commit_msg>Adjusted admin tests to reflect changes with telemetry<commit_after>'use strict';

jest.mock('@strapi/strapi/lib/utils/ee', () => {
  const eeModule = () => false;

  Object.assign(eeModule, {
    features: {
      isEnabled() {
        return false;
      },
      getEnabled() {
        return [];
      },
    },
  });

  return eeModule;
});

const adminController = require('../admin');

describe('Admin Controller', () => {
  describe('init', () => {
    beforeAll(() => {
      global.strapi = {
        config: {
          get: jest.fn(() => 'foo'),
        },
        admin: {
          services: {
            user: {
              exists: jest.fn(() => true),
            },
          },
        },
      };
    });

    test('Returns the uuid and if the app has admins', async () => {
      const result = await adminController.init();

      expect(global.strapi.config.get).toHaveBeenCalledWith('uuid', false);
      expect(global.strapi.config.get).toHaveBeenCalledWith(
        'packageJsonStrapi.telemetryDisabled',
        false
      );
      expect(global.strapi.admin.services.user.exists).toHaveBeenCalled();
      expect(result.data).toBeDefined();
      expect(result.data).toStrictEqual({
        uuid: 'foo',
        telemetryDisabled: 'foo',
        hasAdmin: true,
      });
    });
  });

  describe('information', () => {
    beforeAll(() => {
      global.strapi = {
        config: {
          get: jest.fn(
            (key, value) =>
              ({
                autoReload: undefined,
                'info.strapi': '1.0.0',
                environment: 'development',
              }[key] || value)
          ),
        },
        EE: true,
      };
    });

    test('Returns application information', async () => {
      const result = await adminController.information();

      expect(global.strapi.config.get.mock.calls).toEqual([
        ['environment'],
        ['autoReload', false],
        ['info.strapi', null],
      ]);
      expect(result.data).toBeDefined();
      expect(result.data).toStrictEqual({
        currentEnvironment: 'development',
        autoReload: false,
        strapiVersion: '1.0.0',
        nodeVersion: process.version,
        communityEdition: false,
        useYarn: true,
      });
    });
  });
});
<|endoftext|>


<commit_before>var examplesParser = require('../lib/parseXMLExamples');
var Example = require('docpack/lib/data/Example');
var ExampleFile = require('docpack/lib/data/ExampleFile');

function parse(input) {
  return examplesParser(input)[0];
}

function parseAndGetFirstFile(input) {
  return examplesParser(input)[0].files[0];
}

describe('xmlExampleParser', () => {

  it('should return empty array if no examples found', () => {
    var input = ['\n', '\n', '   ', '\n', '  \n'].join('');
    examplesParser(input).should.be.a('array').and.be.empty;

    input = 'var a = 123; <file></file>';
    examplesParser(input).should.be.a('array').and.be.empty;
  });

  describe('<example>', () => {
    it('should NOT skip empty <example> tags', () => {
      var input = '<example></example>';
      parse(input).should.be.instanceOf(Example);
    });

    it('should copy all <example> tag attributes to Example attrs', () => {
      var example = parse('<example attr1="value1" attr2="true" foo="false"></example>');
      example.attrs.should.be.deep.equal({
        attr1: 'value1', attr2: 'true', foo: 'false'
      })
    });
  });

  describe('<file>', () => {
    it('should NOT skip empty <file> tags', () => {
      var example = parse('<example><file></file></example>');
      example.files.should.be.a('array').and.be.lengthOf(1);
      example.files[0].should.be.instanceOf(ExampleFile);
    });

    it('should copy all <file> tag attributes to ExampleFile attrs', () => {
      var file = parseAndGetFirstFile('<example><file type="js" name="index.js" foo="false">c</file></example>');
      file.should.be.instanceOf(ExampleFile);
      file.attrs.should.be.deep.equal({
        type: 'js', name: 'index.js', foo: 'false'
      })
    });

    it('should not modify file content (strip indents only)', () => {
      var file = parseAndGetFirstFile('<example><file>\n  var foo = "bar<tag></tag>";\n\n</file></example>');
      file.content.should.be.a('string').and.eql('\nvar foo = "bar<tag></tag>";\n\n');
    });

    it('should allow < signs inside <file> tags', () => {
      var file = parseAndGetFirstFile('<example><file>for (var i = 0; i < length; i++) {}</file></example>');
      file.content.should.be.a('string').and.eql('for (var i = 0; i < length; i++) {}');
    });

    it('should treat file type as "js" by default', () => {
      var file = parseAndGetFirstFile('<example><file>var a = 123;</file></example>');
      file.type.should.be.eql('js');
    });

    it('should detect file type by type attr', () => {
      var file = parseAndGetFirstFile('<example><file type="js" name="index.html">c</file></example>');
      file.type.should.be.eql('js');
    });
  });
});<commit_msg>Add some tests to check content property of Example<commit_after>var examplesParser = require('../lib/parseXMLExamples');
var Example = require('docpack/lib/data/Example');
var ExampleFile = require('docpack/lib/data/ExampleFile');

function parse(input) {
  return examplesParser(input)[0];
}

function parseAndGetFirstFile(input) {
  return examplesParser(input)[0].files[0];
}

describe('xmlExampleParser', () => {

  it('should return empty array if no examples found', () => {
    var input = ['\n', '\n', '   ', '\n', '  \n'].join('');
    examplesParser(input).should.be.a('array').and.be.empty;

    input = 'var a = 123; <file></file>';
    examplesParser(input).should.be.a('array').and.be.empty;
  });

  describe('<example>', () => {
    it('should NOT skip empty <example> tags', () => {
      var input = '<example></example>';
      var example = parse(input);
      example.should.be.instanceOf(Example);
      example.should.have.a.property('content').and.equal('');
    });

    it('should copy all <example> tag attributes to Example attrs', () => {
      var example = parse('<example attr1="value1" attr2="true" foo="false"></example>');
      example.should.have.a.property('content').and.equal('');
      example.attrs.should.be.deep.equal({
        attr1: 'value1', attr2: 'true', foo: 'false'
      })
    });
  });

  describe('<file>', () => {
    it('should NOT skip empty <file> tags', () => {
      var example = parse('<example><file></file></example>');
      example.should.have.a.property('content').and.equal('<file></file>');
      example.files.should.be.a('array').and.be.lengthOf(1);
      example.files[0].should.be.instanceOf(ExampleFile);
    });

    it('should copy all <file> tag attributes to ExampleFile attrs', () => {
      var file = parseAndGetFirstFile('<example><file type="js" name="index.js" foo="false">c</file></example>');
      file.should.be.instanceOf(ExampleFile);
      file.attrs.should.be.deep.equal({
        type: 'js', name: 'index.js', foo: 'false'
      })
    });

    it('should not modify file content (strip indents only)', () => {
      var file = parseAndGetFirstFile('<example><file>\n  var foo = "bar<tag></tag>";\n\n</file></example>');
      file.content.should.be.a('string').and.eql('\nvar foo = "bar<tag></tag>";\n\n');
    });

    it('should allow < signs inside <file> tags', () => {
      var file = parseAndGetFirstFile('<example><file>for (var i = 0; i < length; i++) {}</file></example>');
      file.content.should.be.a('string').and.eql('for (var i = 0; i < length; i++) {}');
    });

    it('should treat file type as "js" by default', () => {
      var file = parseAndGetFirstFile('<example><file>var a = 123;</file></example>');
      file.type.should.be.eql('js');
    });

    it('should detect file type by type attr', () => {
      var file = parseAndGetFirstFile('<example><file type="js" name="index.html">c</file></example>');
      file.type.should.be.eql('js');
    });
  });
});<|endoftext|>


<commit_before>ig.module('game.entities.zombie')
.requires(
  'impact.impact',
  'impact.entity',
  'game.entities.particle-spawner',
  'game.effects.zombie-giblet',
  'game.effects.blood-giblet',
  'game.entities.dead-zombie'
)
.defines(function() {
  EntityZombie = ig.Entity.extend({
    // don't allow the editor to scale our object
    _wmScalable: false,

    // always draw a box around us
    _wmDrawBox: true,
    _wmBoxColor: 'rgba(255, 170, 66, 0.7)',

    pointValue: 100,

    animSheet: new ig.AnimationSheet( 'media/zombie.png', 32, 32 ),
    zIndex: 9,

    // the size of our collider
    size: { x: 8, y: 32 },

    health: 9,
    maxHealth: 9,

    deathEntity: EntityDeadZombie,

    // the offset of collider
    offset: { x: 12, y: 0 },

    // movement variables
    maxVel: { x: 6, y: 100 },
    friction: { x: 2000, y: 2000 },
    accel: { x: 0, y: 0 },
    gravityFactor: 10,

    speed: 2000,

    // collision settings, collide against player
    type: ig.Entity.TYPE.B,
    checkAgainst: ig.Entity.TYPE.A,
    collides: ig.Entity.COLLIDES.PASSIVE,

    init: function( x, y, settings ) {
      this.parent( x, y, settings );

      // setup animations
      // true means do not repeat
      // idle is a system animation, called by default
      this.addAnim( 'idle', 3, [0], true);
      this.addAnim( 'walk', 0.3, [1,2,3,4,5,6,7,8]);

      this.flip = settings.flip || false;
    },

    kill: function() {
      // when the zombie dies, spawn a bunch of "giblets"
      var pos = {
        x: this.pos.x + ( 16 * (this.flip ? -1 : 1)) / 2,
        y: this.pos.y + this.size.y / 2
      };
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectZombieGiblet,
        particles: 5
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectBloodGiblet,
        particles: 3
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectZombieGibletSmall,
        particles: 30
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectBloodGibletSmall,
        particles: 10
      });

      ig.game.spawnEntity( this.deathEntity, this.pos.x, this.pos.y, {
        flip: this.flip
      });

      // increase the players score
      if(this.lastDamageAmount < this.maxHealth) {
        // player shot too far away from the zombie
        // so they won't get as many points
        this.pointValue /= 2;
      }
      ig.game.hud.addPoints(this.pointValue);

      this.parent();
    },

    receiveDamage: function(amt, other) {
      this.parent(amt, other);
      this.lastDamageAmount = amt;
    },

    check: function(other) {
      // when a zombie hits the player
      // the player should take damage
      other.receiveDamage(10, this);
    },

    update: function() {
      // check the collision map, see if we're at the
      // edge of a platform, if so then we need to turn around
      var isNearWall = ig.game.collisionMap.getTile && !ig.game.collisionMap.getTile(
        this.pos.x + (this.flip ? +4 : this.size.x - 4),
        this.pos.y + this.size.y+1
      );

      if(isNearWall) {
        this.flip = !this.flip;
      }

      if ( this.vel.x != 0 ) {
        this.currentAnim = this.anims.walk;
      }

      this.accel.x = this.speed * (this.flip ? -1 : 1);
      this.currentAnim.flip.x = this.flip;

      this.parent();
    },

    handleMovementTrace: function( res ) {
      this.parent(res);

      // check the collision map, see if we're colliding with
      // a collision tile, if so then we need to turn around
      if( res.collision.x ) {
        this.flip = !this.flip;
      }
    }
  });
});
<commit_msg>fix particle spawning when flipped/normal<commit_after>ig.module('game.entities.zombie')
.requires(
  'impact.impact',
  'impact.entity',
  'game.entities.particle-spawner',
  'game.effects.zombie-giblet',
  'game.effects.blood-giblet',
  'game.entities.dead-zombie'
)
.defines(function() {
  EntityZombie = ig.Entity.extend({
    // don't allow the editor to scale our object
    _wmScalable: false,

    // always draw a box around us
    _wmDrawBox: true,
    _wmBoxColor: 'rgba(255, 170, 66, 0.7)',

    pointValue: 100,

    animSheet: new ig.AnimationSheet( 'media/zombie.png', 32, 32 ),
    zIndex: 9,

    // the size of our collider
    size: { x: 8, y: 32 },

    health: 9,
    maxHealth: 9,

    deathEntity: EntityDeadZombie,

    // the offset of collider
    offset: { x: 12, y: 0 },

    // movement variables
    maxVel: { x: 6, y: 100 },
    friction: { x: 2000, y: 2000 },
    accel: { x: 0, y: 0 },
    gravityFactor: 10,

    speed: 2000,

    // collision settings, collide against player
    type: ig.Entity.TYPE.B,
    checkAgainst: ig.Entity.TYPE.A,
    collides: ig.Entity.COLLIDES.PASSIVE,

    init: function( x, y, settings ) {
      this.parent( x, y, settings );

      // setup animations
      // true means do not repeat
      // idle is a system animation, called by default
      this.addAnim( 'idle', 3, [0], true);
      this.addAnim( 'walk', 0.3, [1,2,3,4,5,6,7,8]);

      this.flip = settings.flip || false;
    },

    kill: function() {
      // when the zombie dies, spawn a bunch of "giblets"
      var pos = {
        x: this.pos.x + this.size.x / 2,
        y: this.pos.y + this.size.y / 2
      };
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectZombieGiblet,
        particles: 5
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectBloodGiblet,
        particles: 3
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectZombieGibletSmall,
        particles: 30
      });
      ig.game.spawnEntity( EntityParticleSpawner, pos.x, pos.y, {
        Particle: EffectBloodGibletSmall,
        particles: 10
      });

      ig.game.spawnEntity( this.deathEntity, this.pos.x, this.pos.y, {
        flip: this.flip
      });

      // increase the players score
      if(this.lastDamageAmount < this.maxHealth) {
        // player shot too far away from the zombie
        // so they won't get as many points
        this.pointValue /= 2;
      }
      ig.game.hud.addPoints(this.pointValue);

      this.parent();
    },

    receiveDamage: function(amt, other) {
      this.parent(amt, other);
      this.lastDamageAmount = amt;
    },

    check: function(other) {
      // when a zombie hits the player
      // the player should take damage
      other.receiveDamage(10, this);
    },

    update: function() {
      // check the collision map, see if we're at the
      // edge of a platform, if so then we need to turn around
      var isNearWall = ig.game.collisionMap.getTile && !ig.game.collisionMap.getTile(
        this.pos.x + (this.flip ? +4 : this.size.x - 4),
        this.pos.y + this.size.y+1
      );

      if(isNearWall) {
        this.flip = !this.flip;
      }

      if ( this.vel.x != 0 ) {
        this.currentAnim = this.anims.walk;
      }

      this.accel.x = this.speed * (this.flip ? -1 : 1);
      this.currentAnim.flip.x = this.flip;

      this.parent();
    },

    handleMovementTrace: function( res ) {
      this.parent(res);

      // check the collision map, see if we're colliding with
      // a collision tile, if so then we need to turn around
      if( res.collision.x ) {
        this.flip = !this.flip;
      }
    }
  });
});
<|endoftext|>


<commit_before>"use strict";

var fs = require("fs");
var uuid = require("node-uuid");

var generateNewPath = function (path) {
    return path.replace(/[^\/]*(\.[a-z]{3,4})$/, uuid.v4() + "$1");
};

module.exports = function getUniqueFilePath(path, cb) {
    fs.exists(path, function (exists) {
        if (exists) {
            var newPath = generateNewPath(path);
            return getUniqueFilePath(newPath, cb);
        }

        cb(path);
    });
};
<commit_msg>remove rename file race condition with a recently used file names cache<commit_after>"use strict";

var fs = require("fs");
var uuid = require("node-uuid");
var recentlyUsedFileNames = [];
var lastLength = 0;

var generateNewPath = function (path) {
    return path.replace(/[^\/]*(\.[a-z]{3,4})$/, uuid.v4() + "$1");
};

module.exports = function getUniqueFilePath(path, cb) {
    fs.exists(path, function (exists) {
        if (exists || recentlyUsedFileNames.indexOf(path) != -1) {
            var newPath = generateNewPath(path);
            return getUniqueFilePath(newPath, cb);
        }

        recentlyUsedFileNames.push(path);
        cb(path);
    });
};

setInterval(function () {
    if (!lastLength) {
        lastLength = recentlyUsedFileNames.length;
        return;
    }

    recentlyUsedFileNames = recentlyUsedFileNames.slice(lastLength);
    lastLength = recentlyUsedFileNames.length;
}, 60000);
<|endoftext|>


<commit_before>/*
 * index.js: Top-level include for the `producers` module responsible creating events to process.
 *
 * (C) 2012, Nodejitsu Inc.
 *
 */

var utile = require('utile');

//
// ### function producer (options)
// #### @options {Object} Options to use when instantiating this producer
// Creates a new producer for emitting events to process.
//
var producer = module.exports = function (options) {
  return new producer.Producer(options);
};

//
// ### @Producer {Object}
// Base Prototype for the Producer.
//
producer.Producer = require('./producer');<commit_msg>Dead code<commit_after>/*
 * index.js: Top-level include for the `producers` module responsible creating events to process.
 *
 * (C) 2012, Nodejitsu Inc.
 *
 */

//
// ### function producer (options)
// #### @options {Object} Options to use when instantiating this producer
// Creates a new producer for emitting events to process.
//
var producer = module.exports = function (options) {
  return new producer.Producer(options);
};

//
// ### @Producer {Object}
// Base Prototype for the Producer.
//
producer.Producer = require('./producer');<|endoftext|>


<commit_before>App.ProgressBarStackedComponent = Ember.Component.extend({
  overallWidth: '100%',
  thresholdOne: null,
  thresholdTwo: null,
  thresholdThree: null,
  thresholdMax: Ember.computed.alias('thresholdThree'),
  barLabel1: false,
  backgroundWidths: function() {
    var sum = Number(this.get('progressBarTwoPercent')) + Number(this.get('progressBarOnePercent'));
    return 'background-image:'+
      'linear-gradient('+
      ' to right,'+
      ' rgba(94, 185, 94, 0.3), '+
      ' rgba(94, 185, 94, 0.3) ' + this.get('progressBarOnePercent') + '%,'+
      ' rgba(250, 167, 50, 0.3) '+ this.get('progressBarOnePercent') + '%,'+
      ' rgba(250, 167, 50, 0.3) '+ sum + '%,' +
      ' rgba(221, 81, 76, 0.3) ' + sum + '%' +
      ');';
  }.property('progressBarOnePercent', 'progressBarTwoPercent', 'progressBarThreePercent'),
  progressStyle: function() {
    return 'width:' + this.get('overallWidth') + '; ' +
      this.get('backgroundWidths') +
      'overflow:visible;'+
      'position:relative;'+
      'height:10px;'+
      'margin-top:10px;'+
      'margin-left:5px;'+
      'text-align:center;';
  }.property('overallWidth', 'backgroundWidths'),
  currentValueStyle: function() {
    var right = ~~this.get('barRange1Percentage') + ~~this.get('barRange2Percentage') + ~~this.get('barRange3Percentage');
    right = 100 - right;
    if (right < 10) { // this is here for small case. consider extending later for different sizes.
      right = 0;
    } else if (right < 95) {
      right = right - 1;
    } else {
      right = right - 15;
    }
    return 'position:absolute; bottom:-14px; right:'+right+'%';
  }.property('value'),

  barLabel1Style: function() {
    var right = ~~this.get('progressBarTwoPercent') + ~~this.get('progressBarThreePercent');
    return 'position:absolute; bottom:7px; right:'+right+'%';
  }.property('value'),

  progressBarOnePercent: function() {
    return 100 * this.get('thresholdOne') / this.get('thresholdMax');
  }.property('thresholdOne', 'thresholdMax', 'value'),
  progressBarTwoPercent: function() {
    return 100 * (this.get('thresholdTwo') - this.get('thresholdOne')) / this.get('thresholdMax');
  }.property('thresholdOne', 'thresholdTwo', 'thresholdMax', 'value'),
  progressBarThreePercent: function() {
    return 100 * (this.get('thresholdThree') - this.get('thresholdTwo')) / this.get('thresholdMax');
  }.property('thresholdTwo', 'thresholdThree', 'thresholdMax', 'value'),

  barRange1Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdOne'));
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdOne', 'thresholdMax'),
  barRange2Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdTwo')) - this.get('thresholdOne');
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdOne', 'thresholdTwo'),
  barRange3Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdThree')) - this.get('thresholdTwo');
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdTwo','thresholdThree'),

  barRange1Style: function() {
    return 'width:' + this.get('barRange1Percentage') + '%; position:relative;';
  }.property('barRange1Percentage'),
  barRange2Style: function() {
    return 'width:' + this.get('barRange2Percentage') + '%; position:relative;';
  }.property('barRange2Percentage'),
  barRange3Style: function() {
    return 'width:' + this.get('barRange3Percentage') + '%; position:relative;';
  }.property('barRange3Percentage')
});
<commit_msg>Address styling on utilization allocation<commit_after>App.ProgressBarStackedComponent = Ember.Component.extend({
  overallWidth: '100%',
  thresholdOne: null,
  thresholdTwo: null,
  thresholdThree: null,
  thresholdMax: Ember.computed.alias('thresholdThree'),
  barLabel1: false,
  backgroundWidths: function() {
    var sum = Number(this.get('progressBarTwoPercent')) + Number(this.get('progressBarOnePercent'));
    return 'background-image:'+
      'linear-gradient('+
      ' to right,'+
      ' rgba(94, 185, 94, 0.3), '+
      ' rgba(94, 185, 94, 0.3) ' + this.get('progressBarOnePercent') + '%,'+
      ' rgba(250, 167, 50, 0.3) '+ this.get('progressBarOnePercent') + '%,'+
      ' rgba(250, 167, 50, 0.3) '+ sum + '%,' +
      ' rgba(221, 81, 76, 0.3) ' + sum + '%' +
      ');';
  }.property('progressBarOnePercent', 'progressBarTwoPercent', 'progressBarThreePercent'),
  progressStyle: function() {
    return 'width:' + this.get('overallWidth') + '; ' +
      this.get('backgroundWidths') +
      'overflow:visible;'+
      'position:relative;'+
      'height:10px;'+
      'margin-top:10px;'+
      'margin-left:5px;'+
      'text-align:center;';
  }.property('overallWidth', 'backgroundWidths'),
  currentValueStyle: function() {
    var right = ~~this.get('barRange1Percentage') + ~~this.get('barRange2Percentage') + ~~this.get('barRange3Percentage');
    right = 100 - right;
    if (right < 10) { // this is here for small case. consider extending later for different sizes.
      right = 0;
    } else if (right < 95) {
      right = right - 1;
    } else {
      right = right - 15;
    }
    return 'position:absolute; bottom:-14px; right:'+right+'%';
  }.property('value'),

  barLabel1Style: function() {
    var right = ~~this.get('progressBarTwoPercent') + ~~this.get('progressBarThreePercent');
    return 'position:absolute; bottom:6px; right:'+right+'%';
  }.property('value', 'progressBarTwoPercent', 'progressBarThreePercent'),

  progressBarOnePercent: function() {
    return 100 * this.get('thresholdOne') / this.get('thresholdMax');
  }.property('thresholdOne', 'thresholdMax', 'value'),
  progressBarTwoPercent: function() {
    return 100 * (this.get('thresholdTwo') - this.get('thresholdOne')) / this.get('thresholdMax');
  }.property('thresholdOne', 'thresholdTwo', 'thresholdMax', 'value'),
  progressBarThreePercent: function() {
    return 100 * (this.get('thresholdThree') - this.get('thresholdTwo')) / this.get('thresholdMax');
  }.property('thresholdTwo', 'thresholdThree', 'thresholdMax', 'value'),

  barRange1Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdOne'));
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdOne', 'thresholdMax'),
  barRange2Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdTwo')) - this.get('thresholdOne');
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdOne', 'thresholdTwo'),
  barRange3Percentage: function() {
    var width = Math.min(this.get('value'), this.get('thresholdThree')) - this.get('thresholdTwo');
    width = Math.max(width, 0);
    return 100 * width / this.get('thresholdMax');
  }.property('value', 'thresholdTwo','thresholdThree'),

  barRange1Style: function() {
    return 'width:' + this.get('barRange1Percentage') + '%; position:relative;';
  }.property('barRange1Percentage'),
  barRange2Style: function() {
    return 'width:' + this.get('barRange2Percentage') + '%; position:relative;';
  }.property('barRange2Percentage'),
  barRange3Style: function() {
    return 'width:' + this.get('barRange3Percentage') + '%; position:relative;';
  }.property('barRange3Percentage')
});
<|endoftext|>


<commit_before>
const errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];

function Exception(message, node) {
  let loc = node && node.loc,
      line,
      column;
  if (loc) {
    line = loc.start.line;
    column = loc.start.column;

    message += ' - ' + line + ':' + column;
  }

  let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line);

  // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
  for (let idx = 0; idx < errorProps.length; idx++) {
    this[errorProps[idx]] = tmp[errorProps[idx]];
  }

  /* istanbul ignore else */
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, Exception);
  }

  try {
    if (loc) {
      this.lineNumber = line;

      // Work around issue under safari where we can't directly set the column value
      /* istanbul ignore next */
      if (Object.defineProperty) {
        Object.defineProperty(this, 'column', {value: column});
      } else {
        this.column = column;
      }
    }
  } catch (nop) {
    /* Ignore if the browser is very particular */
  }
}

Exception.prototype = new Error();

export default Exception;
<commit_msg>Drop extra Error params<commit_after>
const errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];

function Exception(message, node) {
  let loc = node && node.loc,
      line,
      column;
  if (loc) {
    line = loc.start.line;
    column = loc.start.column;

    message += ' - ' + line + ':' + column;
  }

  let tmp = Error.prototype.constructor.call(this, message);

  // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
  for (let idx = 0; idx < errorProps.length; idx++) {
    this[errorProps[idx]] = tmp[errorProps[idx]];
  }

  /* istanbul ignore else */
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, Exception);
  }

  try {
    if (loc) {
      this.lineNumber = line;

      // Work around issue under safari where we can't directly set the column value
      /* istanbul ignore next */
      if (Object.defineProperty) {
        Object.defineProperty(this, 'column', {value: column});
      } else {
        this.column = column;
      }
    }
  } catch (nop) {
    /* Ignore if the browser is very particular */
  }
}

Exception.prototype = new Error();

export default Exception;
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var path			= require('path')
	, _ = require('lodash');

/**
 * Adds res.view() method (an enhanced version of res.render) to response object.
 * `res.view()` automatically renders the appropriate view based on the calling middleware's source route
 * Note: the original function is still accessible via res.render()
 *
 * @param {Request}  req
 * @param {Response} res
 * @param {Function} next
 */

module.exports = function _addResViewMethod(req, res, next) {

	var sails = req._sails;

	/**
	 * res.view([specifiedPath|locals], [locals])
	 *
	 * @param {String} specifiedPath
	 *				-> path to the view file to load (minus the file extension)
	 *					relative to the app's `views` directory
	 * @param {Object} locals
	 *				-> view locals (data that is accessible in the view template)
	 * @param {Function} cb_view(err)
	 *				-> called when the view rendering is complete (response is already sent, or in the process)
	 *					(probably should be @api private)
	 * @api public
	 */
	res.view = function (specifiedPath, locals, cb_view) {

		sails.log.verbose('Running res.view(' + (specifiedPath ? specifiedPath : '') + ')...');

		// By default, generate a path to the view using what we know about the controller+action
		var relPathToView;

		// Ensure req.target is an object, then merge it into req.options
		// (this helps ensure backwards compatibility for users who were relying
		//  on `req.target` in previous versions of Sails)
		req.options = _.defaults(req.options, req.target || {});

		// Try to guess the view by looking at the controller/action
		if (!req.options.view) {
			relPathToView = req.options.controller + '/' + req.options.action;
		}
		// Use the new view config
		else relPathToView = req.options.view;

		// Now we have a reasonable guess in `relPathToView`

		// If the path to a view was explicitly specified, use that
		// Serve the view specified
		//
		// If first arg is not an object, treat it like the path
		if ( specifiedPath && !_.isObject(specifiedPath)) {
			relPathToView = specifiedPath;
		}
		// If first arg ISSSSS AN object, treat it like locals
		else if (_.isObject(specifiedPath)) {

			// If the "locals" argument is actually the "specifiedPath"
			// give em the old switcheroo
			relPathToView = locals || relPathToView;
			locals = specifiedPath;
		}

		// Ensure specifiedPath is a string (important)
		relPathToView = '' + relPathToView + '';

		// Ensure `locals` is an object
		locals = _.isObject(locals) ? locals : {};

		// Mixin locals from req.options
		if (req.options.locals) {
			locals = _.merge(locals, req.options.locals);
		}

		// Merge with config views locals
		if (sails.config.views.locals) {
			_.defaults(locals, sails.config.views.locals);
		}

		// If the path was specified, but invalid
		// else if (specifiedPath) {
		// 	return res.serverError(new Error('Specified path for view (' + specifiedPath + ') is invalid!'));
		// }

		// Trim trailing slash
		if (relPathToView[(relPathToView.length - 1)] === '/') {
			relPathToView = relPathToView.slice(0, -1);
		}

		// if local `layout` is set to true or unspecified
		// fall back to global config
		var layout = locals.layout;
		if (locals.layout === undefined || locals.layout === true) {
			layout = sails.config.views.layout;
		}

		// Disable sails built-in layouts for all view engine's except for ejs
		if (sails.config.views.engine.ext !== 'ejs') {
			layout = false;
		}

		// Allow `res.locals.layout` to override if it was set:
		if ( typeof res.locals.layout !== 'undefined' ) {
			layout = res.locals.layout;
		}

		var pathToViews = sails.config.paths.views;
		var absPathToView = path.join(pathToViews, relPathToView);
		var absPathToLayout;
		var relPathToLayout;

		// Ensure layout is a string by this point
		if (typeof layout !== 'string') {
			layout = false;
		}

		// Set layout file if enabled (using ejs-locals)
		if (layout) {

			// Solve relative path to layout from the view itself
			// (required by ejs-locals module)
			absPathToLayout = path.join(pathToViews, layout);
			relPathToLayout = path.relative( path.dirname(absPathToView), absPathToLayout);

			// If a layout was specified, set view local so it will be used
			res.locals._layoutFile = relPathToLayout;
			sails.log.silly('Using layout at: ', absPathToLayout);
		}

		// Locals passed in to `res.view()` override app and route locals.
		_.each(locals, function (local, key) {
			res.locals[key] = local;
		});

		// Provide access to view metadata in locals
		// (for convenience)
		res.locals.view = res.locals.view || {
			path: relPathToView,
			absPath: absPathToView,
			pathFromViews: relPathToView,
			pathFromApp: path.join( path.relative(sails.config.appPath, sails.config.paths.views), relPathToView ),
			ext: sails.config.views.engine.ext
		};

		// In development, provide access to complete path to view via `__dirname` local.
		if ( sails.config.environment !== 'production' ) {
			res.locals.__dirname = res.locals.__dirname ||
				absPathToView + '.' + sails.config.views.engine.ext;
		}

		// Render the view
		if (specifiedPath) {
			sails.log.silly('View override argument passed to res.view(): ', specifiedPath);
		}
		sails.log.silly('Serving view at rel path: ', relPathToView);
		sails.log.silly('View root: ', sails.config.paths.views);
		return res.render(relPathToView, function renderView (err, renderedViewStr) {

			// if a template error occurred, don't rely on any of the Sails request/response methods
			// (since they may not exist yet at this point in the request lifecycle.)
			if (err) {
				sails.log.error('Error rendering view at ::',absPathToView);
				sails.log.error('with layout located at ::', absPathToLayout);
				sails.log.error(err && err.message);
				if (process.env.NODE_ENV === 'development') {
					return res.json(500, err);
				}
				else return res.send(500);
			}

			if (layout) { sails.log.verbose('Using layout: ', absPathToLayout); }
			sails.log.verbose('Rendering view ::', relPathToView, '(located @ ' + absPathToView + ')');

			// Backwards compatibility:
			// trigger `res.view` callback if specified
			// (before sending the response)
			if (cb_view) {
				sails.log.warn(
					'Callback function of `res.view([relativePathToView], [options], [cb])`',
					' will be deprecated in an upcoming release.'
				);
				cb_view(err);
			}

			// Finally, send the view down to the client
			res.send(renderedViewStr);

			// Express version updates should be closely monitored.
			// Express is a "hard" dependency.
			//
			// While unlikely this will change, it's worth noting that this implementation
			// relies on express's private implementation of res.render() here:
			// https://github.com/visionmedia/express/blob/master/lib/response.js#L799
			//
			// To be safe, the version of the Express dependency in package.json will remain locked
			// until it can be verified that each subsequent version is compatible.  Even patch releases!!
		});

	};

	next();
};
<commit_msg>Merging locals in a more predictable way<commit_after>/**
 * Module dependencies
 */

var path			= require('path')
	, _ = require('lodash');

/**
 * Adds res.view() method (an enhanced version of res.render) to response object.
 * `res.view()` automatically renders the appropriate view based on the calling middleware's source route
 * Note: the original function is still accessible via res.render()
 *
 * @param {Request}  req
 * @param {Response} res
 * @param {Function} next
 */

module.exports = function _addResViewMethod(req, res, next) {

	var sails = req._sails;

	/**
	 * res.view([specifiedPath|locals], [locals])
	 *
	 * @param {String} specifiedPath
	 *				-> path to the view file to load (minus the file extension)
	 *					relative to the app's `views` directory
	 * @param {Object} locals
	 *				-> view locals (data that is accessible in the view template)
	 * @param {Function} cb_view(err)
	 *				-> called when the view rendering is complete (response is already sent, or in the process)
	 *					(probably should be @api private)
	 * @api public
	 */
	res.view = function (specifiedPath, locals, cb_view) {

		sails.log.verbose('Running res.view(' + (specifiedPath ? specifiedPath : '') + ')...');

		// By default, generate a path to the view using what we know about the controller+action
		var relPathToView;

		// Ensure req.target is an object, then merge it into req.options
		// (this helps ensure backwards compatibility for users who were relying
		//  on `req.target` in previous versions of Sails)
		req.options = _.defaults(req.options, req.target || {});

		// Try to guess the view by looking at the controller/action
		if (!req.options.view) {
			relPathToView = req.options.controller + '/' + req.options.action;
		}
		// Use the new view config
		else relPathToView = req.options.view;

		// Now we have a reasonable guess in `relPathToView`

		// If the path to a view was explicitly specified, use that
		// Serve the view specified
		//
		// If first arg is not an object, treat it like the path
		if ( specifiedPath && !_.isObject(specifiedPath)) {
			relPathToView = specifiedPath;
		}
		// If first arg ISSSSS AN object, treat it like locals
		else if (_.isObject(specifiedPath)) {

			// If the "locals" argument is actually the "specifiedPath"
			// give em the old switcheroo
			relPathToView = locals || relPathToView;
			locals = specifiedPath;
		}

		// Ensure specifiedPath is a string (important)
		relPathToView = '' + relPathToView + '';

		// Ensure `locals` is an object
		locals = _.isObject(locals) ? locals : {};

		// Mixin locals from req.options
		if (req.options.locals) {
			locals = _.merge(locals, req.options.locals);
		}

		// Merge with config views locals
		if (sails.config.views.locals) {
			_.merge(locals, sails.config.views.locals, _.defaults);
		}

		// If the path was specified, but invalid
		// else if (specifiedPath) {
		// 	return res.serverError(new Error('Specified path for view (' + specifiedPath + ') is invalid!'));
		// }

		// Trim trailing slash
		if (relPathToView[(relPathToView.length - 1)] === '/') {
			relPathToView = relPathToView.slice(0, -1);
		}

		// if local `layout` is set to true or unspecified
		// fall back to global config
		var layout = locals.layout;
		if (locals.layout === undefined || locals.layout === true) {
			layout = sails.config.views.layout;
		}

		// Disable sails built-in layouts for all view engine's except for ejs
		if (sails.config.views.engine.ext !== 'ejs') {
			layout = false;
		}

		// Allow `res.locals.layout` to override if it was set:
		if ( typeof res.locals.layout !== 'undefined' ) {
			layout = res.locals.layout;
		}

		var pathToViews = sails.config.paths.views;
		var absPathToView = path.join(pathToViews, relPathToView);
		var absPathToLayout;
		var relPathToLayout;

		// Ensure layout is a string by this point
		if (typeof layout !== 'string') {
			layout = false;
		}

		// Set layout file if enabled (using ejs-locals)
		if (layout) {

			// Solve relative path to layout from the view itself
			// (required by ejs-locals module)
			absPathToLayout = path.join(pathToViews, layout);
			relPathToLayout = path.relative( path.dirname(absPathToView), absPathToLayout);

			// If a layout was specified, set view local so it will be used
			res.locals._layoutFile = relPathToLayout;
			sails.log.silly('Using layout at: ', absPathToLayout);
		}

		// Locals passed in to `res.view()` override app and route locals.
		_.each(locals, function (local, key) {
			res.locals[key] = local;
		});

		// Provide access to view metadata in locals
		// (for convenience)
		res.locals.view = res.locals.view || {
			path: relPathToView,
			absPath: absPathToView,
			pathFromViews: relPathToView,
			pathFromApp: path.join( path.relative(sails.config.appPath, sails.config.paths.views), relPathToView ),
			ext: sails.config.views.engine.ext
		};

		// In development, provide access to complete path to view via `__dirname` local.
		if ( sails.config.environment !== 'production' ) {
			res.locals.__dirname = res.locals.__dirname ||
				absPathToView + '.' + sails.config.views.engine.ext;
		}

		// Render the view
		if (specifiedPath) {
			sails.log.silly('View override argument passed to res.view(): ', specifiedPath);
		}
		sails.log.silly('Serving view at rel path: ', relPathToView);
		sails.log.silly('View root: ', sails.config.paths.views);
		return res.render(relPathToView, function renderView (err, renderedViewStr) {

			// if a template error occurred, don't rely on any of the Sails request/response methods
			// (since they may not exist yet at this point in the request lifecycle.)
			if (err) {
				sails.log.error('Error rendering view at ::',absPathToView);
				sails.log.error('with layout located at ::', absPathToLayout);
				sails.log.error(err && err.message);
				if (process.env.NODE_ENV === 'development') {
					return res.json(500, err);
				}
				else return res.send(500);
			}

			if (layout) { sails.log.verbose('Using layout: ', absPathToLayout); }
			sails.log.verbose('Rendering view ::', relPathToView, '(located @ ' + absPathToView + ')');

			// Backwards compatibility:
			// trigger `res.view` callback if specified
			// (before sending the response)
			if (cb_view) {
				sails.log.warn(
					'Callback function of `res.view([relativePathToView], [options], [cb])`',
					' will be deprecated in an upcoming release.'
				);
				cb_view(err);
			}

			// Finally, send the view down to the client
			res.send(renderedViewStr);

			// Express version updates should be closely monitored.
			// Express is a "hard" dependency.
			//
			// While unlikely this will change, it's worth noting that this implementation
			// relies on express's private implementation of res.render() here:
			// https://github.com/visionmedia/express/blob/master/lib/response.js#L799
			//
			// To be safe, the version of the Express dependency in package.json will remain locked
			// until it can be verified that each subsequent version is compatible.  Even patch releases!!
		});

	};

	next();
};
<|endoftext|>


<commit_before>/*
 * Leaflet-IIIF 0.1.0
 * IIIF Viewer for Leaflet
 * by Jack Reed, @mejackreed
 */

L.TileLayer.Iiif = L.TileLayer.extend({
  options: {
    continuousWorld: true,
    tileSize: 256,
    updateWhenIdle: true,
    tileFormat: 'jpg',
    fitBounds: true
  },

  initialize: function(url, options) {
    options = typeof options !== 'undefined' ? options : {};

    if (options.maxZoom) {
      this._customMaxZoom = true;
    }

    // Check for explicit tileSize set
    if (options.tileSize) {
      this._explicitTileSize = true;
    }

    options = L.setOptions(this, options);
    this._infoDeferred = new $.Deferred();
    this._infoUrl = url;
    this._baseUrl = this._templateUrl();
    this._getInfo();
  },
  getTileUrl: function(coords) {
    var _this = this,
      x = coords.x,
      y = (coords.y),
      zoom = _this._map.getZoom(),
      scale = Math.pow(2, _this.maxNativeZoom - zoom),
      tileBaseSize = _this.options.tileSize * scale,
      minx = (x * tileBaseSize),
      miny = (y * tileBaseSize),
      maxx = Math.min(minx + tileBaseSize, _this.x),
      maxy = Math.min(miny + tileBaseSize, _this.y);

    var xDiff = (maxx - minx);
    var yDiff = (maxy - miny);

    return L.Util.template(this._baseUrl, L.extend({
      format: _this.options.tileFormat,
      quality: _this.quality,
      region: [minx, miny, xDiff, yDiff].join(','),
      rotation: 0,
      size: _this._iiifSizeParam(Math.ceil(xDiff / scale), Math.ceil(yDiff / scale))
    }, this.options));
  },
  /**
  * Returns a IIIF size parameter based off of the max dimension of
  * a tile
  * @param {Number} x - The width of a tile
  * @param {Number} y - The height of a tile
  * @returns {String}
  */
  _iiifSizeParam: function(x, y) {
    if (x >= y) {
      return x + ',';
    } else {
      return ',' + y;
    }
  },
  onAdd: function(map) {
    var _this = this;

    // Wait for deferred to complete
    $.when(_this._infoDeferred).done(function() {

      // Set maxZoom for map
      map._layersMaxZoom = _this.maxZoom;

      // Call add TileLayer
      L.TileLayer.prototype.onAdd.call(_this, map);

      if (_this.options.fitBounds) {
        _this._fitBounds();
      }

      // Reset tile sizes to handle non 256x256 IIIF tiles
      _this.on('tileload', function(tile, url) {

        var height = tile.tile.naturalHeight,
          width = tile.tile.naturalWidth;

        // No need to resize if tile is 256 x 256
        if (height === 256 && width === 256) return;

        tile.tile.style.width = width + 'px';
        tile.tile.style.height = height + 'px';

      });
    });
  },
  _fitBounds: function() {
    var _this = this;

    // Find best zoom level and center map
    var initialZoom = _this._getInitialZoom(map.getSize());
    var imageSize = _this._imageSizes[initialZoom];
    var sw = map.options.crs.pointToLatLng(L.point(0, imageSize.y), initialZoom);
    var ne = map.options.crs.pointToLatLng(L.point(imageSize.x, 0), initialZoom);
    var bounds = L.latLngBounds(sw, ne);

    map.fitBounds(bounds, true);
  },
  _getInfo: function() {
    var _this = this;

    // Look for a way to do this without jQuery
    $.getJSON(_this._infoUrl)
      .done(function(data) {
        _this.y = data.height;
        _this.x = data.width;

        var profile,
          tierSizes = [],
          imageSizes = [],
          scale,
          width_,
          height_,
          tilesX_,
          tilesY_;

        // Set quality based off of IIIF version
        if (data.profile instanceof Array) {
          profile = data.profile[0];
        }else {
          profile = data.profile;
        }
        switch (true) {
          case /^http:\/\/library.stanford.edu\/iiif\/image-api\/1.1\/compliance.html.*$/.test(profile):
            _this.quality = 'native';
            break;
          case /^http:\/\/iiif.io\/api\/image\/2.*$/.test(profile):
            _this.quality = 'default';
            break;
        }

        // Unless an explicit tileSize is set, use a preferred tileSize
        if (!_this.explicitTileSize) {
          if (data.tiles) {
            // Image API 2.0 Case
            _this.options.tileSize = data.tiles[0].width;
          } else if (data.tile_width){
            // Image API 1.1 Case
            _this.options.tileSize = data.tile_width;
          }
        }

        ceilLog2 = function(x) {
          return Math.ceil(Math.log(x) / Math.LN2);
        };

        // Calculates maximum native zoom for the layer
        _this.maxNativeZoom = Math.max(ceilLog2(_this.x / _this.options.tileSize),
          ceilLog2(_this.y / _this.options.tileSize));

        // Enable zooming further than native if maxZoom option supplied
        if (_this._customMaxZoom && _this.options.maxZoom > _this.maxNativeZoom) {
          _this.maxZoom = _this.options.maxZoom;
        }
        else {
          _this.maxZoom = _this.maxNativeZoom;
        }

        for (var i = 0; i <= _this.maxZoom; i++) {
          scale = Math.pow(2, _this.maxNativeZoom - i);
          width_ = Math.ceil(_this.x / scale);
          height_ = Math.ceil(_this.y / scale);
          tilesX_ = Math.ceil(width_ / _this.options.tileSize);
          tilesY_ = Math.ceil(height_ / _this.options.tileSize);
          tierSizes.push([tilesX_, tilesY_]);
          imageSizes.push(L.point(width_,height_));
        }

        _this._tierSizes = tierSizes;
        _this._imageSizes = imageSizes;

        // Resolved Deferred to initiate tilelayer load
        _this._infoDeferred.resolve();
      });
  },
  _infoToBaseUrl: function() {
    return this._infoUrl.replace('info.json', '');
  },
  _templateUrl: function() {
    return this._infoToBaseUrl() + '{region}/{size}/{rotation}/{quality}.{format}';
  },
  _tileShouldBeLoaded: function(coords) {
    var _this = this,
      zoom = _this._map.getZoom(),
      sizes = _this._tierSizes[zoom],
      x = coords.x,
      y = (coords.y);

    if (!sizes) return false;
    if (x < 0 || sizes[0] <= x || y < 0 || sizes[1] <= y) {
      return false;
    }else {
      return true;
    }
  },
  _getInitialZoom: function (mapSize) {
    var _this = this,
      tolerance = 0.8,
      imageSize;

    for (var i = _this.maxNativeZoom; i >= 0; i--) {
      imageSize = this._imageSizes[i];
      if (imageSize.x * tolerance < mapSize.x && imageSize.y * tolerance < mapSize.y) {
        return i;
      }
    }
    // return a default zoom
    return 2;
  }
});

L.tileLayer.iiif = function(url, options) {
  return new L.TileLayer.Iiif(url, options);
};
<commit_msg>fitBounds should reference 'map' from '_this'<commit_after>/*
 * Leaflet-IIIF 0.1.0
 * IIIF Viewer for Leaflet
 * by Jack Reed, @mejackreed
 */

L.TileLayer.Iiif = L.TileLayer.extend({
  options: {
    continuousWorld: true,
    tileSize: 256,
    updateWhenIdle: true,
    tileFormat: 'jpg',
    fitBounds: true
  },

  initialize: function(url, options) {
    options = typeof options !== 'undefined' ? options : {};

    if (options.maxZoom) {
      this._customMaxZoom = true;
    }

    // Check for explicit tileSize set
    if (options.tileSize) {
      this._explicitTileSize = true;
    }

    options = L.setOptions(this, options);
    this._infoDeferred = new $.Deferred();
    this._infoUrl = url;
    this._baseUrl = this._templateUrl();
    this._getInfo();
  },
  getTileUrl: function(coords) {
    var _this = this,
      x = coords.x,
      y = (coords.y),
      zoom = _this._map.getZoom(),
      scale = Math.pow(2, _this.maxNativeZoom - zoom),
      tileBaseSize = _this.options.tileSize * scale,
      minx = (x * tileBaseSize),
      miny = (y * tileBaseSize),
      maxx = Math.min(minx + tileBaseSize, _this.x),
      maxy = Math.min(miny + tileBaseSize, _this.y);

    var xDiff = (maxx - minx);
    var yDiff = (maxy - miny);

    return L.Util.template(this._baseUrl, L.extend({
      format: _this.options.tileFormat,
      quality: _this.quality,
      region: [minx, miny, xDiff, yDiff].join(','),
      rotation: 0,
      size: _this._iiifSizeParam(Math.ceil(xDiff / scale), Math.ceil(yDiff / scale))
    }, this.options));
  },
  /**
  * Returns a IIIF size parameter based off of the max dimension of
  * a tile
  * @param {Number} x - The width of a tile
  * @param {Number} y - The height of a tile
  * @returns {String}
  */
  _iiifSizeParam: function(x, y) {
    if (x >= y) {
      return x + ',';
    } else {
      return ',' + y;
    }
  },
  onAdd: function(map) {
    var _this = this;

    // Wait for deferred to complete
    $.when(_this._infoDeferred).done(function() {

      // Set maxZoom for map
      map._layersMaxZoom = _this.maxZoom;

      // Call add TileLayer
      L.TileLayer.prototype.onAdd.call(_this, map);

      if (_this.options.fitBounds) {
        _this._fitBounds();
      }

      // Reset tile sizes to handle non 256x256 IIIF tiles
      _this.on('tileload', function(tile, url) {

        var height = tile.tile.naturalHeight,
          width = tile.tile.naturalWidth;

        // No need to resize if tile is 256 x 256
        if (height === 256 && width === 256) return;

        tile.tile.style.width = width + 'px';
        tile.tile.style.height = height + 'px';

      });
    });
  },
  _fitBounds: function() {
    var _this = this;

    // Find best zoom level and center map
    var initialZoom = _this._getInitialZoom(_this._map.getSize());
    var imageSize = _this._imageSizes[initialZoom];
    var sw = _this._map.options.crs.pointToLatLng(L.point(0, imageSize.y), initialZoom);
    var ne = _this._map.options.crs.pointToLatLng(L.point(imageSize.x, 0), initialZoom);
    var bounds = L.latLngBounds(sw, ne);

    _this._map.fitBounds(bounds, true);
  },
  _getInfo: function() {
    var _this = this;

    // Look for a way to do this without jQuery
    $.getJSON(_this._infoUrl)
      .done(function(data) {
        _this.y = data.height;
        _this.x = data.width;

        var profile,
          tierSizes = [],
          imageSizes = [],
          scale,
          width_,
          height_,
          tilesX_,
          tilesY_;

        // Set quality based off of IIIF version
        if (data.profile instanceof Array) {
          profile = data.profile[0];
        }else {
          profile = data.profile;
        }
        switch (true) {
          case /^http:\/\/library.stanford.edu\/iiif\/image-api\/1.1\/compliance.html.*$/.test(profile):
            _this.quality = 'native';
            break;
          case /^http:\/\/iiif.io\/api\/image\/2.*$/.test(profile):
            _this.quality = 'default';
            break;
        }

        // Unless an explicit tileSize is set, use a preferred tileSize
        if (!_this.explicitTileSize) {
          if (data.tiles) {
            // Image API 2.0 Case
            _this.options.tileSize = data.tiles[0].width;
          } else if (data.tile_width){
            // Image API 1.1 Case
            _this.options.tileSize = data.tile_width;
          }
        }

        ceilLog2 = function(x) {
          return Math.ceil(Math.log(x) / Math.LN2);
        };

        // Calculates maximum native zoom for the layer
        _this.maxNativeZoom = Math.max(ceilLog2(_this.x / _this.options.tileSize),
          ceilLog2(_this.y / _this.options.tileSize));

        // Enable zooming further than native if maxZoom option supplied
        if (_this._customMaxZoom && _this.options.maxZoom > _this.maxNativeZoom) {
          _this.maxZoom = _this.options.maxZoom;
        }
        else {
          _this.maxZoom = _this.maxNativeZoom;
        }

        for (var i = 0; i <= _this.maxZoom; i++) {
          scale = Math.pow(2, _this.maxNativeZoom - i);
          width_ = Math.ceil(_this.x / scale);
          height_ = Math.ceil(_this.y / scale);
          tilesX_ = Math.ceil(width_ / _this.options.tileSize);
          tilesY_ = Math.ceil(height_ / _this.options.tileSize);
          tierSizes.push([tilesX_, tilesY_]);
          imageSizes.push(L.point(width_,height_));
        }

        _this._tierSizes = tierSizes;
        _this._imageSizes = imageSizes;

        // Resolved Deferred to initiate tilelayer load
        _this._infoDeferred.resolve();
      });
  },
  _infoToBaseUrl: function() {
    return this._infoUrl.replace('info.json', '');
  },
  _templateUrl: function() {
    return this._infoToBaseUrl() + '{region}/{size}/{rotation}/{quality}.{format}';
  },
  _tileShouldBeLoaded: function(coords) {
    var _this = this,
      zoom = _this._map.getZoom(),
      sizes = _this._tierSizes[zoom],
      x = coords.x,
      y = (coords.y);

    if (!sizes) return false;
    if (x < 0 || sizes[0] <= x || y < 0 || sizes[1] <= y) {
      return false;
    }else {
      return true;
    }
  },
  _getInitialZoom: function (mapSize) {
    var _this = this,
      tolerance = 0.8,
      imageSize;

    for (var i = _this.maxNativeZoom; i >= 0; i--) {
      imageSize = this._imageSizes[i];
      if (imageSize.x * tolerance < mapSize.x && imageSize.y * tolerance < mapSize.y) {
        return i;
      }
    }
    // return a default zoom
    return 2;
  }
});

L.tileLayer.iiif = function(url, options) {
  return new L.TileLayer.Iiif(url, options);
};
<|endoftext|>


<commit_before><commit_msg>add solution<commit_after>// How would you reverse a singly LL (no loop)?

function reversesll(sll){

  if(!sll.head || !sll.head.next) return sll; //check if empty

  var nodes=[],
    current = sll.head;
  //storing all the nodes in an array
  while(current){
    nodes.push(current);
    current = current.next;
  }

  var reversedLL = new LinkedList();

  reversedLL.head = nodes.pop();
  current = reversedLL.head;

  var node = nodes.pop();
  //make sure to make next of the newly inserted node to be null
  //other wise the last node of your SLL will retain its old next.
  while(node){
     node.next = null;
     current.next = node;

     current = current.next;
     node = nodes.pop();
  }
  return reversedLL;
}
<|endoftext|>


<commit_before>/* eslint-disable no-magic-numbers */
// NOTE This file is an important documentation of the data structure of v6.

var c = require('./common');
var db = require('tresd-db');

module.exports = {
  collections: {

    config: [{
      key: 'schemaVersion',
      value: 6,  // new
    }],

    entries: [{  // new
      _id: db.id('581f166110a1482dd0b7ea01'),
      data: {
        isVisit: false,
        markdown: 'A ghost town',
        filepath: null,
        mimetype: null,
        thumbfilepath: null,
        thumbmimetype: null,
      },
      deleted: false,
      locationId: c.irbeneId,
      time: '2009-09-04T23:44:21.000Z',
      type: 'location_entry',
      user: 'admin',
    }, {
      _id: db.id('581f166110a1482dd0b7ea02'),
      data: {
        isVisit: false,
        markdown: null,
        filepath: '2009/RxRvKSlbl/radar.jpg',  // the sample contains this
        mimetype: 'image/jpeg',
        thumbfilepath: '2009/RxRvKSlbl/radar_medium.jpg',
        thumbmimetype: 'image/jpeg',
      },
      deleted: false,
      locationId: c.irbeneId,
      time: '2009-10-02T11:11:01.000Z',
      type: 'location_entry',
      user: 'admin',
    }],

    events: [{  // new
      data: {
        lng: 21.857705,
        lat: 57.55341,
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-07-30T10:44:57.000Z',  // note -1 second shift
      type: 'location_created',
      user: 'admin',
    }, {
      data: {
        entryId: db.id('581f166110a1482dd0b7ea01'),
        isVisit: false,
        markdown: 'A ghost town',
        filepath: null,
        mimetype: null,
        thumbfilepath: null,
        thumbmimetype: null,
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-09-04T23:44:21.000Z',
      type: 'location_entry_created',
      user: 'admin',
    }, {
      data: {
        entryId: db.id('581f166110a1482dd0b7ea02'),
        isVisit: false,
        markdown: null,
        filepath: '2009/RxRvKSlbl/radar.jpg',  // the sample contains this
        mimetype: 'image/jpeg',
        thumbfilepath: '2009/RxRvKSlbl/radar_medium.jpg',
        thumbmimetype: 'image/jpeg',
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-10-02T11:11:01.000Z',
      type: 'location_entry_created',
      user: 'admin',
    }],

    users: [{
      admin: true,
      email: 'admin@example.com',
      hash: c.PASSWORD,
      name: 'admin',
      points: 0,  // new
    }],

    locations: [{
      _id: c.irbeneId,
      creator: 'admin',  // new
      deleted: false,
      geom: {
        type: 'Point',
        coordinates: [21.857705, 57.55341],
      },
      layer: 12,
      isLayered: true,
      name: 'Irbene',
      points: 0,  // new
      // places should really be:
      // ['Irbene', 'Ances pagasts', 'Ventspils Municipality', 'Latvia']
      // but we cannot run reverse geocoding for each location.
      places: [],
      tags: ['walk-in'],
    }],
  },
};
<commit_msg>Fix require typo<commit_after>/* eslint-disable no-magic-numbers */
// NOTE This file is an important documentation of the data structure of v6.

var c = require('./common');
var db = require('tresdb-db');

module.exports = {
  collections: {

    config: [{
      key: 'schemaVersion',
      value: 6,  // new
    }],

    entries: [{  // new
      _id: db.id('581f166110a1482dd0b7ea01'),
      data: {
        isVisit: false,
        markdown: 'A ghost town',
        filepath: null,
        mimetype: null,
        thumbfilepath: null,
        thumbmimetype: null,
      },
      deleted: false,
      locationId: c.irbeneId,
      time: '2009-09-04T23:44:21.000Z',
      type: 'location_entry',
      user: 'admin',
    }, {
      _id: db.id('581f166110a1482dd0b7ea02'),
      data: {
        isVisit: false,
        markdown: null,
        filepath: '2009/RxRvKSlbl/radar.jpg',  // the sample contains this
        mimetype: 'image/jpeg',
        thumbfilepath: '2009/RxRvKSlbl/radar_medium.jpg',
        thumbmimetype: 'image/jpeg',
      },
      deleted: false,
      locationId: c.irbeneId,
      time: '2009-10-02T11:11:01.000Z',
      type: 'location_entry',
      user: 'admin',
    }],

    events: [{  // new
      data: {
        lng: 21.857705,
        lat: 57.55341,
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-07-30T10:44:57.000Z',  // note -1 second shift
      type: 'location_created',
      user: 'admin',
    }, {
      data: {
        entryId: db.id('581f166110a1482dd0b7ea01'),
        isVisit: false,
        markdown: 'A ghost town',
        filepath: null,
        mimetype: null,
        thumbfilepath: null,
        thumbmimetype: null,
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-09-04T23:44:21.000Z',
      type: 'location_entry_created',
      user: 'admin',
    }, {
      data: {
        entryId: db.id('581f166110a1482dd0b7ea02'),
        isVisit: false,
        markdown: null,
        filepath: '2009/RxRvKSlbl/radar.jpg',  // the sample contains this
        mimetype: 'image/jpeg',
        thumbfilepath: '2009/RxRvKSlbl/radar_medium.jpg',
        thumbmimetype: 'image/jpeg',
      },
      locationId: c.irbeneId,
      locationName: 'Irbene',
      time: '2009-10-02T11:11:01.000Z',
      type: 'location_entry_created',
      user: 'admin',
    }],

    users: [{
      admin: true,
      email: 'admin@example.com',
      hash: c.PASSWORD,
      name: 'admin',
      points: 0,  // new
    }],

    locations: [{
      _id: c.irbeneId,
      creator: 'admin',  // new
      deleted: false,
      geom: {
        type: 'Point',
        coordinates: [21.857705, 57.55341],
      },
      layer: 12,
      isLayered: true,
      name: 'Irbene',
      points: 0,  // new
      // places should really be:
      // ['Irbene', 'Ances pagasts', 'Ventspils Municipality', 'Latvia']
      // but we cannot run reverse geocoding for each location.
      places: [],
      tags: ['walk-in'],
    }],
  },
};
<|endoftext|>


<commit_before>"use strict";

/*global nodeca, _*/

// stdlib
var path = require('path');

// nodeca
var HashTree = require('nlib').Support.HashTree;

// 3rd-party
var Faye = require('faye');

// internal
var env = require('../../env');

////////////////////////////////////////////////////////////////////////////////

var realtime = module.exports = {
  activeClients: 0
};

////////////////////////////////////////////////////////////////////////////////

var noop = function () {};

// FAYE EXTENSIONS /////////////////////////////////////////////////////////////

// adds extensions for `incoming` messages, that allows to subscribe non-server
// clients to the whitelisted channels only
//
function add_subscription_filter(bayeux, whitelist) {
  bayeux.addExtension({
    incoming: function (message, callback) {
      var allow;

      // allow any message from the server client
      if (bayeux.getClient().getClientId() === message.clientId) {
        callback(message);
        return;
      }

      // allow any non-subscription message
      if (!message.subscription) {
        callback(message);
        return;
      }

      allow = _.any(whitelist, function (re) {
        return re.test(message.subscription);
      });

      // subscription channel is in whitelist
      if (allow) {
        callback(message);
        return;
      }

      nodeca.logger.warn("Subscription denied: " + message.subscription);

      message.error = "Subscription Denied";
      callback(message);
    }
  });
}

// adds extensions for `incoming` messages, that allows to publish non-server
// clients to the whitelisted channels only
//
function add_publishing_filter(bayeux, whitelist) {
  bayeux.addExtension({
    incoming: function (message, callback) {
      var allow;

      // allow any message from the server client
      if (bayeux.getClient().getClientId() === message.clientId) {
        callback(message);
        return;
      }

      // allow any special-case messages
      if ('/meta/' === message.channel.substr(0, 6)) {
        callback(message);
        return;
      }

      allow = _.any(whitelist, function (re) {
        return re.test(message.channel);
      });

      // subscription channel is in whitelist
      if (allow) {
        callback(message);
        return;
      }

      nodeca.logger.warn("Publishing denied: " + JSON.stringify({
        channel:  message.channel,
        clientId: message.clientId
      }));

      message.error = "Publishing Denied";
      callback(message);
    }
  });
}

////////////////////////////////////////////////////////////////////////////////

// Handles incoming rpc message
//
function handle_rpc(msg, cb) {
  var fn = HashTree.get(nodeca.server, msg.method);

  nodeca.debug_trace('handle_rpc()', msg);

  if (msg.version !== nodeca.runtime.version) {
    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    'Nodeca client mismatch'
    });
    return;
  }

  if (!fn) {
    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    'Unknown server method: ' + msg.method
    });
    return;
  }

  nodeca.filters.run(msg.method, msg.params, fn, function (err) {
    var logger  = nodeca.logger.getLogger('server.' + msg.method),
        level   = err ? 'error' : 'info',
        message = (err && err.stack) || (err && err.message) || err || 'OK';

    nodeca.debug_trace('handle_rpc() callback', err);
    logger[level]('"RPC %s(%s) REALTIME" - %d - %s',
                  msg.method,
                  JSON.stringify(msg.params),
                  (err && err.statusCode) || '',
                  message);

    if (err.statusCode) {
      err = "HTTP ONLY";
    }

    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    (err ? err.toString() : null),
      result:   (err ? null : JSON.stringify(this.response))
    });
  }, env({
      realtime: true,
      method:   msg.method
  }));
}

////////////////////////////////////////////////////////////////////////////////

// attaches faye adapter to the `server`
//
realtime.attach = function attach(server, next) {
  var faye = new Faye.NodeAdapter({mount: '/faye'});

  if (process.env.FAYE_LOGLEVEL) {
    // This produces lots of logs, which are usefull
    // only during development of RT things.
    // USAGE: FAYE_LOGLEVEL=info ./fontello.js server
    Faye.Logging.logLevel = process.env.FAYE_LOGLEVEL;
  }

  // FIXME: Replace dummy active_clients inc/dec with real heartbeat/timeouts
  faye.bind('handshake',  function () { realtime.activeClients++; });
  faye.bind('disconnect', function () { realtime.activeClients--; });

  var curr_users_count = 0;
  setInterval(function () {
    if (realtime.activeClients !== curr_users_count) {
      curr_users_count = realtime.activeClients;
      faye.getClient().publish('/stats/users_online', curr_users_count);
    }
  }, 10000);

  // Limit channels clients might subscribe.
  // Applied to "browser" clients only.
  add_subscription_filter(faye, [
    // public stats updates (online users, etc)
    new RegExp('^/stats/'),
    // responses from the server client
    new RegExp('^/x/api3-res/[a-f0-9]{32}$')
  ]);

  // Limit channels clients might publish to.
  // Applied to "browser" clients only.
  add_publishing_filter(faye, [
    // requests from the browser clients
    new RegExp('^/x/api3-req/[a-f0-9]{32}$')
  ]);

  //
  // Process RPC requests
  //

  var CHANNEL_RE = new RegExp('^/x/api3-req/([a-f0-9]{32})$');

  function process_rpc(secret, data) {
    nodeca.logger.debug('API3 [%d] Got request: %s',
                        data.id, JSON.stringify(data.msg));
    handle_rpc(data.msg, function (res) {
      nodeca.logger.debug('API3 [%d] Sending response', data.id);
      faye.getClient().publish('/x/api3-res/' + secret, {
        id  : data.id,
        msg : res
      });
    });
  }

  faye.addExtension({
    // rpc calls implemented via extensions, because this is
    // the most cheapest (in terms of resources) and most
    // lean way to achieve our goal.
    incoming: function (message, callback) {
      var match = CHANNEL_RE.exec(message.channel);

      if (match) {
        process_rpc(match[1], message.data);
      }

      callback(message);
    }
  });

  faye.attach(server);
  next();
};
<commit_msg>Fix realtime error handling<commit_after>"use strict";

/*global nodeca, _*/

// stdlib
var path = require('path');

// nodeca
var HashTree = require('nlib').Support.HashTree;

// 3rd-party
var Faye = require('faye');

// internal
var env = require('../../env');

////////////////////////////////////////////////////////////////////////////////

var realtime = module.exports = {
  activeClients: 0
};

////////////////////////////////////////////////////////////////////////////////

var noop = function () {};

// FAYE EXTENSIONS /////////////////////////////////////////////////////////////

// adds extensions for `incoming` messages, that allows to subscribe non-server
// clients to the whitelisted channels only
//
function add_subscription_filter(bayeux, whitelist) {
  bayeux.addExtension({
    incoming: function (message, callback) {
      var allow;

      // allow any message from the server client
      if (bayeux.getClient().getClientId() === message.clientId) {
        callback(message);
        return;
      }

      // allow any non-subscription message
      if (!message.subscription) {
        callback(message);
        return;
      }

      allow = _.any(whitelist, function (re) {
        return re.test(message.subscription);
      });

      // subscription channel is in whitelist
      if (allow) {
        callback(message);
        return;
      }

      nodeca.logger.warn("Subscription denied: " + message.subscription);

      message.error = "Subscription Denied";
      callback(message);
    }
  });
}

// adds extensions for `incoming` messages, that allows to publish non-server
// clients to the whitelisted channels only
//
function add_publishing_filter(bayeux, whitelist) {
  bayeux.addExtension({
    incoming: function (message, callback) {
      var allow;

      // allow any message from the server client
      if (bayeux.getClient().getClientId() === message.clientId) {
        callback(message);
        return;
      }

      // allow any special-case messages
      if ('/meta/' === message.channel.substr(0, 6)) {
        callback(message);
        return;
      }

      allow = _.any(whitelist, function (re) {
        return re.test(message.channel);
      });

      // subscription channel is in whitelist
      if (allow) {
        callback(message);
        return;
      }

      nodeca.logger.warn("Publishing denied: " + JSON.stringify({
        channel:  message.channel,
        clientId: message.clientId
      }));

      message.error = "Publishing Denied";
      callback(message);
    }
  });
}

////////////////////////////////////////////////////////////////////////////////

// Handles incoming rpc message
//
function handle_rpc(msg, cb) {
  var fn = HashTree.get(nodeca.server, msg.method);

  nodeca.debug_trace('handle_rpc()', msg);

  if (msg.version !== nodeca.runtime.version) {
    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    'Nodeca client mismatch'
    });
    return;
  }

  if (!fn) {
    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    'Unknown server method: ' + msg.method
    });
    return;
  }

  nodeca.filters.run(msg.method, msg.params, fn, function (err) {
    var logger  = nodeca.logger.getLogger('server.' + msg.method),
        level   = err ? 'error' : 'info',
        message = (err && err.stack) || (err && err.message) || err || 'OK';

    nodeca.debug_trace('handle_rpc() callback', err);
    logger[level]('"RPC %s(%s) REALTIME" - %s',
                  msg.method, JSON.stringify(msg.params), message);

    (cb || noop)({
      version:  nodeca.runtime.version,
      error:    (err && err.statusCode && 'HTTP ONLY') || String(err) || null,
      result:   (err ? null : JSON.stringify(this.response))
    });
  }, env({
      realtime: true,
      method:   msg.method
  }));
}

////////////////////////////////////////////////////////////////////////////////

// attaches faye adapter to the `server`
//
realtime.attach = function attach(server, next) {
  var faye = new Faye.NodeAdapter({mount: '/faye'});

  if (process.env.FAYE_LOGLEVEL) {
    // This produces lots of logs, which are usefull
    // only during development of RT things.
    // USAGE: FAYE_LOGLEVEL=info ./fontello.js server
    Faye.Logging.logLevel = process.env.FAYE_LOGLEVEL;
  }

  // FIXME: Replace dummy active_clients inc/dec with real heartbeat/timeouts
  faye.bind('handshake',  function () { realtime.activeClients++; });
  faye.bind('disconnect', function () { realtime.activeClients--; });

  var curr_users_count = 0;
  setInterval(function () {
    if (realtime.activeClients !== curr_users_count) {
      curr_users_count = realtime.activeClients;
      faye.getClient().publish('/stats/users_online', curr_users_count);
    }
  }, 10000);

  // Limit channels clients might subscribe.
  // Applied to "browser" clients only.
  add_subscription_filter(faye, [
    // public stats updates (online users, etc)
    new RegExp('^/stats/'),
    // responses from the server client
    new RegExp('^/x/api3-res/[a-f0-9]{32}$')
  ]);

  // Limit channels clients might publish to.
  // Applied to "browser" clients only.
  add_publishing_filter(faye, [
    // requests from the browser clients
    new RegExp('^/x/api3-req/[a-f0-9]{32}$')
  ]);

  //
  // Process RPC requests
  //

  var CHANNEL_RE = new RegExp('^/x/api3-req/([a-f0-9]{32})$');

  function process_rpc(secret, data) {
    nodeca.logger.debug('API3 [%d] Got request: %s',
                        data.id, JSON.stringify(data.msg));
    handle_rpc(data.msg, function (res) {
      nodeca.logger.debug('API3 [%d] Sending response', data.id);
      faye.getClient().publish('/x/api3-res/' + secret, {
        id  : data.id,
        msg : res
      });
    });
  }

  faye.addExtension({
    // rpc calls implemented via extensions, because this is
    // the most cheapest (in terms of resources) and most
    // lean way to achieve our goal.
    incoming: function (message, callback) {
      var match = CHANNEL_RE.exec(message.channel);

      if (match) {
        process_rpc(match[1], message.data);
      }

      callback(message);
    }
  });

  faye.attach(server);
  next();
};
<|endoftext|>