├── .gitignore ├── LICENSE ├── README.markdown ├── build.properties ├── build.xml ├── examples └── mongodb │ └── test.js ├── lib ├── jquery-1.3.2.min.js └── jquery-license.txt ├── popcorn_maker.html ├── src ├── all.js ├── common.js ├── core.js ├── dictionary.js ├── names.js ├── network.js ├── passwords.js └── project.js └── test ├── common.html ├── core.html ├── dictionary.html ├── network.html ├── test.css └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Mu Dynamics. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the "Mu Dynamics" nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Popcorn - the JSON fuzzer 2 | ========================= 3 | 4 | ## Description 5 | 6 | Popcorn is a JavaScript embedded DSL designed for fast, easy and 7 | flexible JSON object generation. Popcorn core modules provides a basic set 8 | of generators for most common JavaScript types and combinators to build 9 | new generators for any kind of data. Additional modules extend the 10 | functionality with random generators, dictionaries, network type 11 | generators for IP or mac addresses and more. 12 | 13 | Popcorn can be used to generate mock objects for testing of JSON services 14 | or browser side JavaScript code. With Popcorn thousands of test cases 15 | can be expressed in just few lines of code which makes it a great driver for 16 | data driven test engines. 17 | 18 | You can give it a try at [popcorn maker](http://mu-labs.googlecode.com/svn/trunk/eng/tools/popcorn/popcorn_maker.html). 19 | 20 | ## Getting started 21 | 22 | The library consists of several independent loadable modules build on 23 | top of the core framework. To setup the generator: 24 | 25 | 1. Load only required modules or module All. 26 | 2. Define base test case JSON object. 27 | 3. Define generator object and assign generators to attributes you intend to fuzz. 28 | 4. Run `permutate` or `circulate` function to generate test objects. 29 | 30 | For example: 31 | 32 |

 33 | 	// Load modules containing generators used in this scope.
 34 | 	with({ core: Popcorn.Core, comm: Popcorn.Common }) {
 35 | 
 36 | 		var base_object = { // Define the base test case object.
 37 | 			id   : 1, 
 38 | 			name : 'Woody'
 39 | 		};
 40 | 
 41 | 		var generator = { // Define the generator object. 
 42 | 			name : comm.list('Buzz', 'Slinky') // Alter only the name attribute.
 43 | 		};
 44 | 
 45 | 		// And run...
 46 | 		var results = core.permutate(generator, base_object);
 47 | 
 48 | 	}
 49 | 
50 | 51 | ## Generators 101 52 | 53 | In the basics, generators are functions that take one argument value 54 | and return a result value with an optional state. Core function 55 | `gen()` creates the most basic generator that substituts any input with 56 | the parameter value passed to `gen()`. 57 |

 58 | 	var g = gen('test'); // Create a generator g with value 'test'.
 59 | 	g('any input')       // Execute the generator g. The result is 'test'.
 60 | 
61 | 62 | Another basic combinator is `prepend()`: 63 | 64 |

 65 | 	var p = prepend('Hello ');
 66 | 	p('world'); // returns 'Hello world'
 67 | 	p('Buzz'); // returns 'Hello Buzz', etc.
 68 | 
69 | 70 | Some generators accept other generators or generator arrays as argument. 71 | For example `append(g)` executes the generator `g` and appends the 72 | result to the input value: 73 | 74 |

 75 | 	var r = random().int(), // See next section for random generators.
 76 | 	    a = append(r);
 77 | 	    a('user'); // Will return for example 'user42' or 'user573' etc.
 78 | 
79 | 80 | Generator `chain()` can be used to execute generators in sequence. 81 | For example a random user name genarator can be implemented as following: 82 | 83 |

 84 | 	var r = random().int(),
 85 | 	    u = chain(r, function(i) { return append('-' + i); });
 86 | 	    u('admin'); // Will return for example 'admin-385' or 'admin-712', etc.
 87 | 
88 | 89 | `chain()` takes the random generator and a function as argument. It executes 90 | the generator and passes the result to the function that returns a new generator 91 | as result. `chain()` always has to return another generator, so it can be 92 | chained with another generator or just evaluated. 93 | 94 | Random user name generator can be useful already. We can extract it 95 | into a separate library and use with any other generator, for example: 96 | 97 |

 98 | 	var randomUser = chain(random().int(), function(i) { return append('-' + i); });
 99 | 	repeat(10, randomUser)('user'); // Generates 10 random user names `user-xyz`.
100 | 
101 | 102 | Popcors not only support permutations on first attribute level, but on object compositions (currently supported for `permutate()` only), for example: 103 | 104 |

105 | var generator = {
106 | 	id   : range(1, 3),
107 | 	name : {
108 |        first : list('Buzz', 'Slinky'),
109 |        last  : 'Toy'
110 |     }
111 | };
112 | 
113 | 114 | Try [popcorn_maker.html](http://mu-labs.googlecode.com/svn/trunk/eng/tools/popcorn/popcorn_maker.html) 115 | and see [API documentation](http://mu-labs.googlecode.com/svn/trunk/eng/tools/popcorn/docs/api_dev/index.html) 116 | for more information and the complete generator list. 117 | 118 | ## Random generators 119 | 120 | Core module defines a random generator object and a library class 121 | which can be extended with custom generators. Constructor function 122 | `random()` creates the random generator object. It accepts an optional 123 | seed value as argument. 124 | Build in random generator functions are: 125 | 126 | - `int()` - range function that returns an integer in a predefined defined rage. 127 | - `element()` - returns one element from the provided dictionary. 128 | 129 | For example: 130 | 131 |

132 |   var r = random();
133 |   r.int(100, 200); // Returns a random int in the range from 100 to 200
134 |   r.element(['a', 'b', 'c']); // Returns one of the chars in argument array.
135 | 
136 | 137 | To extend the random object with a custom generator, assign 138 | the generator to the `RandomLib` class defined in Core: 139 | 140 |

141 | 	RandomLib.myRandGenerator = function() {
142 | 		... 
143 | 		// this.int()(); call to core int() generator
144 |     //               which returns next int value.
145 | 		... 
146 | 	};
147 | 
148 | 149 | and use as `random().myRandGenerator()`. 150 | Most modules extend the random object with custom generator. 151 | See `Common.alpha` or `Network.emailAddress` for more details. 152 | 153 | ## Dictionaries 154 | 155 | Module Dictionary provides functions to build dictionaries 156 | from JavaScript arrays. Constructor function `dictionary()` 157 | takes an array as argument and returns the dictionary object. 158 | Currently three generator functions are supported by dictionary 159 | objects: 160 | 161 | - `list()` - a range function which returns all or a subset of elements. 162 | - `element()` - returns one random dictionary element. 163 | - `elements()` - returns n random elements. 164 | 165 | Popcorn provides several default dictionaries for most common 166 | names, surnames, passwords, domains etc. 167 | 168 | ## State and variables 169 | 170 | Generation process maintains a state object which is accessible by any generator. 171 | `permutate()` and `circulate()` functions 172 | take an optional state object as argument. If this is not provided, 173 | an empty object is created. 174 | 175 | To access the state use `withState()` generator, for example: 176 | 177 |

178 | var generator = {
179 | 	id  : withState(function(s) { s.id = 1; return gen(s.id); }),
180 | 	user: withState(function(s) { return gen('user-' + s.id); })
181 | };
182 | 
183 | 184 | The first generator sets an id attribute on the state object 185 | and returns a generator for this id. Newly assigned id attribute 186 | of the state object is used by the second generator to create user names of the form 'user-id'. 187 | Similar to `chain()` generator, `withState()` has to return another 188 | generator as result. 189 | 190 | To simplify access to the state object, Popcorn provides functions to 191 | store generator results in variables `setVar()` and access those with `withVar()`. 192 | Above example can be simplified to: 193 | 194 |

195 | var generator = {
196 | 	id  : setVar('id', random().int()),
197 | 	user: withVar('id', function(id) { return gen('user-' + id); })
198 | };
199 | 
200 | 201 | ## JSON object generators 202 | 203 | Popcorn supports two JSON generation functions, `permutate()` 204 | and `circulate()`. If two or more attribute generators are defined 205 | in one object or inner object, `permutate()` will generate object 206 | with all permutations between the values generated by the attribute 207 | generators. For example the generator 208 |

209 | var generator = {
210 | 	id  : range(1, 4),
211 | 	user: list('admin', 'guest')
212 | };
213 | 
214 | 215 | will return: 216 | 217 |

218 | [{ id: 1, user: 'admin' },
219 |  { id: 1, user: 'guest' },
220 |  { id: 2, user: 'admin' },
221 |  { id: 2, user: 'guest' },
222 |  { id: 3, user: 'admin' },
223 |  { id: 3, user: 'guest' },
224 |  { id: 4, user: 'admin' },
225 |  { id: 4, user: 'guest' }]
226 | 
227 | 228 | when executed with `permutate()`. 229 | 230 | `circulate()` in opposite to `permutate()` combines the results 231 | of all attribute generators together. `circulate()` for the 232 | above generator will return: 233 | 234 |

235 | [{ id: 1, user: 'admin' },
236 |  { id: 2, user: 'guest' },
237 |  { id: 3, user: 'admin' },
238 |  { id: 4, user: 'guest' }]
239 | 
240 | 241 | If no count is provided, circulate generates an object array 242 | of the length of the longest attribute generator (here 'id'). 243 | All other attribute values circulate (here 'user'). 244 | 245 | Additionally to the generator and base object, both functions 246 | take an optional result count, a state object and a result transformer 247 | as argument. By default only the result of the generation is 248 | returned by these function. Use `id()` as result transformer 249 | to return the final state as well. 250 | 251 | ## Build 252 | 253 | Just load the Core, Common and other modules as needed. 254 | Use [jGrouseDoc](http://code.google.com/p/jgrousedoc/) to build 255 | API docs. Update 'build.properties' file with the location 256 | of the jGrouseDoc project and run ant. 257 | 258 | ## License 259 | 260 | BSD License, see LICENSE for more information. 261 | 262 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | jGrouseHome.default=../jGrouseDoc-2.0 2 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Popcorn build file. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /examples/mongodb/test.js: -------------------------------------------------------------------------------- 1 | // MongoDB test data generator 2 | 3 | // Load popcorn libs 4 | load('../../src/core.js', '../../src/common.js', '../../src/dictionary.js', 5 | '../../src/names.js', '../../src/passwords.js', '../../src/network.js', 6 | '../../src/all.js'); 7 | 8 | // Generator libs 9 | var g = Popcorn.All; 10 | 11 | // Author generator 12 | var author_gen = { 13 | last : g.surnames.list(100000), 14 | first : g.names.element(), 15 | password : g.passwords.element(), 16 | email : g.random().emailAddress(), 17 | bio : g.random().loremIpsum(5, 10) 18 | }; 19 | 20 | // Generate and insert 21 | var authors = g.generate(author_gen); 22 | for (var i = 0, l = authors.length; i < l; i++) { 23 | db.authors.insert(authors[i]); 24 | } 25 | 26 | 27 | // Tile and tags dictionaries 28 | var titles = g.dictionary(["Just testing", "Live is good!", "WTF is Popcorn?", "On the road", "and more..."]); 29 | var tags = g.dictionary(["MongoDB", "CouchDB", "Popcorn", "Programming", "JavaScript", "Java", "Mu", "Live"]); 30 | 31 | // For all authors 32 | for (var as = db.authors.find({}); as.hasNext(); ) { 33 | var author = as.next(); 34 | 35 | // New blog generator for every author 36 | var blog_entry = {}; 37 | blog_entry.author_id = author._id.toString(), 38 | 39 | // Generate random n blogs between ... 40 | // with one random tiles from titles generator 41 | blog_entry.title = g.chain(g.random().int(40, 60), 42 | function(i) { return g.repeat(i, titles.element()); }); 43 | 44 | // and a date sometimes in 2009 45 | var from = new Date(2009, 1, 1); 46 | to = new Date(2010, 1, 1); 47 | blog_entry.date = g.random().date(from, to); 48 | 49 | // Lorem ipsum body of random length 50 | blog_entry.body = g.lazy(function() { return g.random().loremIpsum(); }); 51 | 52 | // With tags 53 | blog_entry.tags = g.array(tags.elements(3)); 54 | 55 | // and comments: 56 | blog_comment = { 57 | name : g.chain(g.random().int(1, 10), function(i) { return g.repeat(i, g.names.element()); }), 58 | email : g.random().emailAddress(), 59 | comment : g.lazy(function() { return g.random().loremIpsum(); }) 60 | }; 61 | 62 | var blog_entries = g.generate(blog_entry); 63 | for (var i = 0, l = blog_entries.length; i < l; i++) { 64 | blog_entries[i].comments = g.generate(blog_comment); 65 | // printjson(blog_entries[i]); 66 | db.blog_entries.insert(blog_entries[i]); 67 | } 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /lib/jquery-1.3.2.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery JavaScript Library v1.3.2 3 | * http://jquery.com/ 4 | * 5 | * Copyright (c) 2009 John Resig 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://docs.jquery.com/License 8 | * 9 | * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) 10 | * Revision: 6246 11 | */ 12 | (function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); 13 | /* 14 | * Sizzle CSS Selector Engine - v0.9.3 15 | * Copyright 2009, The Dojo Foundation 16 | * Released under the MIT, BSD, and GPL Licenses. 17 | * More information: http://sizzlejs.com/ 18 | */ 19 | (function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); -------------------------------------------------------------------------------- /lib/jquery-license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 John Resig, http://jquery.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /popcorn_maker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Popcorn Maker 5 | 6 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 229 | 230 | 231 | 232 |

Popcorn Maker

233 | 234 | 235 | 236 | 265 | 266 | 271 | 272 |
237 |
238 | Select an example: 239 | 242 |
243 |
244 | or build a new generator: 245 |
246 | 261 | 262 | 263 |
264 |
267 |
268 |
269 |
270 |
273 | 274 | 275 | 276 | 277 | 278 | -------------------------------------------------------------------------------- /src/all.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.All 3 | * @requires Popcorn.Core 4 | * @requires Popcorn.Common 5 | * @requires Popcorn.Dictionary 6 | * @requires Popcorn.Names 7 | * @requires Popcorn.Passwords 8 | * @requires Popcorn.Network 9 | */ 10 | 11 | /** 12 | * For simplification, module 'All' merges all Popcorn modules 13 | * and generators together. Just load all project JavaScript 14 | * files and use as: 15 | *
16 |  *   with({ p: Popcorn.All }) {
17 |  *     ... your generator code ...
18 |  *   }
19 |  * 
20 | * 21 | * @namespace Popcorn.All 22 | * @author Adam Smyczek 23 | */ 24 | Popcorn.All = function (core, common, dictionary, passwords, names, network) { 25 | 26 | // Merge all packages 27 | return core.merge(core, common, dictionary, passwords, names, network); 28 | 29 | }(Popcorn.Core, 30 | Popcorn.Common, 31 | Popcorn.Dictionary, 32 | Popcorn.Passwords, 33 | Popcorn.Names, 34 | Popcorn.Network); 35 | 36 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.Common 3 | * @requires Popcorn.Core 4 | */ 5 | 6 | /** 7 | * A collection of most common generators. 8 | * 9 | * @namespace Popcorn.Common 10 | * @author Adam Smyczek 11 | */ 12 | Popcorn.Common = function (core) { 13 | 14 | var lib = {}; 15 | 16 | // Some internal constants 17 | var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 18 | var digit = '0123456789'; 19 | var alpha_num = alpha + digit; 20 | 21 | /** 22 | * Concats arguments (primitives single result generators) 23 | * into one string. 24 | * 25 | * @function {generator[string]} concat 26 | * @param {[generator/primitives]} value - single value 27 | * generators or primitives to concatenate. 28 | */ 29 | var concat = lib.concat = function() { 30 | var args = core.args2array(arguments), gs = [], v; 31 | for (var i = 0, l = args.length; i < l; i++) { 32 | v = args[i]; 33 | gs[i] = core.isFunction(v)? v : core.gen(v); 34 | } 35 | return core.seq(gs, core.cJoin, ""); 36 | }; 37 | 38 | /** 39 | * 'range' generator creates a list of integer generators 40 | * in the range from min to max. This is a range function 41 | * and accepts no arguments, or one or two integer arguments. 42 | * For example: 43 | *
 44 |    *   var o = { int : 0 }
 45 |    *   var gen = { int : range(1, 3);
 46 |    *   generate(gen, o) will return:
 47 |    *   [{ int : 1 }, { int : 2 }, { int : 3 }]
 48 |    * 
49 | * 50 | * @function {generator[int]} range 51 | * @paramset No arguments - generates a range from 0 to 100. 52 | * @paramset One int argument - generates a range from 0 to max. 53 | * @param {integer} max - range max value. 54 | * @paramset two int arguments - from-to range. 55 | * @param {integer} min - from integer 56 | * @param {integer} max - to integer 57 | * 58 | * @see Popcorn.Utils.args2range 59 | */ 60 | var range = lib.range = function() { 61 | var mm = core.args2range(arguments, 0, 100), 62 | l = mm[1] - mm[0], 63 | r = []; 64 | for (var i = 0; i <= l; i++) { 65 | r[i] = core.gen(mm[0] + i); 66 | } 67 | return r; 68 | }; 69 | 70 | /** 71 | * Converts input arguments into a generator array [gen(arguments[i])].
72 | * For example: 73 | *
 74 |    *   var o = { name : 'Woody' }
 75 |    *   var gen = { name : list('Buzz', 'Slinky');
 76 |    *   generate(gen, o) will return:
 77 |    *   [{ name : 'Buzz' }, { name : 'Slinky' }]
 78 |    * 
79 | * 80 | * @function {generator[any]} list 81 | * @param {any+} args - the values to generate. 82 | */ 83 | var list = lib.list = function() { 84 | var args = core.args2array(arguments); 85 | return function(o, s) { 86 | var rs = [], r; 87 | for (var i = 0, l = args.length; i < l; i++) { 88 | r = args[i]; 89 | if (core.isArray(r)) { 90 | rs.push.apply(rs, list.apply(this, r)(o, s).result); 91 | } else { 92 | rs.push(r); 93 | } 94 | } 95 | return { result: rs, state: s }; 96 | }; 97 | // return core.mapGen(core.args2array(arguments)); 98 | }; 99 | 100 | /** 101 | * Joins arguments together. Generator arguments 102 | * are evaluated and array arguments join recursive. 103 | * 104 | * @function {generator} join 105 | * @param {any+} args - values, arrays or generators. 106 | */ 107 | var join = lib.join = function() { 108 | var args = core.args2array(arguments); 109 | return function(o, s) { 110 | var rs = "", ns = s, gr, r; 111 | for (var i = 0, l = args.length; i < l; i++) { 112 | r = args[i]; 113 | switch(core.typeOf(r)) { 114 | case 'function' : 115 | gr = r(o, s); 116 | rs += gr.result; 117 | ns = gr.state; 118 | break; 119 | case 'array' : 120 | gr = join.apply(this, r)(o, s); 121 | rs += gr.result; 122 | ns = gr.state; 123 | break; 124 | default: 125 | rs += r; 126 | break; 127 | } 128 | } 129 | return { result: rs, state: ns }; 130 | }; 131 | }; 132 | 133 | // ------ Prepend/append generators ------ 134 | 135 | // Internal prepend/append function prepends/appends 136 | // to default value based on handler function. 137 | var pre_a_pend = function(h) { 138 | return function(g, v) { 139 | return function(o, s) { 140 | var pv = v || o; 141 | switch (core.typeOf(g)) { 142 | case 'array' : 143 | var rs = [], ns = s, r; 144 | for (var i = 0, l = g.length; i < l; i++) { 145 | r = pre_a_pend(h)(g[i], v)(pv, ns); 146 | rs.push.call(rs, r.result); 147 | ns = r.state; 148 | } 149 | return { result: rs, state: ns }; 150 | case 'function' : 151 | return core.chain(g, function(r) { return core.gen(h(r, pv)); })(pv, s); 152 | default : 153 | return { result: h(g, pv), state: s }; 154 | } 155 | }; 156 | }; 157 | }; 158 | 159 | /** 160 | * Prepends a value to the attribute value of the base object. 161 | * Prepend takes a value, an array or a generator as argument.
162 | * For example: 163 | *
164 |    *   var o = { name : 'Head' }
165 |    *   generate({ name : prepend('Mr. Potato ') }, o) will generate:
166 |    *   [{ name : 'Mr. Potato Head' }]
167 |    * 
168 | * 169 | * @function {generator} prepend 170 | * @paramset Value 171 | * @param {any} inp - the value to prepend. 172 | * @paramset Array 173 | * @param {any[]} ar - the values to prepend. The resulting array 174 | * contains one object for every array element. 175 | * @paramset generator 176 | * @param {generator} gen - the generator of which result is prepended 177 | * to the base object value. 178 | */ 179 | var prepend = lib.prepend = pre_a_pend(function(a, b) { return a + b; }); 180 | 181 | /** 182 | * Appends a value to the attribute value of the base object. 183 | * See {@link prepend} for details. 184 | * 185 | * @function {generator} append 186 | * @paramset Value 187 | * @param {any} inp - the value to append. 188 | * @paramset Array 189 | * @param {any[]} ar - the values to append. The resulting array 190 | * contains one object for every array element. 191 | * @paramset generator 192 | * @param {generator} gen - the generator of which result is appended 193 | * to the base object value. 194 | */ 195 | var append = lib.append = pre_a_pend(function(a, b) { return b + a; }); 196 | 197 | // ------ Random generators extensions ------ 198 | 199 | // Internal string generator builder. 200 | // Creates a generator for an argument char set, 201 | // see alpha and alphaNum. 202 | var randomString = function(char_set) { 203 | return function() { 204 | var mm = core.args2range(arguments, 1, 100), 205 | int = this.int(mm[0], mm[1]), 206 | element = this.element(char_set); 207 | return core.lazy(function(o, s) { 208 | var l = int().result, r = ""; 209 | for (var i = 0; i < l; i++) { 210 | r += element().result; 211 | } 212 | return core.gen(r); 213 | }); 214 | }; 215 | }; 216 | 217 | /** @scope Popcorn.Core.Random */ 218 | 219 | /** 220 | * The range function 'alpha' generates a random alpha string. 221 | * The length of the string depends on the arguments this 222 | * function is called with. 223 | * 224 | * @function {generator} alpha 225 | * @paramset No arguments - generates an alpha string of length between 0 and 100. 226 | * @paramset One int argument - generates an alpha string of length between 0 and 'max'. 227 | * @param {integer} max - max string length. 228 | * @paramset two int arguments - length range. 229 | * @param {integer} min - min length 230 | * @param {integer} max - max length 231 | * 232 | * @see Popcorn.Utils.args2range 233 | */ 234 | core.RandomLib.alpha = randomString(alpha); 235 | 236 | /** 237 | * Same as {@link alpha} but generates an alpha numeric string. 238 | * 239 | * @function {generator} alphaNum 240 | * @paramset No arguments - generates an alphaNum string of length between 0 and 100. 241 | * @paramset One int argument - generates an alphaNum string of length between 0 and 'max'. 242 | * @param {integer} max - max string length. 243 | * @paramset two int arguments - length range. 244 | * @param {integer} min - min length 245 | * @param {integer} max - max length 246 | * 247 | * @see Popcorn.Utils.args2range 248 | */ 249 | core.RandomLib.alphaNum = randomString(alpha_num); 250 | 251 | /** @scope Popcorn.Common */ 252 | 253 | /** 254 | * Date generator. 255 | * 256 | * @function {generator} date 257 | * @param {date} d - the JavaScript date object or a date string representation, for example 'Sep. 13 2009'. 258 | * @param {string} format - the output format, possible values are: date, hours, minutes, seconds, time, gmt. 259 | * By default date generates the local time string. 260 | */ 261 | var date = lib.date = function(d, format) { 262 | var cdate = core.dateOf(d); 263 | switch(format) { 264 | case 'date' : return core.gen(cdate.getDate()); 265 | case 'hours' : return core.gen(cdate.getHours()); 266 | case 'minutes': return core.gen(cdate.getMinutes()); 267 | case 'seconds': return core.gen(cdate.getSeconds()); 268 | case 'time' : return core.gen(cdate.getTime()); 269 | case 'gmt' : return core.gen(cdate.toString()); 270 | default : return core.gen(cdate.toLocaleString()); 271 | } 272 | }; 273 | 274 | /** 275 | * A convenience function that creates a generator for current date/time. 276 | * 277 | * @function {generator} now 278 | * @param {string} format - the output format, possible values are: date, hours, minutes, seconds, time, gmt. 279 | * By default data prints the local time string. 280 | * @see Popcorn.Common.date 281 | */ 282 | var now = lib.now = function(format) { 283 | return date(new Date(), format); 284 | }; 285 | 286 | /** 287 | * Generates a random date 288 | * 289 | * @function {generator} date 290 | * @param {milisec} from - from date 291 | * @param {milisec} to - to date 292 | * @param {string} format - the output format, possible values are: date, hours, minutes, seconds, time, gmt. 293 | * By default data prints the local time string. 294 | * 295 | * @see Popcorn.Common.date 296 | */ 297 | core.RandomLib.date = function(from, to, format) { 298 | var f = from || new Date(0), 299 | t = to || new Date(99999999999999), 300 | r = this; 301 | return core.lazy(function() { return lib.date(new Date(r.int(f.getTime(), t.getTime())().result), format); }); 302 | }; 303 | 304 | return lib; 305 | 306 | }(Popcorn.Core); 307 | 308 | -------------------------------------------------------------------------------- /src/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 'Core' module combines 'Utils' and 'Core' namespace. 3 | * 4 | * @module Popcorn.Core 5 | */ 6 | 7 | /** 8 | * Root Popcorn namespace. 9 | * 10 | * @namespace Popcorn 11 | * @author Adam Smyczek 12 | */ 13 | var Popcorn = Popcorn || {}; 14 | 15 | // -------------------------------------------------------------------------- 16 | 17 | /** 18 | * 'Utils' namespace contains helper functions used by all Popcorn modules. 19 | * 20 | * @namespace Popcorn.Utils 21 | * @author Adam Smyczek 22 | */ 23 | Popcorn.Utils = function () { 24 | 25 | var lib = {}; 26 | 27 | /** 28 | * Applies function 'f' on all elements of array 'as'.
29 | * map(f, as) => [f(as[i])] 30 | * 31 | * @function {any[]} map 32 | * @param {function} f - function. 33 | * @param {any[]} as - input array. 34 | */ 35 | var map = lib.map = function(f, as) { 36 | var ar = lib.arrayOf(as), 37 | l = as.length, 38 | r = []; 39 | for (var i = 0; i < l; i++) { 40 | r[i] = f(ar[i]); 41 | } 42 | return r; 43 | }; 44 | 45 | var O = function() {}; 46 | /** 47 | * Creates a new object with the argument objects as prototype. 48 | * 49 | * @function {object} clone 50 | * @param {object} o - the object to clone. 51 | */ 52 | var clone = lib.clone = function(o) { 53 | O.prototype = o; 54 | return new O(); 55 | }; 56 | 57 | /** 58 | * Merges argument objects together. 59 | * This function copies all attributes of all argument 60 | * objects into one. Use with care, name conflicts are 61 | * not handled, attributes can be overwritten. 62 | * 63 | * @function {object} merge 64 | * @param {object+} os - one ore more objects to merge. 65 | */ 66 | var merge = lib.merge = function() { 67 | var args = lib.args2array(arguments), r = {}, arg; 68 | for (var i = 0, l = args.length; i < l; i++) { 69 | arg = args[i]; 70 | for (var name in arg) { 71 | if (arg.hasOwnProperty(name)) { 72 | r[name] = arg[name]; 73 | } 74 | } 75 | } 76 | return r; 77 | }; 78 | 79 | /** 80 | * Converts JavaScript function arguments to an array.
81 | * For example: 82 | *
  83 |    *   function() {
  84 |    *     var args = args2array(arguments);
  85 |    *     ...
  86 |    *   }
  87 |    * 
88 | * 89 | * @function {any[]} args2array 90 | * @param {arguments} args - the JavaScript function 'arguments'. 91 | */ 92 | var args2array = lib.args2array = function(args) { 93 | return Array.prototype.slice.apply(args); 94 | }; 95 | 96 | /** 97 | * Function arguments parser for 'range' functions.
98 | * A 'range' function performs operations on an input 99 | * range between a min and max integer value. 100 | * A 'range' function takes no arguments, or one or two 101 | * integer arguments. Bases on arguments the function is 102 | * called with and the provided default 'min' and 'max' 103 | * values, 'args2rage' returns the following range array: 104 | *
    105 | *
  • no args -> [min, max]
  • 106 | *
  • one arg -> [min, arg one]
  • 107 | *
  • two args -> [arg one, arg two]
  • 108 | *
109 | * For example: 110 | *
 111 |    *   function() {
 112 |    *     var min_max = args2range(arguments);
 113 |    *     ...
 114 |    *   }
 115 |    * 
116 | * @see Popcorn.Common.range for an example range function. 117 | * 118 | * @function {any[]} args2range 119 | * @param {arguments} args - the JavaScript function 'arguments'. 120 | * @param {integer} min - range min value used when no arguments are passed to the range function. 121 | * @param {integer} max - range max value used when no or one argument is passed to the range function. 122 | */ 123 | var args2range = lib.args2range = function(args, min, max) { 124 | var a0 = min, a1 = max, as = args2array(args); 125 | switch(as.length) { 126 | case 1 : a1 = lib.intOf(as[0]); 127 | break; 128 | case 2 : a0 = lib.intOf(as[0]); 129 | a1 = lib.intOf(as[1]); 130 | break; 131 | } 132 | return [Math.min(a0, a1), Math.max(a0, a1)]; 133 | }; 134 | 135 | /** 136 | * 'typeOf' extends JavaScript 'typeof' operator with 137 | * support for 'null', 'undefined', 'array' and 138 | * 'date' types. 139 | * See 'Remedial JavaScript' 140 | * for more details. 141 | * 142 | * @function {string} typeOf 143 | * @param {any} inp - any variable, object etc. 144 | * @return a string representation of the type, for example 'null', 'array', 'data'. 145 | */ 146 | var typeOf = lib.typeOf = function(inp) { 147 | if (inp === null) { return 'null'; } 148 | if (inp === undefined) { return 'undefined'; } 149 | 150 | var ot = typeof(inp); 151 | if (ot !== 'object') { return ot; } 152 | if ((typeof(inp.length) === 'number') && 153 | !(inp.propertyIsEnumerable('length')) && 154 | (typeof(inp.splice) === 'function')) { 155 | return 'array'; 156 | } 157 | if (!isNaN (new Date(inp).getDate())) { 158 | return 'date'; 159 | } 160 | return 'object'; 161 | }; 162 | 163 | /** 164 | * @function {boolean} isNull 165 | * @param {any} inp - any variable, object etc. 166 | * @return true if the input is null. 167 | */ 168 | var isNull = lib.isNull = function(inp) { 169 | return typeOf(inp) === 'null'; 170 | }; 171 | 172 | /** 173 | * @function {boolean} isUndefined 174 | * @param {any} inp - any variable, object etc. 175 | * @return true if the input is undefined. 176 | */ 177 | var isUndefined = lib.isUndefined = function(inp) { 178 | return typeOf(inp) === 'undefined'; 179 | }; 180 | 181 | /** 182 | * @function {boolean} isString 183 | * @param {any} inp - any variable, object etc. 184 | * @return true if the input is a string. 185 | */ 186 | var isString = lib.isString = function(inp) { 187 | return typeOf(inp) === 'string'; 188 | }; 189 | 190 | /** 191 | * @function {boolean} isNumber 192 | * @param {any} inp - any variable, object etc. 193 | * @return true if the input is a number. 194 | */ 195 | var isNumber = lib.isNumber = function(inp) { 196 | return typeOf(inp) === 'number'; 197 | }; 198 | 199 | /** 200 | * @function {boolean} isInt 201 | * @param {any} inp - any variable, object etc. 202 | * @return true if the input is an int. 203 | */ 204 | var isInt = lib.isInt = function(inp) { 205 | try { 206 | var i = lib.numberOf(inp); 207 | return Math.floor(i) === i; 208 | } catch(e) { 209 | return false; 210 | } 211 | }; 212 | 213 | /** 214 | * @function {boolean} isFunction 215 | * @param {any} inp - any variable, object etc. 216 | * @return true if the input is a function. 217 | */ 218 | var isFunction = lib.isFunction = function(inp) { 219 | return typeOf(inp) === 'function'; 220 | }; 221 | 222 | /** 223 | * @function {boolean} isArray 224 | * @param {any} inp - any variable, object etc. 225 | * @return true if the input is an array. 226 | */ 227 | var isArray = lib.isArray = function(inp) { 228 | return typeOf(inp) === 'array'; 229 | }; 230 | 231 | /** 232 | * @function {boolean} isDate 233 | * @param {any} inp - any variable, object etc. 234 | * @return true if the input is a date object. 235 | */ 236 | var isDate = lib.isDate = function(inp) { 237 | return typeOf(inp) === 'date'; 238 | }; 239 | 240 | /** 241 | * @function {boolean} isObject 242 | * @param {any} inp - any variable, object etc. 243 | * @return true if the input is an object (not an array of function). 244 | */ 245 | var isObject = lib.isObject = function(inp) { 246 | return typeOf(inp) === 'object'; 247 | }; 248 | 249 | /** 250 | * @function {string} stringOf 251 | * @param {any} inp - any variable, object etc. 252 | * @return the input object if it is a string and throws an exception otherwise. 253 | * @throws an exception if input is not a string. 254 | */ 255 | var stringOf = lib.stringOf = function(inp) { 256 | if (!isString(inp)) { 257 | throw "Invalid input '" + inp + "', expecting a String!"; 258 | } 259 | return inp; 260 | }; 261 | 262 | /** 263 | * @function {number} numberOf 264 | * @param {any} inp - any variable, object etc. 265 | * @return the input object if it is a number and throws an exception otherwise. 266 | * @throws an exception if input is not a number. 267 | */ 268 | var numberOf = lib.numberOf = function(inp) { 269 | if (!isNumber(inp)) { 270 | throw "Invalid input '" + inp + "', expecting a Number!"; 271 | } 272 | return inp; 273 | }; 274 | 275 | /** 276 | * 'intOf' truncates the input to an int if the input object is a number. 277 | * An exception is thrown when the input is not a number. 278 | * 279 | * @function {integer} intOf 280 | * @param {any} inp - any variable, object etc. 281 | * @return the input object if it is an int and throws an exception otherwise. 282 | * @throws an exception if input is not an int. 283 | */ 284 | var intOf = lib.intOf = function(inp) { 285 | try { 286 | return Math.floor(numberOf(inp)); 287 | } catch(e) { 288 | throw "Invalid input '" + inp + "', expecting an Integer!"; 289 | } 290 | }; 291 | 292 | /** 293 | * @function {function} functionOf 294 | * @param {any} inp - any variable, object etc. 295 | * @return the input object if it is a function and throws an exception otherwise. 296 | * @throws an exception if input is not a function. 297 | */ 298 | var functionOf = lib.functionOf = function(inp) { 299 | if (!isFunction(inp)) { 300 | throw "Invalid input '" + inp + "', expecting a Function!"; 301 | } 302 | return inp; 303 | }; 304 | 305 | /** 306 | * @function {date} dateOf 307 | * @param {any} inp - any variable, object etc. 308 | * @return the input object if it is a date object or a date string. 309 | * @throws an exception if input is not a date object. 310 | */ 311 | var dateOf = lib.dateOf = function(inp) { 312 | var d = (isString(inp))? new Date(Date.parse(inp)) : inp; 313 | if (!isDate(d)) { 314 | throw "Invalid input '" + inp + "', expecting an Date object or parsable date string!"; 315 | } 316 | return d; 317 | }; 318 | 319 | /** 320 | * @function {any[]} arrayOf 321 | * @param {any} inp - any variable, object etc. 322 | * @return the input object if it is an array and throws an exception otherwise. 323 | * @throws an exception if input is not an array. 324 | */ 325 | var arrayOf = lib.arrayOf = function(inp) { 326 | if (!isArray(inp)) { 327 | throw "Invalid input '" + inp + "', expecting an Array!"; 328 | } 329 | return inp; 330 | }; 331 | 332 | return lib; 333 | 334 | }(); 335 | 336 | // -------------------------------------------------------------------------- 337 | 338 | /** 339 | * 'Core' namespace defines the basic generators for JavaScript primitive types 340 | * and objects.
341 | * The generator library is build on top of the monadic combinators 342 | * 'return' and 'bind' called 'gen' and 'chain'. However for 343 | * better performance most internal generators have imperative implementations.
344 | * 345 | * @namespace Popcorn.Core 346 | * @author Adam Smyczek 347 | */ 348 | Popcorn.Core = function (utils) { 349 | 350 | // This package object extends utils. 351 | var lib = utils.clone(utils); 352 | 353 | // Object Generation mode 354 | var MODE_PERMUTATE = 'mode_permutate'; 355 | var MODE_CIRCULATE = 'mode_circulate'; 356 | 357 | // ------ Basic operators ------ 358 | 359 | /** 360 | * Identity 361 | * 362 | * @function {any} id 363 | * @param {any} value - any value 364 | * @return the value 365 | */ 366 | var id = lib.id = function (v) { 367 | return v; 368 | }; 369 | 370 | /** 371 | * 'gen' creates a generator that returns the argument value 'v' 372 | * when executed on any input object. 'gen' is basically a generator 373 | * constructor that wraps any value into a generator.
374 | * For example: 375 | *
 376 |    *   var g = gen('test');
 377 |    *   g('any input') will return 'test'.
 378 |    * 
379 | * 380 | * @function {generator} gen 381 | * @param {any} inp - any variable, object etc. 382 | * @return a {@link generator} which executed returns the value 'v'. 383 | */ 384 | var gen = lib.gen = function(v) { 385 | return function (_, s) { return { result: v, state: s }; }; 386 | }; 387 | 388 | /** 389 | * Use 'chain' to execute generators in sequence. 'chain' 390 | * executes the argument generator or generator array 'g' 391 | * and passes the result to the parameter function 'f'. 392 | * 'f' may evaluate the result but always has to return 393 | * a new generator. 'chain' itself is a generator that can 394 | * be evaluated or passed to another chain or other 395 | * generator function.
396 | * For example: 397 | *
 398 |    *   var g = chain(gen(1), function(r) { return gen(r + 1); });
 399 |    *   g('any input') will evaluate to 2.
 400 |    * 
401 | * 402 | * @function {generator} chain 403 | * @paramset 404 | * @param {generator} g - a {@link generator} 405 | * @param {function} f - a function that takes the result of the generator 406 | * 'g' and returns a new generator as result. 407 | * 408 | * @paramset 409 | * @param {generator[]} gs - {@link generator} array 410 | * @param {function} f - a function that takes the array result 411 | * of all generators 'gs' and returns a new generator as result. 412 | * 413 | * @return the 'chain' generator. 414 | */ 415 | var chain = lib.chain = function(g, f) { 416 | return function(o, s) { 417 | var r, a; 418 | if (utils.isArray(g)) { 419 | r = lib.seq(g, lib.cConcat)(o, s); 420 | return f(r.result)(o, r.state); 421 | } else { 422 | r = g(o, s); 423 | a = f(r.result); 424 | return (utils.isArray(a))? lib.seq(a, lib.cConcat)(o, r.state) : a(o, r.state); 425 | } 426 | }; 427 | }; 428 | 429 | /** 430 | * 'seq' executes the generators 'gs' and combines the result using 431 | * {@link combinator} function 'f'. Combinator 'f' is called on every 432 | * step with the result of previous executions ('init' value on first call) 433 | * and the result of the current generator evaluation.
434 | * For example: 435 | *
 436 |    *   var g = seq([gen('a'), gen('b'), gen('c')], cJoin, 0);
 437 |    *   g('any input') will return 'abc'.
 438 |    * 
439 | * 440 | * @function {generator} seq 441 | * @param {generator[]} gs - {@link generator} array. 442 | * @param {combinator} f - {@link combinator} function. 443 | * @param {any} init - the initial value passed on first call to the {@link combinator}. 444 | * 445 | * @see Popcorn.Core.cConcat 446 | * @see Popcorn.Core.cJoin 447 | * 448 | * @return the sequence generator that evaluates the generators 'gs' when executed. 449 | */ 450 | var seq = lib.seq = function(gs, f, init) { 451 | return function(o, s) { 452 | if (gs.length > 0) { 453 | var r = init, ns = s, ir; 454 | for (var i = 0, l = gs.length; i < l; i++) { 455 | ir = gs[i](o, ns); 456 | r = f(r, ir.result, i); 457 | ns = ir.state; 458 | } 459 | return { result: r, state: ns }; 460 | } 461 | return { result: o, state: s }; 462 | }; 463 | }; 464 | 465 | /** 466 | * Repeats value 'v' 'n'-times and returns the resulting array. 467 | * If parameter 'v' is an array, the subsequent results are concatenated. 468 | * 'repeat' is commonly used with object generators, for example: 469 | *
 470 |    *   var gen = {
 471 |    *     name : repeat(3, gen('abc'))
 472 |    *   }
 473 |    *   will generate three objects { name : 'abc' } when evaluated with {@link generate}.
 474 |    * 
475 | * See {@link Popcorn.Core.generate} for details. 476 | * 477 | * @function {any[]} repeat 478 | * @param {integer} n - repeat count. 479 | * @param {any} v - object or generator to repeat. 480 | */ 481 | var repeat = lib.repeat = function(n, v) { 482 | var c = Math.max(1, utils.intOf(n)), 483 | vs = []; 484 | if (utils.isArray(v)) { 485 | while (c--) { vs.push.apply(vs, v); } 486 | } else if (utils.isFunction(v)) { 487 | while (c--) { vs.push(v); } 488 | } else { 489 | while (c--) { vs.push(gen(v)); } 490 | } 491 | return vs; 492 | }; 493 | 494 | /** 495 | * 'replicate' executes generator 'g' 'n'-times and combines 496 | * the results using {@link combinator} function 'f'. 497 | * This function is a specialization of {@link seq}.
498 | * Example: 499 | *
 500 |    *   var overflow = replicate(gen('A'), cJoin, '');
 501 |    *   overflow(5) generates 'AAAAA'
 502 |    * 
503 | * 504 | * @function {generator} replicate 505 | * @param {generator} g - a {@link generator}. 506 | * @param {combinator} f - {@link combinator} function. 507 | * @param {any} init - the initial value for the {@link combinator} function 'f'. 508 | * @see Popcorn.Core.seq 509 | * @return the replicator generator 510 | */ 511 | var replicate = lib.replicate = function(g, f, init) { 512 | return function(n) { 513 | var c = Math.max(1, utils.intOf(n)), 514 | gs = []; 515 | for (var i = 0; i < c; i++) { gs[i] = g; } 516 | return seq(gs, f, init); 517 | }; 518 | }; 519 | 520 | /** 521 | * 'cConcat' {@link combinator} function concatenates the results 522 | * of generators executed in sequence into one array.
523 | * For example: 524 | *
 525 |    *   seq([gen(1), gen(2)], cConcat)() => [1,2]
 526 |    * 
527 | * 'cConcat' can be used in combination with {@link seq] and {@link replicate}. 528 | * 529 | * @function {any} cConcat 530 | * @param {any} r - combined result of previous executions. 531 | * @param {any} n - result of current generator evaluation. 532 | */ 533 | var cConcat = lib.cConcat = function(r, n) { return (r || []).concat(n); }; 534 | 535 | /** 536 | * 'cJoin' combinator function joins the results of generators 537 | * executed in sequence into one string.
538 | * For example: 539 | *
 540 |    *   seq([gen(1), gen(2)], cJoin)() => '12'
 541 |    * 
542 | * 'cJoin' can be used in combination with {@link seq] and {@link replicate}. 543 | * 544 | * @function {any} cJoin 545 | * @param {any} r - combined result of previous executions. 546 | * @param {any} n - result of current generator evaluation. 547 | */ 548 | var cJoin = lib.cJoin = function(r, n) { return (r || '') + n; }; 549 | 550 | // ------ Handling objects ------ 551 | 552 | /** 553 | * 'property' applies generator 'g' on an object property of name 554 | * 'name' and returns the resulting object. 'property' acts as a 555 | * property selector and is a generator itself that can be 556 | * evaluated or passed to other generators.
557 | * For example: 558 | *
 559 |    *   var o    = { name:'Woody', toy:'cowboy' };
 560 |    *   var name = property('name');
 561 |    *   name(gen('Buzz'))(o) will return the object { name:'Buzz', toy:'cowboy' }
 562 |    * 
563 | * 564 | * @function {generator} property 565 | * @param {string} name - object property name. 566 | */ 567 | var property = lib.property = function(name) { 568 | return function(g) { 569 | return function(o, s) { 570 | var r = g(o[name]); 571 | o[name] = r.result; 572 | return { result: o, state: r.state }; 573 | }; 574 | }; 575 | }; 576 | 577 | /** 578 | * Executes generators 'gs' on an input object 579 | * and returns the updated object.
580 | * For example: 581 | *
 582 |    *   var o    = { name: 'Woody', toy: 'cowboy' };
 583 |    *   var name = property('name');
 584 |    *   var toy  = property('toy');
 585 |    *   update([name(gen('Buzz')), toy(gen('action figure'))])(o) will return the object 
 586 |    *   { name:'Buzz', toy:'action figure' }
 587 |    * 
588 | * 589 | * @function {generator} update 590 | * @param {generator[]} gs - {@link generator} array. 591 | */ 592 | var update = lib.update = function(gs) { 593 | return seq(gs, function(r, n) { return r || n; }); 594 | }; 595 | 596 | /** 597 | * 'mutate' executes generators 'gs' on the input object o. 598 | * For example: 599 | *
 600 |    *   mutate([gen('Buzz'), gen('Woody')](o) will return 
 601 |    *   ['Buzz', 'Woody']
 602 |    * 
603 | * @function {generator} mutate 604 | * @param {generator[]} gs - {@link generator} array. 605 | */ 606 | var mutate = lib.mutate = function(gs) { 607 | return function(o, s) { 608 | if (gs.length > 0) { 609 | var r = [], ns = s, ogr; 610 | for(var i = 0, l = gs.length; i < l; i++) { 611 | var gr = gs[i](o, ns); 612 | ns = gr.state; 613 | 614 | // Mutate on an array 615 | if (utils.isArray(gr.result)) { 616 | for (var j = 0, jl = gr.result.length; j < jl; j++) { 617 | r.push(gr.result[j]); 618 | } 619 | 620 | // Mutate on a group generator 621 | } else if (utils.isObject(gr.result) && (gr.result._array_result === true)) { 622 | ogr = (utils.isArray(gr.result._generator))? 623 | seq(gr.result._generator, cConcat)(o, ns) : 624 | gr.result._generator(o, ns); 625 | ns = ogr.state; 626 | r.push((gr.result._join_result === true)? ogr.result : ogr.result.join()); 627 | 628 | // Mutate on an inner-object 629 | // TODO currently supported for permutation only 630 | } else if (utils.isObject(gr.result)) { 631 | if (MODE_PERMUTATE === ns._generation_mode) { 632 | ogr = lib.permutate(gr.result, o, -1, ns, id); 633 | ns = ogr.state; 634 | for (var k = 0, kl = ogr.result.length; k < kl; k++) { 635 | r.push(ogr.result[k]); 636 | } 637 | } else { 638 | r.push(gr.result); 639 | } 640 | 641 | // All other values 642 | } else { 643 | r.push(gr.result); 644 | } 645 | } 646 | return { result: r, state: ns }; 647 | } 648 | return { result: [o], state: s }; 649 | }; 650 | }; 651 | 652 | // New object constructor function used for object 653 | // 'mutateOnAttribute' and 'permutate' functions. 654 | var O = function() {}; 655 | 656 | /** 657 | * 'mutateOnAttribute' executes generators 'gs' on an object property 658 | * of name 'name'. The result is an array that contains 659 | * one result object for every generator result value.
660 | * For example: 661 | *
 662 |    *   var o = { name: 'Woody', age:2 };
 663 |    *   mutateOnAttribute('name', [gen('Buzz'), gen('Woody')](o) will return 
 664 |    *   the object array [{ name:'Buzz', age:2 }, { name:'Woody', age:2 }]
 665 |    * 
666 | * 667 | * @function {generator} mutateOnAttribute 668 | * @param {string} name - object property name. 669 | * @param {generator[]} gs - {@link generator} array. 670 | */ 671 | var mutateOnAttribute = function(name, gs) { 672 | return function(o, s) { 673 | if (gs.length > 0) { 674 | var gr = mutate(gs)(o[name], s), 675 | rs = gr.result, 676 | r = [], n; 677 | for (var j = 0, jl = rs.length; j < jl; j++) { 678 | O.prototype = o; 679 | n = new O(); 680 | n[name] = rs[j]; 681 | r.push(n); 682 | } 683 | return { result: r, state: gr.state }; 684 | } 685 | return { result: [o], state: s }; 686 | }; 687 | }; 688 | 689 | /** 690 | * Wrappes a value into generator array, 691 | * the default input for 'mutate'. 692 | * 693 | * @function {generator[]} toGenArray 694 | * @param {value/generator/[generator]} value 695 | */ 696 | var toGenArray = function(v) { 697 | if (utils.isArray(v)) { 698 | return v; 699 | } else if (utils.isFunction(v)) { 700 | return [v]; 701 | } else { 702 | return [gen(v)]; 703 | } 704 | }; 705 | 706 | // ------ JSON object generation functions ------ 707 | 708 | /** 709 | * 'permutate' is one of two supported JSON object 710 | * generation functions. It executes the argument 711 | * generator 'gen' on the default object 'base' 712 | * and returns the resulting object array.
713 | * This generation method permutates over all results 714 | * of all attribute generator, for example: 715 | *
 716 |    *   var base = { name: 'Woody', age:2 }; 
 717 |    *   var gen  = { name: list('Buzz', 'Slinky'), age: range(2,4) }; 
 718 |    *   generate(gen, base) will return the array: 
 719 |    *    [{ name: 'Buzz',   age: 2 },
 720 |    *     { name: 'Buzz',   age: 3 }, 
 721 |    *     { name: 'Buzz',   age: 4 }, 
 722 |    *     { name: 'Slinky', age: 2 }, 
 723 |    *     { name: 'Slinky', age: 3 }, 
 724 |    *     { name: 'Slinky', age: 4 }]
 725 |    * 
726 | * 727 | * @function {object[]} permutate 728 | * @param {object} gen - the generator object. 729 | * @param {object} base - the base test case object. 730 | * @param {int} count - an optional result count 731 | * @param {object} state - an optional state object that 732 | * can be read and manipulated by any generator. 733 | * @param {function} result_transformer - an optional function 734 | * which takes the result generator object { result:r, state:s } 735 | * as argument and returns the desired result. If not defined, 736 | * the default transformer returns just the result array. 737 | * To return the result and state use 'id' function. 738 | */ 739 | var permutate = lib.permutate = function(generator, base, count, state, result_transformer) { 740 | var st = state || {}; 741 | var c = count || -1; 742 | var rt = result_transformer || function(r) { return r.result; }; 743 | var gs = [], rs = [], r; 744 | st._generation_mode = MODE_PERMUTATE; 745 | 746 | // Recursive permutate helper applies 747 | // generator 'g' on all objects 'os'. 748 | var perm_rec = function(g, os, s) { 749 | var rs = [], rr, ns = s, r, o; 750 | for (var i = 0, l = os.length; i < l; i++) { 751 | O.prototype = os[i]; 752 | o = new O(); 753 | ns._result_object = o; 754 | r = g(o, ns); 755 | ns = r.state; 756 | rs.push.apply(rs, r.result); 757 | } 758 | return { result: rs, state: ns }; 759 | }; 760 | 761 | // Permutate generator 762 | var perm_gen = function(o, s) { 763 | if (gs.length > 0) { 764 | var rs = [o], ns = s, r; 765 | for (var i = 0, l = gs.length; i < l; i++) { 766 | r = perm_rec(gs[i], rs, ns); 767 | ns = r.state; 768 | rs = r.result; 769 | } 770 | return { result: rs, state: ns }; 771 | } 772 | return { result: [o], state: s }; 773 | }; 774 | 775 | // Generation 776 | for (var name in generator) { 777 | if (generator.hasOwnProperty(name)) { 778 | gs.push(mutateOnAttribute(name, toGenArray(generator[name]))); 779 | } 780 | } 781 | 782 | // TODO: move count logic into the permutate generator 783 | // XXX: state does not match the result of the last run 784 | // if n x run > count !!! 785 | var done = false; 786 | while(!done) { 787 | r = perm_gen(base, st); 788 | rs = rs.concat(r.result); 789 | st = r.state; 790 | if (c < 0) { 791 | done = true; 792 | } else if (rs.length > c) { 793 | rs = rs.slice(0, c); 794 | done = true; 795 | } 796 | } 797 | 798 | return rt({ result : rs, state : st }); 799 | }; 800 | 801 | /** 802 | * Same as 'permutate', 'circulate' executes the argument 803 | * generator 'gen' on the default object 'base' 804 | * and returns the resulting object array.
805 | * In difference to 'permutate', the results of all 806 | * attribute generators are combined together. 807 | * If no count is provided, circulate generates object array 808 | * of the length of the longest attribute generator. 809 | * All other attribute values circulate, for example: 810 | *
 811 |    *   var base = { name: 'Woody', age:2 }; 
 812 |    *   var gen  = { name: list('Buzz', 'Slinky'), age: range(2,5) }; 
 813 |    *   generate(gen, base) will return the array: 
 814 |    *    [{ name: 'Buzz',   age: 2 },
 815 |    *     { name: 'Slinky', age: 3 }, 
 816 |    *     { name: 'Buzz',   age: 4 }, 
 817 |    *     { name: 'Slinky', age: 5 }]
 818 |    * 
819 | * 820 | * @function {object[]} circulate 821 | * @param {object} gen - the generator object. 822 | * @param {object} base - the base test case object. 823 | * @param {int} count - an optional result count 824 | * @param {object} state - an optional state object that 825 | * can be read and manipulated by any generator. 826 | * @param {function} result_transformer - an optional function 827 | * which takes the result generator object { result:r, state:s } 828 | * as argument and returns the desired result. If not defined, 829 | * the default transformer returns just the result array. 830 | * To return the result and state use 'id' function. 831 | */ 832 | var circulate = lib.circulate = function(generator, base, count, state, result_transformer) { 833 | var s = state || {}; 834 | var c = count || -1; 835 | var rt = result_transformer || function(r) { return r.result; }; 836 | s._generation_mode = MODE_CIRCULATE; 837 | s._result_object = base; 838 | 839 | var gs = {}, gr = {}, r, o, max = 0, rs = [], name; 840 | 841 | // Initialize 842 | for (name in generator) { 843 | if (generator.hasOwnProperty(name)) { 844 | gs[name] = mutate(toGenArray(generator[name])); 845 | r = gs[name](base[name], s); 846 | if (r.result.length > max) { max = r.result.length; } 847 | gr[name] = []; 848 | } 849 | } 850 | 851 | // Generate 852 | max = (c < 0)? max : c; 853 | while(max > 0) { 854 | max--; 855 | O.prototype = base; 856 | o = new O(); 857 | s._result_object = o; 858 | for (name in generator) { 859 | if (generator.hasOwnProperty(name)) { 860 | if (gr[name].length === 0) { 861 | r = gs[name](base[name], s); 862 | gr[name] = r.result; 863 | s = r.state; 864 | } 865 | o[name] = gr[name].shift(); 866 | } 867 | } 868 | rs.push(o); 869 | } 870 | 871 | return rt({ result : rs, state : s }); 872 | }; 873 | 874 | /** 875 | * 'current' provides access to current generated object. 876 | * It's experimental, use with care!!! 877 | * For example: 878 | *
 879 |    *   var o = { name: 'Woody', age:2 };
 880 |    *   var g = { name : list('Buzz', 'Woody'), 
 881 |    *             description : current(function(r) { return r.name + ' is ' + r.age; }) }
 882 |    *   permutate(g, o) will return 
 883 |    *   [{ name:'Buzz', age:2, description: 'Buzz is 2' }, 
 884 |    *    { name:'Woody', age:2, description: 'Woody is 2' }]
 885 |    * 
886 | * 887 | * @function {generator} current 888 | * @param {function} f - a callback function that takes the current 889 | * generated objects as parameter and returns 890 | * this attribute value. 891 | */ 892 | var current = lib.current = function(f) { 893 | return function(o, s) { 894 | return { result : f(s._result_object), state : s }; 895 | }; 896 | }; 897 | 898 | /** 899 | * Equivalent to 'permutate'. 900 | * @Deprecated 901 | */ 902 | var generate = lib.generate = function(generator, base, state, result_transformer) { 903 | return permutate(generator, base, -1, state, result_transformer); 904 | }; 905 | 906 | // ------ State and variables ------ 907 | 908 | /** 909 | * 'setVar' stores the result of one generator that can be used 910 | * as input to another generator in same generation process.
911 | * For example: 912 | * 913 | *
 914 |    *   var g = {
 915 |    *     int   : setVar('my_rand', random().int()),
 916 |    *     plus1 : withVar('my_rand', function(i) { return gen(i + 1); })
 917 |    *   }
 918 |    * 
919 | * 920 | * The random integer value generated for attribute 'int' is stored 921 | * in the state object under the attribute name 'my_rand' and referenced 922 | * using {@link withVar} function. 923 | * 924 | * @function {generator} setVar 925 | * @param {string} name - variable name the generator value is stored for. 926 | * @param {generator} g - the generator to execute. 927 | * @return result of the generator 'g'. 928 | */ 929 | var setVar = lib.setVar = function(name, g) { 930 | return function(o, s) { 931 | var r = g(o, s); 932 | r.state[name] = r.result; 933 | return gen(r.result)(o, r.state); 934 | }; 935 | }; 936 | 937 | /** 938 | * 'withVar' provides access to variables stored using {@link setVar} 939 | * generator. It takes the variable name and a function as argument. 940 | * The value of the variable is passed to the function that has 941 | * to return another generator as result. 942 | * For an example see {@link setVar} generator. 943 | * 944 | * @function {generator} withVar 945 | * @param {string} name - variable name. 946 | * @param {function} f - takes the variable as argument and returns 947 | * a new generator as result. 948 | */ 949 | var withVar = lib.withVar = function(name, f) { 950 | return function (o, s) { 951 | return f(s[name])(o, s); 952 | }; 953 | }; 954 | 955 | /** 956 | * Creates a generator that returns the value of the 957 | * variable 'name' when executed. For example: 958 | * 959 | *
 960 |    *   var g = {
 961 |    *     att1 : setVar('my_rand', random().int()),
 962 |    *     att2 : varGen('my_rand')
 963 |    *   }
 964 |    * 
965 | * will generate an object with same value for 966 | * both attributes. 967 | * 968 | * @function {generator} varGen 969 | * @param {string} name - variable name. 970 | */ 971 | var varGen = lib.varGen = function(name) { 972 | return function (o, s) { 973 | return gen(s[name])(o, s); 974 | }; 975 | }; 976 | 977 | /** 978 | * 'withState' provides access to the state object. 979 | * The function 'f' takes the state object as argument 980 | * and returns another generator as result. All modifications 981 | * to the state object are visible to other generators. 982 | * For example: 983 | * 984 | *
 985 |    *   var g = {
 986 |    *     int : withState(function(s) { s.init = 10; return random().int(); } ),
 987 |    *     add : withState(function(s) { return gen(s.init + 10); } )
 988 |    *   }
 989 |    * 
990 | * 991 | * @function {generator} withState 992 | * @param {function} f - takes the state object as argument and 993 | * returns a new generator as result. 994 | */ 995 | var withState = lib.withState = function(f) { 996 | return function (o, s) { 997 | return f(s)(o, s); 998 | }; 999 | }; 1000 | 1001 | /** 1002 | * Group generator results into array 1003 | * 1004 | * @function {generator} array 1005 | * @param {function} g - the generator to wrap 1006 | */ 1007 | // A work-around for not supporting seq-monad yet! 1008 | var array = lib.array = function(g) { 1009 | return gen({ _array_result : true, _generator : g }); 1010 | }; 1011 | 1012 | // ------ Core random generators ------ 1013 | 1014 | /** 1015 | * Creates a linear congruential random generator object using an optional 1016 | * 'seed' value. If 'seed' is not defined, the default JavaScript Math.random() 1017 | * function is used. See Wikipedia 1018 | * LCR 1019 | * for details. 1020 | * 1021 | * @function {random} random 1022 | * @param {integer} seed - an optional seed. 1023 | * @return the random generator object. 1024 | */ 1025 | var random = lib.random = function(seed) { 1026 | var m = 4294967296, // 2^32 1027 | a = 1103515245, // glibc conform multiplier 1028 | c = 12345, // and increment 1029 | s = seed || Math.floor(Math.random() * m), 1030 | x = s % m; 1031 | 1032 | // Moves to the next pseudo-random value in the sequence 1033 | // and generates next int in the range from min to max. 1034 | var nextInt = function(min, max) { 1035 | x = (a * x + c) % m; 1036 | return Math.floor(min + x/m * (max - min)); 1037 | }; 1038 | 1039 | /** 1040 | * Random generator object. 1041 | * This object implements all {@link Popcorn.Core.RandomLib} 1042 | * generator functions. 1043 | * 1044 | * @object Popcorn.Core.Random 1045 | */ 1046 | var rand = utils.clone(lib.RandomLib); 1047 | 1048 | /** 1049 | * A random integer generator. 'int' is a rage function 1050 | * that generates a value between min and max, depending 1051 | * on arguments the function is called with. 1052 | * 1053 | * @function {generator} int 1054 | * @paramset No arguments - the generator returns a random value between 0 and 100. 1055 | * @paramset One int argument - the generator returns a random value between 0 and max. 1056 | * @param {integer} max - max value. 1057 | * @paramset Two int argument - the generator returns a random value between min and max. 1058 | * @param {integer} min - from integer 1059 | * @param {integer} max - to integer 1060 | * @return a generator which executed generates a random integer. 1061 | */ 1062 | rand.int = function() { 1063 | var mm = utils.args2range(arguments, 0, 1000); 1064 | return lib.lazy(function() { return gen(nextInt(mm[0], mm[1])); }); 1065 | }; 1066 | 1067 | /** 1068 | * 'element' picks a random element from provided argument array 'as'. 1069 | * 1070 | * @function {generator} element 1071 | * @param {any[]} as - array 1072 | * @return the element generator which executed returns a random element 1073 | * from argument array 'as'. 1074 | */ 1075 | rand.element = function(as) { 1076 | if (as.length > 0) { 1077 | return lib.lazy(function() { return gen(as[nextInt(0, as.length)]); }); 1078 | } 1079 | throw "Empty array or string!"; 1080 | }; 1081 | 1082 | return rand; 1083 | }; 1084 | 1085 | /** 1086 | * Extensible library class for random generators. 1087 | * 'RandomLib' can be extended by other modules as following: 1088 | *
1089 |    *   core.RandomLib.randomAlpha = function() {...}; 
1090 |    * 
1091 | * Once the module is loaded, 'randomAlpha' is available 1092 | * in the {@link Random} object and can be executed as: 1093 | *
1094 |    *   random().randomAlpha();
1095 |    * 
1096 | * 1097 | * @class Popcorn.Core.RandomLib 1098 | * @see Popcorn.Common.alpha 1099 | */ 1100 | var RandomLib = lib.RandomLib = {}; 1101 | 1102 | // ------ Other generator functions ------ 1103 | 1104 | /** @scope Popcorn.Core */ 1105 | 1106 | /** 1107 | * Lazy generator evaluation wrapper 1108 | * used for example by random generators.
1109 | * For example: 1110 | *
1111 |    *   var g1 = gen(Math.random());
1112 |    *   var g2 = lazy(function() { return gen(Math.random()); });
1113 |    *   g1 will always return the same value and g2 a different one
1114 |    *   when executed.
1115 |    * 
1116 | * 1117 | * @function {generator} lazy 1118 | * @param g - the {@link generator} to wrap. 1119 | */ 1120 | var lazy = lib.lazy = function(g) { 1121 | return function(o, s) { return g(o, s)(o, s); }; 1122 | }; 1123 | 1124 | /** 1125 | * 'mapGen' is a helper function that 1126 | * converts all elements of an array to 1127 | * generators.
1128 | * magGen(as) -> [gen(as[i])] 1129 | * 1130 | * @function {generator[]} mapGen 1131 | * @param {any[]} vs - array. 1132 | */ 1133 | var mapGen = lib.mapGen = function(vs) { 1134 | return utils.map(gen, vs); 1135 | }; 1136 | 1137 | return lib; 1138 | 1139 | }(Popcorn.Utils); 1140 | 1141 | -------------------------------------------------------------------------------- /src/dictionary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.Dictionary 3 | * @requires Popcorn.Core 4 | */ 5 | 6 | /** 7 | * Base functions and objects to build dictionaries. 8 | * 9 | * @namespace Popcorn.Dictionary 10 | * @author Adam Smyczek 11 | * @author Brian Wilkerson 12 | */ 13 | Popcorn.Dictionary = function (core) { 14 | 15 | var lib = {}; 16 | 17 | /** 18 | * Creates a {@link Dict} object for an dictionary array.
19 | * For example: 20 | *
 21 |    *   The pronouns dictionary
 22 |    *     var pronoun = dictionary(['I', 'you', 'he', 'she', 'it']);
 23 |    *   provides generators:
 24 |    *     pronoun.list(), pronoun.element(), etc.
 25 |    * 
26 | * 27 | * @function {object} dictionary 28 | * @param {any[]} dict - a dictionary array. 29 | * @return a dictionary object. 30 | */ 31 | var dictionary = lib.dictionary = function(dict) { 32 | 33 | /** 34 | * A base dictionary object provides common 35 | * generators for array dictionaries. 36 | * 37 | * @object Popcorn.Dictionary.Dict 38 | */ 39 | return { 40 | 41 | /** 42 | * Creates a generator to list dictionary elements. 43 | * By default all dictionary elements are listed. If 'n' > dict.length 44 | * the resulting elements are repeated in loop. 45 | * 'list' is a range function that takes no arguments, or 46 | * one or two integer arguments. 47 | * 48 | * @function {generator} list 49 | * @paramset No arguments - the generator returns the entire dictionary. 50 | * @paramset One int argument - the generator returns the first n elements. 51 | * @param {integer} n - element count. 52 | * @paramset two int arguments - the generator returns elements from n to m 53 | * @param {integer} n - from list index 54 | * @param {integer} m - to list index 55 | * 56 | * @see Popcorn.Utils.args2range 57 | */ 58 | list : function() { 59 | var mm = core.args2range(arguments, 0, dict.length), 60 | ar = dict, r = []; 61 | while (ar.length < mm[1]) { 62 | ar.push.apply(ar, dict); 63 | } 64 | for (var i = 0, l = mm[1] - mm[0]; i < l; i++) { 65 | r[i] = core.gen(ar[mm[0] + i]); 66 | } 67 | return r; 68 | }, 69 | 70 | /** 71 | * 'element' returns one random dictionary element. 72 | * This generator uses a random generator 'rand' if 73 | * provided, otherwise creates a new {@link Popcorn.Core.random} 74 | * generator. 75 | * 76 | * @function {generator} element 77 | * @param {random} rand - a random generator 'random()'. 78 | * 79 | * @see Popcorn.Core.random 80 | */ 81 | element : function(rand) { 82 | var r = rand || core.random(); 83 | return core.lazy(function() { return r.element(dict); }); 84 | }, 85 | 86 | /** 87 | * 'elements' returns n random dictionary element. 88 | * 89 | * @function {generator} elements 90 | * @param {integer} n - element count to generate 91 | * @param {random} rand - optional a random generator 'random()'. 92 | * 93 | * @see Popcorn.Core.random 94 | */ 95 | elements : function(n, rand) { 96 | var c = n || 5, 97 | r = rand || core.random(); 98 | return core.repeat(c, r.element(dict)); 99 | } 100 | 101 | }; 102 | 103 | }; 104 | 105 | // ------ Lorem ipsum ------ 106 | 107 | var lorem_ipsum = [ 108 | 'Lorem', 'ipsum', 'dolor', 'sit', 'amet,', 'consectetur', 'adipisicing', 'elit,', 109 | 'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore', 110 | 'magna', 'aliqua.', 'Ut', 'enim', 'ad', 'minim', 'veniam,', 'quis', 'nostrud', 111 | 'exercitation', 'ullamco', 'laboris', 'nisi', 'ut', 'aliquip', 'ex', 'ea', 112 | 'commodo', 'consequat.', 'Duis', 'aute', 'irure', 'dolor', 'in', 'reprehenderit', 113 | 'in', 'voluptate', 'velit', 'esse', 'cillum', 'dolore', 'eu', 'fugiat', 'nulla', 114 | 'pariatur.', 'Excepteur', 'sint', 'occaecat', 'cupidatat', 'non', 'proident,', 115 | 'sunt', 'in', 'culpa', 'qui', 'officia', 'deserunt', 'mollit', 'anim', 'id', 116 | 'est', 'laborum.']; 117 | 118 | /** @scope Popcorn.Dictionary */ 119 | 120 | /** 121 | * Generate a lorem ipsum 122 | * content of the length 'n'. 123 | * This function returns the lorem ipsum if 'n' is not defined. 124 | * 125 | * @function {generator} loremIpsum 126 | * @param {integer} n - optional length of the generated lorem ipsum content. 127 | * @param {integer} m - optional min/max length randomly chosen. 128 | */ 129 | var loremIpsum = lib.loremIpsum = function(n) { 130 | var l = n || lorem_ipsum.length; 131 | return core.gen(lorem_ipsum.slice(0, l).join(" ")); 132 | }; 133 | 134 | /** 135 | * Random length lorem ipsum generator. 136 | * 137 | * @function {generator[int]} loremIpsum 138 | * @paramset No arguments - generates a range from 0 to lorem ipsum length 139 | * @paramset One int argument - generates a range from 0 to lorem ipsum length. 140 | * @param {integer} max - range max value. 141 | * @paramset two int arguments - from-to range. 142 | * @param {integer} min - from integer 143 | * @param {integer} max - to integer 144 | * 145 | * @see Popcorn.Core.random 146 | */ 147 | core.RandomLib.loremIpsum = function() { 148 | var mm = core.args2range(arguments, 0, lorem_ipsum.length); 149 | return core.gen(lorem_ipsum.slice(mm[0], mm[0] + this.int(mm[0], mm[1])().result).join(" ")); 150 | }; 151 | 152 | return lib; 153 | 154 | }(Popcorn.Core); 155 | 156 | -------------------------------------------------------------------------------- /src/names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.Names 3 | * @requires Popcorn.Core 4 | * @requires Popcorn.Dictionary 5 | */ 6 | 7 | /** 8 | * Most common English names and surnames dictionaries.
9 | * Credits to 10 | * Chris Pound's language machines. 11 | * 12 | * @namespace Popcorn.Names 13 | * @author Brian Wilkerson 14 | * @author Adam Smyczek 15 | */ 16 | Popcorn.Names = function (core, dict) { 17 | 18 | var lib = {}; 19 | 20 | // Names dictionary 21 | // http://www.ruf.rice.edu/~pound/english-m 22 | // http://www.ruf.rice.edu/~pound/english-f 23 | var names_dict = [ 24 | "Aimee", "Aleksandra", "Alice", "Alicia", "Allison", "Alyssa", "Amy", "Andrea", "Angel", "Angela", 25 | "Ann", "Anna", "Anne", "Anne", "Marie", "Annie", "Ashley", "Barbara", "Beatrice", "Beth", "Betty", 26 | "Brenda", "Brooke", "Candace", "Cara", "Caren", "Carol", "Caroline", "Carolyn", "Carrie", 27 | "Cassandra", "Catherine", "Charlotte", "Chrissy", "Christen", "Christina", "Christine", 28 | "Christy", "Claire", "Claudia", "Courtney", "Crystal", "Cynthia", "Dana", "Danielle", "Deanne", 29 | "Deborah", "Deirdre", "Denise", "Diane", "Dianne", "Dorothy", "Eileen", "Elena", "Elizabeth", 30 | "Emily", "Erica", "Erin", "Frances", "Gina", "Giulietta", "Heather", "Helen", "Jane", "Janet", "Janice", 31 | "Jenna", "Jennifer", "Jessica", "Joanna", "Joyce", "Julia", "Juliana", "Julie", "Justine", "Kara", 32 | "Karen", "Katharine", "Katherine", "Kathleen", "Kathryn", "Katrina", "Kelly", "Kerry", "Kim", 33 | "Kimberly", "Kristen", "Kristina", "Kristine", "Laura", "Laurel", "Lauren", "Laurie", "Leah", 34 | "Linda", "Lisa", "Lori", "Marcia", "Margaret", "Maria", "Marina", "Marisa", "Martha", "Mary", "Mary", 35 | "Ann", "Maya", "Melanie", "Melissa", "Michelle", "Monica", "Nancy", "Natalie", "Nicole", "Nina", 36 | "Pamela", "Patricia", "Rachel", "Rebecca", "Renee", "Sandra", "Sara", "Sharon", "Sheri", "Shirley", 37 | "Sonia", "Stefanie", "Stephanie", "Susan", "Suzanne", "Sylvia", "Tamara", "Tara", "Tatiana", "Terri", 38 | "Theresa", "Tiffany", "Tracy", "Valerie", "Veronica", "Vicky", "Vivian", "Wendy", 39 | "Aaron", "Adam", "Adrian", "Alan", "Alejandro", "Alex", "Allen", "Andrew", "Andy", "Anthony", "Art", 40 | "Arthur", "Barry", "Bart", "Ben", "Benjamin", "Bill", "Bobby", "Brad", "Bradley", "Brendan", "Brett", 41 | "Brian", "Bruce", "Bryan", "Carlos", "Chad", "Charles", "Chris", "Christopher", "Chuck", "Clay", 42 | "Corey", "Craig", "Dan", "Daniel", "Darren", "Dave", "David", "Dean", "Dennis", "Denny", "Derek", "Don", 43 | "Doug", "Duane", "Edward", "Eric", "Eugene", "Evan", "Frank", "Fred", "Gary", "Gene", "George", "Gordon", 44 | "Greg", "Harry", "Henry", "Hunter", "Ivan", "Jack", "James", "Jamie", "Jason", "Jay", "Jeff", "Jeffrey", 45 | "Jeremy", "Jim", "Joe", "Joel", "John", "Jonathan", "Joseph", "Justin", "Keith", "Ken", "Kevin", "Larry", 46 | "Logan", "Marc", "Mark", "Matt", "Matthew", "Michael", "Mike", "Nat", "Nathan", "Patrick", "Paul", "Perry", 47 | "Peter", "Philip", "Phillip", "Randy", "Raymond", "Ricardo", "Richard", "Rick", "Rob", "Robert", "Rod", 48 | "Roger", "Ross", "Ruben", "Russell", "Ryan", "Sam", "Scot", "Scott", "Sean", "Shaun", "Stephen", "Steve", 49 | "Steven", "Stewart", "Stuart", "Ted", "Thomas", "Tim", "Toby", "Todd", "Tom", "Troy", "Victor", "Wade", 50 | "Walter", "Wayne", "William"]; 51 | 52 | /** 53 | * English names dictionary. 54 | * 55 | * @function {Dict} names 56 | * @return dictionary object containing most common English names. 57 | * 58 | * @see Popcorn.Dictionary.Dict 59 | */ 60 | var names = lib.names = dict.dictionary(names_dict); 61 | 62 | 63 | // Surname dictionary 64 | // http://www.ruf.rice.edu/~pound/english-s 65 | var surnames_dict = [ 66 | "Adams", "Adamson", "Adler", "Akers", "Akin", "Aleman", "Alexander", "Allen", "Allison", "Allwood", 67 | "Anderson", "Andreou", "Anthony", "Appelbaum", "Applegate", "Arbore", "Arenson", "Armold", 68 | "Arntzen", "Askew", "Athanas", "Atkinson", "Ausman", "Austin", "Averitt", "Avila-Sakar", 69 | "Badders", "Baer", "Baggerly", "Bailliet", "Baird", "Baker", "Ball", "Ballentine", "Ballew", "Banks", 70 | "Baptist-Nguyen", "Barbee", "Barber", "Barchas", "Barcio", "Bardsley", "Barkauskas", "Barnes", 71 | "Barnett", "Barnwell", "Barrera", "Barreto", "Barroso", "Barrow", "Bart", "Barton", "Bass", "Bates", 72 | "Bavinger", "Baxter", "Bazaldua", "Becker", "Beeghly", "Belforte", "Bellamy", "Bellavance", 73 | "Beltran", "Belusar", "Bennett", "Benoit", "Bensley", "Berger", "Berggren", "Bergman", "Berry", 74 | "Bertelson", "Bess", "Beusse", "Bickford", "Bierner", "Bird", "Birdwell", "Bixby", "Blackmon", 75 | "Blackwell", "Blair", "Blankinship", "Blanton", "Block", "Blomkalns", "Bloomfield", "Blume", 76 | "Boeckenhauer", "Bolding", "Bolt", "Bolton", "Book", "Boucher", "Boudreau", "Bowman", "Boyd", 77 | "Boyes", "Boyles", "Braby", "Braden", "Bradley", "Brady", "Bragg", "Brandow", "Brantley", "Brauner", 78 | "Braunhardt", "Bray", "Bredenberg", "Bremer", "Breyer", "Bricout", "Briggs", "Brittain", 79 | "Brockman", "Brockmoller", "Broman", "Brooks", "Brown", "Brubaker", "Bruce", "Brumfield", 80 | "Brumley", "Bruning", "Buck", "Budd", "Buhler", "Buhr", "Burleson", "Burns", "Burton", "Bush", 81 | "Butterfield", "Byers", "Byon", "Byrd", "Bzostek", "Cabrera", "Caesar", "Caffey", "Caffrey", 82 | "Calhoun", "Call", "Callahan", "Campbell", "Cano", "Capri", "Carey", "Carlisle", "Carlson", 83 | "Carmichael", "Carnes", "Carr", "Carreira", "Carroll", "Carson", "Carswell", "Carter", 84 | "Cartwright", "Cason", "Cates", "Catlett", "Caudle", "Cavallaro", "Cave", "Cazamias", "Chabot", 85 | "Chance", "Chapman", "Characklis", "Cheatham", "Chen", "Chern", "Cheville", "Chong", 86 | "Christensen", "Church", "Claibourn", "Clark", "Clasen", "Claude", "Close", "Coakley", "Coffey", 87 | "Cohen", "Cole", "Collier", "Conant", "Connell", "Conte", "Conway", "Cooley", "Cooper", "Copeland", 88 | "Coram", "Corbett", "Cort", "Cortes", "Cousins", "Cowsar", "Cox", "Coyne", "Crain", "Crankshaw", 89 | "Craven", "Crawford", "Cressman", "Crestani", "Crier", "Crocker", "Cromwell", "Crouse", "Crowder", 90 | "Crowe", "Culpepper", "Cummings", "Cunningham", "Currie", "Cusey", "Cutcher", "Cyprus", 91 | "D'Ascenzo", "Dabak", "Dakoulas", "Daly", "Dana", "Danburg", "Danenhauer", "Darley", "Darrouzet", 92 | "Dartt", "Daugherty", "Davila", "Davis", "Dawkins", "Day", "DeHart", "DeMoss", "DeMuth", 93 | "DeVincentis", "Deaton", "Dees", "Degenhardt", "Deggeller", "Deigaard", "Delabroy", "Delaney", 94 | "Demir", "Denison", "Denney", "Derr", "Deuel", "Devitt", "Diamond", "Dickinson", "Dietrich", 95 | "Dilbeck", "Dobson", "Dodds", "Dodson", "Doherty", "Dooley", "Dorsey", "Dortch", "Doughty", "Dove", 96 | "Dowd", "Dowling", "Drescher", "Drucker", "Dryer", "Dryver", "Duckworth", "Dunbar", "Dunham", "Dunn", 97 | "Duston", "Dettweiler", "Dyson", "Eason", "Eaton", "Ebert", "Eckhoff", "Edelman", "Edmonds", 98 | "Eichhorn", "Eisbach", "Elders", "Elias", "Elijah", "Elizabeth", "Elliott", "Elliston", "Elms", 99 | "Emerson", "Engelberg", "Engle", "Eplett", "Epp", "Erickson", "Estades", "Etezadi", "Evans", "Ewing", 100 | "Fair", "Farfan", "Fargason", "Farhat", "Farry", "Fawcett", "Faye", "Federle", "Felcher", "Feldman", 101 | "Ferguson", "Fergusson", "Fernandez", "Ferrer", "Fine", "Fineman", "Fisher", "Flanagan", 102 | "Flathmann", "Fleming", "Fletcher", "Folk", "Fortune", "Fossati", "Foster", "Foulston", "Fowler", 103 | "Fox", "Francis", "Frantom", "Franz", "Frazer", "Fredericks", "Frey", "Freymann", "Fuentes", 104 | "Fuller", "Fundling", "Furlong", "Gainer", "Galang", "Galeazzi", "Gamse", "Gannaway", "Garcia", 105 | "Gardner", "Garneau", "Gartler", "Garverick", "Garza", "Gatt", "Gattis", "Gayman", "Geiger", 106 | "Gelder", "George", "Gerbino", "Gerbode", "Gibson", "Gifford", "Gillespie", "Gillingham", 107 | "Gilpin", "Gilyot", "Girgis", "Gjertsen", "Glantz", "Glaze", "Glenn", "Glotzbach", "Gobble", 108 | "Gockenbach", "Goff", "Goffin", "Golden", "Goldwyn", "Gomez", "Gonzalez", "Good", "Graham", "Gramm", 109 | "Granlund", "Grant", "Gray", "Grayson", "Greene", "Greenslade", "Greenwood", "Greer", "Griffin", 110 | "Grinstein", "Grisham", "Gross", "Grove", "Guthrie", "Guyton", "Haas", "Hackney", "Haddock", 111 | "Hagelstein", "Hagen", "Haggard", "Haines", "Hale", "Haley", "Hall", "Halladay", "Hamill", 112 | "Hamilton", "Hammer", "Hancock", "Hane", "Hansen", "Harding", "Harless", "Harms", "Harper", 113 | "Harrigan", "Harris", "Harrison", "Hart", "Harton", "Hartz", "Harvey", "Hastings", "Hauenstein", 114 | "Haushalter", "Haven", "Hawes", "Hawkins", "Hawley", "Haygood", "Haylock", "Hazard", "Heath", 115 | "Heidel", "Heins", "Hellums", "Hendricks", "Henry", "Henson", "Herbert", "Herman", "Hernandez", 116 | "Herrera", "Hertzmann", "Hewitt", "Hightower", "Hildebrand", "Hill", "Hindman", "Hirasaki", 117 | "Hirsh", "Hochman", "Hocker", "Hoffman", "Hoffmann", "Holder", "Holland", "Holloman", "Holstein", 118 | "Holt", "Holzer", "Honeyman", "Hood", "Hooks", "Hopper", "Horne", "House", "Houston", "Howard", 119 | "Howell", "Howley", "Huang", "Hudgings", "Huffman", "Hughes", "Humphrey", "Hunt", "Hunter", "Hurley", 120 | "Huston", "Hutchinson", "Hyatt", "Irving", "Jacobs", "Jaramillo", "Jaranson", "Jarboe", "Jarrell", 121 | "Jenkins", "Johnson", "Johnston", "Jones", "Joy", "Juette", "Julicher", "Jumper", "Kabir", 122 | "Kamberova", "Kamen", "Kamine", "Kampe", "Kane", "Kang", "Kapetanovic", "Kargatis", "Karlin", 123 | "Karlsson", "Kasbekar", "Kasper", "Kastensmidt", "Katz", "Kauffman", "Kavanagh", "Kaydos", 124 | "Kearsley", "Keleher", "Kelly", "Kelty", "Kendrick", "Key", "Kicinski", "Kiefer", "Kielt", "Kim", 125 | "Kimmel", "Kincaid", "King", "Kinney", "Kipp", "Kirby", "Kirk", "Kirkland", "Kirkpatrick", 126 | "Klamczynski", "Klein", "Kopnicky", "Kotsonis", "Koutras", "Kramer", "Kremer", "Krohn", "Kuhlken", 127 | "Kunitz", "LaLonde", "LaValle", "LaWare", "Lacy", "Lam", "Lamb", "Lampkin", "Lane", "Langston", 128 | "Lanier", "Larsen", "Lassiter", "Latchford", "Lawera", "LeBlanc", "LeGrand", "Leatherbury", 129 | "Lebron", "Ledman", "Lee", "Leinenbach", "Leslie", "Levy", "Lewis", "Lichtenstein", "Lisowski", 130 | "Liston", "Litvak", "Llano-Restrepo", "Lloyd", "Lock", "Lodge", "Logan", "Lomonaco", "Long", "Lopez", 131 | "Lopez-Bassols", "Loren", "Loughridge", "Love", "Ludtke", "Luers", "Lukes", "Luxemburg", 132 | "MacAllister", "MacLeod", "Mackey", "Maddox", "Magee", "Mallinson", "Mann", "Manning", "Manthos", 133 | "Marie", "Marrow", "Marshall", "Martin", "Martinez", "Martisek", "Massey", "Mathis", "Matt", 134 | "Maxwell", "Mayer", "Mazurek", "McAdams", "McAfee", "McAlexander", "McBride", "McCarthy", 135 | "McClure", "McCord", "McCoy", "McCrary", "McCrossin", "McDonald", "McElfresh", "McFarland", 136 | "McGarr", "McGhee", "McGoldrick", "McGrath", "McGuire", "McKinley", "McMahan", "McMahon", 137 | "McMath", "McNally", "Mcdonald", "Meade", "Meador", "Mebane", "Medrano", "Melton", "Merchant", 138 | "Merwin", "Millam", "Millard", "Miller", "Mills", "Milstead", "Minard", "Miner", "Minkoff", 139 | "Minnotte", "Minyard", "Mirza", "Mitchell", "Money", "Monk", "Montgomery", "Monton", "Moore", 140 | "Moren", "Moreno", "Morris", "Morse", "Moss", "Moyer", "Mueller", "Mull", "Mullet", "Mullins", "Munn", 141 | "Murdock", "Murphey", "Murphy", "Murray", "Murry", "Mutchler", "Myers", "Myrick", "Nassar", "Nathan", 142 | "Nazzal", "Neal", "Nederveld", "Nelson", "Nguyen", "Nichols", "Nielsen", "Nockton", "Nolan", 143 | "Noonan", "Norbury", "Nordlander", "Norris", "Norvell", "Noyes", "Nugent", "Nunn", "O'Brien", 144 | "O'Connell", "O'Neill", "O'Steen", "Ober", "Odegard", "Oliver", "Ollmann", "Olson", "Ongley", 145 | "Ordway", "Ortiz", "Ouellette", "Overcash", "Overfelt", "Overley", "Owens", "Page", "Paige", 146 | "Pardue", "Parham", "Parker", "Parks", "Patterson", "Patton", "Paul", "Payne", "Peck", "Penisson", 147 | "Percer", "Perez", "Perlioni", "Perrino", "Peterman", "Peters", "Pfeiffer", "Phelps", "Philip", 148 | "Philippe", "Phillips", "Pickett", "Pippenger", "Pistole", "Platzek", "Player", "Poddar", 149 | "Poirier", "Poklepovic", "Polk", "Polking", "Pond", "Popish", "Porter", "Pound", "Pounds", "Powell", 150 | "Powers", "Prado", "Preston", "Price", "Prichep", "Priour", "Prischmann", "Pryor", "Puckett", 151 | "Raglin", "Ralston", "Rampersad", "Ratner", "Rawles", "Ray", "Read", "Reddy", "Reed", "Reese", "Reeves", 152 | "Reichenbach", "Reifel", "Rein", "Reiten", "Reiter", "Reitmeier", "Reynolds", "Richardson", 153 | "Rider", "Rhinehart", "Ritchie", "Rittenbach", "Roberts", "Robinson", "Rodriguez", "Rogers", 154 | "Roper", "Rosemblun", "Rosen", "Rosenberg", "Rosenblatt", "Ross", "Roth", "Rowatt", "Roy", "Royston", 155 | "Rozendal", "Rubble", "Ruhlin", "Rupert", "Russell", "Ruthruff", "Ryan", "Rye", "Sabry", "Sachitano", 156 | "Sachs", "Sammartino", "Sands", "Saunders", "Savely", "Scales", "Schaefer", "Schafer", "Scheer", 157 | "Schild", "Schlitt", "Schmitz", "Schneider", "Schoenberger", "Schoppe", "Scott", "Seay", "Segura", 158 | "Selesnick", "Self", "Seligmann", "Sewall", "Shami", "Shampine", "Sharp", "Shaw", "Shefelbine", 159 | "Sheldon", "Sherrill", "Shidle", "Shifley", "Shillingsburg", "Shisler", "Shopbell", "Shupack", 160 | "Sievert", "Simpson", "Sims", "Sissman", "Smayling", "Smith", "Snyder", "Solomon", "Solon", 161 | "Soltero", "Sommers", "Sonneborn", "Sorensen", "Southworth", "Spear", "Speight", "Spencer", 162 | "Spruell", "Spudich", "Stacy", "Staebel", "Steele", "Steinhour", "Steinke", "Stepp", "Stevens", 163 | "Stewart", "Stickel", "Stine", "Stivers", "Stobb", "Stone", "Stratmann", "Stubbers", "Stuckey", 164 | "Stugart", "Sullivan", "Sultan", "Sumrall", "Sunley", "Sunshine", "Sutton", "Swaim", "Swales", 165 | "Sweed", "Swick", "Swift", "Swindell", "Swint", "Symonds", "Syzdek", "Szafranski", "Takimoto", 166 | "Talbott", "Talwar", "Tanner", "Taslimi", "Tate", "Tatum", "Taylor", "Tchainikov", "Terk", "Thacker", 167 | "Thomas", "Thompson", "Thomson", "Thornton", "Thurman", "Thurow", "Tilley", "Tolle", "Towns", 168 | "Trafton", "Tran", "Trevas", "Trevino", "Triggs", "Truchard", "Tunison", "Turner", "Twedell", 169 | "Tyler", "Tyree", "Unger", "Van", "Vanderzanden", "Vanlandingham", "Varanasi", "Varela", "Varman", 170 | "Venier", "Verspoor", "Vick", "Visinsky", "Voltz", "Wagner", "Wake", "Walcott", "Waldron", "Walker", 171 | "Wallace", "Walters", "Walton", "Ward", "Wardle", "Warnes", "Warren", "Washington", "Watson", 172 | "Watters", "Webber", "Weidenfeller", "Weien", "Weimer", "Weiner", "Weinger", "Weinheimer", 173 | "Weirich", "Welch", "Wells", "Wendt", "West", "Westmoreland", "Wex", "Whitaker", "White", "Whitley", 174 | "Wiediger", "Wilburn", "Williams", "Williamson", "Willman", "Wilson", "Winger", "Wise", "Wisur", 175 | "Witt", "Wong", "Woodbury", "Wooten", "Workman", "Wright", "Wyatt", "Yates", "Yeamans", "Yen", "York", 176 | "Yotov", "Younan", "Young", "Zeldin", "Zettner", "Ziegler", "Zitterkopf", "Zucker"]; 177 | 178 | /** 179 | * English surnames dictionary. 180 | * 181 | * @function {Dict} surnames 182 | * @return dictionary object containing most common English surnames. 183 | * 184 | * @see Popcorn.Dictionary.Dict 185 | */ 186 | var surnames = lib.surnames = dict.dictionary(surnames_dict); 187 | 188 | return lib; 189 | 190 | }(Popcorn.Core, Popcorn.Dictionary); 191 | 192 | -------------------------------------------------------------------------------- /src/network.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.Network 3 | * @requires Popcorn.Core 4 | * @requires Popcorn.Common 5 | * @requires Popcorn.Dictionary 6 | * @requires Popcorn.Names 7 | */ 8 | 9 | /** 10 | * Generators for common data types used in networking. 11 | * 12 | * @namespace Popcorn.Network 13 | * @author Adam Smyczek 14 | * @author Brian Wilkerson 15 | */ 16 | Popcorn.Network = function (core, common, dict, names) { 17 | 18 | var lib = {}; 19 | 20 | // Hex char set 21 | var hex = "FEDCBA9876543210"; 22 | 23 | // ------ Utils for IP addresses ------ 24 | 25 | // Parse and validate IP string to an int array, 26 | // for example "192.168.0.1" -> [192, 168, 0, 1] 27 | var parseIP = function(ip_str) { 28 | var ip = new RegExp("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})", "g").exec(ip_str), 29 | pInt = function(seg) { 30 | var i = parseInt(seg, 10); 31 | if (isNaN(i) || i > 255 || i < 0) { 32 | throw "Invalid IP octet " + seg + " of IP: " + ip_str; 33 | } 34 | return i; 35 | }; 36 | if (ip && ip.length > 4) { 37 | return core.map(pInt, ip.slice(1)); 38 | } 39 | throw "Invalid IP address: " + ip_str; 40 | }; 41 | 42 | // Convert an IP array to a string 43 | var ip2str = function(ip) { 44 | return ip.join("."); 45 | }; 46 | 47 | // Convert an IP array to an int value. 48 | // Uses only last three octets. 49 | var ip2int = function(ip) { 50 | if (ip.length > 3) { 51 | throw "Max 3 IP octets supported."; 52 | } 53 | var rip = ip.reverse(); 54 | return core.seq(core.mapGen(rip.slice(1)), function(r, o, i) { return r + (o << (8 << i)); }, rip[0])().result; 55 | }; 56 | 57 | // Opposite to ip2int converts an int to last three IP octets. 58 | var int2ip = function(i) { 59 | return core.seq(core.mapGen([0,8,16]), function(r, s) { return r.concat((i >> s) & 255); }, [])().result.reverse(); 60 | }; 61 | 62 | // ------ Random generators extensions ------ 63 | 64 | /** @scope Popcorn.Core.Random */ 65 | 66 | /** 67 | * Generates a random IP address string in the range 68 | * from 'fromIP' to 'toIP'. 69 | * 70 | * @function {generator} ipAddress 71 | * @param {string} fromIP - IP string of the form '192.168.0.1'. 72 | * @param {string} toIP - IP string of the form '192.168.0.10'. 73 | * @return a random IP address generator. 74 | */ 75 | core.RandomLib.ipAddress = function(fromIP, toIP) { 76 | var ip1 = parseIP(fromIP), 77 | ip2 = parseIP(toIP); 78 | 79 | // Validate range 80 | if (ip1[0] !== ip2[0]) { 81 | throw "Ip rage to large."; 82 | } 83 | 84 | // Convert string to int array first and int using last three octets. 85 | var ipi1 = ip2int(ip1.slice(1)), 86 | ipi2 = ip2int(ip2.slice(1)), 87 | from = Math.min(ipi1, ipi2), 88 | to = Math.max(ipi1, ipi2), 89 | int = this.int(from, to); 90 | 91 | return core.lazy(function() { 92 | return core.gen(ip2str([ip1[0]].concat(int2ip(int().result)))); 93 | }); 94 | }; 95 | 96 | /** 97 | * Generates a random mac address string. This generator 98 | * accepts an optional delimiter char. 99 | * 100 | * @function {generator} macAddress 101 | * @param {string} delimiter - an optional delimiter char. 102 | * @return a random mac address generator. 103 | */ 104 | core.RandomLib.macAddress = function(delimiter) { 105 | var del = delimiter|| ":", 106 | hCh = this.element(hex); 107 | return core.lazy(function() { 108 | var mac = "00"; 109 | for (var i = 0; i < 5; i++) { 110 | mac = mac.concat(del, hCh().result, hCh().result); 111 | } 112 | return core.gen(mac); 113 | }); 114 | }; 115 | 116 | /** 117 | * Random email address generator that 118 | * uses {@link names}, {@link surnames} and 119 | * {@link domains} dictionaries to generate 120 | * email addresses of the form 'name.surname1@surname2.domain'. 121 | * 122 | * @function {generator} emailAddress 123 | * @return a random email address generator. 124 | */ 125 | core.RandomLib.emailAddress = function() { 126 | var n = names.names.element(this), 127 | s = names.surnames.element(this), 128 | d = domains.element(this); 129 | return core.lazy(function() { 130 | return core.gen("".concat(n().result, ".", s().result, "@", s().result, ".", d().result)); 131 | }); 132 | }; 133 | 134 | 135 | // ------ Ohter network generator ------ 136 | 137 | /** @scope Popcorn.Network */ 138 | 139 | /** 140 | * IP range generator creates IPs in the range from 'fromIP' to 'toIP'. 141 | * Currently the maximum range length is restricted to 5000 elements. 142 | * 143 | * @function {generator} ipRange 144 | * @param {string} fromIP - IP string of the form '192.168.0.1'. 145 | * @param {string} toIP - IP string of the form '192.168.0.10'. 146 | * @return a IP range generator. 147 | */ 148 | var ipRange = lib.ipRange = function(fromIp, toIp) { 149 | var ip1 = parseIP(fromIp), 150 | ip2 = parseIP(toIp), 151 | max_ips = 5000; 152 | 153 | // Validate range 154 | if (ip1[0] !== ip2[0]) { 155 | throw "To many IP addresses, maximum range count is " + max_ips + "."; 156 | } 157 | 158 | // Convert string to int array first and int using last three octets. 159 | var ipi1 = ip2int(ip1.slice(1)), 160 | ipi2 = ip2int(ip2.slice(1)), 161 | from = Math.min(ipi1, ipi2), 162 | to = Math.max(ipi1, ipi2), 163 | r = []; 164 | 165 | // Create IP array 166 | for (var i = from; i <= to; i++) { 167 | r[i - from] = core.gen(ip2str([ip1[0]].concat(int2ip(i)))); 168 | } 169 | return r; 170 | }; 171 | 172 | // ------ Domains dictionary ------ 173 | 174 | // Domains dictionary 175 | var domains_dict = [ 176 | "ac", "ad", "ae", "aero", "af", "ag", "ai", "al", "am", "an", 177 | "ao", "aq", "ar", "arpa", "as", "asia", "at", "au", "aw", "ax", 178 | "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "biz", "bj", 179 | "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", "bz", "ca", 180 | "cat", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", 181 | "co", "com", "coop", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj", 182 | "dk", "dm", "do", "dz", "ec", "edu", "ee", "eg", "er", "es", "et", 183 | "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", 184 | "gg", "gh", "gi", "gl", "gm", "gn", "gov", "gp", "gq", "gr", "gs", 185 | "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", 186 | "ie", "il", "im", "in", "info", "int", "io", "iq", "ir", "is", "it", 187 | "je", "jm", "jo", "jobs", "jp", "ke", "kg", "kh", "ki", "km", "kn", 188 | "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", 189 | "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mg", "mh", 190 | "mil", "mk", "ml", "mm", "mn", "mo", "mobi", "mp", "mq", "mr", "ms", 191 | "mt", "mu", "museum", "mv", "mw", "mx", "my", "mz", "na", "name", 192 | "nc", "ne", "net", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", 193 | "om", "org", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", 194 | "pro", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", 195 | "sb", "sc", "sd", "se", "sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", 196 | "so", "sr", "st", "su", "sv", "sy", "sz", "tc", "td", "tel", "tf", "tg", 197 | "th", "tj", "tk", "tl", "tm", "tn", "to", "tp", "tr", "travel", "tt", "tv", 198 | "tw", "tz", "ua", "ug", "uk", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", 199 | "vn", "vu", "wf", "ws", "xn", "ye", "yt", "yu", "za", "zm", "zw"]; 200 | 201 | /** 202 | * Domains dictionary. 203 | * 204 | * @function {Dict} domains 205 | * @return the domains dictionary object. 206 | * 207 | * @see Popcorn.Dictionary.Dict 208 | */ 209 | var domains = lib.domains = dict.dictionary(domains_dict); 210 | 211 | /** 212 | * Most common domains dictionary. 213 | * It contains the domains com, net, org, edu, gov, biz and info. 214 | * 215 | * @function {Dict} commonDomains 216 | * @return the common domains dictionary object. 217 | * 218 | * @see Popcorn.Dictionary.Dict 219 | */ 220 | var commonDomains = lib.commonDomains = dict.dictionary(["com", "net", "org", "edu", "gov", "biz", "info"]); 221 | 222 | return lib; 223 | 224 | }(Popcorn.Core, Popcorn.Common, Popcorn.Dictionary, Popcorn.Names); 225 | 226 | -------------------------------------------------------------------------------- /src/passwords.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module Popcorn.Passwords 3 | * @requires Popcorn.Core 4 | * @requires Popcorn.Dictionary 5 | */ 6 | 7 | /** 8 | * A common passwords dictionary.
9 | * Credits to 10 | * The top 500 worst passwords of all time. 11 | * 12 | * @namespace Popcorn.Passwords 13 | * @author Brian Wilkerson 14 | * @author Adam Smyczek 15 | */ 16 | Popcorn.Passwords = function (core, dict) { 17 | 18 | var lib = {}; 19 | 20 | var passwords_dict = [ 21 | '123456 ', 'porsche ', 'firebird ', 'prince ', 'rosebud', 22 | 'password ', 'guitar ', 'butter ', 'beach ', 'jaguar', 23 | '12345678 ', 'chelsea ', 'united ', 'amateur ', 'great', 24 | '1234 ', 'black ', 'turtle ', '7777777 ', 'cool', 25 | 'pussy ', 'diamond ', 'steelers ', 'muffin ', 'cooper', 26 | '12345 ', 'nascar ', 'tiffany ', 'redsox ', '1313', 27 | 'dragon ', 'jackson ', 'zxcvbn ', 'star ', 'scorpio', 28 | 'qwerty ', 'cameron ', 'tomcat ', 'testing ', 'mountain', 29 | '696969 ', '654321 ', 'golf ', 'shannon ', 'madison', 30 | 'mustang ', 'computer ', 'bond007 ', 'murphy ', '987654', 31 | 'letmein ', 'amanda ', 'bear ', 'frank ', 'brazil', 32 | 'baseball ', 'wizard ', 'tiger ', 'hannah ', 'lauren', 33 | 'master ', 'xxxxxxxx ', 'doctor ', 'dave ', 'japan', 34 | 'michael ', 'money ', 'gateway ', 'eagle1 ', 'naked', 35 | 'football ', 'phoenix ', 'gators ', '11111 ', 'squirt', 36 | 'shadow ', 'mickey ', 'angel ', 'mother ', 'stars', 37 | 'monkey ', 'bailey ', 'junior ', 'nathan ', 'apple', 38 | 'abc123 ', 'knight ', 'thx1138 ', 'raiders ', 'alexis', 39 | 'pass ', 'iceman ', 'porno ', 'steve ', 'aaaa', 40 | 'fuckme ', 'tigers ', 'badboy ', 'forever ', 'bonnie', 41 | '6969 ', 'purple ', 'debbie ', 'angela ', 'peaches', 42 | 'jordan ', 'andrea ', 'spider ', 'viper ', 'jasmine', 43 | 'harley ', 'horny ', 'melissa ', 'ou812 ', 'kevin', 44 | 'ranger ', 'dakota ', 'booger ', 'jake ', 'matt', 45 | 'iwantu ', 'aaaaaa ', '1212 ', 'lovers ', 'qwertyui', 46 | 'jennifer ', 'player ', 'flyers ', 'suckit ', 'danielle', 47 | 'hunter ', 'sunshine ', 'fish ', 'gregory ', 'beaver', 48 | 'fuck ', 'morgan ', 'porn ', 'buddy ', '4321', 49 | '2000 ', 'starwars ', 'matrix ', 'whatever ', '4128', 50 | 'test ', 'boomer ', 'teens ', 'young ', 'runner', 51 | 'batman ', 'cowboys ', 'scooby ', 'nicholas ', 'swimming', 52 | 'trustno1 ', 'edward ', 'jason ', 'lucky ', 'dolphin', 53 | 'thomas ', 'charles ', 'walter ', 'helpme ', 'gordon', 54 | 'tigger ', 'girls ', 'cumshot ', 'jackie ', 'casper', 55 | 'robert ', 'booboo ', 'boston ', 'monica ', 'stupid', 56 | 'access ', 'coffee ', 'braves ', 'midnight ', 'shit', 57 | 'love ', 'xxxxxx ', 'yankee ', 'college ', 'saturn', 58 | 'buster ', 'bulldog ', 'lover ', 'baby ', 'gemini', 59 | '1234567 ', 'ncc1701 ', 'barney ', 'cunt ', 'apples', 60 | 'soccer ', 'rabbit ', 'victor ', 'brian ', 'august', 61 | 'hockey ', 'peanut ', 'tucker ', 'mark ', '3333', 62 | 'killer ', 'john ', 'princess ', 'startrek ', 'canada', 63 | 'george ', 'johnny ', 'mercedes ', 'sierra ', 'blazer', 64 | 'sexy ', 'gandalf ', '5150 ', 'leather ', 'cumming', 65 | 'andrew ', 'spanky ', 'doggie ', '232323 ', 'hunting', 66 | 'charlie ', 'winter ', 'zzzzzz ', '4444 ', 'kitty', 67 | 'superman ', 'brandy ', 'gunner ', 'beavis ', 'rainbow', 68 | 'asshole ', 'compaq ', 'horney ', 'bigcock ', '112233', 69 | 'fuckyou ', 'carlos ', 'bubba ', 'happy ', 'arthur', 70 | 'dallas ', 'tennis ', '2112 ', 'sophie ', 'cream', 71 | 'jessica ', 'james ', 'fred ', 'ladies ', 'calvin', 72 | 'panties ', 'mike ', 'johnson ', 'naughty ', 'shaved', 73 | 'pepper ', 'brandon ', 'xxxxx ', 'giants ', 'surfer', 74 | '1111 ', 'fender ', 'tits ', 'booty ', 'samson', 75 | 'austin ', 'anthony ', 'member ', 'blonde ', 'kelly', 76 | 'william ', 'blowme ', 'boobs ', 'fucked ', 'paul', 77 | 'daniel ', 'ferrari ', 'donald ', 'golden ', 'mine', 78 | 'golfer ', 'cookie ', 'bigdaddy ', '0 ', 'king', 79 | 'summer ', 'chicken ', 'bronco ', 'fire ', 'racing', 80 | 'heather ', 'maverick ', 'penis ', 'sandra ', '5555', 81 | 'hammer ', 'chicago ', 'voyager ', 'pookie ', 'eagle', 82 | 'yankees ', 'joseph ', 'rangers ', 'packers ', 'hentai', 83 | 'joshua ', 'diablo ', 'birdie ', 'einstein ', 'newyork', 84 | 'maggie ', 'sexsex ', 'trouble ', 'dolphins ', 'little', 85 | 'biteme ', 'hardcore ', 'white ', '0 ', 'redwings', 86 | 'enter ', '666666 ', 'topgun ', 'chevy ', 'smith', 87 | 'ashley ', 'willie ', 'bigtits ', 'winston ', 'sticky', 88 | 'thunder ', 'welcome ', 'bitches ', 'warrior ', 'cocacola', 89 | 'cowboy ', 'chris ', 'green ', 'sammy ', 'animal', 90 | 'silver ', 'panther ', 'super ', 'slut ', 'broncos', 91 | 'richard ', 'yamaha ', 'qazwsx ', '8675309 ', 'private', 92 | 'fucker ', 'justin ', 'magic ', 'zxcvbnm ', 'skippy', 93 | 'orange ', 'banana ', 'lakers ', 'nipples ', 'marvin', 94 | 'merlin ', 'driver ', 'rachel ', 'power ', 'blondes', 95 | 'michelle ', 'marine ', 'slayer ', 'victoria ', 'enjoy', 96 | 'corvette ', 'angels ', 'scott ', 'asdfgh ', 'girl', 97 | 'bigdog ', 'fishing ', '2222 ', 'vagina ', 'apollo', 98 | 'cheese ', 'david ', 'asdf ', 'toyota ', 'parker', 99 | 'matthew ', 'maddog ', 'video ', 'travis ', 'qwert', 100 | '121212 ', 'hooters ', 'london ', 'hotdog ', 'time', 101 | 'patrick ', 'wilson ', '7777 ', 'paris ', 'sydney', 102 | 'martin ', 'butthead ', 'marlboro ', 'rock ', 'women', 103 | 'freedom ', 'dennis ', 'srinivas ', 'xxxx ', 'voodoo', 104 | 'ginger ', 'fucking ', 'internet ', 'extreme ', 'magnum', 105 | 'blowjob ', 'captain ', 'action ', 'redskins ', 'juice', 106 | 'nicole ', 'bigdick ', 'carter ', 'erotic ', 'abgrtyu', 107 | 'sparky ', 'chester ', 'jasper ', 'dirty ', '777777', 108 | 'yellow ', 'smokey ', 'monster ', 'ford ', 'dreams', 109 | 'camaro ', 'xavier ', 'teresa ', 'freddy ', 'maxwell', 110 | 'secret ', 'steven ', 'jeremy ', 'arsenal ', 'music', 111 | 'dick ', 'viking ', '11111111 ', 'access14 ', 'rush2112', 112 | 'falcon ', 'snoopy ', 'bill ', 'wolf ', 'russia', 113 | 'taylor ', 'blue ', 'crystal ', 'nipple ', 'scorpion', 114 | '111111 ', 'eagles ', 'peter ', 'iloveyou ', 'rebecca', 115 | '131313 ', 'winner ', 'pussies ', 'alex ', 'tester', 116 | '123123 ', 'samantha ', 'cock ', 'florida ', 'mistress', 117 | 'bitch ', 'house ', 'beer ', 'eric ', 'phantom', 118 | 'hello ', 'miller ', 'rocket ', 'legend ', 'billy', 119 | 'scooter ', 'flower ', 'theman ', 'movie ', '6666', 120 | 'please ', 'jack ', 'oliver ', 'success ', 'albert']; 121 | 122 | /** 123 | * Common passwords. 124 | * 125 | * @function {Dict} passwords 126 | * @return dictionary object containing common passwords. 127 | * 128 | * @see Popcorn.Dictionary.Dict 129 | */ 130 | var passwords = lib.passwords = dict.dictionary(passwords_dict); 131 | 132 | return lib; 133 | 134 | }(Popcorn.Core, Popcorn.Dictionary); 135 | 136 | -------------------------------------------------------------------------------- /src/project.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Popcorn is a JavaScript embedded DSL designed for quick, ease and 3 | * flexible JSON object generation. The core modules provides a basic set 4 | * of generators for most common JavaScript types, and combinators to build 5 | * new generators for any kind of data. Additional modules extend the 6 | * functionality with random generators, dictionaries, network type 7 | * generators for IP or mac address and more.
8 | *
9 | * Main purpose of this framework is mock object generation for testing 10 | * of JSON services and browser side JavaScript code. Since with this 11 | * DSL thousands of test cases can be expressed in just few lines of code, 12 | * it makes for a great driver for data-driven test engines.
13 | *
14 | * 15 | * Quick start: 16 | *

17 |  * with({ core: Popcorn.Core, 
18 |  *        comm: Popcorn.Common }) { // Load other modules as needed.
19 |  *
20 |  *   var base_object = { // Define the base object.
21 |  *     id : 1, 
22 |  *     name : 'Woody'
23 |  *   };
24 |  * 
25 |  *   var generator = { // Define the generator object.
26 |  *     id : core.range(10, 20),
27 |  *     name : comm.list('Buzz', 'Slinky')
28 |  *   };
29 |  * 
30 |  *   // And run it!
31 |  *   var results = core.generate(generator, base_object);
32 |  * }
33 |  * 
34 | * 35 | * @project Popcorn 36 | * @version 37 | * @author Adam Smyczek 38 | * @author Brian Wilkerson 39 | * @description Popcorn - a DSL for JSON 40 | * @timestamp 41 | */ 42 | 43 | // -------------------------------------------------------------------------- 44 | 45 | // Global interface definitions 46 | 47 | /** @scope Popcorn */ 48 | 49 | /** 50 | * A generator is a function that takes one argument and 51 | * returns an object of the form: 52 | * 53 | *

54 |  *   {
55 |  *     result: value,
56 |  *     state : state_obj
57 |  *   }
58 |  * 
59 | * 60 | * 'result' is the evaluation result of the generator. 61 | * A state object is passed to the generation process 62 | * and can be manipulated by any generator. See 63 | * {@link Popcorn.Core.generate} for details. 64 | * 65 | * Popcorn provides functions to create 66 | * and combine generators to build any kind of data. 67 | * See README for more information. 68 | * 69 | * @ifunction {any} generator 70 | * @param {any} input - any variable, object, etc. 71 | */ 72 | 73 | /** 74 | * A combinator function is used by {@link Popcorn.Core.seq} and 75 | * {@link Popcorn.Core.replicate} to accumulate results of 76 | * subsequent generator executions. 77 | * 78 | * @ifunction {any} combinator 79 | * @param {any} r - the combined result from previous executions 80 | * or the initial value on first call. 81 | * @param {any} n - the result of the current generator execution. 82 | * @return the new accumulated result. 83 | * 84 | * @see Popcorn.Core.seq 85 | * @see Popcorn.Core.replicate 86 | */ 87 | 88 | -------------------------------------------------------------------------------- /test/common.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Popcorn.Common - Unit tests 5 | 6 | 7 | 8 | 9 | 10 | 11 |

Popcorn.Common - unit tests

12 | 13 |

14 |

Tests run:
15 |
Tests passed:
16 |
Tests failed:
17 |

18 | 19 |

20 |

Common lib
21 | 45 |

46 | 47 |

48 |

Random generator extensions
49 | 61 |

62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /test/core.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Popcorn.Core - Unit tests 5 | 6 | 7 | 8 | 9 | 10 |

Popcorn.Core - unit tests

11 | 12 |

13 |

Tests run:
14 |
Tests passed:
15 |
Tests failed:
16 |

17 | 18 |

19 |

Core lib
20 | 33 |

34 | 35 |

36 |

Object generators
37 | 54 |

55 | 56 |

57 |

State and variables
58 | 86 |

87 | 88 |

89 |

Random generators
90 | 103 |

104 | 105 |

106 |

Utils lib
107 | 133 |

134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /test/dictionary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Popcorn.Dictionary - Unit tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

Popcorn.Dictionary - unit tests

14 | 15 |

16 |

Tests run:
17 |
Tests passed:
18 |
Tests failed:
19 |

20 | 21 |

22 |

Dictionary lib
23 | 38 |

39 | 40 |

41 |

Names lib
42 | 52 |

53 | 54 |

55 |

Passwords lib
56 | 67 |

68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/network.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Popcorn.Network - Unit tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

Popcorn.Network - unit tests

14 | 15 |

16 |

Tests run:
17 |
Tests passed:
18 |
Tests failed:
19 |

20 | 21 |

22 |

Network lib
23 | 35 |

36 | 37 |

38 |

Random generator extensions
39 | 49 |

50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /test/test.css: -------------------------------------------------------------------------------- 1 | span.ok { 2 | color: green; 3 | } 4 | 5 | span.error { 6 | color: red; 7 | font-weight: bolder; 8 | } 9 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | // A custom tiny unit test framework 2 | // requires 'core.js' 3 | 4 | // Stat handling 5 | var tests_count = 0; 6 | var tests_passed = 0; 7 | var tests_failed = 0; 8 | 9 | // Core lib reference 10 | var core = Popcorn.Core; 11 | 12 | // Basic assertion function just compares 13 | // expect to result value 14 | var assert = function(expects, result, desc) { 15 | // Update test counter 16 | tests_count++; 17 | document.getElementById('tests_count').innerHTML = tests_count; 18 | 19 | // Run assert 20 | if (passed(expects, result, desc)) { 21 | write_passed(desc); 22 | } 23 | 24 | // Update result counters 25 | var p = document.getElementById('tests_passed'); 26 | p.innerHTML = tests_passed; 27 | if (tests_count == tests_passed) { 28 | p.setAttribute('class', 'ok'); 29 | } 30 | p = document.getElementById('tests_failed'); 31 | p.innerHTML = tests_failed; 32 | if (tests_failed > 0) { 33 | p.setAttribute('class', 'error'); 34 | } 35 | }; 36 | 37 | // Expects result to be true 38 | var assertTrue = function(result, desc) { 39 | assert(true, result, desc); 40 | }; 41 | 42 | // Expects a false result 43 | var assertFalse = function(result, desc) { 44 | assert(false, result, desc); 45 | }; 46 | 47 | // Assert with generator as argument 48 | var assertGen = function(generator, input, expects, desc) { 49 | if (core.isArray(generator)) { 50 | assert(expects, core.map(function(g) { return g(input).result; }, generator), desc); 51 | } else if (core.isFunction(expects)) { 52 | assertTrue(expects(generator(input).result), desc); 53 | } else { 54 | assert(expects, generator(input).result, desc); 55 | } 56 | }; 57 | 58 | // Assert generator throws an exception 59 | var assertException = function(gen, input, desc) { 60 | try { 61 | gen(input); 62 | write_failed(desc, "Exception expected, but not thrown!"); 63 | } catch(e) { 64 | write_passed(desc); 65 | } 66 | }; 67 | 68 | // Custom recursive value comparator with 69 | // support for object and array comparison. 70 | var passed = function(expects, result, desc) { 71 | if (core.isObject(expects)) { 72 | for (var name in expects) { 73 | if (!passed(expects[name], result[name], desc)) { 74 | write_failed(desc, "Error: expected '" + expects[name] + "' but result is '" + result[name] + "' !"); 75 | return false; 76 | } 77 | } 78 | } else if (core.isArray(expects)) { 79 | if (expects.length != result.length) { 80 | write_failed(desc, "Error: array length mismatch, expecting '" + expects.length + 81 | "' but result is '" + result.length + "' !"); 82 | return false; 83 | } 84 | for (var i = 0; i < expects.length; i++) { 85 | if (!passed(expects[i], result[i], desc)) { 86 | write_failed(desc, "Error: expected '" + expects[i] + "' but result is '" + result[i] + "' !"); 87 | return false; 88 | } 89 | } 90 | } else { 91 | if (expects !== result) { 92 | write_failed(desc, "Error: expected '" + expects + "' but result is '" + result + "' !"); 93 | return false; 94 | } 95 | } 96 | return true; 97 | }; 98 | 99 | // Writes test case passed massage 100 | var write_passed = function(desc) { 101 | tests_passed++; 102 | document.writeln(desc + " - OK
"); 103 | }; 104 | 105 | // Writes test failed message 106 | var write_failed = function(desc, msg) { 107 | tests_failed++; 108 | document.writeln(desc + " - " + msg + "
"); 109 | }; 110 | 111 | --------------------------------------------------------------------------------