--- /dev/null
+/*\r
+jed.js\r
+v0.5.0beta\r
+\r
+https://github.com/SlexAxton/Jed\r
+-----------\r
+A gettext compatible i18n library for modern JavaScript Applications\r
+\r
+by Alex Sexton - AlexSexton [at] gmail - @SlexAxton\r
+WTFPL license for use\r
+Dojo CLA for contributions\r
+\r
+Jed offers the entire applicable GNU gettext spec'd set of\r
+functions, but also offers some nicer wrappers around them.\r
+The api for gettext was written for a language with no function\r
+overloading, so Jed allows a little more of that.\r
+\r
+Many thanks to Joshua I. Miller - unrtst@cpan.org - who wrote\r
+gettext.js back in 2008. I was able to vet a lot of my ideas\r
+against his. I also made sure Jed passed against his tests\r
+in order to offer easy upgrades -- jsgettext.berlios.de\r
+*/\r
+(function (root, undef) {\r
+\r
+ // Set up some underscore-style functions, if you already have\r
+ // underscore, feel free to delete this section, and use it\r
+ // directly, however, the amount of functions used doesn't\r
+ // warrant having underscore as a full dependency.\r
+ // Underscore 1.3.0 was used to port and is licensed\r
+ // under the MIT License by Jeremy Ashkenas.\r
+ var ArrayProto = Array.prototype,\r
+ ObjProto = Object.prototype,\r
+ slice = ArrayProto.slice,\r
+ hasOwnProp = ObjProto.hasOwnProperty,\r
+ nativeForEach = ArrayProto.forEach,\r
+ breaker = {};\r
+\r
+ // We're not using the OOP style _ so we don't need the\r
+ // extra level of indirection. This still means that you\r
+ // sub out for real `_` though.\r
+ var _ = {\r
+ forEach : function( obj, iterator, context ) {\r
+ var i, l, key;\r
+ if ( obj === null ) {\r
+ return;\r
+ }\r
+\r
+ if ( nativeForEach && obj.forEach === nativeForEach ) {\r
+ obj.forEach( iterator, context );\r
+ }\r
+ else if ( obj.length === +obj.length ) {\r
+ for ( i = 0, l = obj.length; i < l; i++ ) {\r
+ if ( i in obj && iterator.call( context, obj[i], i, obj ) === breaker ) {\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ for ( key in obj) {\r
+ if ( hasOwnProp.call( obj, key ) ) {\r
+ if ( iterator.call (context, obj[key], key, obj ) === breaker ) {\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ },\r
+ extend : function( obj ) {\r
+ this.forEach( slice.call( arguments, 1 ), function ( source ) {\r
+ for ( var prop in source ) {\r
+ obj[prop] = source[prop];\r
+ }\r
+ });\r
+ return obj;\r
+ }\r
+ };\r
+ // END Miniature underscore impl\r
+\r
+ // Jed is a constructor function\r
+ var Jed = function ( options ) {\r
+ // Some minimal defaults\r
+ this.defaults = {\r
+ "locale_data" : {\r
+ "messages" : {\r
+ "" : {\r
+ "domain" : "messages",\r
+ "lang" : "en",\r
+ "plural_forms" : "nplurals=2; plural=(n != 1);"\r
+ }\r
+ // There are no default keys, though\r
+ }\r
+ },\r
+ // The default domain if one is missing\r
+ "domain" : "messages"\r
+ };\r
+\r
+ // Mix in the sent options with the default options\r
+ this.options = _.extend( {}, this.defaults, options );\r
+ this.textdomain( this.options.domain );\r
+\r
+ if ( this.options.domain && ! this.options.locale_data[ this.options.domain ] ) {\r
+ throw new Error('Text domain set to non-existent domain: `' + this.options.domain + '`');\r
+ }\r
+ };\r
+\r
+ // The gettext spec sets this character as the default\r
+ // delimiter for context lookups.\r
+ // e.g.: context\u0004key\r
+ // If your translation company uses something different,\r
+ // just change this at any time and it will use that instead.\r
+ Jed.context_delimiter = String.fromCharCode( 4 );\r
+\r
+ function getPluralFormFunc ( plural_form_string ) {\r
+ return Jed.PF.compile( plural_form_string || "nplurals=2; plural=(n != 1);");\r
+ }\r
+\r
+ function Chain( key, i18n ){\r
+ this._key = key;\r
+ this._i18n = i18n;\r
+ }\r
+\r
+ // Create a chainable api for adding args prettily\r
+ _.extend( Chain.prototype, {\r
+ onDomain : function ( domain ) {\r
+ this._domain = domain;\r
+ return this;\r
+ },\r
+ withContext : function ( context ) {\r
+ this._context = context;\r
+ return this;\r
+ },\r
+ ifPlural : function ( num, pkey ) {\r
+ this._val = num;\r
+ this._pkey = pkey;\r
+ return this;\r
+ },\r
+ fetch : function ( sArr ) {\r
+ if ( {}.toString.call( sArr ) != '[object Array]' ) {\r
+ sArr = [].slice.call(arguments);\r
+ }\r
+ return ( sArr && sArr.length ? Jed.sprintf : function(x){ return x; } )(\r
+ this._i18n.dcnpgettext(this._domain, this._context, this._key, this._pkey, this._val),\r
+ sArr\r
+ );\r
+ }\r
+ });\r
+\r
+ // Add functions to the Jed prototype.\r
+ // These will be the functions on the object that's returned\r
+ // from creating a `new Jed()`\r
+ // These seem redundant, but they gzip pretty well.\r
+ _.extend( Jed.prototype, {\r
+ // The sexier api start point\r
+ translate : function ( key ) {\r
+ return new Chain( key, this );\r
+ },\r
+\r
+ textdomain : function ( domain ) {\r
+ if ( ! domain ) {\r
+ return this._textdomain;\r
+ }\r
+ this._textdomain = domain;\r
+ },\r
+\r
+ gettext : function ( key ) {\r
+ return this.dcnpgettext.call( this, undef, undef, key );\r
+ },\r
+\r
+ dgettext : function ( domain, key ) {\r
+ return this.dcnpgettext.call( this, domain, undef, key );\r
+ },\r
+\r
+ dcgettext : function ( domain , key /*, category */ ) {\r
+ // Ignores the category anyways\r
+ return this.dcnpgettext.call( this, domain, undef, key );\r
+ },\r
+\r
+ ngettext : function ( skey, pkey, val ) {\r
+ return this.dcnpgettext.call( this, undef, undef, skey, pkey, val );\r
+ },\r
+\r
+ dngettext : function ( domain, skey, pkey, val ) {\r
+ return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );\r
+ },\r
+\r
+ dcngettext : function ( domain, skey, pkey, val/*, category */) {\r
+ return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );\r
+ },\r
+\r
+ pgettext : function ( context, key ) {\r
+ return this.dcnpgettext.call( this, undef, context, key );\r
+ },\r
+\r
+ dpgettext : function ( domain, context, key ) {\r
+ return this.dcnpgettext.call( this, domain, context, key );\r
+ },\r
+\r
+ dcpgettext : function ( domain, context, key/*, category */) {\r
+ return this.dcnpgettext.call( this, domain, context, key );\r
+ },\r
+\r
+ npgettext : function ( context, skey, pkey, val ) {\r
+ return this.dcnpgettext.call( this, undef, context, skey, pkey, val );\r
+ },\r
+\r
+ dnpgettext : function ( domain, context, skey, pkey, val ) {\r
+ return this.dcnpgettext.call( this, domain, context, skey, pkey, val );\r
+ },\r
+\r
+ // The most fully qualified gettext function. It has every option.\r
+ // Since it has every option, we can use it from every other method.\r
+ // This is the bread and butter.\r
+ // Technically there should be one more argument in this function for 'Category',\r
+ // but since we never use it, we might as well not waste the bytes to define it.\r
+ dcnpgettext : function ( domain, context, singular_key, plural_key, val ) {\r
+ // Set some defaults\r
+\r
+ plural_key = plural_key || singular_key;\r
+\r
+ // Use the global domain default if one\r
+ // isn't explicitly passed in\r
+ domain = domain || this._textdomain;\r
+\r
+ // Default the value to the singular case\r
+ val = typeof val == 'undefined' ? 1 : val;\r
+\r
+ var fallback;\r
+\r
+ // Handle special cases\r
+\r
+ // No options found\r
+ if ( ! this.options ) {\r
+ // There's likely something wrong, but we'll return the correct key for english\r
+ // We do this by instantiating a brand new Jed instance with the default set\r
+ // for everything that could be broken.\r
+ fallback = new Jed();\r
+ return fallback.dcnpgettext.call( fallback, undefined, undefined, singular_key, plural_key, val );\r
+ }\r
+\r
+ // No translation data provided\r
+ if ( ! this.options.locale_data ) {\r
+ throw new Error('No locale data provided.');\r
+ }\r
+\r
+ if ( ! this.options.locale_data[ domain ] ) {\r
+ throw new Error('Domain `' + domain + '` was not found.');\r
+ }\r
+\r
+ if ( ! this.options.locale_data[ domain ][ "" ] ) {\r
+ throw new Error('No locale meta information provided.');\r
+ }\r
+\r
+ // Make sure we have a truthy key. Otherwise we might start looking\r
+ // into the empty string key, which is the options for the locale\r
+ // data.\r
+ if ( ! singular_key ) {\r
+ throw new Error('No translation key found.');\r
+ }\r
+\r
+ // Handle invalid numbers, but try casting strings for good measure\r
+ if ( typeof val != 'number' ) {\r
+ val = parseInt( val, 10 );\r
+\r
+ if ( isNaN( val ) ) {\r
+ throw new Error('The number that was passed in is not a number.');\r
+ }\r
+ }\r
+\r
+ var key = context ? context + Jed.context_delimiter + singular_key : singular_key,\r
+ locale_data = this.options.locale_data,\r
+ dict = locale_data[ domain ],\r
+ pluralForms = dict[""].plural_forms || (locale_data.messages || this.defaults.locale_data.messages)[""].plural_forms,\r
+ val_idx = getPluralFormFunc(pluralForms)(val) + 1,\r
+ val_list,\r
+ res;\r
+\r
+ // Throw an error if a domain isn't found\r
+ if ( ! dict ) {\r
+ throw new Error('No domain named `' + domain + '` could be found.');\r
+ }\r
+\r
+ val_list = dict[ key ];\r
+\r
+ // If there is no match, then revert back to\r
+ // english style singular/plural with the keys passed in.\r
+ if ( ! val_list || val_idx >= val_list.length ) {\r
+ res = [ null, singular_key, plural_key ];\r
+ return res[ getPluralFormFunc(pluralForms)( val ) + 1 ];\r
+ }\r
+\r
+ res = val_list[ val_idx ];\r
+\r
+ // This includes empty strings on purpose\r
+ if ( ! res ) {\r
+ res = [ null, singular_key, plural_key ];\r
+ return res[ getPluralFormFunc(pluralForms)( val ) + 1 ];\r
+ }\r
+ return res;\r
+ }\r
+ });\r
+\r
+\r
+ // We add in sprintf capabilities for post translation value interolation\r
+ // This is not internally used, so you can remove it if you have this\r
+ // available somewhere else, or want to use a different system.\r
+\r
+ // We _slightly_ modify the normal sprintf behavior to more gracefully handle\r
+ // undefined values.\r
+\r
+ /**\r
+ sprintf() for JavaScript 0.7-beta1\r
+ http://www.diveintojavascript.com/projects/javascript-sprintf\r
+\r
+ Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions are met:\r
+ * Redistributions of source code must retain the above copyright\r
+ notice, this list of conditions and the following disclaimer.\r
+ * Redistributions in binary form must reproduce the above copyright\r
+ notice, this list of conditions and the following disclaimer in the\r
+ documentation and/or other materials provided with the distribution.\r
+ * Neither the name of sprintf() for JavaScript nor the\r
+ names of its contributors may be used to endorse or promote products\r
+ derived from this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY\r
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+ var sprintf = (function() {\r
+ function get_type(variable) {\r
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();\r
+ }\r
+ function str_repeat(input, multiplier) {\r
+ for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}\r
+ return output.join('');\r
+ }\r
+\r
+ var str_format = function() {\r
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {\r
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);\r
+ }\r
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);\r
+ };\r
+\r
+ str_format.format = function(parse_tree, argv) {\r
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;\r
+ for (i = 0; i < tree_length; i++) {\r
+ node_type = get_type(parse_tree[i]);\r
+ if (node_type === 'string') {\r
+ output.push(parse_tree[i]);\r
+ }\r
+ else if (node_type === 'array') {\r
+ match = parse_tree[i]; // convenience purposes only\r
+ if (match[2]) { // keyword argument\r
+ arg = argv[cursor];\r
+ for (k = 0; k < match[2].length; k++) {\r
+ if (!arg.hasOwnProperty(match[2][k])) {\r
+ throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));\r
+ }\r
+ arg = arg[match[2][k]];\r
+ }\r
+ }\r
+ else if (match[1]) { // positional argument (explicit)\r
+ arg = argv[match[1]];\r
+ }\r
+ else { // positional argument (implicit)\r
+ arg = argv[cursor++];\r
+ }\r
+\r
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {\r
+ throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));\r
+ }\r
+\r
+ // Jed EDIT\r
+ if ( typeof arg == 'undefined' || arg === null ) {\r
+ arg = '';\r
+ }\r
+ // Jed EDIT\r
+\r
+ switch (match[8]) {\r
+ case 'b': arg = arg.toString(2); break;\r
+ case 'c': arg = String.fromCharCode(arg); break;\r
+ case 'd': arg = parseInt(arg, 10); break;\r
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;\r
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;\r
+ case 'o': arg = arg.toString(8); break;\r
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;\r
+ case 'u': arg = Math.abs(arg); break;\r
+ case 'x': arg = arg.toString(16); break;\r
+ case 'X': arg = arg.toString(16).toUpperCase(); break;\r
+ }\r
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);\r
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';\r
+ pad_length = match[6] - String(arg).length;\r
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';\r
+ output.push(match[5] ? arg + pad : pad + arg);\r
+ }\r
+ }\r
+ return output.join('');\r
+ };\r
+\r
+ str_format.cache = {};\r
+\r
+ str_format.parse = function(fmt) {\r
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;\r
+ while (_fmt) {\r
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {\r
+ parse_tree.push(match[0]);\r
+ }\r
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {\r
+ parse_tree.push('%');\r
+ }\r
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {\r
+ if (match[2]) {\r
+ arg_names |= 1;\r
+ var field_list = [], replacement_field = match[2], field_match = [];\r
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+ field_list.push(field_match[1]);\r
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {\r
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+ field_list.push(field_match[1]);\r
+ }\r
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {\r
+ field_list.push(field_match[1]);\r
+ }\r
+ else {\r
+ throw('[sprintf] huh?');\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ throw('[sprintf] huh?');\r
+ }\r
+ match[2] = field_list;\r
+ }\r
+ else {\r
+ arg_names |= 2;\r
+ }\r
+ if (arg_names === 3) {\r
+ throw('[sprintf] mixing positional and named placeholders is not (yet) supported');\r
+ }\r
+ parse_tree.push(match);\r
+ }\r
+ else {\r
+ throw('[sprintf] huh?');\r
+ }\r
+ _fmt = _fmt.substring(match[0].length);\r
+ }\r
+ return parse_tree;\r
+ };\r
+\r
+ return str_format;\r
+ })();\r
+\r
+ var vsprintf = function(fmt, argv) {\r
+ argv.unshift(fmt);\r
+ return sprintf.apply(null, argv);\r
+ };\r
+\r
+ Jed.parse_plural = function ( plural_forms, n ) {\r
+ plural_forms = plural_forms.replace(/n/g, n);\r
+ return Jed.parse_expression(plural_forms);\r
+ };\r
+\r
+ Jed.sprintf = function ( fmt, args ) {\r
+ if ( {}.toString.call( args ) == '[object Array]' ) {\r
+ return vsprintf( fmt, [].slice.call(args) );\r
+ }\r
+ return sprintf.apply(this, [].slice.call(arguments) );\r
+ };\r
+\r
+ Jed.prototype.sprintf = function () {\r
+ return Jed.sprintf.apply(this, arguments);\r
+ };\r
+ // END sprintf Implementation\r
+\r
+ // Start the Plural forms section\r
+ // This is a full plural form expression parser. It is used to avoid\r
+ // running 'eval' or 'new Function' directly against the plural\r
+ // forms.\r
+ //\r
+ // This can be important if you get translations done through a 3rd\r
+ // party vendor. I encourage you to use this instead, however, I\r
+ // also will provide a 'precompiler' that you can use at build time\r
+ // to output valid/safe function representations of the plural form\r
+ // expressions. This means you can build this code out for the most\r
+ // part.\r
+ Jed.PF = {};\r
+\r
+ Jed.PF.parse = function ( p ) {\r
+ var plural_str = Jed.PF.extractPluralExpr( p );\r
+ return Jed.PF.parser.parse.call(Jed.PF.parser, plural_str);\r
+ };\r
+\r
+ Jed.PF.compile = function ( p ) {\r
+ // Handle trues and falses as 0 and 1\r
+ function imply( val ) {\r
+ return (val === true ? 1 : val ? val : 0);\r
+ }\r
+\r
+ var ast = Jed.PF.parse( p );\r
+ return function ( n ) {\r
+ return imply( Jed.PF.interpreter( ast )( n ) );\r
+ };\r
+ };\r
+\r
+ Jed.PF.interpreter = function ( ast ) {\r
+ return function ( n ) {\r
+ var res;\r
+ switch ( ast.type ) {\r
+ case 'GROUP':\r
+ return Jed.PF.interpreter( ast.expr )( n );\r
+ case 'TERNARY':\r
+ if ( Jed.PF.interpreter( ast.expr )( n ) ) {\r
+ return Jed.PF.interpreter( ast.truthy )( n );\r
+ }\r
+ return Jed.PF.interpreter( ast.falsey )( n );\r
+ case 'OR':\r
+ return Jed.PF.interpreter( ast.left )( n ) || Jed.PF.interpreter( ast.right )( n );\r
+ case 'AND':\r
+ return Jed.PF.interpreter( ast.left )( n ) && Jed.PF.interpreter( ast.right )( n );\r
+ case 'LT':\r
+ return Jed.PF.interpreter( ast.left )( n ) < Jed.PF.interpreter( ast.right )( n );\r
+ case 'GT':\r
+ return Jed.PF.interpreter( ast.left )( n ) > Jed.PF.interpreter( ast.right )( n );\r
+ case 'LTE':\r
+ return Jed.PF.interpreter( ast.left )( n ) <= Jed.PF.interpreter( ast.right )( n );\r
+ case 'GTE':\r
+ return Jed.PF.interpreter( ast.left )( n ) >= Jed.PF.interpreter( ast.right )( n );\r
+ case 'EQ':\r
+ return Jed.PF.interpreter( ast.left )( n ) == Jed.PF.interpreter( ast.right )( n );\r
+ case 'NEQ':\r
+ return Jed.PF.interpreter( ast.left )( n ) != Jed.PF.interpreter( ast.right )( n );\r
+ case 'MOD':\r
+ return Jed.PF.interpreter( ast.left )( n ) % Jed.PF.interpreter( ast.right )( n );\r
+ case 'VAR':\r
+ return n;\r
+ case 'NUM':\r
+ return ast.val;\r
+ default:\r
+ throw new Error("Invalid Token found.");\r
+ }\r
+ };\r
+ };\r
+\r
+ Jed.PF.extractPluralExpr = function ( p ) {\r
+ // trim first\r
+ p = p.replace(/^\s\s*/, '').replace(/\s\s*$/, '');\r
+\r
+ if (! /;\s*$/.test(p)) {\r
+ p = p.concat(';');\r
+ }\r
+\r
+ var nplurals_re = /nplurals\=(\d+);/,\r
+ plural_re = /plural\=(.*);/,\r
+ nplurals_matches = p.match( nplurals_re ),\r
+ res = {},\r
+ plural_matches;\r
+\r
+ // Find the nplurals number\r
+ if ( nplurals_matches.length > 1 ) {\r
+ res.nplurals = nplurals_matches[1];\r
+ }\r
+ else {\r
+ throw new Error('nplurals not found in plural_forms string: ' + p );\r
+ }\r
+\r
+ // remove that data to get to the formula\r
+ p = p.replace( nplurals_re, "" );\r
+ plural_matches = p.match( plural_re );\r
+\r
+ if (!( plural_matches && plural_matches.length > 1 ) ) {\r
+ throw new Error('`plural` expression not found: ' + p);\r
+ }\r
+ return plural_matches[ 1 ];\r
+ };\r
+\r
+ /* Jison generated parser */\r
+ Jed.PF.parser = (function(){\r
+\r
+var parser = {trace: function trace() { },\r
+yy: {},\r
+symbols_: {"error":2,"expressions":3,"e":4,"EOF":5,"?":6,":":7,"||":8,"&&":9,"<":10,"<=":11,">":12,">=":13,"!=":14,"==":15,"%":16,"(":17,")":18,"n":19,"NUMBER":20,"$accept":0,"$end":1},\r
+terminals_: {2:"error",5:"EOF",6:"?",7:":",8:"||",9:"&&",10:"<",11:"<=",12:">",13:">=",14:"!=",15:"==",16:"%",17:"(",18:")",19:"n",20:"NUMBER"},\r
+productions_: [0,[3,2],[4,5],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,1],[4,1]],\r
+performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {\r
+\r
+var $0 = $$.length - 1;\r
+switch (yystate) {\r
+case 1: return { type : 'GROUP', expr: $$[$0-1] }; \r
+break;\r
+case 2:this.$ = { type: 'TERNARY', expr: $$[$0-4], truthy : $$[$0-2], falsey: $$[$0] }; \r
+break;\r
+case 3:this.$ = { type: "OR", left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 4:this.$ = { type: "AND", left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 5:this.$ = { type: 'LT', left: $$[$0-2], right: $$[$0] }; \r
+break;\r
+case 6:this.$ = { type: 'LTE', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 7:this.$ = { type: 'GT', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 8:this.$ = { type: 'GTE', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 9:this.$ = { type: 'NEQ', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 10:this.$ = { type: 'EQ', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 11:this.$ = { type: 'MOD', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 12:this.$ = { type: 'GROUP', expr: $$[$0-1] }; \r
+break;\r
+case 13:this.$ = { type: 'VAR' }; \r
+break;\r
+case 14:this.$ = { type: 'NUM', val: Number(yytext) }; \r
+break;\r
+}\r
+},\r
+table: [{3:1,4:2,17:[1,3],19:[1,4],20:[1,5]},{1:[3]},{5:[1,6],6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{4:17,17:[1,3],19:[1,4],20:[1,5]},{5:[2,13],6:[2,13],7:[2,13],8:[2,13],9:[2,13],10:[2,13],11:[2,13],12:[2,13],13:[2,13],14:[2,13],15:[2,13],16:[2,13],18:[2,13]},{5:[2,14],6:[2,14],7:[2,14],8:[2,14],9:[2,14],10:[2,14],11:[2,14],12:[2,14],13:[2,14],14:[2,14],15:[2,14],16:[2,14],18:[2,14]},{1:[2,1]},{4:18,17:[1,3],19:[1,4],20:[1,5]},{4:19,17:[1,3],19:[1,4],20:[1,5]},{4:20,17:[1,3],19:[1,4],20:[1,5]},{4:21,17:[1,3],19:[1,4],20:[1,5]},{4:22,17:[1,3],19:[1,4],20:[1,5]},{4:23,17:[1,3],19:[1,4],20:[1,5]},{4:24,17:[1,3],19:[1,4],20:[1,5]},{4:25,17:[1,3],19:[1,4],20:[1,5]},{4:26,17:[1,3],19:[1,4],20:[1,5]},{4:27,17:[1,3],19:[1,4],20:[1,5]},{6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[1,28]},{6:[1,7],7:[1,29],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{5:[2,3],6:[2,3],7:[2,3],8:[2,3],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[2,5],11:[2,5],12:[2,5],13:[2,5],14:[2,5],15:[2,5],16:[1,16],18:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],11:[2,6],12:[2,6],13:[2,6],14:[2,6],15:[2,6],16:[1,16],18:[2,6]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],11:[2,7],12:[2,7],13:[2,7],14:[2,7],15:[2,7],16:[1,16],18:[2,7]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],11:[2,8],12:[2,8],13:[2,8],14:[2,8],15:[2,8],16:[1,16],18:[2,8]},{5:[2,9],6:[2,9],7:[2,9],8:[2,9],9:[2,9],10:[2,9],11:[2,9],12:[2,9],13:[2,9],14:[2,9],15:[2,9],16:[1,16],18:[2,9]},{5:[2,10],6:[2,10],7:[2,10],8:[2,10],9:[2,10],10:[2,10],11:[2,10],12:[2,10],13:[2,10],14:[2,10],15:[2,10],16:[1,16],18:[2,10]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],11:[2,11],12:[2,11],13:[2,11],14:[2,11],15:[2,11],16:[2,11],18:[2,11]},{5:[2,12],6:[2,12],7:[2,12],8:[2,12],9:[2,12],10:[2,12],11:[2,12],12:[2,12],13:[2,12],14:[2,12],15:[2,12],16:[2,12],18:[2,12]},{4:30,17:[1,3],19:[1,4],20:[1,5]},{5:[2,2],6:[1,7],7:[2,2],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,2]}],\r
+defaultActions: {6:[2,1]},\r
+parseError: function parseError(str, hash) {\r
+ throw new Error(str);\r
+},\r
+parse: function parse(input) {\r
+ var self = this,\r
+ stack = [0],\r
+ vstack = [null], // semantic value stack\r
+ lstack = [], // location stack\r
+ table = this.table,\r
+ yytext = '',\r
+ yylineno = 0,\r
+ yyleng = 0,\r
+ recovering = 0,\r
+ TERROR = 2,\r
+ EOF = 1;\r
+\r
+ //this.reductionCount = this.shiftCount = 0;\r
+\r
+ this.lexer.setInput(input);\r
+ this.lexer.yy = this.yy;\r
+ this.yy.lexer = this.lexer;\r
+ if (typeof this.lexer.yylloc == 'undefined')\r
+ this.lexer.yylloc = {};\r
+ var yyloc = this.lexer.yylloc;\r
+ lstack.push(yyloc);\r
+\r
+ if (typeof this.yy.parseError === 'function')\r
+ this.parseError = this.yy.parseError;\r
+\r
+ function popStack (n) {\r
+ stack.length = stack.length - 2*n;\r
+ vstack.length = vstack.length - n;\r
+ lstack.length = lstack.length - n;\r
+ }\r
+\r
+ function lex() {\r
+ var token;\r
+ token = self.lexer.lex() || 1; // $end = 1\r
+ // if token isn't its numeric value, convert\r
+ if (typeof token !== 'number') {\r
+ token = self.symbols_[token] || token;\r
+ }\r
+ return token;\r
+ }\r
+\r
+ var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;\r
+ while (true) {\r
+ // retreive state number from top of stack\r
+ state = stack[stack.length-1];\r
+\r
+ // use default actions if available\r
+ if (this.defaultActions[state]) {\r
+ action = this.defaultActions[state];\r
+ } else {\r
+ if (symbol == null)\r
+ symbol = lex();\r
+ // read action for current state and first input\r
+ action = table[state] && table[state][symbol];\r
+ }\r
+\r
+ // handle parse error\r
+ _handle_error:\r
+ if (typeof action === 'undefined' || !action.length || !action[0]) {\r
+\r
+ if (!recovering) {\r
+ // Report error\r
+ expected = [];\r
+ for (p in table[state]) if (this.terminals_[p] && p > 2) {\r
+ expected.push("'"+this.terminals_[p]+"'");\r
+ }\r
+ var errStr = '';\r
+ if (this.lexer.showPosition) {\r
+ errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";\r
+ } else {\r
+ errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +\r
+ (symbol == 1 /*EOF*/ ? "end of input" :\r
+ ("'"+(this.terminals_[symbol] || symbol)+"'"));\r
+ }\r
+ this.parseError(errStr,\r
+ {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});\r
+ }\r
+\r
+ // just recovered from another error\r
+ if (recovering == 3) {\r
+ if (symbol == EOF) {\r
+ throw new Error(errStr || 'Parsing halted.');\r
+ }\r
+\r
+ // discard current lookahead and grab another\r
+ yyleng = this.lexer.yyleng;\r
+ yytext = this.lexer.yytext;\r
+ yylineno = this.lexer.yylineno;\r
+ yyloc = this.lexer.yylloc;\r
+ symbol = lex();\r
+ }\r
+\r
+ // try to recover from error\r
+ while (1) {\r
+ // check for error recovery rule in this state\r
+ if ((TERROR.toString()) in table[state]) {\r
+ break;\r
+ }\r
+ if (state == 0) {\r
+ throw new Error(errStr || 'Parsing halted.');\r
+ }\r
+ popStack(1);\r
+ state = stack[stack.length-1];\r
+ }\r
+\r
+ preErrorSymbol = symbol; // save the lookahead token\r
+ symbol = TERROR; // insert generic error symbol as new lookahead\r
+ state = stack[stack.length-1];\r
+ action = table[state] && table[state][TERROR];\r
+ recovering = 3; // allow 3 real symbols to be shifted before reporting a new error\r
+ }\r
+\r
+ // this shouldn't happen, unless resolve defaults are off\r
+ if (action[0] instanceof Array && action.length > 1) {\r
+ throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);\r
+ }\r
+\r
+ switch (action[0]) {\r
+\r
+ case 1: // shift\r
+ //this.shiftCount++;\r
+\r
+ stack.push(symbol);\r
+ vstack.push(this.lexer.yytext);\r
+ lstack.push(this.lexer.yylloc);\r
+ stack.push(action[1]); // push state\r
+ symbol = null;\r
+ if (!preErrorSymbol) { // normal execution/no error\r
+ yyleng = this.lexer.yyleng;\r
+ yytext = this.lexer.yytext;\r
+ yylineno = this.lexer.yylineno;\r
+ yyloc = this.lexer.yylloc;\r
+ if (recovering > 0)\r
+ recovering--;\r
+ } else { // error just occurred, resume old lookahead f/ before error\r
+ symbol = preErrorSymbol;\r
+ preErrorSymbol = null;\r
+ }\r
+ break;\r
+\r
+ case 2: // reduce\r
+ //this.reductionCount++;\r
+\r
+ len = this.productions_[action[1]][1];\r
+\r
+ // perform semantic action\r
+ yyval.$ = vstack[vstack.length-len]; // default to $$ = $1\r
+ // default location, uses first token for firsts, last for lasts\r
+ yyval._$ = {\r
+ first_line: lstack[lstack.length-(len||1)].first_line,\r
+ last_line: lstack[lstack.length-1].last_line,\r
+ first_column: lstack[lstack.length-(len||1)].first_column,\r
+ last_column: lstack[lstack.length-1].last_column\r
+ };\r
+ r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);\r
+\r
+ if (typeof r !== 'undefined') {\r
+ return r;\r
+ }\r
+\r
+ // pop off stack\r
+ if (len) {\r
+ stack = stack.slice(0,-1*len*2);\r
+ vstack = vstack.slice(0, -1*len);\r
+ lstack = lstack.slice(0, -1*len);\r
+ }\r
+\r
+ stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)\r
+ vstack.push(yyval.$);\r
+ lstack.push(yyval._$);\r
+ // goto new state = table[STATE][NONTERMINAL]\r
+ newState = table[stack[stack.length-2]][stack[stack.length-1]];\r
+ stack.push(newState);\r
+ break;\r
+\r
+ case 3: // accept\r
+ return true;\r
+ }\r
+\r
+ }\r
+\r
+ return true;\r
+}};/* Jison generated lexer */\r
+var lexer = (function(){\r
+\r
+var lexer = ({EOF:1,\r
+parseError:function parseError(str, hash) {\r
+ if (this.yy.parseError) {\r
+ this.yy.parseError(str, hash);\r
+ } else {\r
+ throw new Error(str);\r
+ }\r
+ },\r
+setInput:function (input) {\r
+ this._input = input;\r
+ this._more = this._less = this.done = false;\r
+ this.yylineno = this.yyleng = 0;\r
+ this.yytext = this.matched = this.match = '';\r
+ this.conditionStack = ['INITIAL'];\r
+ this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};\r
+ return this;\r
+ },\r
+input:function () {\r
+ var ch = this._input[0];\r
+ this.yytext+=ch;\r
+ this.yyleng++;\r
+ this.match+=ch;\r
+ this.matched+=ch;\r
+ var lines = ch.match(/\n/);\r
+ if (lines) this.yylineno++;\r
+ this._input = this._input.slice(1);\r
+ return ch;\r
+ },\r
+unput:function (ch) {\r
+ this._input = ch + this._input;\r
+ return this;\r
+ },\r
+more:function () {\r
+ this._more = true;\r
+ return this;\r
+ },\r
+pastInput:function () {\r
+ var past = this.matched.substr(0, this.matched.length - this.match.length);\r
+ return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");\r
+ },\r
+upcomingInput:function () {\r
+ var next = this.match;\r
+ if (next.length < 20) {\r
+ next += this._input.substr(0, 20-next.length);\r
+ }\r
+ return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");\r
+ },\r
+showPosition:function () {\r
+ var pre = this.pastInput();\r
+ var c = new Array(pre.length + 1).join("-");\r
+ return pre + this.upcomingInput() + "\n" + c+"^";\r
+ },\r
+next:function () {\r
+ if (this.done) {\r
+ return this.EOF;\r
+ }\r
+ if (!this._input) this.done = true;\r
+\r
+ var token,\r
+ match,\r
+ col,\r
+ lines;\r
+ if (!this._more) {\r
+ this.yytext = '';\r
+ this.match = '';\r
+ }\r
+ var rules = this._currentRules();\r
+ for (var i=0;i < rules.length; i++) {\r
+ match = this._input.match(this.rules[rules[i]]);\r
+ if (match) {\r
+ lines = match[0].match(/\n.*/g);\r
+ if (lines) this.yylineno += lines.length;\r
+ this.yylloc = {first_line: this.yylloc.last_line,\r
+ last_line: this.yylineno+1,\r
+ first_column: this.yylloc.last_column,\r
+ last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}\r
+ this.yytext += match[0];\r
+ this.match += match[0];\r
+ this.matches = match;\r
+ this.yyleng = this.yytext.length;\r
+ this._more = false;\r
+ this._input = this._input.slice(match[0].length);\r
+ this.matched += match[0];\r
+ token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);\r
+ if (token) return token;\r
+ else return;\r
+ }\r
+ }\r
+ if (this._input === "") {\r
+ return this.EOF;\r
+ } else {\r
+ this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), \r
+ {text: "", token: null, line: this.yylineno});\r
+ }\r
+ },\r
+lex:function lex() {\r
+ var r = this.next();\r
+ if (typeof r !== 'undefined') {\r
+ return r;\r
+ } else {\r
+ return this.lex();\r
+ }\r
+ },\r
+begin:function begin(condition) {\r
+ this.conditionStack.push(condition);\r
+ },\r
+popState:function popState() {\r
+ return this.conditionStack.pop();\r
+ },\r
+_currentRules:function _currentRules() {\r
+ return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;\r
+ },\r
+topState:function () {\r
+ return this.conditionStack[this.conditionStack.length-2];\r
+ },\r
+pushState:function begin(condition) {\r
+ this.begin(condition);\r
+ }});\r
+lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {\r
+\r
+var YYSTATE=YY_START;\r
+switch($avoiding_name_collisions) {\r
+case 0:/* skip whitespace */\r
+break;\r
+case 1:return 20\r
+break;\r
+case 2:return 19\r
+break;\r
+case 3:return 8\r
+break;\r
+case 4:return 9\r
+break;\r
+case 5:return 6\r
+break;\r
+case 6:return 7\r
+break;\r
+case 7:return 11\r
+break;\r
+case 8:return 13\r
+break;\r
+case 9:return 10\r
+break;\r
+case 10:return 12\r
+break;\r
+case 11:return 14\r
+break;\r
+case 12:return 15\r
+break;\r
+case 13:return 16\r
+break;\r
+case 14:return 17\r
+break;\r
+case 15:return 18\r
+break;\r
+case 16:return 5\r
+break;\r
+case 17:return 'INVALID'\r
+break;\r
+}\r
+};\r
+lexer.rules = [/^\s+/,/^[0-9]+(\.[0-9]+)?\b/,/^n\b/,/^\|\|/,/^&&/,/^\?/,/^:/,/^<=/,/^>=/,/^</,/^>/,/^!=/,/^==/,/^%/,/^\(/,/^\)/,/^$/,/^./];\r
+lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"inclusive":true}};return lexer;})()\r
+parser.lexer = lexer;\r
+return parser;\r
+})();\r
+// End parser\r
+\r
+ // Handle node, amd, and global systems\r
+ if (typeof exports !== 'undefined') {\r
+ if (typeof module !== 'undefined' && module.exports) {\r
+ exports = module.exports = Jed;\r
+ }\r
+ exports.Jed = Jed;\r
+ }\r
+ else {\r
+ if (typeof define === 'function' && define.amd) {\r
+ define('jed', function() {\r
+ return Jed;\r
+ });\r
+ }\r
+ // Leak a global regardless of module system\r
+ root['Jed'] = Jed;\r
+ }\r
+\r
+})(this);\r