<commit_before>import List from "#SRC/js/structs/List";
import Tree from "#SRC/js/structs/Tree";

import Framework from "./Framework";
import HealthTypes from "../constants/HealthTypes";
import HealthStatus from "../constants/HealthStatus";
import Pod from "./Pod";
import Service from "./Service";
import ServiceOther from "../constants/ServiceOther";
import ServiceStatus from "../constants/ServiceStatus";
import ServiceUtil from "../utils/ServiceUtil";
import VolumeList from "../structs/VolumeList";

module.exports = class ServiceTree extends Tree {
  /**
   * (Marathon) ServiceTree
   * @param {{
   *          id:string,
   *          items:array<({id:string, items:array}|*)>,
   *          groups:array<({id:string, groups:array, apps:array}|*)>,
   *          apps:array,
   *          filterProperties:{propertyName:(null|string|function)}
   *        }} options
   * @constructor
   * @struct
   */
  constructor(options = {}) {
    super(options);

    this.id = "/";
    if (options.id || typeof options.id == "string") {
      this.id = options.id;
    }

    // Converts items into instances of ServiceTree, Application or Framework
    // based on their properties.
    this.list = this.list.map(item => {
      if (item instanceof ServiceTree || item instanceof Service) {
        return item;
      }

      // Check item properties and convert items with an items array (sub trees)
      // into ServiceTree instances.
      if (item.items != null && Array.isArray(item.items)) {
        return new this.constructor(
          Object.assign({ filterProperties: this.getFilterProperties() }, item)
        );
      }

      // Create the appropriate service according to definition
      return ServiceUtil.createServiceFromResponse(item);
    });
  }

  getDeployments() {
    return this.reduceItems(function(deployments, item) {
      if (item instanceof Service && item.getDeployments() != null) {
        deployments = deployments.concat(item.getDeployments());
      }

      return deployments;
    }, []);
  }

  getQueue() {
    return null;
  }

  getHealth() {
    return this.reduceItems(function(aggregatedHealth, item) {
      if (item instanceof Service) {
        const health = item.getHealth();
        if (HealthTypes[aggregatedHealth.key] > HealthTypes[health.key]) {
          aggregatedHealth = health;
        }
      }

      return aggregatedHealth;
    }, HealthStatus.NA);
  }

  getId() {
    return this.id;
  }

  getServiceFromTaskID(taskID) {
    return this.findItemById(ServiceUtil.getServiceIDFromTaskID(taskID));
  }

  getTaskFromTaskID(taskID) {
    const service = this.getServiceFromTaskID(taskID);

    if (service == null || service.tasks == null || !service.tasks.length) {
      return null;
    }

    return service.tasks.find(function(task) {
      return task.id === taskID;
    });
  }

  getItemParent(id) {
    if (!this.list || this.list.length === 0) {
      return null;
    }

    let parentFound = null;

    this.list.forEach(child => {
      if (child instanceof ServiceTree) {
        parentFound = child.getItemParent(id);
      } else if (child.getId() === id) {
        parentFound = this;
      }
    });

    return parentFound;
  }

  /**
   * @param {string} id
   * @return {Service|ServiceTree} matching item
   */
  findItemById(id) {
    if (this.getId() === id) {
      return this;
    }

    return this.findItem(function(item) {
      return item.getId() === id;
    });
  }

  // TODO @pierlo-upitup MARATHON-1030: refactor for more generic usage
  filterItemsByFilter(filter) {
    let services = this.getItems();

    if (filter) {
      if (filter.ids) {
        services = services.filter(
          function(service) {
            return this.ids.indexOf(service.id) !== -1;
          },
          { ids: filter.ids }
        );
      }

      if (filter.id) {
        const filterProperties = Object.assign({}, this.getFilterProperties(), {
          name(item) {
            return item.getName();
          }
        });

        services = this.flattenItems()
          .filterItemsByText(filter.id, filterProperties)
          .getItems();
      }

      if (Array.isArray(filter.health) && filter.health.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.health.forEach(function(healthValue) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service
                  .filterItemsByFilter({ health: [healthValue] })
                  .getItems()
              );

              return;
            }

            if (service.getHealth().value === parseInt(healthValue, 10)) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.labels) && filter.labels.length > 0) {
        services = services.reduce(function(memo, service) {
          filter.labels.forEach(function(label) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service.filterItemsByFilter({ labels: [label] }).getItems()
              );

              return;
            }

            let serviceLabels = service.getLabels();

            if (service instanceof Service) {
              serviceLabels = ServiceUtil.convertServiceLabelsToArray(service);
            }

            const hasLabel = serviceLabels.some(function(serviceLabel) {
              return (
                serviceLabel.key === label.key &&
                serviceLabel.value === label.value
              );
            });

            if (hasLabel) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.other) && filter.other.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.other.forEach(function(otherKey) {
            if (parseInt(otherKey, 10) === ServiceOther.CATALOG.key) {
              if (service instanceof ServiceTree) {
                memo = memo.concat(
                  service.filterItemsByFilter({ other: [otherKey] }).getItems()
                );
              }

              if (service instanceof Framework) {
                memo.push(service);
              }
            }

            if (parseInt(otherKey, 10) === ServiceOther.VOLUMES.key) {
              const volumes = service.getVolumes();

              if (volumes.list && volumes.list.length > 0) {
                memo.push(service);
              }
            }

            if (parseInt(otherKey, 10) === ServiceOther.PODS.key) {
              if (service instanceof ServiceTree) {
                memo = memo.concat(
                  service.filterItemsByFilter({ other: [otherKey] }).getItems()
                );
              }

              if (service instanceof Pod) {
                memo.push(service);
              }
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.status) && filter.status.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.status.some(function(statusValue) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service
                  .filterItemsByFilter({ status: [statusValue] })
                  .getItems()
              );

              return;
            }

            if (service.getServiceStatus().key === parseInt(statusValue, 10)) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }
    }

    const { uniques } = services.reduce(
      function(memo, service) {
        if (!(service.getId() in memo.serviceIds)) {
          memo.serviceIds[service.getId()] = true;
          memo.uniques.push(service);
        }

        return memo;
      },
      { uniques: [], serviceIds: {} }
    );

    return new this.constructor(Object.assign({}, this, { items: uniques }));
  }

  getInstancesCount() {
    return this.reduceItems(function(instances, item) {
      if (item instanceof Service) {
        instances += item.getInstancesCount();
      }

      return instances;
    }, 0);
  }

  getName() {
    return this.getId().split("/").pop();
  }

  getResources() {
    return this.reduceItems(
      function(resources, item) {
        if (item instanceof Service) {
          const { cpus = 0, mem = 0, disk = 0 } = item.getResources();

          resources.cpus += cpus;
          resources.mem += mem;
          resources.disk += disk;
        }

        return resources;
      },
      { cpus: 0, mem: 0, disk: 0 }
    );
  }

  getStatus() {
    const status = this.getServiceStatus();
    if (status == null) {
      return null;
    }

    return status.displayName;
  }

  getServiceStatus() {
    return this.reduceItems(function(serviceTreeStatus, item) {
      if (item instanceof Service) {
        const status = item.getServiceStatus();
        if (status == null) {
          return serviceTreeStatus;
        }

        if (status.key > serviceTreeStatus.key) {
          serviceTreeStatus = status;
        }
      }

      return serviceTreeStatus;
    }, ServiceStatus.NA);
  }

  getServices() {
    const items = this.reduceItems(function(services, item) {
      if (item instanceof Service) {
        services.push(item);
      }

      return services;
    }, []);

    return new List({ items });
  }

  getTasksSummary() {
    return this.reduceItems(
      function(taskSummary, item) {
        if (item instanceof Service) {
          const {
            tasksHealthy = 0,
            tasksRunning = 0,
            tasksOverCapacity = 0,
            tasksStaged = 0,
            tasksUnhealthy = 0
          } = item.getTasksSummary();

          taskSummary.tasksHealthy += tasksHealthy;
          taskSummary.tasksRunning += tasksRunning;
          taskSummary.tasksStaged += tasksStaged;
          taskSummary.tasksUnhealthy += tasksUnhealthy;
          taskSummary.tasksUnknown +=
            tasksRunning - tasksHealthy - tasksUnhealthy;

          taskSummary.tasksOverCapacity += tasksOverCapacity;
        }

        return taskSummary;
      },
      {
        tasksHealthy: 0,
        tasksRunning: 0,
        tasksStaged: 0,
        tasksUnhealthy: 0,
        tasksUnknown: 0,
        tasksOverCapacity: 0
      }
    );
  }

  getRunningInstancesCount() {
    return this.flattenItems().getItems().reduce(function(memo, service) {
      if (service instanceof ServiceTree) {
        return memo;
      }

      return memo + service.getRunningInstancesCount();
    }, 0);
  }

  getFrameworks() {
    return this.reduceItems(function(frameworks, item) {
      if (item instanceof Framework) {
        frameworks.push(item);
      }

      return frameworks;
    }, []);
  }

  getVolumes() {
    const items = this.reduceItems(function(serviceTreeVolumes, item) {
      if (item instanceof Service) {
        const itemVolumes = item.getVolumes().getItems();
        if (itemVolumes && itemVolumes.length) {
          serviceTreeVolumes.push(itemVolumes);
        }
      }

      return serviceTreeVolumes;
    }, []);

    return new VolumeList({ items });
  }

  getLabels() {
    return this.reduceItems(function(serviceTreeLabels, item) {
      ServiceUtil.convertServiceLabelsToArray(item).forEach(function({
        key,
        value
      }) {
        if (
          serviceTreeLabels.findIndex(function(label) {
            return label.key === key && label.value === value;
          }) < 0
        ) {
          serviceTreeLabels = serviceTreeLabels.concat([{ key, value }]);
        }
      });

      return serviceTreeLabels;
    }, []);
  }
};
<commit_msg>fix(ServiceTree): stay in group view when group deleted<commit_after>import List from "#SRC/js/structs/List";
import Tree from "#SRC/js/structs/Tree";

import Framework from "./Framework";
import HealthTypes from "../constants/HealthTypes";
import HealthStatus from "../constants/HealthStatus";
import Pod from "./Pod";
import Service from "./Service";
import ServiceOther from "../constants/ServiceOther";
import ServiceStatus from "../constants/ServiceStatus";
import ServiceUtil from "../utils/ServiceUtil";
import VolumeList from "../structs/VolumeList";

module.exports = class ServiceTree extends Tree {
  /**
   * (Marathon) ServiceTree
   * @param {{
   *          id:string,
   *          items:array<({id:string, items:array}|*)>,
   *          groups:array<({id:string, groups:array, apps:array}|*)>,
   *          apps:array,
   *          filterProperties:{propertyName:(null|string|function)}
   *        }} options
   * @constructor
   * @struct
   */
  constructor(options = {}) {
    super(options);

    this.id = "/";
    if (options.id || typeof options.id == "string") {
      this.id = options.id;
    }

    // Converts items into instances of ServiceTree, Application or Framework
    // based on their properties.
    this.list = this.list.map(item => {
      if (item instanceof ServiceTree || item instanceof Service) {
        return item;
      }

      // Check item properties and convert items with an items array (sub trees)
      // into ServiceTree instances.
      if (item.items != null && Array.isArray(item.items)) {
        return new this.constructor(
          Object.assign({ filterProperties: this.getFilterProperties() }, item)
        );
      }

      // Create the appropriate service according to definition
      return ServiceUtil.createServiceFromResponse(item);
    });
  }

  getDeployments() {
    return this.reduceItems(function(deployments, item) {
      if (item instanceof Service && item.getDeployments() != null) {
        deployments = deployments.concat(item.getDeployments());
      }

      return deployments;
    }, []);
  }

  getQueue() {
    return null;
  }

  getHealth() {
    return this.reduceItems(function(aggregatedHealth, item) {
      if (item instanceof Service) {
        const health = item.getHealth();
        if (HealthTypes[aggregatedHealth.key] > HealthTypes[health.key]) {
          aggregatedHealth = health;
        }
      }

      return aggregatedHealth;
    }, HealthStatus.NA);
  }

  getId() {
    return this.id;
  }

  getServiceFromTaskID(taskID) {
    return this.findItemById(ServiceUtil.getServiceIDFromTaskID(taskID));
  }

  getTaskFromTaskID(taskID) {
    const service = this.getServiceFromTaskID(taskID);

    if (service == null || service.tasks == null || !service.tasks.length) {
      return null;
    }

    return service.tasks.find(function(task) {
      return task.id === taskID;
    });
  }

  getItemParent(id, parent = null) {
    if (this.getId() === id) {
      return parent;
    }

    if (!this.list || this.list.length === 0) {
      return null;
    }

    let parentFound = null;

    this.list.forEach(child => {
      if (child instanceof ServiceTree) {
        parentFound = child.getItemParent(id, this);
      } else if (child.getId() === id) {
        parentFound = this;
      }
    });

    return parentFound;
  }

  /**
   * @param {string} id
   * @return {Service|ServiceTree} matching item
   */
  findItemById(id) {
    if (this.getId() === id) {
      return this;
    }

    return this.findItem(function(item) {
      return item.getId() === id;
    });
  }

  // TODO @pierlo-upitup MARATHON-1030: refactor for more generic usage
  filterItemsByFilter(filter) {
    let services = this.getItems();

    if (filter) {
      if (filter.ids) {
        services = services.filter(
          function(service) {
            return this.ids.indexOf(service.id) !== -1;
          },
          { ids: filter.ids }
        );
      }

      if (filter.id) {
        const filterProperties = Object.assign({}, this.getFilterProperties(), {
          name(item) {
            return item.getName();
          }
        });

        services = this.flattenItems()
          .filterItemsByText(filter.id, filterProperties)
          .getItems();
      }

      if (Array.isArray(filter.health) && filter.health.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.health.forEach(function(healthValue) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service
                  .filterItemsByFilter({ health: [healthValue] })
                  .getItems()
              );

              return;
            }

            if (service.getHealth().value === parseInt(healthValue, 10)) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.labels) && filter.labels.length > 0) {
        services = services.reduce(function(memo, service) {
          filter.labels.forEach(function(label) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service.filterItemsByFilter({ labels: [label] }).getItems()
              );

              return;
            }

            let serviceLabels = service.getLabels();

            if (service instanceof Service) {
              serviceLabels = ServiceUtil.convertServiceLabelsToArray(service);
            }

            const hasLabel = serviceLabels.some(function(serviceLabel) {
              return (
                serviceLabel.key === label.key &&
                serviceLabel.value === label.value
              );
            });

            if (hasLabel) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.other) && filter.other.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.other.forEach(function(otherKey) {
            if (parseInt(otherKey, 10) === ServiceOther.CATALOG.key) {
              if (service instanceof ServiceTree) {
                memo = memo.concat(
                  service.filterItemsByFilter({ other: [otherKey] }).getItems()
                );
              }

              if (service instanceof Framework) {
                memo.push(service);
              }
            }

            if (parseInt(otherKey, 10) === ServiceOther.VOLUMES.key) {
              const volumes = service.getVolumes();

              if (volumes.list && volumes.list.length > 0) {
                memo.push(service);
              }
            }

            if (parseInt(otherKey, 10) === ServiceOther.PODS.key) {
              if (service instanceof ServiceTree) {
                memo = memo.concat(
                  service.filterItemsByFilter({ other: [otherKey] }).getItems()
                );
              }

              if (service instanceof Pod) {
                memo.push(service);
              }
            }
          });

          return memo;
        }, []);
      }

      if (Array.isArray(filter.status) && filter.status.length !== 0) {
        services = services.reduce(function(memo, service) {
          filter.status.some(function(statusValue) {
            if (service instanceof ServiceTree) {
              memo = memo.concat(
                service
                  .filterItemsByFilter({ status: [statusValue] })
                  .getItems()
              );

              return;
            }

            if (service.getServiceStatus().key === parseInt(statusValue, 10)) {
              memo.push(service);
            }
          });

          return memo;
        }, []);
      }
    }

    const { uniques } = services.reduce(
      function(memo, service) {
        if (!(service.getId() in memo.serviceIds)) {
          memo.serviceIds[service.getId()] = true;
          memo.uniques.push(service);
        }

        return memo;
      },
      { uniques: [], serviceIds: {} }
    );

    return new this.constructor(Object.assign({}, this, { items: uniques }));
  }

  getInstancesCount() {
    return this.reduceItems(function(instances, item) {
      if (item instanceof Service) {
        instances += item.getInstancesCount();
      }

      return instances;
    }, 0);
  }

  getName() {
    return this.getId().split("/").pop();
  }

  getResources() {
    return this.reduceItems(
      function(resources, item) {
        if (item instanceof Service) {
          const { cpus = 0, mem = 0, disk = 0 } = item.getResources();

          resources.cpus += cpus;
          resources.mem += mem;
          resources.disk += disk;
        }

        return resources;
      },
      { cpus: 0, mem: 0, disk: 0 }
    );
  }

  getStatus() {
    const status = this.getServiceStatus();
    if (status == null) {
      return null;
    }

    return status.displayName;
  }

  getServiceStatus() {
    return this.reduceItems(function(serviceTreeStatus, item) {
      if (item instanceof Service) {
        const status = item.getServiceStatus();
        if (status == null) {
          return serviceTreeStatus;
        }

        if (status.key > serviceTreeStatus.key) {
          serviceTreeStatus = status;
        }
      }

      return serviceTreeStatus;
    }, ServiceStatus.NA);
  }

  getServices() {
    const items = this.reduceItems(function(services, item) {
      if (item instanceof Service) {
        services.push(item);
      }

      return services;
    }, []);

    return new List({ items });
  }

  getTasksSummary() {
    return this.reduceItems(
      function(taskSummary, item) {
        if (item instanceof Service) {
          const {
            tasksHealthy = 0,
            tasksRunning = 0,
            tasksOverCapacity = 0,
            tasksStaged = 0,
            tasksUnhealthy = 0
          } = item.getTasksSummary();

          taskSummary.tasksHealthy += tasksHealthy;
          taskSummary.tasksRunning += tasksRunning;
          taskSummary.tasksStaged += tasksStaged;
          taskSummary.tasksUnhealthy += tasksUnhealthy;
          taskSummary.tasksUnknown +=
            tasksRunning - tasksHealthy - tasksUnhealthy;

          taskSummary.tasksOverCapacity += tasksOverCapacity;
        }

        return taskSummary;
      },
      {
        tasksHealthy: 0,
        tasksRunning: 0,
        tasksStaged: 0,
        tasksUnhealthy: 0,
        tasksUnknown: 0,
        tasksOverCapacity: 0
      }
    );
  }

  getRunningInstancesCount() {
    return this.flattenItems().getItems().reduce(function(memo, service) {
      if (service instanceof ServiceTree) {
        return memo;
      }

      return memo + service.getRunningInstancesCount();
    }, 0);
  }

  getFrameworks() {
    return this.reduceItems(function(frameworks, item) {
      if (item instanceof Framework) {
        frameworks.push(item);
      }

      return frameworks;
    }, []);
  }

  getVolumes() {
    const items = this.reduceItems(function(serviceTreeVolumes, item) {
      if (item instanceof Service) {
        const itemVolumes = item.getVolumes().getItems();
        if (itemVolumes && itemVolumes.length) {
          serviceTreeVolumes.push(itemVolumes);
        }
      }

      return serviceTreeVolumes;
    }, []);

    return new VolumeList({ items });
  }

  getLabels() {
    return this.reduceItems(function(serviceTreeLabels, item) {
      ServiceUtil.convertServiceLabelsToArray(item).forEach(function({
        key,
        value
      }) {
        if (
          serviceTreeLabels.findIndex(function(label) {
            return label.key === key && label.value === value;
          }) < 0
        ) {
          serviceTreeLabels = serviceTreeLabels.concat([{ key, value }]);
        }
      });

      return serviceTreeLabels;
    }, []);
  }
};
<|endoftext|>


<commit_before>'use strict';

var Promise = require('rsvp').Promise;

var L10nError = require('./errors').L10nError;
var debug = require('./debug').debug.bind(null, null);

function Context(env, ready, resIds) {
  this._env = env;
  this._resIds = resIds;

  this.ready = ready.then(this._load.bind(this));
}

Context.prototype.get = function(id, args) {
  return this.ready.then(function(supported) {
    return this._getFallback(supported.slice(), id, args);
  }.bind(this));
};

Context.prototype.destroy = function() {
  var env = this._env;
  this._resIds.forEach(function(resId) {
    if (env._resMap[resId].size === 1) {
      env._resMap[resId].clear();
      delete env._resCache[resId];
    } else {
      env._resMap[resId].delete(this);
    }
  }, this);
};

Context.prototype._load = function(supported) {
  return this._fetchResources(supported[0]).then(function() {
    return supported;
  }.bind(this));
};

Context.prototype._fetchResources = function(lang) {
  debug('fetching resources for', lang);
  if (!lang) {
    return Promise.reject(
      new L10nError('No more supported languages to try'));
  }

  return Promise.all(
    this._resIds.map(
      this._env._getResource.bind(this._env, lang)));
};

Context.prototype._getFallback = function(chain, id, args) {
  var lang = chain.shift();
  var entity = this._getEntity(lang, id);

  if (!entity) {
    debug(id, 'missing from', lang);
    return this._fetchResources(chain[0]).then(
      this._getFallback.bind(this, chain, id, args),
      function(err) {
        debug(err);
        // XXX comply to Gaia's l10n.js behavior for now;
        // return id in the future
        return Promise.resolve(null);
      });
  } else {
    debug(id, 'found in', lang);
    // XXX format the entity here, passing ctx and args
    // XXX handle compiler's runtime errors and fall back if needed
    // return entity.format(this, args);
    return Promise.resolve(entity);
  }
};

Context.prototype._getEntity = function(lang, id) {
  var cache = this._env._resCache;

  // Look for `id` in every resource in order.
  for (var i = 0, resId; resId = this._resIds[i]; i++) {
    if (cache[resId][lang] instanceof L10nError) {
      continue;
    }
    if (id in cache[resId][lang]) {
      // XXX compile here, passing lang
      // return new Entity(id, cache[resId][lang][id], lang);
      return cache[resId][lang][id];
    }
  }
  return undefined;
};

exports.Context = Context;
<commit_msg>supported.slice()<commit_after>'use strict';

var Promise = require('rsvp').Promise;

var L10nError = require('./errors').L10nError;
var debug = require('./debug').debug.bind(null, null);

function Context(env, ready, resIds) {
  this._env = env;
  this._resIds = resIds;

  this.ready = ready.then(this._fetchResources.bind(this));
}

Context.prototype.get = function(id, args) {
  return this.ready.then(this._getFallback.bind(this, id, args));
};

Context.prototype.destroy = function() {
  var env = this._env;
  this._resIds.forEach(function(resId) {
    if (env._resMap[resId].size === 1) {
      env._resMap[resId].clear();
      delete env._resCache[resId];
    } else {
      env._resMap[resId].delete(this);
    }
  }, this);
};

Context.prototype._fetchResources = function(supported) {
  debug('fetching resources for', supported.join(', '));

  if (supported.length === 0) {
    return Promise.reject(
      new L10nError('No more supported languages to try'));
  }

  return Promise.all(
    this._resIds.map(
      this._env._getResource.bind(this._env, supported[0]))).then(
        function() {
          return supported;
        });
};

Context.prototype._getFallback = function(id, args, supported) {
  var lang = supported[0];
  var entity = this._getEntity(lang, id);

  if (!entity) {
    debug(id, 'missing from', lang);
    return this._fetchResources(supported.slice(1)).then(
      this._getFallback.bind(this, id, args),
      function(err) {
        debug(err);
        // XXX comply to Gaia's l10n.js behavior for now;
        // return id in the future
        return Promise.resolve(null);
      });
  } else {
    debug(id, 'found in', lang);
    // XXX format the entity here, passing ctx and args
    // XXX handle compiler's runtime errors and fall back if needed
    // return entity.format(this, args);
    return Promise.resolve(entity);
  }
};

Context.prototype._getEntity = function(lang, id) {
  var cache = this._env._resCache;

  // Look for `id` in every resource in order.
  for (var i = 0, resId; resId = this._resIds[i]; i++) {
    if (cache[resId][lang] instanceof L10nError) {
      continue;
    }
    if (id in cache[resId][lang]) {
      // XXX compile here, passing lang
      // return new Entity(id, cache[resId][lang][id], lang);
      return cache[resId][lang][id];
    }
  }
  return undefined;
};

exports.Context = Context;
<|endoftext|>


<commit_before>if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define(function (require, exports, module) {
  'use strict';

  var EventEmitter = require('./events').EventEmitter;
  var Parser = require('./parser').Parser;
  var Compiler = require('./compiler').Compiler;
  var IO = require('./bindings/html/io').IO;
  var Promise = require('./promise').Promise;
  var RetranslationManager = require('./retranslation').RetranslationManager;

  function Resource(id, parser) {
    var self = this;

    this.id = id;
    this.resources = [];
    this.source = null;
    this.isReady = false;
    this.ast = {
      type: 'LOL',
      body: [],
    };

    this.build = build;

    var _imports_positions = [];

    function build(nesting, async) {
      if (nesting >= 7) {
        throw new ContextError("Too many nested imports.");
      }
      if (!async) {
        fetch(async);
        parse();
        buildImports(nesting + 1, async);
        flatten();
        return;
      }
      return fetch(async)
        .then(parse)
        .then(buildImports.bind(this, nesting + 1, async))
        .then(flatten);
    }

    function fetch(async) {
      if (!async) {
        if (!self.source) {
          self.source = IO.loadSync(self.id);
        }
        return;
      }
      if (self.source) {
        var source = new Promise();
        source.fulfill();
        return source;
      }
      return IO.loadAsync(self.id).then(function load_success(text) {
        self.source = text;
      });
    }

    function parse() {
      self.ast = parser.parse(self.source);
    }

    function buildImports(nesting, async) {
      var imports = self.ast.body.filter(function(elem, i) {
        if (elem.type == 'ImportStatement') {
          _imports_positions.push(i);
          return true;
        }
        return false;
      });

      imports.forEach(function(imp) {
        var uri = relativeToSelf(imp.uri.content);
        var res = new Resource(uri, parser);
        self.resources.push(res);
      });

      var imports_built = [];
      self.resources.forEach(function(res) {
        imports_built.push(res.build(nesting, async));
      });

      if (async) {
        return Promise.all(imports_built);
      }
    }

    function flatten() {
      for (var i = self.resources.length-1; i >= 0; i--) {
        var pos = _imports_positions[i] || 0;
        Array.prototype.splice.apply(self.ast.body,
          [pos, 1].concat(self.resources[i].ast.body));
      }
      self.isReady = true;
    }

    function relativeToSelf(url) {
      if (self.id === null || url[0] == '/') {
        return url;
      }
      var dirname = self.id.split('/').slice(0, -1).join('/');
      if (dirname) {
        // strip the trailing slash if present
        if (dirname[dirname.length - 1] == '/') {
          dirname = dirname.slice(0, dirname.length - 1);
        }
        return dirname + '/' + url;
      } else {
        return './' + url;
      }
    }

  }

  function Locale(id, parser, compiler) {
    this.id = id;
    this.resources = [];
    this.entries = null;
    this.ast = {
      type: 'LOL',
      body: [],
    };
    this.isReady = false;

    this.build = build;
    this.getEntry = getEntry;

    var self = this;

    function build(async) {
      if (!async) {
        buildResources(async);
        flatten();
        compile();
        return this;
      }
      return buildResources(async)
        .then(flatten)
        .then(compile);
    }

    function buildResources(async) {
      var resources_built = [];
      self.resources.forEach(function(res) {
        resources_built.push(res.build(0, async));
      });
      if (async) {
        return Promise.all(resources_built);
      }
    }

    function flatten() {
      self.ast.body = self.resources.reduce(function(prev, curr) {
        return prev.concat(curr.ast.body);
      }, self.ast.body);
    }

    function compile() {
      self.entries = compiler.compile(self.ast);
      self.isReady = true;
    }

    function getEntry(id) {
      if (this.entries.hasOwnProperty(id)) {
        return this.entries[id];
      }
      return undefined;
    }
  }

  function Context(id) {

    this.id = id;
    this.data = {};

    this.addResource = addResource;
    this.linkResource = linkResource;
    this.registerLocales = registerLocales;
    this.freeze = freeze;

    this.get = get;
    this.getEntity = getEntity;
    this.localize = localize;

    this.addEventListener = addEventListener;
    this.removeEventListener = removeEventListener;

    // all languages registered as available (list of codes)
    var _available = [];
    var _locales = {};
    // a special Locale for resources not associated with any other
    var _none;

    var _reslinks = [];

    var _isFrozen = false;
    var _isReady = false;
    var _emitter = new EventEmitter();
    var _parser = new Parser();
    var _compiler = new Compiler();

    var _retr = new RetranslationManager();

    var _listeners = [];

    _parser.addEventListener('error', echo);
    _compiler.addEventListener('error', echo);
    _compiler.setGlobals(_retr.globals);

    function get(id, data) {
      if (!_isReady) {
        throw new ContextError("Context not ready");
      }
      return getFromLocale.call(this, 0, id, data).value;
    }

    function getEntity(id, data) {
      if (!_isReady) {
        throw new ContextError("Context not ready");
      }
      return getFromLocale.call(this, 0, id, data);
    }

    function localize(idsOrTuples, callback) {
      if (!_isReady) {
        if (!callback) {
          throw new ContextError("Context not ready");
        }
        _retr.bindGet({
          id: callback,
          callback: getMany.bind(this, idsOrTuples, callback),
          globals: [],
        });
        // XXX: add stop and retranslate to the returned object
        return {};
      }
      return getMany.call(this, idsOrTuples, callback);
    }

    function getMany(idsOrTuples, callback) {
      var vals = {};
      var globalsUsed = {};
      var id;
      for (var i = 0, iot; iot = idsOrTuples[i]; i++) {
        if (Array.isArray(iot)) {
          id = iot[0];
          vals[id] = getEntity.call(this, iot[0], iot[1]);
        } else {
          id = iot;
          vals[id] = getEntity.call(this, iot);
        }
        for (var global in vals[id].globals) {
          if (vals[id].globals.hasOwnProperty(global)) {
            globalsUsed[global] = true;
          }
        }
      }
      var l10n = {
        entities: vals,
        //stop: fn
      };
      if (callback) {
        callback(l10n);
        _retr.bindGet({
          id: callback,
          callback: getMany.bind(this, idsOrTuples, callback),
          globals: Object.keys(globalsUsed),
        });
      }
      // XXX: add stop and retranslate to the returned object
      return {};
    }

    function getLocale(i) {
      // if we're out of locales from `_available`, resort to `_none`
      if (_available.length - i == 0) {
        return _none;
      }
      return  _locales[_available[i]];
    }

    function getFromLocale(cur, id, data, sourceString) {
      var locale = getLocale(cur);

      if (!locale) {
        var ex = new GetError("Entity couldn't be retrieved", id, _available);
        _emitter.emit('error', ex);
        // imitate the return value of Compiler.Entity.get
        return {
          value: sourceString ? sourceString : id,
          attributes: {},
          globals: {}
        };
      }

      if (!locale.isReady) {
        locale.build(false);
      }

      var entry = locale.getEntry(id);

      // if the entry is missing, just go to the next locale immediately
      if (entry === undefined) {
        _emitter.emit('error', new EntityError("Not found", id, locale.id));
        return getFromLocale.call(this, cur + 1, id, data, sourceString);
      }

      // otherwise, try to get the value of the entry
      try {
        return entry.get(getArgs.call(this, data));
      } catch(e) {
        if (e instanceof Compiler.RuntimeError) {
          _emitter.emit('error', new EntityError(e.message, id, locale.id));
          return getFromLocale.call(this, cur + 1, id, data,
                                    sourceString || e.source);
        } else {
          throw e;
        }
      }
    }

    function getArgs(data) {
      if (!data) {
        return this.data;
      }
      var args = {};
      for (var i in this.data) {
        if (this.data.hasOwnProperty(i)) {
          args[i] = this.data[i];
        }
      }
      if (data) {
        for (i in data) {
          if (data.hasOwnProperty(i)) {
            args[i] = data[i];
          }
        }
      }
      return args;
    }

    function addResource(text) {
      if (_none === undefined) {
        _none = new Locale(null, _parser, _compiler);
      }
      var res = new Resource(null, _parser);
      res.source = text;
      _none.resources.push(res);
    }

    function linkResource(uri) {
      _reslinks.push(uri);
    }

    function link(uri) {
      if (typeof uri === 'function') {
        return linkTemplate(uri);
      } else {
        return linkURI(uri);
      }
    }

    function linkTemplate(uriTemplate) {
      var uri, inRes;
      for (var lang in _locales) {
        uri = uriTemplate(lang);
        inRes = _locales[lang].resources.some(function(res) {
          return res.id === uri;
        });
        if (!inRes) {
          _locales[lang].resources.push(new Resource(uri, _parser));
        }
      }
      return true;
    }

    function linkURI(uri) {
      var res = new Resource(uri, _parser);
      var inRes;
      if (_available.length !== 0) {
        for (var lang in _locales) {
          inRes = _locales[lang].resources.some(function(res) {
            return res.id === uri;
          });
          if (!inRes) {
            _locales[lang].resources.push(res);
          }
        }
      }
      if (_none === undefined) {
        _none = new Locale(null, _parser, _compiler);
      } else {
        inRes = _none.resources.some(function(res) {
          return res.id === uri;
        });
        if (!inRes) {
          _none.resources.push(res);
        }
      }
      return true;
    }

    function registerLocales() {
      if (_isFrozen && !_isReady) {
        throw new ContextError("Context not ready");
      }
      _available = [];
      for (var i in arguments) {
        var lang = arguments[i];
        _available.push(lang);
        if (!(lang in _locales)) {
          _locales[lang] = new Locale(lang, _parser, _compiler);
        }
      }
      if (_isFrozen) {
        freeze();
      }
    }

    function freeze() {
      _isFrozen = true;
      for (var i = 0; i < _reslinks.length; i++) {
        link(_reslinks[i]);
      }
      var locale = _available.length > 0 ? _locales[_available[0]] : _none;
      return locale.build(true).then(setReady);
    }

    function setReady() {
      _isReady = true;
      _emitter.emit('ready');
      _retr.retranslate();
    }

    function addEventListener(type, listener) {
      _emitter.addEventListener(type, listener);
    }

    function removeEventListener(type, listener) {
      _emitter.removeEventListener(type, listener);
    }

    function echo(e) {
      _emitter.emit('error', e);
    }
}

  Context.Error = ContextError;
  Context.EntityError = EntityError;

  function ContextError(message) {
    this.name = 'ContextError';
    this.message = message;
  }
  ContextError.prototype = Object.create(Error.prototype);
  ContextError.prototype.constructor = ContextError;

  function EntityError(message, id, lang) {
    ContextError.call(this, message);
    this.name = 'EntityError';
    this.id = id;
    this.lang = lang;
    this.message = '[' + lang + '] ' + id + ': ' + message;
  }
  EntityError.prototype = Object.create(ContextError.prototype);
  EntityError.prototype.constructor = EntityError;

  function GetError(message, id, langs) {
    ContextError.call(this, message);
    this.name = 'GetError';
    this.id = id;
    this.tried = langs;
    if (langs.length) {
      this.message = id + ': ' + message + '; tried ' + langs.join(', ');
    } else {
      this.message = id + ': ' + message;
    }
  }
  GetError.prototype = Object.create(ContextError.prototype);
  GetError.prototype.constructor = GetError;

  exports.Context = Context;

});
<commit_msg>do not rebuild locale if it's ready<commit_after>if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}
define(function (require, exports, module) {
  'use strict';

  var EventEmitter = require('./events').EventEmitter;
  var Parser = require('./parser').Parser;
  var Compiler = require('./compiler').Compiler;
  var IO = require('./bindings/html/io').IO;
  var Promise = require('./promise').Promise;
  var RetranslationManager = require('./retranslation').RetranslationManager;

  function Resource(id, parser) {
    var self = this;

    this.id = id;
    this.resources = [];
    this.source = null;
    this.isReady = false;
    this.ast = {
      type: 'LOL',
      body: [],
    };

    this.build = build;

    var _imports_positions = [];

    function build(nesting, async) {
      if (nesting >= 7) {
        throw new ContextError("Too many nested imports.");
      }
      if (!async) {
        fetch(async);
        parse();
        buildImports(nesting + 1, async);
        flatten();
        return;
      }
      return fetch(async)
        .then(parse)
        .then(buildImports.bind(this, nesting + 1, async))
        .then(flatten);
    }

    function fetch(async) {
      if (!async) {
        if (!self.source) {
          self.source = IO.loadSync(self.id);
        }
        return;
      }
      if (self.source) {
        var source = new Promise();
        source.fulfill();
        return source;
      }
      return IO.loadAsync(self.id).then(function load_success(text) {
        self.source = text;
      });
    }

    function parse() {
      self.ast = parser.parse(self.source);
    }

    function buildImports(nesting, async) {
      var imports = self.ast.body.filter(function(elem, i) {
        if (elem.type == 'ImportStatement') {
          _imports_positions.push(i);
          return true;
        }
        return false;
      });

      imports.forEach(function(imp) {
        var uri = relativeToSelf(imp.uri.content);
        var res = new Resource(uri, parser);
        self.resources.push(res);
      });

      var imports_built = [];
      self.resources.forEach(function(res) {
        imports_built.push(res.build(nesting, async));
      });

      if (async) {
        return Promise.all(imports_built);
      }
    }

    function flatten() {
      for (var i = self.resources.length-1; i >= 0; i--) {
        var pos = _imports_positions[i] || 0;
        Array.prototype.splice.apply(self.ast.body,
          [pos, 1].concat(self.resources[i].ast.body));
      }
      self.isReady = true;
    }

    function relativeToSelf(url) {
      if (self.id === null || url[0] == '/') {
        return url;
      }
      var dirname = self.id.split('/').slice(0, -1).join('/');
      if (dirname) {
        // strip the trailing slash if present
        if (dirname[dirname.length - 1] == '/') {
          dirname = dirname.slice(0, dirname.length - 1);
        }
        return dirname + '/' + url;
      } else {
        return './' + url;
      }
    }

  }

  function Locale(id, parser, compiler) {
    this.id = id;
    this.resources = [];
    this.entries = null;
    this.ast = {
      type: 'LOL',
      body: [],
    };
    this.isReady = false;

    this.build = build;
    this.getEntry = getEntry;

    var self = this;

    function build(async) {
      if (!async) {
        buildResources(async);
        flatten();
        compile();
        return this;
      }
      return buildResources(async)
        .then(flatten)
        .then(compile);
    }

    function buildResources(async) {
      var resources_built = [];
      self.resources.forEach(function(res) {
        resources_built.push(res.build(0, async));
      });
      if (async) {
        return Promise.all(resources_built);
      }
    }

    function flatten() {
      self.ast.body = self.resources.reduce(function(prev, curr) {
        return prev.concat(curr.ast.body);
      }, self.ast.body);
    }

    function compile() {
      self.entries = compiler.compile(self.ast);
      self.isReady = true;
    }

    function getEntry(id) {
      if (this.entries.hasOwnProperty(id)) {
        return this.entries[id];
      }
      return undefined;
    }
  }

  function Context(id) {

    this.id = id;
    this.data = {};

    this.addResource = addResource;
    this.linkResource = linkResource;
    this.registerLocales = registerLocales;
    this.freeze = freeze;

    this.get = get;
    this.getEntity = getEntity;
    this.localize = localize;

    this.addEventListener = addEventListener;
    this.removeEventListener = removeEventListener;

    // all languages registered as available (list of codes)
    var _available = [];
    var _locales = {};
    // a special Locale for resources not associated with any other
    var _none;

    var _reslinks = [];

    var _isFrozen = false;
    var _isReady = false;
    var _emitter = new EventEmitter();
    var _parser = new Parser();
    var _compiler = new Compiler();

    var _retr = new RetranslationManager();

    var _listeners = [];

    _parser.addEventListener('error', echo);
    _compiler.addEventListener('error', echo);
    _compiler.setGlobals(_retr.globals);

    function get(id, data) {
      if (!_isReady) {
        throw new ContextError("Context not ready");
      }
      return getFromLocale.call(this, 0, id, data).value;
    }

    function getEntity(id, data) {
      if (!_isReady) {
        throw new ContextError("Context not ready");
      }
      return getFromLocale.call(this, 0, id, data);
    }

    function localize(idsOrTuples, callback) {
      if (!_isReady) {
        if (!callback) {
          throw new ContextError("Context not ready");
        }
        _retr.bindGet({
          id: callback,
          callback: getMany.bind(this, idsOrTuples, callback),
          globals: [],
        });
        // XXX: add stop and retranslate to the returned object
        return {};
      }
      return getMany.call(this, idsOrTuples, callback);
    }

    function getMany(idsOrTuples, callback) {
      var vals = {};
      var globalsUsed = {};
      var id;
      for (var i = 0, iot; iot = idsOrTuples[i]; i++) {
        if (Array.isArray(iot)) {
          id = iot[0];
          vals[id] = getEntity.call(this, iot[0], iot[1]);
        } else {
          id = iot;
          vals[id] = getEntity.call(this, iot);
        }
        for (var global in vals[id].globals) {
          if (vals[id].globals.hasOwnProperty(global)) {
            globalsUsed[global] = true;
          }
        }
      }
      var l10n = {
        entities: vals,
        //stop: fn
      };
      if (callback) {
        callback(l10n);
        _retr.bindGet({
          id: callback,
          callback: getMany.bind(this, idsOrTuples, callback),
          globals: Object.keys(globalsUsed),
        });
      }
      // XXX: add stop and retranslate to the returned object
      return {};
    }

    function getLocale(i) {
      // if we're out of locales from `_available`, resort to `_none`
      if (_available.length - i == 0) {
        return _none;
      }
      return  _locales[_available[i]];
    }

    function getFromLocale(cur, id, data, sourceString) {
      var locale = getLocale(cur);

      if (!locale) {
        var ex = new GetError("Entity couldn't be retrieved", id, _available);
        _emitter.emit('error', ex);
        // imitate the return value of Compiler.Entity.get
        return {
          value: sourceString ? sourceString : id,
          attributes: {},
          globals: {}
        };
      }

      if (!locale.isReady) {
        locale.build(false);
      }

      var entry = locale.getEntry(id);

      // if the entry is missing, just go to the next locale immediately
      if (entry === undefined) {
        _emitter.emit('error', new EntityError("Not found", id, locale.id));
        return getFromLocale.call(this, cur + 1, id, data, sourceString);
      }

      // otherwise, try to get the value of the entry
      try {
        return entry.get(getArgs.call(this, data));
      } catch(e) {
        if (e instanceof Compiler.RuntimeError) {
          _emitter.emit('error', new EntityError(e.message, id, locale.id));
          return getFromLocale.call(this, cur + 1, id, data,
                                    sourceString || e.source);
        } else {
          throw e;
        }
      }
    }

    function getArgs(data) {
      if (!data) {
        return this.data;
      }
      var args = {};
      for (var i in this.data) {
        if (this.data.hasOwnProperty(i)) {
          args[i] = this.data[i];
        }
      }
      if (data) {
        for (i in data) {
          if (data.hasOwnProperty(i)) {
            args[i] = data[i];
          }
        }
      }
      return args;
    }

    function addResource(text) {
      if (_none === undefined) {
        _none = new Locale(null, _parser, _compiler);
      }
      var res = new Resource(null, _parser);
      res.source = text;
      _none.resources.push(res);
    }

    function linkResource(uri) {
      _reslinks.push(uri);
    }

    function link(uri) {
      if (typeof uri === 'function') {
        return linkTemplate(uri);
      } else {
        return linkURI(uri);
      }
    }

    function linkTemplate(uriTemplate) {
      var uri, inRes;
      for (var lang in _locales) {
        uri = uriTemplate(lang);
        inRes = _locales[lang].resources.some(function(res) {
          return res.id === uri;
        });
        if (!inRes) {
          _locales[lang].resources.push(new Resource(uri, _parser));
        }
      }
      return true;
    }

    function linkURI(uri) {
      var res = new Resource(uri, _parser);
      var inRes;
      if (_available.length !== 0) {
        for (var lang in _locales) {
          inRes = _locales[lang].resources.some(function(res) {
            return res.id === uri;
          });
          if (!inRes) {
            _locales[lang].resources.push(res);
          }
        }
      }
      if (_none === undefined) {
        _none = new Locale(null, _parser, _compiler);
      } else {
        inRes = _none.resources.some(function(res) {
          return res.id === uri;
        });
        if (!inRes) {
          _none.resources.push(res);
        }
      }
      return true;
    }

    function registerLocales() {
      if (_isFrozen && !_isReady) {
        throw new ContextError("Context not ready");
      }
      _available = [];
      for (var i in arguments) {
        var lang = arguments[i];
        _available.push(lang);
        if (!(lang in _locales)) {
          _locales[lang] = new Locale(lang, _parser, _compiler);
        }
      }
      if (_isFrozen) {
        freeze();
      }
    }

    function freeze() {
      _isFrozen = true;
      for (var i = 0; i < _reslinks.length; i++) {
        link(_reslinks[i]);
      }
      var locale = _available.length > 0 ? _locales[_available[0]] : _none;
      if (locale.isReady) {
        return setReady();
      } else {
        return locale.build(true).then(setReady);
      }
    }

    function setReady() {
      _isReady = true;
      _emitter.emit('ready');
      _retr.retranslate();
    }

    function addEventListener(type, listener) {
      _emitter.addEventListener(type, listener);
    }

    function removeEventListener(type, listener) {
      _emitter.removeEventListener(type, listener);
    }

    function echo(e) {
      _emitter.emit('error', e);
    }
}

  Context.Error = ContextError;
  Context.EntityError = EntityError;

  function ContextError(message) {
    this.name = 'ContextError';
    this.message = message;
  }
  ContextError.prototype = Object.create(Error.prototype);
  ContextError.prototype.constructor = ContextError;

  function EntityError(message, id, lang) {
    ContextError.call(this, message);
    this.name = 'EntityError';
    this.id = id;
    this.lang = lang;
    this.message = '[' + lang + '] ' + id + ': ' + message;
  }
  EntityError.prototype = Object.create(ContextError.prototype);
  EntityError.prototype.constructor = EntityError;

  function GetError(message, id, langs) {
    ContextError.call(this, message);
    this.name = 'GetError';
    this.id = id;
    this.tried = langs;
    if (langs.length) {
      this.message = id + ': ' + message + '; tried ' + langs.join(', ');
    } else {
      this.message = id + ': ' + message;
    }
  }
  GetError.prototype = Object.create(ContextError.prototype);
  GetError.prototype.constructor = GetError;

  exports.Context = Context;

});
<|endoftext|>


<commit_before>//
// browser.js - client-side engine
//

var isFileProtocol = location.protocol === 'file:';

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.port.length > 0         ||
           isFileProtocol                   ? 'development'
                                            : 'production';

// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
less.async = false;

// Interval between watch polls
less.poll = isFileProtocol ? 1000 : 1500;

//
// Watch mode
//
less.watch   = function () { return this.watchMode = true };
less.unwatch = function () { return this.watchMode = false };

if (less.env === 'development') {
    less.optimization = 0;

    if (/!watch/.test(location.hash)) {
        less.watch();
    }
    less.watchTimer = setInterval(function () {
        if (less.watchMode) {
            loadStyleSheets(function (root, sheet, env) {
                if (root) {
                    createCSS(root.toCSS(), sheet, env.lastModified);
                }
            });
        }
    }, less.poll);
} else {
    less.optimization = 3;
}

var cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;

//
// Select all links with the 'rel' attribute set to "less"
//
var sheets = select('link[rel="stylesheet/less"]');

less.refresh = function () {
    loadStyleSheets(function (root, sheet, env) {
        if (env.local) {
            log("less: loading " + sheet.href + " from local storage.");
        } else {
            createCSS(root.toCSS(), sheet, env.lastModified);
            log("less: parsed " + sheet.href + " successfully.");
        }
    });
};

less.refresh();

function select(str) {
    if (!document.querySelectorAll && typeof(jQuery) === "undefined") {
        log("No selector method found");
    } else {
        return (document.querySelectorAll || jQuery).call(document, str);
    }
}

function loadStyleSheets(callback, async) {
    for (var i = 0; i < sheets.length; i++) {
        loadStyleSheet(sheets[i], callback, async);
    }
}

function loadStyleSheet(sheet, callback, async) {
    var css       = cache && cache.getItem(sheet.href);
    var timestamp = cache && cache.getItem(sheet.href + ':timestamp');
    var styles = { css: css, timestamp: timestamp };

    xhr(sheet.href, async, function (data, lastModified) {
        if (styles && (new(Date)(lastModified).valueOf() ===
                       new(Date)(styles.timestamp).valueOf())) {
            // Use local copy
            createCSS(styles.css, sheet);
            callback(null, sheet, { local: true });
        } else {
            // Use remote copy (re-parse)
            new(less.Parser)({
                optimization: less.optimization
            }).parse(data, function (e, root) {
                if (e) { return error(e, sheet.href) }
                try {
                    callback(root, sheet, { local: false, lastModified: lastModified });
                    removeNode(document.getElementById('less-error-message:' + sheet.href.replace(/[^a-z]+/gi, '-')));
                } catch (e) {
                    error(e, sheet.href);
                }
            });
        }
    }, function (status) {
        throw new(Error)("Couldn't load " + sheet.href + " (" + status + ")");
    });
}

function createCSS(styles, sheet, lastModified) {
    var css;

    // If there is no title set, use the filename, minus the extension
    var id = 'less:' + (sheet.title || sheet.href.match(/(?:^|\/)([-\w]+)\.[a-z]+$/i)[1]);

    // If the stylesheet doesn't exist, create a new node
    if ((css = document.getElementById(id)) === null) {
        css = document.createElement('style');
        css.type = 'text/css';
        css.media = 'screen';
        css.id = id;
        document.getElementsByTagName('head')[0].appendChild(css);
    }

    if (css.styleSheet) { // IE
        try {
            css.styleSheet.cssText = styles;
        } catch (e) {
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
        }
    } else {
        (function (node) {
            if (css.childNodes.length > 0) {
                if (css.firstChild.nodeValue !== node.nodeValue) {
                    css.replaceChild(node, css.firstChild);
                }
            } else {
                css.appendChild(node);
            }
        })(document.createTextNode(styles));
    }

    // Don't update the local store if the file wasn't modified
    if (lastModified && cache) {
        cache.setItem(sheet.href, styles);
        cache.setItem(sheet.href + ':timestamp', lastModified);
    }
}

function xhr(url, async, callback, errback) {
    var xhr = getXMLHttpRequest();

    async = isFileProtocol ? false : (async || less.async);

    xhr.open('GET', url, async);
    xhr.send(null);

    if (isFileProtocol) {
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.status);
        }
    } else if (async) {
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                handleResponse(xhr, callback, errback);
            }
        };
    } else {
        handleResponse(xhr, callback, errback);
    }

    function handleResponse(xhr, callback, errback) {
        if (xhr.status >= 200 && xhr.status < 300) {
            callback(xhr.responseText,
                     xhr.getResponseHeader("Last-Modified"));
        } else if (typeof(errback) === 'function') {
            errback(xhr.status);
        }
    }
}

function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        return new(XMLHttpRequest);
    } else {
        try {
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
        } catch (e) {
            log("less: browser doesn't support AJAX.");
            return null;
        }
    }
}

function removeNode(node) {
    return node && node.parentNode.removeChild(node);
}

function log(str) {
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log(str) }
}

function error(e, href) {
    var id = 'less-error-message:' + href.replace(/[^a-z]+/ig, '-');

    if (! e.extract) { throw e }

    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = id;
    elem.className = "less-error-message";
    elem.innerHTML = '
' + (e.message || 'There is an error in your .less file') + '
' +
                     '
' + href + " "                +
                     'on line '     + e.line + ', column ' + (e.column + 1)         + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         return (parseInt(e.line) + parseInt(i)) || '';
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)] || '';
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)      +
                                               ''               +
                                               e.extract[1].slice(e.column)         +
                                               '');
    // CSS for error messages
    createCSS([
        '.less-error-message span {',
            'margin-right: 15px;',
        '}',
        '.less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '.less-error-message pre.ctx {',
            'color: #dd7777;',
        '}',
        '.less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '.less-error-message a {',
            'color: #10a',
        '}',
        '.less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join('\n'), { title: 'error-message' });

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "-webkit-border-radius: 5px",
        "-moz-border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                if (document.getElementById(id)) {
                    document.body.replaceChild(elem, document.getElementById(id));
                } else {
                    document.body.insertBefore(elem, document.body.firstChild);
                }
                clearInterval(timer);
            }
        }, 10);
    }
}

//
// Used by `@import` directives
//
less.Parser.importer = function (path, paths, callback) {
    loadStyleSheet({ href: path, title: path }, function (root) {
        callback(root);
    });
};

<commit_msg>(api) less.refresh(true) reloads stylesheets from source<commit_after>//
// browser.js - client-side engine
//

var isFileProtocol = location.protocol === 'file:';

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.port.length > 0         ||
           isFileProtocol                   ? 'development'
                                            : 'production';

// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
less.async = false;

// Interval between watch polls
less.poll = isFileProtocol ? 1000 : 1500;

//
// Watch mode
//
less.watch   = function () { return this.watchMode = true };
less.unwatch = function () { return this.watchMode = false };

if (less.env === 'development') {
    less.optimization = 0;

    if (/!watch/.test(location.hash)) {
        less.watch();
    }
    less.watchTimer = setInterval(function () {
        if (less.watchMode) {
            loadStyleSheets(function (root, sheet, env) {
                if (root) {
                    createCSS(root.toCSS(), sheet, env.lastModified);
                }
            });
        }
    }, less.poll);
} else {
    less.optimization = 3;
}

var cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;

//
// Select all links with the 'rel' attribute set to "less"
//
var sheets = select('link[rel="stylesheet/less"]');

less.refresh = function (reload) {
    loadStyleSheets(function (root, sheet, env) {
        if (env.local) {
            log("less: loading " + sheet.href + " from local storage.");
        } else {
            createCSS(root.toCSS(), sheet, env.lastModified);
            log("less: parsed " + sheet.href + " successfully.");
        }
    }, reload);
};

less.refresh();

function select(str) {
    if (!document.querySelectorAll && typeof(jQuery) === "undefined") {
        log("No selector method found");
    } else {
        return (document.querySelectorAll || jQuery).call(document, str);
    }
}

function loadStyleSheets(callback, reload) {
    for (var i = 0; i < sheets.length; i++) {
        loadStyleSheet(sheets[i], callback, reload);
    }
}

function loadStyleSheet(sheet, callback, reload) {
    var css       = cache && cache.getItem(sheet.href);
    var timestamp = cache && cache.getItem(sheet.href + ':timestamp');
    var styles = { css: css, timestamp: timestamp };

    xhr(sheet.href, function (data, lastModified) {
        if (!reload && styles &&
           (new(Date)(lastModified).valueOf() ===
            new(Date)(styles.timestamp).valueOf())) {
            // Use local copy
            createCSS(styles.css, sheet);
            callback(null, sheet, { local: true });
        } else {
            // Use remote copy (re-parse)
            new(less.Parser)({
                optimization: less.optimization
            }).parse(data, function (e, root) {
                if (e) { return error(e, sheet.href) }
                try {
                    callback(root, sheet, { local: false, lastModified: lastModified });
                    removeNode(document.getElementById('less-error-message:' + sheet.href.replace(/[^a-z]+/gi, '-')));
                } catch (e) {
                    error(e, sheet.href);
                }
            });
        }
    }, function (status) {
        throw new(Error)("Couldn't load " + sheet.href + " (" + status + ")");
    });
}

function createCSS(styles, sheet, lastModified) {
    var css;

    // If there is no title set, use the filename, minus the extension
    var id = 'less:' + (sheet.title || sheet.href.match(/(?:^|\/)([-\w]+)\.[a-z]+$/i)[1]);

    // If the stylesheet doesn't exist, create a new node
    if ((css = document.getElementById(id)) === null) {
        css = document.createElement('style');
        css.type = 'text/css';
        css.media = 'screen';
        css.id = id;
        document.getElementsByTagName('head')[0].appendChild(css);
    }

    if (css.styleSheet) { // IE
        try {
            css.styleSheet.cssText = styles;
        } catch (e) {
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
        }
    } else {
        (function (node) {
            if (css.childNodes.length > 0) {
                if (css.firstChild.nodeValue !== node.nodeValue) {
                    css.replaceChild(node, css.firstChild);
                }
            } else {
                css.appendChild(node);
            }
        })(document.createTextNode(styles));
    }

    // Don't update the local store if the file wasn't modified
    if (lastModified && cache) {
        log('saving ' + sheet.href + ' to cache.');
        cache.setItem(sheet.href, styles);
        cache.setItem(sheet.href + ':timestamp', lastModified);
    }
}

function xhr(url, callback, errback) {
    var xhr = getXMLHttpRequest();
    var async = isFileProtocol ? false : less.async;

    xhr.open('GET', url, async);
    xhr.send(null);

    if (isFileProtocol) {
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.status);
        }
    } else if (async) {
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                handleResponse(xhr, callback, errback);
            }
        };
    } else {
        handleResponse(xhr, callback, errback);
    }

    function handleResponse(xhr, callback, errback) {
        if (xhr.status >= 200 && xhr.status < 300) {
            callback(xhr.responseText,
                     xhr.getResponseHeader("Last-Modified"));
        } else if (typeof(errback) === 'function') {
            errback(xhr.status);
        }
    }
}

function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        return new(XMLHttpRequest);
    } else {
        try {
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
        } catch (e) {
            log("less: browser doesn't support AJAX.");
            return null;
        }
    }
}

function removeNode(node) {
    return node && node.parentNode.removeChild(node);
}

function log(str) {
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log(str) }
}

function error(e, href) {
    var id = 'less-error-message:' + href.replace(/[^a-z]+/ig, '-');

    if (! e.extract) { throw e }

    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = id;
    elem.className = "less-error-message";
    elem.innerHTML = '
' + (e.message || 'There is an error in your .less file') + '
' +
                     '
' + href + " "                +
                     'on line '     + e.line + ', column ' + (e.column + 1)         + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         return (parseInt(e.line) + parseInt(i)) || '';
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)] || '';
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)      +
                                               ''               +
                                               e.extract[1].slice(e.column)         +
                                               '');
    // CSS for error messages
    createCSS([
        '.less-error-message span {',
            'margin-right: 15px;',
        '}',
        '.less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '.less-error-message pre.ctx {',
            'color: #dd7777;',
        '}',
        '.less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '.less-error-message a {',
            'color: #10a',
        '}',
        '.less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join('\n'), { title: 'error-message' });

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "-webkit-border-radius: 5px",
        "-moz-border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                if (document.getElementById(id)) {
                    document.body.replaceChild(elem, document.getElementById(id));
                } else {
                    document.body.insertBefore(elem, document.body.firstChild);
                }
                clearInterval(timer);
            }
        }, 10);
    }
}

//
// Used by `@import` directives
//
less.Parser.importer = function (path, paths, callback) {
    loadStyleSheet({ href: path, title: path }, function (root) {
        callback(root);
    });
};

<|endoftext|>


<commit_before>//
// browser.js - client-side engine
//

var isFileProtocol = (location.protocol === 'file:' ||
                      location.protocol === 'chrome:' ||
                      location.protocol === 'resource:');

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.port.length > 0         ||
           isFileProtocol                   ? 'development'
                                            : 'production';

// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
less.async = false;

// Interval between watch polls
less.poll = isFileProtocol ? 1000 : 1500;

//
// Watch mode
//
less.watch   = function () { return this.watchMode = true };
less.unwatch = function () { return this.watchMode = false };

if (less.env === 'development') {
    less.optimization = 0;

    if (/!watch/.test(location.hash)) {
        less.watch();
    }
    less.watchTimer = setInterval(function () {
        if (less.watchMode) {
            loadStyleSheets(function (root, sheet, env) {
                if (root) {
                    createCSS(root.toCSS(), sheet, env.lastModified);
                }
            });
        }
    }, less.poll);
} else {
    less.optimization = 3;
}

var cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;

//
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
//
var links = document.getElementsByTagName('link');

less.sheets = [];

for (var i = 0; i < links.length; i++) {
    if (links[i].rel === 'stylesheet/less') {
        less.sheets.push(links[i]);
    }
}

var startTime = endTime = new(Date);

less.refresh = function (reload) {
    loadStyleSheets(function (root, sheet, env) {
        if (env.local) {
            log("loading " + sheet.href + " from cache.");
        } else {
            log("parsed " + sheet.href + " successfully.");
            createCSS(root.toCSS(), sheet, env.lastModified);
        }
        log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
        (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
        endTime = new(Date);
    }, reload);
};

less.refresh();

function loadStyleSheets(callback, reload) {
    for (var i = 0; i < less.sheets.length; i++) {
        loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
    }
}

function loadStyleSheet(sheet, callback, reload, remaining) {
    var href      = sheet.href.replace(/\?.*$/, '');
    var css       = cache && cache.getItem(href);
    var timestamp = cache && cache.getItem(href + ':timestamp');
    var styles    = { css: css, timestamp: timestamp };

    xhr(sheet.href, function (data, lastModified) {
        if (!reload && styles &&
           (new(Date)(lastModified).valueOf() ===
            new(Date)(styles.timestamp).valueOf())) {
            // Use local copy
            createCSS(styles.css, sheet);
            callback(null, sheet, { local: true, remaining: remaining });
        } else {
            // Use remote copy (re-parse)
            new(less.Parser)({
                optimization: less.optimization,
                paths: [href.replace(/[\w\.-]+$/, '')]
            }).parse(data, function (e, root) {
                if (e) { return error(e, href) }
                try {
                    callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining });
                    removeNode(document.getElementById('less-error-message:' + href.replace(/[^a-z]+/gi, '-')));
                } catch (e) {
                    error(e, href);
                }
            });
        }
    }, function (status, url) {
        throw new(Error)("Couldn't load " + url+ " (" + status + ")");
    });
}

function createCSS(styles, sheet, lastModified) {
    var css;

    // Strip the query-string
    var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';

    // If there is no title set, use the filename, minus the extension
    var id = 'less:' + (sheet.title || href.match(/(?:^|\/)([-\w]+)\.[a-z]+$/i)[1]);

    // If the stylesheet doesn't exist, create a new node
    if ((css = document.getElementById(id)) === null) {
        css = document.createElement('style');
        css.type = 'text/css';
        css.media = sheet.media;
        css.id = id;
        document.getElementsByTagName('head')[0].appendChild(css);
    }

    if (css.styleSheet) { // IE
        try {
            css.styleSheet.cssText = styles;
        } catch (e) {
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
        }
    } else {
        (function (node) {
            if (css.childNodes.length > 0) {
                if (css.firstChild.nodeValue !== node.nodeValue) {
                    css.replaceChild(node, css.firstChild);
                }
            } else {
                css.appendChild(node);
            }
        })(document.createTextNode(styles));
    }

    // Don't update the local store if the file wasn't modified
    if (lastModified && cache) {
        log('saving ' + href + ' to cache.');
        cache.setItem(href, styles);
        cache.setItem(href + ':timestamp', lastModified);
    }
}

function xhr(url, callback, errback) {
    var xhr = getXMLHttpRequest();
    var async = isFileProtocol ? false : less.async;

    if (typeof xhr.overrideMimeType === 'function') {
      xhr.overrideMimeType('text/css');
    }
    xhr.open('GET', url, async);
    xhr.send(null);

    if (isFileProtocol) {
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.status);
        }
    } else if (async) {
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                handleResponse(xhr, callback, errback);
            }
        };
    } else {
        handleResponse(xhr, callback, errback);
    }

    function handleResponse(xhr, callback, errback) {
        if (xhr.status >= 200 && xhr.status < 300) {
            callback(xhr.responseText,
                     xhr.getResponseHeader("Last-Modified"));
        } else if (typeof(errback) === 'function') {
            errback(xhr.status, url);
        }
    }
}

function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        return new(XMLHttpRequest);
    } else {
        try {
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
        } catch (e) {
            log("browser doesn't support AJAX.");
            return null;
        }
    }
}

function removeNode(node) {
    return node && node.parentNode.removeChild(node);
}

function log(str) {
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
}

function error(e, href) {
    var id = 'less-error-message:' + href.replace(/[^a-z]+/ig, '-');

    if (! e.extract) { throw e }

    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = id;
    elem.className = "less-error-message";
    elem.innerHTML = '
' + (e.message || 'There is an error in your .less file') + '
' +
                     '
' + href + " "                +
                     'on line '     + e.line + ', column ' + (e.column + 1)         + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         return (parseInt(e.line) + parseInt(i)) || '';
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)] || '';
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)      +
                                               ''               +
                                               e.extract[1].slice(e.column)         +
                                               '');
    // CSS for error messages
    createCSS([
        '.less-error-message span {',
            'margin-right: 15px;',
        '}',
        '.less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '.less-error-message pre.ctx {',
            'color: #dd7777;',
        '}',
        '.less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '.less-error-message a {',
            'color: #10a',
        '}',
        '.less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join('\n'), { title: 'error-message' });

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "-webkit-border-radius: 5px",
        "-moz-border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                if (document.getElementById(id)) {
                    document.body.replaceChild(elem, document.getElementById(id));
                } else {
                    document.body.insertBefore(elem, document.body.firstChild);
                }
                clearInterval(timer);
            }
        }, 10);
    }
}

<commit_msg>bug: window.localStorage in Firefox<commit_after>//
// browser.js - client-side engine
//

var isFileProtocol = (location.protocol === 'file:' ||
                      location.protocol === 'chrome:' ||
                      location.protocol === 'resource:');

less.env = location.hostname == '127.0.0.1' ||
           location.hostname == '0.0.0.0'   ||
           location.hostname == 'localhost' ||
           location.port.length > 0         ||
           isFileProtocol                   ? 'development'
                                            : 'production';

// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
less.async = false;

// Interval between watch polls
less.poll = isFileProtocol ? 1000 : 1500;

//
// Watch mode
//
less.watch   = function () { return this.watchMode = true };
less.unwatch = function () { return this.watchMode = false };

if (less.env === 'development') {
    less.optimization = 0;

    if (/!watch/.test(location.hash)) {
        less.watch();
    }
    less.watchTimer = setInterval(function () {
        if (less.watchMode) {
            loadStyleSheets(function (root, sheet, env) {
                if (root) {
                    createCSS(root.toCSS(), sheet, env.lastModified);
                }
            });
        }
    }, less.poll);
} else {
    less.optimization = 3;
}

var cache;
try {
  cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
} catch (e) {
  cache = null;
}

//
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
//
var links = document.getElementsByTagName('link');

less.sheets = [];

for (var i = 0; i < links.length; i++) {
    if (links[i].rel === 'stylesheet/less') {
        less.sheets.push(links[i]);
    }
}

var startTime = endTime = new(Date);

less.refresh = function (reload) {
    loadStyleSheets(function (root, sheet, env) {
        if (env.local) {
            log("loading " + sheet.href + " from cache.");
        } else {
            log("parsed " + sheet.href + " successfully.");
            createCSS(root.toCSS(), sheet, env.lastModified);
        }
        log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
        (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
        endTime = new(Date);
    }, reload);
};

less.refresh();

function loadStyleSheets(callback, reload) {
    for (var i = 0; i < less.sheets.length; i++) {
        loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
    }
}

function loadStyleSheet(sheet, callback, reload, remaining) {
    var href      = sheet.href.replace(/\?.*$/, '');
    var css       = cache && cache.getItem(href);
    var timestamp = cache && cache.getItem(href + ':timestamp');
    var styles    = { css: css, timestamp: timestamp };

    xhr(sheet.href, function (data, lastModified) {
        if (!reload && styles &&
           (new(Date)(lastModified).valueOf() ===
            new(Date)(styles.timestamp).valueOf())) {
            // Use local copy
            createCSS(styles.css, sheet);
            callback(null, sheet, { local: true, remaining: remaining });
        } else {
            // Use remote copy (re-parse)
            new(less.Parser)({
                optimization: less.optimization,
                paths: [href.replace(/[\w\.-]+$/, '')]
            }).parse(data, function (e, root) {
                if (e) { return error(e, href) }
                try {
                    callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining });
                    removeNode(document.getElementById('less-error-message:' + href.replace(/[^a-z]+/gi, '-')));
                } catch (e) {
                    error(e, href);
                }
            });
        }
    }, function (status, url) {
        throw new(Error)("Couldn't load " + url+ " (" + status + ")");
    });
}

function createCSS(styles, sheet, lastModified) {
    var css;

    // Strip the query-string
    var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';

    // If there is no title set, use the filename, minus the extension
    var id = 'less:' + (sheet.title || href.match(/(?:^|\/)([-\w]+)\.[a-z]+$/i)[1]);

    // If the stylesheet doesn't exist, create a new node
    if ((css = document.getElementById(id)) === null) {
        css = document.createElement('style');
        css.type = 'text/css';
        css.media = sheet.media;
        css.id = id;
        document.getElementsByTagName('head')[0].appendChild(css);
    }

    if (css.styleSheet) { // IE
        try {
            css.styleSheet.cssText = styles;
        } catch (e) {
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
        }
    } else {
        (function (node) {
            if (css.childNodes.length > 0) {
                if (css.firstChild.nodeValue !== node.nodeValue) {
                    css.replaceChild(node, css.firstChild);
                }
            } else {
                css.appendChild(node);
            }
        })(document.createTextNode(styles));
    }

    // Don't update the local store if the file wasn't modified
    if (lastModified && cache) {
        log('saving ' + href + ' to cache.');
        cache.setItem(href, styles);
        cache.setItem(href + ':timestamp', lastModified);
    }
}

function xhr(url, callback, errback) {
    var xhr = getXMLHttpRequest();
    var async = isFileProtocol ? false : less.async;

    if (typeof xhr.overrideMimeType === 'function') {
      xhr.overrideMimeType('text/css');
    }
    xhr.open('GET', url, async);
    xhr.send(null);

    if (isFileProtocol) {
        if (xhr.status === 0) {
            callback(xhr.responseText);
        } else {
            errback(xhr.status);
        }
    } else if (async) {
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                handleResponse(xhr, callback, errback);
            }
        };
    } else {
        handleResponse(xhr, callback, errback);
    }

    function handleResponse(xhr, callback, errback) {
        if (xhr.status >= 200 && xhr.status < 300) {
            callback(xhr.responseText,
                     xhr.getResponseHeader("Last-Modified"));
        } else if (typeof(errback) === 'function') {
            errback(xhr.status, url);
        }
    }
}

function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        return new(XMLHttpRequest);
    } else {
        try {
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
        } catch (e) {
            log("browser doesn't support AJAX.");
            return null;
        }
    }
}

function removeNode(node) {
    return node && node.parentNode.removeChild(node);
}

function log(str) {
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
}

function error(e, href) {
    var id = 'less-error-message:' + href.replace(/[^a-z]+/ig, '-');

    if (! e.extract) { throw e }

    var template = ['
',
                        '
[-1]{0}
',
                        '
[0]{current}
',
                        '
[1]{2}
',
                    '
'].join('\n');

    var elem = document.createElement('div'), timer;
    elem.id = id;
    elem.className = "less-error-message";
    elem.innerHTML = '
' + (e.message || 'There is an error in your .less file') + '
' +
                     '
' + href + " "                +
                     'on line '     + e.line + ', column ' + (e.column + 1)         + ':
' +
                     template.replace(/\[(-?\d)\]/g, function (_, i) {
                         return (parseInt(e.line) + parseInt(i)) || '';
                     }).replace(/\{(\d)\}/g, function (_, i) {
                         return e.extract[parseInt(i)] || '';
                     }).replace(/\{current\}/, e.extract[1].slice(0, e.column)      +
                                               ''               +
                                               e.extract[1].slice(e.column)         +
                                               '');
    // CSS for error messages
    createCSS([
        '.less-error-message span {',
            'margin-right: 15px;',
        '}',
        '.less-error-message pre {',
            'color: #ee4444;',
            'padding: 4px 0;',
            'margin: 0;',
        '}',
        '.less-error-message pre.ctx {',
            'color: #dd7777;',
        '}',
        '.less-error-message h3 {',
            'padding: 15px 0 5px 0;',
            'margin: 0;',
        '}',
        '.less-error-message a {',
            'color: #10a',
        '}',
        '.less-error-message .error {',
            'color: red;',
            'font-weight: bold;',
            'padding-bottom: 2px;',
            'border-bottom: 1px dashed red;',
        '}'
    ].join('\n'), { title: 'error-message' });

    elem.style.cssText = [
        "font-family: Arial, sans-serif",
        "border: 1px solid #e00",
        "background-color: #eee",
        "border-radius: 5px",
        "-webkit-border-radius: 5px",
        "-moz-border-radius: 5px",
        "color: #e00",
        "padding: 15px",
        "margin-bottom: 15px"
    ].join(';');

    if (less.env == 'development') {
        timer = setInterval(function () {
            if (document.body) {
                if (document.getElementById(id)) {
                    document.body.replaceChild(elem, document.getElementById(id));
                } else {
                    document.body.insertBefore(elem, document.body.firstChild);
                }
                clearInterval(timer);
            }
        }, 10);
    }
}

<|endoftext|>


<commit_before>/**
 * include is a function which decorates a target class with the static
 * and instance methods of another class. Usage:
 *
 * @include(IncludableModule, AntherIncludable)
 * class Something {}
 *
*/
function include(...included) {
  return function decorate(target) {
    if (typeof included !== 'undefined' && included.length > 0) {
      included.forEach(to_include => {
        _include(target, to_include)
        _include(target.prototype, to_include.prototype)
      })
    }
  }
}

/**
 * Copies the Proprerty from the source to the target maintaining the
 * given descriptor from the source.
*/
function _include(klass, to_include) {
  Object.getOwnPropertyNames(to_include).forEach(include_property)
  Object.getOwnPropertySymbols(to_include).forEach(include_property)

  function include_property(name) {
    if (should_include(name)) {
      const descriptor = Object.getOwnPropertyDescriptor(to_include, name)
      Object.defineProperty(klass, name, descriptor)
    }
  }

  /**
   * Only the non-existing properties are included. Special properties
   * are also ignored.
  */
  function should_include(name) {
    return (
      !Object.hasOwnProperty(klass, name) &&
        ['prototype', 'name', 'constructor'].indexOf(name) === -1
    )
  }
}

export { include }
<commit_msg>Add documentation for include<commit_after>/**
 * include is a function which decorates a target class with the static
 * and instance methods of another class.
 *
 * ```js
 * import { include }  from 'tays/meta'
 * import { IncludeableModule, AnotherIncludeable } from '../mixins'
 *
 * @include(IncludableModule, AntherIncludable)
 * class Something {}
 *
 * // Something now has the static and instance methods of
 * // IncludableModule and AnotherIncludeable
 * ```
 *
 * If your environment is not using descorators. The following syntax
 * may be used as an alternative.
 *
 * ```js
 * import { include }  from 'tays/meta'
 * import { IncludeableModule, AnotherIncludeable } from '../mixins'
 *
 * class Something {}
 * include(IncludableModule, AntherIncludable)(Something)
 * ```
*/
export function include(...included) {
  return function decorate(target) {
    if (typeof included !== 'undefined' && included.length > 0) {
      included.forEach(to_include => {
        _include(target, to_include)
        _include(target.prototype, to_include.prototype)
      })
    }
  }
}

/**
 * Copies the Properties from the source class to the target class.
 * Both Symbols and Names are copied.
*/
function _include(klass, to_include) {
  Object.getOwnPropertyNames(to_include).forEach(include_property)
  Object.getOwnPropertySymbols(to_include).forEach(include_property)

  /**
   * Copies a single property of a name or symbol from the source to
   * the target class.
  */
  function include_property(name) {
    if (should_include(name)) {
      const descriptor = Object.getOwnPropertyDescriptor(to_include, name)
      Object.defineProperty(klass, name, descriptor)
    }
  }

  /**
   * Only the non-existing properties are included. Special properties
   * are also ignored.
  */
  function should_include(name) {
    return (
      !Object.hasOwnProperty(klass, name) &&
        ['prototype', 'name', 'constructor'].indexOf(name) === -1
    )
  }
}
<|endoftext|>


<commit_before>Accounts.onLogin(function() {
	if ($('#navigation').hasClass('in')) {
		$('#navigation').removeClass('in');
	}
});
<commit_msg>Add automatic route<commit_after>Accounts.onLogin(function() {
	if ($('#navigation').hasClass('in')) {
		$('#navigation').removeClass('in');
	}
	if (!Meteor.user().profile.firstName || !Meteor.user().profile.lastName) {
		Router.go('accountWrapper');
	}
});
<|endoftext|>