EzDevInfo.com

r.js

Runs RequireJS in Node and Rhino, and used to run the RequireJS optimizer

How do I use Backbone.js with Require.js (r.js), but resulting in 2 files after I optimize it?

I have followed the basic tutorials (results in one file after you run r.js)

The problem is, my main.js file at the end is 500KB. That's too big. I want to split it into two files.

I want to optimize my main.js file into two files:

  1. One that holds the front page and user profile pages, since they're most accessed
  2. One that holds all the other pages (ordering, account settings, profile settings, etc.)

Most people will hit the front page and user profile pages, and I want those to load quickly first (while having the other pages load in the background in the 2nd main file)

The problem is, I don't know how to do this. There are examples like this online, but these examples do not use Backbone. They don't cover how to deal with router and app.js

I'm confused...because I only have one app.js, one router.js...how can I split router.js into two files?

I don't know how to split my project up when dealing with Backbone.

Below is the code

HTML PAGE (the entry point for my Single Page Application)

<html>
<head>
    <script type="text/javascript" data-main='/media/js/main' src='/media/js/lib/requirejs/require-jquery.js'></script>
</head>
<body>
    Hello
</body>
</html>

Main.js

require.config({
    paths:{
        jquery: 'lib/requirejs/require-jquery',
        jquery_ui:'lib/jquery-ui/jquery-ui-1.10.3.custom',
        underscore: 'lib/underscore/underscore-min',
        backbone:'lib/backbone/backbone-min',
        backbone_viewhelper:'lib/backbone/backbone.viewhelper',
        text: 'lib/requirejs/text',
        birthdaypicker: 'lib/birthdaypicker/bday-picker',
        //more paths
    },
    waitSeconds: 30,
    shim:{
        'underscore':{
            exports: '_'
        },
        'backbone':{
            deps:[ 'underscore', 'jquery'],
            exports: 'Backbone'
        },
        'backbone_viewhelper':{
            deps:['underscore','backbone']
        }
    }
});


require([
    'app',
    'json2',
    'jquery_ui',
    'backbone_viewhelper',
    'bootstrap_js',
    'bootstrap_select',
    'birthdaypicker',
    'accounting',
    'numbersonly',
    'main_alert',
    'string_tools',
    'plupload',
    //more things here
], function(App){
    App.initialize();
});

App.js

define([
    'jquery',
    'underscore',
    'backbone',
    'router'
], function($, _, Backbone, Router){    
    var initialize = function(){
        Router.initialize();
    }
    return {
        initialize: initialize
    };

});

Router.js

define([
    'jquery',
    'underscore',
    'backbone',
    'modules/index/view',
    'modules/home/view',
    'modules/listings_search/view',
    'modules/profile/view',
    //more modules
], function($, _, Backbone, indexView, homeView,searchView, profileView){
    var AppRouter = Backbone.Router.extend({
        initialize:function(){
            _.bindAll(this);
        },
        routes:{
            '':'index',
            'home': 'home',
            'register': 'register',
            'login': 'login',
            'listings(/start/:start)(/num/:num)': 'search',
            'listings/create': 'listingsCreate',
            'listings/:listing_id/edit': 'listingsEdit',
            'orders/listings/:listing_id/create': 'ordersCreate',
            'orders/buyer(/start/:start)(/num/:num)': 'ordersListBuyer',
            'orders/seller(/start/:start)(/num/:num)': 'ordersListSeller',
            'orders/:order_id': 'orders',
            'orders/:order_id/messages':'messages',
            '*actions': 'defaultAction'
            //more stuff
        },
        index:function(){
            app_router_view.show(indexView);
        },
        search:function(start, num){
            var options = {
                filters:{
                    start: start,
                    num: num
                }
            };
            app_router_view.show(searchView, options);
        },
        static:function(template){
            app_router_view.show(staticView, { static_view: { template: template }});
        },
        profile:function(){
            app_router_view.show(profileView);
        },
        passResetCode:function(code){
            app_router_view.show(passCodeView, {'code':code});
        },
        //more stuff
        home:function(){
            app_router_view.show(homeView);
        },
        defaultAction:function(actions){
            this.navigate('/', { trigger:true});
        }
    });
    var initialize = function(){
        var app_router = new AppRouter;
        Backbone.history.start({pushState:true, root: '/'});
        $(document).on('click', 'a:not([data-bypass])', function (evt) {
            var href = $(this).attr('href');
            if(href){
                var protocol = this.protocol + '//';
                if (href.slice(protocol.length) !== protocol && href != '#') {
                    evt.preventDefault();
                    app_router.navigate(href, { trigger: true});
                }
            }else{
            }
        });
    };
    return {
        initialize:initialize
    }
});

As you can see , my entire app starts with main.js, goes to app.js, and finally goes to router.js.

How can I split this?


Source: (StackOverflow)

Using r.js to package a SPA application that loads views using 'text'

I'm attempting to build a SPA application (requirejs, durandal 2, knockout) into a single main-build.js file using grunt, and I'm running into serious issues with the 'text' plugin that durandal is using to load my views.

In dev, I'm successfully using 'text' to load views dynamically as per the standard way of building durandal apps. The difference is that I need to do some server side templating for the views and so they are actually being dynamically generated.

With that in mind I'd like to use r.js to package the apps models, view models and services (via the grunt-durandal plugin) into a single file, but to NOT package the views (.html) and still load them dynamically as needed.

In my grunt config, I'm using the inlineText: false option - which I have checked is suppressing the 'text!*' modules in the build. But when I run the application I'm getting:

Uncaught TypeError: undefined is not a function from inside text.load on the following line:

var parsed = text.parseName(name),
            nonStripName = parsed.moduleName +
                (parsed.ext ? '.' + parsed.ext : ''),
            url = req.toUrl(nonStripName), // EXCEPTION THROWN HERE

The module name being loaded seems to be correct (its a 'text!*' one) but beyond that I have no idea how to proceed to debug this issue. What am I doing wrong?

My grunt configuraiton is:

/*global module, require */

module.exports = function (grunt) {
'use strict';

// library that allows config objects to be merged together
var mixIn = require('mout/object/mixIn');

var requireConfig = {
    baseUrl: 'App/',
    paths: {
        'jquery': '../Scripts/jquery-2.1.0',
        'knockout': '../Scripts/knockout-3.1.0',
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions',
    }
};

grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jshint: {
        options: {
            "-W099": true, // allowed mixed tabs and spaces
            "-W004": true, // needed to avoid errors where TS fakes inheritance
            ignores: [
                'App/main-built.js' // ingore the built/compacted file
            ]
        },
        all: [ // run jshint on these files
            'gruntfile.js',
            'App/**/*.js'
        ]
    },
    // TODO: could add jasmine here to do JS testing
    clean: {
        build: ['build/*']
    },
    copy: {
        scripts: {
            src: 'Scripts/**/**',
            dest: 'build/'
        }
    },
    durandal: {
        main: {
            src: [
                'App/**/*.*',
                '!App/main-built.js', // ignore the built file!
                'Scripts/durandal/**/*.js'
            ],
            options: {
                name: '../Scripts/almond-custom',
                baseUrl: requireConfig.baseUrl,
                mainPath: 'App/main',
                paths: mixIn(
                    {},
                    requireConfig.paths,
                    { 'almond': '../Scripts/almond-custom.js' }),
                exclude: [],
                inlineText: false, // prevent bundling of .html (since we are dynamically generating these for content)
                optimize: 'none', // turn off optimisations - uglify will run seperately by grunt to do this
                out: 'build/app/main-built.js'
            }
        }
    },
    uglify: {
        options: {
            banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n' +
                '* Copyright (c) <%= grunt.template.today("yyyy") %> Kieran Benton \n' +
                '*/\n'
        },
        build: {
            src: 'build/App/main.js',
            dest: 'build/App/main-built.js'
        }
    }
}
);

// loading plugin(s)
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-durandal');

// only one grunt task
grunt.registerTask('build', [
    'jshint',
    'clean',
    'copy',
    'durandal:main']);
};

Source: (StackOverflow)

Advertisements

Dynamic require in RequireJS, getting "Module name has not been loaded yet for context" error?

Is there a way to define a module that "dynamically" load other modules in RequireJS? If yes, how the optimizer (r.js) understands how/when a module has to be included?

For example, let dynModules a module which defines name/path pairs:

define([], function () {
    return ['moduleA', 'moduleB']; // Array of module names
});

Another module is going to load modules dynamically, based on the array. This will not work:

define(['dyn_modules'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});

... gives me:

Uncaught Error: Module name "moduleA" has not been loaded yet for context: _. Use require([]) http://requirejs.org/docs/errors.html#notloaded

I can solve the error, but it's not "dynamic" anymore:

define(['dyn_modules', 'moduleA', 'moduleB'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});

Source: (StackOverflow)

Require.js and r.js include all dependencies even of submodules

I'm using require.js for the first time and all is working pretty for the moment. However, I started wanting to make a build. The idea is to create one file with ALL my js and templates. However, every time I use r.js it just includes the dependencies of my main module.

here is my app.build.js:

({
appDir: "public/javascripts",
baseUrl: ".",
dir: "build",
paths: {
    "hbs": "lib/hbs",
    "jquery": "lib/jquery",
    "Handlebars": "lib/Handlebars",
    "Backbone": "lib/backbone",
    "underscore": "lib/underscore",
    "bootstrap": "lib/bootstrap.min.js"
},
modules: [{name: "main"}],
shim: {
    "bootstrap": {
      deps: ["jquery"],
      exports: "$.fn.popover"
    },
    underscore: {
      exports: '_'
    },
    'Handlebars': {
      exports: 'Handlebars'
    },
    Backbone: {
      deps: ["underscore", "jquery"],
      exports: "Backbone"
    }
}}) 

the beginning of main.js:

require.config({
 paths: {
    "hbs": "lib/hbs",
    "Handlebars": "lib/Handlebars",
    "Backbone": "lib/backbone",
    "underscore": "lib/underscore",
    "jquery": "lib/jquery",
    "bootstrap": "lib/bootstrap.min.js"
  },
  hbs: {
    disableI18n: true
  },
  shim: {
    "bootstrap": {
      deps: ["jquery"],
      exports: "$.fn.popover"
    },
    underscore: {
      exports: '_'
    },
    'Handlebars': {
      exports: 'Handlebars'
    },
    Backbone: {
      deps: ["underscore", "jquery"],
      exports: "Backbone"
    }
  }
});

require(['jquery', 'Backbone', 'videos'], function($, Backbone, Videos) { // Whatever });

In this case the final file created in my build 'main.js' only contains: jquery, underscore, backbone and videos. How can I make sure it also includes the dependencies of the module videos namely: the template 'hbs!template/videos/show'. How can I also make sure that bootstrap.min.js is also added even though it's not required anywhere? Finally should I remove the require.config as it will define paths that are not supposed to be anymore as all the modules are in the final file?


Source: (StackOverflow)

single dependency across multiple modules - r.js "the following module share the same URL"

I have implemented requirejs across a multipage web application, which works fine but now I am trying to use r.js to create a single file of 'all' the modules except any of the third party libraries and frameworks such as jquery etc...

the broken down build file (build.js) looks like this:

({

baseUrl: "../",
out: "main-v0.1.js", //"charts-v0.1.js",

include: [


    "bi/jquery/jquery.ui.autocomplete",
    "bi/jquery/jquery.ui.combobox",


    "bi/ui/investmentselector"
],

wrap: true,

exclude: [
    'jquery', 'jqueryui', 'jcanvas', 'jqtools', 'prettyphoto', 'cssSandpaper', 'knockout', 'datatables', 'handlebars'
],
preserveLicenseComments: false,
optimize: "none", // "uglify", "uglify2"

paths: {
    handlebars      : 'lib/handlebars',
    /*hb runtime    : 'lib/handlebars.runtime',*/
    jquery          : 'lib/jquery-1.9.1',
    jqueryui        : 'lib/jquery.ui/jquery-ui-1.10.3.min',
    jcanvas         : 'lib/jcanvas.min',
    jqtools         : 'lib/jquery.tools/jquery.tools.min',
    prettyphoto     : 'lib/jquery/jquery.prettyphoto-3.1.5.min',
    BI              : 'bi/BI',
    sliderconnect   : 'bi/charts/slider-connect',
    cssSandpaper    : 'lib/csssandpaper/cssSandpaper',
    csstransform    : 'bi/enhance/csstransform',
    knockout        : 'lib/knockout-2.2.1',
    datatables      : 'lib/jquery/jquery.dataTables',
    // jquery ui widgets
    uicombobox      : 'bi/jquery/jquery.ui.combobox',
    uiautocomplete  : 'bi/jquery/jquery.ui.autocomplete'
}

})

The jquery.ui.autocomplete.js and jquery.ui.combobox.js files are custom jqueryui widgets without any define() wrapped around them. The module investmentselector.js (broken down) looks like this...

define(['jquery',
    'bi/templates/investmentselector.js',
    'bi/jquery/datatables/investmentselector.js',
    'lib/JSLinq/JSLINQ.js',
    'uicombobox', 'uiautocomplete'], function ($, tmp, datatables, jsLinq, uicombobox, uiautocomplete) {

    'use strict';


    var methods = {
        // ... code
    };

    return methods;
});

what I am getting when I run r.js to build the single file named 'main-v0.1.js' is this...

Tracing dependencies for: D:/Files/Trunk/BestInvest.Select.Website/js/build/main
-v0.1.js
Error: Error: Module loading did not complete for: bi/ui/investmentselector, uic
ombobox, uiautocomplete
The following modules share the same URL. This could be a misconfiguration if th
at URL only has one anonymous module in it:
D:/Files/Trunk/BestInvest.Select.Website/js/bi/jquery/jquery.ui.autocomplete.js:
 uiautocomplete, bi/jquery/jquery.ui.autocomplete
D:/Files/Trunk/BestInvest.Select.Website/js/bi/jquery/jquery.ui.combobox.js: uic
ombobox, bi/jquery/jquery.ui.combobox
    at Function.build.checkForErrors (D:\Files\Trunk\BestInvest.Select.Website\j
s\build\r.js:27237:19)

Any ideas as to what is going on?

FYI the widget code (broken down again) looks like this...

$.widget("bi.bicombobox", {
_create: function () {
    // ...code
},
_destroy: function () { }
});

and...

$.widget("bi.biautocomplete", {
_create: function () {
    // ...code
},
_destroy: function () { }
});

Any help on this would be greatful, Thanks!


Source: (StackOverflow)

How to share common client-side javascript across NodeJS projects?

I'm a Node n00b starting a couple web app projects using Express, and I've got some common client-side libraries I'd like to share between the two projects. This seems like a very common problem, so there must be several solutions available already.

I come from a java background, and in java, I'd create a separate "common" project and "overlay" common WAR over my project during packaging. This would also allow for r.js optimization during the build process.

My best guess in Node is that I need to create a private NPM module, and map those common files into express via a use() middleware plugin. Is that right?

How, then, can I package both my common and project specific javascript into a minified file using r.js?

Or is source control the answer? Checking out my "common" repository inside each project?

Any help would be most appreciated. Thanks.


Source: (StackOverflow)

Requirejs - Share the same dependency through different modules

Imagine this project scaffold:

  • utils.js
  • module1/controllers.js
  • module1/services.js
  • module2/controllers.js
  • module2/services.js

utils.js

define([], function(){  /* My utils functions */ });

module1/controllers.js

define(['../utils'], function(utils){  /* Module1 stuff */ });

module2/controllers.js

define(['../utils'], function(utils){  /* Module2 stuff */ });

This works very well in a non-optimization context, because utils.js is downloaded only once, no matter whether is from module1 or module2. However I need to optimize and package each module in a JS file.

In order to get this, I add a main.js file in each module, for example:

module1/main.js

define(['./controllers', './services.js'], function(){});

Now I start playing with the optimization tool, this is my app.build.js

...
modules: [
        { name: "module1/main" },
        { name: "module2/main" },
    ]
...

Ok, I get the behaviour I wanted, but I see that both modules include the utils.js code. This behaviour is right because you can't guarantee the loading order.

So, these are my questions:

  1. Does exist any smart solution for this?
  2. If this can't be skipped, does anybody know how requirejs works under the hood? Could this strategy generate any kind of problems?

Source: (StackOverflow)

parse error using esprima for file while optimizing js files with r.js

I am optimizing several js files into one using r.js. It works fine before. Recently,I modified some js code, add the code as:

var x = 08;

then it shows

ERROR:parse error using esprima for file D://webroot/js/a.js

ERROR:line 45: Unexpected token ILLEGAL.

Line 45 is where I add var x = 08, and 09 will show error too. It seemed that numbers begining with 0 meanwhile containing 8 or 9 is illegal. Maybe they were treated as bese 8 number .. ?

How can I let r.js ignore this point and still optimizie js files?


Source: (StackOverflow)

Exclude arbitrary files from RequireJS's r.js optimisation and load them async

I have RequireJS implemented fine, and a Grunt based build process which is optimising the JS app into one file via r.js which is also working fine. All my app files are concatenated into one for efficient production deployment.

The r.js optimisation is also including all my templates into the main app JS file too, which is also great for templates that will be needed as soon as the app boots up, or very soon afterwards. It's not so great for views that may never be seen, or perhaps be seen much later on in the app lifecycle, it'd be better if these templates were loaded async as needed.

So my question is this, is there a way to arbitrarily exclude my templates from being included into the monolithic app JS file and loaded async by RequireJS, or is this not supported? If it isn't supported what approaches are there for loading templates in async?

I'm using the tpl text template plugin and Backbone.Marionette. My template usage currently looks a bit like this:

define(function (require) {

    var Backbone = require("backbone");

    var tpl = require("tpl!./some-view-template.tpl");

    return Backbone.Marionette.ItemView.extend({
        template: tpl
    });
});

Source: (StackOverflow)

TableTools code giving DataTables warning message when application built with r.js

I am having a problem building an application that includes TableTools. I am using r.js and the build line is

E:\Software\nodejs\node r.js -o build.js

The build.js is

({
    baseUrl: ".",
    paths: {
            'jquery'  : 'jquery-1.9.1',
            'jquery-ui' : 'jquery-ui-1.10.3.custom',
            'jquery.dataTables': 'jquery.dataTables',
            'jquery.tableTools' : 'TableTools'
    },
    name: "build_main",
    out: "external.min.js",
    optimize: "none"
})

Note that I have flattened all of the directories to make it easier to investigate.

When I load my test application, I get the message

Warning: TableTools 2 requires DataTables 1.9.0 or newer ...

I am pretty sure that DataTables is correctly specified in the build. It would seem that when the check in the TableTools code is done DataTables doesn't seem to have been fully loaded/initialised. If I put a break point at the line

if ( typeof $.fn.dataTable == "function" &&

in external.min.js and then step through, it won't popup the warning. Datatables looks to have been correctly initialised just by putting in a breakpoint and stepping through. If I remove TableTools then everything loads fine - DataTables is there.


Source: (StackOverflow)

How to preserve sourcemaps from Babel transpiling to r.js uglifying?

I'm writing ES6 JavaScript modules and using Babel to transpile them to ES5. Babel generates sourcemaps that point back to the original ES6 code. I then use r.js to take those ES5 AMD modules and combine and uglify them. r.js creates a sourcemap that shows the ES5 files. I want the ES6 ones from the first step. My grunt file looks like this:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt); // npm install --save-dev load-grunt-tasks

  // Project configuration.
  grunt.initConfig({
    babel: {
      options: {
        modules: "amd",
        sourceMap: true
      },
      dist: {
        files: {
          "es5/editor.js": "src/editor.js",
          "es5/editor-events.js": "src/editor-events.js"
        }
      }
    },
    requirejs: {
      production: {
        options: {
          baseUrl: "es5",
          mainConfigFile: "es5/require.config.js",
          name: "../node_modules/almond/almond",
          include: ["editor"],
          out: "dist/ed.js",
          optimize: "uglify2",
          generateSourceMaps: true,
          preserveLicenseComments: false
        }
      }
    }
  });

  // Default task(s).
  grunt.registerTask('default', ['babel', 'requirejs']);

};

It compiles everything perfectly. But it loses the nice ES6 sourcemaps. Any way to keep them? Is there a better build process that'll get me to a single, browser-friendly JavaScript file?


Source: (StackOverflow)

RequireJS - exclude by directory (or regex)

This is a portion of my build configuration for requireJS's optimizer, r.js.

exclude: [
    'widgets/cr-log-display',
    'widgets/cr-pager',
    'widgets/cr-time-input'

My question is simply this: is it possible to exclude ALL dependencies starting with widgets/.

The docs don't seem to indicate that a regex, or anything similar can be passed here. Is there another configuration parameter that I'm missing?


Source: (StackOverflow)

How to exclude urlArgs from build using r.js

I use r.js optimizer to combine js files based on build profile as it's suggested in documentation. Here's my build-config.js:

({
    baseUrl: ".",
    paths: {
        jquery: '//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
    },
    name: "main",
    out: "main-built.2013-07-30.js"
})

As you can see it's based upon main.js file, here's a code of it:

requirejs.config({
    baseUrl: 'scripts',
    urlArgs: "bust=" + (new Date()).getTime(),
    paths: {
        jquery: [
            '//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
            'lib/jquery-1.9.1.min',
        ],
    },
});

require([
    'layout',
    'cue',
], function() {

});

If I preserve urlArgs: "bust=" + (new Date()).getTime() in main.js all external files (here jquery which is loaded from CDN) look like .../jquery.js?bust=1377412213

So it's PITA to comment out this line every time I make a build. I've read through all the documentation and googled for a solution but everything in vain. Maybe I do it wrong?


Source: (StackOverflow)

RequireJS: optimize scripts and include RequireJS itself in it

I have a complex JS-project that is written in AMD form. It uses RequireJS.

My system should be able to include it's functionality to different external sites. I want to compile it to a single js-file and include it like this:

<script type="text/javascript" src="http://mysystem.com/core-build.js"></script>

I don't know if an external site has requirejs or not, that's why it seems that requirejs itself should be included into core-build.js. Compiled file should be completely independ on the environment.

From the other side, it should not redefine an external site environment. My system uses jquery, knockout, and theese libraries should be defined locally for my system purposes only. They should not affect the site's global namespace.

So my question is how to optimize scripts to one file, include requirejs itself in it and wrap everything into a local namespace?


Source: (StackOverflow)

Require.js optimizer supposed to copy all files over into the output directory?

I am trying to integrate the r.js optimizer on the server side (Apache Sling) and face one problem: when resolving modules it always looks them up under the output directory (dir), not from within the source directory (baseUrl or appDir), doesn't find them and thus fails.

/project/build.js

({
    name: "modules/main",
    dir: "/target",
    baseUrl: "/sources"
})

If you wonder, the root path / is inside the server's JCR repository, not a file system. Also I simplified the example a bit (hopefully without concealing the issue).

It will resolve and read the main file properly:

/sources/modules/main.js

require(["modules/foo"]);

However, when it now tries to resolve modules/foo, it tries to read it from /target/modules/foo.js instead of /sources/modules/foo.js as I would expect, which does not exist and the whole r.js execution fails and stops.

I tried using appDir and all kinds of combinations, but the issue is always the same. I am fairly sure it is not related to my integration code... AFAIU from documentation and googling around, it should either copy them to the target before building the optimized file or simply pick them up from the source directory automatically.

  • Am I supposed to copy all the raw source files to /target myself before running r.js?
  • Maybe the problem is that baseUrl=/overlay is different from build.js residing inside /project?
  • Maybe r.js also looks at the current working directory of the r.js process (which is so far undefined in my case)?
  • Can the output directory (dir) live outside appDir or baseUrl?

Source: (StackOverflow)