4.11.0 • Published 2 months ago

@squared-functions/watch v4.11.0

Weekly downloads
3,262
License
MIT
Repository
github
Last release
2 months ago

squared-functions 0.9

These are some of the available options when creating archives or copying files with squared 2.2.

squared.settings.outputArchiveFormat = 'tar'; // Format: zip | tar | gz/tgz (default: zip)

squared.saveAs('archive1', { // OR: archive1.gz
    format: 'gz',
    assets: [
        {
            pathname: 'app/src/main/res/drawable',
            filename: 'ic_launcher_background.xml',
            uri: 'http://localhost:3000/common/images/ic_launcher_background.xml',
            compress: [{ format: 'gz', level: 9 }, { format: 'br' }]
        }
    ],

    // All attributes are optional (case-sensitive except extension)
    exclusions: {
        glob: ['**/*.zip'],
        pathname: ['app/build', 'app/libs'],
        filename: ['ic_launcher_foreground.xml'],
        extension: ['iml', 'pro'],
        pattern: ['output', /grad.+?\./i, '\\.git']
    }
});

Image conversion can be achieved using the "commands" array property in a FileAsset object. The supported formats are:

  • png - r/w
  • jpeg - r/w
  • webp - r/w
  • bmp - r/w
  • gif - r
  • tiff - r

NOTE: WebP support requires manual NPM installation of the binaries.

  • dwebp - r
  • cwebp - w

npm install dwebp-bin && npm install cwebp-bin

// All commands are optional except "format". Outer groupings and inner brackets are required.

+ <format>

- @|%
- ( minSize(n,0) , maxSize(n,*) )
- ( width(n|auto) x height(n|auto) [bilinear|bicubic|hermite|bezier]? ^(cover|contain|scale)?[left|center|right|top|middle|bottom]? #background-color? )
- ( left(+|-n) , top(+|-n) | cropWidth(n) x cropHeight(n) ) // "+" reserved for chaining
- { ...rotate(n) #background-color? }
- | opacity(0.0-1.0) OR jpeg_webp_quality(0-100)[photo|picture|drawing|icon|text]?[0-100]?| // cwebp: -preset -near_lossless
- !method // no arguments (e.g. jimp: dither565|greyscale|invert|normalize|opaque|sepia)

@ - replace
% - smaller

Placing an @ symbol (png@) after the format will remove the original file from the package. Using the % symbol (png%) instead will choose the smaller of the two files. You can also use these commands with the setting "convertImages" in the Android framework as a string with the "+" chain format.

// Multiple transformations per asset use the "::" as the separator when using "data-chrome-commands"

webp(50000,*)(800x600[bezier]^contain[right|bottom]#FFFFFF)(-50,50|200x200){45,135,215,315#FFFFFF}|0.5||100[photo][75]|!opaque!greyscale

TinyPNG is used for compression and supports only PNG and JPEG.

Gulp

Tasks can be performed with Gulp to take advantage of their pre-built plugin repository. Gulp is the final stage preceding archiving or copying after file content has been downloaded and transformed.

// squared.settings.json

{
  "gulp": {
    "minify": "./gulpfile.js"
    "beautify": "./gulpfile.js",
    "compress": "./gulpfile.android.js"
  }
}

// chrome
{
  "selector": "head > script:nth-of-type(1)",
  "type": "js",
  "tasks": [
    "minify",
    "beautify"
  ]
}

// android
const options = {
    assets: [
        {
            pathname: 'images',
            filename: 'pencil.png',
            mimeType: 'image/png',
            commands: ['jpeg', 'bmp@(50000,100000)'],
            tasks: ['compress'],
            uri: 'http://localhost:3000/common/images/pencil.png'
        }
    ]
};
<!-- chrome -->
<script src="/common/system.js" data-chrome-tasks="minify+beautify"></script>

<!-- android -->
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/harbour1.jpg" data-android-tasks="compress" />

NOTE: SRC (temp) and DEST (original) always read and write to the current directory.

// gulpfile.js

const gulp = require('gulp');
const uglify = require('gulp-uglify');
 
gulp.task('minify', () => {
  return gulp.src('*')
    .pipe(uglify())
    .pipe(gulp.dest('./'));
});

Renaming files with Gulp is not recommended. It is better to use the "saveAs" or "filename" attributes when the asset is part of the HTML page.

CHROME: Saving web page assets

Bundling options are available with these HTML tag names.

  • saveAs: html + script + link
  • exportAs: script + style
  • exclude: script + link + style

Files with the same path and filename will automatically create a bundle assuming there are no conflicts in call ordering.

// JSON/YAML configuration is recommended

{
  "selector": "head > script:nth-of-type(2), head > script:nth-of-type(3)",
  "type": "js",
  "saveAs": "js/modules2.js"
}

JS and CSS files can be bundled together with the "saveAs" or "exportAs" action. Multiple transformations per asset can be chained using the "+" symbol. Whitespace can be used between anything for readability.

+ saveAs: location | ~  // same
+ exportAs: location

- ::
- format (chain "+")

These are the available option modifiers:

* preserve
    - css: Prevent unused styles from being deleted
* inline
    - js: Rendered inline with <script>
    - css: Rendered inline with <style>
    - image: Rendered inline with base64 encoding as data url
* compress
    - png: TinyPNG service for PNG or JPEG
    - gz: Gzip
    - br: Brotli

NOTE: Placing the "chrome" dataset commands at the end is recommended especially if you are using the ">" character in your attributes. When possible use the "&gt;" entity instead.

<!-- Required: Lowercase tag names and attributes with no extra spaces -->

<link rel="stylesheet" href="css/dev.css" data-chrome-file="saveAs:css/prod.css::beautify" data-chrome-options="preserve|inline" />
<style data-chrome-file="exportAs:css/prod.css::minify+beautify" data-chrome-options="compress[gz]">
    body {
        font: 1em/1.4 Helvetica, Arial, sans-serif;
        background-color: #fafafa;
    }
</style>
<script src="/dist/squared.js" data-chrome-file="saveAs:js/bundle1.js::minify"></script>
<script src="/dist/squared.base.js" data-chrome-file="saveAs:js/bundle1.js::minify"></script>
<script src="/dist/chrome.framework.js" data-chrome-file="saveAs:js/bundle2.js"></script>

Bundling with "exportAs" gives you the ability to debug source code inside <script> elements.

Raw assets

<!-- img | video | audio | source | track | object | embed | iframe -->

<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/harbour1.jpg"
     data-chrome-file="saveAs:images/harbour.jpg"
     data-chrome-options="compress" />

You can use images commands with saveTo (directory) on any element where the image is the primary display output.

<!-- img | object | embed | iframe -->

<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/12005/harbour1.jpg"
     data-chrome-file="saveTo:../images/harbour"
     data-chrome-commands="png(10000,75000)(800x600[bezier]^contain[right|bottom])"
     data-chrome-options="compress|inline" />

Transformations including the original file are given a UUID filename. Leaving "file" empty will save the transformations to the current image directory.

Built-In plugins

JS and CSS files can be optimized further using these settings:

  • beautify
  • minify
  • es5 (Babel)
  • es5-minify (UglifyJS)
  • custom name

You can also define your own optimizations in squared.settings.json:

These particular plugins can be configured using a plain object literal. Manual installation is required when using any of these packages npm run install-chrome. Transpiling with Babel is also configurable with a .babelrc file in the base folder for any presets and additional settings. Other non-builtin minifiers can similarly be applied and chained by defining a custom string-based synchronous function.

chrome -> html | js | css -> npm package name -> custom name
  • Function object
  • file relative to serve.js
  • function closure
// squared.settings.json

{
  "chrome": {
    "html": { // built-in minifier
      "posthtml": {
        "transform": {
          "plugins": [
            ["posthtml-doctype", { "doctype": "HTML 5" }], // Plugins have be installed with NPM manually
            ["posthtml-include", { "root": "./", "encoding": "utf-8" }]
          ]
        },
        "transform-output": {
          "directives": [
            { "name": "?php", "start": "<", "end": ">" }
          ]
        }
      },
      "prettier": {
        "beautify": {
          "parser": "html",
          "printWidth": 120,
          "tabWidth": 4
        }
      }
    },
    "js": { // custom function (chrome -> eval_function: true)
      "terser": {
        "minify-example": "function(context, value, output) { return context.minify(value, output).code; }", // "minify-example-output" creates scoped variable "output"
        "minify-example-output": {
          "keep_classnames": true
        }
      },
      "@babel/core": {
        "es5-example": "./es5.js" // startsWith('./ | ../')
      },
      "rollup": {
        "bundle-es6": {
          "plugins": [
            ["@rollup/plugin-json", { compact: true }]
          ],
          "external": ["lodash"]
        },
        "bundle-es6-output": "./rollup.output.config.json" // supplemental JSON configuration settings use the "-output" suffix
      }
    },
    "css": {
      "postcss": {
        "transform": {
          "plugins": ["autoprefixer", "cssnano"] // Plugins have be installed with NPM manually
        }
      },
      "node-sass": { // npm i node-sass
        "sass-example": "function(context, value) { return context.renderSync({ data: value }, functions: {}); }" // first transpiler in chain
      }
    }
  }
}
// es5.js

function (context, value, output /* optional: "@babel/core-output" */) {
    const options = { presets: ['@babel/preset-env'] }; // <https://babeljs.io/docs/en/options>
    return context.transformSync(value, output).code;
}

The same concept can be used inline anywhere using a <script> tag with the type attribute set to "text/template". The script template will be completely removed from the final output.

// "es5-example" is a custom name (chrome -> eval_text_template: true)

<script type="text/template" data-chrome-template="js::@babel/core::es5-example">
function (context, value, output /* optional */, input /* optional */) {
    const options = { ...output, presets: ['@babel/preset-env'], sourceMaps: true };
    const result = context.transformSync(value, options);
    if (result) {
        if (result.map) {
            input.nextMap('babel', result.map, result.code);
        }
        return result.code;
    }
}
</script>

Here is the equivalent configuration in YAML and when available has higher precedence than JSON.

Modifying content attributes

There are possible scenarios when a transformation may cause an asset type to change into another format.

<!-- before -->
<link id="sass-example" rel="alternate" type="text/plain" href="css/dev.sass" />

Using element "id" is recommended when there are multiple elements with identical structure and content. Similar to JSON use only double quotes (or &quot;) and do not use unnecessary extra spaces. Tags that are not well-formed may fail to be replaced.

{
  "selector": "#sass-example",
  "type": "css",
  "filename": "prod.css",
  "attributes": {
      "id": undefined,
      "rel": "stylesheet",
      "type": "text/css",
      "title": "",
      "disabled": null
    }
  ],
  "process": [
    "node-sass"
  ]
}
<!-- after -->
<link rel="stylesheet" type="text/css" title="" disabled href="css/prod.css" />

External configuration

JSON (json/js) configuration is optional and is provided for those who prefer to separate the bundling and transformations from the HTML. Any assets inside the configuration file will override any settings either inline or from JavaScript. You can also use the equivalent in YAML (yml/yaml) for configuring as well.

interface OutputModifiers {
    inline?: boolean; // type: js | css | image (base64)
    preserve?: boolean; // type: css
    ignore?: boolean;
    exclude?: boolean
}

interface AssetCommand extends OutputModifiers {
    selector?: string;
    type?: string;
    saveAs?: string; // type: js | css
    exportAs?: string; // type: js | css
    saveTo?: string; // type: image | video | audio (transforms create multiple files and are given a UUID filename)
    pathname?: string; // alias for "saveTo"
    filename?: string; // type: html | ...image
    process?: string[]; // type: js | css
    commands?: string[]; // type: image
    cloudStorage?: CloudService[];
    attributes?: { [key: string]: value?: Null<string> };
    tasks?: string[];
    watch?: boolean | { interval?: number, expires?: string }; // type: js | css | image (expires: 1h 1m 1s)
    template?: {
        module: string;
        identifier?: string;
        value?: string;
    };
}
squared.saveAs('bundle.zip', { configUri: 'http://localhost:3000/chrome/bundle.yml' });

Here is the equivalent page using only inline commands with "data-chrome-file" and "data-chrome-tasks".

Cloud storage

Manual installation of the SDK is required including an account with at least one of these cloud storage provider.

* Amazon
  - npm install aws-sdk
  - AWS: https://aws.amazon.com/free (5GB - 12 months)

* Microsoft
  - npm install @azure/storage-blob
  - Azure: https://azure.microsoft.com/en-us/free (5GB - 12 months)

* Google
  - npm install @google-cloud/storage
  - GCloud: https://cloud.google.com/free (5GB - US)

* IBM
  - npm install ibm-cos-sdk
  - IBM: https://www.ibm.com/cloud/free (25GB)

* Oracle
  - npm install aws-sdk
  - OCI: https://www.oracle.com/cloud/free (10GB)
  - Uses S3 compatibility API
  - Cannot create new public buckets

Other service providers can be integrated similarly except for credential verification.

// Optional fields are supported by all services

{
  "selector": "#picture1",
  "type": "image",
  "commands": [
    "png(100x200){90,180,270}" // Uploaded with UUID filename
  ],
  "cloudStorage": [
    {
      "service": "aws",
      "bucket": "squared-001",
      "credential": {
        "accessKeyId": "**********",
        "secretAccessKey": "**********",
        "region": "us-west-2", // Custom properties are sent to the S3 client (optional)
        "sessionToken": "**********" // optional
      },
      "credential": "main", // OR: Load host configuration from settings at instantiation
      "upload": {
        "active": false, // Rewrites "src" to cloud storage location (optional)
        "localStorage": true, // Remove current file from archive or local disk (optional)
        "filename": "picture1.webp", // Choose a different bucket filename (optional)
        "all": false, // Include transforms (optional)
        "overwrite": false // Always use current filename (optional)
      },
      "download": {
        "filename": "picture2.png",
        "versionId": "12345", // Retrieve a previous file snapshot (optional)
        "pathname": "download/images", // File adjacent or base directory when omitted (optional: Overrides "preservePath")
        "active": false, // Always write file or rename to main file when same extension (optional)
        "overwrite": false, // Always write file (optional)
        "deleteObject": false // Remove if download success (optional)
      }
    },
    {
      "service": "azure",
      "bucket": "squared-002",
      "credential": {
        "accountName": "**********", // +1 password option (required)
        "accountKey": "**********",
        "connectionString": "**********",
        "sharedAccessSignature": "**********"
      },
      "upload": {
        "pathname": "a/b/c/", // Virtual directory in bucket (optional: Overrides "preservePath")
        "endpoint": "http://squaredjs.azureedge.net/squared-002" // e.g. CDN (optional)
      }
    },
    {
      "service": "gcloud",
      "bucket": "squared-003", // UUID generated when omitted (optional)
      "credential": {
        "keyFilename": "./gcloud.json" // Path to JSON credentials
      },
      "admin": {
        "publicRead": false, // New buckets (optional: Not supported OCI)
        "emptyBucket": false, // More convenient than using "overwrite" (optional),
        "preservePath": false // Use current pathname as file prefix
      },
      "upload": {
        "active": true, // Implicity "publicRead: true" except when explicitly "publicRead: false"
        "publicRead": false // User with "admin" privileges (optional: Not supported Azure and OCI)
      }
    },
    {
      "service": "ibm",
      "bucket": "squared-004",
      "credential": {
        "apiKeyId": "**********",
        "serviceInstanceId": "**********",
        "region": "us-south",
        "endpoint": "https://s3.us-south.cloud-object-storage.appdomain.cloud" // Same as region (optional)
      }
    },
    {
      "service": "oci",
      "bucket": "squared-005", // New buckets are private when using S3 API
      "credential": {
        "region": "us-phoenix-1",
        "namespace": "abcdefghijkl",
        "accessKeyId": "**********",
        "secretAccessKey": "**********"
      }
    }
  ]
}

NOTE: Using S3 and OCI at the same time with identical bucket names causes a conflict with the S3 region cache.

Serving CSS files from cloud storage or CDN requires every image inside the file to be hosted with an absolute URL.

squared.saveAs('index.zip', {
    configUri: 'http://localhost:3000/chrome/bundle.yml',
    saveAs: {
        html: {
            cloudStorage: [{ // Create static website
                service: 'aws',
                bucket: 'squared-001',
                settings: 'main',
                upload: {
                    active: true,
                    endpoint: 'https://squared-001.s3.us-west-2.amazonaws.com',
                    overwrite: true
                }
            }]
        },
        image: { // Non-element images using url() method
            cloudStorage: [{
                service: 'aws',
                bucket: 'squared-001',
                settings: 'main',
                upload: {
                    active: true
                }
            }]
        }
    }
});

Inline commands are not supported when using cloud features.

Cloud database

Basic text replacement can be achieved using any of these cloud based document databases. Each provider has a different query syntax and consulting their documentation is recommended.

* Amazon DynamoDB
  - npm install aws-sdk
  - AWS: https://aws.amazon.com/dynamodb (25GB + 25 RCU/WCU)

* Microsoft Cosmos DB
  - npm install @azure/cosmos
  - Azure: https://azure.microsoft.com/en-us/services/cosmos-db (5GB + 400RU/s)

* Google Firestore
  - npm install @google-cloud/firestore
  - GCloud: https://cloud.google.com/firestore (1GB + 50K/20K r/w@day)

* IBM Cloudant
  - npm install @cloudant/cloudant
  - IBM: https://www.ibm.com/cloud/cloudant (1GB + 20/10 r/w@sec)

* Oracle Autonomous DB
  - npm install oracledb
  - OCI: https://www.oracle.com/autonomous-database (20GB)
         https://www.oracle.com/autonomous-database/autonomous-json-database (Paid - 1TB)
// NOTE: Attribute "table" is required

interface CloudDatabase {
    table: string;
    value: string | ObjectMap<string | string[]>;
    name?: string;
    id?: string;
    query?: string | PlainObject | any[];
    limit?: number;
    params?: unknown[];
    options?: PlainObject;
}

/* AWS: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.html */
{
  "selector": ".card:nth-of-type(1) p",
  "type": "text",
  "cloudDatabase": {
    "service": "aws",
    "credential": {
      "accessKeyId": "**********",
      "secretAccessKey": "**********",
      "region": "us-east-1", // Endpoint specified (optional)
      "endpoint": "https://dynamodb.us-east-1.amazonaws.com" // Local development (required) 
    },
    "table": "demo",
    "query": {
      "KeyConditionExpression": "#name = :value",
      "ExpressionAttributeNames": { "#name": "id" },
      "ExpressionAttributeValues": { ":value": "1" }
    },
    "limit": 1, // optional
    "value": "<b>${title}</b>: ${description}" // Only one field per template literal
  }
}

/* Azure: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-query-getting-started */
{
  "selector": ".card:nth-of-type(1) p",
  "type": "text",
  "cloudDatabase": {
    "service": "azure",
    "credential": {
      "endpoint": "https://squared-001.documents.azure.com:443",
      "key": "**********"
    },
    "name": "squared", // Database name (required)
    "table": "demo",
    "partitionKey": "Pictures", // optional
    "query": "SELECT * FROM c WHERE c.id = '1'", // OR: storedProcedureId + partitionKey? + params?
    "value": "<b>${title}</b>: ${description}"
  }
}

/* GCloud: https://firebase.google.com/docs/firestore/query-data/queries */
{
  "selector": ".card:nth-of-type(1) p",
  "type": "text",
  "cloudDatabase": {
    "service": "gcloud",
    "credential": {
      "keyFilename": "./gcloud.json"
    },
    "table": "demo",
    "query": [["group", "==", "Firestore"], ["id", "==", "1"]], // where
    "orderBy": [["title", "asc"]], // optional
    "value": "<b>${title}</b>: ${description}"
  }
}

/* IBM: https://github.com/cloudant/nodejs-cloudant#readme */
{
  "selector": ".card:nth-of-type(1) p",
  "type": "text",
  "cloudDatabase": {
    "service": "ibm",
    "credential": {
      "account": "**********", // IAM and legacy credentials
      "password": "**********",
      "url": "https://<account>:<password>@<account>.cloudantnosqldb.appdomain.cloud" // OR: Service credentials
    },
    "table": "demo",
    "query": { "selector": { "id": { "$eq": "1" } } },
    "value": "<b>${title}</b>: ${description}"
  }
}

/* OCI: https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/adsdi/oracle-database-introduction-simple-oracle-document-access-soda.pdf */
{
  "selector": ".card:nth-of-type(1) p",
  "type": "text",
  "cloudDatabase": {
    "service": "oci",
    "credential": {
      "user": "**********",
      "password": "**********",
      "connectionString": "tcps://adb.us-phoenix-1.oraclecloud.com:1522/abcdefghijklmno_squared_high.adb.oraclecloud.com?wallet_location=/Users/Oracle/wallet"
    },
    "table": "demo",
    "query": "SELECT d.* from demo NESTED json_document COLUMNS(id, title, description) d WHERE d.id = '1'", // SQL: Column names might be UPPERCASED
    "query": { "id": { "$eq": "1" } }, // SODA
    "value": "<b>${title}</b>: ${description}"
  }
}
// Retrieval using ID is supported by all providers

{
  "selector": ".card:nth-of-type(2) img",
  "type": "attribute",
  "cloudDatabase": {
    "service": "azure",
    "credential": "db-main",
    "name": "squared", // Azure (required)
    "table": "demo",
    "id": "2", // OCI (server assigned)
    "partitionKey": "Pictures", // AWS (required) | Azure and IBM (optional)
    "value": {
      "src": "imageData.src", // Template literal syntax is not supported
      "style": [":join(; )" /* optional: " " */, "imageData.style[0]", "imageData.style[1]"]
    }
  }
}

Some queries use an optional parameters array (params) or configuration object (options) which is sent with the query when applicable. If you require this advanced usage then further instructions can be found in the database provider documentation.

When in development mode you can save read units by setting a timeout value for the DB cache.

// squared.settings.json

"cloud": {
  "cache": {
    "aws": 0, // No cache per reload
    "azure": 60, // 1 minute
    "gcloud": 86400 // 1 day
  }
}

Results are cached using the supplied credentials and queries will individually be cleared when the amount of time has expired.

Options: Development / Production

The entire page can similarly be transformed as a group using the "saveAs" attribute in options. Cloud storage can be used for all assets except HTML using the same configuration as element selectors.

squared.saveAs('index.zip', {
    removeUnusedStyles: false, // Use only when you are not switching classnames with JavaScript
    productionRelease: false, // Ignore local url rewriting and load assets using absolute paths
    preserveCrossOrigin: false, // Ignore downloading a local copy of assets hosted on other domains

    // All attributes are optional except "filename" for <script> and <link>.
    saveAs: {
        html: { filename: 'index.html', format: 'beautify', attributes: [{ name: 'lang', value: 'en' }] },
        script: { pathname: '../js', filename: 'bundle.js', format: 'es5+es5-minify' },
        link: { pathname: 'css', filename: 'bundle.css', preserve: true, inline: true },
        image: { inline: true },
        base64: { commands: ['png'] }
    }
}); 
// js | css | image | video | audio

{
  "selector": "script",
  "type": "js",
  "watch": {
    "interval": 100,
    "expires": "1h 1m 1s"
  },
  "process": [
    "bundle",
    "minify"
  ],
  "cloudStorage": [
    {
      "service": "aws",
      "bucket": "squared-001",
      "credential": "main",
      "upload": {
        "active": true
      }
    }
  ]
}

squared.copyTo('/local/user/www', {
    watch: true,
    saveAs: {
        script: { pathname: '../js', format: 'es5+es5-minify', watch: true },
        link: { pathname: 'css', filename: 'bundle.css', watch: { interval: 500 } }
    }
});
<!-- chrome -->
<script src="/common/system.js" data-chrome-watch="true"></script>

<!-- android -->
<img src="images/harbour1.jpg" data-android-watch="1000::1h 30m" />

File watching is available and uses HTTP HEAD requests to determine modifications. You can also watch any file that is served using HTTP on a different server or computer. The HTML page itself or any inlined assets cannot be watched since changes to the DOM structure requires a complete browser reload.

Asset exclusion

You can exclude unnecessary processing files using the dataset attribute in <script|link|style> tags.

<script data-chrome-file="exclude" src="/dist/squared.js"></script>
<script data-chrome-file="exclude" src="/dist/squared.base.js"></script>
<script data-chrome-file="exclude" src="/dist/chrome.framework.js"></script>
<script data-chrome-file="exclude">
    squared.setFramework(chrome);
    squared.save();
</script>

You can similarly prevent an asset from being downloaded or transformed using the "ignore" command.

<iframe src="https://www.google.com/maps" data-chrome-file="ignore" />

LICENSE

MIT

4.11.0

2 months ago

4.10.5

3 months ago

4.10.4

3 months ago

4.10.3

4 months ago

4.10.2

5 months ago

4.10.1

5 months ago

4.9.20

10 months ago

4.10.0

9 months ago

4.8.45

11 months ago

4.9.19

11 months ago

4.9.18

11 months ago

4.9.8

1 year ago

4.9.9

1 year ago

3.10.0

1 year ago

4.8.41

1 year ago

4.8.40

1 year ago

4.8.43

1 year ago

4.9.11

1 year ago

4.8.42

1 year ago

4.9.10

1 year ago

4.9.13

1 year ago

4.8.44

1 year ago

4.9.12

1 year ago

4.9.15

1 year ago

4.9.14

1 year ago

4.9.17

1 year ago

4.9.16

1 year ago

4.8.34

1 year ago

4.8.35

1 year ago

4.8.38

1 year ago

4.8.39

1 year ago

4.9.7

1 year ago

4.9.6

1 year ago

4.9.5

1 year ago

3.9.3

1 year ago

3.9.27

1 year ago

4.8.32

1 year ago

4.8.33

1 year ago

4.9.4

1 year ago

4.8.31

1 year ago

4.9.3

1 year ago

4.9.0

1 year ago

4.9.2

1 year ago

4.9.1

1 year ago

3.8.14

1 year ago

3.8.15

1 year ago

3.9.2

1 year ago

3.9.1

1 year ago

3.9.0

1 year ago

4.8.90

1 year ago

4.8.92

1 year ago

4.8.91

1 year ago

4.8.94

1 year ago

4.8.93

1 year ago

4.8.96

1 year ago

4.8.95

1 year ago

4.8.50

1 year ago

4.8.85

1 year ago

4.8.87

1 year ago

4.8.86

1 year ago

4.8.89

1 year ago

4.8.88

1 year ago

4.8.76

1 year ago

4.8.75

1 year ago

4.8.78

1 year ago

4.8.77

1 year ago

4.8.79

1 year ago

4.8.25

1 year ago

4.8.27

1 year ago

4.8.26

1 year ago

4.8.29

1 year ago

4.8.28

1 year ago

4.8.30

1 year ago

4.8.36

1 year ago

4.8.37

1 year ago

3.8.12

1 year ago

3.8.13

1 year ago

3.8.10

1 year ago

3.8.11

1 year ago

4.8.9

1 year ago

4.8.8

1 year ago

4.8.5

1 year ago

4.8.4

1 year ago

4.8.7

1 year ago

4.8.6

1 year ago

4.8.1

1 year ago

4.8.0

2 years ago

4.8.3

1 year ago

4.8.2

1 year ago

4.7.0

2 years ago

4.7.5

2 years ago

4.7.2

2 years ago

4.7.1

2 years ago

4.7.4

2 years ago

4.7.3

2 years ago

3.8.0

2 years ago

4.6.0

2 years ago

3.8.9

1 year ago

3.8.4

2 years ago

3.8.3

2 years ago

3.8.2

2 years ago

3.8.1

2 years ago

3.8.8

1 year ago

3.8.7

1 year ago

3.8.6

1 year ago

3.8.5

2 years ago

4.5.0

2 years ago

4.5.2

2 years ago

4.5.1

2 years ago

4.5.7

2 years ago

4.5.4

2 years ago

4.5.3

2 years ago

4.5.6

2 years ago

4.5.5

2 years ago

4.8.21

1 year ago

4.8.20

1 year ago

4.8.23

1 year ago

4.8.22

1 year ago

4.8.24

1 year ago

4.8.10

1 year ago

4.8.12

1 year ago

4.8.11

1 year ago

4.8.14

1 year ago

4.8.13

1 year ago

4.8.16

1 year ago

4.8.15

1 year ago

4.8.18

1 year ago

4.8.17

1 year ago

4.8.19

1 year ago

3.7.5

2 years ago

3.7.4

2 years ago

3.7.3

2 years ago

3.7.2

2 years ago

3.7.7

2 years ago

3.7.6

2 years ago

4.4.1

2 years ago

4.4.0

2 years ago

4.4.3

2 years ago

4.4.2

2 years ago

4.4.5

2 years ago

4.4.4

2 years ago

4.3.4

2 years ago

4.3.3

2 years ago

4.3.9

2 years ago

4.3.6

2 years ago

4.3.5

2 years ago

4.3.8

2 years ago

4.3.7

2 years ago

4.3.13

2 years ago

4.3.12

2 years ago

4.3.11

2 years ago

4.3.10

2 years ago

4.3.14

2 years ago

4.3.2

2 years ago

4.3.1

2 years ago

4.3.0

2 years ago

4.2.3

2 years ago

4.2.2

2 years ago

4.2.4

2 years ago

4.2.1

2 years ago

4.2.0

2 years ago

3.6.13

2 years ago

3.6.12

2 years ago

3.7.1

2 years ago

3.7.0

2 years ago

3.6.11

2 years ago

4.1.4

2 years ago

4.1.3

2 years ago

4.1.2

2 years ago

4.1.1

2 years ago

4.0.5

2 years ago

4.0.4

2 years ago

4.0.7

2 years ago

4.0.6

2 years ago

4.0.3

2 years ago

3.6.9

2 years ago

3.6.10

2 years ago

4.1.0

2 years ago

4.0.1

2 years ago

4.0.2

2 years ago

3.6.8

2 years ago

2.4.1

2 years ago

2.4.0

2 years ago

2.4.2

2 years ago

3.6.2

2 years ago

3.6.1

2 years ago

3.6.0

2 years ago

4.0.0

2 years ago

3.6.6

2 years ago

3.6.5

2 years ago

3.6.4

2 years ago

3.6.3

2 years ago

3.6.7

2 years ago

3.5.3

2 years ago

3.5.2

2 years ago

3.5.1

2 years ago

3.5.0

2 years ago

3.4.0

2 years ago

3.4.4

2 years ago

3.4.3

2 years ago

3.4.2

2 years ago

3.4.1

2 years ago

3.4.6

2 years ago

3.4.5

2 years ago

3.3.1

2 years ago

3.3.0

2 years ago

3.3.3

2 years ago

3.3.2

2 years ago

3.2.0

2 years ago

2.3.6

2 years ago

3.1.3

2 years ago

3.1.2

2 years ago

3.1.1

2 years ago

3.1.0

2 years ago

3.1.5

2 years ago

3.1.4

2 years ago

3.0.8

2 years ago

2.3.8

2 years ago

2.3.7

2 years ago

2.3.9

2 years ago

1.3.4

2 years ago

2.3.5

3 years ago

3.0.7

3 years ago

3.0.6

3 years ago

2.3.4

3 years ago

2.3.3

3 years ago

3.0.4

3 years ago

3.0.3

3 years ago

3.0.2

3 years ago

3.0.1

3 years ago

3.0.5

3 years ago

1.3.3

3 years ago

2.2.3

3 years ago

2.2.2

3 years ago

3.0.0

3 years ago

1.2.14

3 years ago

1.3.2

3 years ago

1.3.1

3 years ago

1.3.0

3 years ago

2.3.0

3 years ago

2.3.2

3 years ago

2.3.1

3 years ago

2.2.1

3 years ago

2.2.0

3 years ago

1.2.13

3 years ago

1.2.12

3 years ago

2.1.3

3 years ago

1.2.11

3 years ago

2.1.2

3 years ago

2.1.1

3 years ago

2.1.0

3 years ago

2.0.9

3 years ago

1.2.10

3 years ago

2.0.10

3 years ago

1.2.9

3 years ago

2.0.8

3 years ago

2.0.7

3 years ago

2.0.6

3 years ago

2.0.5

3 years ago

1.2.8

3 years ago

2.0.4

3 years ago

1.2.7

3 years ago

2.0.3

3 years ago

2.0.2

3 years ago

2.0.1

3 years ago

2.0.0

3 years ago

1.1.9

3 years ago

1.2.6

3 years ago

1.2.5

3 years ago

1.1.8

3 years ago

1.2.4

3 years ago

1.1.7

3 years ago

1.2.3

3 years ago

1.1.6

3 years ago

1.2.2

3 years ago

1.2.1

3 years ago

1.1.5

3 years ago

1.2.0

3 years ago

1.1.4

3 years ago

1.1.3

3 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.7

3 years ago

0.15.3

3 years ago

1.0.6

3 years ago

0.15.2

3 years ago

1.0.5

3 years ago

0.15.1

3 years ago

0.15.0

3 years ago

1.0.4

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.3

3 years ago

1.0.0

3 years ago

0.14.4

3 years ago

0.14.3

3 years ago

0.14.2

3 years ago

0.14.1

3 years ago

0.14.0

3 years ago

0.13.3

3 years ago

0.13.2

3 years ago

0.13.0

3 years ago

0.13.1

3 years ago

0.12.0

3 years ago

0.11.0

3 years ago

0.10.1

3 years ago

0.10.0

3 years ago

0.9.11

3 years ago

0.9.10

3 years ago

0.9.9

3 years ago

0.9.8

3 years ago

0.9.7

3 years ago

0.9.6

3 years ago

0.9.5

3 years ago

0.9.4

3 years ago

0.9.3

3 years ago

0.9.2

3 years ago

0.9.1

3 years ago

0.9.0

3 years ago

0.8.1

3 years ago

0.8.0

3 years ago