<commit_before>var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var packageClient = require('./package-client.js');
var watch = require('./watch.js');
var archinfo = require('./archinfo.js');
var isopack = require('./isopack.js');
var compiler = require('./compiler.js');
var buildmessage = require('./buildmessage.js');
var tropohouse = require('./tropohouse.js');
var files = require('./files.js');
var utils = require('./utils.js');
var catalog = require('./catalog.js');
var PackageSource = require('./package-source.js');
var VersionParser = require('./package-version-parser.js');

// LocalCatalog represents packages located in the application's
// package directory, other package directories specified via an
// environment variable, and core packages in the repo if meteor is
// being run from a git checkout.
var LocalCatalog = function (options) {
  var self = this;
  options = options || {};

  // Package server data.  Maps package name to a {packageSource, packageRecord,
  // versionRecord} object.
  self.packages = {};

  // We use the initialization design pattern because it makes it easier to use
  // both of our catalogs as singletons.
  self.initialized = false;
  self.containingCatalog = options.containingCatalog || self;

    // Local directories to search for package source trees
  self.localPackageSearchDirs = null;

  // Packagedirs specified by addLocalPackage: added explicitly through a
  // directory. We mainly use this to allow the user to run test-packages
  // against a package in a specific directory.
  self.explicitlyAddedLocalPackageDirs = [];

  // All packages found either by localPackageSearchDirs or
  // explicitlyAddedLocalPackageDirs. There is a hierarchy of packages, as
  // detailed below and there can only be one local version of a package at a
  // time. This refers to the package by the specific package directory that we
  // need to process.
  self.effectiveLocalPackageDirs = [];

  self.buildRequested = null;

  self.nextVersionId = 1;
};

_.extend(LocalCatalog.prototype, {
  toString: function () {
    var self = this;
    return "LocalCatalog [localPackageSearchDirs="
      + self.localPackageSearchDirs + "]";
  },

  // Initialize the Catalog. This must be called before any other
  // Catalog function.

  // options:
  //  - localPackageSearchDirs: an array of paths on local disk, that contain
  //    subdirectories, that each contain a source tree for a package that
  //    should override the packages on the package server. For example, if
  //    there is a package 'foo' that we find through localPackageSearchDirs,
  //    then we will ignore all versions of 'foo' that we find through the
  //    package server. Directories that don't exist (or paths that aren't
  //    directories) will be silently ignored.
  initialize: function (options) {
    var self = this;
    buildmessage.assertInCapture();

    options = options || {};

    // At this point, effectiveLocalPackageDirs is just the local package
    // directories, since we haven't had a chance to add any other local
    // packages. Nonetheless, let's set those.
    self.localPackageSearchDirs = [];
    _.each(options.localPackageSearchDirs, function (dir) {
      dir = path.resolve(dir);
      if (utils.isDirectory(dir))
        self.localPackageSearchDirs.push(dir);
    });

    self.refresh();
  },

  // Set all the collections to their initial values, which are mostly
  // blank. This does not set self.initialized -- do that manually in the child
  // class when applicable.
  reset: function () {
    var self = this;

    // Initialize everything to its default version.
    self.packages = {};

    self.buildRequested = {};
  },

  // Throw if the catalog's self.initialized value has not been set to true.
  _requireInitialized: function () {
    var self = this;

    if (! self.initialized)
      throw new Error("catalog not initialized yet?");
  },

  // Return an array with the names of all of the packages that we
  // know about, in no particular order.
  getAllPackageNames: function () {
    var self = this;
    self._requireInitialized();

    return _.keys(self.packages);
  },

  // Returns general (non-version-specific) information about a
  // package, or null if there is no such package.
  getPackage: function (name, options) {
    var self = this;
    self._requireInitialized();
    options = options || {};

    if (!_.has(self.packages, name))
      return null;
    return self.packages[name].packageRecord;
  },

  // Given a package, returns an array of the versions available (ie, the one
  // version we have, or an empty array).
  getSortedVersions: function (name) {
    var self = this;
    self._requireInitialized();

    if (!_.has(self.packages, name))
      return [];
    return [self.packages[name].versionRecord.version];
  },

  // Return information about a particular version of a package, or
  // null if there is no such package or version.
  getVersion: function (name, version) {
    var self = this;
    self._requireInitialized();

    if (!_.has(self.packages, name))
      return null;
    var versionRecord = self.packages[name].versionRecord;
    // The catalog doesn't understand buildID versions and doesn't know about
    // them. Depending on when we build them, we can refer to local packages as
    // 1.0.0+local or 1.0.0+[buildId]. Luckily, we know which packages are
    // local, so just look those up by their local version instead.
    version = self._changeBuildIdToLocal(version);
    if (versionRecord.version !== version)
      return null;
    return versionRecord;
  },

  // As getVersion, but returns info on the latest version of the
  // package, or null if the package doesn't exist or has no versions.
  getLatestVersion: function (name) {
    var self = this;

    if (!_.has(self.packages, name))
      return null;
    return self.packages[name].versionRecord;
  },

  // Refresh the packages in the catalog, by re-scanning local packages.
  //
  // options:
  // - watchSet: if provided, any files read in reloading packages will be added
  //   to this set.
  refresh: function (options) {
    var self = this;
    options = options || {};
    buildmessage.assertInCapture();

    self.reset();
    self._recomputeEffectiveLocalPackages();
    self._loadLocalPackages({ watchSet: options.watchSet });
    self.initialized = true;
  },

  // Compute self.effectiveLocalPackageDirs from self.localPackageSearchDirs and
  // self.explicitlyAddedLocalPackageDirs.
  _recomputeEffectiveLocalPackages: function () {
    var self = this;
    self.effectiveLocalPackageDirs = _.clone(
      self.explicitlyAddedLocalPackageDirs);

    _.each(self.localPackageSearchDirs, function (searchDir) {
      if (! utils.isDirectory(searchDir))
        return;
      var contents = fs.readdirSync(searchDir);
      _.each(contents, function (item) {
        var packageDir = path.join(searchDir, item);
        if (! utils.isDirectory(packageDir))
          return;

        // Consider a directory to be a package source tree if it contains
        // 'package.js'. (We used to support isopacks in localPackageSearchDirs,
        // but no longer.)
        if (fs.existsSync(path.join(packageDir, 'package.js'))) {
          // Let earlier package directories override later package
          // directories.

          // We don't know the name of the package, so we can't deal with
          // duplicates yet. We are going to have to rely on the fact that we
          // are putting these in in order, to be processed in order.
          self.effectiveLocalPackageDirs.push(packageDir);
        }
      });
    });
  },

  _loadLocalPackages: function (options) {
    var self = this;
    options = options || {};
    buildmessage.assertInCapture();

    // Load the package source from a directory. We don't know the names of our
    // local packages until we do this.
    //
    // THIS MUST BE RUN IN LOAD ORDER. Let's say that we have two directories
    // for mongo-livedata. The first one processed by this function will be
    // canonical.  The second one will be ignored.
    //
    // (note: this is the behavior that we want for overriding things in
    //  checkout.  It is not clear that you get good UX if you have two packages
    //  with the same name in your app. We don't check that.)
    var initSourceFromDir = function (packageDir, definiteName) {
      var packageSource = new PackageSource(self.containingCatalog);
      buildmessage.enterJob({
        title: "reading package from `" + packageDir + "`",
        rootPath: packageDir
      }, function () {
        // All packages in the catalog must have versions. Though, for local
        // packages without version, we can be kind and set it to
        // 0.0.0. Anything requiring any version above that will not be
        // compatible, which is fine.
        var opts = {
          requireVersion: true,
          defaultVersion: "0.0.0"
        };
        // If we specified a name, then we know what we want to get and should
        // pass that into the options. Otherwise, we will use the 'name'
        // attribute from package-source.js.
        if (definiteName) {
          opts["name"] = definiteName;
        }
        packageSource.initFromPackageDir(packageDir, opts);

        if (options.watchSet) {
          options.watchSet.merge(packageSource.pluginWatchSet);
          _.each(packageSource.architectures, function (sourceArch) {
            options.watchSet.merge(sourceArch.watchSet);
          });
        }

        // Recover by ignoring, but not until after we've augmented the watchSet
        // (since we want the watchSet to include files with problems that the
        // user may fix!)
        if (buildmessage.jobHasMessages()) {
          return;
        }

        // Now that we have initialized the package from package.js, we know its
        // name.
        var name = packageSource.name;

        // We should only have one package dir for each name; in this case, we
        // are going to take the first one we get (since we preserved the order
        // in which we loaded local package dirs when running this function.)
        if (_.has(self.packages, name))
          return;

        // Accurate version numbers are of supreme importance, because we use
        // version numbers (of build-time dependencies such as the coffeescript
        // plugin), together with source file hashes and the notion of a
        // repeatable build, to decide when a package build is out of date and
        // trigger a rebuild of the package.
        //
        // The package we have just loaded may declare its version to be 1.2.3,
        // but that doesn't mean it's really the official version 1.2.3 of the
        // package. It only gets that version number officially when it's
        // published to the package server. So what we'd like to do here is give
        // it a version number like '1.2.3+<buildid>', where <buildid> is a hash
        // of everything that's necessary to repeat the build exactly: all of
        // the package's source files, all of the package's build-time
        // dependencies, and the version of the Meteor build tool used to build
        // it.
        //
        // Unfortunately we can't actually compute such a buildid yet since it
        // depends on knowing the build-time dependencies of the package, which
        // requires that we run the constraint solver, which can only be done
        // once we've populated the catalog, which is what we're trying to do
        // right now.
        //
        // So we have a workaround. For local packages we will fake the version
        // in the catalog by setting the buildid to 'local', as in
        // '1.2.3+local'. This is enough for the constraint solver to run, but
        // any code that actually relies on accurate versions (for example, code
        // that checks if a build is up to date) needs to be careful to get the
        // versions not from the catalog but from the actual built Isopack
        // objects, which will have accurate versions (with precise buildids)
        // even for local packages.
        var version = packageSource.version;
        if (version.indexOf('+') !== -1)
          throw new Error("version already has a buildid?");
        version = version + "+local";

        self.packages[name] = {
          packageSource: packageSource,
          packageRecord: {
            name: name,
            maintainers: null,
            lastUpdated: null
          },
          versionRecord: {
            _id: "VID" + self.nextVersionId++,
            packageName: name,
            testName: packageSource.testName,
            version: version,
            publishedBy: null,
            description: packageSource.metadata.summary,
            dependencies: packageSource.getDependencyMetadata(),
            source: null,
            lastUpdated: null,
            published: null,
            isTest: packageSource.isTest,
            debugOnly: packageSource.debugOnly,
            containsPlugins: packageSource.containsPlugins()
          }
        };

        // If this is NOT a test package AND it has tests (tests will be
        // marked as test packages by package source, so we will not recurse
        // infinitely), then process that too.
        if (!packageSource.isTest && packageSource.testName) {
          initSourceFromDir(packageSource.sourceRoot, packageSource.testName);
        }
      });
    };

    // Load the package sources for packages and their tests into
    // self.packages.
    //
    // XXX We should make this work with parallel: true; right now it seems to
    // hit node problems.
    buildmessage.forkJoin(
      { 'title': 'Initializing packages', parallel: false },
      self.effectiveLocalPackageDirs,
      function (dir) {
        initSourceFromDir(dir);
      });
  },

  // Register local package directories with a watchSet. We want to know if a
  // package is created or deleted, which includes both its top-level source
  // directory and its main package metadata file.
  //
  // This will watch the local package directories that are in effect when the
  // function is called.  (As set by the most recent call to
  // setLocalPackageDirs.)
  watchLocalPackageDirs: function (watchSet) {
    var self = this;
    self._requireInitialized();

    _.each(self.localPackageSearchDirs, function (packageDir) {
      var packages = watch.readAndWatchDirectory(watchSet, {
        absPath: packageDir,
        include: [/\/$/]
      });
      _.each(packages, function (p) {
        watch.readAndWatchFile(watchSet,
                               path.join(packageDir, p, 'package.js'));
      });
    });
  },

  // True if `name` is a local package (is to be loaded via
  // localPackageSearchDirs or addLocalPackage rather than from the package
  // server)
  isLocalPackage: function (name) {
    var self = this;
    self._requireInitialized();

    return _.has(self.packages, name);
  },

  // Add a local package to the catalog. `name` is the name to use for
  // the package and `directory` is the directory that contains the
  // source tree for the package.
  //
  // If a package named `name` exists on the package server, it will
  // be overridden (it will be as if that package doesn't exist on the
  // package server at all). And for now, it's an error to call this
  // function twice with the same `name`.
  addLocalPackage: function (directory) {
    var self = this;
    buildmessage.assertInCapture();
    self._requireInitialized();

    var resolvedPath = path.resolve(directory);
    self.explicitlyAddedLocalPackageDirs.push(resolvedPath);

    // If we were making lots of calls to addLocalPackage, we would
    // want to coalesce the calls to refresh somehow, but I don't
    // think we'll actually be doing that so this should be fine.
    // #CallingRefreshEveryTimeLocalPackagesChange
    self.refresh();
  },

  getPackageSource: function (name) {
    var self = this;
    if (! _.has(self.packages, name))
      return null;
    return self.packages[name].packageSource;
  },

  // Given a version string that may or may not have a build ID, convert it into
  // the catalog's internal format for local versions -- [version
  // number]+local. (for example, 1.0.0+local).
  _changeBuildIdToLocal: function (version) {
    if (version)
      return version.split("+")[0] + "+local";
    return version;
  }
});

exports.LocalCatalog = LocalCatalog;
<commit_msg>Stop fiddling with local package build IDs<commit_after>var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var packageClient = require('./package-client.js');
var watch = require('./watch.js');
var archinfo = require('./archinfo.js');
var isopack = require('./isopack.js');
var compiler = require('./compiler.js');
var buildmessage = require('./buildmessage.js');
var tropohouse = require('./tropohouse.js');
var files = require('./files.js');
var utils = require('./utils.js');
var catalog = require('./catalog.js');
var PackageSource = require('./package-source.js');
var VersionParser = require('./package-version-parser.js');

// LocalCatalog represents packages located in the application's
// package directory, other package directories specified via an
// environment variable, and core packages in the repo if meteor is
// being run from a git checkout.
var LocalCatalog = function (options) {
  var self = this;
  options = options || {};

  // Package server data.  Maps package name to a {packageSource, packageRecord,
  // versionRecord} object.
  self.packages = {};

  // We use the initialization design pattern because it makes it easier to use
  // both of our catalogs as singletons.
  self.initialized = false;
  self.containingCatalog = options.containingCatalog || self;

    // Local directories to search for package source trees
  self.localPackageSearchDirs = null;

  // Packagedirs specified by addLocalPackage: added explicitly through a
  // directory. We mainly use this to allow the user to run test-packages
  // against a package in a specific directory.
  self.explicitlyAddedLocalPackageDirs = [];

  // All packages found either by localPackageSearchDirs or
  // explicitlyAddedLocalPackageDirs. There is a hierarchy of packages, as
  // detailed below and there can only be one local version of a package at a
  // time. This refers to the package by the specific package directory that we
  // need to process.
  self.effectiveLocalPackageDirs = [];

  self.buildRequested = null;

  self.nextVersionId = 1;
};

_.extend(LocalCatalog.prototype, {
  toString: function () {
    var self = this;
    return "LocalCatalog [localPackageSearchDirs="
      + self.localPackageSearchDirs + "]";
  },

  // Initialize the Catalog. This must be called before any other
  // Catalog function.

  // options:
  //  - localPackageSearchDirs: an array of paths on local disk, that contain
  //    subdirectories, that each contain a source tree for a package that
  //    should override the packages on the package server. For example, if
  //    there is a package 'foo' that we find through localPackageSearchDirs,
  //    then we will ignore all versions of 'foo' that we find through the
  //    package server. Directories that don't exist (or paths that aren't
  //    directories) will be silently ignored.
  initialize: function (options) {
    var self = this;
    buildmessage.assertInCapture();

    options = options || {};

    // At this point, effectiveLocalPackageDirs is just the local package
    // directories, since we haven't had a chance to add any other local
    // packages. Nonetheless, let's set those.
    self.localPackageSearchDirs = [];
    _.each(options.localPackageSearchDirs, function (dir) {
      dir = path.resolve(dir);
      if (utils.isDirectory(dir))
        self.localPackageSearchDirs.push(dir);
    });

    self.refresh();
  },

  // Set all the collections to their initial values, which are mostly
  // blank. This does not set self.initialized -- do that manually in the child
  // class when applicable.
  reset: function () {
    var self = this;

    // Initialize everything to its default version.
    self.packages = {};

    self.buildRequested = {};
  },

  // Throw if the catalog's self.initialized value has not been set to true.
  _requireInitialized: function () {
    var self = this;

    if (! self.initialized)
      throw new Error("catalog not initialized yet?");
  },

  // Return an array with the names of all of the packages that we
  // know about, in no particular order.
  getAllPackageNames: function () {
    var self = this;
    self._requireInitialized();

    return _.keys(self.packages);
  },

  // Returns general (non-version-specific) information about a
  // package, or null if there is no such package.
  getPackage: function (name, options) {
    var self = this;
    self._requireInitialized();
    options = options || {};

    if (!_.has(self.packages, name))
      return null;
    return self.packages[name].packageRecord;
  },

  // Given a package, returns an array of the versions available (ie, the one
  // version we have, or an empty array).
  getSortedVersions: function (name) {
    var self = this;
    self._requireInitialized();

    if (!_.has(self.packages, name))
      return [];
    return [self.packages[name].versionRecord.version];
  },

  // Return information about a particular version of a package, or
  // null if there is no such package or version.
  getVersion: function (name, version) {
    var self = this;
    self._requireInitialized();

    if (!_.has(self.packages, name))
      return null;
    var versionRecord = self.packages[name].versionRecord;
    if (versionRecord.version !== version)
      return null;
    return versionRecord;
  },

  // As getVersion, but returns info on the latest version of the
  // package, or null if the package doesn't exist or has no versions.
  getLatestVersion: function (name) {
    var self = this;

    if (!_.has(self.packages, name))
      return null;
    return self.packages[name].versionRecord;
  },

  // Refresh the packages in the catalog, by re-scanning local packages.
  //
  // options:
  // - watchSet: if provided, any files read in reloading packages will be added
  //   to this set.
  refresh: function (options) {
    var self = this;
    options = options || {};
    buildmessage.assertInCapture();

    self.reset();
    self._recomputeEffectiveLocalPackages();
    self._loadLocalPackages({ watchSet: options.watchSet });
    self.initialized = true;
  },

  // Compute self.effectiveLocalPackageDirs from self.localPackageSearchDirs and
  // self.explicitlyAddedLocalPackageDirs.
  _recomputeEffectiveLocalPackages: function () {
    var self = this;
    self.effectiveLocalPackageDirs = _.clone(
      self.explicitlyAddedLocalPackageDirs);

    _.each(self.localPackageSearchDirs, function (searchDir) {
      if (! utils.isDirectory(searchDir))
        return;
      var contents = fs.readdirSync(searchDir);
      _.each(contents, function (item) {
        var packageDir = path.join(searchDir, item);
        if (! utils.isDirectory(packageDir))
          return;

        // Consider a directory to be a package source tree if it contains
        // 'package.js'. (We used to support isopacks in localPackageSearchDirs,
        // but no longer.)
        if (fs.existsSync(path.join(packageDir, 'package.js'))) {
          // Let earlier package directories override later package
          // directories.

          // We don't know the name of the package, so we can't deal with
          // duplicates yet. We are going to have to rely on the fact that we
          // are putting these in in order, to be processed in order.
          self.effectiveLocalPackageDirs.push(packageDir);
        }
      });
    });
  },

  _loadLocalPackages: function (options) {
    var self = this;
    options = options || {};
    buildmessage.assertInCapture();

    // Load the package source from a directory. We don't know the names of our
    // local packages until we do this.
    //
    // THIS MUST BE RUN IN LOAD ORDER. Let's say that we have two directories
    // for mongo-livedata. The first one processed by this function will be
    // canonical.  The second one will be ignored.
    //
    // (note: this is the behavior that we want for overriding things in
    //  checkout.  It is not clear that you get good UX if you have two packages
    //  with the same name in your app. We don't check that.)
    var initSourceFromDir = function (packageDir, definiteName) {
      var packageSource = new PackageSource(self.containingCatalog);
      buildmessage.enterJob({
        title: "reading package from `" + packageDir + "`",
        rootPath: packageDir
      }, function () {
        // All packages in the catalog must have versions. Though, for local
        // packages without version, we can be kind and set it to
        // 0.0.0. Anything requiring any version above that will not be
        // compatible, which is fine.
        var opts = {
          requireVersion: true,
          defaultVersion: "0.0.0"
        };
        // If we specified a name, then we know what we want to get and should
        // pass that into the options. Otherwise, we will use the 'name'
        // attribute from package-source.js.
        if (definiteName) {
          opts["name"] = definiteName;
        }
        packageSource.initFromPackageDir(packageDir, opts);

        if (options.watchSet) {
          options.watchSet.merge(packageSource.pluginWatchSet);
          _.each(packageSource.architectures, function (sourceArch) {
            options.watchSet.merge(sourceArch.watchSet);
          });
        }

        // Recover by ignoring, but not until after we've augmented the watchSet
        // (since we want the watchSet to include files with problems that the
        // user may fix!)
        if (buildmessage.jobHasMessages()) {
          return;
        }

        // Now that we have initialized the package from package.js, we know its
        // name.
        var name = packageSource.name;

        // We should only have one package dir for each name; in this case, we
        // are going to take the first one we get (since we preserved the order
        // in which we loaded local package dirs when running this function.)
        if (_.has(self.packages, name))
          return;

        self.packages[name] = {
          packageSource: packageSource,
          packageRecord: {
            name: name,
            maintainers: null,
            lastUpdated: null
          },
          versionRecord: {
            _id: "VID" + self.nextVersionId++,
            packageName: name,
            testName: packageSource.testName,
            version: packageSource.version,
            publishedBy: null,
            description: packageSource.metadata.summary,
            dependencies: packageSource.getDependencyMetadata(),
            source: null,
            lastUpdated: null,
            published: null,
            isTest: packageSource.isTest,
            debugOnly: packageSource.debugOnly,
            containsPlugins: packageSource.containsPlugins()
          }
        };

        // If this is NOT a test package AND it has tests (tests will be
        // marked as test packages by package source, so we will not recurse
        // infinitely), then process that too.
        if (!packageSource.isTest && packageSource.testName) {
          initSourceFromDir(packageSource.sourceRoot, packageSource.testName);
        }
      });
    };

    // Load the package sources for packages and their tests into
    // self.packages.
    //
    // XXX We should make this work with parallel: true; right now it seems to
    // hit node problems.
    buildmessage.forkJoin(
      { 'title': 'Initializing packages', parallel: false },
      self.effectiveLocalPackageDirs,
      function (dir) {
        initSourceFromDir(dir);
      });
  },

  // Register local package directories with a watchSet. We want to know if a
  // package is created or deleted, which includes both its top-level source
  // directory and its main package metadata file.
  //
  // This will watch the local package directories that are in effect when the
  // function is called.  (As set by the most recent call to
  // setLocalPackageDirs.)
  watchLocalPackageDirs: function (watchSet) {
    var self = this;
    self._requireInitialized();

    _.each(self.localPackageSearchDirs, function (packageDir) {
      var packages = watch.readAndWatchDirectory(watchSet, {
        absPath: packageDir,
        include: [/\/$/]
      });
      _.each(packages, function (p) {
        watch.readAndWatchFile(watchSet,
                               path.join(packageDir, p, 'package.js'));
      });
    });
  },

  // True if `name` is a local package (is to be loaded via
  // localPackageSearchDirs or addLocalPackage rather than from the package
  // server)
  isLocalPackage: function (name) {
    var self = this;
    self._requireInitialized();

    return _.has(self.packages, name);
  },

  // Add a local package to the catalog. `name` is the name to use for
  // the package and `directory` is the directory that contains the
  // source tree for the package.
  //
  // If a package named `name` exists on the package server, it will
  // be overridden (it will be as if that package doesn't exist on the
  // package server at all). And for now, it's an error to call this
  // function twice with the same `name`.
  addLocalPackage: function (directory) {
    var self = this;
    buildmessage.assertInCapture();
    self._requireInitialized();

    var resolvedPath = path.resolve(directory);
    self.explicitlyAddedLocalPackageDirs.push(resolvedPath);

    // If we were making lots of calls to addLocalPackage, we would
    // want to coalesce the calls to refresh somehow, but I don't
    // think we'll actually be doing that so this should be fine.
    // #CallingRefreshEveryTimeLocalPackagesChange
    self.refresh();
  },

  getPackageSource: function (name) {
    var self = this;
    if (! _.has(self.packages, name))
      return null;
    return self.packages[name].packageSource;
  }
});

exports.LocalCatalog = LocalCatalog;
<|endoftext|>


<commit_before>// import TextEncoderShim from 'text-encoding-shim';

const sizeOf = {
  int: 4,
  MYFLT: 4,
  char: 1,
};

export const decoder = new TextDecoder("utf-8");
export const encoder = new TextEncoder("utf-8");

export const uint2String = (uint) => decoder.decode(uint);

export const trimNull = (a) => {
  const c = a.indexOf("\0");
  if (c > -1) {
    // eslint-disable-next-line unicorn/prefer-string-slice
    return a.substr(0, c);
  }
  return a;
};

// eslint-disable-next-line no-unused-vars
export const cleanStdout = (stdout) => {
  const pattern = [
    "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
    "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
  ].join("|");
  const regexPattern = new RegExp(pattern, "g");
  return stdout.replace(regexPattern, "");
};

export const string2ptr = (wasm, string) => {
  if (typeof string !== "string") {
    console.error("Expected string but got", typeof string);
    return;
  }

  const { buffer } = wasm.exports.memory;
  const stringBuf = encoder.encode(string);
  const offset = wasm.exports.allocStringMem(stringBuf.length);
  const outBuf = new Uint8Array(buffer, offset, stringBuf.length + 1);
  outBuf.set(stringBuf);
  return offset;
};

export const ptr2string = (wasm, stringPtr) => {

  const { buffer } = wasm.exports.memory;
  const buf = new Uint8Array(buffer, stringPtr);
  const res = decoder.decode(buf);
  return res;
};

export const sizeofStruct = (jsStruct) => {
  const result = jsStruct.reduce((total, [_, primitive, ...rest]) => {
    if (primitive === "char") {
      return (total += sizeOf[primitive] * rest[0]);
    } else {
      return (total += sizeOf[primitive]);
    }
  }, 0);
  return result;
};

export const freeStringPtr = (wasm, ptr) => {
  wasm.exports.freeStringMem(ptr);
};

export const structBuffer2Object = (jsStruct, buffer) => {
  const [result] = jsStruct.reduce(
    ([parameters, offset], [parameterName, primitive, ...rest]) => {
      const currentSize = primitive === "char" ? sizeOf[primitive] * rest[0] : sizeOf[primitive];
      const currentValue =
        primitive === "char"
          ? trimNull(uint2String(buffer.subarray(offset, currentSize))) || ""
          : buffer[offset];
      parameters[parameterName] = currentValue;
      return [parameters, offset + currentSize];
    },
    [{}, 0],
  );
  return result;
};

export const nearestPowerOf2 = (n) => {
  return 1 << (31 - Math.clz32(n));
};

export const isIos = () => /iPhone|iPad|iPod/.test(navigator.userAgent);

const isFirefox = () => navigator.userAgent.toLowerCase().includes("firefox");

export const isSabSupported = () =>
  !isFirefox() &&
  typeof window.Atomics !== "undefined" &&
  typeof window.SharedArrayBuffer !== "undefined";

export const areWorkletsSupported = () =>
  typeof AudioNode !== "undefined" && typeof AudioWorkletNode !== "undefined";

export const WebkitAudioContext = () => {
  if (typeof window.webkitAudioContext !== "undefined") {
    return window.webkitAudioContext;
  } else if (typeof window.AudioContext !== "undefined") {
    return window.AudioContext;
  }
};

export const isScriptProcessorNodeSupported = () => {
  const audioContext = WebkitAudioContext();
  return (
    typeof audioContext !== "undefined" &&
    typeof audioContext.prototype.createScriptProcessor !== "undefined"
  );
};

export const csoundApiRename = (apiName) => {
  const minusCsound = apiName.replace(/^csound/i, "");
  return minusCsound.charAt(0).toLowerCase() + minusCsound.substring(1);
};

export const makeProxyCallback = (proxyPort, csoundInstance, apiK) => async (...arguments_) => {
  return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};

export const makeSingleThreadCallback = (csoundInstance, apiCallback) => async (...arguments_) => {
  return await apiCallback.apply({}, [csoundInstance, ...arguments_]);
  // return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};

export const stopableStates = new Set([
  "realtimePerformanceStarted",
  "realtimePerformancePaused",
  "realtimePerformanceResumed",
  "renderStarted",
]);
<commit_msg>fix issue with memory growth after calling allocStringMem by moving when buffer is referenced<commit_after>// import TextEncoderShim from 'text-encoding-shim';

const sizeOf = {
  int: 4,
  MYFLT: 4,
  char: 1,
};

export const decoder = new TextDecoder("utf-8");
export const encoder = new TextEncoder("utf-8");

export const uint2String = (uint) => decoder.decode(uint);

export const trimNull = (a) => {
  const c = a.indexOf("\0");
  if (c > -1) {
    // eslint-disable-next-line unicorn/prefer-string-slice
    return a.substr(0, c);
  }
  return a;
};

// eslint-disable-next-line no-unused-vars
export const cleanStdout = (stdout) => {
  const pattern = [
    "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
    "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
  ].join("|");
  const regexPattern = new RegExp(pattern, "g");
  return stdout.replace(regexPattern, "");
};

export const string2ptr = (wasm, string) => {
  if (typeof string !== "string") {
    console.error("Expected string but got", typeof string);
    return;
  }

  const stringBuf = encoder.encode(string);
  const offset = wasm.exports.allocStringMem(stringBuf.length);
  const { buffer } = wasm.exports.memory;
  const outBuf = new Uint8Array(buffer, offset, stringBuf.length + 1);
  outBuf.set(stringBuf);
  return offset;
};

export const ptr2string = (wasm, stringPtr) => {

  const { buffer } = wasm.exports.memory;
  const buf = new Uint8Array(buffer, stringPtr);
  const res = decoder.decode(buf);
  return res;
};

export const sizeofStruct = (jsStruct) => {
  const result = jsStruct.reduce((total, [_, primitive, ...rest]) => {
    if (primitive === "char") {
      return (total += sizeOf[primitive] * rest[0]);
    } else {
      return (total += sizeOf[primitive]);
    }
  }, 0);
  return result;
};

export const freeStringPtr = (wasm, ptr) => {
  wasm.exports.freeStringMem(ptr);
};

export const structBuffer2Object = (jsStruct, buffer) => {
  const [result] = jsStruct.reduce(
    ([parameters, offset], [parameterName, primitive, ...rest]) => {
      const currentSize = primitive === "char" ? sizeOf[primitive] * rest[0] : sizeOf[primitive];
      const currentValue =
        primitive === "char"
          ? trimNull(uint2String(buffer.subarray(offset, currentSize))) || ""
          : buffer[offset];
      parameters[parameterName] = currentValue;
      return [parameters, offset + currentSize];
    },
    [{}, 0],
  );
  return result;
};

export const nearestPowerOf2 = (n) => {
  return 1 << (31 - Math.clz32(n));
};

export const isIos = () => /iPhone|iPad|iPod/.test(navigator.userAgent);

const isFirefox = () => navigator.userAgent.toLowerCase().includes("firefox");

export const isSabSupported = () =>
  !isFirefox() &&
  typeof window.Atomics !== "undefined" &&
  typeof window.SharedArrayBuffer !== "undefined";

export const areWorkletsSupported = () =>
  typeof AudioNode !== "undefined" && typeof AudioWorkletNode !== "undefined";

export const WebkitAudioContext = () => {
  if (typeof window.webkitAudioContext !== "undefined") {
    return window.webkitAudioContext;
  } else if (typeof window.AudioContext !== "undefined") {
    return window.AudioContext;
  }
};

export const isScriptProcessorNodeSupported = () => {
  const audioContext = WebkitAudioContext();
  return (
    typeof audioContext !== "undefined" &&
    typeof audioContext.prototype.createScriptProcessor !== "undefined"
  );
};

export const csoundApiRename = (apiName) => {
  const minusCsound = apiName.replace(/^csound/i, "");
  return minusCsound.charAt(0).toLowerCase() + minusCsound.substring(1);
};

export const makeProxyCallback = (proxyPort, csoundInstance, apiK) => async (...arguments_) => {
  return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};

export const makeSingleThreadCallback = (csoundInstance, apiCallback) => async (...arguments_) => {
  return await apiCallback.apply({}, [csoundInstance, ...arguments_]);
  // return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};

export const stopableStates = new Set([
  "realtimePerformanceStarted",
  "realtimePerformancePaused",
  "realtimePerformanceResumed",
  "renderStarted",
]);
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import currency from 'currency.js';

export const selectPrescriptionSubTotal = ({ payment }) => {
  const { transaction } = payment;
  const { items = [] } = transaction || {};
  const total = items.reduce((acc, { totalPrice }) => currency(totalPrice || 0).add(acc), 0);
  return total;
};

export const selectPrescriptionTotal = ({ payment }) => {
  const { policy } = payment;
  console.log(!!policy);
  const subtotal = selectPrescriptionSubTotal({ payment });

  return currency(subtotal * (policy ? (policy.discountRate || 100) / 100 : 1));
};

export const selectCreditBeingUsed = ({ payment }) => {
  const { paymentAmount } = payment;

  const prescriptionTotal = selectPrescriptionTotal({ payment });

  const creditBeingUsed = Math.max(prescriptionTotal.subtract(paymentAmount).value, 0);

  return currency(creditBeingUsed);
};
<commit_msg>Add removal of console.log<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import currency from 'currency.js';

export const selectPrescriptionSubTotal = ({ payment }) => {
  const { transaction } = payment;
  const { items = [] } = transaction || {};
  const total = items.reduce((acc, { totalPrice }) => currency(totalPrice || 0).add(acc), 0);
  return total;
};

export const selectPrescriptionTotal = ({ payment }) => {
  const { policy } = payment;
  const subtotal = selectPrescriptionSubTotal({ payment });

  return currency(subtotal * (policy ? (policy.discountRate || 100) / 100 : 1));
};

export const selectCreditBeingUsed = ({ payment }) => {
  const { paymentAmount } = payment;

  const prescriptionTotal = selectPrescriptionTotal({ payment });

  const creditBeingUsed = Math.max(prescriptionTotal.subtract(paymentAmount).value, 0);

  return currency(creditBeingUsed);
};
<|endoftext|>


<commit_before>/*
 * jQuery UI Effects Scale @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Scale
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.effect.puff = function( o ) {
	return this.queue( function() {
		var elem = $( this ),
			mode = $.effects.setMode( elem, o.mode || 'hide' ),
			percent = parseInt( o.percent, 10 ) || 150,
			factor = percent / 100,
			original = {
				height: elem.height(),
				width: elem.width()
			};

		$.extend(o, {
			effect: 'scale',
			queue: false,
			fade: true,
			mode: mode,
			percent: mode == 'hide' ? percent : 100,
			from: mode == 'hide'
				? original
				: {
					height: original.height * factor,
					width: original.width * factor
				}
		});

		elem.effect( o );
	});
};

$.effects.effect.scale = function( o ) {

	return this[ o.queue === false ? "each" : "queue" ]( function() {

		// Create element
		var el = $( this ),
			options = $.extend( true, {}, o ),
			mode = $.effects.setMode( el, o.mode || 'effect' ),
			percent = parseInt( o.percent, 10 ) || ( parseInt( o.percent, 10 ) == 0 ? 0 : ( mode == 'hide' ? 0 : 100 ) ),
			direction = o.direction || 'both',
			origin = o.origin,
			original = {
				height: el.height(),
				width: el.width(),
				outerHeight: el.outerHeight(),
				outerWidth: el.outerWidth()
			},
			factor = {
				y: direction != 'horizontal' ? (percent / 100) : 1,
				x: direction != 'vertical' ? (percent / 100) : 1
			};

		// We are going to pass this effect to the size effect:
		options.effect = "size";
		options.queue = false;

		// Set default origin and restore for show/hide
		if ( mode != 'effect' ) {
			options.origin = origin || ['middle','center'];
			options.restore = true;
		}

		options.from = o.from || ( mode == 'show' ? { height: 0, width: 0 } : original );
		options.to = {
			height: original.height * factor.y,
			width: original.width * factor.x,
			outerHeight: original.outerHeight * factor.y,
			outerWidth: original.outerWidth * factor.x
		};

		if ( options.fade ) { // Fade option to support puff
			if ( mode == 'show' ) {
				options.from.opacity = 0;
				options.to.opacity = 1;
			}
			if ( mode == 'hide' ) {
				options.from.opacity = 1;
				options.to.opacity = 0;
			}
		};

		// Animate
		el.effect(options);
	});

};

$.effects.effect.size = function( o ) {

	return this[ o.queue === false ? "each" : "queue" ]( function() {
		// Create element
		var el = $( this ),
			props = [ 'position', 'top', 'bottom', 'left', 'right', 'width', 'height', 'overflow', 'opacity' ],

			// Always restore
			props1 = [ 'position', 'top', 'bottom', 'left', 'right', 'overflow', 'opacity' ],

			// Copy for children
			props2 = [ 'width', 'height', 'overflow' ],
			cProps = [ 'fontSize' ],
			vProps = [ 'borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom' ],
			hProps = [ 'borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight' ],

			// Set options
			mode = $.effects.setMode( el, o.mode || 'effect' ),
			restore = o.restore || mode !== "effect",
			scale = o.scale || 'both',
			origin = o.origin,
			original, baseline, factor;

		if ( mode === "show" ) {
			el.show();
		}
		original = {
			height: el.height(),
			width: el.width(),
			outerHeight: el.outerHeight(),
			outerWidth: el.outerWidth()
		};

		el.from = o.from || original;
		el.to = o.to || original;

		// Set scaling factor
		factor = {
			from: {
				y: el.from.height / original.height,
				x: el.from.width / original.width
			},
			to: {
				y: el.to.height / original.height,
				x: el.to.width / original.width
			}
		};

		// Scale the css box
		if ( scale == 'box' || scale == 'both' ) {

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				props = props.concat( vProps );
				el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
				el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
			};

			// Horizontal props scaling
			if ( factor.from.x !== factor.to.x ) {
				props = props.concat( hProps );
				el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
				el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
			};
		};

		// Scale the content
		if ( scale == 'content' || scale == 'both' ) {

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				props = props.concat( cProps );
				el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
				el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
			};
		};

		$.effects.save( el, restore ? props : props1 );
		el.show();
		$.effects.createWrapper( el );
		el.css( 'overflow', 'hidden' ).css( el.from );

		// Adjust
		if (origin) { // Calculate baseline shifts
			baseline = $.effects.getBaseline( origin, original );
			el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
			el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
			el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
			el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
		}
		el.css( el.from ); // set top & left

		// Animate
		if ( scale == 'content' || scale == 'both' ) { // Scale the children

			// Add margins/font-size
			vProps = vProps.concat([ 'marginTop', 'marginBottom' ]).concat(cProps);
			hProps = hProps.concat([ 'marginLeft', 'marginRight' ]);
			props2 = props.concat(vProps).concat(hProps);

			el.find( "*[width]" ).each( function(){
				var child = $( this ),
					c_original = {
						height: child.height(),
						width: child.width()
					};
				if (restore) $.effects.save(child, props2);

				child.from = {
					height: c_original.height * factor.from.y,
					width: c_original.width * factor.from.x
				};
				child.to = {
					height: c_original.height * factor.to.y,
					width: c_original.width * factor.to.x
				};

				// Vertical props scaling
				if ( factor.from.y != factor.to.y ) {
					child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
					child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
				};

				// Horizontal props scaling
				if ( factor.from.x != factor.to.x ) {
					child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
					child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
				};

				// Animate children
				child.css( child.from );
				child.animate( child.to, o.duration, o.easing, function() {

					// Restore children
					if (restore) $.effects.restore( child, props2 );
				});
			});
		};

		// Animate
		el.animate( el.to, {
			queue: false,
			duration: o.duration,
			easing: o.easing,
			complete: function() {
				if ( el.to.opacity === 0 ) {
					el.css( 'opacity', el.from.opacity );
				}
				if( mode == 'hide' ) {
					el.hide();
				}
				$.effects.restore( el, restore ? props : props1 );
				$.effects.removeWrapper( el );
				$.isFunction( o.complete ) && o.complete.apply( this, arguments ); // Callback
				el.dequeue();
			}
		});

	});

};

})(jQuery);
<commit_msg>Effects.scale: Update the position of the element post animation to avoid jumping - Fixed #4316 - Element jumps to wrong position after scale effect with origin: ['middle','center'] parameter<commit_after>/*
 * jQuery UI Effects Scale @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Scale
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.effect.puff = function( o ) {
	return this.queue( function() {
		var elem = $( this ),
			mode = $.effects.setMode( elem, o.mode || 'hide' ),
			percent = parseInt( o.percent, 10 ) || 150,
			factor = percent / 100,
			original = {
				height: elem.height(),
				width: elem.width()
			};

		$.extend(o, {
			effect: 'scale',
			queue: false,
			fade: true,
			mode: mode,
			percent: mode == 'hide' ? percent : 100,
			from: mode == 'hide'
				? original
				: {
					height: original.height * factor,
					width: original.width * factor
				}
		});

		elem.effect( o );
	});
};

$.effects.effect.scale = function( o ) {

	return this[ o.queue === false ? "each" : "queue" ]( function() {

		// Create element
		var el = $( this ),
			options = $.extend( true, {}, o ),
			mode = $.effects.setMode( el, o.mode || 'effect' ),
			percent = parseInt( o.percent, 10 ) || ( parseInt( o.percent, 10 ) == 0 ? 0 : ( mode == 'hide' ? 0 : 100 ) ),
			direction = o.direction || 'both',
			origin = o.origin,
			original = {
				height: el.height(),
				width: el.width(),
				outerHeight: el.outerHeight(),
				outerWidth: el.outerWidth()
			},
			factor = {
				y: direction != 'horizontal' ? (percent / 100) : 1,
				x: direction != 'vertical' ? (percent / 100) : 1
			};

		// We are going to pass this effect to the size effect:
		options.effect = "size";
		options.queue = false;

		// Set default origin and restore for show/hide
		if ( mode != 'effect' ) {
			options.origin = origin || ['middle','center'];
			options.restore = true;
		}

		options.from = o.from || ( mode == 'show' ? { height: 0, width: 0 } : original );
		options.to = {
			height: original.height * factor.y,
			width: original.width * factor.x,
			outerHeight: original.outerHeight * factor.y,
			outerWidth: original.outerWidth * factor.x
		};

		if ( options.fade ) { // Fade option to support puff
			if ( mode == 'show' ) {
				options.from.opacity = 0;
				options.to.opacity = 1;
			}
			if ( mode == 'hide' ) {
				options.from.opacity = 1;
				options.to.opacity = 0;
			}
		};

		// Animate
		el.effect(options);
	});

};

$.effects.effect.size = function( o ) {

	return this[ o.queue === false ? "each" : "queue" ]( function() {
		// Create element
		var el = $( this ),
			props = [ 'position', 'top', 'bottom', 'left', 'right', 'width', 'height', 'overflow', 'opacity' ],

			// Always restore
			props1 = [ 'position', 'top', 'bottom', 'left', 'right', 'overflow', 'opacity' ],

			// Copy for children
			props2 = [ 'width', 'height', 'overflow' ],
			cProps = [ 'fontSize' ],
			vProps = [ 'borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom' ],
			hProps = [ 'borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight' ],

			// Set options
			mode = $.effects.setMode( el, o.mode || 'effect' ),
			restore = o.restore || mode !== "effect",
			scale = o.scale || 'both',
			origin = o.origin || [ "middle", "center" ],
			original, baseline, factor,
			position = el.css( "position" ),
			originalVerticalPositioning = el.css( "bottom" ) !== "auto" ? "bottom" : "top";
			originalHorizontalPositioning = el.css( "right" ) !== "auto" ? "right" : "left";

		if ( mode === "show" ) {
			el.show();
		}
		original = {
			height: el.height(),
			width: el.width(),
			outerHeight: el.outerHeight(),
			outerWidth: el.outerWidth()
		};

		el.from = o.from || original;
		el.to = o.to || original;

		// Set scaling factor
		factor = {
			from: {
				y: el.from.height / original.height,
				x: el.from.width / original.width
			},
			to: {
				y: el.to.height / original.height,
				x: el.to.width / original.width
			}
		};

		// Scale the css box
		if ( scale == 'box' || scale == 'both' ) {

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				props = props.concat( vProps );
				el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
				el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
			};

			// Horizontal props scaling
			if ( factor.from.x !== factor.to.x ) {
				props = props.concat( hProps );
				el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
				el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
			};
		};

		// Scale the content
		if ( scale == 'content' || scale == 'both' ) {

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				props = props.concat( cProps );
				el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
				el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
			};
		};

		$.effects.save( el, restore ? props : props1 );
		el.show();
		$.effects.createWrapper( el );
		el.css( 'overflow', 'hidden' ).css( el.from );

		// Adjust
		if (origin) { // Calculate baseline shifts
			baseline = $.effects.getBaseline( origin, original );
			el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
			el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
			el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
			el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
		}
		el.css( el.from ); // set top & left

		// Animate
		if ( scale == 'content' || scale == 'both' ) { // Scale the children

			// Add margins/font-size
			vProps = vProps.concat([ 'marginTop', 'marginBottom' ]).concat(cProps);
			hProps = hProps.concat([ 'marginLeft', 'marginRight' ]);
			props2 = props.concat(vProps).concat(hProps);

			el.find( "*[width]" ).each( function(){
				var child = $( this ),
					c_original = {
						height: child.height(),
						width: child.width()
					};
				if (restore) $.effects.save(child, props2);

				child.from = {
					height: c_original.height * factor.from.y,
					width: c_original.width * factor.from.x
				};
				child.to = {
					height: c_original.height * factor.to.y,
					width: c_original.width * factor.to.x
				};

				// Vertical props scaling
				if ( factor.from.y != factor.to.y ) {
					child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
					child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
				};

				// Horizontal props scaling
				if ( factor.from.x != factor.to.x ) {
					child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
					child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
				};

				// Animate children
				child.css( child.from );
				child.animate( child.to, o.duration, o.easing, function() {

					// Restore children
					if (restore) $.effects.restore( child, props2 );
				});
			});
		};

		// Animate
		el.animate( el.to, {
			queue: false,
			duration: o.duration,
			easing: o.easing,
			complete: function() {
				if ( el.to.opacity === 0 ) {
					el.css( 'opacity', el.from.opacity );
				}
				if( mode == 'hide' ) {
					el.hide();
				}
				$.effects.restore( el, restore ? props : props1 );

				// we need to recalculate our positioning based on the new scaling
				if ( position === "static" ) {
					el.css({
						position: "relative",
						top: el.to.top,
						left: el.to.left
					});
				} else {
					$.each([ originalVerticalPositioning, originalHorizontalPositioning ], function( idx, pos ) {
						el.css( pos, function( _, str ) {
							var val = parseInt( str, 10 ),
								toRef = idx ? el.to.left : el.to.top,
								delta = idx ? el.to.outerWidth - el.from.outerWidth: el.to.outerHeight - el.from.outerHeight,
								same = origin[ idx ] === pos,
								mid = origin[ idx ] === "middle" || origin[ idx ] === "center",
								direction = pos == "left" || pos == "top";

							// if original was "auto", recalculate the new value from wrapper
							if ( str === "auto" ) {
								return toRef + "px";
							}

							// if not setting left or top
							if ( !direction ) {

								// if the position is relative, bottom/right are reversed meaning
								if ( position === "relative" ) {
									toRef *= -1;

								// otherwise, if its NOT a midpoint origin, compensate for the outerWidth difference
								} else if ( !mid ) {
									toRef -= delta * ( same ? -1 : 1 );
								}
							}
							return val + toRef + "px";
						});
					});
				}

				$.effects.removeWrapper( el );
				$.isFunction( o.complete ) && o.complete.apply( this, arguments ); // Callback
				el.dequeue();
			}
		});

	});

};

})(jQuery);
<|endoftext|>


<commit_before>"use strict";
let fetch = require('node-fetch');
let Converter = require("csvtojson");
let Promise = require('bluebird');
let _ = require("lodash");
let tr = require('transliteration').transliterate;
let readFile = Promise.promisify(require('fs').readFile);
let writeFile = Promise.promisify(require('fs').writeFile);
let remoteCSVtoJSON = require("./remote-csv-to-json");

const input = {
    judgesPerRegionCSVLinksArray: "./input/all-ukraine-judges-csv-links.json",
    cachedJudges: "./input/all-ukraine-judges.json",
    textsCSV: "https://docs.google.com/spreadsheets/d/1SDFmxJEo3Al4-dTS4PkA_E88bH40keZFfIcoT2mVOO4/pub?gid=0&single=true&output=csv"
};
const output = {
    judges: "../source/judges.json",
    dictionary: "../source/dictionary.json",
    texts: "../source/texts.json"
};
const judgeModel = require("./model/judge");

(function run() {
    Promise.all([
            getJudgesSource()
                .then(filterEmptyLines)
                .then(normalizeNames)
                .then(checkDuplicates)
                .then(transliterateNames)
                .then(saveLocalJudgesJSONLocallyOnceMore)
                .then(searchDeclarationsAndWriteInFiles)
                .then(createDictionary)
                .spread(zipJudges),
            getTextsSource()
        ])
        .spread(() => {
            console.log("Done");
            process.exit(0);
        })
        .error(console.log)
        .catch(console.log);
})();

function getJudgesSource() {
    if (process.env.LOCAL_JUDGES_JSON) {
        console.log("Use cached judges JSON.");
        return readFile(input.cachedJudges, 'utf8')
            .then(data => JSON.parse(data))
    }

    return readFile(input.judgesPerRegionCSVLinksArray, 'utf8')
        .then(function (data) {
            return Promise.reduce(JSON.parse(data), function (regions, region) {
                console.log("Fetching: " + region.name);
                return remoteCSVtoJSON(region.link)
                    .then((json) => regions.concat(json));
            }, []);
        })
        .then(function (judges) {
            return writeFile(input.cachedJudges, JSON.stringify(judges))
                .then(() => saveTimestampLabel(input.cachedJudges))
                .then(() => judges);
        });
}

function getTextsSource () {
    console.log("getTextsSource");
    return remoteCSVtoJSON(input.textsCSV)
        .then(function (texts) {
            console.log("getTextsSource:texts");
            var textsKeyValue = {};
            _.forEach(texts, (text) => {
                textsKeyValue[text.key] = text.ukr;
            });
            return writeFile(output.texts, JSON.stringify(textsKeyValue))
                .then(() => saveTimestampLabel(output.texts))
                .then(() => texts);
        });
}

function saveTimestampLabel (filePath) {
    return writeFile(filePath + ".timestamp", ""+ (new Date().getTime()));
}

function filterEmptyLines(judges) {
    console.log('filterEmptyLines');
    return _.filter(judges, judge => judge[judgeModel.name] && !/\d/.test(judge[judgeModel.name]))
}

function checkDuplicates(judges) {
    console.log('Duplicates');
    var uniq = judges
        .map((judge) => {
            return {count: 1, name: judge[judgeModel.name]}
        })
        .reduce((a, b) => {
            a[b.name] = (a[b.name] || 0) + b.count;
            return a
        }, {});

    var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1);

    if (_.size(duplicates)) {
        console.log("... duplicates exists. More then 2 if any:");
        _.forEach(duplicates, (duplicate) => {
            if (uniq[duplicate] > 2) {
                console.log(uniq[duplicate] + " " + duplicate);
            }
        });
    }
    return judges;
}

function searchDeclarationsAndWriteInFiles(judges) {
    console.log('searchTheirDeclarations');
    return Promise.reduce(judges, function (_judges, judge) {
        return searchDeclaration(judge)
            .then(function (json) {
                judge.declarations = json;
                judge.declarationsLength = json && json.length;
                return writeFile(`../judges/${judge.key}.json`, JSON.stringify(judge))
                    .then(function () {
                        _judges.push({
                            d: judge[judgeModel.department], // department
                            p: judge[judgeModel.position], // position
                            r: judge[judgeModel.region], // region
                            n: judge[judgeModel.name], // Surname Name Patronymic
                            k: judge[judgeModel.key] // key of JSON file under http://prosud.info/judges/AbdukadirovaKarineEskenderivna.json
                        });
                        return _judges;
                    });
            })
    }, []);
}

function searchDeclaration(judge) {
    if (!judge[judgeModel.name]) {
        Promise.resolve(false);
        return;
    }
    // TODO add hack with readFile(`../declarations/${judge.key}.json`, 'utf8')
    return fetch(getSearchLink(judge[judgeModel.name]))
        .then(response => response.text())
        .then(data => JSON.parse(data))
        .then(response => {
            response = _.get(response, "results.object_list");
            return _.filter(response, function (declaration) {
                return _.lowerCase(_.get(declaration, "general.full_name")) === _.lowerCase(judge[judgeModel.name]);
            })
        })
        .catch(function (e) {
            throw new Error(e.message);
        })
}

function getSearchLink(s) {
    console.log("search " + s);
    s = encodeURI(s);
    return `http://declarations.com.ua/search?q=${s}&format=json`;
}

function transliterateNames(judges) {
    console.log('transliterateNames');
    judges.forEach(function (judge) {
        judge.key = _.toLower(transliterateName(judge[judgeModel.name]));
    });
    return judges;
}

function transliterateName(name) {
    return tr(name).split(' ').join('_');
}

function saveLocalJudgesJSONLocallyOnceMore(judges) {
    return writeFile(input.cachedJudges, JSON.stringify(judges))
        .then(() => judges);
}

function normalizeNames(judges) {
    judges.forEach(function (judge) {
        judge[judgeModel.name] = normalize(judge[judgeModel.name]);
    });
    return judges;
}

function normalize(string) {
    string = _.toLower(string);

    return _.chain(string.split(" "))
        .map(_.capitalize)
        .reduce(function (name, n) {
            return name + n + " ";
        }, "")
        .value()
        .slice(0, -1);
}

function createDictionary (judges) {
    var d = _.uniq(_.map(judges, 'd'));
    var p = _.uniq(_.map(judges, 'p'));
    var r = _.uniq(_.map(judges, 'r'));

    var dictionary = _.keyBy(d.concat(p).concat(r), function() {
        return _.uniqueId();
    });

    return writeFile(output.dictionary, JSON.stringify(dictionary))
        .then(() => saveTimestampLabel(output.dictionary))
        .then(() => [judges, _.invert(dictionary)]);
}

function zipJudges (judges, dictionary) {
    judges = _.map(judges, (judge) => {
        return {
            d: _.get(dictionary, judge.d), // department
            p: _.get(dictionary, judge.p), // position
            r: _.get(dictionary, judge.r), // region
            n: judge.n, // Surname Name Patronymic
            k: judge.k // key of JSON file under http://prosud.info/declarations/AbdukadirovaKarineEskenderivna.json
        };
    });

    return writeFile(output.judges, JSON.stringify(judges))
        .then(() => saveTimestampLabel(output.judges))
        .then(() => judges);
}
<commit_msg>Force toString<commit_after>"use strict";
let fetch = require('node-fetch');
let Converter = require("csvtojson");
let Promise = require('bluebird');
let _ = require("lodash");
let tr = require('transliteration').transliterate;
let readFile = Promise.promisify(require('fs').readFile);
let writeFile = Promise.promisify(require('fs').writeFile);
let remoteCSVtoJSON = require("./remote-csv-to-json");

const input = {
    judgesPerRegionCSVLinksArray: "./input/all-ukraine-judges-csv-links.json",
    cachedJudges: "./input/all-ukraine-judges.json",
    textsCSV: "https://docs.google.com/spreadsheets/d/1SDFmxJEo3Al4-dTS4PkA_E88bH40keZFfIcoT2mVOO4/pub?gid=0&single=true&output=csv"
};
const output = {
    judges: "../source/judges.json",
    dictionary: "../source/dictionary.json",
    texts: "../source/texts.json"
};
const judgeModel = require("./model/judge");

(function run() {
    Promise.all([
            getJudgesSource()
                .then(filterEmptyLines)
                .then(normalizeNames)
                .then(checkDuplicates)
                .then(transliterateNames)
                .then(saveLocalJudgesJSONLocallyOnceMore)
                .then(searchDeclarationsAndWriteInFiles)
                .then(createDictionary)
                .spread(zipJudges),
            getTextsSource()
        ])
        .spread(() => {
            console.log("Done");
            process.exit(0);
        })
        .error(console.log)
        .catch(console.log);
})();

function getJudgesSource() {
    if (process.env.LOCAL_JUDGES_JSON) {
        console.log("Use cached judges JSON.");
        return readFile(input.cachedJudges, 'utf8')
            .then(data => JSON.parse(data))
    }

    return readFile(input.judgesPerRegionCSVLinksArray, 'utf8')
        .then(function (data) {
            return Promise.reduce(JSON.parse(data), function (regions, region) {
                console.log("Fetching: " + region.name);
                return remoteCSVtoJSON(region.link)
                    .then((json) => regions.concat(json));
            }, []);
        })
        .then(function (judges) {
            return writeFile(input.cachedJudges, JSON.stringify(judges))
                .then(() => saveTimestampLabel(input.cachedJudges))
                .then(() => judges);
        });
}

function getTextsSource () {
    console.log("getTextsSource");
    return remoteCSVtoJSON(input.textsCSV)
        .then(function (texts) {
            console.log("getTextsSource:texts");
            var textsKeyValue = {};
            _.forEach(texts, (text) => {
                textsKeyValue[text.key] = text.ukr;
            });
            return writeFile(output.texts, JSON.stringify(textsKeyValue))
                .then(() => saveTimestampLabel(output.texts))
                .then(() => texts);
        });
}

function saveTimestampLabel (filePath) {
    return writeFile(filePath + ".timestamp", ""+ (new Date().getTime()));
}

function filterEmptyLines(judges) {
    console.log('filterEmptyLines');
    return _.filter(judges, judge => judge[judgeModel.name] && !/\d/.test(judge[judgeModel.name]))
}

function checkDuplicates(judges) {
    console.log('Duplicates');
    var uniq = judges
        .map((judge) => {
            return {count: 1, name: judge[judgeModel.name]}
        })
        .reduce((a, b) => {
            a[b.name] = (a[b.name] || 0) + b.count;
            return a
        }, {});

    var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1);

    if (_.size(duplicates)) {
        console.log("... duplicates exists. More then 2 if any:");
        _.forEach(duplicates, (duplicate) => {
            if (uniq[duplicate] > 2) {
                console.log(uniq[duplicate] + " " + duplicate);
            }
        });
    }
    return judges;
}

function searchDeclarationsAndWriteInFiles(judges) {
    console.log('searchTheirDeclarations');
    return Promise.reduce(judges, function (_judges, judge) {
        return searchDeclaration(judge)
            .then(function (json) {
                judge.declarations = json;
                judge.declarationsLength = json && json.length;
                return writeFile(`../judges/${judge.key}.json`, JSON.stringify(judge))
                    .then(function () {
                        _judges.push({
                            d: judge[judgeModel.department], // department
                            p: judge[judgeModel.position], // position
                            r: judge[judgeModel.region], // region
                            n: judge[judgeModel.name], // Surname Name Patronymic
                            k: judge[judgeModel.key] // key of JSON file under http://prosud.info/judges/AbdukadirovaKarineEskenderivna.json
                        });
                        return _judges;
                    });
            })
    }, []);
}

function searchDeclaration(judge) {
    if (!judge[judgeModel.name]) {
        Promise.resolve(false);
        return;
    }
    // TODO add hack with readFile(`../declarations/${judge.key}.json`, 'utf8')
    return fetch(getSearchLink(judge[judgeModel.name]))
        .then(response => response.text())
        .then(data => JSON.parse(data))
        .then(response => {
            response = _.get(response, "results.object_list");
            return _.filter(response, function (declaration) {
                return _.lowerCase(_.get(declaration, "general.full_name")) === _.lowerCase(judge[judgeModel.name]);
            })
        })
        .catch(function (e) {
            throw new Error(e.message);
        })
}

function getSearchLink(s) {
    console.log("search " + s);
    s = encodeURI(s);
    return `http://declarations.com.ua/search?q=${s}&format=json`;
}

function transliterateNames(judges) {
    console.log('transliterateNames');
    judges.forEach(function (judge) {
        judge.key = _.toLower(transliterateName(judge[judgeModel.name]));
    });
    return judges;
}

function transliterateName(name) {
    return tr(name).split(' ').join('_');
}

function saveLocalJudgesJSONLocallyOnceMore(judges) {
    return writeFile(input.cachedJudges, JSON.stringify(judges))
        .then(() => judges);
}

function normalizeNames(judges) {
    judges.forEach(function (judge) {
        judge[judgeModel.name] = normalize(judge[judgeModel.name]);
    });
    return judges;
}

function normalize(string) {
    string = _.toLower(string);

    return _.chain(string.split(" "))
        .map(_.capitalize)
        .reduce(function (name, n) {
            return name + n + " ";
        }, "")
        .value()
        .slice(0, -1);
}

function createDictionary (judges) {
    var d = _.uniq(_.map(judges, 'd'));
    var p = _.uniq(_.map(judges, 'p'));
    var r = _.uniq(_.map(judges, 'r'));

    var dictionary = _.keyBy(d.concat(p).concat(r), function() {
        return _.uniqueId();
    });

    var correctedDictionary = _.mapValues(dictionary, function (value) {
        return _.toString(value);
    });

    return writeFile(output.dictionary, JSON.stringify(correctedDictionary))
        .then(() => saveTimestampLabel(output.dictionary))
        .then(() => [judges, _.invert(dictionary)]);
}

function zipJudges (judges, dictionary) {
    judges = _.map(judges, (judge) => {
        return {
            d: _.get(dictionary, judge.d), // department
            p: _.get(dictionary, judge.p), // position
            r: _.get(dictionary, judge.r), // region
            n: judge.n, // Surname Name Patronymic
            k: judge.k // key of JSON file under http://prosud.info/declarations/AbdukadirovaKarineEskenderivna.json
        };
    });

    return writeFile(output.judges, JSON.stringify(judges))
        .then(() => saveTimestampLabel(output.judges))
        .then(() => judges);
}
<|endoftext|>


<commit_before>/* eslint-env node */
const EmberApp = require('ember-cli/lib/broccoli/ember-app');

const environment = EmberApp.env();
const isProd = environment === 'production';
const isTest = environment === 'test';

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    addons: {
      blacklist: isProd ? ['ember-freestyle'] : [],
    },
    svg: {
      paths: ['public/images/icons'],
    },
    codemirror: {
      modes: ['javascript'],
    },
    funnel: {
      enabled: isProd,
      exclude: [
        `${defaults.project.pkg.name}/components/freestyle/**/*`,
        `${defaults.project.pkg.name}/templates/components/freestyle/**/*`,
      ],
    },
    babel: {
      plugins: ['@babel/plugin-proposal-object-rest-spread'],
    },
    'ember-cli-babel': {
      includePolyfill: isProd,
    },
    hinting: isTest,
    tests: isTest,
    sourcemaps: {
      enabled: false,
    },
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};
<commit_msg>Don't remove viewBox from svgs as part of svgo<commit_after>/* eslint-env node */
const EmberApp = require('ember-cli/lib/broccoli/ember-app');

const environment = EmberApp.env();
const isProd = environment === 'production';
const isTest = environment === 'test';

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    addons: {
      blacklist: isProd ? ['ember-freestyle'] : [],
    },
    svg: {
      paths: ['public/images/icons'],
      optimize: {
        plugins: [{ removeViewBox: false }],
      },
    },
    codemirror: {
      modes: ['javascript'],
    },
    funnel: {
      enabled: isProd,
      exclude: [
        `${defaults.project.pkg.name}/components/freestyle/**/*`,
        `${defaults.project.pkg.name}/templates/components/freestyle/**/*`,
      ],
    },
    babel: {
      plugins: ['@babel/plugin-proposal-object-rest-spread'],
    },
    'ember-cli-babel': {
      includePolyfill: isProd,
    },
    hinting: isTest,
    tests: isTest,
    sourcemaps: {
      enabled: false,
    },
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};
<|endoftext|>


<commit_before>

window.onload = function() {
    // autoplay when finished
    var audio_track = document.getElementById("track");
    var autoplay_button = document.getElementById("autoplay");
    var autoplay = getQueryParams().autoplay == "true";
    var volume_string = getQueryParams().volume;
    function next_autoplay_location() {
        var volume = audio_track ? "&volume=" + audio_track.volume : ""
        return next_post_url + "?autoplay=true" + volume;
    }
    if (audio_track) {
        audio_track.onended = function () {
            if ((!autoplay_button || autoplay_button.checked) && next_post_url) {
                document.location = next_autoplay_location();
            }
        }
        if (autoplay) {
            audio_track.play()
        }
        if (volume_string) {
            audio_track.volume = parseFloat(volume_string);
        }
    } else if (autoplay && next_post_url) {
        // skip if there is nothing to play
        document.location = next_autoplay_location();
    }
    if (autoplay_button) {
        autoplay_button.checked = autoplay;
    }
}

<commit_msg>fixed bugÖ loosing volume if skipping<commit_after>

window.onload = function() {
    // autoplay when finished
    var audio_track = document.getElementById("track");
    var autoplay_button = document.getElementById("autoplay");
    var autoplay = getQueryParams().autoplay == "true";
    var volume_string = getQueryParams().volume;
    function next_autoplay_location() {
        var volume = audio_track ? "&volume=" + audio_track.volume : ( volume_string ? "&volume=" + volume_string : "" );
        return next_post_url + "?autoplay=true" + volume;
    }
    if (audio_track) {
        audio_track.onended = function () {
            if ((!autoplay_button || autoplay_button.checked) && next_post_url) {
                document.location = next_autoplay_location();
            }
        }
        if (autoplay) {
            audio_track.play()
        }
        if (volume_string) {
            audio_track.volume = parseFloat(volume_string);
        }
    } else if (autoplay && next_post_url) {
        // skip if there is nothing to play
        document.location = next_autoplay_location();
    }
    if (autoplay_button) {
        autoplay_button.checked = autoplay;
    }
}

<|endoftext|>


<commit_before>// ==UserScript==
// @name        quick-translations
// @namespace   danielcgirotto
// @description Tradução rápida de palavras. en ~> pt-BR
// @include     http*
// @version     1
// @resource    cleanslate https://raw.githubusercontent.com/premasagar/cleanslate/master/cleanslate.css
// @resource    magic https://raw.githubusercontent.com/miniMAC/magic/master/magic.min.css
// @resource    style http://localhost:8000/style.css
// @require     http://code.jquery.com/jquery-1.11.2.min.js
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @noframes
// ==/UserScript==
$(function() {
  GM_addStyle(GM_getResourceText('cleanslate'));
  GM_addStyle(GM_getResourceText("magic"));
  GM_addStyle(GM_getResourceText("style"));

  $('body').dblclick(function(event) {
    var text = getSelectionText().toLowerCase();

    if(/[a-z]/.test(text))
      request(text);
  });

  $(document).click(function(event) {
    $('.tooltip').remove();
  });

  function getSelectionText() {
    if (window.getSelection) {
      return window.getSelection().toString();
    }
    if (document.selection && document.selection.type != 'Control') {
      return document.selection.createRange().text;
    }
    return '';
  }

  function request(text) {
    if(!request.cache) request.cache = {};

    if(request.cache[text] != null) {
      callback(request.cache[text]);
      return;
    }

    GM_xmlhttpRequest({
      method: 'POST',
      url: 'https://translate.google.com/translate_a/t?',
      data: 'client=t&text=' + encodeURIComponent(text) + '&hl=auto&tl=pt',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      onload: function(response) {
        request.cache[text] = callback(response.responseText);
      }
    });
  }

  function callback(response) {
    parse(response);
    return response;
  }

  function parse(source) {
    var source = eval(source);

    $('<table>', {
      class: 'popup cleanslate magictime puffIn',
        append: $('<tr>', {
          text: 'Traduções de ' + source[0][0][1] + ' : ' + source[0][0][0]
        })
    }).appendTo('body');

    source = (typeof(source[1]) == "undefined") ? [] : source[1];

    $.each(source, function(index, word_classes) {
      $('<tr>', {
        class: 'word_classes',
        text: word_classes[0]
      }).appendTo('.popup');

      $.each(word_classes[2], function(index, words) {
        $('<tr>', {
          class: 'border_top',
          append: [
            $('<td>', {text: words[0]}),
            $('<td>', {text: words[1].join(', ')})
          ]
        }).appendTo('.popup');
      });
    });
  }
});
<commit_msg>Update quick-translations.js<commit_after>// ==UserScript==
// @name        quick-translations
// @namespace   danielcgirotto
// @description Tradução rápida de palavras. en ~> pt-BR
// @include     http*
// @version     1
// @resource    cleanslate https://raw.githubusercontent.com/premasagar/cleanslate/master/cleanslate.css
// @resource    magic https://raw.githubusercontent.com/miniMAC/magic/master/magic.min.css
// @resource    style https://raw.githubusercontent.com/danielgirotto/quick-translations/master/style.css
// @require     http://code.jquery.com/jquery-1.11.2.min.js
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @noframes
// ==/UserScript==
$(function() {
  GM_addStyle(GM_getResourceText('cleanslate'));
  GM_addStyle(GM_getResourceText("magic"));
  GM_addStyle(GM_getResourceText("style"));

  $('body').dblclick(function(event) {
    var text = getSelectionText().toLowerCase();

    if(/[a-z]/.test(text))
      request(text);
  });

  $(document).click(function(event) {
    $('.tooltip').remove();
  });

  function getSelectionText() {
    if (window.getSelection) {
      return window.getSelection().toString();
    }
    if (document.selection && document.selection.type != 'Control') {
      return document.selection.createRange().text;
    }
    return '';
  }

  function request(text) {
    if(!request.cache) request.cache = {};

    if(request.cache[text] != null) {
      callback(request.cache[text]);
      return;
    }

    GM_xmlhttpRequest({
      method: 'POST',
      url: 'https://translate.google.com/translate_a/t?',
      data: 'client=t&text=' + encodeURIComponent(text) + '&hl=auto&tl=pt',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      onload: function(response) {
        request.cache[text] = callback(response.responseText);
      }
    });
  }

  function callback(response) {
    parse(response);
    return response;
  }

  function parse(source) {
    var source = eval(source);

    $('<table>', {
      class: 'popup cleanslate magictime puffIn',
        append: $('<tr>', {
          text: 'Traduções de ' + source[0][0][1] + ' : ' + source[0][0][0]
        })
    }).appendTo('body');

    source = (typeof(source[1]) == "undefined") ? [] : source[1];

    $.each(source, function(index, word_classes) {
      $('<tr>', {
        class: 'word_classes',
        text: word_classes[0]
      }).appendTo('.popup');

      $.each(word_classes[2], function(index, words) {
        $('<tr>', {
          class: 'border_top',
          append: [
            $('<td>', {text: words[0]}),
            $('<td>', {text: words[1].join(', ')})
          ]
        }).appendTo('.popup');
      });
    });
  }
});
<|endoftext|>


<commit_before>import Backbone from 'backbone';
import { isUndefined, isString, isFunction } from 'underscore';

const $ = Backbone.$;

export default Backbone.View.extend({
  events: {
    change: 'onChange'
  },

  appendInput: 1,

  attributes() {
    return this.model.get('attributes');
  },

  templateLabel() {
    const { ppfx } = this;
    const label = this.getLabel();
    return `<div class="${ppfx}label" title="${label}">${label}</div>`;
  },

  templateInput() {
    const { clsField } = this;
    return `<div class="${clsField}" data-input></div>`;
  },

  initialize(o = {}) {
    const { config = {} } = o;
    const { model } = this;
    const { target } = model;
    const { type } = model.attributes;
    this.config = config;
    this.em = config.em;
    this.pfx = config.stylePrefix || '';
    this.ppfx = config.pStylePrefix || '';
    this.target = target;
    const { ppfx } = this;
    this.clsField = `${ppfx}field ${ppfx}field-${type}`;
    [['change:value', this.onValueChange], ['remove', this.removeView]].forEach(
      ([event, clb]) => {
        model.off(event, clb);
        this.listenTo(model, event, clb);
      }
    );
    model.view = this;
    this.init();
  },

  removeView() {
    this.remove();
    this.removed();
  },

  init() {},
  removed() {},

  /**
   * Fires when the input is changed
   * @private
   */
  onChange() {
    const el = this.getInputElem();
    if (el && !isUndefined(el.value)) {
      this.model.set('value', el.value);
    }
  },

  getValueForTarget() {
    return this.model.get('value');
  },

  setInputValue(value) {
    const el = this.getInputElem();
    el && (el.value = value);
  },

  /**
   * On change callback
   * @private
   */
  onValueChange(model, value, opts = {}) {
    if (opts.fromTarget) {
      this.setInputValue(model.get('value'));
    } else {
      const val = this.getValueForTarget();
      model.setTargetValue(val, opts);
    }
  },

  /**
   * Render label
   * @private
   */
  renderLabel() {
    const { $el, target } = this;
    const label = this.getLabel();
    let tpl = this.templateLabel(target);

    if (this.createLabel) {
      tpl =
        this.createLabel({
          label,
          component: target
        }) || '';
    }

    $el.find('[data-label]').append(tpl);
  },

  /**
   * Returns label for the input
   * @return {string}
   * @private
   */
  getLabel() {
    var model = this.model;
    var label = model.get('label') || model.get('name');
    return label.charAt(0).toUpperCase() + label.slice(1).replace(/-/g, ' ');
  },

  /**
   * Returns current target component
   */
  getComponent() {
    return this.target;
  },

  /**
   * Returns input element
   * @return {HTMLElement}
   * @private
   */
  getInputEl() {
    if (!this.$input) {
      const md = this.model;
      const plh = md.get('placeholder') || md.get('default') || '';
      const type = md.get('type') || 'text';
      const min = md.get('min');
      const max = md.get('max');
      const value = this.getModelValue();
      const input = $(`<input type="${type}" placeholder="${plh}">`);

      if (!isUndefined(value)) {
        md.set({ value }, { silent: true });
        input.prop('value', value);
      }

      if (min) {
        input.prop('min', min);
      }

      if (max) {
        input.prop('max', max);
      }

      this.$input = input;
    }
    return this.$input.get(0);
  },

  getInputElem() {
    const { input, $input } = this;
    return input || ($input && $input.get(0));
  },

  getModelValue() {
    let value;
    const model = this.model;
    const target = this.target;
    const name = model.get('name');

    if (model.get('changeProp')) {
      value = target.get(name);
    } else {
      const attrs = target.get('attributes');
      value = model.get('value') || attrs[name];
    }

    return !isUndefined(value) ? value : '';
  },

  getElInput() {
    return this.elInput;
  },

  /**
   * Renders input
   * @private
   * */
  renderField() {
    const { $el, target, appendInput, model } = this;
    const inputOpts = { component: target };
    const inputs = $el.find('[data-input]');
    const el = inputs[inputs.length - 1];
    let tpl = model.el;

    if (!tpl) {
      tpl = this.createInput ? this.createInput(inputOpts) : this.getInputEl();
    }

    if (isString(tpl)) {
      el.innerHTML = tpl;
      this.elInput = el.firstChild;
    } else {
      appendInput ? el.appendChild(tpl) : el.insertBefore(tpl, el.firstChild);
      this.elInput = tpl;
    }

    model.el = this.elInput;
  },

  hasLabel() {
    return !this.model.get('noLabel');
  },

  render() {
    const { $el, pfx, ppfx, model } = this;
    const { type } = model.attributes;
    const hasLabel = this.hasLabel && this.hasLabel();
    const cls = `${pfx}trait`;
    this.$input = null;
    let tmpl = `

      ${hasLabel ? `<div class="${ppfx}label-wrp" data-label></div>` : ''}

        ${
          this.templateInput
            ? isFunction(this.templateInput)
              ? this.templateInput()
              : this.templateInput
            : ''
        }

`;
    $el.empty().append(tmpl);
    hasLabel && this.renderLabel();
    this.renderField();
    this.el.className = `${cls}__wrp`;
    return this;
  }
});
<commit_msg>Add onRender hook<commit_after>import Backbone from 'backbone';
import { isUndefined, isString, isFunction } from 'underscore';

const $ = Backbone.$;

export default Backbone.View.extend({
  events: {
    change: 'onChange'
  },

  appendInput: 1,

  attributes() {
    return this.model.get('attributes');
  },

  templateLabel() {
    const { ppfx } = this;
    const label = this.getLabel();
    return `<div class="${ppfx}label" title="${label}">${label}</div>`;
  },

  templateInput() {
    const { clsField } = this;
    return `<div class="${clsField}" data-input></div>`;
  },

  initialize(o = {}) {
    const { config = {} } = o;
    const { model } = this;
    const { target } = model;
    const { type } = model.attributes;
    this.config = config;
    this.em = config.em;
    this.pfx = config.stylePrefix || '';
    this.ppfx = config.pStylePrefix || '';
    this.target = target;
    const { ppfx } = this;
    this.clsField = `${ppfx}field ${ppfx}field-${type}`;
    [['change:value', this.onValueChange], ['remove', this.removeView]].forEach(
      ([event, clb]) => {
        model.off(event, clb);
        this.listenTo(model, event, clb);
      }
    );
    model.view = this;
    this.init();
  },

  removeView() {
    this.remove();
    this.removed();
  },

  init() {},
  removed() {},
  onRender() {},

  /**
   * Fires when the input is changed
   * @private
   */
  onChange() {
    const el = this.getInputElem();
    if (el && !isUndefined(el.value)) {
      this.model.set('value', el.value);
    }
  },

  getValueForTarget() {
    return this.model.get('value');
  },

  setInputValue(value) {
    const el = this.getInputElem();
    el && (el.value = value);
  },

  /**
   * On change callback
   * @private
   */
  onValueChange(model, value, opts = {}) {
    if (opts.fromTarget) {
      this.setInputValue(model.get('value'));
    } else {
      const val = this.getValueForTarget();
      model.setTargetValue(val, opts);
    }
  },

  /**
   * Render label
   * @private
   */
  renderLabel() {
    const { $el, target } = this;
    const label = this.getLabel();
    let tpl = this.templateLabel(target);

    if (this.createLabel) {
      tpl =
        this.createLabel({
          label,
          component: target
        }) || '';
    }

    $el.find('[data-label]').append(tpl);
  },

  /**
   * Returns label for the input
   * @return {string}
   * @private
   */
  getLabel() {
    var model = this.model;
    var label = model.get('label') || model.get('name');
    return label.charAt(0).toUpperCase() + label.slice(1).replace(/-/g, ' ');
  },

  /**
   * Returns current target component
   */
  getComponent() {
    return this.target;
  },

  /**
   * Returns input element
   * @return {HTMLElement}
   * @private
   */
  getInputEl() {
    if (!this.$input) {
      const md = this.model;
      const plh = md.get('placeholder') || md.get('default') || '';
      const type = md.get('type') || 'text';
      const min = md.get('min');
      const max = md.get('max');
      const value = this.getModelValue();
      const input = $(`<input type="${type}" placeholder="${plh}">`);

      if (!isUndefined(value)) {
        md.set({ value }, { silent: true });
        input.prop('value', value);
      }

      if (min) {
        input.prop('min', min);
      }

      if (max) {
        input.prop('max', max);
      }

      this.$input = input;
    }
    return this.$input.get(0);
  },

  getInputElem() {
    const { input, $input } = this;
    return input || ($input && $input.get(0));
  },

  getModelValue() {
    let value;
    const model = this.model;
    const target = this.target;
    const name = model.get('name');

    if (model.get('changeProp')) {
      value = target.get(name);
    } else {
      const attrs = target.get('attributes');
      value = model.get('value') || attrs[name];
    }

    return !isUndefined(value) ? value : '';
  },

  getElInput() {
    return this.elInput;
  },

  /**
   * Renders input
   * @private
   * */
  renderField() {
    const { $el, target, appendInput, model } = this;
    const inputOpts = { component: target };
    const inputs = $el.find('[data-input]');
    const el = inputs[inputs.length - 1];
    let tpl = model.el;

    if (!tpl) {
      tpl = this.createInput ? this.createInput(inputOpts) : this.getInputEl();
    }

    if (isString(tpl)) {
      el.innerHTML = tpl;
      this.elInput = el.firstChild;
    } else {
      appendInput ? el.appendChild(tpl) : el.insertBefore(tpl, el.firstChild);
      this.elInput = tpl;
    }

    model.el = this.elInput;
  },

  hasLabel() {
    return !this.model.get('noLabel');
  },

  render() {
    const { $el, pfx, ppfx, model, target } = this;
    const { type } = model.attributes;
    const hasLabel = this.hasLabel && this.hasLabel();
    const cls = `${pfx}trait`;
    this.$input = null;
    let tmpl = `

      ${hasLabel ? `<div class="${ppfx}label-wrp" data-label></div>` : ''}

        ${
          this.templateInput
            ? isFunction(this.templateInput)
              ? this.templateInput()
              : this.templateInput
            : ''
        }

`;
    $el.empty().append(tmpl);
    hasLabel && this.renderLabel();
    this.renderField();
    this.el.className = `${cls}__wrp`;
    this.onRender({ component: target });
    return this;
  }
});
<|endoftext|>