diff --git a/dist/susanin.js b/dist/susanin.js index 0dc811c..0f8d7b2 100644 --- a/dist/susanin.js +++ b/dist/susanin.js @@ -327,7 +327,8 @@ Route.prototype._parsePattern = function(pattern, isOptional) { i = 0, j, size, countOpened = 0, isFindingClosed = false, - length = pattern.length; + length = pattern.length, + what; while (i < length) { character = pattern.charAt(i++); @@ -354,8 +355,12 @@ Route.prototype._parsePattern = function(pattern, isOptional) { parts.push(part); for (j = 0, size = part.parts.length; j < size; ++j) { - if (part.parts[j] && part.parts[j].what === 'param') { + what = part.parts[j] && part.parts[j].what; + + if (what === 'param') { part.dependOnParams.push(part.parts[j].name); + } else if (what === 'optional') { + part.dependOnParams.push.apply(part.dependOnParams, part.parts[j].dependOnParams); } } diff --git a/dist/susanin.min.js b/dist/susanin.min.js index c9ecd20..1d750f2 100644 --- a/dist/susanin.min.js +++ b/dist/susanin.min.js @@ -1 +1 @@ -!function(t){function e(t){return{"./querystring":function(){var t={},e=Object.prototype.hasOwnProperty,r=Object.prototype.toString,n=function(t){return"[object Array]"===r.call(t)},i={decode:function(t){var e;try{e=decodeURIComponent(t.replace(/\+/g,"%20"))}catch(r){e=t}return e},parse:function(t,r,o){var a,s,u,p,f,h,c={};if("string"!=typeof t||""===t)return c;for(r||(r="&"),o||(o="="),a=t.split(r),f=0,h=a.length;h>f;++f)s=a[f].split(o),u="undefined"!=typeof s[1]?i.decode(s[1]):"",p=i.decode(s[0]),e.call(c,p)?n(c[p])?c[p].push(u):c[p]=[c[p],u]:c[p]=u;return c},stringify:function(t,r,n){var i,o,a,s,u,p,f="";if(!t)return f;r||(r="&"),n||(n="=");for(p in t)if(e.call(t,p))for(a=[].concat(t[p]),s=0,u=a.length;u>s;++s)o=typeof a[s],i="object"===o||"undefined"===o?"":encodeURIComponent(a[s]),f+=r+encodeURIComponent(p)+n+i;return f.substr(r.length)}};return t.exports=i,t.exports},"./route":function(){function t(e){if(!(this instanceof t))return new t(e);if("string"==typeof e&&(e={pattern:e}),!e||"object"!=typeof e)throw new Error("You must specify options");if("string"!=typeof e.pattern)throw new Error("You must specify the pattern of the route");this._options=e,this._conditions=e.conditions&&"object"==typeof e.conditions?e.conditions:{},e.isTrailingSlashOptional!==!1&&(e.pattern+=c+f+g+h+l,this._conditions[g]=P),e.pattern+=c+"?"+f+b+h+l,this._conditions[b]=".*",this._paramsMap=[],this._mainParamsMap={},this._requiredParams=[],this._parts=this._parsePattern(e.pattern),this._buildParseRegExp(),this._buildBuildFn()}var r={},n=Object.prototype.hasOwnProperty,i=function(t,e){return n.call(t,e)},o=Object.prototype.toString,a=function(t){return"[object Array]"===o.call(t)},s=e("./querystring"),u=function(){var t=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],e=new RegExp("(\\"+t.join("|\\")+")","g");return function(t){return t.replace(e,"\\$1")}}(),p=String(Math.random()).substr(2,5),f="<",h=">",c="(",l=")",d="[a-zA-Z_][\\w\\-]*",_="[\\w\\-\\.~]+",m=new RegExp("("+u(f)+d+u(h)+"|"+"[^"+u(f)+u(h)+"]+"+"|"+u(f)+"|"+u(h)+")","g"),g="ts_"+p,y="/",P=u("/"),b="qs_"+p;return t.prototype._parsePattern=function(t,e){for(var r,n,i,o=[],a="",s=0,u=0,p=!1,f=t.length;f>s;)if(r=t.charAt(s++),r===c)p?(++u,a+=r):(this._parseParams(a,o,e),a="",u=0,p=!0);else if(r===l)if(p)if(0===u){for(a={what:"optional",dependOnParams:[],parts:this._parsePattern(a,!0)},o.push(a),n=0,i=a.parts.length;i>n;++n)a.parts[n]&&"param"===a.parts[n].what&&a.dependOnParams.push(a.parts[n].name);a="",p=!1}else--u,a+=r;else a+=r;else a+=r;return this._parseParams(a,o,e),o},t.prototype._parseParams=function(t,e,r){var n,i,o,a,s=t.match(m);if(s)for(n=0,i=s.length;i>n;++n)o=s[n],o.charAt(0)===f&&o.charAt(o.length-1)===h?(a=o.substr(1,o.length-2),this._paramsMap.push(a),this._mainParamsMap[a]=!0,r||this._requiredParams.push(a),e.push({what:"param",name:a})):e.push(o)},t.prototype._buildParseRegExp=function(){this._parseRegExpSource="^"+this._buildParseRegExpParts(this._parts)+"$",this._parseRegExp=new RegExp(this._parseRegExpSource)},t.prototype._buildParseRegExpParts=function(t){var e,r,n,i="";for(e=0,r=t.length;r>e;++e)n=t[e],i+="string"==typeof n?u(n):"param"===n.what?"("+(this._getParamValueRegExpSource(n.name)||_)+")":"(?:"+this._buildParseRegExpParts(n.parts)+")?";return i},t.prototype._getParamValueRegExpSource=function(t){var e,r,n=this._conditionRegExpSources||(this._conditionRegExpSources={}),o=this._conditions;return i(n,t)||(i(o,t)?(r=o[t],e=a(r)?"(?:"+r.join("|")+")":r+""):e=null,n[t]=e),n[t]},t.prototype._getParamValueRegExp=function(t){var e,r=this._conditionRegExps||(this._conditionRegExps={});return i(r,t)||(e=this._getParamValueRegExpSource(t),r[t]=e?new RegExp("^"+e+"$"):null),r[t]},t.prototype._checkParamValue=function(t,e){var r=this._getParamValueRegExp(t);return r?r.test(e):!0},t.prototype._buildBuildFn=function(){this._buildFnSource="var h=({}).hasOwnProperty;return "+this._buildBuildFnParts(this._parts)+";",this._buildFn=new Function("p",this._buildFnSource)},t.prototype._buildBuildFnParts=function(t){var e,r,n,o,a,s,p='""',f=this._options.defaults;for(e=0,r=t.length;r>e;++e)if(a=t[e],"string"==typeof a)p+='+"'+u(a)+'"';else if("param"===a.what)this._mainParamsMap[a.name]=!0,p+='+(h.call(p,"'+u(a.name)+'")?'+'p["'+u(a.name)+'"]:'+(f&&i(f,a.name)?'"'+u(f[a.name])+'"':'""')+")";else{for(p+="+((false",n=0,o=a.dependOnParams.length;o>n;++n)s=a.dependOnParams[n],p+='||(h.call(p,"'+u(s)+'")'+(f&&i(f,s)?'&&p["'+u(s)+'"]!=="'+u(f[s])+'"':"")+")";p+=")?("+this._buildBuildFnParts(a.parts)+'):"")'}return p},t.prototype._isDataMatched=function(t){var e,r=this._options.data;if("function"==typeof t)return Boolean(t(r));if(t&&"object"==typeof t)for(e in t)if(i(t,e)&&(!r||"object"!=typeof r||r[e]!==t[e]))return!1;return!0},t.prototype.match=function(t,e){var r,n,o,u,p,f,h,c=null,l=this._options,d=l.postMatch,_=l.defaults;if("string"!=typeof t||e&&!this._isDataMatched(e))return c;if(r=t.match(this._parseRegExp)){for(c={},n=1,o=r.length;o>n;++n)if("undefined"!=typeof r[n]&&""!==r[n])if(u=this._paramsMap[n-1],u===b)h=r[n];else if(u===g){if(t.charAt(t.length-2)===y)return null}else c[u]=r[n];if(h&&l.useQueryString!==!1){f=s.parse(h);for(u in f)if(i(f,u)&&!i(c,u))if(p=f[u],this._mainParamsMap[u]&&a(p)&&(p=p[0]),a(p))for(c[u]=[],n=0,o=p.length;o>n;++n)this._checkParamValue(u,p[n])&&c[u].push(p[n]);else this._checkParamValue(u,p)&&(c[u]=p)}for(u in _)i(_,u)&&!i(c,u)&&(c[u]=_[u])}return c&&"function"==typeof d&&(c=d(c),c&&"object"==typeof c||(c=null)),c},t.prototype.build=function(t,e){var r,n,o,a,u,p=this._options,f={},h=p.useQueryString!==!1,c={},l=p.preBuild;"function"==typeof l&&(t=l(t));for(n in t)if(i(t,n)&&null!==t[n]&&"undefined"!=typeof t[n]&&(this._mainParamsMap[n]||h)){if(o=t[n],e&&!this._checkParamValue(n,o))return null;(this._mainParamsMap[n]?f:c)[n]=o}if(e)for(a=0,u=this._requiredParams.length;u>a;++a)if(!i(f,this._requiredParams[a]))return null;return h&&(r=s.stringify(c),r&&(f[b]=r)),this._buildFn(f)},t.prototype.getData=function(){return this._options.data},t.prototype.getName=function(){return this._options.name},r.exports=t,r.exports},"./router":function(){function t(){return this instanceof t?(this._routes=[],this._routesByName={},void 0):new t}var r={},n=e("./route");return t.prototype.addRoute=function(t){var e,r;return e=new n(t),this._routes.push(e),r=e.getName(),r&&(this._routesByName[r]=e),e},t.prototype.find=function(){var t,e,r,n=[],i=this._routes;for(e=0,r=i.length;r>e;++e)t=i[e].match.apply(i[e],arguments),null!==t&&n.push([i[e],t]);return n},t.prototype.findFirst=function(){var t,e,r,n=this._routes;for(e=0,r=n.length;r>e;++e)if(t=n[e].match.apply(n[e],arguments),null!==t)return[n[e],t];return null},t.prototype.getRouteByName=function(t){return this._routesByName[t]||null},t.Route=n,r.exports=t,r.exports}}[t]()}var r=e("./router"),n=!0;t.module&&"object"==typeof module.exports&&(module.exports=r,n=!1),t.modules&&modules.define&&modules.require&&(modules.define("susanin",function(t){t(r)}),n=!1),"function"==typeof t.define&&define.amd&&(define(function(){return r}),n=!1),n&&(t.Susanin=r)}(this); \ No newline at end of file +!function(t){function e(t){return{"./querystring":function(){var t={},e=Object.prototype.hasOwnProperty,r=Object.prototype.toString,n=function(t){return"[object Array]"===r.call(t)},i={decode:function(t){var e;try{e=decodeURIComponent(t.replace(/\+/g,"%20"))}catch(r){e=t}return e},parse:function(t,r,o){var a,s,p,u,f,h,l={};if("string"!=typeof t||""===t)return l;for(r||(r="&"),o||(o="="),a=t.split(r),f=0,h=a.length;h>f;++f)s=a[f].split(o),p="undefined"!=typeof s[1]?i.decode(s[1]):"",u=i.decode(s[0]),e.call(l,u)?n(l[u])?l[u].push(p):l[u]=[l[u],p]:l[u]=p;return l},stringify:function(t,r,n){var i,o,a,s,p,u,f="";if(!t)return f;r||(r="&"),n||(n="=");for(u in t)if(e.call(t,u))for(a=[].concat(t[u]),s=0,p=a.length;p>s;++s)o=typeof a[s],i="object"===o||"undefined"===o?"":encodeURIComponent(a[s]),f+=r+encodeURIComponent(u)+n+i;return f.substr(r.length)}};return t.exports=i,t.exports},"./route":function(){function t(e){if(!(this instanceof t))return new t(e);if("string"==typeof e&&(e={pattern:e}),!e||"object"!=typeof e)throw new Error("You must specify options");if("string"!=typeof e.pattern)throw new Error("You must specify the pattern of the route");this._options=e,this._conditions=e.conditions&&"object"==typeof e.conditions?e.conditions:{},e.isTrailingSlashOptional!==!1&&(e.pattern+=l+f+g+h+c,this._conditions[g]=P),e.pattern+=l+"?"+f+b+h+c,this._conditions[b]=".*",this._paramsMap=[],this._mainParamsMap={},this._requiredParams=[],this._parts=this._parsePattern(e.pattern),this._buildParseRegExp(),this._buildBuildFn()}var r={},n=Object.prototype.hasOwnProperty,i=function(t,e){return n.call(t,e)},o=Object.prototype.toString,a=function(t){return"[object Array]"===o.call(t)},s=e("./querystring"),p=function(){var t=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],e=new RegExp("(\\"+t.join("|\\")+")","g");return function(t){return t.replace(e,"\\$1")}}(),u=String(Math.random()).substr(2,5),f="<",h=">",l="(",c=")",d="[a-zA-Z_][\\w\\-]*",m="[\\w\\-\\.~]+",_=new RegExp("("+p(f)+d+p(h)+"|"+"[^"+p(f)+p(h)+"]+"+"|"+p(f)+"|"+p(h)+")","g"),g="ts_"+u,y="/",P=p("/"),b="qs_"+u;return t.prototype._parsePattern=function(t,e){for(var r,n,i,o,a=[],s="",p=0,u=0,f=!1,h=t.length;h>p;)if(r=t.charAt(p++),r===l)f?(++u,s+=r):(this._parseParams(s,a,e),s="",u=0,f=!0);else if(r===c)if(f)if(0===u){for(s={what:"optional",dependOnParams:[],parts:this._parsePattern(s,!0)},a.push(s),n=0,i=s.parts.length;i>n;++n)o=s.parts[n]&&s.parts[n].what,"param"===o?s.dependOnParams.push(s.parts[n].name):"optional"===o&&s.dependOnParams.push.apply(s.dependOnParams,s.parts[n].dependOnParams);s="",f=!1}else--u,s+=r;else s+=r;else s+=r;return this._parseParams(s,a,e),a},t.prototype._parseParams=function(t,e,r){var n,i,o,a,s=t.match(_);if(s)for(n=0,i=s.length;i>n;++n)o=s[n],o.charAt(0)===f&&o.charAt(o.length-1)===h?(a=o.substr(1,o.length-2),this._paramsMap.push(a),this._mainParamsMap[a]=!0,r||this._requiredParams.push(a),e.push({what:"param",name:a})):e.push(o)},t.prototype._buildParseRegExp=function(){this._parseRegExpSource="^"+this._buildParseRegExpParts(this._parts)+"$",this._parseRegExp=new RegExp(this._parseRegExpSource)},t.prototype._buildParseRegExpParts=function(t){var e,r,n,i="";for(e=0,r=t.length;r>e;++e)n=t[e],i+="string"==typeof n?p(n):"param"===n.what?"("+(this._getParamValueRegExpSource(n.name)||m)+")":"(?:"+this._buildParseRegExpParts(n.parts)+")?";return i},t.prototype._getParamValueRegExpSource=function(t){var e,r,n=this._conditionRegExpSources||(this._conditionRegExpSources={}),o=this._conditions;return i(n,t)||(i(o,t)?(r=o[t],e=a(r)?"(?:"+r.join("|")+")":r+""):e=null,n[t]=e),n[t]},t.prototype._getParamValueRegExp=function(t){var e,r=this._conditionRegExps||(this._conditionRegExps={});return i(r,t)||(e=this._getParamValueRegExpSource(t),r[t]=e?new RegExp("^"+e+"$"):null),r[t]},t.prototype._checkParamValue=function(t,e){var r=this._getParamValueRegExp(t);return r?r.test(e):!0},t.prototype._buildBuildFn=function(){this._buildFnSource="var h=({}).hasOwnProperty;return "+this._buildBuildFnParts(this._parts)+";",this._buildFn=new Function("p",this._buildFnSource)},t.prototype._buildBuildFnParts=function(t){var e,r,n,o,a,s,u='""',f=this._options.defaults;for(e=0,r=t.length;r>e;++e)if(a=t[e],"string"==typeof a)u+='+"'+p(a)+'"';else if("param"===a.what)this._mainParamsMap[a.name]=!0,u+='+(h.call(p,"'+p(a.name)+'")?'+'p["'+p(a.name)+'"]:'+(f&&i(f,a.name)?'"'+p(f[a.name])+'"':'""')+")";else{for(u+="+((false",n=0,o=a.dependOnParams.length;o>n;++n)s=a.dependOnParams[n],u+='||(h.call(p,"'+p(s)+'")'+(f&&i(f,s)?'&&p["'+p(s)+'"]!=="'+p(f[s])+'"':"")+")";u+=")?("+this._buildBuildFnParts(a.parts)+'):"")'}return u},t.prototype._isDataMatched=function(t){var e,r=this._options.data;if("function"==typeof t)return Boolean(t(r));if(t&&"object"==typeof t)for(e in t)if(i(t,e)&&(!r||"object"!=typeof r||r[e]!==t[e]))return!1;return!0},t.prototype.match=function(t,e){var r,n,o,p,u,f,h,l=null,c=this._options,d=c.postMatch,m=c.defaults;if("string"!=typeof t||e&&!this._isDataMatched(e))return l;if(r=t.match(this._parseRegExp)){for(l={},n=1,o=r.length;o>n;++n)if("undefined"!=typeof r[n]&&""!==r[n])if(p=this._paramsMap[n-1],p===b)h=r[n];else if(p===g){if(t.charAt(t.length-2)===y)return null}else l[p]=r[n];if(h&&c.useQueryString!==!1){f=s.parse(h);for(p in f)if(i(f,p)&&!i(l,p))if(u=f[p],this._mainParamsMap[p]&&a(u)&&(u=u[0]),a(u))for(l[p]=[],n=0,o=u.length;o>n;++n)this._checkParamValue(p,u[n])&&l[p].push(u[n]);else this._checkParamValue(p,u)&&(l[p]=u)}for(p in m)i(m,p)&&!i(l,p)&&(l[p]=m[p])}return l&&"function"==typeof d&&(l=d(l),l&&"object"==typeof l||(l=null)),l},t.prototype.build=function(t,e){var r,n,o,a,p,u=this._options,f={},h=u.useQueryString!==!1,l={},c=u.preBuild;"function"==typeof c&&(t=c(t));for(n in t)if(i(t,n)&&null!==t[n]&&"undefined"!=typeof t[n]&&(this._mainParamsMap[n]||h)){if(o=t[n],e&&!this._checkParamValue(n,o))return null;(this._mainParamsMap[n]?f:l)[n]=o}if(e)for(a=0,p=this._requiredParams.length;p>a;++a)if(!i(f,this._requiredParams[a]))return null;return h&&(r=s.stringify(l),r&&(f[b]=r)),this._buildFn(f)},t.prototype.getData=function(){return this._options.data},t.prototype.getName=function(){return this._options.name},r.exports=t,r.exports},"./router":function(){function t(){return this instanceof t?(this._routes=[],this._routesByName={},void 0):new t}var r={},n=e("./route");return t.prototype.addRoute=function(t){var e,r;return e=new n(t),this._routes.push(e),r=e.getName(),r&&(this._routesByName[r]=e),e},t.prototype.find=function(){var t,e,r,n=[],i=this._routes;for(e=0,r=i.length;r>e;++e)t=i[e].match.apply(i[e],arguments),null!==t&&n.push([i[e],t]);return n},t.prototype.findFirst=function(){var t,e,r,n=this._routes;for(e=0,r=n.length;r>e;++e)if(t=n[e].match.apply(n[e],arguments),null!==t)return[n[e],t];return null},t.prototype.getRouteByName=function(t){return this._routesByName[t]||null},t.Route=n,r.exports=t,r.exports}}[t]()}var r=e("./router"),n=!0;t.module&&"object"==typeof module.exports&&(module.exports=r,n=!1),t.modules&&modules.define&&modules.require&&(modules.define("susanin",function(t){t(r)}),n=!1),"function"==typeof t.define&&define.amd&&(define(function(){return r}),n=!1),n&&(t.Susanin=r)}(this); \ No newline at end of file diff --git a/lib/route.js b/lib/route.js index 8eef506..8d3ba08 100644 --- a/lib/route.js +++ b/lib/route.js @@ -193,7 +193,8 @@ Route.prototype._parsePattern = function(pattern, isOptional) { i = 0, j, size, countOpened = 0, isFindingClosed = false, - length = pattern.length; + length = pattern.length, + what; while (i < length) { character = pattern.charAt(i++); @@ -220,8 +221,12 @@ Route.prototype._parsePattern = function(pattern, isOptional) { parts.push(part); for (j = 0, size = part.parts.length; j < size; ++j) { - if (part.parts[j] && part.parts[j].what === 'param') { + what = part.parts[j] && part.parts[j].what; + + if (what === 'param') { part.dependOnParams.push(part.parts[j].name); + } else if (what === 'optional') { + part.dependOnParams.push.apply(part.dependOnParams, part.parts[j].dependOnParams); } } diff --git a/test/route.build.js b/test/route.build.js index d76dfa3..9f25209 100644 --- a/test/route.build.js +++ b/test/route.build.js @@ -56,6 +56,7 @@ describe('route.build()', function() { }); assert.strictEqual(route.build(), '/opa/value'); + assert.strictEqual(route.build({ param : 'value' }), '/opa/value'); assert.strictEqual(route.build({ param : 'bar' }), '/opa/bar'); assert.strictEqual(route.build({ param : 'bar', foo1 : [ 'bar1', 'bar2' ], foo2 : [ 'bar3' ] }), '/opa/bar?foo1=bar1&foo1=bar2&foo2=bar3'); @@ -83,6 +84,7 @@ describe('route.build()', function() { }); assert.strictEqual(route.build(), '/opa'); + assert.strictEqual(route.build({ param : 'value' }), '/opa'); assert.strictEqual(route.build({ param : 'bar' }), '/opa/opapa/bar'); assert.strictEqual(route.build({ param : 'bar', foo1 : [ 'bar1', 'bar2' ], foo2 : [ 'bar3' ] }), '/opa/opapa/bar?foo1=bar1&foo1=bar2&foo2=bar3'); @@ -113,8 +115,13 @@ describe('route.build()', function() { }); assert.strictEqual(route.build(), '/opa'); + assert.strictEqual(route.build({ param1 : 'value1' }), '/opa'); + assert.strictEqual(route.build({ param2 : 'value2' }), '/opa'); assert.strictEqual(route.build({ param1 : 'bar' }), '/opa/opapa/bar'); assert.strictEqual(route.build({ param2 : 'bar' }), '/opa/bar'); + assert.strictEqual(route.build({ param1 : 'value1', param2 : 'value2' }), '/opa'); + assert.strictEqual(route.build({ param1 : 'value1', param2 : 'bar' }), '/opa/bar'); + assert.strictEqual(route.build({ param1 : 'bar', param2 : 'value2' }), '/opa/opapa/bar'); assert.strictEqual(route.build({ param1 : 'bar1', param2 : 'bar2' }), '/opa/opapa/bar1/bar2'); assert.strictEqual(route.build({ param1 : 'bar', foo1 : [ 'bar1', 'bar2' ], foo2 : [ 'bar3' ] }), '/opa/opapa/bar?foo1=bar1&foo1=bar2&foo2=bar3'); @@ -122,6 +129,29 @@ describe('route.build()', function() { done(); }); + it('/opa(/opapa/(/)) and defaults', function(done) { + var route = Route({ + pattern : '/opa(/opapa/(/))', + defaults : { + param1 : 'value1', + param2 : 'value2' + } + }); + + assert.strictEqual(route.build(), '/opa'); + assert.strictEqual(route.build({ param1 : 'value1' }), '/opa'); + assert.strictEqual(route.build({ param2 : 'value2' }), '/opa'); + assert.strictEqual(route.build({ param1 : 'bar' }), '/opa/opapa/bar'); + assert.strictEqual(route.build({ param2 : 'bar' }), '/opa/opapa/value1/bar'); + assert.strictEqual(route.build({ param1 : 'value1', param2 : 'value2' }), '/opa'); + assert.strictEqual(route.build({ param1 : 'value1', param2 : 'bar' }), '/opa/opapa/value1/bar'); + assert.strictEqual(route.build({ param1 : 'bar', param2 : 'value2' }), '/opa/opapa/bar'); + assert.strictEqual(route.build({ param1 : 'bar', foo1 : [ 'bar1', 'bar2' ], foo2 : [ 'bar3' ] }), + '/opa/opapa/bar?foo1=bar1&foo1=bar2&foo2=bar3'); + + done(); + }); + it('Unsupported characters in params name', function(done) { [ '+', '.', ',', ' ' ].forEach(function(character) { var paramName = 'param' + character,