{"_id":"verbotenjs","_rev":"58-cc0a4cae955f7bc8460ad3205710ab83","name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","dist-tags":{"latest":"1.2.10"},"versions":{"0.0.1":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"0.0.1","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"VerbotenJS Development Framework\r\n================================\r\n\r\nBecause everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n\r\n\"Maintainable JavaScript: Don't modify objects you don't own.\" - Nicholas C. Zakas\r\n\r\nI, Marcus Pope, by imperial proclamation hereby declare ownership of Object.prototype.  As sole owner I am the only\r\nauthorized person to modify the prototype definition.  Nope, too late I already called it and double stamped it.\r\nYou can't tripple stamp a double stamp!\r\n\r\nWhat Is VerbotenJS?\r\n-------------------\r\n\r\nVerbotenJS is a general application development framework desined for NodeJS & Browser JavaScript hosts.  In addition\r\nto a bunch of base prototype enhancements and terse programming patterns, the framework also includes extension libraries\r\nfor various domains such as databases, filesystems, shell scripts etc.\r\n\r\nVerbotenJS strives to abstract the minutia of JavaScript development into helper functions on the various base prototype\r\nchains like Function, Date, Number, Object etc.  I also tend to normalize interfaces between async and sync nodejs functions\r\nby checking for the existence of a callback argument.  \r\n\r\nWho Should Use VerbotenJS?\r\n--------------------------\r\n\r\nNobody, it's verboten remember?!? No I'm kidding, you can use it for any personal project you want.  I don't recommend\r\nusing it for production systems since it is version 1.0 and I'm just one man trying to support his own personal JS\r\nframework.  I'll probably change framework logic on a whim too, because that too is considered verboten right?\r\n\r\nWhat If I Wanted To Create A Commercial Product?\r\n------------------------------------------------\r\n\r\nWell, let's talk licensing and target market.  But really you should probably wait until 2.0 at least before considering\r\nsomething for production.\r\n\r\nWhy Is VerbotenJS 750k Uncompressed, and do you really expect me to download that to a client?\r\n----------------------------------------------------------------------------------------------\r\n\r\nNo, I don't, it's verboten to do so remember? Actually here's the deal.  jQuery is not compatible with Object.prototype\r\nextensions.  I had intended on releasing my own DOM, Event and Ajax wrapper but I ran out of time.  So I decided to\r\ninject a forked version of jQuery which added almost 350k to the footprint. My DOM wrapper will probably put the library\r\nin the 500k realm for browser hosts.  For NodeJS hosts modules are dynamically included on access so the runtime memory usage\r\nrequirements are dynamic based on the modules you use.\r\n\r\nBut by today's standards 750k is not really that bad except for mobile devices and cellular networks.  If you must you\r\ncan compress and gzip it down to 75k but with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\nBut I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n---------------------------------------------------------------------\r\n\r\nGood for you.  Play around a little, find out how good it feels to be bad for once in your life :D\r\n\r\nWhere Do I Start?\r\n-----------------\r\n\r\nFirst grab a copy of verbotenjs from npm.\r\n\r\n    npm install verbotenjs\r\n    \r\nIn node hosts use:\r\n\r\n    require('verbotenjs');\r\n\r\nFor browser hosts include a reference to this file\r\n\r\n    [verbotenjs]/web/verboten.js\r\n    \r\nI Kinda Like Where This Is Going, How Do I Help?\r\n------------------------------------------------\r\n\r\nWell, I'm not really in a position to coordinate a team of developers at the moment.  I have a newborn daughter and a\r\nfull time job, so to avoid the frustration of not hearing from me for a few weeks at a time, which totally happens, send\r\nme small patches, <500 lines, and I'll review them.  Since I doubt this will be much of an issue either way, I'll leave\r\nit at that for now.\r\n\r\nWhat's In Store For The Future Of VerbotenJS?\r\n---------------------------------------------\r\n\r\nJesus, what isn't in a state of almost complete!  Documentation, Bugs, Dom.js, Cross Platform Compatibility, JSDom,\r\nUnit Tests, etc.  You know, all the stuff you'd expect from a professional open source project.  The same stuff you'd\r\nexpect to be missing from a project named VerbotenJS.\r\n\r\n\r\n\r\n\r\nDocumentation\r\n========================================================================================================================\r\n    Node Framework: http://nodejs.org/docs/latest/api/index.html\r\n\r\nFonts used for prototype headers\r\n========================================================================================================================\r\n//http://www.network-science.de/ascii/\r\n   - Using \"Slant\" font\r\n\r\nThings to do for VerbotenJS\r\n========================================================================================================================\r\n    Array.prototype.thread = function(f, status_handler, params, callback) {\r\n        //I've had this idea for a while now, since web workers now exist this is probably a less than ideal solution, but it could\r\n        //serve as a worker shim maybe?\r\n\r\n        //This is some pseudo code for implementing threaded processing in a browser\r\n        //A suitable counterpart to threaded server side operations in node,\r\n        //when the client needs to process millions of records quickly\r\n        //essentially map reduce via popups\r\n        //not all supporting functions are built or built to spec for this to work\r\n\r\n        var x = this.inGroupsOf(this.size().squared().limit(200)); //100,000 == 36, 100,000,000 == 81 up to 200 browsers\r\n\r\n        var threads = [];\r\n        x.ea(function(g, i) {\r\n            //spawn each browser with a bootstrap of the q framework\r\n            threads.push(window.open('thread' + i, 'qbootstrap.html'));\r\n            //create special eval async function that passes a stringified version of the function to run\r\n            //and the group of data to run it on to the child browser window for processing\r\n            threads.last().evalAsync(f.toString(), g.toString()); //async eval occurs in child window\r\n        });\r\n\r\n        var res = [];\r\n        var remaining = threads.length;\r\n\r\n        var id = setInterval(function() {\r\n            //check on results ever second or so\r\n            threads.ea(function(t,i) {\r\n                if (t.finished) { //evalAsync function should set global finished & result variables\r\n                    res[i] = t.result; //get result from child processing and insert into original index\r\n                    t.close(); //close browser\r\n                    remaining--;\r\n                }\r\n            });\r\n\r\n            if (remaining <= 0) {\r\n                //don't need to check results anymore, all browsers are closed\r\n                clearInterval(id);\r\n                //now reduce the results into a flat array\r\n                callback(res.flatten(1)); //but only flatten the first layer\r\n            }\r\n        }, 1000);\r\n    };\r\n\r\n\r\nCoding Standards:\r\n========================================================================================================================\r\nGood:\r\n    if (test == 1) {\r\n        return msg;\r\n    }\r\nBad:\r\n    if (test == 1) return msg;\r\nReason:\r\n    Setting a break point to inspect msg when test == 1 is difficult when they are on one line.\r\n    Having curly brackets ensures future code modifications are understood and doesn't cost much.\r\n\r\nGood:\r\n    (function() {\r\n        //self executing function\r\n        var x = 1;\r\n    })();\r\nBad:\r\n    var x = 1;\r\nReason:\r\n    'x' is public meaning others can modify it or you could be modifying someone else's x if they used it already.\r\n    Global namespace collisions can be reduced by wrapping a self executing function\r\n\r\nGood:\r\n    var x = function() {    };\r\nBad:\r\n    var x = function() {    }\r\nReason:\r\n    Missing semicolon on function assignment can cause code to fail in ways you probably wouldn't expect.\r\n    This will throw an exception:\r\n        var literal = {\r\n            say: function(msg) { alert(msg); }\r\n        }\r\n\r\n        (function() {\r\n        })();\r\n    Unless you add a semicolon to the literal object definition.\r\n    And the error you receive is \"undefined is not a function\" on the last line at the start of the open paren.\r\n    \r\n    For a great explanation of semicolon insertion rules see this article:\r\n    http://mattbriggs.net/blog/2012/04/16/why-i-dont-use-semicolons/\r\n\r\nGood:\r\n    for (var x in obj) {\r\n        if (obj.hasOwnProperty(x)) {\r\n            //use obj.x\r\n        }\r\n    }\r\nBad:\r\n    for (var x in obj) {\r\n        //use obj.x\r\n    }\r\nReason:\r\n    Prototype extensions will be included in the second for loop.  You most likely did not want those references\r\n    if you are just trying to access the properties associated with just the object.  Ideally you would not iterate over\r\n    objects to begin with, but alternatively you should just use the .ea iterator method which handles this for you. In\r\n    the event that you do want the prototype introspection, then by all means continue to use it.\r\n\r\n---------------------------------------\r\n\r\nAlternative:\r\n    Object.prototype.hasOwnProperty.apply(obj, key);\r\n\r\nReason:\r\n    Although many will tell you to do this to avoid problems with a person overwrites hasOwnProperty on a local object, that's\r\n    a bad reason.  If anyone were to override the hasOwnProperty() method on an object it's probably for a damn good reason.\r\n    Bypassing this option would be like preventing a function from being overriden in a subclass.  And while strict proponents\r\n    think this is ideal, the entire premise of dynamic overrides is that you can temporally adjust what is considered a local\r\n    property of an object simply by overriding the hasOwnProperty method and selectively including or excluding specific keys.\r\n    \r\n    The real reason to do this is because not all objects inherit from the Object.prototype chain in JS.  IE is notorious for this\r\n    design when it comes to DOM and COM objects.  But applying the Object.prototype method to the host object will still work as\r\n    expected.  \r\n\r\n---------------------------------------\r\n\r\nJust Bad:\r\n\r\n    (function(undefined) {\r\n        //locally overwriting undefined to be undefined.\r\n    })();\r\n\r\nReason:\r\n    In the event that a programmer wants to temporally alter the value of undefined, they can do so because JavaScript is\r\n    dynamic.  Precluding this option makes your code less dynamic.  You should probably be using another language if that's\r\n    what you want.  In the event that someone alters the value of undefined and your code breaks, this is obviously the fault\r\n    of the coder, not you.  So don't limit the coding options for those who would use the dynamic nature of the language for good\r\n    use because someone might hang themselves.\r\n\r\nGood:\r\n    var i = parseInt(\"08\", 10);  //let's assume 08 was part of a date string\r\n    //i == 8\r\nBad:\r\n    var i = parseInt(\"08\");\r\n    //i == 0\r\nReason:\r\n    parseInt does not always assume a base 10 radix.  In this example it will assume 08 is octal (base 8) which doesn't\r\n    have an 8, so it results in 0;\r\n\r\nGood:\r\n    function() {\r\n        var myVar = 'local';\r\n    }\r\nBad:\r\n    function() {\r\n        myVar = 'local';\r\n    }\r\nReason:\r\n    Always use var to define a variable, in the second case a global myVar will be created instead of a local myVar.\r\n\r\nGood:\r\n    var x;\r\n    if (FB && FB.api && FB.api.getCurrentUser) {\r\n        x = FB.api.getCurrentUser();\r\n    }\r\n    ----------or------------\r\n    try {\r\n        var x = FB.api.getCurrentUser();\r\n    } catch(e) { }\r\nBad:\r\n    var x = FB.api.getCurrentUser();\r\nReason:\r\n    Always check an object chain before accessing its children or calling a function.  If FB isn't defined,\r\n    accessing FB.api will throw an exception.  And if FB.api is defined, but getCurrentUser is not, calling it as a\r\n    function will also throw an exception.  Alternatively you can, and in the case of Facebook probably should, EAFP\r\n    (Easier to Ask Forgiveness than Permission) or just try catch the exception.  \r\n\r\nGreat References:\r\n========================================================================================================================\r\n    http://kangax.github.com/nfe/\r\n    http://perfectionkills.com/\r\n    http://bonsaiden.github.com/JavaScript-Garden/\r\n    \r\nInteresting Reads:\r\n========================================================================================================================\r\n    https://github.com/BonsaiDen/JavaScript-Garden/issues/84\r\n    http://perfectionkills.com/category/ecma-262/\r\n\r\nTroubleshooting:\r\n========================================================================================================================\r\n    Object Prototypes you should avoid overriding\r\n        Object.prototype.sort = function() { }; //messes with mongodb in node.js\r\n        Object.prototype.toString = function() { }; //messes with jQuery & other internals\r\n        Object.prototype.set = function() { }; //messes with require('child_process');\r\n        Object.prototype.size = function() { }; //breaks node.js url.parse method ??? weird.\r\n        Array.prototype.reduce = function() { }; //map reduce much?\r\n        Array.prototype.map = function(f) { };\r\n","_id":"verbotenjs@0.0.1","dist":{"shasum":"8dd2887a1ce67e29b5229d6155b2660231981dc6","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-0.0.1.tgz","integrity":"sha512-cC3cABI0MRa/AF6P+JNLdNmnBJ179D3MUVjeQX6Dc03yVXBg8XgKgLWcTnqsMT3P/p78+/DfMfrtgQt7ma/fiw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDTw+gdYum07dfN/26zA8RFpaaKKz8PRyIOEsmjfGfzAgIgJrNq43RE6k2bwgasgl6/YVG7C9NDfr4sX7jIuPJnxHM="}]},"_npmVersion":"1.1.62","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}],"directories":{}},"1.0.0":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.0","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","_id":"verbotenjs@1.0.0","dist":{"shasum":"72d21e75531b5eda42194d4a6f9774ee45a230a0","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.0.tgz","integrity":"sha512-GMdlO8JDiqRoH0OOVPG29ijNKuKF9vpzM+knYl/SsWmo4L2ssVctUMVDeikhqsTTEkDeNlF5VHPosCUaXBAIyg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDsSr1y6eHsismPICWkA2YYfYSdkDhm2BRatLail4A5mwIgUPM7oVBSBr3bLJ0qWbNRkBkC7H+5WR+xZwUDmaBLe4I="}]},"_npmVersion":"1.1.62","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.1":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.1","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","_id":"verbotenjs@1.0.1","dist":{"shasum":"2b69e7af9e420f93a5ab1c7aa5e0580cf17ef81c","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.1.tgz","integrity":"sha512-xc2BhqrPKKimeU6zRRbj3RhBpdXsDc/HqFPB/Bzlf1SUNvF2rEvbVz+MZNAX6Rw2f1jZ9qDp310il8dyA3w3BA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHJz3InuM8kUsGrfYc893BA9155ubVL2PNBsqvTSPjhqAiBaXlp+xjv7PgjPqTrPin1Mjbd+Z0AhtDhakp9RtZs6VA=="}]},"_npmVersion":"1.1.62","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.2":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.2","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.2","dist":{"shasum":"e3877da915a2cbd2282cc2c9aff613a4e80548e1","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.2.tgz","integrity":"sha512-a74sXuHPLAGCsdPXwyt725Hjfaq2jM7TOEyxW+srl1vqcfq1XqU3yZNTTy33B5myfkHsLN0q/B0TNgsygPloSA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDDeAqdd6GZgavrtx9fSCxmKgAw5Bx1ITOtq7dcCE1asAiEAwI/HYEwZwwsCBcOhx8dgNdo4hmV4WJJ5El3MFXro0Cw="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.3":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.3","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.3","dist":{"shasum":"61d0352ac273d685d83dfd452d6fde0e4fc70625","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.3.tgz","integrity":"sha512-NIn93C3kIar4TEVR1le+bVzP7rWEPeWa0gW97rJ5zHdJxvHBaCTriDKdDxxRbDRDYSAhG2Ejl3CRqamNrFs2+w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpXz1yxsm7ZzcLPoqqXb6oNwXW6nd/AzYSAp0g509nrgIge5ahUjPtQUYX9lqjjL1uu+LoEwc4XfPwagq3g1zbRsg="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.4":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.4","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.4","dist":{"shasum":"487eb1517d15325a1a9c806afae56eb3d6787a8c","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.4.tgz","integrity":"sha512-kO+Wpr6i9kJrWsalfwQ4NrW05FKTHV/aZuJ3bMaewCqzMrpf9wd9jiGEyVP+/lSQItL4S7Vz8NssWUqVbG+LUg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTSL4StOJZQzJPFY9VP6RzuKmhsNCRIsJIempMrOXGagIhAOVRlvTisug38uGZXuqOIWshuDhedIxZefJK8xdYjLdI"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.5":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.5","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.5","dist":{"shasum":"04c2f2f4693917d0f8df4dc98fa6e8962458db7d","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.5.tgz","integrity":"sha512-9zr70sFwEiOfuHSwOZYGGIMrJ1z0kHAbJ2IcW/4spCUjXbwc/LS8Z41kESIELlrALb0fILfwWmWgeIeKhSzO5Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCZ0AZRqZwzDnY+Kd9D4tmp/MTr53iq+wpBR7nQSa2XqwIhAMeI7NgCwM4XVKiFS5Xd4OX/VFdFiExCl6LaRsboU2yc"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.6":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.6","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.6","dist":{"shasum":"9e27124682fa1935762e99249e4ac6e2c7e573ce","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.6.tgz","integrity":"sha512-vuie90VDs9dtQ6M9A+OeFpNEO5y9ND0F8xmZuqbCPBGgO22XRQOygjYJXYIysHpocUCoXbZhu4XWowJnX0bpCw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBCmIjdeVpRXYGKgcxhdNDZYJHqpj/CCFdiV9jVk6RMuAiBG71UBDus5MkecvaG91CLuV2ZPN1NLbE2tfbjOxhBEHw=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.7":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.7","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.7","dist":{"shasum":"11316198c0ec296bebadc5ecd84a8e07c703c99e","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.7.tgz","integrity":"sha512-BBpdV9HskQCi0r2nxO6dSugEA9lss/cs+QEHjGHw1nEtb0rinQZQi0Jxj51J/nN5qszrxRQ0Tl09/BTpVKXHuw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3n7TxJQfWmVB45x8Re2HNpTN7DuvoXGXutG1dfwlhMgIhALW++6gDCX3HPjvS5LVlkWDSoZnhK2HiI8TJVLuX/MRB"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.8":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.8","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.8","dist":{"shasum":"34367f9537221e6258af7cb05ba7878093f079de","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.8.tgz","integrity":"sha512-AOqI0Y3TR2/wVeJ4dmLUBXKQ7A/znkURYVqDQi2xaGUrSxZY23tbdAvo+xAh6lwa/Sp6BELbXvtW61L6l/ETdg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+3jxC8fSoQBcSodFZTM/n/rlpjjYPWH5bGc8g/NtZkAIhAMrLMy2/hTesqUUxtX0PqbgJv58G98wBCmVUgwzZwz74"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.9":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.9","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.9","dist":{"shasum":"2b448ecb99d74fc269284e18bda24186f50ed6f0","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.9.tgz","integrity":"sha512-l6gZ7sQR/ZRsU4NKJHZKsOTxJYsRxsTICDA5df9tzkHp9ntTb0HWGbZIEGmihzIHZnuJyBtofk+uE4Vu0eLWKQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCGvF7h+Ef07LTw0TPjnV/8GP1w3887XuA7q/xifDteEgIgIrPf88Fx98udReOl+baqsQQpT3ijuVHAsua0AuupQko="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.10":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.10","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.10","dist":{"shasum":"fb0ca536a6122739a507bfe0eacda79cba55efc0","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.10.tgz","integrity":"sha512-JIleznIoPFJft7qqvkPjrO2Zgr0aJXKlgx6s3aiOUHA/XjmRhCAxOXs5KGUAJGlyrpAxbGiPIm0ie7tm21888w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD68/o6z6r8EA/iH4N/d/TYzd9UrMGzjDxAyeVGDgJJ0wIgKYsSIJKyhDwvdT5Ri2NJjiVRgJ0EBcI0c2KN6WYRm3M="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.0.11":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.0.11","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.0.11","dist":{"shasum":"bf50479472f5683f3353f84cbbb82c121612a05f","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.0.11.tgz","integrity":"sha512-FKPEh0XsLS8ZFsUu4281BNunFHJc8leyzGKVRiobYsyflqQwU77UvaG3V4vCnYefSEvuxm5UWwvLxJifb0rUTg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCr6iwP/fMntGvy9rcGJFPMRzdkVNLE9imZSdSZd3fcdwIgcFhX2h3lL7yE+i9OY/hxHjfenS9jKG/I8yW4waqHaBQ="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.1.0":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.1.0","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.1.0","dist":{"shasum":"c11e7bf94ad6bb5b9ac02f67ebe2f803b5b7d55f","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.1.0.tgz","integrity":"sha512-JYRDV0UIC3PWblxRmqGilcKhR+zg4d+cb55qylOZLz8SnONUeOEc/B05LQ4obOI4t/rMB51rr7ydut5oqUAX7g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICBgKlgTGP0hdLMt5+ovF5V6rc61BYjGJpp6ScPB5WBKAiB0MfCYb64beaFc+eHi0uW1Bn0CvOuNeWCS0uvpVeHnmQ=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.0":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.0","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.0","dist":{"shasum":"23d06f6cf4d9eea75ca858c0216f434ddcb10aef","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.0.tgz","integrity":"sha512-oWLF7Ar0ykl+/HhFFjoZnuqNF/5JrV2Vi7SPRSMLlPNp3JiTERM1ZbB6cQ3yyQoZ2VSs57FjHIwq64/2SIElkQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCS6z3Flr4IOfCSGH9JwcARo5/MsF++Ikv0eDiax3hpLwIgBufjxp6bhIyvCNIrnk/5GEMgvzQ/gvo3wIfMIlmc3ZE="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.1":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.1","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.1","dist":{"shasum":"239d23febce3b9dd323011e9a68b8924b2daade7","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.1.tgz","integrity":"sha512-+1BmV9O1CGxBJ20aJh9f1tLIkX5yKHroBzRmE7yUrJiw/j938y7TifV6tC+VPHoe162aRO+je1nZNS7giyRB2w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDFJcO22cLpFCGCpgoAU8x2vlZ67jSxYY/29TYAkSffsAiB+q7GnunnSN21fI63g2lau3SEGa3aVDAnrC04QCVdaTQ=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.2":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.2","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.2","dist":{"shasum":"b7ab6eddc2feeffb1be09e5e67b26a697abab122","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.2.tgz","integrity":"sha512-meNGivSZ6rQobcYa/8DxZNy8Fs7iD/U6QLLT3vd0dadzmYqvNsCUaQ3WNWVGpwJPVAvQkP76DilV4P0emFYGCQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCL7CHakF2aYc7q9V3qjk8ucIAJ7xbQ8mLSC139UO++VwIgbj4GtsFIjxGN+AIfPNpD6oiueGix24X+JIm8XzShPJI="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.3":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.3","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.3","dist":{"shasum":"f999b2f4543456b076f25b9cdecaa26e08183650","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.3.tgz","integrity":"sha512-gxpkNP/CqSGD79bDoLuu5uy18XZpZfgPXHoV9XhPdWxO6kX9WK3sJTo4ZdphPi3E6MdTNwN8/GiUBloZLAtUfA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAiCv7YU/pFnONeJZZgv5zMOfwF3bDeTvgX05IRJSlaXAiEAn9YWVMUhE32HPK73YMbxoEZy8u2KphnZRMwv1Fms/4I="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.4":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.4","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.4","dist":{"shasum":"ec5ffd604973a25a6eb20d25c5fce4dde9da4c20","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.4.tgz","integrity":"sha512-pPPM2EZpOiw00ZT2rinFlj6DV1MOWk2KxAHlJNDnT7xPDemO3vEAMNygQEW2RQAmy+B5dKVhySnXk4XfE2/Xjw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDS3jT7nhqmTUHKrrfD8T18Zf7aonroMxWLLEqNz1MI8AiBj1YjLl35uiXPgJqHyQZJGZGNjONM95CUDj33dQOXTZw=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.5":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.5","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.5","dist":{"shasum":"19ef7c587d96c43cc7d8cbc77f8fbc97976787c1","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.5.tgz","integrity":"sha512-sxaZmxb1yMtTFUeHXwafG4hTd0+ucBj/5Td0yAo7xt+dh3k8MkWzFFiQuic4M/s8RqFDw+w308WUg222bbtmmg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICZiJ2/Z/adlZxR74+W/4DaB65oJZh+ZMkPSZD+2V8sGAiEAs0aKR6ab8iS/vPE6JwPWCxRsYgTRgBrFj/hPzmeNYNU="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.6":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.6","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.6","dist":{"shasum":"74bb0aeaf002cfc5c75c9bd02b1d70cfed631a85","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.6.tgz","integrity":"sha512-3BSYll8d4eKGVzPRXPIuFSfpOkdSdeENp5rHEQwDOeFNBo949nwegKz7q/IxkAUR8BYb6ENZgyqVo6XqqXiORw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDcMrFrOPXaKgKaXcK7esg6oKSOErTyQwZEIGLi4rXt5AIhANTDwOhcWqyAU7X6nkMLTzm9bwGVB/aAQ7AZdPBIaRWu"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.7":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.7","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.7","dist":{"shasum":"6b13decf3b503732c78a24f7d4c9541b09c0d1b2","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.7.tgz","integrity":"sha512-RqY4bcQNCciaialErVnP3244cdvbTTNHjTjlVym2JO4SZzP1Dq5ytBc0JfIrVRxZ0SFvKSJ9CfJ8mkemC6I+EA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB4ovwpVFEb75OvRLkGEFIlQYjXnx6/erLrACZhp+5y5AiBrHGu2XbXRLNfgFevs/9E7abPeyG0fgz61vQYgyaAteQ=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.8":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.8","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.8","dist":{"shasum":"e9e05b8f325be15af970ff4ce952eda86a76d052","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.8.tgz","integrity":"sha512-QMBRKMGbC+qTYmQePZw7kDbo7mJTOTqiQ4FX/yltPAS28VxttjdLQh2QjV50uBV5wXKh5x9tQWXkvCpXLxo27A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEYg+pW+eb2hSFTJmA7Nm2bGDgzNc3/EqJ+u7anEKlFOAiEArmI+UuMYIUlkRCcsPzHWZ/KSQ9xC1Kv4KyKBfabB+1U="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.9":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.9","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.9","dist":{"shasum":"de1ce91274729caecad7f50bef6a44595f265699","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.9.tgz","integrity":"sha512-n/glB3n2sR8TkTSLDPP5UdT6DjSah9kR8PTecDzw56IdZWU3yFGdwE9DB7SW2IW9rmSsVoAbkw6LnrDevz6kuQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGvfaihb/2nlMyukrtvR7LuiJIqcpl0pxnb5CFD7PAJEAiEA8aelsa+p9AQ8XRVkeVj9erOgQiCUUCrH6cQyZNQ7twQ="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]},"1.2.10":{"name":"verbotenjs","description":"A general application development framework for node.js, browsers, and other hosts","keywords":["verboten","verbotenjs"],"version":"1.2.10","main":"index.js","files":["lib","web","index.js","license.txt","readme.txt","package.json","verbotenize.js"],"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"homepage":"http://www.verbotenjs.com/","contributors":[],"dependencies":{"esprima":"*","falafel":"*","escodegen":"*"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"bugs":{"url":"https://bitbucket.org/marcuspope/verbotenjs/issues"},"engines":{"node":">=0.8.0"},"licenses":[{"type":"Creative Commons BY-NC-SA License 3.0","url":"http://creativecommons.org/licenses/by-nc-sa/3.0/"}],"readme":"  _    __          __          __                 _______\r\n | |  / /__  _____/ /_  ____  / /____  ____      / / ___/\r\n | | / / _ \\/ ___/ __ \\/ __ \\/ __/ _ \\/ __ \\__  / /\\__ \\\r\n | |/ /  __/ /  / /_/ / /_/ / /_/  __/ / / / /_/ /___/ /\r\n |___/\\___/_/  /_.___/\\____/\\__/\\___/_/ /_/\\____//____/\r\n        \r\n zip archive: http://www.verbotenjs.com/ver/1.0.0/archive.zip\r\n hg source: https://www.bitbucket.org/marcuspope/verbotenjs\r\n npm package: https://npmjs.org/package/verbotenjs\r\n\r\n Introduction\r\n ================================================== \r\n\r\n Because everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n \r\n   �Maintainable JavaScript: Don't modify objects you don't own. - Nicholas C. Zakas�\r\n\r\n I, Marcus Pope, by imperial proclamation hereby declare ownership of\r\n Object.prototype. As sole owner I am the only authorized person to modify the\r\n prototype definition. Nope, too late I already called it and double stamped it.\r\n You can't triple stamp a double stamp!\r\n\r\n What Is VerbotenJS?\r\n ------------------- \r\n\r\n VerbotenJS is a general application development framework designed for NodeJS &\r\n Browser JavaScript hosts. In addition to a bunch of base prototype enhancements\r\n and terse programming patterns, the framework also includes extension libraries\r\n for various domains such as databases, filesystems, shell scripts etc.\r\n \r\n Who Should Use VerbotenJS?\r\n -------------------------- \r\n\r\n Nobody, it's verboten remember?!? No I'm kidding, you can use it for any\r\n personal project you want. I don't recommend using it for production systems\r\n since it is version 1.0 and I'm just one man trying to support his own personal\r\n JS framework. I'll probably change framework logic on a whim too, because that\r\n too is considered verboten right?\r\n \r\n Why Is VerbotenJS 750k Uncompressed, and do you really expect me to download\r\n that to a client?\r\n -------------------------------------------------------------- \r\n\r\n No, I don't, it's verboten to do so remember? Actually here's the deal. jQuery\r\n is not compatible with Object.prototype extensions. I had intended on releasing\r\n my own DOM, Event and Ajax wrapper but I ran out of time. So I decided to\r\n inject a forked version of jQuery which added almost 350k to the footprint. My\r\n DOM wrapper will probably put the library in the 500k realm for browser hosts.\r\n For NodeJS hosts modules are dynamically included on access so the run-time\r\n memory usage requirements are dynamic based on the modules you use.\r\n\r\n But by today's standards 750k is not really that bad except for mobile devices\r\n and cellular networks. If you must you can compress and gzip it down to 75k but\r\n with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\n But I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n -------------------------------------------------------------- \r\n\r\n Good for you. Play around a little, find out how good it feels to be bad for\r\n once in your life :D\r\n\r\n Well, If Object Prototype Extensions Are Good, Then Why Does VerbotenJS Break\r\n My Application/Library/3rd Party Code?\r\n -------------------------------------------------------------- \r\n\r\n Some people write bad JavaScript code, including myself. jQuery authors, for\r\n instance, recognize that their codebase has a bug that makes jQuery\r\n incompatible with object prototype extensions, however they choose to ignore\r\n the issue for various artificial reasons. ExpressJS authors just don't\r\n understand how JavaScript reflection works, and they think OPE's are code\r\n smell. And yet in other cases VerbotenJS may conflict with existing namespaces\r\n in your application. In the latter case I recommend either opening a bug if the\r\n issue is caused by a non-conforming standard on my part, or refactoring your\r\n application if you want to use VerbotenJS.\r\n\r\n Where Do I Start?\r\n ----------------- \r\n\r\n First grab a copy of verbotenjs from npm.\r\n \r\n    npm install verbotenjs\r\n \r\n In node hosts use:\r\n \r\n    require('verbotenjs');\r\n    \r\n For browser hosts include a reference to this file\r\n \r\n    [verbotenjs]/web/verboten.js \r\n \r\n There are no init functions that you have to worry about, and there is no real\r\n global entry point to the verboten framework. Everything you need is either\r\n declared globally, or attached to the prototypes of existing data types\r\n including Objects.\r\n\r\n I Kinda Like Where This Is Going, How Do I Help?\r\n ------------------------------------------------ \r\n\r\n Well, I'm not really in a position to coordinate a team of developers at the\r\n moment. I have a newborn daughter and a full time job, so to avoid the\r\n frustration of not hearing from me for a few weeks at a time, which totally\r\n happens, send me small patches, <500 lines, and I'll review them. Since I doubt\r\n this will be much of an issue either way, I'll leave it at that for now.\r\n\r\n What If I Wanted To Create A Commercial Product?\r\n ------------------------------------------------ \r\n\r\n Well, let's talk licensing and target market. But really you should probably\r\n wait until 2.0 at least before considering something for production.\r\n\r\n What's In Store For The Future Of VerbotenJS?\r\n --------------------------------------------- \r\n\r\n Jesus, what isn't in a state of almost complete! Documentation, Bugs, Dom.js,\r\n Cross Platform Compatibility, JSDom, Unit Tests, etc. You know, all the stuff\r\n you'd expect from a professional open source project. The same stuff you should\r\n expect to be missing from a project named VerbotenJS.\r\n\r\n Documentation\r\n ================================================= \r\n\r\n Ha!\r\n\r\n No, but I'm working on it. You'll notice some documentation tags in the source\r\n code, that's about as far as I've made it on the documentation front. Much of\r\n the codebase is pretty self explanatory, much of it is not. I do have a couple\r\n of other projects and a bunch of scripts that I've written over the years that\r\n will be used as examples, but otherwise I have no documentation other than\r\n comments in the source.\r\n\r\n Examples\r\n -------- \r\n\r\n Here are some before and after code samples to show how VerbotenJS can make\r\n your coding efforts easier.\r\n\r\n Grepping The File System Without VerbotenJS:\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      if (typeof query == \"string\") {\r\n        query = new RegExp(query, \"i\");\r\n      }\r\n      \r\n      //optionally filter by filemask\r\n      if (typeof filemask == \"string\") {\r\n        filemask = new RegExp(filemask);\r\n      }\r\n      \r\n      var count = 1, //file count\r\n        async = 0, //async callback count\r\n        out = [],\r\n        list = [],\r\n        fs = require('fs'),\r\n        fp = require('path');\r\n      \r\n      dir = dir || process.cwd();\r\n      \r\n      function search(path) {\r\n        fs.stat(path, function(err, stat){\r\n          count--;\r\n          \r\n          if (err) throw err;\r\n          \r\n          if (stat.isDirectory()) {\r\n            \r\n            async++;\r\n            \r\n            fs.readdir(path, function(err, files){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              for (var i=0; i < files.length; i++) {\r\n                if (!hidden && files[i][0] == '.') return;\r\n                count++;\r\n                search(fp.join(path, files[i]));\r\n              }\r\n            });\r\n          } else if (stat.isFile()) {\r\n            //ignore unmatched file masks\r\n            if (!filemask.test(path)) {\r\n               return;\r\n            }\r\n            \r\n            async++;\r\n            fs.readFile(path, 'utf8', function(err, str){\r\n              async--;\r\n              \r\n              if (err) throw err;\r\n              \r\n              var lines = str.split('\\n');\r\n              \r\n              for (var i=0; i < lines.length; i++) {\r\n                var line = lines[i].trim(); \r\n                //return matching lines & line number\r\n                if (query.test(line)) return [i, line];\r\n              }\r\n              \r\n              if (lines.length) {\r\n                out.push(path);\r\n                for (var i=0; i < lines.length; i++) {\r\n                  out.push((lines[i][0]+1) + \": \" + lines[i][1]);\r\n                  list.push({\r\n                    path : path,\r\n                    line : lines[i][0],\r\n                    text : lines[i][1]\r\n                  });\r\n                }\r\n                out.push('');\r\n              }\r\n              \r\n              if(count == 0 && async == 0) {\r\n                cb(out.join(\"\\n\") || \"\", list);\r\n              }\r\n            });\r\n          }\r\n        });\r\n      }\r\n      \r\n      search(dir);\r\n    };\r\n    \r\n About 50 lines of code (minus empty lines, comments and closing brackets) to\r\n implement a grep-like file system search in NodeJS. Here's the same function\r\n implemented with VerbotenJS conventions.\r\n \r\n    function grep(dir, query, filemask, recurse, hidden, cb) {\r\n      //grep for 'query' in 'dir'.\r\n      //'recurse' if necessary,\r\n      //ignore 'hidden' files if necessary.\r\n      //'cb' required.\r\n      dir = dir || process.cwd();\r\n      query = query.toRegex('i');\r\n      filemask = filemask.toRegex('i');\r\n      \r\n      //recursively search the filesystem\r\n      q.fs.ls(dir, recurse, function(list) {\r\n        //filter files we don't need\r\n        var files = list.ea(function(f) {\r\n          if (!hidden && f[0] == \".\") return; //things like .hg/.git\r\n          if (!filemask.test(f)) return;\r\n          return f;\r\n        });\r\n        \r\n        var matches = [];\r\n        \r\n        //read each file and collect matching line info\r\n        files.sort().ea(function(next, f) {\r\n          q.f.utf8(f, function(txt) {\r\n            txt.split('\\n').trim().ea(function(line, i) {\r\n              //if line matches query, return info\r\n              if (query.test(line)) {\r\n                matches.push({\r\n                  path : f,\r\n                  line : i,\r\n                  text : line\r\n                });\r\n              }\r\n            });\r\n            \r\n            //process next file\r\n            next();\r\n          });\r\n        }, function() {\r\n          //replicate grep stdout\r\n          var stdout = matches.ea(function(o) {\r\n            return [o.path, o.line + 1, \": \", o.text, ''].join('\\n');\r\n          });\r\n          \r\n          //return stdout and matches obj\r\n          cb(stdout, matches);\r\n        });\r\n      });\r\n    };\r\n    \r\n Here it only took 22 lines of code to implement the same logic. And in reality,\r\n the VerbotenJS version is more robust than the raw JavaScript version due to\r\n the flexibility of functions like .toRegex() and .test().\r\n\r\n And my .ea() function operates like Array.forEach, except that it allows for\r\n Object key iteration, asynchronous or synchronous iteration based on the\r\n presence of a callback function, and enhanced iteration workflows with helpers\r\n like ea.exit(), ea.merge() and ea.join(). Basically .ea() precludes the need to\r\n ever use for loops, for-in loops, or any of the new ES5 array extensions \r\n Array.forEach|map|filter|some|every|reduce* functions.\r\n\r\n That's all I have time to report on now, but I'll put up some more examples as\r\n I find well isolated examples.\r\n\r\n Conclusion\r\n ==================================================\r\n\r\n VerbotenJS has been a career long project of mine. I've renamed/rewritten the\r\n project multiple times over, for various different JavaScript hosts like\r\n WScript/JScript, HTA's, Rhino, J#, Jaxer and even a custom C# host I wrote for\r\n fun. With the growing popularity of NodeJS I think VerbotenJS has finally found\r\n a good home. And the architecture is finally to a point that I consider it\r\n stable and worthy of peer review. So get reviewing peers!\r\n\r\n Thanks for reading,\r\n Marcus Pope\r\n","readmeFilename":"readme.txt","_id":"verbotenjs@1.2.10","dist":{"shasum":"b82a9ac9f9d957e4d32d75d0b7995671eb6cfba9","tarball":"https://registry.npmjs.org/verbotenjs/-/verbotenjs-1.2.10.tgz","integrity":"sha512-ZmpORzM/9NmYxpWPFCm9KYAPbRgFt6InTXe1t9mdxtVU6H6+UeLjxvw9JNVOX7qvrxFKTsdTAoUGLB+Hu0+5BQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC/81xYrhdu15J8aFsDFFPUJqvdADRfnVPXMWLM78KUwAiEAgP0dab/FC/2nE1SSjjUZCapvGHG2mL+hHGTg330GRy0="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"marcuspope","email":"me@marcuspope.com"},"maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}]}},"readme":"VerbotenJS Development Framework\r\n================================\r\n\r\nBecause everybody will think it is verboten anyway, I present to you VerbotenJS.\r\n\r\n\"Maintainable JavaScript: Don't modify objects you don't own.\" - Nicholas C. Zakas\r\n\r\nI, Marcus Pope, by imperial proclamation hereby declare ownership of Object.prototype.  As sole owner I am the only\r\nauthorized person to modify the prototype definition.  Nope, too late I already called it and double stamped it.\r\nYou can't tripple stamp a double stamp!\r\n\r\nWhat Is VerbotenJS?\r\n-------------------\r\n\r\nVerbotenJS is a general application development framework desined for NodeJS & Browser JavaScript hosts.  In addition\r\nto a bunch of base prototype enhancements and terse programming patterns, the framework also includes extension libraries\r\nfor various domains such as databases, filesystems, shell scripts etc.\r\n\r\nVerbotenJS strives to abstract the minutia of JavaScript development into helper functions on the various base prototype\r\nchains like Function, Date, Number, Object etc.  I also tend to normalize interfaces between async and sync nodejs functions\r\nby checking for the existence of a callback argument.  \r\n\r\nWho Should Use VerbotenJS?\r\n--------------------------\r\n\r\nNobody, it's verboten remember?!? No I'm kidding, you can use it for any personal project you want.  I don't recommend\r\nusing it for production systems since it is version 1.0 and I'm just one man trying to support his own personal JS\r\nframework.  I'll probably change framework logic on a whim too, because that too is considered verboten right?\r\n\r\nWhat If I Wanted To Create A Commercial Product?\r\n------------------------------------------------\r\n\r\nWell, let's talk licensing and target market.  But really you should probably wait until 2.0 at least before considering\r\nsomething for production.\r\n\r\nWhy Is VerbotenJS 750k Uncompressed, and do you really expect me to download that to a client?\r\n----------------------------------------------------------------------------------------------\r\n\r\nNo, I don't, it's verboten to do so remember? Actually here's the deal.  jQuery is not compatible with Object.prototype\r\nextensions.  I had intended on releasing my own DOM, Event and Ajax wrapper but I ran out of time.  So I decided to\r\ninject a forked version of jQuery which added almost 350k to the footprint. My DOM wrapper will probably put the library\r\nin the 500k realm for browser hosts.  For NodeJS hosts modules are dynamically included on access so the runtime memory usage\r\nrequirements are dynamic based on the modules you use.\r\n\r\nBut by today's standards 750k is not really that bad except for mobile devices and cellular networks.  If you must you\r\ncan compress and gzip it down to 75k but with modern bandwidth and caching infrastructures it really isn't that bad.\r\n\r\nBut I Heard/Read/Know That Object Prototype Extensions Are Bad, mkay?\r\n---------------------------------------------------------------------\r\n\r\nGood for you.  Play around a little, find out how good it feels to be bad for once in your life :D\r\n\r\nWhere Do I Start?\r\n-----------------\r\n\r\nFirst grab a copy of verbotenjs from npm.\r\n\r\n    npm install verbotenjs\r\n    \r\nIn node hosts use:\r\n\r\n    require('verbotenjs');\r\n\r\nFor browser hosts include a reference to this file\r\n\r\n    [verbotenjs]/web/verboten.js\r\n    \r\nI Kinda Like Where This Is Going, How Do I Help?\r\n------------------------------------------------\r\n\r\nWell, I'm not really in a position to coordinate a team of developers at the moment.  I have a newborn daughter and a\r\nfull time job, so to avoid the frustration of not hearing from me for a few weeks at a time, which totally happens, send\r\nme small patches, <500 lines, and I'll review them.  Since I doubt this will be much of an issue either way, I'll leave\r\nit at that for now.\r\n\r\nWhat's In Store For The Future Of VerbotenJS?\r\n---------------------------------------------\r\n\r\nJesus, what isn't in a state of almost complete!  Documentation, Bugs, Dom.js, Cross Platform Compatibility, JSDom,\r\nUnit Tests, etc.  You know, all the stuff you'd expect from a professional open source project.  The same stuff you'd\r\nexpect to be missing from a project named VerbotenJS.\r\n\r\n\r\n\r\n\r\nDocumentation\r\n========================================================================================================================\r\n    Node Framework: http://nodejs.org/docs/latest/api/index.html\r\n\r\nFonts used for prototype headers\r\n========================================================================================================================\r\n//http://www.network-science.de/ascii/\r\n   - Using \"Slant\" font\r\n\r\nThings to do for VerbotenJS\r\n========================================================================================================================\r\n    Array.prototype.thread = function(f, status_handler, params, callback) {\r\n        //I've had this idea for a while now, since web workers now exist this is probably a less than ideal solution, but it could\r\n        //serve as a worker shim maybe?\r\n\r\n        //This is some pseudo code for implementing threaded processing in a browser\r\n        //A suitable counterpart to threaded server side operations in node,\r\n        //when the client needs to process millions of records quickly\r\n        //essentially map reduce via popups\r\n        //not all supporting functions are built or built to spec for this to work\r\n\r\n        var x = this.inGroupsOf(this.size().squared().limit(200)); //100,000 == 36, 100,000,000 == 81 up to 200 browsers\r\n\r\n        var threads = [];\r\n        x.ea(function(g, i) {\r\n            //spawn each browser with a bootstrap of the q framework\r\n            threads.push(window.open('thread' + i, 'qbootstrap.html'));\r\n            //create special eval async function that passes a stringified version of the function to run\r\n            //and the group of data to run it on to the child browser window for processing\r\n            threads.last().evalAsync(f.toString(), g.toString()); //async eval occurs in child window\r\n        });\r\n\r\n        var res = [];\r\n        var remaining = threads.length;\r\n\r\n        var id = setInterval(function() {\r\n            //check on results ever second or so\r\n            threads.ea(function(t,i) {\r\n                if (t.finished) { //evalAsync function should set global finished & result variables\r\n                    res[i] = t.result; //get result from child processing and insert into original index\r\n                    t.close(); //close browser\r\n                    remaining--;\r\n                }\r\n            });\r\n\r\n            if (remaining <= 0) {\r\n                //don't need to check results anymore, all browsers are closed\r\n                clearInterval(id);\r\n                //now reduce the results into a flat array\r\n                callback(res.flatten(1)); //but only flatten the first layer\r\n            }\r\n        }, 1000);\r\n    };\r\n\r\n\r\nCoding Standards:\r\n========================================================================================================================\r\nGood:\r\n    if (test == 1) {\r\n        return msg;\r\n    }\r\nBad:\r\n    if (test == 1) return msg;\r\nReason:\r\n    Setting a break point to inspect msg when test == 1 is difficult when they are on one line.\r\n    Having curly brackets ensures future code modifications are understood and doesn't cost much.\r\n\r\nGood:\r\n    (function() {\r\n        //self executing function\r\n        var x = 1;\r\n    })();\r\nBad:\r\n    var x = 1;\r\nReason:\r\n    'x' is public meaning others can modify it or you could be modifying someone else's x if they used it already.\r\n    Global namespace collisions can be reduced by wrapping a self executing function\r\n\r\nGood:\r\n    var x = function() {    };\r\nBad:\r\n    var x = function() {    }\r\nReason:\r\n    Missing semicolon on function assignment can cause code to fail in ways you probably wouldn't expect.\r\n    This will throw an exception:\r\n        var literal = {\r\n            say: function(msg) { alert(msg); }\r\n        }\r\n\r\n        (function() {\r\n        })();\r\n    Unless you add a semicolon to the literal object definition.\r\n    And the error you receive is \"undefined is not a function\" on the last line at the start of the open paren.\r\n    \r\n    For a great explanation of semicolon insertion rules see this article:\r\n    http://mattbriggs.net/blog/2012/04/16/why-i-dont-use-semicolons/\r\n\r\nGood:\r\n    for (var x in obj) {\r\n        if (obj.hasOwnProperty(x)) {\r\n            //use obj.x\r\n        }\r\n    }\r\nBad:\r\n    for (var x in obj) {\r\n        //use obj.x\r\n    }\r\nReason:\r\n    Prototype extensions will be included in the second for loop.  You most likely did not want those references\r\n    if you are just trying to access the properties associated with just the object.  Ideally you would not iterate over\r\n    objects to begin with, but alternatively you should just use the .ea iterator method which handles this for you. In\r\n    the event that you do want the prototype introspection, then by all means continue to use it.\r\n\r\n---------------------------------------\r\n\r\nAlternative:\r\n    Object.prototype.hasOwnProperty.apply(obj, key);\r\n\r\nReason:\r\n    Although many will tell you to do this to avoid problems with a person overwrites hasOwnProperty on a local object, that's\r\n    a bad reason.  If anyone were to override the hasOwnProperty() method on an object it's probably for a damn good reason.\r\n    Bypassing this option would be like preventing a function from being overriden in a subclass.  And while strict proponents\r\n    think this is ideal, the entire premise of dynamic overrides is that you can temporally adjust what is considered a local\r\n    property of an object simply by overriding the hasOwnProperty method and selectively including or excluding specific keys.\r\n    \r\n    The real reason to do this is because not all objects inherit from the Object.prototype chain in JS.  IE is notorious for this\r\n    design when it comes to DOM and COM objects.  But applying the Object.prototype method to the host object will still work as\r\n    expected.  \r\n\r\n---------------------------------------\r\n\r\nJust Bad:\r\n\r\n    (function(undefined) {\r\n        //locally overwriting undefined to be undefined.\r\n    })();\r\n\r\nReason:\r\n    In the event that a programmer wants to temporally alter the value of undefined, they can do so because JavaScript is\r\n    dynamic.  Precluding this option makes your code less dynamic.  You should probably be using another language if that's\r\n    what you want.  In the event that someone alters the value of undefined and your code breaks, this is obviously the fault\r\n    of the coder, not you.  So don't limit the coding options for those who would use the dynamic nature of the language for good\r\n    use because someone might hang themselves.\r\n\r\nGood:\r\n    var i = parseInt(\"08\", 10);  //let's assume 08 was part of a date string\r\n    //i == 8\r\nBad:\r\n    var i = parseInt(\"08\");\r\n    //i == 0\r\nReason:\r\n    parseInt does not always assume a base 10 radix.  In this example it will assume 08 is octal (base 8) which doesn't\r\n    have an 8, so it results in 0;\r\n\r\nGood:\r\n    function() {\r\n        var myVar = 'local';\r\n    }\r\nBad:\r\n    function() {\r\n        myVar = 'local';\r\n    }\r\nReason:\r\n    Always use var to define a variable, in the second case a global myVar will be created instead of a local myVar.\r\n\r\nGood:\r\n    var x;\r\n    if (FB && FB.api && FB.api.getCurrentUser) {\r\n        x = FB.api.getCurrentUser();\r\n    }\r\n    ----------or------------\r\n    try {\r\n        var x = FB.api.getCurrentUser();\r\n    } catch(e) { }\r\nBad:\r\n    var x = FB.api.getCurrentUser();\r\nReason:\r\n    Always check an object chain before accessing its children or calling a function.  If FB isn't defined,\r\n    accessing FB.api will throw an exception.  And if FB.api is defined, but getCurrentUser is not, calling it as a\r\n    function will also throw an exception.  Alternatively you can, and in the case of Facebook probably should, EAFP\r\n    (Easier to Ask Forgiveness than Permission) or just try catch the exception.  \r\n\r\nGreat References:\r\n========================================================================================================================\r\n    http://kangax.github.com/nfe/\r\n    http://perfectionkills.com/\r\n    http://bonsaiden.github.com/JavaScript-Garden/\r\n    \r\nInteresting Reads:\r\n========================================================================================================================\r\n    https://github.com/BonsaiDen/JavaScript-Garden/issues/84\r\n    http://perfectionkills.com/category/ecma-262/\r\n\r\nTroubleshooting:\r\n========================================================================================================================\r\n    Object Prototypes you should avoid overriding\r\n        Object.prototype.sort = function() { }; //messes with mongodb in node.js\r\n        Object.prototype.toString = function() { }; //messes with jQuery & other internals\r\n        Object.prototype.set = function() { }; //messes with require('child_process');\r\n        Object.prototype.size = function() { }; //breaks node.js url.parse method ??? weird.\r\n        Array.prototype.reduce = function() { }; //map reduce much?\r\n        Array.prototype.map = function(f) { };\r\n","maintainers":[{"name":"marcuspope","email":"me@marcuspope.com"}],"time":{"modified":"2022-06-28T10:07:06.671Z","created":"2013-01-11T22:47:09.142Z","0.0.1":"2013-01-11T22:47:10.765Z","1.0.0":"2013-01-15T14:51:25.710Z","1.0.1":"2013-04-02T20:13:27.959Z","1.0.2":"2013-04-18T19:26:20.931Z","1.0.3":"2013-05-04T04:05:06.955Z","1.0.4":"2013-05-04T18:32:17.653Z","1.0.5":"2013-05-04T18:34:22.566Z","1.0.6":"2013-05-04T19:02:47.290Z","1.0.7":"2013-05-05T21:22:12.481Z","1.0.8":"2013-05-06T00:23:14.035Z","1.0.9":"2013-05-06T00:29:40.541Z","1.0.10":"2013-05-08T03:30:26.355Z","1.0.11":"2013-05-08T03:46:14.366Z","1.1.0":"2013-05-10T22:54:05.810Z","1.2.0":"2013-06-25T20:38:41.315Z","1.2.1":"2013-08-06T03:20:16.371Z","1.2.2":"2013-08-08T04:28:34.851Z","1.2.3":"2013-08-10T02:38:26.535Z","1.2.4":"2013-08-10T02:49:15.583Z","1.2.5":"2013-08-13T02:48:42.821Z","1.2.6":"2013-08-14T00:41:14.081Z","1.2.7":"2013-08-15T03:18:09.816Z","1.2.8":"2013-08-16T02:28:50.657Z","1.2.9":"2013-08-23T03:32:03.344Z","1.2.10":"2013-08-24T04:07:02.222Z"},"author":{"name":"Marcus Pope","email":"me@marcuspope.com"},"repository":{"type":"hg","url":"https://bitbucket.org/marcuspope/verbotenjs"},"users":{"forivall":true}}