commit 23892b662539b4aa6fec2252d0aae8bb2e01bc47 Author: elclanrs Date: Thu Oct 3 20:45:36 2013 -0400 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e8da70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.swp +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d43ec1 --- /dev/null +++ b/README.md @@ -0,0 +1,647 @@ +![Ideal Forms logo](http://i.imgur.com/F9erFXl.png) + +The best forms just got better! Ideal Forms 3 is smaller, faster, and more extensible. + +**Support:** IE9+ and all modern browsers. +**Demo:** + +### Major changes since version 2 + +Ideal Forms 3 is **not** compatible with version 2. Here's what's new: + +- New architecture, more modularity +- Custom markup +- Extensions +- Improved custom checkbox, radio and file inputs +- Improved built-in theme +- Switch to Stylus +- Drop custom select menu +- Drop support for IE8 + +## Table of Contents + +- [Setup](#setup) +- [Options](#options) +- [Markup](#markup) + - [Custom Markup](#custom-markup) +- [Adding Rules](#adding-rules) +- [Built-in Rules](#built-in-rules) +- [Methods](#methods) +- [Built-in Extensions](#built-in-extensions) + - [Dynamic Fields](#extension-dynamic-fields) + - [Steps](#extension:-steps) + - [Custom Inputs](#extension-custom-inputs) + - [Ajax](#extension-ajax) + - [Datepicker](#extension-datepicker) +- [Custom Rules](#custom-rules) +- [Custom Extensions](#custom-extensions) +- [Themes](#themes) +- [Build & Share](#build--share) + +## Setup + +- Load latest [jQuery](http://code.jquery.com/jquery-2.0.3.min.js) library +- Load `css/jquery.idealforms.css` stylesheet +- Load `js/out/jquery.idealforms.min.js` plugin +- For better IE support, replace the opening `html` tag with: + +```html + + +``` + +- Call Ideal Forms on your form: + +```javascript +$('form').idealforms({ options }); +``` + +## Options + +```javascript +defaults = { + field: '.field', + error: '.error', + iconHtml: '', + iconClass: 'icon', + invalidClass: 'invalid', + validClass: 'valid', + silentLoad: true, + onValidate: $.noop, + onSubmit: $.noop, + rules: {} +} +``` + +### field + +The field container for [custom markup](#custom-markup). + +### error + +The error container for custom markup. + +### iconHtml + +The element to use as icon. Set to `false` to disable icons. + +### iconClass + +The class for the icon element. + +### invalidClass + +The class that will be added to invalid fields. + +### validClass + +The class that will be added to valid fields. + +### silentLoad + +Initialize the form silently, otherwise focus the first invalid input. + +### onValidate(input, rule, valid) + +Callback that runs after an input attempts to validate. + +- **input:** The input being validated +- **rule:** The rule that the input is validating. +- **valid:** Boolean. Did it validate? + +### onSubmit(invalid, event) + +Callback that runs when the form is submitted. + +- **invalid:** The number of invalid fields if any. +- **event:** The submit event (prevented by default). + +## Markup + +You can get started quickly using Ideal Forms' default markup: + +```html +
+ + +
+ + + +
+ + +
+ + + +
+ + +
+ +

+ + +

+ +
+ + +
+ +

+ + + +

+ +
+ + +
+ + + +
+ + +
+ + + +
+ + + + +
+``` + +### Custom Markup + +Ideal Forms 3 has been built from scratch with flexibility in mind. The markup is no longer tied to the plugin. If the default markup doesn't work for you, you can create your own markup. Ideal Forms will look for the following: + +- **A field:** A field must contain at least a label, an input and an error. +- **A label:** The label to identify the field. +- **An input or group of inputs:** Must be a single input or multiple related inputs such as checkboxes or radios. A field _cannot_ contain inputs with different `name` attributes; this is a limitation by design. +- **An error container:** An element to hold the error. + +Then you have to tell Ideal Forms that you want to use custom markup. You can specify these options when initializing the plugin: + +```javascript +$('form').idealforms({ + field: '.myfield', // selector + error: '.myerror', // selector + validClass: 'myvalid', // class name + invalidClass: 'myinvalid' // class name +}); +``` + +## Adding Rules + +Pass an object to the `rules` option, where each key corresponds to a `name` attribute and each value is a string of rules assigned to that input. Always quote keys for consistency: + +```javascript +$('form').idealforms({ + rules: { + 'username': 'required username', + 'password': 'required password', + 'sex': 'minoption:1', + 'hobbies[]': 'minoption:1 maxoption:2', + 'options': 'select:default' + } +}); +``` + +You can also add rules after initializing the plugin: + +```javascript +$('form').idealforms('addRules', { + 'comments': 'required minmax:50:200' +}); +``` + +## Built-in Rules + +A rule must be in this format `rule:param` where `rule` is the name of the `rule` and `param` is a rule parameter, for example `minmax:10:50` will use the `minmax` rule with two arguments, `10` and `50`. + +- **required:** The field is required. Only works with text inputs. +- **digits:** Only digits. +- **number:** Must be a number. +- **username:** Must be between 4 and 32 characters long and start with a letter. You may use letters, numbers, underscores, and one dot. +- **email:** Must be a valid email. +- **pass:** Must be at least 6 characters long, and contain at least one number, one uppercase and one lowercase letter. +- **strongpass:** Must be at least 8 characters long and contain at least one uppercase and one lowercase letter and one number or special character. +- **phone:** Must be a valid US phone number. +- **zip:** Must be a valid US zip code +- **url:** Must be a valid URL. +- **range:min:max:** Must be a number between `min` and `max`. Usually combined with `number` or `digits`. +- **min:min:** Must be at least `min` characters long. +- **max:max:** Must be no more that `max` characters long. +- **minmax:min:max:** Must be between `min` and `max` characters long. +- **minoption:min:** Must have at least `min` checkboxes or radios selected. +- **maxoption:max:** Must have no more than `max` checkboxes or radios selected. +- **select:default:** Make a select required, where `default` is the value of the default option. +- **extension:ext:** Validates file inputs. You can have as many `ext` as you want. +- **equalto:name:** Must be equal to another field where `name` is the name of the field. +- **ajax:** See the built-in [Ajax Extension](#ajax). + +## Methods + +To call a method run `idealforms` on the form and pass the method and arguments: + +```javascript +$('form').idealforms('method', arg1, arg2, ...); +``` + +### .idealforms('addRules', rules) + +See [Adding Rules](#adding-rules) + +### .idealforms('get:invalid') + +Returns a jQuery collection of all invalid fields. Access the `length` to check how many fields are invalid. + +### .idealforms('focusFirstInvalid') + +Focus the first invalid field. + +### .idealforms('is:valid', name) + +Check if the input with `name` attribute is valid. + +### .idealforms('reset') + +Reset all onputs to zero. That means emptying all the values of text inputs, unchecking all checkboxes and radios, and reverting selects to their default option. + +## Built-in Extensions + +Ideal Forms 3 has been re-designed to be able to extend the core easily. Read on [Custom Extensions](#custom-extensions) to learn more. + +Ideal Forms comes with a few built-in extensions. Extensions can be disabled with the `disabledExtensions` option by passing a space separated string of extensions. + +```javascript +$('form').idealforms({ + disabledExtensions: 'dynamicFields steps customInputs ajax' +}); +``` + +### Extension: Dynamic Fields + +Dynamic Fields extends core with the following methods: + +#### .idealforms('addFields', fields) + +Add fields to the form. + +- **fields:** And object where each key corresponds to the `name` attribute. The value of the object is another object that can contain any of the following options (* are required): + +```javascript +{ + type*: 'text:subtype | file | group:subtype | select', + label*: 'Label', + value: 'value', + attrs: 'attr="value"', + after: 'name', + before: 'name', + list: [ + { value: 'value', text: 'text' } + ... + ], + rules: 'rule rule rule' +} +``` + +Text subtypes include all HMTL5 text types, such as `email`, `number`, etc... + +Group subtypes include `radio` and `checkbox`. + +If `before` or `after` are not set, the field will be added at the end of the form. + +**Example:** + +```javascript +$('form').idealforms('addFields', { + 'fruits[]': { + type: 'group:checkbox', + label: 'Fruits', + list: [ + { value: 'apple', text: 'Apple', attrs: 'checked' }, + { value: 'orange', text: 'Orange' }, + { value: 'banana', text: 'Banana' } + ], + rules: 'minoption:1 maxoption:2' + } +}); +``` + +The HTML is generated according to built-in templates. If you're using your own custom markup you may need custom templates. Ideal Forms provides a simple templating system to easy the pain. These are the default templates that you may change in the options when calling the plugin. They are listed as real HTML for convenience but you must pass a string in the options (you can get the HTML from a script tag for example): + +```html + +
+ + {field} + +
+ + + + + + + + + + + +

+ {@list} + + {/list} +

+ + + +``` + +```javascript +$('form').idealforms('templates', { + + templates: { + base: '...', + text: '...', + file: '...', + textarea: '...', + group: '...', + select: '...' + } +}); +``` + +The templating rules are: + +- **{var}:** A variable or property. +- **{@list} html {/list}:** A loop. +- **{#var}:** A loop variable (inside the loop). + +#### .idealforms('removeFields', names) + +Remove fields from the form. + +- **names:** A space separated string of `name` attributes. + +**Example:** + +```javascript +$('form').idealforms('removeFields', 'username password hobbies[]'); +``` + +#### .idealforms('toggleFields', names) + +Show or hide fields. When the fields are hidden they will be excluded from the validation. + +- **names:** A space separated string of `name` attributes. + +**Example:** + +```javascript +$('form').idealforms('toggleFields', 'username password hobbies[]'); +``` + +### Extension: Steps + +Steps let you organize your form in sections. Steps expects a container, navigation, wrapper, and at least one step. Using the default options you may build your form like so: + +```html +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+``` + +Steps adds the following options to Ideal Forms: + +```javascript +{ + stepsContainer: 'idealsteps-container', // the main container + stepsOptions: { // the options for the Steps extension + nav: '.idealsteps-nav', + navItems: 'li', + // Build nav items as "Step 1", "Step 2"... automatically + // Set to `false` to use your own custom markup + buildNavItems: true, + wrap: '.idealsteps-wrap', + step: '.idealsteps-step', + activeClass: 'idealsteps-step-active', + before: null, // runs before changing steps + after: null, // runs after changing steps + fadeSpeed: 0 + } +} +``` + +Steps provides these methods: + +#### .idealforms('goToStep', index) + +Go to the step number `index`. Indices start at `0`. + +#### .idealforms('prevStep') + +Go to the previous step. It wraps around. + +#### .idealforms('nextStep') + +Go to the next step. It wraps around. + +#### .idealforms('firstStep') + +Go to the first step. + +#### .idealforms('lastStep') + +Go to the last step. + +### Extension: Custom Inputs + +Adds custom checkboxes, radios and file inputs (yes!) seamlessly. The custom select menu has been dropped from Ideal Forms 3; it was proving to be a pain to maintain, and there are much better alternatives, such as [Select2](http://ivaynberg.github.io/select2/) if you need them. + +This extension has no additional options or methods. + +### Extension: Ajax + +Adds an `ajax` rule. First specify a URL on your input: + +```html + +``` + +Then add the rule to the field _always_ at last. + +```javascript +$('form').idealforms({ + rules: { + 'username': 'required username ajax' + } +}); +``` + +The ajax filter will read the URL and send a POST request to the server. The server side script must return a JSON encoded `true` (passes validation) or `false` (fails validation). for example in PHP: + +```php + +``` + +Now you can add the `date` rule: + +```javascript +$('form').idealforms({ + rules: { + 'event': 'date' + } +}); +``` + +The default format is `mm/dd/yyyy` for Ideal Forms and `mm/dd/yy` for the jQuery UI datepicker. Note that Ideal Forms represents years with `yyyy` not `yy`, but the formats are interchangeable. + +```javascript +$('form').idealforms({ + rules: { + 'event': 'date:yyyy-mm-dd' + } +}); + +$('.datepicker').datepicker('option', 'dateFormat', 'yy-mm-dd'); +``` + +## Custom Rules + +You can add rules by extending the global `rules` object: + +```javascript +$.extend($.idealforms.rules, { + + ruleRegex: /abc/g, + + // The rule is added as "ruleFunction:arg1:arg2" + // @param input {Node} + ruleFunction: function(input, value, arg1, arg2, ...) { + + } +}); +``` + +After you add a rule you must add an error for it, by extending the global `errors` object. Don't forget this step: + +```javascript +$.extend($.idealforms.errors, { + ruleRegex: 'Must be a valid value for this rule', + ruleFunction: 'Must be a valid value. {0}, {1}' +}); +``` + +If the rule is a function that takes rule parameters pass the parameters as `{0}`, `{1}`, etc. If you want to print all the parameters use `{*}` where the default separator is a comma but you can use your own like `{*~}` where `~` is the custom separator. + +## Custom Extensions + +```javascript +$.idealforms.addExtension({ + + name: 'extensionName', + + options: { + option: 'default' + }, + + methods: { + + // @extend + _init: function() { + + }, + + newMethod: function() { + + } + } +}); +``` + +## Themes + +## FAQ + +### How to access the Ideal Forms plugin instance + +Ideal Forms attaches an instance of itself to your form(s). To access the instance (prototype) use `data`: + +```javascript +var instance = $('form').data('idealforms'); +``` + +Now you an use methods like so: + +```javascript +instance.reset(); // reset the form +``` + +## Build & Share + +Ideal Forms 3 is built using some popular NodeJS tools. This is what you'll need to install globally: + +- [Stylus](https://github.com/learnboost/stylus) +- [UglifyJS](https://github.com/mishoo/UglifyJS2) +- [Browserify](https://github.com/substack/node-browserify) + +Then clone the repo, `cd` into the folder and run `npm install` to install dependencies. + +Finally run `watch -c sh compile.sh` to watch for changes and compile. Now you're ready to edit files and help make Ideal Forms better, or create your own fork. + +If you want to test ajax make sure to run it on your localhost. + +**Enjoy ;)** \ No newline at end of file diff --git a/ajax.php b/ajax.php new file mode 100644 index 0000000..ef8e727 --- /dev/null +++ b/ajax.php @@ -0,0 +1,9 @@ + js/out/jquery.idealforms.js +cat js/out/jquery.idealforms.js | uglifyjs --comments -m -c warnings=false -o js/out/jquery.idealforms.min.js diff --git a/css/jquery.idealforms.css b/css/jquery.idealforms.css new file mode 100644 index 0000000..ac70f56 --- /dev/null +++ b/css/jquery.idealforms.css @@ -0,0 +1,91 @@ +/* + * jQuery Ideal Forms + * @author: Cedric Ruiz + * @version: 3.0 + * @license GPL or MIT + */ +form.idealforms{zoom:1;line-height:1.5;} +form.idealforms:before,form.idealforms:after{content:"";display:table} +form.idealforms:after{clear:both} +form.idealforms *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +form.idealforms .field{position:relative;float:left;clear:both;margin:.35em 0} +form.idealforms label.main,form.idealforms .field > input,form.idealforms select,form.idealforms button,form.idealforms textarea,form.idealforms .field .group{float:left} +form.idealforms label.main{width:120px;margin-top:.55em} +form.idealforms input,form.idealforms textarea,form.idealforms select,form.idealforms button,form.idealforms .field .group{margin:0;padding:0;border:0;outline:0;width:290px;padding:.55em;border:1px solid #999;outline:0;background:#fff;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.15)} +form.idealforms input{-webkit-transition:background 0.3s ease-in-out;-moz-transition:background 0.3s ease-in-out;-o-transition:background 0.3s ease-in-out;-ms-transition:background 0.3s ease-in-out;transition:background 0.3s ease-in-out} +form.idealforms textarea{width:435px} +form.idealforms select,form.idealforms button{color:#2b2b2b;background:#eee;background:-webkit-linear-gradient(#fff, #ddd);background:-moz-linear-gradient(#fff, #ddd);background:-o-linear-gradient(#fff, #ddd);background:-ms-linear-gradient(#fff, #ddd);background:linear-gradient(#fff, #ddd);border:1px solid #aaa;border-bottom-color:#919191;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.15);box-shadow:0 1px 2px rgba(0,0,0,0.15);-webkit-border-radius:3px;border-radius:3px;padding:.55em 1.5em;} +form.idealforms select:hover,form.idealforms button:hover{background:-webkit-linear-gradient(#fff, #eaeaea);background:-moz-linear-gradient(#fff, #eaeaea);background:-o-linear-gradient(#fff, #eaeaea);background:-ms-linear-gradient(#fff, #eaeaea);background:linear-gradient(#fff, #eaeaea)} +form.idealforms select:active,form.idealforms button:active{background:#ddd} +form.idealforms button{width:auto} +form.idealforms select{padding:.55em;} +form.idealforms select:focus{border:1px solid #444} +form.idealforms input[type="file"]{padding:0} +form.idealforms .field .group{position:relative;padding:1.25em;-webkit-box-shadow:none;box-shadow:none;} +form.idealforms .field .group label{float:left;clear:both;padding:.15em 0;} +form.idealforms .field .group input,form.idealforms .field .group label{margin:0} +form.idealforms .field .group input{width:auto;margin-right:.5em;-webkit-box-shadow:none;box-shadow:none} +form.idealforms .field .group label{margin-right:1em;} +form.idealforms .field .group label:last-of-type{margin:0} +form.idealforms .field.valid input,form.idealforms .field.valid select,form.idealforms .field.valid textarea,form.idealforms .field.valid .group{color:#18445a;background:#edf7fc;border-color:#3f9dcc} +form.idealforms .field.invalid input,form.idealforms .field.invalid select,form.idealforms .field.invalid textarea,form.idealforms .field.invalid .group{color:#430e08;background:#ffeded;border-color:#cc2a18} +form.idealforms .field.valid .group,form.idealforms .field.invalid .group,form.idealforms .field.valid textarea,form.idealforms .field.invalid textarea,form.idealforms .field.valid select,form.idealforms .field.invalid select{color:inherit;background:none} +form.idealforms .field.valid select,form.idealforms .field.invalid select{background:-webkit-linear-gradient(#fff, #ddd);background:-moz-linear-gradient(#fff, #ddd);background:-o-linear-gradient(#fff, #ddd);background:-ms-linear-gradient(#fff, #ddd);background:linear-gradient(#fff, #ddd)} +form.idealforms .field .icon{position:absolute;width:16px;height:16px;top:50%;left:100%;margin-top:-8px;margin-left:8px;background:url("../img/validation.png") -16px 0 no-repeat;cursor:pointer} +form.idealforms .field.invalid .icon{background-position:-16px 0} +form.idealforms .field.valid .icon{background-position:0 0;cursor:default} +form.idealforms .field.invalid .group input,form.idealforms .field.valid .group input{border:0;outline:0;-webkit-box-shadow:none;box-shadow:none} +form.idealforms .field.ajax input{color:#463a09;background:#faf9e8;border-color:#cfaa19} +form.idealforms .field.ajax .icon{background:url("../img/loading.gif")} +form.idealforms .error{display:none;position:absolute;z-index:1;left:100%;top:50%;padding:1em 1.5em;width:193.33333333333334px;margin-left:40px;background:#285d85;background:-webkit-linear-gradient(#285d85, #3070a0);background:-moz-linear-gradient(#285d85, #3070a0);background:-o-linear-gradient(#285d85, #3070a0);background:-ms-linear-gradient(#285d85, #3070a0);background:linear-gradient(#285d85, #3070a0);color:#fff;font-size:85%;font-weight:bold;text-shadow:0 1px 0 rgba(0,0,0,0.3);line-height:1.35;border:1px solid #1c425e;-webkit-border-radius:0 3px 3px 3px;border-radius:0 3px 3px 3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.15);box-shadow:0 1px 1px rgba(0,0,0,0.15);} +form.idealforms .error:after{content:"";position:absolute;z-index:-1;top:-1px;left:-.7em;border-width:.7em;border-style:solid;border-color:transparent;border-top-color:#285d85} +form.idealforms .idealforms-field-checkbox .icon,form.idealforms .idealforms-field-radio .icon,form.idealforms .idealforms-field-textarea .icon{top:8px;margin-top:0} +form.idealforms .idealforms-field-checkbox .error,form.idealforms .idealforms-field-radio .error,form.idealforms .idealforms-field-textarea .error{top:20px} +.idealsteps-step{zoom:1} +.idealsteps-step:before,.idealsteps-step:after{content:"";display:table} +.idealsteps-step:after{clear:both} +.idealsteps-nav{color:#2b2b2b;background:#eee;background:-webkit-linear-gradient(#fff, #ddd);background:-moz-linear-gradient(#fff, #ddd);background:-o-linear-gradient(#fff, #ddd);background:-ms-linear-gradient(#fff, #ddd);background:linear-gradient(#fff, #ddd);border:1px solid #aaa;border-bottom-color:#919191;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.15);box-shadow:0 1px 2px rgba(0,0,0,0.15);-webkit-border-radius:3px;border-radius:3px;overflow:hidden;margin-bottom:2em;} +.idealsteps-nav ul{margin:0;padding:0;border:0;outline:0;list-style:none} +.idealsteps-nav li{float:left} +.idealsteps-nav a{position:relative;float:left;padding:0 1.5em 0 2.75em;height:3.5em;line-height:3.5em;text-decoration:none;color:#5e5e5e;background:#ddd;-webkit-transition:padding 0.2s ease-in-out;-moz-transition:padding 0.2s ease-in-out;-o-transition:padding 0.2s ease-in-out;-ms-transition:padding 0.2s ease-in-out;transition:padding 0.2s ease-in-out;} +.idealsteps-nav a:focus{outline:0} +.idealsteps-nav a:hover{background:#eaeaea;} +.idealsteps-nav a:hover:after{border-left-color:#eaeaea} +.idealsteps-nav a:after,.idealsteps-nav a:before{content:"";position:absolute;z-index:1;top:0;right:-2em;margin-right:0;margin-top:-.125em;border-width:2em 1em;border-style:solid;border-color:transparent;border-left-color:#ddd} +.idealsteps-nav a:before{margin-right:-1px;border-left-color:#aaa} +.idealsteps-nav li:first-child a{padding-left:1.75em} +.idealsteps-nav li.idealsteps-step-active a{padding-right:3.5em;background:#fff;color:#3f9dcc;font-weight:bold;} +.idealsteps-nav li.idealsteps-step-active a:after{border-left-color:#fff} +.idealsteps-nav li.idealsteps-step-active .counter{opacity:1;-ms-filter:none;filter:none} +.idealsteps-nav .counter{opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);position:absolute;top:50%;right:1em;height:20px;width:20px;margin-top:-.75em;line-height:20px !important;text-align:center;line-height:1;color:#cc2a18;border:1px solid #cc2a18;-webkit-border-radius:10em;border-radius:10em;-webkit-transition:opacity 0.2s ease-in-out;-moz-transition:opacity 0.2s ease-in-out;-o-transition:opacity 0.2s ease-in-out;-ms-transition:opacity 0.2s ease-in-out;transition:opacity 0.2s ease-in-out;} +.idealsteps-nav .counter.zero{color:#3f9dcc;border-color:#3f9dcc} +form.idealforms .ideal-radiocheck-label{cursor:pointer;margin:.15em 0 !important;} +form.idealforms .ideal-radiocheck-label input{float:left} +form.idealforms .ideal-check,form.idealforms .ideal-radio{float:left;margin-right:10px !important;width:20px;height:20px;background:url("../img/radiocheck.png") 0 0} +form.idealforms .ideal-check.focus{background-position:-20px 0} +form.idealforms .ideal-check.checked{background-position:-40px 0} +form.idealforms .ideal-check.checked.focus{background-position:-60px 0} +form.idealforms .ideal-radio{background-position:0 bottom} +form.idealforms .ideal-radio.focus{background-position:-20px bottom} +form.idealforms .ideal-radio.checked{background-position:-40px bottom} +form.idealforms .ideal-radio.checked.focus{background-position:-60px bottom} +form.idealforms .ideal-file-wrap{float:left} +form.idealforms .ideal-file-filename{float:left;width:204px;height:100%;-webkit-border-radius:0;border-radius:0;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;} +form.idealforms .ideal-file-upload{color:#2b2b2b;background:#eee;background:-webkit-linear-gradient(#fff, #ddd);background:-moz-linear-gradient(#fff, #ddd);background:-o-linear-gradient(#fff, #ddd);background:-ms-linear-gradient(#fff, #ddd);background:linear-gradient(#fff, #ddd);border:1px solid #aaa;border-bottom-color:#919191;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.15);box-shadow:0 1px 2px rgba(0,0,0,0.15);-webkit-border-radius:3px;border-radius:3px;padding:.55em 1.5em;overflow:visible;position:relative;float:right;left:-1px;width:87px;padding-left:0;padding-right:0;text-align:center;-webkit-border-radius:0;border-radius:0;-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;} +form.idealforms .ideal-file-upload:hover{background:-webkit-linear-gradient(#fff, #eaeaea);background:-moz-linear-gradient(#fff, #eaeaea);background:-o-linear-gradient(#fff, #eaeaea);background:-ms-linear-gradient(#fff, #eaeaea);background:linear-gradient(#fff, #eaeaea)} +form.idealforms .ideal-file-upload:active{background:#ddd} +.ie9 .ideal-file-upload{line-height:1.15} +.idealforms input.datepicker.open{border-bottom-color:transparent;-webkit-border-radius:0;border-radius:0;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;border-top-right-radius:3px;} +.ui-datepicker{display:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:290px;margin-top:-2px;padding:.75em;background:#fff;border:1px solid #999;-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.2);box-shadow:0 1px 2px rgba(0,0,0,0.2)} +.ui-datepicker-header{position:relative;padding:.2em 0;margin-bottom:.75em;font-weight:bold;} +.ui-datepicker-header .ui-datepicker-title{text-align:center} +.ui-datepicker-header .ui-datepicker-prev,.ui-datepicker-header .ui-datepicker-next{text-indent:-9999px;width:16px;height:16px;position:absolute;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background:url("../img/datepicker.png") 0 0;} +.ui-datepicker-header .ui-datepicker-prev:active,.ui-datepicker-header .ui-datepicker-next:active{margin-top:1px} +.ui-datepicker-header .ui-datepicker-next{background-position:-16px 0} +.ui-datepicker-header .ui-datepicker-prev{left:8px} +.ui-datepicker-header .ui-datepicker-next{right:8px} +.ui-datepicker-calendar{width:100%;border-collapse:collapse;table-layout:fixed;} +.ui-datepicker-calendar td{padding:.25em 0;text-align:center} +.ui-datepicker-calendar a{display:block;text-decoration:none;color:#808080;} +.ui-datepicker-calendar a:hover{color:#3f9dcc;font-weight:bold} +.ui-datepicker-calendar .ui-datepicker-today a{margin:0 .25em;background:#eee;-webkit-border-radius:3px;border-radius:3px} diff --git a/img/datepicker.png b/img/datepicker.png new file mode 100644 index 0000000..34f944e Binary files /dev/null and b/img/datepicker.png differ diff --git a/img/loading.gif b/img/loading.gif new file mode 100644 index 0000000..e40f19a Binary files /dev/null and b/img/loading.gif differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000..a977cb9 Binary files /dev/null and b/img/logo.png differ diff --git a/img/logo.svg b/img/logo.svg new file mode 100644 index 0000000..8d46649 --- /dev/null +++ b/img/logo.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + IDEAL FORMS + + + 3 + + + diff --git a/img/radiocheck.png b/img/radiocheck.png new file mode 100644 index 0000000..e950165 Binary files /dev/null and b/img/radiocheck.png differ diff --git a/img/validation.png b/img/validation.png new file mode 100644 index 0000000..9019634 Binary files /dev/null and b/img/validation.png differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..03b8676 --- /dev/null +++ b/index.php @@ -0,0 +1,208 @@ + + + + + + + + + + +Ideal Forms 3 + + + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ +

+ + +

+ +
+ +
+ +

+ + + + + +

+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ +
+ +
+ + +
+ +
+ +
+ + + + + + + + diff --git a/js/errors.js b/js/errors.js new file mode 100644 index 0000000..0fef924 --- /dev/null +++ b/js/errors.js @@ -0,0 +1,28 @@ +/** + * Errors + */ +module.exports = { + + required: 'This field is required', + digits: 'Must be only digits', + name: 'Must be at least 3 characters long and must only contain letters', + email: 'Must be a valid email', + username: 'Must be at between 4 and 32 characters long and start with a letter. You may use letters, numbers, underscores, and one dot', + pass: 'Must be at least 6 characters long, and contain at least one number, one uppercase and one lowercase letter', + strongpass: 'Must be at least 8 characters long and contain at least one uppercase and one lowercase letter and one number or special character', + phone: 'Must be a valid phone number', + zip: 'Must be a valid zip code', + url: 'Must be a valid URL', + number: 'Must be a number', + range: 'Must be a number between {0} and {1}', + min: 'Must be at least {0} characters long', + max: 'Must be under {0} characters', + minoption: 'Select at least {0} options', + maxoption: 'Select no more than {0} options', + minmax: 'Must be between {0} and {1} characters long', + select: 'Select an option', + extension: 'File(s) must have a valid extension ({*})', + equalto: 'Must have the same value as the "{0}" field', + date: 'Must be a valid date {0}' + +}; diff --git a/js/extensions/ajax/ajax.ext.js b/js/extensions/ajax/ajax.ext.js new file mode 100644 index 0000000..db7ec3f --- /dev/null +++ b/js/extensions/ajax/ajax.ext.js @@ -0,0 +1,61 @@ +module.exports = { + + name: 'idealAjax', + + methods: { + + // @extend + _init: function() { + + $.extend($.idealforms, { _requests: {} }); + + $.extend($.idealforms.errors, { + ajax: 'Loading...' + }); + + $.extend($.idealforms.rules, { + + ajax: function(input) { + + var self = this + , $field = this._getField(input) + , url = $(input).data('idealforms-ajax') + , userError = $.idealforms._getKey('errors.'+ input.name +'.ajaxError', self.opts) + , requests = $.idealforms._requests + , data = {}; + + data[input.name] = input.value; + + $field.addClass('ajax'); + + if (requests[input.name]) requests[input.name].abort(); + + requests[input.name] = $.post(url, data, function(resp) { + + if (resp === true) { + $field.data('idealforms-valid', true); + self._handleError(input); + self._handleStyle(input); + } else { + self._handleError(input, userError); + } + + $field.removeClass('ajax'); + + }, 'json'); + + return false; + } + }); + }, + + // @extend + _validate: function(input, rule) { + if (rule != 'ajax' && $.idealforms._requests[input.name]) { + $.idealforms._requests[input.name].abort(); + this._getField(input).removeClass('ajax'); + } + } + + } +}; diff --git a/js/extensions/custom-inputs/custom-inputs.ext.js b/js/extensions/custom-inputs/custom-inputs.ext.js new file mode 100644 index 0000000..4d67967 --- /dev/null +++ b/js/extensions/custom-inputs/custom-inputs.ext.js @@ -0,0 +1,25 @@ +require('./idealfile'); +require('./idealradiocheck'); + +module.exports = { + + name: 'customInputs', + + methods: { + + // @extend + _init: function() { + this._buildCustomInputs(); + }, + + addFields: function() { + this._buildCustomInputs(); + }, + + _buildCustomInputs: function() { + this.$form.find(':file').idealfile(); + this.$form.find(':checkbox, :radio').idealradiocheck(); + } + + } +}; diff --git a/js/extensions/custom-inputs/idealfile.js b/js/extensions/custom-inputs/idealfile.js new file mode 100644 index 0000000..0103436 --- /dev/null +++ b/js/extensions/custom-inputs/idealfile.js @@ -0,0 +1,97 @@ +/** + * Ideal File + */ +(function($, win, doc, undefined) { + + // Browser supports HTML5 multiple file? + var multipleSupport = typeof $('')[0].multiple !== 'undefined' + , isIE = /msie/i.test(navigator.userAgent) + , plugin = {}; + + plugin.name = 'idealfile'; + + plugin.methods = { + + _init: function() { + + var $file = $(this.el).addClass('ideal-file') // the original file input + , $wrap = $('
') + , $input = $('') + // Button that will be used in non-IE browsers + , $button = $('') + // Hack for IE + , $label = $(''); + + // Hide by shifting to the left so we + // can still trigger events + $file.css({ + position: 'absolute', + left: '-9999px' + }); + + $wrap.append($input, (isIE ? $label : $button)).insertAfter($file); + + // Prevent focus + $file.attr('tabIndex', -1); + $button.attr('tabIndex', -1); + + $button.click(function () { + $file.focus().click(); // Open dialog + }); + + $file.change(function () { + + var files = [] + , fileArr, filename; + + // If multiple is supported then extract + // all filenames from the file array + if (multipleSupport) { + fileArr = $file[0].files; + for (var i = 0, len = fileArr.length; i < len; i++) { + files.push(fileArr[i].name); + } + filename = files.join(', '); + + // If not supported then just take the value + // and remove the path to just show the filename + } else { + filename = $file.val().split('\\').pop(); + } + + $input .val(filename).attr('title', filename); + + }); + + $input.on({ + blur: function () { + $file.trigger('blur'); + }, + keydown: function (e) { + if (e.which === 13) { // Enter + if (!isIE) $file.trigger('click'); + $(this).closest('form').one('keydown', function(e) { + if (e.which === 13) e.preventDefault(); + }); + } else if (e.which === 8 || e.which === 46) { // Backspace & Del + // In IE the value is read-only + // with this trick we remove the old input and add + // a clean clone with all the original events attached + if (isIE) $file.replaceWith($file = $file.clone(true)); + $file.val('').trigger('change'); + $input.val(''); + } else if (e.which === 9) { // TAB + return; + } else { // All other keys + return false; + } + } + }); + + } + + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); diff --git a/js/extensions/custom-inputs/idealradiocheck.js b/js/extensions/custom-inputs/idealradiocheck.js new file mode 100644 index 0000000..ad7775f --- /dev/null +++ b/js/extensions/custom-inputs/idealradiocheck.js @@ -0,0 +1,48 @@ +/* + * idealRadioCheck: jQuery plguin for checkbox and radio replacement + * Usage: $('input[type=checkbox], input[type=radio]').idealRadioCheck() + */ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealradiocheck'; + + plugin.methods = { + + _init: function() { + + var $input = $(this.el); + var $span = $(''); + + $span.addClass('ideal-'+ ($input.is(':checkbox') ? 'check' : 'radio')); + $input.is(':checked') && $span.addClass('checked'); // init + $span.insertAfter($input); + + $input.parent('label') + .addClass('ideal-radiocheck-label') + .attr('onclick', ''); // Fix clicking label in iOS + + $input.css({ position: 'absolute', left: '-9999px' }); // hide by shifting left + + // Events + $input.on({ + change: function() { + var $input = $(this); + if ( $input.is('input[type="radio"]') ) { + $input.parent().siblings('label').find('.ideal-radio').removeClass('checked'); + } + $span.toggleClass('checked', $input.is(':checked')); + }, + focus: function() { $span.addClass('focus') }, + blur: function() { $span.removeClass('focus') }, + click: function() { $(this).trigger('focus') } + }); + } + + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); + diff --git a/js/extensions/datepicker/datepicker.ext.js b/js/extensions/datepicker/datepicker.ext.js new file mode 100644 index 0000000..4716702 --- /dev/null +++ b/js/extensions/datepicker/datepicker.ext.js @@ -0,0 +1,52 @@ +module.exports = { + + name: 'datepicker', + + methods: { + + // @extend + _init: function() { + this._buildDatepicker(); + }, + + _buildDatepicker: function() { + + var $datepicker = this.$form.find('input.datepicker'); + + // Always show datepicker below the input + if (jQuery.ui) { + $.datepicker._checkOffset = function(a,b,c){ return b }; + } + + if (jQuery.ui && $datepicker.length) { + + $datepicker.each(function() { + + $(this).datepicker({ + beforeShow: function(input) { + $(input).addClass('open'); + }, + onChangeMonthYear: function() { + // Hack to fix IE9 not resizing + var $this = $(this) + , width = $this.outerWidth(); // cache first! + setTimeout(function() { + $this.datepicker('widget').css('width', width); + }, 1); + }, + onClose: function() { + $(this).removeClass('open'); + } + }); + }); + + // Adjust width + $datepicker.on('focus keyup', function() { + var t = $(this), w = t.outerWidth(); + t.datepicker('widget').css('width', w); + }); + } + } + + } +}; diff --git a/js/extensions/dynamic-fields/dynamic-fields.ext.js b/js/extensions/dynamic-fields/dynamic-fields.ext.js new file mode 100644 index 0000000..24e2d5e --- /dev/null +++ b/js/extensions/dynamic-fields/dynamic-fields.ext.js @@ -0,0 +1,125 @@ +function template(html, data) { + + var loop = /\{@([^}]+)\}(.+?)\{\/\1\}/g + , loopVariable = /\{#([^}]+)\}/g + , variable = /\{([^}]+)\}/g; + + return html + .replace(loop, function(_, key, list) { + return $.map(data[key], function(item) { + return list.replace(loopVariable, function(_, k) { + return item[k]; + }); + }).join(''); + }) + .replace(variable, function(_, key) { + return data[key] || ''; + }); +} + +module.exports = { + + name: 'dynamicFields', + + options: { + + templates: { + + base:'\ +
\ + \ + {field}\ + \ +
\ + ', + + text: '', + + file: '', + + textarea: '', + + group: '\ +

\ + {@list}\ + \ + {/list}\ +

\ + ', + + select: '\ + \ + ' + } + }, + + methods: { + + addFields: function(fields) { + + var self = this; + + $.each(fields, function(name, field) { + + var typeArray = field.type.split(':') + , rules = {}; + + field.name = name; + field.type = typeArray[0]; + if (typeArray[1]) field.subtype = typeArray[1]; + + var html = template(self.opts.templates.base, { + label: field.label, + field: template(self.opts.templates[field.type], field) + }); + + if (field.after || field.before) { + self.$form.find('[name='+ (field.after || field.before) +']').each(function() { + self._getField(this)[field.after ? 'after' : 'before'](html); + }); + } else { + self.$form.find(self.opts.field).last().after(html); + } + + if (field.rules) { + rules[name] = field.rules; + self.addRules(rules); + } + }); + + this._inject('addFields'); + }, + + removeFields: function(names) { + + var self = this; + + $.each(names.split(' '), function(i, name) { + var $field = self._getField($('[name="'+ name +'"]')); + self.$fields = self.$fields.filter(function() { + return ! $(this).is($field); + }); + $field.remove(); + }); + + this._inject('removeFields'); + }, + + toggleFields: function(names) { + + var self = this; + + $.each(names.split(' '), function(i, name) { + var $field = self._getField($('[name="'+ name +'"]')); + $field.data('idealforms-valid', $field.is(':visible')).toggle(); + }); + + this._inject('toggleFields'); + } + + } +}; diff --git a/js/extensions/steps/idealsteps.js b/js/extensions/steps/idealsteps.js new file mode 100644 index 0000000..32baa15 --- /dev/null +++ b/js/extensions/steps/idealsteps.js @@ -0,0 +1,104 @@ +/*! + * Ideal Steps +*/ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealsteps'; + + plugin.defaults = { + nav: '.idealsteps-nav', + navItems: 'li', + buildNavItems: true, + wrap: '.idealsteps-wrap', + step: '.idealsteps-step', + activeClass: 'idealsteps-step-active', + before: null, + after: null, + fadeSpeed: 0 + }; + + plugin.methods = { + + _init: function() { + + var self = this, + active = this.opts.activeClass; + + this.$el = $(this.el); + + this.$nav = this.$el.find(this.opts.nav); + this.$navItems = this.$nav.find(this.opts.navItems); + + this.$wrap = this.$el.find(this.opts.wrap); + this.$steps = this.$wrap.find(this.opts.step); + + if (this.opts.buildNavItems) this._buildNavItems(); + + this.$steps.hide().first().show(); + this.$navItems.removeClass(active).first().addClass(active); + + this.$navItems.click(function() { + self.go(self.$navItems.index(this)); + }); + }, + + _buildNavItems: function() { + + var self = this, + isCustom = typeof this.opts.buildNavItems == 'function', + item = function(val){ return '
  • '+ val +'
  • '; }, + items; + + items = isCustom ? + this.$steps.map(function(i){ return item(self.opts.buildNavItems.call(self, i)) }).get() : + this.$steps.map(function(i){ return item(++i); }).get(); + + this.$navItems = $(items.join('')); + + this.$nav.append($('
      ').append(this.$navItems)); + }, + + _getCurIdx: function() { + return this.$steps.index(this.$steps.filter(':visible')); + }, + + go: function(idx) { + + var active = this.opts.activeClass, + fadeSpeed = this.opts.fadeSpeed; + + if (typeof idx == 'function') idx = idx.call(this, this._getCurIdx()); + + if (idx >= this.$steps.length) idx = 0; + if (idx < 0) idx = this.$steps.length-1; + + if (this.opts.before) this.opts.before.call(this, idx); + + this.$navItems.removeClass(active).eq(idx).addClass(active); + this.$steps.fadeOut(fadeSpeed).eq(idx).fadeIn(fadeSpeed); + + if (this.opts.after) this.opts.after.call(this, idx); + }, + + prev: function() { + this.go(this._getCurIdx() - 1); + }, + + next: function() { + this.go(this._getCurIdx() + 1); + }, + + first: function() { + this.go(0); + }, + + last: function() { + this.go(this.$steps.length-1); + } + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); diff --git a/js/extensions/steps/steps.ext.js b/js/extensions/steps/steps.ext.js new file mode 100644 index 0000000..d3f3475 --- /dev/null +++ b/js/extensions/steps/steps.ext.js @@ -0,0 +1,111 @@ +require('./idealsteps'); + +module.exports = { + + name: 'steps', + + options: { + stepsContainer: '.idealsteps-container', + stepsOptions: {} + }, + + methods: { + + // @extend + _init: function() { + this._buildSteps(); + }, + + // @extend + _validate: function() { + + var self = this; + + this._updateSteps(); + + if ($.idealforms.hasExtension('idealAjax')) { + $.each($.idealforms._requests, function(key, request) { + request.done(function(){ self._updateSteps() }); + }); + } + }, + + // @extend + focusFirstInvalid: function(firstInvalid) { + + var self = this; + + this.$stepsContainer.idealsteps('go', function() { + return this.$steps.filter(function() { + return $(this).find(firstInvalid).length; + }).index(); + }); + }, + + _buildSteps: function() { + + var self = this, options + , hasRules = ! $.isEmptyObject(this.opts.rules) + , counter = hasRules + ? '' + : '0'; + + options = $.extend({}, { + buildNavItems: function(i){ return 'Step '+ (i+1) + counter } + }, this.opts.stepsOptions); + + this.$stepsContainer = this.$form.closest(this.opts.stepsContainer).idealsteps(options); + }, + + _updateSteps: function() { + + var self = this; + + this.$stepsContainer.idealsteps('_inject', function() { + + var idealsteps = this; + + this.$navItems.each(function(i) { + var invalid = idealsteps.$steps.eq(i).find(self.getInvalid()).length; + $(this).find('span').text(invalid).toggleClass('zero', ! invalid); + }); + }); + }, + + // @extend + addRules: function() { + this.firstStep(); + }, + + // @extend + toggleFields: function() { + this._updateSteps(); + }, + + // @extend + removeFields: function() { + this._updateSteps(); + }, + + goToStep: function(idx) { + this.$stepsContainer.idealsteps('go', idx); + }, + + prevStep: function() { + this.$stepsContainer.idealsteps('prev'); + }, + + nextStep: function() { + this.$stepsContainer.idealsteps('next'); + }, + + firstStep: function() { + this.$stepsContainer.idealsteps('first'); + }, + + lastStep: function() { + this.$stepsContainer.idealsteps('last'); + } + } + +}; diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..9cc04d9 --- /dev/null +++ b/js/main.js @@ -0,0 +1,61 @@ +/*! + * jQuery Ideal Forms + * @author: Cedric Ruiz + * @version: 3.0 + * @license GPL or MIT + */ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealforms'; + + plugin.defaults = { + field: '.field', + error: '.error', + iconHtml: '', + iconClass: 'icon', + invalidClass: 'invalid', + validClass: 'valid', + silentLoad: true, + onValidate: $.noop, + onSubmit: $.noop + }; + + plugin.global = { + + _format: function(str) { + var args = [].slice.call(arguments, 1); + return str.replace(/\{(\d)\}/g, function(_, match) { + return args[+match] || ''; + }).replace(/\{\*([^*}]*)\}/g, function(_, sep) { + return args.join(sep || ', '); + }); + }, + + _getKey: function(key, obj) { + return key.split('.').reduce(function(a,b) { + return a && a[b]; + }, obj); + }, + + ruleSeparator: ' ', + argSeparator: ':', + + rules: require('./rules'), + errors: require('./errors'), + + extensions: [ + require('./extensions/dynamic-fields/dynamic-fields.ext'), + require('./extensions/ajax/ajax.ext'), + require('./extensions/steps/steps.ext'), + require('./extensions/custom-inputs/custom-inputs.ext'), + require('./extensions/datepicker/datepicker.ext') + ] + }; + + plugin.methods = $.extend({}, require('./private'), require('./public')); + + require('./plugin')(plugin); + +}(jQuery, window, document)); diff --git a/js/out/jquery.idealforms.js b/js/out/jquery.idealforms.js new file mode 100644 index 0000000..ad83374 --- /dev/null +++ b/js/out/jquery.idealforms.js @@ -0,0 +1,1209 @@ +;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o')[0].multiple !== 'undefined' + , isIE = /msie/i.test(navigator.userAgent) + , plugin = {}; + + plugin.name = 'idealfile'; + + plugin.methods = { + + _init: function() { + + var $file = $(this.el).addClass('ideal-file') // the original file input + , $wrap = $('
      ') + , $input = $('') + // Button that will be used in non-IE browsers + , $button = $('') + // Hack for IE + , $label = $(''); + + // Hide by shifting to the left so we + // can still trigger events + $file.css({ + position: 'absolute', + left: '-9999px' + }); + + $wrap.append($input, (isIE ? $label : $button)).insertAfter($file); + + // Prevent focus + $file.attr('tabIndex', -1); + $button.attr('tabIndex', -1); + + $button.click(function () { + $file.focus().click(); // Open dialog + }); + + $file.change(function () { + + var files = [] + , fileArr, filename; + + // If multiple is supported then extract + // all filenames from the file array + if (multipleSupport) { + fileArr = $file[0].files; + for (var i = 0, len = fileArr.length; i < len; i++) { + files.push(fileArr[i].name); + } + filename = files.join(', '); + + // If not supported then just take the value + // and remove the path to just show the filename + } else { + filename = $file.val().split('\\').pop(); + } + + $input .val(filename).attr('title', filename); + + }); + + $input.on({ + blur: function () { + $file.trigger('blur'); + }, + keydown: function (e) { + if (e.which === 13) { // Enter + if (!isIE) $file.trigger('click'); + $(this).closest('form').one('keydown', function(e) { + if (e.which === 13) e.preventDefault(); + }); + } else if (e.which === 8 || e.which === 46) { // Backspace & Del + // In IE the value is read-only + // with this trick we remove the old input and add + // a clean clone with all the original events attached + if (isIE) $file.replaceWith($file = $file.clone(true)); + $file.val('').trigger('change'); + $input.val(''); + } else if (e.which === 9) { // TAB + return; + } else { // All other keys + return false; + } + } + }); + + } + + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); + +},{"../../plugin":11}],5:[function(require,module,exports){ +/* + * idealRadioCheck: jQuery plguin for checkbox and radio replacement + * Usage: $('input[type=checkbox], input[type=radio]').idealRadioCheck() + */ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealradiocheck'; + + plugin.methods = { + + _init: function() { + + var $input = $(this.el); + var $span = $(''); + + $span.addClass('ideal-'+ ($input.is(':checkbox') ? 'check' : 'radio')); + $input.is(':checked') && $span.addClass('checked'); // init + $span.insertAfter($input); + + $input.parent('label') + .addClass('ideal-radiocheck-label') + .attr('onclick', ''); // Fix clicking label in iOS + + $input.css({ position: 'absolute', left: '-9999px' }); // hide by shifting left + + // Events + $input.on({ + change: function() { + var $input = $(this); + if ( $input.is('input[type="radio"]') ) { + $input.parent().siblings('label').find('.ideal-radio').removeClass('checked'); + } + $span.toggleClass('checked', $input.is(':checked')); + }, + focus: function() { $span.addClass('focus') }, + blur: function() { $span.removeClass('focus') }, + click: function() { $(this).trigger('focus') } + }); + } + + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); + + +},{"../../plugin":11}],6:[function(require,module,exports){ +module.exports = { + + name: 'datepicker', + + methods: { + + // @extend + _init: function() { + this._buildDatepicker(); + }, + + _buildDatepicker: function() { + + var $datepicker = this.$form.find('input.datepicker'); + + // Always show datepicker below the input + if (jQuery.ui) { + $.datepicker._checkOffset = function(a,b,c){ return b }; + } + + if (jQuery.ui && $datepicker.length) { + + $datepicker.each(function() { + + $(this).datepicker({ + beforeShow: function(input) { + $(input).addClass('open'); + }, + onChangeMonthYear: function() { + // Hack to fix IE9 not resizing + var $this = $(this) + , width = $this.outerWidth(); // cache first! + setTimeout(function() { + $this.datepicker('widget').css('width', width); + }, 1); + }, + onClose: function() { + $(this).removeClass('open'); + } + }); + }); + + // Adjust width + $datepicker.on('focus keyup', function() { + var t = $(this), w = t.outerWidth(); + t.datepicker('widget').css('width', w); + }); + } + } + + } +}; + +},{}],7:[function(require,module,exports){ +function template(html, data) { + + var loop = /\{@([^}]+)\}(.+?)\{\/\1\}/g + , loopVariable = /\{#([^}]+)\}/g + , variable = /\{([^}]+)\}/g; + + return html + .replace(loop, function(_, key, list) { + return $.map(data[key], function(item) { + return list.replace(loopVariable, function(_, k) { + return item[k]; + }); + }).join(''); + }) + .replace(variable, function(_, key) { + return data[key] || ''; + }); +} + +module.exports = { + + name: 'dynamicFields', + + options: { + + templates: { + + base:'\ +
      \ + \ + {field}\ + \ +
      \ + ', + + text: '', + + file: '', + + textarea: '', + + group: '\ +

      \ + {@list}\ + \ + {/list}\ +

      \ + ', + + select: '\ + \ + ' + } + }, + + methods: { + + addFields: function(fields) { + + var self = this; + + $.each(fields, function(name, field) { + + var typeArray = field.type.split(':') + , rules = {}; + + field.name = name; + field.type = typeArray[0]; + if (typeArray[1]) field.subtype = typeArray[1]; + + var html = template(self.opts.templates.base, { + label: field.label, + field: template(self.opts.templates[field.type], field) + }); + + if (field.after || field.before) { + self.$form.find('[name='+ (field.after || field.before) +']').each(function() { + self._getField(this)[field.after ? 'after' : 'before'](html); + }); + } else { + self.$form.find(self.opts.field).last().after(html); + } + + if (field.rules) { + rules[name] = field.rules; + self.addRules(rules); + } + }); + + this._inject('addFields'); + }, + + removeFields: function(names) { + + var self = this; + + $.each(names.split(' '), function(i, name) { + var $field = self._getField($('[name="'+ name +'"]')); + self.$fields = self.$fields.filter(function() { + return ! $(this).is($field); + }); + $field.remove(); + }); + + this._inject('removeFields'); + }, + + toggleFields: function(names) { + + var self = this; + + $.each(names.split(' '), function(i, name) { + var $field = self._getField($('[name="'+ name +'"]')); + $field.data('idealforms-valid', $field.is(':visible')).toggle(); + }); + + this._inject('toggleFields'); + } + + } +}; + +},{}],8:[function(require,module,exports){ +/*! + * Ideal Steps +*/ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealsteps'; + + plugin.defaults = { + nav: '.idealsteps-nav', + navItems: 'li', + buildNavItems: true, + wrap: '.idealsteps-wrap', + step: '.idealsteps-step', + activeClass: 'idealsteps-step-active', + before: null, + after: null, + fadeSpeed: 0 + }; + + plugin.methods = { + + _init: function() { + + var self = this, + active = this.opts.activeClass; + + this.$el = $(this.el); + + this.$nav = this.$el.find(this.opts.nav); + this.$navItems = this.$nav.find(this.opts.navItems); + + this.$wrap = this.$el.find(this.opts.wrap); + this.$steps = this.$wrap.find(this.opts.step); + + if (this.opts.buildNavItems) this._buildNavItems(); + + this.$steps.hide().first().show(); + this.$navItems.removeClass(active).first().addClass(active); + + this.$navItems.click(function() { + self.go(self.$navItems.index(this)); + }); + }, + + _buildNavItems: function() { + + var self = this, + isCustom = typeof this.opts.buildNavItems == 'function', + item = function(val){ return '
    • '+ val +'
    • '; }, + items; + + items = isCustom ? + this.$steps.map(function(i){ return item(self.opts.buildNavItems.call(self, i)) }).get() : + this.$steps.map(function(i){ return item(++i); }).get(); + + this.$navItems = $(items.join('')); + + this.$nav.append($('
        ').append(this.$navItems)); + }, + + _getCurIdx: function() { + return this.$steps.index(this.$steps.filter(':visible')); + }, + + go: function(idx) { + + var active = this.opts.activeClass, + fadeSpeed = this.opts.fadeSpeed; + + if (typeof idx == 'function') idx = idx.call(this, this._getCurIdx()); + + if (idx >= this.$steps.length) idx = 0; + if (idx < 0) idx = this.$steps.length-1; + + if (this.opts.before) this.opts.before.call(this, idx); + + this.$navItems.removeClass(active).eq(idx).addClass(active); + this.$steps.fadeOut(fadeSpeed).eq(idx).fadeIn(fadeSpeed); + + if (this.opts.after) this.opts.after.call(this, idx); + }, + + prev: function() { + this.go(this._getCurIdx() - 1); + }, + + next: function() { + this.go(this._getCurIdx() + 1); + }, + + first: function() { + this.go(0); + }, + + last: function() { + this.go(this.$steps.length-1); + } + }; + + require('../../plugin')(plugin); + +}(jQuery, window, document)); + +},{"../../plugin":11}],9:[function(require,module,exports){ +require('./idealsteps'); + +module.exports = { + + name: 'steps', + + options: { + stepsContainer: '.idealsteps-container', + stepsOptions: {} + }, + + methods: { + + // @extend + _init: function() { + this._buildSteps(); + }, + + // @extend + _validate: function() { + + var self = this; + + this._updateSteps(); + + if ($.idealforms.hasExtension('idealAjax')) { + $.each($.idealforms._requests, function(key, request) { + request.done(function(){ self._updateSteps() }); + }); + } + }, + + // @extend + focusFirstInvalid: function(firstInvalid) { + + var self = this; + + this.$stepsContainer.idealsteps('go', function() { + return this.$steps.filter(function() { + return $(this).find(firstInvalid).length; + }).index(); + }); + }, + + _buildSteps: function() { + + var self = this, options + , hasRules = ! $.isEmptyObject(this.opts.rules) + , counter = hasRules + ? '' + : '0'; + + options = $.extend({}, { + buildNavItems: function(i){ return 'Step '+ (i+1) + counter } + }, this.opts.stepsOptions); + + this.$stepsContainer = this.$form.closest(this.opts.stepsContainer).idealsteps(options); + }, + + _updateSteps: function() { + + var self = this; + + this.$stepsContainer.idealsteps('_inject', function() { + + var idealsteps = this; + + this.$navItems.each(function(i) { + var invalid = idealsteps.$steps.eq(i).find(self.getInvalid()).length; + $(this).find('span').text(invalid).toggleClass('zero', ! invalid); + }); + }); + }, + + // @extend + addRules: function() { + this.firstStep(); + }, + + // @extend + toggleFields: function() { + this._updateSteps(); + }, + + // @extend + removeFields: function() { + this._updateSteps(); + }, + + goToStep: function(idx) { + this.$stepsContainer.idealsteps('go', idx); + }, + + prevStep: function() { + this.$stepsContainer.idealsteps('prev'); + }, + + nextStep: function() { + this.$stepsContainer.idealsteps('next'); + }, + + firstStep: function() { + this.$stepsContainer.idealsteps('first'); + }, + + lastStep: function() { + this.$stepsContainer.idealsteps('last'); + } + } + +}; + +},{"./idealsteps":8}],10:[function(require,module,exports){ +/*! + * jQuery Ideal Forms + * @author: Cedric Ruiz + * @version: 3.0 + * @license GPL or MIT + */ +(function($, win, doc, undefined) { + + var plugin = {}; + + plugin.name = 'idealforms'; + + plugin.defaults = { + field: '.field', + error: '.error', + iconHtml: '', + iconClass: 'icon', + invalidClass: 'invalid', + validClass: 'valid', + silentLoad: true, + onValidate: $.noop, + onSubmit: $.noop + }; + + plugin.global = { + + _format: function(str) { + var args = [].slice.call(arguments, 1); + return str.replace(/\{(\d)\}/g, function(_, match) { + return args[+match] || ''; + }).replace(/\{\*([^*}]*)\}/g, function(_, sep) { + return args.join(sep || ', '); + }); + }, + + _getKey: function(key, obj) { + return key.split('.').reduce(function(a,b) { + return a && a[b]; + }, obj); + }, + + ruleSeparator: ' ', + argSeparator: ':', + + rules: require('./rules'), + errors: require('./errors'), + + extensions: [ + require('./extensions/dynamic-fields/dynamic-fields.ext'), + require('./extensions/ajax/ajax.ext'), + require('./extensions/steps/steps.ext'), + require('./extensions/custom-inputs/custom-inputs.ext'), + require('./extensions/datepicker/datepicker.ext') + ] + }; + + plugin.methods = $.extend({}, require('./private'), require('./public')); + + require('./plugin')(plugin); + +}(jQuery, window, document)); + +},{"./errors":1,"./extensions/ajax/ajax.ext":2,"./extensions/custom-inputs/custom-inputs.ext":3,"./extensions/datepicker/datepicker.ext":6,"./extensions/dynamic-fields/dynamic-fields.ext":7,"./extensions/steps/steps.ext":9,"./plugin":11,"./private":12,"./public":13,"./rules":14}],11:[function(require,module,exports){ +/** + * Plugin boilerplate + */ +module.exports = (function() { + + var AP = Array.prototype; + + return function(plugin) { + + $.extend({ + name: 'plugin', + defaults: {}, + methods: {}, + global: {}, + }, plugin); + + $[plugin.name] = $.extend({ + + addExtension: function(extension) { + plugin.global.extensions.push(extension); + }, + + hasExtension: function(extension) { + return plugin.global.extensions.filter(function(ext) { + return ext.name == extension; + }).length; + } + }, plugin.global); + + function Plugin(element, options) { + + this.opts = $.extend({}, plugin.defaults, options); + this.el = element; + + this._name = plugin.name; + + this._init(); + } + + Plugin._extended = {}; + + Plugin.prototype._extend = function(extensions) { + + var self = this + , disabled = self.opts.disabledExtensions || 'none'; + + $.each(extensions, function(i, extension) { + + $.extend(self.opts, $.extend(true, extension.options, self.opts)); + + $.each(extension.methods, function(method, fn) { + + if (disabled.indexOf(extension.name) > -1) { + return; + } + + if (Plugin.prototype[method]) { + Plugin._extended[method] = Plugin._extended[method] || []; + Plugin._extended[method].push({ name: extension.name, fn: fn }); + } else { + Plugin.prototype[method] = fn; + } + }); + + }); + }; + + Plugin.prototype._inject = function(method) { + + var args = [].slice.call(arguments, 1); + + if (typeof method == 'function') return method.call(this); + + var self = this; + + if (Plugin._extended[method]) { + $.each(Plugin._extended[method], function(i, plugin) { + plugin.fn.apply(self, args); + }); + } + }; + + Plugin.prototype._init = $.noop; + + Plugin.prototype[plugin.name] = function(method) { + if (!method) return this; + try { return this[method].apply(this, AP.slice.call(arguments, 1)); } + catch(e) {} + }; + + $.extend(Plugin.prototype, plugin.methods); + + $.fn[plugin.name] = function() { + + var args = AP.slice.call(arguments) + , methodArray = typeof args[0] == 'string' && args[0].split(':') + , method = methodArray[methodArray.length > 1 ? 1 : 0] + , prefix = methodArray.length > 1 && methodArray[0] + , opts = typeof args[0] == 'object' && args[0] + , params = args.slice(1) + , ret; + + if (prefix) { + method = prefix + method.substr(0,1).toUpperCase() + method.substr(1,method.length-1); + } + + this.each(function() { + + var instance = $.data(this, plugin.name); + + // Method + if (instance) { + return ret = instance[plugin.name].apply(instance, [method].concat(params)); + } + + // Init + return $.data(this, plugin.name, new Plugin(this, opts)); + }); + + return prefix ? ret : this; + }; + }; + +}()); + +},{}],12:[function(require,module,exports){ +/** + * Private methods + */ +module.exports = { + + _init: function() { + + var self = this; + + this._extend($.idealforms.extensions); + + this.$form = $(this.el); + this.$fields = $(); + this.$inputs = $(); + + this.$form.submit(function(e) { + e.preventDefault(); + self.focusFirstInvalid(); + self.opts.onSubmit.call(this, self.getInvalid().length, e); + }); + + this._inject('_init'); + + this.addRules(this.opts.rules || {}); + + if (! this.opts.silentLoad) this.focusFirstInvalid(); + }, + + _buildField: function(input) { + + var self = this + , $field = this._getField(input) + , $icon; + + $icon = $(this.opts.iconHtml, { + class: this.opts.iconClass, + click: function(){ $(input).focus() } + }); + + if (! this.$fields.filter($field).length) { + this.$fields = this.$fields.add($field); + if (this.opts.iconHtml) $field.append($icon); + $field.addClass('idealforms-field idealforms-field-'+ input.type); + } + + this._addEvents(input); + + this._inject('_buildField', input); + }, + + _addEvents: function(input) { + + var self = this + , $field = this._getField(input); + + $(input) + .on('change keyup', function(e) { + + var oldValue = $field.data('idealforms-value'); + + if (e.which == 9 || e.which == 16) return; + if (! $(this).is(':checkbox, :radio') && oldValue == this.value) return; + + $field.data('idealforms-value', this.value); + + self._validate(this, true, true); + }) + .focus(function() { + + if (self.isValid(this.name)) return false; + + if (self._isRequired(this) || this.value) { + $field.find(self.opts.error).show(); + } + }) + .blur(function() { + $field.find(self.opts.error).hide(); + }); + }, + + _isRequired: function(input) { + // We assume non-text inputs with rules are required + if ($(input).is(':checkbox, :radio, select')) return true; + return this.opts.rules[input.name].indexOf('required') > -1; + }, + + _getRelated: function(input) { + return this._getField(input).find('[name="'+ input.name +'"]'); + }, + + _getField: function(input) { + return $(input).closest(this.opts.field); + }, + + _getFirstInvalid: function() { + return this.getInvalid().first().find('input:first, textarea, select'); + }, + + _handleError: function(input, error, valid) { + valid = valid || this.isValid(input.name); + var $error = this._getField(input).find(this.opts.error); + this.$form.find(this.opts.error).hide(); + if (error) $error.text(error); + $error.toggle(!valid); + }, + + _handleStyle: function(input, valid) { + valid = valid || this.isValid(input.name); + this._getField(input) + .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) + .addClass(valid ? this.opts.validClass : this.opts.invalidClass) + .find('.'+ this.opts.iconClass).show(); + }, + + _fresh: function(input) { + this._getField(input) + .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) + .find(this.opts.error).hide() + .end() + .find('.'+ this.opts.iconClass).toggle(this._isRequired(input)); + }, + + _validate: function(input, handleError, handleStyle) { + + var self = this + , $field = this._getField(input) + , userRules = this.opts.rules[input.name].split($.idealforms.ruleSeparator) + , valid = true + , rule; + + // Non-required input with empty value must pass validation + if (! input.value && ! this._isRequired(input)) { + $field.removeData('idealforms-valid'); + this._fresh(input); + + // Required inputs + } else { + + $.each(userRules, function(i, userRule) { + + userRule = userRule.split($.idealforms.argSeparator); + + rule = userRule[0]; + + var theRule = $.idealforms.rules[rule] + , args = userRule.slice(1) + , error; + + error = $.idealforms._format.apply(null, [ + $.idealforms._getKey('errors.'+ input.name +'.'+ rule, self.opts) || + $.idealforms.errors[rule] + ].concat(args)); + + valid = typeof theRule == 'function' + ? theRule.apply(self, [input, input.value].concat(args)) + : theRule.test(input.value); + + $field.data('idealforms-valid', valid); + + if (handleError) self._handleError(input, error, valid); + if (handleStyle) self._handleStyle(input, valid); + + self.opts.onValidate.call(self, input, rule, valid); + + return valid; + }); + } + + this._inject('_validate', input, rule, valid); + + return valid; + } + +}; + +},{}],13:[function(require,module,exports){ +/** + * Public methods + */ +module.exports = { + + addRules: function(rules) { + + var self = this; + + var $inputs = this.$form.find($.map(rules, function(_, name) { + return '[name="'+ name +'"]'; + }).join(',')); + + $.extend(this.opts.rules, rules); + + $inputs.each(function(){ self._buildField(this) }); + + this.$inputs = this.$inputs + .add($inputs) + .each(function(){ self._validate(this, true) }); + + this.$fields.find(this.opts.error).hide(); + + this._inject('addRules'); + }, + + getInvalid: function() { + return this.$fields.filter(function() { + return $(this).data('idealforms-valid') === false; + }); + }, + + focusFirstInvalid: function() { + + var firstInvalid = this._getFirstInvalid()[0]; + + if (firstInvalid) { + this._handleError(firstInvalid); + this._handleStyle(firstInvalid); + this._inject('focusFirstInvalid', firstInvalid); + firstInvalid.focus(); + } + }, + + isValid: function(name) { + if (name) return ! this.getInvalid().find('[name="'+ name +'"]').length; + return ! this.getInvalid().length; + }, + + reset: function(name) { + + var self = this + , $inputs = this.$inputs; + + if (name) $inputs = $inputs.filter('[name="'+ name +'"]'); + + $inputs.filter('input:not(:checkbox, :radio)').val(''); + $inputs.filter(':checkbox, :radio').prop('checked', false); + $inputs.filter('select').find('option').prop('selected', function() { + return this.defaultSelected; + }); + + $inputs.change().each(function(){ self._resetErrorAndStyle(this) }); + } + +}; + +},{}],14:[function(require,module,exports){ +/** + * Rules + */ +module.exports = { + + required: /.+/, + digits: /^\d+$/, + email: /^[^@]+@[^@]+\..{2,6}$/, + username: /^[a-z](?=[\w.]{3,31}$)\w*\.?\w*$/i, + pass: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/, + strongpass: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, + phone: /^[2-9]\d{2}-\d{3}-\d{4}$/, + zip: /^\d{5}$|^\d{5}-\d{4}$/, + url: /^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i, + + number: function(input, value) { + return !isNaN(value); + }, + + range: function(input, value, mix, max) { + return Number(value) >= min && Number(value) <= max; + }, + + min: function(input, value, min) { + return value.length >= min; + }, + + max: function(input, value, max) { + return value.length <= max; + }, + + minoption: function(input, value, min) { + return this._getRelated(input).filter(':checked').length >= min; + }, + + maxoption: function(input, value, max) { + return this._getRelated(input).filter(':checked').length <= max; + }, + + minmax: function(input, value, min, max) { + return value.length >= min && value.length <= max; + }, + + select: function(input, value, def) { + return value != def; + }, + + extension: function(input) { + + var extensions = [].slice.call(arguments, 1) + , valid = false; + + $.each(input.files || [{name: input.value}], function(i, file) { + valid = $.inArray(file.name.match(/\.(.+)$/)[1], extensions) > -1; + }); + + return valid; + }, + + equalto: function(input, value, target) { + + var self = this + , $target = $('[name="'+ target +'"]'); + + if (this.getInvalid().find($target).length) return false; + + $target.off('keyup.equalto').on('keyup.equalto', function() { + self._validate(input, false, true); + }); + + return input.value == $target.val(); + }, + + date: function(input, value, format) { + + format = format || 'mm/dd/yyyy'; + + var delimiter = /[^mdy]/.exec(format)[0] + , theFormat = format.split(delimiter) + , theDate = value.split(delimiter); + + function isDate(date, format) { + + var m, d, y; + + for (var i = 0, len = format.length; i < len; i++) { + if (/m/.test(format[i])) m = date[i]; + if (/d/.test(format[i])) d = date[i]; + if (/y/.test(format[i])) y = date[i]; + } + + if (!m || !d || !y) return false; + + return m > 0 && m < 13 && + y && y.length == 4 && + d > 0 && d <= (new Date(y, m, 0)).getDate(); + } + + return isDate(theDate, theFormat); + } + +}; + +},{}]},{},[10]) +//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL2Vycm9ycy5qcyIsIi92YXIvd3d3L2lkZWFsZm9ybXMvanMvZXh0ZW5zaW9ucy9hamF4L2FqYXguZXh0LmpzIiwiL3Zhci93d3cvaWRlYWxmb3Jtcy9qcy9leHRlbnNpb25zL2N1c3RvbS1pbnB1dHMvY3VzdG9tLWlucHV0cy5leHQuanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL2V4dGVuc2lvbnMvY3VzdG9tLWlucHV0cy9pZGVhbGZpbGUuanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL2V4dGVuc2lvbnMvY3VzdG9tLWlucHV0cy9pZGVhbHJhZGlvY2hlY2suanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL2V4dGVuc2lvbnMvZGF0ZXBpY2tlci9kYXRlcGlja2VyLmV4dC5qcyIsIi92YXIvd3d3L2lkZWFsZm9ybXMvanMvZXh0ZW5zaW9ucy9keW5hbWljLWZpZWxkcy9keW5hbWljLWZpZWxkcy5leHQuanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL2V4dGVuc2lvbnMvc3RlcHMvaWRlYWxzdGVwcy5qcyIsIi92YXIvd3d3L2lkZWFsZm9ybXMvanMvZXh0ZW5zaW9ucy9zdGVwcy9zdGVwcy5leHQuanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL21haW4uanMiLCIvdmFyL3d3dy9pZGVhbGZvcm1zL2pzL3BsdWdpbi5qcyIsIi92YXIvd3d3L2lkZWFsZm9ybXMvanMvcHJpdmF0ZS5qcyIsIi92YXIvd3d3L2lkZWFsZm9ybXMvanMvcHVibGljLmpzIiwiL3Zhci93d3cvaWRlYWxmb3Jtcy9qcy9ydWxlcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXJyb3JzXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIHJlcXVpcmVkOiAnVGhpcyBmaWVsZCBpcyByZXF1aXJlZCcsXG4gIGRpZ2l0czogJ011c3QgYmUgb25seSBkaWdpdHMnLFxuICBuYW1lOiAnTXVzdCBiZSBhdCBsZWFzdCAzIGNoYXJhY3RlcnMgbG9uZyBhbmQgbXVzdCBvbmx5IGNvbnRhaW4gbGV0dGVycycsXG4gIGVtYWlsOiAnTXVzdCBiZSBhIHZhbGlkIGVtYWlsJyxcbiAgdXNlcm5hbWU6ICdNdXN0IGJlIGF0IGJldHdlZW4gNCBhbmQgMzIgY2hhcmFjdGVycyBsb25nIGFuZCBzdGFydCB3aXRoIGEgbGV0dGVyLiBZb3UgbWF5IHVzZSBsZXR0ZXJzLCBudW1iZXJzLCB1bmRlcnNjb3JlcywgYW5kIG9uZSBkb3QnLFxuICBwYXNzOiAnTXVzdCBiZSBhdCBsZWFzdCA2IGNoYXJhY3RlcnMgbG9uZywgYW5kIGNvbnRhaW4gYXQgbGVhc3Qgb25lIG51bWJlciwgb25lIHVwcGVyY2FzZSBhbmQgb25lIGxvd2VyY2FzZSBsZXR0ZXInLFxuICBzdHJvbmdwYXNzOiAnTXVzdCBiZSBhdCBsZWFzdCA4IGNoYXJhY3RlcnMgbG9uZyBhbmQgY29udGFpbiBhdCBsZWFzdCBvbmUgdXBwZXJjYXNlIGFuZCBvbmUgbG93ZXJjYXNlIGxldHRlciBhbmQgb25lIG51bWJlciBvciBzcGVjaWFsIGNoYXJhY3RlcicsXG4gIHBob25lOiAnTXVzdCBiZSBhIHZhbGlkIHBob25lIG51bWJlcicsXG4gIHppcDogJ011c3QgYmUgYSB2YWxpZCB6aXAgY29kZScsXG4gIHVybDogJ011c3QgYmUgYSB2YWxpZCBVUkwnLFxuICBudW1iZXI6ICdNdXN0IGJlIGEgbnVtYmVyJyxcbiAgcmFuZ2U6ICdNdXN0IGJlIGEgbnVtYmVyIGJldHdlZW4gezB9IGFuZCB7MX0nLFxuICBtaW46ICdNdXN0IGJlIGF0IGxlYXN0IHswfSBjaGFyYWN0ZXJzIGxvbmcnLFxuICBtYXg6ICdNdXN0IGJlIHVuZGVyIHswfSBjaGFyYWN0ZXJzJyxcbiAgbWlub3B0aW9uOiAnU2VsZWN0IGF0IGxlYXN0IHswfSBvcHRpb25zJyxcbiAgbWF4b3B0aW9uOiAnU2VsZWN0IG5vIG1vcmUgdGhhbiB7MH0gb3B0aW9ucycsXG4gIG1pbm1heDogJ011c3QgYmUgYmV0d2VlbiB7MH0gYW5kIHsxfSBjaGFyYWN0ZXJzIGxvbmcnLFxuICBzZWxlY3Q6ICdTZWxlY3QgYW4gb3B0aW9uJyxcbiAgZXh0ZW5zaW9uOiAnRmlsZShzKSBtdXN0IGhhdmUgYSB2YWxpZCBleHRlbnNpb24gKHsqfSknLFxuICBlcXVhbHRvOiAnTXVzdCBoYXZlIHRoZSBzYW1lIHZhbHVlIGFzIHRoZSBcInswfVwiIGZpZWxkJyxcbiAgZGF0ZTogJ011c3QgYmUgYSB2YWxpZCBkYXRlIHswfSdcblxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIG5hbWU6ICdpZGVhbEFqYXgnLFxuXG4gIG1ldGhvZHM6IHtcblxuICAgIC8vIEBleHRlbmRcbiAgICBfaW5pdDogZnVuY3Rpb24oKSB7XG5cbiAgICAgICQuZXh0ZW5kKCQuaWRlYWxmb3JtcywgeyBfcmVxdWVzdHM6IHt9IH0pO1xuXG4gICAgICAkLmV4dGVuZCgkLmlkZWFsZm9ybXMuZXJyb3JzLCB7XG4gICAgICAgIGFqYXg6ICdMb2FkaW5nLi4uJ1xuICAgICAgfSk7XG5cbiAgICAgICQuZXh0ZW5kKCQuaWRlYWxmb3Jtcy5ydWxlcywge1xuXG4gICAgICAgIGFqYXg6IGZ1bmN0aW9uKGlucHV0KSB7XG5cbiAgICAgICAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICAgICAgICAgICwgJGZpZWxkID0gdGhpcy5fZ2V0RmllbGQoaW5wdXQpXG4gICAgICAgICAgICAsIHVybCA9ICQoaW5wdXQpLmRhdGEoJ2lkZWFsZm9ybXMtYWpheCcpXG4gICAgICAgICAgICAsIHVzZXJFcnJvciA9ICQuaWRlYWxmb3Jtcy5fZ2V0S2V5KCdlcnJvcnMuJysgaW5wdXQubmFtZSArJy5hamF4RXJyb3InLCBzZWxmLm9wdHMpXG4gICAgICAgICAgICAsIHJlcXVlc3RzID0gJC5pZGVhbGZvcm1zLl9yZXF1ZXN0c1xuICAgICAgICAgICAgLCBkYXRhID0ge307XG5cbiAgICAgICAgICBkYXRhW2lucHV0Lm5hbWVdID0gaW5wdXQudmFsdWU7XG5cbiAgICAgICAgICAkZmllbGQuYWRkQ2xhc3MoJ2FqYXgnKTtcblxuICAgICAgICAgIGlmIChyZXF1ZXN0c1tpbnB1dC5uYW1lXSkgcmVxdWVzdHNbaW5wdXQubmFtZV0uYWJvcnQoKTtcblxuICAgICAgICAgIHJlcXVlc3RzW2lucHV0Lm5hbWVdID0gJC5wb3N0KHVybCwgZGF0YSwgZnVuY3Rpb24ocmVzcCkge1xuXG4gICAgICAgICAgICBpZiAocmVzcCA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAkZmllbGQuZGF0YSgnaWRlYWxmb3Jtcy12YWxpZCcsIHRydWUpO1xuICAgICAgICAgICAgICBzZWxmLl9oYW5kbGVFcnJvcihpbnB1dCk7XG4gICAgICAgICAgICAgIHNlbGYuX2hhbmRsZVN0eWxlKGlucHV0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHNlbGYuX2hhbmRsZUVycm9yKGlucHV0LCB1c2VyRXJyb3IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAkZmllbGQucmVtb3ZlQ2xhc3MoJ2FqYXgnKTtcblxuICAgICAgICAgIH0sICdqc29uJyk7XG5cbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgX3ZhbGlkYXRlOiBmdW5jdGlvbihpbnB1dCwgcnVsZSkge1xuICAgICAgaWYgKHJ1bGUgIT0gJ2FqYXgnICYmICQuaWRlYWxmb3Jtcy5fcmVxdWVzdHNbaW5wdXQubmFtZV0pIHtcbiAgICAgICAgJC5pZGVhbGZvcm1zLl9yZXF1ZXN0c1tpbnB1dC5uYW1lXS5hYm9ydCgpO1xuICAgICAgICB0aGlzLl9nZXRGaWVsZChpbnB1dCkucmVtb3ZlQ2xhc3MoJ2FqYXgnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgfVxufTtcbiIsInJlcXVpcmUoJy4vaWRlYWxmaWxlJyk7XG5yZXF1aXJlKCcuL2lkZWFscmFkaW9jaGVjaycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblxuICBuYW1lOiAnY3VzdG9tSW5wdXRzJyxcblxuICBtZXRob2RzOiB7XG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5fYnVpbGRDdXN0b21JbnB1dHMoKTtcbiAgICB9LFxuXG4gICAgYWRkRmllbGRzOiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMuX2J1aWxkQ3VzdG9tSW5wdXRzKCk7XG4gICAgfSxcblxuICAgIF9idWlsZEN1c3RvbUlucHV0czogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLiRmb3JtLmZpbmQoJzpmaWxlJykuaWRlYWxmaWxlKCk7XG4gICAgICB0aGlzLiRmb3JtLmZpbmQoJzpjaGVja2JveCwgOnJhZGlvJykuaWRlYWxyYWRpb2NoZWNrKCk7XG4gICAgfVxuXG4gIH1cbn07XG4iLCIvKipcbiAqIElkZWFsIEZpbGVcbiAqL1xuKGZ1bmN0aW9uKCQsIHdpbiwgZG9jLCB1bmRlZmluZWQpIHtcblxuICAvLyBCcm93c2VyIHN1cHBvcnRzIEhUTUw1IG11bHRpcGxlIGZpbGU/XG4gIHZhciBtdWx0aXBsZVN1cHBvcnQgPSB0eXBlb2YgJCgnPGlucHV0Lz4nKVswXS5tdWx0aXBsZSAhPT0gJ3VuZGVmaW5lZCdcbiAgICAsIGlzSUUgPSAvbXNpZS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudClcbiAgICAsIHBsdWdpbiA9IHt9O1xuXG4gIHBsdWdpbi5uYW1lID0gJ2lkZWFsZmlsZSc7XG5cbiAgcGx1Z2luLm1ldGhvZHMgPSB7XG4gIFxuICAgICAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuXG4gICAgICAgIHZhciAkZmlsZSA9ICQodGhpcy5lbCkuYWRkQ2xhc3MoJ2lkZWFsLWZpbGUnKSAvLyB0aGUgb3JpZ2luYWwgZmlsZSBpbnB1dFxuICAgICAgICAgICwgJHdyYXAgPSAkKCc8ZGl2IGNsYXNzPVwiaWRlYWwtZmlsZS13cmFwXCI+JylcbiAgICAgICAgICAsICRpbnB1dCA9ICQoJzxpbnB1dCB0eXBlPVwidGV4dFwiIGNsYXNzPVwiaWRlYWwtZmlsZS1maWxlbmFtZVwiIC8+JylcbiAgICAgICAgICAgIC8vIEJ1dHRvbiB0aGF0IHdpbGwgYmUgdXNlZCBpbiBub24tSUUgYnJvd3NlcnNcbiAgICAgICAgICAsICRidXR0b24gPSAkKCc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImlkZWFsLWZpbGUtdXBsb2FkXCI+T3BlbjwvYnV0dG9uPicpXG4gICAgICAgICAgICAvLyBIYWNrIGZvciBJRVxuICAgICAgICAgICwgJGxhYmVsID0gJCgnPGxhYmVsIGNsYXNzPVwiaWRlYWwtZmlsZS11cGxvYWRcIiBmb3I9XCInICsgJGZpbGVbMF0uaWQgKyAnXCI+T3BlbjwvbGFiZWw+Jyk7XG5cbiAgICAgICAgLy8gSGlkZSBieSBzaGlmdGluZyB0byB0aGUgbGVmdCBzbyB3ZVxuICAgICAgICAvLyBjYW4gc3RpbGwgdHJpZ2dlciBldmVudHNcbiAgICAgICAgJGZpbGUuY3NzKHtcbiAgICAgICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgICAgICBsZWZ0OiAnLTk5OTlweCdcbiAgICAgICAgfSk7XG5cbiAgICAgICAgJHdyYXAuYXBwZW5kKCRpbnB1dCwgKGlzSUUgPyAkbGFiZWwgOiAkYnV0dG9uKSkuaW5zZXJ0QWZ0ZXIoJGZpbGUpO1xuXG4gICAgICAgIC8vIFByZXZlbnQgZm9jdXNcbiAgICAgICAgJGZpbGUuYXR0cigndGFiSW5kZXgnLCAtMSk7XG4gICAgICAgICRidXR0b24uYXR0cigndGFiSW5kZXgnLCAtMSk7XG5cbiAgICAgICAgJGJ1dHRvbi5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgJGZpbGUuZm9jdXMoKS5jbGljaygpOyAvLyBPcGVuIGRpYWxvZ1xuICAgICAgICB9KTtcblxuICAgICAgICAkZmlsZS5jaGFuZ2UoZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgdmFyIGZpbGVzID0gW11cbiAgICAgICAgICAgICwgZmlsZUFyciwgZmlsZW5hbWU7XG5cbiAgICAgICAgICAgIC8vIElmIG11bHRpcGxlIGlzIHN1cHBvcnRlZCB0aGVuIGV4dHJhY3RcbiAgICAgICAgICAgIC8vIGFsbCBmaWxlbmFtZXMgZnJvbSB0aGUgZmlsZSBhcnJheVxuICAgICAgICAgIGlmIChtdWx0aXBsZVN1cHBvcnQpIHtcbiAgICAgICAgICAgIGZpbGVBcnIgPSAkZmlsZVswXS5maWxlcztcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBmaWxlQXJyLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICAgIGZpbGVzLnB1c2goZmlsZUFycltpXS5uYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZpbGVuYW1lID0gZmlsZXMuam9pbignLCAnKTtcblxuICAgICAgICAgICAgLy8gSWYgbm90IHN1cHBvcnRlZCB0aGVuIGp1c3QgdGFrZSB0aGUgdmFsdWVcbiAgICAgICAgICAgIC8vIGFuZCByZW1vdmUgdGhlIHBhdGggdG8ganVzdCBzaG93IHRoZSBmaWxlbmFtZVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmaWxlbmFtZSA9ICRmaWxlLnZhbCgpLnNwbGl0KCdcXFxcJykucG9wKCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgJGlucHV0IC52YWwoZmlsZW5hbWUpLmF0dHIoJ3RpdGxlJywgZmlsZW5hbWUpO1xuXG4gICAgICAgIH0pO1xuXG4gICAgICAgICRpbnB1dC5vbih7XG4gICAgICAgICAgYmx1cjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJGZpbGUudHJpZ2dlcignYmx1cicpO1xuICAgICAgICAgIH0sXG4gICAgICAgICAga2V5ZG93bjogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGlmIChlLndoaWNoID09PSAxMykgeyAvLyBFbnRlclxuICAgICAgICAgICAgICBpZiAoIWlzSUUpICRmaWxlLnRyaWdnZXIoJ2NsaWNrJyk7XG4gICAgICAgICAgICAgICQodGhpcykuY2xvc2VzdCgnZm9ybScpLm9uZSgna2V5ZG93bicsIGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoZS53aGljaCA9PT0gMTMpIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IDggfHwgZS53aGljaCA9PT0gNDYpIHsgLy8gQmFja3NwYWNlICYgRGVsXG4gICAgICAgICAgICAgIC8vIEluIElFIHRoZSB2YWx1ZSBpcyByZWFkLW9ubHlcbiAgICAgICAgICAgICAgLy8gd2l0aCB0aGlzIHRyaWNrIHdlIHJlbW92ZSB0aGUgb2xkIGlucHV0IGFuZCBhZGRcbiAgICAgICAgICAgICAgLy8gYSBjbGVhbiBjbG9uZSB3aXRoIGFsbCB0aGUgb3JpZ2luYWwgZXZlbnRzIGF0dGFjaGVkXG4gICAgICAgICAgICAgIGlmIChpc0lFKSAkZmlsZS5yZXBsYWNlV2l0aCgkZmlsZSA9ICRmaWxlLmNsb25lKHRydWUpKTtcbiAgICAgICAgICAgICAgJGZpbGUudmFsKCcnKS50cmlnZ2VyKCdjaGFuZ2UnKTtcbiAgICAgICAgICAgICAgJGlucHV0LnZhbCgnJyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IDkpIHsgLy8gVEFCXG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gZWxzZSB7IC8vIEFsbCBvdGhlciBrZXlzXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICB9XG4gIFxuICB9O1xuXG4gIHJlcXVpcmUoJy4uLy4uL3BsdWdpbicpKHBsdWdpbik7XG5cbn0oalF1ZXJ5LCB3aW5kb3csIGRvY3VtZW50KSk7XG4iLCIvKlxuICogaWRlYWxSYWRpb0NoZWNrOiBqUXVlcnkgcGxndWluIGZvciBjaGVja2JveCBhbmQgcmFkaW8gcmVwbGFjZW1lbnRcbiAqIFVzYWdlOiAkKCdpbnB1dFt0eXBlPWNoZWNrYm94XSwgaW5wdXRbdHlwZT1yYWRpb10nKS5pZGVhbFJhZGlvQ2hlY2soKVxuICovXG4oZnVuY3Rpb24oJCwgd2luLCBkb2MsIHVuZGVmaW5lZCkge1xuXG4gIHZhciBwbHVnaW4gPSB7fTtcblxuICBwbHVnaW4ubmFtZSA9ICdpZGVhbHJhZGlvY2hlY2snO1xuXG4gIHBsdWdpbi5tZXRob2RzID0ge1xuXG4gICAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuXG4gICAgICB2YXIgJGlucHV0ID0gJCh0aGlzLmVsKTtcbiAgICAgIHZhciAkc3BhbiA9ICQoJzxzcGFuLz4nKTtcblxuICAgICAgJHNwYW4uYWRkQ2xhc3MoJ2lkZWFsLScrICgkaW5wdXQuaXMoJzpjaGVja2JveCcpID8gJ2NoZWNrJyA6ICdyYWRpbycpKTtcbiAgICAgICRpbnB1dC5pcygnOmNoZWNrZWQnKSAmJiAkc3Bhbi5hZGRDbGFzcygnY2hlY2tlZCcpOyAvLyBpbml0XG4gICAgICAkc3Bhbi5pbnNlcnRBZnRlcigkaW5wdXQpO1xuXG4gICAgICAkaW5wdXQucGFyZW50KCdsYWJlbCcpXG4gICAgICAgIC5hZGRDbGFzcygnaWRlYWwtcmFkaW9jaGVjay1sYWJlbCcpXG4gICAgICAgIC5hdHRyKCdvbmNsaWNrJywgJycpOyAvLyBGaXggY2xpY2tpbmcgbGFiZWwgaW4gaU9TXG5cbiAgICAgICRpbnB1dC5jc3MoeyBwb3NpdGlvbjogJ2Fic29sdXRlJywgbGVmdDogJy05OTk5cHgnIH0pOyAvLyBoaWRlIGJ5IHNoaWZ0aW5nIGxlZnRcblxuICAgICAgLy8gRXZlbnRzXG4gICAgICAkaW5wdXQub24oe1xuICAgICAgICBjaGFuZ2U6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHZhciAkaW5wdXQgPSAkKHRoaXMpO1xuICAgICAgICAgIGlmICggJGlucHV0LmlzKCdpbnB1dFt0eXBlPVwicmFkaW9cIl0nKSApIHtcbiAgICAgICAgICAgICRpbnB1dC5wYXJlbnQoKS5zaWJsaW5ncygnbGFiZWwnKS5maW5kKCcuaWRlYWwtcmFkaW8nKS5yZW1vdmVDbGFzcygnY2hlY2tlZCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAkc3Bhbi50b2dnbGVDbGFzcygnY2hlY2tlZCcsICRpbnB1dC5pcygnOmNoZWNrZWQnKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGZvY3VzOiBmdW5jdGlvbigpIHsgJHNwYW4uYWRkQ2xhc3MoJ2ZvY3VzJykgfSxcbiAgICAgICAgYmx1cjogZnVuY3Rpb24oKSB7ICRzcGFuLnJlbW92ZUNsYXNzKCdmb2N1cycpIH0sXG4gICAgICAgIGNsaWNrOiBmdW5jdGlvbigpIHsgJCh0aGlzKS50cmlnZ2VyKCdmb2N1cycpIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICB9O1xuXG4gIHJlcXVpcmUoJy4uLy4uL3BsdWdpbicpKHBsdWdpbik7XG5cbn0oalF1ZXJ5LCB3aW5kb3csIGRvY3VtZW50KSk7XG5cbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIG5hbWU6ICdkYXRlcGlja2VyJyxcblxuICBtZXRob2RzOiB7XG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5fYnVpbGREYXRlcGlja2VyKCk7XG4gICAgfSxcblxuICAgX2J1aWxkRGF0ZXBpY2tlcjogZnVuY3Rpb24oKSB7XG5cbiAgICAgIHZhciAkZGF0ZXBpY2tlciA9IHRoaXMuJGZvcm0uZmluZCgnaW5wdXQuZGF0ZXBpY2tlcicpO1xuXG4gICAgICAvLyBBbHdheXMgc2hvdyBkYXRlcGlja2VyIGJlbG93IHRoZSBpbnB1dFxuICAgICAgaWYgKGpRdWVyeS51aSkge1xuICAgICAgICAkLmRhdGVwaWNrZXIuX2NoZWNrT2Zmc2V0ID0gZnVuY3Rpb24oYSxiLGMpeyByZXR1cm4gYiB9O1xuICAgICAgfVxuXG4gICAgICBpZiAoalF1ZXJ5LnVpICYmICRkYXRlcGlja2VyLmxlbmd0aCkge1xuXG4gICAgICAgICRkYXRlcGlja2VyLmVhY2goZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgICAkKHRoaXMpLmRhdGVwaWNrZXIoe1xuICAgICAgICAgICAgYmVmb3JlU2hvdzogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICAgICAgICAgICAgJChpbnB1dCkuYWRkQ2xhc3MoJ29wZW4nKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvbkNoYW5nZU1vbnRoWWVhcjogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIC8vIEhhY2sgdG8gZml4IElFOSBub3QgcmVzaXppbmdcbiAgICAgICAgICAgICAgdmFyICR0aGlzID0gJCh0aGlzKVxuICAgICAgICAgICAgICAgICwgd2lkdGggPSAkdGhpcy5vdXRlcldpZHRoKCk7IC8vIGNhY2hlIGZpcnN0IVxuICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICR0aGlzLmRhdGVwaWNrZXIoJ3dpZGdldCcpLmNzcygnd2lkdGgnLCB3aWR0aCk7XG4gICAgICAgICAgICAgIH0sIDEpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uQ2xvc2U6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAkKHRoaXMpLnJlbW92ZUNsYXNzKCdvcGVuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEFkanVzdCB3aWR0aFxuICAgICAgICAkZGF0ZXBpY2tlci5vbignZm9jdXMga2V5dXAnLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICB2YXIgdCA9ICQodGhpcyksIHcgPSB0Lm91dGVyV2lkdGgoKTtcbiAgICAgICAgICB0LmRhdGVwaWNrZXIoJ3dpZGdldCcpLmNzcygnd2lkdGgnLCB3KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gIH1cbn07XG4iLCJmdW5jdGlvbiB0ZW1wbGF0ZShodG1sLCBkYXRhKSB7XG5cbiAgdmFyIGxvb3AgPSAvXFx7QChbXn1dKylcXH0oLis/KVxce1xcL1xcMVxcfS9nXG4gICAgLCBsb29wVmFyaWFibGUgPSAvXFx7IyhbXn1dKylcXH0vZ1xuICAgICwgdmFyaWFibGUgPSAvXFx7KFtefV0rKVxcfS9nO1xuXG4gIHJldHVybiBodG1sXG4gICAgLnJlcGxhY2UobG9vcCwgZnVuY3Rpb24oXywga2V5LCBsaXN0KSB7XG4gICAgICByZXR1cm4gJC5tYXAoZGF0YVtrZXldLCBmdW5jdGlvbihpdGVtKSB7XG4gICAgICAgIHJldHVybiBsaXN0LnJlcGxhY2UobG9vcFZhcmlhYmxlLCBmdW5jdGlvbihfLCBrKSB7XG4gICAgICAgICAgcmV0dXJuIGl0ZW1ba107XG4gICAgICAgIH0pO1xuICAgICAgfSkuam9pbignJyk7XG4gICAgfSlcbiAgICAucmVwbGFjZSh2YXJpYWJsZSwgZnVuY3Rpb24oXywga2V5KSB7XG4gICAgICByZXR1cm4gZGF0YVtrZXldIHx8ICcnO1xuICAgIH0pO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblxuICBuYW1lOiAnZHluYW1pY0ZpZWxkcycsXG5cbiAgb3B0aW9uczoge1xuXG4gICAgdGVtcGxhdGVzOiB7XG5cbiAgICAgIGJhc2U6J1xcXG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWVsZFwiIHtjbGFzc30+XFxcbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJtYWluXCI+e2xhYmVsfTwvbGFiZWw+XFxcbiAgICAgICAgICB7ZmllbGR9XFxcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImVycm9yXCI+PC9zcGFuPlxcXG4gICAgICAgIDwvZGl2PlxcXG4gICAgICAnLFxuXG4gICAgICB0ZXh0OiAnPGlucHV0IG5hbWU9XCJ7bmFtZX1cIiB0eXBlPVwie3N1YnR5cGV9XCIgdmFsdWU9XCJ7dmFsdWV9XCIge2F0dHJzfT4nLFxuXG4gICAgICBmaWxlOiAnPGlucHV0IGlkPVwie25hbWV9IFwibmFtZT1cIntuYW1lfVwiIHR5cGU9XCJmaWxlXCIge2F0dHJzfT4nLFxuXG4gICAgICB0ZXh0YXJlYTogJzx0ZXh0YXJlYSBuYW1lPVwie25hbWV9XCIge2F0dHJzfT57dGV4dH08L3RleHRhcmVhPicsXG5cbiAgICAgIGdyb3VwOiAnXFxcbiAgICAgICAgPHAgY2xhc3M9XCJncm91cFwiPlxcXG4gICAgICAgICAge0BsaXN0fVxcXG4gICAgICAgICAgPGxhYmVsPjxpbnB1dCBuYW1lPVwie25hbWV9XCIgdHlwZT1cIntzdWJ0eXBlfVwiIHZhbHVlPVwieyN2YWx1ZX1cIiB7I2F0dHJzfT57I3RleHR9PC9sYWJlbD5cXFxuICAgICAgICAgIHsvbGlzdH1cXFxuICAgICAgICA8L3A+XFxcbiAgICAgICcsXG5cbiAgICAgIHNlbGVjdDogJ1xcXG4gICAgICAgIDxzZWxlY3QgbmFtZT17bmFtZX0+XFxcbiAgICAgICAgICB7QGxpc3R9XFxcbiAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwieyN2YWx1ZX1cIj57I3RleHR9PC9vcHRpb24+XFxcbiAgICAgICAgICB7L2xpc3R9XFxcbiAgICAgICAgPC9zZWxlY3Q+XFxcbiAgICAgICdcbiAgICB9XG4gIH0sXG5cbiAgbWV0aG9kczoge1xuXG4gICAgYWRkRmllbGRzOiBmdW5jdGlvbihmaWVsZHMpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAkLmVhY2goZmllbGRzLCBmdW5jdGlvbihuYW1lLCBmaWVsZCkge1xuXG4gICAgICAgIHZhciB0eXBlQXJyYXkgPSBmaWVsZC50eXBlLnNwbGl0KCc6JylcbiAgICAgICAgICAsIHJ1bGVzID0ge307XG5cbiAgICAgICAgZmllbGQubmFtZSA9IG5hbWU7XG4gICAgICAgIGZpZWxkLnR5cGUgPSB0eXBlQXJyYXlbMF07XG4gICAgICAgIGlmICh0eXBlQXJyYXlbMV0pIGZpZWxkLnN1YnR5cGUgPSB0eXBlQXJyYXlbMV07XG5cbiAgICAgICAgdmFyIGh0bWwgPSB0ZW1wbGF0ZShzZWxmLm9wdHMudGVtcGxhdGVzLmJhc2UsIHtcbiAgICAgICAgICBsYWJlbDogZmllbGQubGFiZWwsXG4gICAgICAgICAgZmllbGQ6IHRlbXBsYXRlKHNlbGYub3B0cy50ZW1wbGF0ZXNbZmllbGQudHlwZV0sIGZpZWxkKVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoZmllbGQuYWZ0ZXIgfHwgZmllbGQuYmVmb3JlKSB7XG4gICAgICAgICAgc2VsZi4kZm9ybS5maW5kKCdbbmFtZT0nKyAoZmllbGQuYWZ0ZXIgfHwgZmllbGQuYmVmb3JlKSArJ10nKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgc2VsZi5fZ2V0RmllbGQodGhpcylbZmllbGQuYWZ0ZXIgPyAnYWZ0ZXInIDogJ2JlZm9yZSddKGh0bWwpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNlbGYuJGZvcm0uZmluZChzZWxmLm9wdHMuZmllbGQpLmxhc3QoKS5hZnRlcihodG1sKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmaWVsZC5ydWxlcykge1xuICAgICAgICAgIHJ1bGVzW25hbWVdID0gZmllbGQucnVsZXM7XG4gICAgICAgICAgc2VsZi5hZGRSdWxlcyhydWxlcyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLl9pbmplY3QoJ2FkZEZpZWxkcycpO1xuICAgIH0sXG5cbiAgICByZW1vdmVGaWVsZHM6IGZ1bmN0aW9uKG5hbWVzKSB7XG5cbiAgICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgICAgJC5lYWNoKG5hbWVzLnNwbGl0KCcgJyksIGZ1bmN0aW9uKGksIG5hbWUpIHtcbiAgICAgICAgdmFyICRmaWVsZCA9IHNlbGYuX2dldEZpZWxkKCQoJ1tuYW1lPVwiJysgbmFtZSArJ1wiXScpKTtcbiAgICAgICAgc2VsZi4kZmllbGRzID0gc2VsZi4kZmllbGRzLmZpbHRlcihmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gISAkKHRoaXMpLmlzKCRmaWVsZCk7XG4gICAgICAgIH0pO1xuICAgICAgICAkZmllbGQucmVtb3ZlKCk7XG4gICAgICB9KTtcblxuICAgICAgdGhpcy5faW5qZWN0KCdyZW1vdmVGaWVsZHMnKTtcbiAgICB9LFxuXG4gICAgdG9nZ2xlRmllbGRzOiBmdW5jdGlvbihuYW1lcykge1xuXG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICQuZWFjaChuYW1lcy5zcGxpdCgnICcpLCBmdW5jdGlvbihpLCBuYW1lKSB7XG4gICAgICAgIHZhciAkZmllbGQgPSBzZWxmLl9nZXRGaWVsZCgkKCdbbmFtZT1cIicrIG5hbWUgKydcIl0nKSk7XG4gICAgICAgICRmaWVsZC5kYXRhKCdpZGVhbGZvcm1zLXZhbGlkJywgJGZpZWxkLmlzKCc6dmlzaWJsZScpKS50b2dnbGUoKTtcbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLl9pbmplY3QoJ3RvZ2dsZUZpZWxkcycpO1xuICAgIH1cblxuICB9XG59O1xuIiwiLyohXG4gKiBJZGVhbCBTdGVwc1xuKi9cbihmdW5jdGlvbigkLCB3aW4sIGRvYywgdW5kZWZpbmVkKSB7XG5cbiAgdmFyIHBsdWdpbiA9IHt9O1xuXG4gIHBsdWdpbi5uYW1lID0gJ2lkZWFsc3RlcHMnO1xuXG4gIHBsdWdpbi5kZWZhdWx0cyA9IHtcbiAgICBuYXY6ICcuaWRlYWxzdGVwcy1uYXYnLFxuICAgIG5hdkl0ZW1zOiAnbGknLFxuICAgIGJ1aWxkTmF2SXRlbXM6IHRydWUsXG4gICAgd3JhcDogJy5pZGVhbHN0ZXBzLXdyYXAnLFxuICAgIHN0ZXA6ICcuaWRlYWxzdGVwcy1zdGVwJyxcbiAgICBhY3RpdmVDbGFzczogJ2lkZWFsc3RlcHMtc3RlcC1hY3RpdmUnLFxuICAgIGJlZm9yZTogbnVsbCxcbiAgICBhZnRlcjogbnVsbCxcbiAgICBmYWRlU3BlZWQ6IDBcbiAgfTtcblxuICBwbHVnaW4ubWV0aG9kcyA9IHtcblxuICAgIF9pbml0OiBmdW5jdGlvbigpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxuICAgICAgICAgIGFjdGl2ZSA9IHRoaXMub3B0cy5hY3RpdmVDbGFzcztcblxuICAgICAgdGhpcy4kZWwgPSAkKHRoaXMuZWwpO1xuXG4gICAgICB0aGlzLiRuYXYgPSB0aGlzLiRlbC5maW5kKHRoaXMub3B0cy5uYXYpO1xuICAgICAgdGhpcy4kbmF2SXRlbXMgPSB0aGlzLiRuYXYuZmluZCh0aGlzLm9wdHMubmF2SXRlbXMpO1xuXG4gICAgICB0aGlzLiR3cmFwID0gdGhpcy4kZWwuZmluZCh0aGlzLm9wdHMud3JhcCk7XG4gICAgICB0aGlzLiRzdGVwcyA9IHRoaXMuJHdyYXAuZmluZCh0aGlzLm9wdHMuc3RlcCk7XG5cbiAgICAgIGlmICh0aGlzLm9wdHMuYnVpbGROYXZJdGVtcykgdGhpcy5fYnVpbGROYXZJdGVtcygpO1xuXG4gICAgICB0aGlzLiRzdGVwcy5oaWRlKCkuZmlyc3QoKS5zaG93KCk7XG4gICAgICB0aGlzLiRuYXZJdGVtcy5yZW1vdmVDbGFzcyhhY3RpdmUpLmZpcnN0KCkuYWRkQ2xhc3MoYWN0aXZlKTtcblxuICAgICAgdGhpcy4kbmF2SXRlbXMuY2xpY2soZnVuY3Rpb24oKSB7XG4gICAgICAgIHNlbGYuZ28oc2VsZi4kbmF2SXRlbXMuaW5kZXgodGhpcykpO1xuICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9idWlsZE5hdkl0ZW1zOiBmdW5jdGlvbigpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxuICAgICAgICAgIGlzQ3VzdG9tID0gdHlwZW9mIHRoaXMub3B0cy5idWlsZE5hdkl0ZW1zID09ICdmdW5jdGlvbicsXG4gICAgICAgICAgaXRlbSA9IGZ1bmN0aW9uKHZhbCl7IHJldHVybiAnPGxpPjxhIGhyZWY9XCIjXCIgdGFiaW5kZXg9XCItMVwiPicrIHZhbCArJzwvYT48L2xpPic7IH0sXG4gICAgICAgICAgaXRlbXM7XG5cbiAgICAgIGl0ZW1zID0gaXNDdXN0b20gP1xuICAgICAgICB0aGlzLiRzdGVwcy5tYXAoZnVuY3Rpb24oaSl7IHJldHVybiBpdGVtKHNlbGYub3B0cy5idWlsZE5hdkl0ZW1zLmNhbGwoc2VsZiwgaSkpIH0pLmdldCgpIDpcbiAgICAgICAgdGhpcy4kc3RlcHMubWFwKGZ1bmN0aW9uKGkpeyByZXR1cm4gaXRlbSgrK2kpOyB9KS5nZXQoKTtcblxuICAgICAgdGhpcy4kbmF2SXRlbXMgPSAkKGl0ZW1zLmpvaW4oJycpKTtcblxuICAgICAgdGhpcy4kbmF2LmFwcGVuZCgkKCc8dWwvPicpLmFwcGVuZCh0aGlzLiRuYXZJdGVtcykpO1xuICAgIH0sXG5cbiAgICBfZ2V0Q3VySWR4OiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiB0aGlzLiRzdGVwcy5pbmRleCh0aGlzLiRzdGVwcy5maWx0ZXIoJzp2aXNpYmxlJykpO1xuICAgIH0sXG5cbiAgICBnbzogZnVuY3Rpb24oaWR4KSB7XG5cbiAgICAgIHZhciBhY3RpdmUgPSB0aGlzLm9wdHMuYWN0aXZlQ2xhc3MsXG4gICAgICAgICAgZmFkZVNwZWVkID0gdGhpcy5vcHRzLmZhZGVTcGVlZDtcblxuICAgICAgaWYgKHR5cGVvZiBpZHggPT0gJ2Z1bmN0aW9uJykgaWR4ID0gaWR4LmNhbGwodGhpcywgdGhpcy5fZ2V0Q3VySWR4KCkpO1xuXG4gICAgICBpZiAoaWR4ID49IHRoaXMuJHN0ZXBzLmxlbmd0aCkgaWR4ID0gMDtcbiAgICAgIGlmIChpZHggPCAwKSBpZHggPSB0aGlzLiRzdGVwcy5sZW5ndGgtMTtcblxuICAgICAgaWYgKHRoaXMub3B0cy5iZWZvcmUpIHRoaXMub3B0cy5iZWZvcmUuY2FsbCh0aGlzLCBpZHgpO1xuXG4gICAgICB0aGlzLiRuYXZJdGVtcy5yZW1vdmVDbGFzcyhhY3RpdmUpLmVxKGlkeCkuYWRkQ2xhc3MoYWN0aXZlKTtcbiAgICAgIHRoaXMuJHN0ZXBzLmZhZGVPdXQoZmFkZVNwZWVkKS5lcShpZHgpLmZhZGVJbihmYWRlU3BlZWQpO1xuXG4gICAgICBpZiAodGhpcy5vcHRzLmFmdGVyKSB0aGlzLm9wdHMuYWZ0ZXIuY2FsbCh0aGlzLCBpZHgpO1xuICAgIH0sXG5cbiAgICBwcmV2OiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMuZ28odGhpcy5fZ2V0Q3VySWR4KCkgLSAxKTtcbiAgICB9LFxuXG4gICAgbmV4dDogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLmdvKHRoaXMuX2dldEN1cklkeCgpICsgMSk7XG4gICAgfSxcblxuICAgIGZpcnN0OiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMuZ28oMCk7XG4gICAgfSxcblxuICAgIGxhc3Q6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5nbyh0aGlzLiRzdGVwcy5sZW5ndGgtMSk7XG4gICAgfVxuICB9O1xuXG4gIHJlcXVpcmUoJy4uLy4uL3BsdWdpbicpKHBsdWdpbik7XG5cbn0oalF1ZXJ5LCB3aW5kb3csIGRvY3VtZW50KSk7XG4iLCJyZXF1aXJlKCcuL2lkZWFsc3RlcHMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG5cbiAgbmFtZTogJ3N0ZXBzJyxcblxuICBvcHRpb25zOiB7XG4gICAgc3RlcHNDb250YWluZXI6ICcuaWRlYWxzdGVwcy1jb250YWluZXInLFxuICAgIHN0ZXBzT3B0aW9uczoge31cbiAgfSxcblxuICBtZXRob2RzOiB7XG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5fYnVpbGRTdGVwcygpO1xuICAgIH0sXG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgX3ZhbGlkYXRlOiBmdW5jdGlvbigpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICB0aGlzLl91cGRhdGVTdGVwcygpO1xuXG4gICAgICBpZiAoJC5pZGVhbGZvcm1zLmhhc0V4dGVuc2lvbignaWRlYWxBamF4JykpIHtcbiAgICAgICAgJC5lYWNoKCQuaWRlYWxmb3Jtcy5fcmVxdWVzdHMsIGZ1bmN0aW9uKGtleSwgcmVxdWVzdCkge1xuICAgICAgICAgIHJlcXVlc3QuZG9uZShmdW5jdGlvbigpeyBzZWxmLl91cGRhdGVTdGVwcygpIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLy8gQGV4dGVuZFxuICAgIGZvY3VzRmlyc3RJbnZhbGlkOiBmdW5jdGlvbihmaXJzdEludmFsaWQpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICB0aGlzLiRzdGVwc0NvbnRhaW5lci5pZGVhbHN0ZXBzKCdnbycsIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy4kc3RlcHMuZmlsdGVyKGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHJldHVybiAkKHRoaXMpLmZpbmQoZmlyc3RJbnZhbGlkKS5sZW5ndGg7XG4gICAgICAgIH0pLmluZGV4KCk7XG4gICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2J1aWxkU3RlcHM6IGZ1bmN0aW9uKCkge1xuXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsIG9wdGlvbnNcbiAgICAgICAgLCBoYXNSdWxlcyA9ICEgJC5pc0VtcHR5T2JqZWN0KHRoaXMub3B0cy5ydWxlcylcbiAgICAgICAgLCBjb3VudGVyID0gaGFzUnVsZXNcbiAgICAgICAgICA/ICc8c3BhbiBjbGFzcz1cImNvdW50ZXJcIi8+J1xuICAgICAgICAgIDogJzxzcGFuIGNsYXNzPVwiY291bnRlciB6ZXJvXCI+MDwvc3Bhbj4nO1xuXG4gICAgICBvcHRpb25zID0gJC5leHRlbmQoe30sIHtcbiAgICAgICAgYnVpbGROYXZJdGVtczogZnVuY3Rpb24oaSl7IHJldHVybiAnU3RlcCAnKyAoaSsxKSArIGNvdW50ZXIgfVxuICAgICAgfSwgdGhpcy5vcHRzLnN0ZXBzT3B0aW9ucyk7XG5cbiAgICAgIHRoaXMuJHN0ZXBzQ29udGFpbmVyID0gdGhpcy4kZm9ybS5jbG9zZXN0KHRoaXMub3B0cy5zdGVwc0NvbnRhaW5lcikuaWRlYWxzdGVwcyhvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgX3VwZGF0ZVN0ZXBzOiBmdW5jdGlvbigpIHtcblxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICB0aGlzLiRzdGVwc0NvbnRhaW5lci5pZGVhbHN0ZXBzKCdfaW5qZWN0JywgZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgdmFyIGlkZWFsc3RlcHMgPSB0aGlzO1xuXG4gICAgICAgIHRoaXMuJG5hdkl0ZW1zLmVhY2goZnVuY3Rpb24oaSkge1xuICAgICAgICAgIHZhciBpbnZhbGlkID0gaWRlYWxzdGVwcy4kc3RlcHMuZXEoaSkuZmluZChzZWxmLmdldEludmFsaWQoKSkubGVuZ3RoO1xuICAgICAgICAgICQodGhpcykuZmluZCgnc3BhbicpLnRleHQoaW52YWxpZCkudG9nZ2xlQ2xhc3MoJ3plcm8nLCAhIGludmFsaWQpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgYWRkUnVsZXM6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5maXJzdFN0ZXAoKTtcbiAgICB9LFxuXG4gICAgLy8gQGV4dGVuZFxuICAgIHRvZ2dsZUZpZWxkczogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLl91cGRhdGVTdGVwcygpO1xuICAgIH0sXG5cbiAgICAvLyBAZXh0ZW5kXG4gICAgcmVtb3ZlRmllbGRzOiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMuX3VwZGF0ZVN0ZXBzKCk7XG4gICAgfSxcblxuICAgIGdvVG9TdGVwOiBmdW5jdGlvbihpZHgpIHtcbiAgICAgIHRoaXMuJHN0ZXBzQ29udGFpbmVyLmlkZWFsc3RlcHMoJ2dvJywgaWR4KTtcbiAgICB9LFxuXG4gICAgcHJldlN0ZXA6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy4kc3RlcHNDb250YWluZXIuaWRlYWxzdGVwcygncHJldicpO1xuICAgIH0sXG5cbiAgICBuZXh0U3RlcDogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLiRzdGVwc0NvbnRhaW5lci5pZGVhbHN0ZXBzKCduZXh0Jyk7XG4gICAgfSxcblxuICAgIGZpcnN0U3RlcDogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLiRzdGVwc0NvbnRhaW5lci5pZGVhbHN0ZXBzKCdmaXJzdCcpO1xuICAgIH0sXG5cbiAgICBsYXN0U3RlcDogZnVuY3Rpb24oKSB7XG4gICAgICB0aGlzLiRzdGVwc0NvbnRhaW5lci5pZGVhbHN0ZXBzKCdsYXN0Jyk7XG4gICAgfVxuICB9XG5cbn07XG4iLCIvKiFcbiAqIGpRdWVyeSBJZGVhbCBGb3Jtc1xuICogQGF1dGhvcjogQ2VkcmljIFJ1aXpcbiAqIEB2ZXJzaW9uOiAzLjBcbiAqIEBsaWNlbnNlIEdQTCBvciBNSVRcbiAqL1xuKGZ1bmN0aW9uKCQsIHdpbiwgZG9jLCB1bmRlZmluZWQpIHtcblxuICB2YXIgcGx1Z2luID0ge307XG5cbiAgcGx1Z2luLm5hbWUgPSAnaWRlYWxmb3Jtcyc7XG5cbiAgcGx1Z2luLmRlZmF1bHRzID0ge1xuICAgIGZpZWxkOiAnLmZpZWxkJyxcbiAgICBlcnJvcjogJy5lcnJvcicsXG4gICAgaWNvbkh0bWw6ICc8aS8+JyxcbiAgICBpY29uQ2xhc3M6ICdpY29uJyxcbiAgICBpbnZhbGlkQ2xhc3M6ICdpbnZhbGlkJyxcbiAgICB2YWxpZENsYXNzOiAndmFsaWQnLFxuICAgIHNpbGVudExvYWQ6IHRydWUsXG4gICAgb25WYWxpZGF0ZTogJC5ub29wLFxuICAgIG9uU3VibWl0OiAkLm5vb3BcbiAgfTtcblxuICBwbHVnaW4uZ2xvYmFsID0ge1xuXG4gICAgX2Zvcm1hdDogZnVuY3Rpb24oc3RyKSB7XG4gICAgICB2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgIHJldHVybiBzdHIucmVwbGFjZSgvXFx7KFxcZClcXH0vZywgZnVuY3Rpb24oXywgbWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3NbK21hdGNoXSB8fCAnJztcbiAgICAgIH0pLnJlcGxhY2UoL1xce1xcKihbXip9XSopXFx9L2csIGZ1bmN0aW9uKF8sIHNlcCkge1xuICAgICAgICByZXR1cm4gYXJncy5qb2luKHNlcCB8fCAnLCAnKTtcbiAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfZ2V0S2V5OiBmdW5jdGlvbihrZXksIG9iaikge1xuICAgICAgcmV0dXJuIGtleS5zcGxpdCgnLicpLnJlZHVjZShmdW5jdGlvbihhLGIpIHtcbiAgICAgICAgcmV0dXJuIGEgJiYgYVtiXTtcbiAgICAgIH0sIG9iaik7XG4gICAgfSxcblxuICAgIHJ1bGVTZXBhcmF0b3I6ICcgJyxcbiAgICBhcmdTZXBhcmF0b3I6ICc6JyxcblxuICAgIHJ1bGVzOiByZXF1aXJlKCcuL3J1bGVzJyksXG4gICAgZXJyb3JzOiByZXF1aXJlKCcuL2Vycm9ycycpLFxuXG4gICAgZXh0ZW5zaW9uczogW1xuICAgICAgcmVxdWlyZSgnLi9leHRlbnNpb25zL2R5bmFtaWMtZmllbGRzL2R5bmFtaWMtZmllbGRzLmV4dCcpLFxuICAgICAgcmVxdWlyZSgnLi9leHRlbnNpb25zL2FqYXgvYWpheC5leHQnKSxcbiAgICAgIHJlcXVpcmUoJy4vZXh0ZW5zaW9ucy9zdGVwcy9zdGVwcy5leHQnKSxcbiAgICAgIHJlcXVpcmUoJy4vZXh0ZW5zaW9ucy9jdXN0b20taW5wdXRzL2N1c3RvbS1pbnB1dHMuZXh0JyksXG4gICAgICByZXF1aXJlKCcuL2V4dGVuc2lvbnMvZGF0ZXBpY2tlci9kYXRlcGlja2VyLmV4dCcpXG4gICAgXVxuICB9O1xuXG4gIHBsdWdpbi5tZXRob2RzID0gJC5leHRlbmQoe30sIHJlcXVpcmUoJy4vcHJpdmF0ZScpLCByZXF1aXJlKCcuL3B1YmxpYycpKTtcblxuICByZXF1aXJlKCcuL3BsdWdpbicpKHBsdWdpbik7XG5cbn0oalF1ZXJ5LCB3aW5kb3csIGRvY3VtZW50KSk7XG4iLCIvKipcbiAqIFBsdWdpbiBib2lsZXJwbGF0ZVxuICovXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbigpIHtcblxuICB2YXIgQVAgPSBBcnJheS5wcm90b3R5cGU7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uKHBsdWdpbikge1xuXG4gICAgJC5leHRlbmQoe1xuICAgICAgbmFtZTogJ3BsdWdpbicsXG4gICAgICBkZWZhdWx0czoge30sXG4gICAgICBtZXRob2RzOiB7fSxcbiAgICAgIGdsb2JhbDoge30sXG4gICAgfSwgcGx1Z2luKTtcblxuICAgICRbcGx1Z2luLm5hbWVdID0gJC5leHRlbmQoe1xuXG4gICAgICBhZGRFeHRlbnNpb246IGZ1bmN0aW9uKGV4dGVuc2lvbikge1xuICAgICAgICBwbHVnaW4uZ2xvYmFsLmV4dGVuc2lvbnMucHVzaChleHRlbnNpb24pO1xuICAgICAgfSxcblxuICAgICAgaGFzRXh0ZW5zaW9uOiBmdW5jdGlvbihleHRlbnNpb24pIHtcbiAgICAgICAgcmV0dXJuIHBsdWdpbi5nbG9iYWwuZXh0ZW5zaW9ucy5maWx0ZXIoZnVuY3Rpb24oZXh0KSB7XG4gICAgICAgICAgcmV0dXJuIGV4dC5uYW1lID09IGV4dGVuc2lvbjtcbiAgICAgICAgfSkubGVuZ3RoO1xuICAgICAgfVxuICAgIH0sIHBsdWdpbi5nbG9iYWwpO1xuXG4gICAgZnVuY3Rpb24gUGx1Z2luKGVsZW1lbnQsIG9wdGlvbnMpIHtcblxuICAgICAgdGhpcy5vcHRzID0gJC5leHRlbmQoe30sIHBsdWdpbi5kZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgICB0aGlzLmVsID0gZWxlbWVudDtcblxuICAgICAgdGhpcy5fbmFtZSA9IHBsdWdpbi5uYW1lO1xuXG4gICAgICB0aGlzLl9pbml0KCk7XG4gICAgfVxuXG4gICAgUGx1Z2luLl9leHRlbmRlZCA9IHt9O1xuXG4gICAgUGx1Z2luLnByb3RvdHlwZS5fZXh0ZW5kID0gZnVuY3Rpb24oZXh0ZW5zaW9ucykge1xuXG4gICAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICAgICAgLCBkaXNhYmxlZCA9IHNlbGYub3B0cy5kaXNhYmxlZEV4dGVuc2lvbnMgfHwgJ25vbmUnO1xuXG4gICAgICAkLmVhY2goZXh0ZW5zaW9ucywgZnVuY3Rpb24oaSwgZXh0ZW5zaW9uKSB7XG5cbiAgICAgICAgJC5leHRlbmQoc2VsZi5vcHRzLCAkLmV4dGVuZCh0cnVlLCBleHRlbnNpb24ub3B0aW9ucywgc2VsZi5vcHRzKSk7XG5cbiAgICAgICAgJC5lYWNoKGV4dGVuc2lvbi5tZXRob2RzLCBmdW5jdGlvbihtZXRob2QsIGZuKSB7XG5cbiAgICAgICAgICBpZiAoZGlzYWJsZWQuaW5kZXhPZihleHRlbnNpb24ubmFtZSkgPiAtMSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChQbHVnaW4ucHJvdG90eXBlW21ldGhvZF0pIHtcbiAgICAgICAgICAgIFBsdWdpbi5fZXh0ZW5kZWRbbWV0aG9kXSA9IFBsdWdpbi5fZXh0ZW5kZWRbbWV0aG9kXSB8fCBbXTtcbiAgICAgICAgICAgIFBsdWdpbi5fZXh0ZW5kZWRbbWV0aG9kXS5wdXNoKHsgbmFtZTogZXh0ZW5zaW9uLm5hbWUsIGZuOiBmbiB9KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgUGx1Z2luLnByb3RvdHlwZVttZXRob2RdID0gZm47XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIFBsdWdpbi5wcm90b3R5cGUuX2luamVjdCA9IGZ1bmN0aW9uKG1ldGhvZCkge1xuXG4gICAgICB2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcblxuICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT0gJ2Z1bmN0aW9uJykgcmV0dXJuIG1ldGhvZC5jYWxsKHRoaXMpO1xuXG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgIGlmIChQbHVnaW4uX2V4dGVuZGVkW21ldGhvZF0pIHtcbiAgICAgICAgJC5lYWNoKFBsdWdpbi5fZXh0ZW5kZWRbbWV0aG9kXSwgZnVuY3Rpb24oaSwgcGx1Z2luKSB7XG4gICAgICAgICAgcGx1Z2luLmZuLmFwcGx5KHNlbGYsIGFyZ3MpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgUGx1Z2luLnByb3RvdHlwZS5faW5pdCA9ICQubm9vcDtcblxuICAgIFBsdWdpbi5wcm90b3R5cGVbcGx1Z2luLm5hbWVdID0gZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICBpZiAoIW1ldGhvZCkgcmV0dXJuIHRoaXM7XG4gICAgICB0cnkgeyByZXR1cm4gdGhpc1ttZXRob2RdLmFwcGx5KHRoaXMsIEFQLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7IH1cbiAgICAgIGNhdGNoKGUpIHt9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKFBsdWdpbi5wcm90b3R5cGUsIHBsdWdpbi5tZXRob2RzKTtcblxuICAgICQuZm5bcGx1Z2luLm5hbWVdID0gZnVuY3Rpb24oKSB7XG5cbiAgICAgIHZhciBhcmdzID0gQVAuc2xpY2UuY2FsbChhcmd1bWVudHMpXG4gICAgICAgICwgbWV0aG9kQXJyYXkgPSB0eXBlb2YgYXJnc1swXSA9PSAnc3RyaW5nJyAmJiBhcmdzWzBdLnNwbGl0KCc6JylcbiAgICAgICAgLCBtZXRob2QgPSBtZXRob2RBcnJheVttZXRob2RBcnJheS5sZW5ndGggPiAxID8gMSA6IDBdXG4gICAgICAgICwgcHJlZml4ID0gbWV0aG9kQXJyYXkubGVuZ3RoID4gMSAmJiBtZXRob2RBcnJheVswXVxuICAgICAgICAsIG9wdHMgPSB0eXBlb2YgYXJnc1swXSA9PSAnb2JqZWN0JyAmJiBhcmdzWzBdXG4gICAgICAgICwgcGFyYW1zID0gYXJncy5zbGljZSgxKVxuICAgICAgICAsIHJldDtcblxuICAgICAgaWYgKHByZWZpeCkge1xuICAgICAgICBtZXRob2QgPSBwcmVmaXggKyBtZXRob2Quc3Vic3RyKDAsMSkudG9VcHBlckNhc2UoKSArIG1ldGhvZC5zdWJzdHIoMSxtZXRob2QubGVuZ3RoLTEpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgdmFyIGluc3RhbmNlID0gJC5kYXRhKHRoaXMsIHBsdWdpbi5uYW1lKTtcblxuICAgICAgICAvLyBNZXRob2RcbiAgICAgICAgaWYgKGluc3RhbmNlKSB7XG4gICAgICAgICAgcmV0dXJuIHJldCA9IGluc3RhbmNlW3BsdWdpbi5uYW1lXS5hcHBseShpbnN0YW5jZSwgW21ldGhvZF0uY29uY2F0KHBhcmFtcykpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSW5pdFxuICAgICAgICByZXR1cm4gJC5kYXRhKHRoaXMsIHBsdWdpbi5uYW1lLCBuZXcgUGx1Z2luKHRoaXMsIG9wdHMpKTtcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gcHJlZml4ID8gcmV0IDogdGhpcztcbiAgICB9O1xuICB9O1xuXG59KCkpO1xuIiwiLyoqXG4gKiBQcml2YXRlIG1ldGhvZHNcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSB7XG5cbiAgX2luaXQ6IGZ1bmN0aW9uKCkge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdGhpcy5fZXh0ZW5kKCQuaWRlYWxmb3Jtcy5leHRlbnNpb25zKTtcblxuICAgIHRoaXMuJGZvcm0gPSAkKHRoaXMuZWwpO1xuICAgIHRoaXMuJGZpZWxkcyA9ICQoKTtcbiAgICB0aGlzLiRpbnB1dHMgPSAkKCk7XG5cbiAgICB0aGlzLiRmb3JtLnN1Ym1pdChmdW5jdGlvbihlKSB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBzZWxmLmZvY3VzRmlyc3RJbnZhbGlkKCk7XG4gICAgICBzZWxmLm9wdHMub25TdWJtaXQuY2FsbCh0aGlzLCBzZWxmLmdldEludmFsaWQoKS5sZW5ndGgsIGUpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5faW5qZWN0KCdfaW5pdCcpO1xuXG4gICAgdGhpcy5hZGRSdWxlcyh0aGlzLm9wdHMucnVsZXMgfHwge30pO1xuXG4gICAgaWYgKCEgdGhpcy5vcHRzLnNpbGVudExvYWQpIHRoaXMuZm9jdXNGaXJzdEludmFsaWQoKTtcbiAgfSxcblxuICBfYnVpbGRGaWVsZDogZnVuY3Rpb24oaW5wdXQpIHtcblxuICAgIHZhciBzZWxmID0gdGhpc1xuICAgICAgLCAkZmllbGQgPSB0aGlzLl9nZXRGaWVsZChpbnB1dClcbiAgICAgICwgJGljb247XG5cbiAgICAkaWNvbiA9ICQodGhpcy5vcHRzLmljb25IdG1sLCB7XG4gICAgICBjbGFzczogdGhpcy5vcHRzLmljb25DbGFzcyxcbiAgICAgIGNsaWNrOiBmdW5jdGlvbigpeyAkKGlucHV0KS5mb2N1cygpIH1cbiAgICB9KTtcblxuICAgIGlmICghIHRoaXMuJGZpZWxkcy5maWx0ZXIoJGZpZWxkKS5sZW5ndGgpIHtcbiAgICAgIHRoaXMuJGZpZWxkcyA9IHRoaXMuJGZpZWxkcy5hZGQoJGZpZWxkKTtcbiAgICAgIGlmICh0aGlzLm9wdHMuaWNvbkh0bWwpICRmaWVsZC5hcHBlbmQoJGljb24pO1xuICAgICAgJGZpZWxkLmFkZENsYXNzKCdpZGVhbGZvcm1zLWZpZWxkIGlkZWFsZm9ybXMtZmllbGQtJysgaW5wdXQudHlwZSk7XG4gICAgfVxuXG4gICAgdGhpcy5fYWRkRXZlbnRzKGlucHV0KTtcblxuICAgIHRoaXMuX2luamVjdCgnX2J1aWxkRmllbGQnLCBpbnB1dCk7XG4gIH0sXG5cbiAgX2FkZEV2ZW50czogZnVuY3Rpb24oaW5wdXQpIHtcblxuICAgIHZhciBzZWxmID0gdGhpc1xuICAgICAgLCAkZmllbGQgPSB0aGlzLl9nZXRGaWVsZChpbnB1dCk7XG5cbiAgICAkKGlucHV0KVxuICAgICAgLm9uKCdjaGFuZ2Uga2V5dXAnLCBmdW5jdGlvbihlKSB7XG5cbiAgICAgICAgdmFyIG9sZFZhbHVlID0gJGZpZWxkLmRhdGEoJ2lkZWFsZm9ybXMtdmFsdWUnKTtcblxuICAgICAgICBpZiAoZS53aGljaCA9PSA5IHx8IGUud2hpY2ggPT0gMTYpIHJldHVybjtcbiAgICAgICAgaWYgKCEgJCh0aGlzKS5pcygnOmNoZWNrYm94LCA6cmFkaW8nKSAmJiBvbGRWYWx1ZSA9PSB0aGlzLnZhbHVlKSByZXR1cm47XG5cbiAgICAgICAgJGZpZWxkLmRhdGEoJ2lkZWFsZm9ybXMtdmFsdWUnLCB0aGlzLnZhbHVlKTtcblxuICAgICAgICBzZWxmLl92YWxpZGF0ZSh0aGlzLCB0cnVlLCB0cnVlKTtcbiAgICAgIH0pXG4gICAgICAuZm9jdXMoZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgaWYgKHNlbGYuaXNWYWxpZCh0aGlzLm5hbWUpKSByZXR1cm4gZmFsc2U7XG5cbiAgICAgICAgaWYgKHNlbGYuX2lzUmVxdWlyZWQodGhpcykgfHwgdGhpcy52YWx1ZSkge1xuICAgICAgICAgICRmaWVsZC5maW5kKHNlbGYub3B0cy5lcnJvcikuc2hvdygpO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgLmJsdXIoZnVuY3Rpb24oKSB7XG4gICAgICAgICRmaWVsZC5maW5kKHNlbGYub3B0cy5lcnJvcikuaGlkZSgpO1xuICAgICAgfSk7XG4gIH0sXG5cbiAgX2lzUmVxdWlyZWQ6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgLy8gV2UgYXNzdW1lIG5vbi10ZXh0IGlucHV0cyB3aXRoIHJ1bGVzIGFyZSByZXF1aXJlZFxuICAgIGlmICgkKGlucHV0KS5pcygnOmNoZWNrYm94LCA6cmFkaW8sIHNlbGVjdCcpKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdGhpcy5vcHRzLnJ1bGVzW2lucHV0Lm5hbWVdLmluZGV4T2YoJ3JlcXVpcmVkJykgPiAtMTtcbiAgfSxcblxuICBfZ2V0UmVsYXRlZDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICByZXR1cm4gdGhpcy5fZ2V0RmllbGQoaW5wdXQpLmZpbmQoJ1tuYW1lPVwiJysgaW5wdXQubmFtZSArJ1wiXScpO1xuICB9LFxuXG4gIF9nZXRGaWVsZDogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICByZXR1cm4gJChpbnB1dCkuY2xvc2VzdCh0aGlzLm9wdHMuZmllbGQpO1xuICB9LFxuXG4gIF9nZXRGaXJzdEludmFsaWQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLmdldEludmFsaWQoKS5maXJzdCgpLmZpbmQoJ2lucHV0OmZpcnN0LCB0ZXh0YXJlYSwgc2VsZWN0Jyk7XG4gIH0sXG5cbiAgX2hhbmRsZUVycm9yOiBmdW5jdGlvbihpbnB1dCwgZXJyb3IsIHZhbGlkKSB7XG4gICAgdmFsaWQgPSB2YWxpZCB8fCB0aGlzLmlzVmFsaWQoaW5wdXQubmFtZSk7XG4gICAgdmFyICRlcnJvciA9IHRoaXMuX2dldEZpZWxkKGlucHV0KS5maW5kKHRoaXMub3B0cy5lcnJvcik7XG4gICAgdGhpcy4kZm9ybS5maW5kKHRoaXMub3B0cy5lcnJvcikuaGlkZSgpO1xuICAgIGlmIChlcnJvcikgJGVycm9yLnRleHQoZXJyb3IpO1xuICAgICRlcnJvci50b2dnbGUoIXZhbGlkKTtcbiAgfSxcblxuICBfaGFuZGxlU3R5bGU6IGZ1bmN0aW9uKGlucHV0LCB2YWxpZCkge1xuICAgIHZhbGlkID0gdmFsaWQgfHwgdGhpcy5pc1ZhbGlkKGlucHV0Lm5hbWUpO1xuICAgIHRoaXMuX2dldEZpZWxkKGlucHV0KVxuICAgICAgLnJlbW92ZUNsYXNzKHRoaXMub3B0cy52YWxpZENsYXNzICsnICcrIHRoaXMub3B0cy5pbnZhbGlkQ2xhc3MpXG4gICAgICAuYWRkQ2xhc3ModmFsaWQgPyB0aGlzLm9wdHMudmFsaWRDbGFzcyA6IHRoaXMub3B0cy5pbnZhbGlkQ2xhc3MpXG4gICAgICAuZmluZCgnLicrIHRoaXMub3B0cy5pY29uQ2xhc3MpLnNob3coKTtcbiAgfSxcblxuICBfZnJlc2g6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgdGhpcy5fZ2V0RmllbGQoaW5wdXQpXG4gICAgICAucmVtb3ZlQ2xhc3ModGhpcy5vcHRzLnZhbGlkQ2xhc3MgKycgJysgdGhpcy5vcHRzLmludmFsaWRDbGFzcylcbiAgICAgIC5maW5kKHRoaXMub3B0cy5lcnJvcikuaGlkZSgpXG4gICAgICAuZW5kKClcbiAgICAgIC5maW5kKCcuJysgdGhpcy5vcHRzLmljb25DbGFzcykudG9nZ2xlKHRoaXMuX2lzUmVxdWlyZWQoaW5wdXQpKTtcbiAgfSxcblxuICBfdmFsaWRhdGU6IGZ1bmN0aW9uKGlucHV0LCBoYW5kbGVFcnJvciwgaGFuZGxlU3R5bGUpIHtcblxuICAgIHZhciBzZWxmID0gdGhpc1xuICAgICAgLCAkZmllbGQgPSB0aGlzLl9nZXRGaWVsZChpbnB1dClcbiAgICAgICwgdXNlclJ1bGVzID0gdGhpcy5vcHRzLnJ1bGVzW2lucHV0Lm5hbWVdLnNwbGl0KCQuaWRlYWxmb3Jtcy5ydWxlU2VwYXJhdG9yKVxuICAgICAgLCB2YWxpZCA9IHRydWVcbiAgICAgICwgcnVsZTtcblxuICAgIC8vIE5vbi1yZXF1aXJlZCBpbnB1dCB3aXRoIGVtcHR5IHZhbHVlIG11c3QgcGFzcyB2YWxpZGF0aW9uXG4gICAgaWYgKCEgaW5wdXQudmFsdWUgJiYgISB0aGlzLl9pc1JlcXVpcmVkKGlucHV0KSkge1xuICAgICAgJGZpZWxkLnJlbW92ZURhdGEoJ2lkZWFsZm9ybXMtdmFsaWQnKTtcbiAgICAgIHRoaXMuX2ZyZXNoKGlucHV0KTtcblxuICAgIC8vIFJlcXVpcmVkIGlucHV0c1xuICAgIH0gZWxzZSB7XG5cbiAgICAgICQuZWFjaCh1c2VyUnVsZXMsIGZ1bmN0aW9uKGksIHVzZXJSdWxlKSB7XG5cbiAgICAgICAgdXNlclJ1bGUgPSB1c2VyUnVsZS5zcGxpdCgkLmlkZWFsZm9ybXMuYXJnU2VwYXJhdG9yKTtcblxuICAgICAgICBydWxlID0gdXNlclJ1bGVbMF07XG5cbiAgICAgICAgdmFyIHRoZVJ1bGUgPSAkLmlkZWFsZm9ybXMucnVsZXNbcnVsZV1cbiAgICAgICAgICAsIGFyZ3MgPSB1c2VyUnVsZS5zbGljZSgxKVxuICAgICAgICAgICwgZXJyb3I7XG5cbiAgICAgICAgZXJyb3IgPSAkLmlkZWFsZm9ybXMuX2Zvcm1hdC5hcHBseShudWxsLCBbXG4gICAgICAgICAgJC5pZGVhbGZvcm1zLl9nZXRLZXkoJ2Vycm9ycy4nKyBpbnB1dC5uYW1lICsnLicrIHJ1bGUsIHNlbGYub3B0cykgfHxcbiAgICAgICAgICAkLmlkZWFsZm9ybXMuZXJyb3JzW3J1bGVdXG4gICAgICAgIF0uY29uY2F0KGFyZ3MpKTtcblxuICAgICAgICB2YWxpZCA9IHR5cGVvZiB0aGVSdWxlID09ICdmdW5jdGlvbidcbiAgICAgICAgICA/IHRoZVJ1bGUuYXBwbHkoc2VsZiwgW2lucHV0LCBpbnB1dC52YWx1ZV0uY29uY2F0KGFyZ3MpKVxuICAgICAgICAgIDogdGhlUnVsZS50ZXN0KGlucHV0LnZhbHVlKTtcblxuICAgICAgICAkZmllbGQuZGF0YSgnaWRlYWxmb3Jtcy12YWxpZCcsIHZhbGlkKTtcblxuICAgICAgICBpZiAoaGFuZGxlRXJyb3IpIHNlbGYuX2hhbmRsZUVycm9yKGlucHV0LCBlcnJvciwgdmFsaWQpO1xuICAgICAgICBpZiAoaGFuZGxlU3R5bGUpIHNlbGYuX2hhbmRsZVN0eWxlKGlucHV0LCB2YWxpZCk7XG5cbiAgICAgICAgc2VsZi5vcHRzLm9uVmFsaWRhdGUuY2FsbChzZWxmLCBpbnB1dCwgcnVsZSwgdmFsaWQpO1xuXG4gICAgICAgIHJldHVybiB2YWxpZDtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMuX2luamVjdCgnX3ZhbGlkYXRlJywgaW5wdXQsIHJ1bGUsIHZhbGlkKTtcblxuICAgIHJldHVybiB2YWxpZDtcbiAgfVxuXG59O1xuIiwiLyoqXG4gKiBQdWJsaWMgbWV0aG9kc1xuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcblxuICBhZGRSdWxlczogZnVuY3Rpb24ocnVsZXMpIHtcblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHZhciAkaW5wdXRzID0gdGhpcy4kZm9ybS5maW5kKCQubWFwKHJ1bGVzLCBmdW5jdGlvbihfLCBuYW1lKSB7XG4gICAgICByZXR1cm4gJ1tuYW1lPVwiJysgbmFtZSArJ1wiXSc7XG4gICAgfSkuam9pbignLCcpKTtcblxuICAgICQuZXh0ZW5kKHRoaXMub3B0cy5ydWxlcywgcnVsZXMpO1xuXG4gICAgJGlucHV0cy5lYWNoKGZ1bmN0aW9uKCl7IHNlbGYuX2J1aWxkRmllbGQodGhpcykgfSk7XG5cbiAgICB0aGlzLiRpbnB1dHMgPSB0aGlzLiRpbnB1dHNcbiAgICAgIC5hZGQoJGlucHV0cylcbiAgICAgIC5lYWNoKGZ1bmN0aW9uKCl7IHNlbGYuX3ZhbGlkYXRlKHRoaXMsIHRydWUpIH0pO1xuXG4gICAgdGhpcy4kZmllbGRzLmZpbmQodGhpcy5vcHRzLmVycm9yKS5oaWRlKCk7XG5cbiAgICB0aGlzLl9pbmplY3QoJ2FkZFJ1bGVzJyk7XG4gIH0sXG5cbiAgZ2V0SW52YWxpZDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuJGZpZWxkcy5maWx0ZXIoZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gJCh0aGlzKS5kYXRhKCdpZGVhbGZvcm1zLXZhbGlkJykgPT09IGZhbHNlO1xuICAgIH0pO1xuICB9LFxuXG4gIGZvY3VzRmlyc3RJbnZhbGlkOiBmdW5jdGlvbigpIHtcblxuICAgIHZhciBmaXJzdEludmFsaWQgPSB0aGlzLl9nZXRGaXJzdEludmFsaWQoKVswXTtcblxuICAgIGlmIChmaXJzdEludmFsaWQpIHtcbiAgICAgIHRoaXMuX2hhbmRsZUVycm9yKGZpcnN0SW52YWxpZCk7XG4gICAgICB0aGlzLl9oYW5kbGVTdHlsZShmaXJzdEludmFsaWQpO1xuICAgICAgdGhpcy5faW5qZWN0KCdmb2N1c0ZpcnN0SW52YWxpZCcsIGZpcnN0SW52YWxpZCk7XG4gICAgICBmaXJzdEludmFsaWQuZm9jdXMoKTtcbiAgICB9XG4gIH0sXG5cbiAgaXNWYWxpZDogZnVuY3Rpb24obmFtZSkge1xuICAgIGlmIChuYW1lKSByZXR1cm4gISB0aGlzLmdldEludmFsaWQoKS5maW5kKCdbbmFtZT1cIicrIG5hbWUgKydcIl0nKS5sZW5ndGg7XG4gICAgcmV0dXJuICEgdGhpcy5nZXRJbnZhbGlkKCkubGVuZ3RoO1xuICB9LFxuXG4gIHJlc2V0OiBmdW5jdGlvbihuYW1lKSB7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICAgICwgJGlucHV0cyA9IHRoaXMuJGlucHV0cztcblxuICAgIGlmIChuYW1lKSAkaW5wdXRzID0gJGlucHV0cy5maWx0ZXIoJ1tuYW1lPVwiJysgbmFtZSArJ1wiXScpO1xuXG4gICAgJGlucHV0cy5maWx0ZXIoJ2lucHV0Om5vdCg6Y2hlY2tib3gsIDpyYWRpbyknKS52YWwoJycpO1xuICAgICRpbnB1dHMuZmlsdGVyKCc6Y2hlY2tib3gsIDpyYWRpbycpLnByb3AoJ2NoZWNrZWQnLCBmYWxzZSk7XG4gICAgJGlucHV0cy5maWx0ZXIoJ3NlbGVjdCcpLmZpbmQoJ29wdGlvbicpLnByb3AoJ3NlbGVjdGVkJywgZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gdGhpcy5kZWZhdWx0U2VsZWN0ZWQ7XG4gICAgfSk7XG5cbiAgICAkaW5wdXRzLmNoYW5nZSgpLmVhY2goZnVuY3Rpb24oKXsgc2VsZi5fcmVzZXRFcnJvckFuZFN0eWxlKHRoaXMpIH0pO1xuICB9XG5cbn07XG4iLCIvKipcbiAqIFJ1bGVzXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIHJlcXVpcmVkOiAvLisvLFxuICBkaWdpdHM6IC9eXFxkKyQvLFxuICBlbWFpbDogL15bXkBdK0BbXkBdK1xcLi57Miw2fSQvLFxuICB1c2VybmFtZTogL15bYS16XSg/PVtcXHcuXXszLDMxfSQpXFx3KlxcLj9cXHcqJC9pLFxuICBwYXNzOiAvKD89LipcXGQpKD89LipbYS16XSkoPz0uKltBLVpdKS57Nix9LyxcbiAgc3Ryb25ncGFzczogLyg/PV4uezgsfSQpKCg/PS4qXFxkKXwoPz0uKlxcVyspKSg/IVsuXFxuXSkoPz0uKltBLVpdKSg/PS4qW2Etel0pLiokLyxcbiAgcGhvbmU6IC9eWzItOV1cXGR7Mn0tXFxkezN9LVxcZHs0fSQvLFxuICB6aXA6IC9eXFxkezV9JHxeXFxkezV9LVxcZHs0fSQvLFxuICB1cmw6IC9eKD86KGZ0cHxodHRwfGh0dHBzKTpcXC9cXC8pPyg/OltcXHdcXC1dK1xcLikrW2Etel17Miw2fShbXFw6XFwvPyNdLiopPyQvaSxcblxuICBudW1iZXI6IGZ1bmN0aW9uKGlucHV0LCB2YWx1ZSkge1xuICAgIHJldHVybiAhaXNOYU4odmFsdWUpO1xuICB9LFxuXG4gIHJhbmdlOiBmdW5jdGlvbihpbnB1dCwgdmFsdWUsIG1peCwgbWF4KSB7XG4gICAgcmV0dXJuIE51bWJlcih2YWx1ZSkgPj0gbWluICYmIE51bWJlcih2YWx1ZSkgPD0gbWF4O1xuICB9LFxuXG4gIG1pbjogZnVuY3Rpb24oaW5wdXQsIHZhbHVlLCBtaW4pIHtcbiAgICByZXR1cm4gdmFsdWUubGVuZ3RoID49IG1pbjtcbiAgfSxcblxuICBtYXg6IGZ1bmN0aW9uKGlucHV0LCB2YWx1ZSwgbWF4KSB7XG4gICAgcmV0dXJuIHZhbHVlLmxlbmd0aCA8PSBtYXg7XG4gIH0sXG5cbiAgbWlub3B0aW9uOiBmdW5jdGlvbihpbnB1dCwgdmFsdWUsIG1pbikge1xuICAgIHJldHVybiB0aGlzLl9nZXRSZWxhdGVkKGlucHV0KS5maWx0ZXIoJzpjaGVja2VkJykubGVuZ3RoID49IG1pbjtcbiAgfSxcblxuICBtYXhvcHRpb246IGZ1bmN0aW9uKGlucHV0LCB2YWx1ZSwgbWF4KSB7XG4gICAgcmV0dXJuIHRoaXMuX2dldFJlbGF0ZWQoaW5wdXQpLmZpbHRlcignOmNoZWNrZWQnKS5sZW5ndGggPD0gbWF4O1xuICB9LFxuXG4gIG1pbm1heDogZnVuY3Rpb24oaW5wdXQsIHZhbHVlLCBtaW4sIG1heCkge1xuICAgIHJldHVybiB2YWx1ZS5sZW5ndGggPj0gbWluICYmIHZhbHVlLmxlbmd0aCA8PSBtYXg7XG4gIH0sXG5cbiAgc2VsZWN0OiBmdW5jdGlvbihpbnB1dCwgdmFsdWUsIGRlZikge1xuICAgIHJldHVybiB2YWx1ZSAhPSBkZWY7XG4gIH0sXG5cbiAgZXh0ZW5zaW9uOiBmdW5jdGlvbihpbnB1dCkge1xuXG4gICAgdmFyIGV4dGVuc2lvbnMgPSBbXS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSlcbiAgICAgICwgdmFsaWQgPSBmYWxzZTtcblxuICAgICQuZWFjaChpbnB1dC5maWxlcyB8fCBbe25hbWU6IGlucHV0LnZhbHVlfV0sIGZ1bmN0aW9uKGksIGZpbGUpIHtcbiAgICAgIHZhbGlkID0gJC5pbkFycmF5KGZpbGUubmFtZS5tYXRjaCgvXFwuKC4rKSQvKVsxXSwgZXh0ZW5zaW9ucykgPiAtMTtcbiAgICB9KTtcblxuICAgIHJldHVybiB2YWxpZDtcbiAgfSxcblxuICBlcXVhbHRvOiBmdW5jdGlvbihpbnB1dCwgdmFsdWUsIHRhcmdldCkge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzXG4gICAgICAsICR0YXJnZXQgPSAkKCdbbmFtZT1cIicrIHRhcmdldCArJ1wiXScpO1xuXG4gICAgaWYgKHRoaXMuZ2V0SW52YWxpZCgpLmZpbmQoJHRhcmdldCkubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG5cbiAgICAkdGFyZ2V0Lm9mZigna2V5dXAuZXF1YWx0bycpLm9uKCdrZXl1cC5lcXVhbHRvJywgZnVuY3Rpb24oKSB7XG4gICAgICBzZWxmLl92YWxpZGF0ZShpbnB1dCwgZmFsc2UsIHRydWUpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGlucHV0LnZhbHVlID09ICR0YXJnZXQudmFsKCk7XG4gIH0sXG5cbiAgZGF0ZTogZnVuY3Rpb24oaW5wdXQsIHZhbHVlLCBmb3JtYXQpIHtcblxuICAgIGZvcm1hdCA9IGZvcm1hdCB8fCAnbW0vZGQveXl5eSc7XG5cbiAgICB2YXIgZGVsaW1pdGVyID0gL1tebWR5XS8uZXhlYyhmb3JtYXQpWzBdXG4gICAgICAsIHRoZUZvcm1hdCA9IGZvcm1hdC5zcGxpdChkZWxpbWl0ZXIpXG4gICAgICAsIHRoZURhdGUgPSB2YWx1ZS5zcGxpdChkZWxpbWl0ZXIpO1xuXG4gICAgZnVuY3Rpb24gaXNEYXRlKGRhdGUsIGZvcm1hdCkge1xuXG4gICAgICB2YXIgbSwgZCwgeTtcblxuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGZvcm1hdC5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgICBpZiAoL20vLnRlc3QoZm9ybWF0W2ldKSkgbSA9IGRhdGVbaV07XG4gICAgICAgIGlmICgvZC8udGVzdChmb3JtYXRbaV0pKSBkID0gZGF0ZVtpXTtcbiAgICAgICAgaWYgKC95Ly50ZXN0KGZvcm1hdFtpXSkpIHkgPSBkYXRlW2ldO1xuICAgICAgfVxuXG4gICAgICBpZiAoIW0gfHwgIWQgfHwgIXkpIHJldHVybiBmYWxzZTtcblxuICAgICAgcmV0dXJuIG0gPiAwICYmIG0gPCAxMyAmJlxuICAgICAgICB5ICYmIHkubGVuZ3RoID09IDQgJiZcbiAgICAgICAgZCA+IDAgJiYgZCA8PSAobmV3IERhdGUoeSwgbSwgMCkpLmdldERhdGUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaXNEYXRlKHRoZURhdGUsIHRoZUZvcm1hdCk7XG4gIH1cblxufTtcbiJdfQ== +; \ No newline at end of file diff --git a/js/out/jquery.idealforms.min.js b/js/out/jquery.idealforms.min.js new file mode 100644 index 0000000..c461bb6 --- /dev/null +++ b/js/out/jquery.idealforms.min.js @@ -0,0 +1,7 @@ +!function e(t,i,n){function s(o,r){if(!i[o]){if(!t[o]){var l="function"==typeof require&&require;if(!r&&l)return l(o,!0);if(a)return a(o,!0);throw new Error("Cannot find module '"+o+"'")}var d=i[o]={exports:{}};t[o][0].call(d.exports,function(e){var i=t[o][1][e];return s(i?i:e)},d,d.exports,e,t,i,n)}return i[o].exports}for(var a="function"==typeof require&&require,o=0;o")[0].multiple,n=/msie/i.test(navigator.userAgent),s={};s.name="idealfile",s.methods={_init:function(){var e=t(this.el).addClass("ideal-file"),s=t('
        '),a=t(''),o=t(''),r=t('');e.css({position:"absolute",left:"-9999px"}),s.append(a,n?r:o).insertAfter(e),e.attr("tabIndex",-1),o.attr("tabIndex",-1),o.click(function(){e.focus().click()}),e.change(function(){var t,n,s=[];if(i){t=e[0].files;for(var o=0,r=t.length;r>o;o++)s.push(t[o].name);n=s.join(", ")}else n=e.val().split("\\").pop();a.val(n).attr("title",n)}),a.on({blur:function(){e.trigger("blur")},keydown:function(i){if(13===i.which)n||e.trigger("click"),t(this).closest("form").one("keydown",function(e){13===e.which&&e.preventDefault()});else{if(8!==i.which&&46!==i.which)return 9===i.which?void 0:!1;n&&e.replaceWith(e=e.clone(!0)),e.val("").trigger("change"),a.val("")}}})}},e("../../plugin")(s)}(jQuery,window,document)},{"../../plugin":11}],5:[function(e){!function(t){var i={};i.name="idealradiocheck",i.methods={_init:function(){var e=t(this.el),i=t("");i.addClass("ideal-"+(e.is(":checkbox")?"check":"radio")),e.is(":checked")&&i.addClass("checked"),i.insertAfter(e),e.parent("label").addClass("ideal-radiocheck-label").attr("onclick",""),e.css({position:"absolute",left:"-9999px"}),e.on({change:function(){var e=t(this);e.is('input[type="radio"]')&&e.parent().siblings("label").find(".ideal-radio").removeClass("checked"),i.toggleClass("checked",e.is(":checked"))},focus:function(){i.addClass("focus")},blur:function(){i.removeClass("focus")},click:function(){t(this).trigger("focus")}})}},e("../../plugin")(i)}(jQuery,window,document)},{"../../plugin":11}],6:[function(e,t){t.exports={name:"datepicker",methods:{_init:function(){this._buildDatepicker()},_buildDatepicker:function(){var e=this.$form.find("input.datepicker");jQuery.ui&&($.datepicker._checkOffset=function(e,t){return t}),jQuery.ui&&e.length&&(e.each(function(){$(this).datepicker({beforeShow:function(e){$(e).addClass("open")},onChangeMonthYear:function(){var e=$(this),t=e.outerWidth();setTimeout(function(){e.datepicker("widget").css("width",t)},1)},onClose:function(){$(this).removeClass("open")}})}),e.on("focus keyup",function(){var e=$(this),t=e.outerWidth();e.datepicker("widget").css("width",t)}))}}}},{}],7:[function(e,t){function i(e,t){var i=/\{@([^}]+)\}(.+?)\{\/\1\}/g,n=/\{#([^}]+)\}/g,s=/\{([^}]+)\}/g;return e.replace(i,function(e,i,s){return $.map(t[i],function(e){return s.replace(n,function(t,i){return e[i]})}).join("")}).replace(s,function(e,i){return t[i]||""})}t.exports={name:"dynamicFields",options:{templates:{base:'
        {field}
        ',text:'',file:'',textarea:'',group:'

        {@list} {/list}

        ',select:' '}},methods:{addFields:function(e){var t=this;$.each(e,function(e,n){var s=n.type.split(":"),a={};n.name=e,n.type=s[0],s[1]&&(n.subtype=s[1]);var o=i(t.opts.templates.base,{label:n.label,field:i(t.opts.templates[n.type],n)});n.after||n.before?t.$form.find("[name="+(n.after||n.before)+"]").each(function(){t._getField(this)[n.after?"after":"before"](o)}):t.$form.find(t.opts.field).last().after(o),n.rules&&(a[e]=n.rules,t.addRules(a))}),this._inject("addFields")},removeFields:function(e){var t=this;$.each(e.split(" "),function(e,i){var n=t._getField($('[name="'+i+'"]'));t.$fields=t.$fields.filter(function(){return!$(this).is(n)}),n.remove()}),this._inject("removeFields")},toggleFields:function(e){var t=this;$.each(e.split(" "),function(e,i){var n=t._getField($('[name="'+i+'"]'));n.data("idealforms-valid",n.is(":visible")).toggle()}),this._inject("toggleFields")}}}},{}],8:[function(e){!function(t){var i={};i.name="idealsteps",i.defaults={nav:".idealsteps-nav",navItems:"li",buildNavItems:!0,wrap:".idealsteps-wrap",step:".idealsteps-step",activeClass:"idealsteps-step-active",before:null,after:null,fadeSpeed:0},i.methods={_init:function(){var e=this,i=this.opts.activeClass;this.$el=t(this.el),this.$nav=this.$el.find(this.opts.nav),this.$navItems=this.$nav.find(this.opts.navItems),this.$wrap=this.$el.find(this.opts.wrap),this.$steps=this.$wrap.find(this.opts.step),this.opts.buildNavItems&&this._buildNavItems(),this.$steps.hide().first().show(),this.$navItems.removeClass(i).first().addClass(i),this.$navItems.click(function(){e.go(e.$navItems.index(this))})},_buildNavItems:function(){var e,i=this,n="function"==typeof this.opts.buildNavItems,s=function(e){return'
      • '+e+"
      • "};e=n?this.$steps.map(function(e){return s(i.opts.buildNavItems.call(i,e))}).get():this.$steps.map(function(e){return s(++e)}).get(),this.$navItems=t(e.join("")),this.$nav.append(t("
          ").append(this.$navItems))},_getCurIdx:function(){return this.$steps.index(this.$steps.filter(":visible"))},go:function(e){var t=this.opts.activeClass,i=this.opts.fadeSpeed;"function"==typeof e&&(e=e.call(this,this._getCurIdx())),e>=this.$steps.length&&(e=0),0>e&&(e=this.$steps.length-1),this.opts.before&&this.opts.before.call(this,e),this.$navItems.removeClass(t).eq(e).addClass(t),this.$steps.fadeOut(i).eq(e).fadeIn(i),this.opts.after&&this.opts.after.call(this,e)},prev:function(){this.go(this._getCurIdx()-1)},next:function(){this.go(this._getCurIdx()+1)},first:function(){this.go(0)},last:function(){this.go(this.$steps.length-1)}},e("../../plugin")(i)}(jQuery,window,document)},{"../../plugin":11}],9:[function(e,t){e("./idealsteps"),t.exports={name:"steps",options:{stepsContainer:".idealsteps-container",stepsOptions:{}},methods:{_init:function(){this._buildSteps()},_validate:function(){var e=this;this._updateSteps(),$.idealforms.hasExtension("idealAjax")&&$.each($.idealforms._requests,function(t,i){i.done(function(){e._updateSteps()})})},focusFirstInvalid:function(e){this.$stepsContainer.idealsteps("go",function(){return this.$steps.filter(function(){return $(this).find(e).length}).index()})},_buildSteps:function(){var e,t=!$.isEmptyObject(this.opts.rules),i=t?'':'0';e=$.extend({},{buildNavItems:function(e){return"Step "+(e+1)+i}},this.opts.stepsOptions),this.$stepsContainer=this.$form.closest(this.opts.stepsContainer).idealsteps(e)},_updateSteps:function(){var e=this;this.$stepsContainer.idealsteps("_inject",function(){var t=this;this.$navItems.each(function(i){var n=t.$steps.eq(i).find(e.getInvalid()).length;$(this).find("span").text(n).toggleClass("zero",!n)})})},addRules:function(){this.firstStep()},toggleFields:function(){this._updateSteps()},removeFields:function(){this._updateSteps()},goToStep:function(e){this.$stepsContainer.idealsteps("go",e)},prevStep:function(){this.$stepsContainer.idealsteps("prev")},nextStep:function(){this.$stepsContainer.idealsteps("next")},firstStep:function(){this.$stepsContainer.idealsteps("first")},lastStep:function(){this.$stepsContainer.idealsteps("last")}}}},{"./idealsteps":8}],10:[function(e){/*! + * jQuery Ideal Forms + * @author: Cedric Ruiz + * @version: 3.0 + * @license GPL or MIT + */ +!function(t){var i={};i.name="idealforms",i.defaults={field:".field",error:".error",iconHtml:"",iconClass:"icon",invalidClass:"invalid",validClass:"valid",silentLoad:!0,onValidate:t.noop,onSubmit:t.noop},i.global={_format:function(e){var t=[].slice.call(arguments,1);return e.replace(/\{(\d)\}/g,function(e,i){return t[+i]||""}).replace(/\{\*([^*}]*)\}/g,function(e,i){return t.join(i||", ")})},_getKey:function(e,t){return e.split(".").reduce(function(e,t){return e&&e[t]},t)},ruleSeparator:" ",argSeparator:":",rules:e("./rules"),errors:e("./errors"),extensions:[e("./extensions/dynamic-fields/dynamic-fields.ext"),e("./extensions/ajax/ajax.ext"),e("./extensions/steps/steps.ext"),e("./extensions/custom-inputs/custom-inputs.ext"),e("./extensions/datepicker/datepicker.ext")]},i.methods=t.extend({},e("./private"),e("./public")),e("./plugin")(i)}(jQuery,window,document)},{"./errors":1,"./extensions/ajax/ajax.ext":2,"./extensions/custom-inputs/custom-inputs.ext":3,"./extensions/datepicker/datepicker.ext":6,"./extensions/dynamic-fields/dynamic-fields.ext":7,"./extensions/steps/steps.ext":9,"./plugin":11,"./private":12,"./public":13,"./rules":14}],11:[function(e,t){t.exports=function(){var e=Array.prototype;return function(t){function i(e,i){this.opts=$.extend({},t.defaults,i),this.el=e,this._name=t.name,this._init()}$.extend({name:"plugin",defaults:{},methods:{},global:{}},t),$[t.name]=$.extend({addExtension:function(e){t.global.extensions.push(e)},hasExtension:function(e){return t.global.extensions.filter(function(t){return t.name==e}).length}},t.global),i._extended={},i.prototype._extend=function(e){var t=this,n=t.opts.disabledExtensions||"none";$.each(e,function(e,s){$.extend(t.opts,$.extend(!0,s.options,t.opts)),$.each(s.methods,function(e,t){n.indexOf(s.name)>-1||(i.prototype[e]?(i._extended[e]=i._extended[e]||[],i._extended[e].push({name:s.name,fn:t})):i.prototype[e]=t)})})},i.prototype._inject=function(e){var t=[].slice.call(arguments,1);if("function"==typeof e)return e.call(this);var n=this;i._extended[e]&&$.each(i._extended[e],function(e,i){i.fn.apply(n,t)})},i.prototype._init=$.noop,i.prototype[t.name]=function(t){if(!t)return this;try{return this[t].apply(this,e.slice.call(arguments,1))}catch(i){}},$.extend(i.prototype,t.methods),$.fn[t.name]=function(){var n,s=e.slice.call(arguments),a="string"==typeof s[0]&&s[0].split(":"),o=a[a.length>1?1:0],r=a.length>1&&a[0],l="object"==typeof s[0]&&s[0],d=s.slice(1);return r&&(o=r+o.substr(0,1).toUpperCase()+o.substr(1,o.length-1)),this.each(function(){var e=$.data(this,t.name);return e?n=e[t.name].apply(e,[o].concat(d)):$.data(this,t.name,new i(this,l))}),r?n:this}}}()},{}],12:[function(e,t){t.exports={_init:function(){var e=this;this._extend($.idealforms.extensions),this.$form=$(this.el),this.$fields=$(),this.$inputs=$(),this.$form.submit(function(t){t.preventDefault(),e.focusFirstInvalid(),e.opts.onSubmit.call(this,e.getInvalid().length,t)}),this._inject("_init"),this.addRules(this.opts.rules||{}),this.opts.silentLoad||this.focusFirstInvalid()},_buildField:function(e){var t,i=this._getField(e);t=$(this.opts.iconHtml,{"class":this.opts.iconClass,click:function(){$(e).focus()}}),this.$fields.filter(i).length||(this.$fields=this.$fields.add(i),this.opts.iconHtml&&i.append(t),i.addClass("idealforms-field idealforms-field-"+e.type)),this._addEvents(e),this._inject("_buildField",e)},_addEvents:function(e){var t=this,i=this._getField(e);$(e).on("change keyup",function(e){var n=i.data("idealforms-value");9!=e.which&&16!=e.which&&($(this).is(":checkbox, :radio")||n!=this.value)&&(i.data("idealforms-value",this.value),t._validate(this,!0,!0))}).focus(function(){return t.isValid(this.name)?!1:((t._isRequired(this)||this.value)&&i.find(t.opts.error).show(),void 0)}).blur(function(){i.find(t.opts.error).hide()})},_isRequired:function(e){return $(e).is(":checkbox, :radio, select")?!0:this.opts.rules[e.name].indexOf("required")>-1},_getRelated:function(e){return this._getField(e).find('[name="'+e.name+'"]')},_getField:function(e){return $(e).closest(this.opts.field)},_getFirstInvalid:function(){return this.getInvalid().first().find("input:first, textarea, select")},_handleError:function(e,t,i){i=i||this.isValid(e.name);var n=this._getField(e).find(this.opts.error);this.$form.find(this.opts.error).hide(),t&&n.text(t),n.toggle(!i)},_handleStyle:function(e,t){t=t||this.isValid(e.name),this._getField(e).removeClass(this.opts.validClass+" "+this.opts.invalidClass).addClass(t?this.opts.validClass:this.opts.invalidClass).find("."+this.opts.iconClass).show()},_fresh:function(e){this._getField(e).removeClass(this.opts.validClass+" "+this.opts.invalidClass).find(this.opts.error).hide().end().find("."+this.opts.iconClass).toggle(this._isRequired(e))},_validate:function(e,t,i){var n,s=this,a=this._getField(e),o=this.opts.rules[e.name].split($.idealforms.ruleSeparator),r=!0;return e.value||this._isRequired(e)?$.each(o,function(o,l){l=l.split($.idealforms.argSeparator),n=l[0];var d,u=$.idealforms.rules[n],c=l.slice(1);return d=$.idealforms._format.apply(null,[$.idealforms._getKey("errors."+e.name+"."+n,s.opts)||$.idealforms.errors[n]].concat(c)),r="function"==typeof u?u.apply(s,[e,e.value].concat(c)):u.test(e.value),a.data("idealforms-valid",r),t&&s._handleError(e,d,r),i&&s._handleStyle(e,r),s.opts.onValidate.call(s,e,n,r),r}):(a.removeData("idealforms-valid"),this._fresh(e)),this._inject("_validate",e,n,r),r}}},{}],13:[function(e,t){t.exports={addRules:function(e){var t=this,i=this.$form.find($.map(e,function(e,t){return'[name="'+t+'"]'}).join(","));$.extend(this.opts.rules,e),i.each(function(){t._buildField(this)}),this.$inputs=this.$inputs.add(i).each(function(){t._validate(this,!0)}),this.$fields.find(this.opts.error).hide(),this._inject("addRules")},getInvalid:function(){return this.$fields.filter(function(){return $(this).data("idealforms-valid")===!1})},focusFirstInvalid:function(){var e=this._getFirstInvalid()[0];e&&(this._handleError(e),this._handleStyle(e),this._inject("focusFirstInvalid",e),e.focus())},isValid:function(e){return e?!this.getInvalid().find('[name="'+e+'"]').length:!this.getInvalid().length},reset:function(e){var t=this,i=this.$inputs;e&&(i=i.filter('[name="'+e+'"]')),i.filter("input:not(:checkbox, :radio)").val(""),i.filter(":checkbox, :radio").prop("checked",!1),i.filter("select").find("option").prop("selected",function(){return this.defaultSelected}),i.change().each(function(){t._resetErrorAndStyle(this)})}}},{}],14:[function(e,t){t.exports={required:/.+/,digits:/^\d+$/,email:/^[^@]+@[^@]+\..{2,6}$/,username:/^[a-z](?=[\w.]{3,31}$)\w*\.?\w*$/i,pass:/(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/,strongpass:/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,phone:/^[2-9]\d{2}-\d{3}-\d{4}$/,zip:/^\d{5}$|^\d{5}-\d{4}$/,url:/^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i,number:function(e,t){return!isNaN(t)},range:function(e,t,i,n){return Number(t)>=min&&Number(t)<=n},min:function(e,t,i){return t.length>=i},max:function(e,t,i){return t.length<=i},minoption:function(e,t,i){return this._getRelated(e).filter(":checked").length>=i},maxoption:function(e,t,i){return this._getRelated(e).filter(":checked").length<=i},minmax:function(e,t,i,n){return t.length>=i&&t.length<=n},select:function(e,t,i){return t!=i},extension:function(e){var t=[].slice.call(arguments,1),i=!1;return $.each(e.files||[{name:e.value}],function(e,n){i=$.inArray(n.name.match(/\.(.+)$/)[1],t)>-1}),i},equalto:function(e,t,i){var n=this,s=$('[name="'+i+'"]');return this.getInvalid().find(s).length?!1:(s.off("keyup.equalto").on("keyup.equalto",function(){n._validate(e,!1,!0)}),e.value==s.val())},date:function(e,t,i){function n(e,t){for(var i,n,s,a=0,o=t.length;o>a;a++)/m/.test(t[a])&&(i=e[a]),/d/.test(t[a])&&(n=e[a]),/y/.test(t[a])&&(s=e[a]);return i&&n&&s?i>0&&13>i&&s&&4==s.length&&n>0&&n<=new Date(s,i,0).getDate():!1}i=i||"mm/dd/yyyy";var s=/[^mdy]/.exec(i)[0],a=i.split(s),o=t.split(s);return n(o,a)}}},{}]},{},[10]); \ No newline at end of file diff --git a/js/plugin.js b/js/plugin.js new file mode 100644 index 0000000..04d635e --- /dev/null +++ b/js/plugin.js @@ -0,0 +1,124 @@ +/** + * Plugin boilerplate + */ +module.exports = (function() { + + var AP = Array.prototype; + + return function(plugin) { + + $.extend({ + name: 'plugin', + defaults: {}, + methods: {}, + global: {}, + }, plugin); + + $[plugin.name] = $.extend({ + + addExtension: function(extension) { + plugin.global.extensions.push(extension); + }, + + hasExtension: function(extension) { + return plugin.global.extensions.filter(function(ext) { + return ext.name == extension; + }).length; + } + }, plugin.global); + + function Plugin(element, options) { + + this.opts = $.extend({}, plugin.defaults, options); + this.el = element; + + this._name = plugin.name; + + this._init(); + } + + Plugin._extended = {}; + + Plugin.prototype._extend = function(extensions) { + + var self = this + , disabled = self.opts.disabledExtensions || 'none'; + + $.each(extensions, function(i, extension) { + + $.extend(self.opts, $.extend(true, extension.options, self.opts)); + + $.each(extension.methods, function(method, fn) { + + if (disabled.indexOf(extension.name) > -1) { + return; + } + + if (Plugin.prototype[method]) { + Plugin._extended[method] = Plugin._extended[method] || []; + Plugin._extended[method].push({ name: extension.name, fn: fn }); + } else { + Plugin.prototype[method] = fn; + } + }); + + }); + }; + + Plugin.prototype._inject = function(method) { + + var args = [].slice.call(arguments, 1); + + if (typeof method == 'function') return method.call(this); + + var self = this; + + if (Plugin._extended[method]) { + $.each(Plugin._extended[method], function(i, plugin) { + plugin.fn.apply(self, args); + }); + } + }; + + Plugin.prototype._init = $.noop; + + Plugin.prototype[plugin.name] = function(method) { + if (!method) return this; + try { return this[method].apply(this, AP.slice.call(arguments, 1)); } + catch(e) {} + }; + + $.extend(Plugin.prototype, plugin.methods); + + $.fn[plugin.name] = function() { + + var args = AP.slice.call(arguments) + , methodArray = typeof args[0] == 'string' && args[0].split(':') + , method = methodArray[methodArray.length > 1 ? 1 : 0] + , prefix = methodArray.length > 1 && methodArray[0] + , opts = typeof args[0] == 'object' && args[0] + , params = args.slice(1) + , ret; + + if (prefix) { + method = prefix + method.substr(0,1).toUpperCase() + method.substr(1,method.length-1); + } + + this.each(function() { + + var instance = $.data(this, plugin.name); + + // Method + if (instance) { + return ret = instance[plugin.name].apply(instance, [method].concat(params)); + } + + // Init + return $.data(this, plugin.name, new Plugin(this, opts)); + }); + + return prefix ? ret : this; + }; + }; + +}()); diff --git a/js/private.js b/js/private.js new file mode 100644 index 0000000..264a129 --- /dev/null +++ b/js/private.js @@ -0,0 +1,174 @@ +/** + * Private methods + */ +module.exports = { + + _init: function() { + + var self = this; + + this._extend($.idealforms.extensions); + + this.$form = $(this.el); + this.$fields = $(); + this.$inputs = $(); + + this.$form.submit(function(e) { + e.preventDefault(); + self.focusFirstInvalid(); + self.opts.onSubmit.call(this, self.getInvalid().length, e); + }); + + this._inject('_init'); + + this.addRules(this.opts.rules || {}); + + if (! this.opts.silentLoad) this.focusFirstInvalid(); + }, + + _buildField: function(input) { + + var self = this + , $field = this._getField(input) + , $icon; + + $icon = $(this.opts.iconHtml, { + class: this.opts.iconClass, + click: function(){ $(input).focus() } + }); + + if (! this.$fields.filter($field).length) { + this.$fields = this.$fields.add($field); + if (this.opts.iconHtml) $field.append($icon); + $field.addClass('idealforms-field idealforms-field-'+ input.type); + } + + this._addEvents(input); + + this._inject('_buildField', input); + }, + + _addEvents: function(input) { + + var self = this + , $field = this._getField(input); + + $(input) + .on('change keyup', function(e) { + + var oldValue = $field.data('idealforms-value'); + + if (e.which == 9 || e.which == 16) return; + if (! $(this).is(':checkbox, :radio') && oldValue == this.value) return; + + $field.data('idealforms-value', this.value); + + self._validate(this, true, true); + }) + .focus(function() { + + if (self.isValid(this.name)) return false; + + if (self._isRequired(this) || this.value) { + $field.find(self.opts.error).show(); + } + }) + .blur(function() { + $field.find(self.opts.error).hide(); + }); + }, + + _isRequired: function(input) { + // We assume non-text inputs with rules are required + if ($(input).is(':checkbox, :radio, select')) return true; + return this.opts.rules[input.name].indexOf('required') > -1; + }, + + _getRelated: function(input) { + return this._getField(input).find('[name="'+ input.name +'"]'); + }, + + _getField: function(input) { + return $(input).closest(this.opts.field); + }, + + _getFirstInvalid: function() { + return this.getInvalid().first().find('input:first, textarea, select'); + }, + + _handleError: function(input, error, valid) { + valid = valid || this.isValid(input.name); + var $error = this._getField(input).find(this.opts.error); + this.$form.find(this.opts.error).hide(); + if (error) $error.text(error); + $error.toggle(!valid); + }, + + _handleStyle: function(input, valid) { + valid = valid || this.isValid(input.name); + this._getField(input) + .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) + .addClass(valid ? this.opts.validClass : this.opts.invalidClass) + .find('.'+ this.opts.iconClass).show(); + }, + + _fresh: function(input) { + this._getField(input) + .removeClass(this.opts.validClass +' '+ this.opts.invalidClass) + .find(this.opts.error).hide() + .end() + .find('.'+ this.opts.iconClass).toggle(this._isRequired(input)); + }, + + _validate: function(input, handleError, handleStyle) { + + var self = this + , $field = this._getField(input) + , userRules = this.opts.rules[input.name].split($.idealforms.ruleSeparator) + , valid = true + , rule; + + // Non-required input with empty value must pass validation + if (! input.value && ! this._isRequired(input)) { + $field.removeData('idealforms-valid'); + this._fresh(input); + + // Required inputs + } else { + + $.each(userRules, function(i, userRule) { + + userRule = userRule.split($.idealforms.argSeparator); + + rule = userRule[0]; + + var theRule = $.idealforms.rules[rule] + , args = userRule.slice(1) + , error; + + error = $.idealforms._format.apply(null, [ + $.idealforms._getKey('errors.'+ input.name +'.'+ rule, self.opts) || + $.idealforms.errors[rule] + ].concat(args)); + + valid = typeof theRule == 'function' + ? theRule.apply(self, [input, input.value].concat(args)) + : theRule.test(input.value); + + $field.data('idealforms-valid', valid); + + if (handleError) self._handleError(input, error, valid); + if (handleStyle) self._handleStyle(input, valid); + + self.opts.onValidate.call(self, input, rule, valid); + + return valid; + }); + } + + this._inject('_validate', input, rule, valid); + + return valid; + } + +}; diff --git a/js/public.js b/js/public.js new file mode 100644 index 0000000..18f11dd --- /dev/null +++ b/js/public.js @@ -0,0 +1,66 @@ +/** + * Public methods + */ +module.exports = { + + addRules: function(rules) { + + var self = this; + + var $inputs = this.$form.find($.map(rules, function(_, name) { + return '[name="'+ name +'"]'; + }).join(',')); + + $.extend(this.opts.rules, rules); + + $inputs.each(function(){ self._buildField(this) }); + + this.$inputs = this.$inputs + .add($inputs) + .each(function(){ self._validate(this, true) }); + + this.$fields.find(this.opts.error).hide(); + + this._inject('addRules'); + }, + + getInvalid: function() { + return this.$fields.filter(function() { + return $(this).data('idealforms-valid') === false; + }); + }, + + focusFirstInvalid: function() { + + var firstInvalid = this._getFirstInvalid()[0]; + + if (firstInvalid) { + this._handleError(firstInvalid); + this._handleStyle(firstInvalid); + this._inject('focusFirstInvalid', firstInvalid); + firstInvalid.focus(); + } + }, + + isValid: function(name) { + if (name) return ! this.getInvalid().find('[name="'+ name +'"]').length; + return ! this.getInvalid().length; + }, + + reset: function(name) { + + var self = this + , $inputs = this.$inputs; + + if (name) $inputs = $inputs.filter('[name="'+ name +'"]'); + + $inputs.filter('input:not(:checkbox, :radio)').val(''); + $inputs.filter(':checkbox, :radio').prop('checked', false); + $inputs.filter('select').find('option').prop('selected', function() { + return this.defaultSelected; + }); + + $inputs.change().each(function(){ self._resetErrorAndStyle(this) }); + } + +}; diff --git a/js/rules.js b/js/rules.js new file mode 100644 index 0000000..9c45bf1 --- /dev/null +++ b/js/rules.js @@ -0,0 +1,102 @@ +/** + * Rules + */ +module.exports = { + + required: /.+/, + digits: /^\d+$/, + email: /^[^@]+@[^@]+\..{2,6}$/, + username: /^[a-z](?=[\w.]{3,31}$)\w*\.?\w*$/i, + pass: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/, + strongpass: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, + phone: /^[2-9]\d{2}-\d{3}-\d{4}$/, + zip: /^\d{5}$|^\d{5}-\d{4}$/, + url: /^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i, + + number: function(input, value) { + return !isNaN(value); + }, + + range: function(input, value, mix, max) { + return Number(value) >= min && Number(value) <= max; + }, + + min: function(input, value, min) { + return value.length >= min; + }, + + max: function(input, value, max) { + return value.length <= max; + }, + + minoption: function(input, value, min) { + return this._getRelated(input).filter(':checked').length >= min; + }, + + maxoption: function(input, value, max) { + return this._getRelated(input).filter(':checked').length <= max; + }, + + minmax: function(input, value, min, max) { + return value.length >= min && value.length <= max; + }, + + select: function(input, value, def) { + return value != def; + }, + + extension: function(input) { + + var extensions = [].slice.call(arguments, 1) + , valid = false; + + $.each(input.files || [{name: input.value}], function(i, file) { + valid = $.inArray(file.name.match(/\.(.+)$/)[1], extensions) > -1; + }); + + return valid; + }, + + equalto: function(input, value, target) { + + var self = this + , $target = $('[name="'+ target +'"]'); + + if (this.getInvalid().find($target).length) return false; + + $target.off('keyup.equalto').on('keyup.equalto', function() { + self._validate(input, false, true); + }); + + return input.value == $target.val(); + }, + + date: function(input, value, format) { + + format = format || 'mm/dd/yyyy'; + + var delimiter = /[^mdy]/.exec(format)[0] + , theFormat = format.split(delimiter) + , theDate = value.split(delimiter); + + function isDate(date, format) { + + var m, d, y; + + for (var i = 0, len = format.length; i < len; i++) { + if (/m/.test(format[i])) m = date[i]; + if (/d/.test(format[i])) d = date[i]; + if (/y/.test(format[i])) y = date[i]; + } + + if (!m || !d || !y) return false; + + return m > 0 && m < 13 && + y && y.length == 4 && + d > 0 && d <= (new Date(y, m, 0)).getDate(); + } + + return isDate(theDate, theFormat); + } + +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..a31770b --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "idealforms", + "version": "3.0.0", + "dependencies": { + "nib": "*" + } +} diff --git a/styl/datepicker.styl b/styl/datepicker.styl new file mode 100644 index 0000000..f2a6b53 --- /dev/null +++ b/styl/datepicker.styl @@ -0,0 +1,72 @@ +// Datepicker +//--------------------------------------- + +.idealforms input.datepicker.open + border-bottom-color: transparent + border-radius: 0 + border-radius: top radius + +.ui-datepicker + display: none + box-sizing: border-box + width: input-width + margin-top: -2px + padding: .75em + background: white + border: 1px solid #999 + border-radius: bottom radius + box-shadow: 0 1px 2px rgba(black, .2) + +.ui-datepicker-header + position: relative + padding: .2em 0 + margin-bottom: .75em + font-weight: bold + + .ui-datepicker-title + text-align: center + + .ui-datepicker-prev + .ui-datepicker-next + text-indent: -9999px + width: 16px + height: 16px + position: absolute + cursor: pointer + user-select: none + background: url(../img/datepicker.png) 0 0 + + &:active + margin-top: 1px + + .ui-datepicker-next + background-position: -16px 0 + + .ui-datepicker-prev + left: 8px + + .ui-datepicker-next + right: 8px + +.ui-datepicker-calendar + width: 100% + border-collapse: collapse + table-layout: fixed + + td + padding: .25em 0 + text-align: center + + a + display: block + text-decoration: none + color: gray + + &:hover + color: valid + font-weight: bold + + .ui-datepicker-today a + margin: 0 .25em + background: #eee + border-radius: radius diff --git a/styl/idealfile.styl b/styl/idealfile.styl new file mode 100644 index 0000000..3bedae1 --- /dev/null +++ b/styl/idealfile.styl @@ -0,0 +1,31 @@ +// Ideal File +//--------------------------------------- + +form.idealforms + + .ideal-file-wrap + float: left + + .ideal-file-filename + float: left + width: input-width*.7 + 1px + height: 100% + border-radius: 0 + border-radius: left radius + + .ideal-file-upload + idealbutton() + overflow: visible + position: relative + float: right + left: -1px + width: input-width*.3 + padding-left: 0 + padding-right: 0 + text-align: center + border-radius: 0 + border-radius: right radius + +.ie9 + .ideal-file-upload + line-height: 1.15 diff --git a/styl/idealradiocheck.styl b/styl/idealradiocheck.styl new file mode 100644 index 0000000..e3666d8 --- /dev/null +++ b/styl/idealradiocheck.styl @@ -0,0 +1,42 @@ +// Ideal Radio & Check +//--------------------------------------- + +form.idealforms + + .ideal-radiocheck-label + cursor: pointer + margin: .15em 0 !important + + if group-horizontal + margin: .15em 10px !important + + input + float: left + + .ideal-check, .ideal-radio + float: left + margin-right: 10px !important + width: 20px + height: 20px + background: url(../img/radiocheck.png) 0 0 + + .ideal-check.focus + background-position: -20px 0 + + .ideal-check.checked + background-position: -40px 0 + + .ideal-check.checked.focus + background-position: -60px 0 + + .ideal-radio + background-position: 0 bottom + + .ideal-radio.focus + background-position: -20px bottom + + .ideal-radio.checked + background-position: -40px bottom + + .ideal-radio.checked.focus + background-position: -60px bottom diff --git a/styl/idealsteps.styl b/styl/idealsteps.styl new file mode 100644 index 0000000..891679a --- /dev/null +++ b/styl/idealsteps.styl @@ -0,0 +1,91 @@ +// Ideal Steps +//--------------------------------------- + +.idealsteps-step + clearfix() + +.idealsteps-nav + + ui() + overflow: hidden + margin-bottom: 2em + + ul + reset-box-model() + list-style: none + + li + float: left + + a + position: relative + float: left + padding: 0 1.5em 0 2.75em + height: 3.5em + line-height: 3.5em + text-decoration: none + color: darken(ui-element, 50) + background: ui-element + transition: padding .2s ease-in-out + + &:focus + outline: 0 // Firefox + + &:hover + background: lighten(ui-element, 5) + &:after + border-left-color: lighten(ui-element, 5) + + &:after, &:before + content: "" + position: absolute + z-index: 1 + top: 0 + right: -2em + margin-right: 0 + margin-top: -.125em + border-width: 2em 1em + border-style: solid + border-color: transparent + border-left-color: ui-element + + &:before + margin-right: -1px + border-left-color: darken(ui-element, 20) + + li:first-child a + padding-left: 1.75em + + li.idealsteps-step-active + a + padding-right: 3.5em + background: white + color: valid + font-weight: bold + + &:after + border-left-color: white + + .counter + opacity: 1 + + .counter + opacity: 0 + position: absolute + top: 50% + right: 1em + height: 20px + width: 20px + margin-top: -.75em + line-height: 20px !important + text-align: center + line-height: 1 + color: invalid + border: 1px solid invalid + border-radius: 10em + transition: opacity .2s ease-in-out + + &.zero + color: valid + border-color: valid + diff --git a/styl/jquery.idealforms.styl b/styl/jquery.idealforms.styl new file mode 100644 index 0000000..6f8d360 --- /dev/null +++ b/styl/jquery.idealforms.styl @@ -0,0 +1,13 @@ +/*! + * jQuery Ideal Forms + * @author: Cedric Ruiz + * @version: 3.0 + * @license GPL or MIT + */ +@import '../node_modules/nib' +@import 'vars' +@import 'main' +@import 'idealsteps' +@import 'idealradiocheck' +@import 'idealfile' +@import 'datepicker' diff --git a/styl/main.styl b/styl/main.styl new file mode 100644 index 0000000..80dbf67 --- /dev/null +++ b/styl/main.styl @@ -0,0 +1,175 @@ +// Style +//--------------------------------------- + +form.idealforms + clearfix() + line-height: 1.5 + + * + box-sizing: border-box + + .field + position: relative + float: left + clear: both + margin: .35em 0 + + label.main, .field > input, select, button, textarea, .field .group + float: left + + label.main + width: label-width + margin-top: .55em + + input, textarea, select, button, .field .group + reset-box-model() + width: input-width + padding: .55em + border: 1px solid #999 + outline: 0 + background: white + border-radius: radius + box-shadow: inset 0 1px 2px rgba(black, .15) + + input + transition: background .3s ease-in-out + + textarea + width: input-width*1.5 + + select, button + idealbutton() + + button + width: auto + + select + padding: .55em + + &:focus + border: 1px solid darken(ui-element, 60) + + input[type="file"] + padding: 0 + + .field .group + position: relative + padding: 1.25em + box-shadow: none + + label + float: left + clear: both + padding: .15em 0 + + if group-horizontal + clear: none + + input,label + margin: 0 + + input + width: auto + margin-right: .5em + box-shadow: none + + label + margin-right: 1em + &:last-of-type + margin: 0 + + .field.valid + input, select, textarea, .group + color: darken(valid, 30) + background: valid-bg + border-color: valid + + .field.invalid + input, select, textarea, .group + color: darken(invalid, 30) + background: invalid-bg + border-color: invalid + + .field.valid, .field.invalid + .group, textarea, select + color: inherit + background: none + + select + background: linear-gradient(lighten(ui-element, 15), ui-element) + + .field .icon + position: absolute + width: 16px + height: 16px + top: 50% + left: 100% + margin-top: -8px + margin-left: 8px + background: url(../img/validation.png) -16px 0 no-repeat + cursor: pointer + + .field.invalid .icon + background-position: -16px 0 + + .field.valid .icon + background-position: 0 0 + cursor: default + + .field.invalid, .field.valid + .group input + border: 0 + outline: 0 + box-shadow: none + + .field.ajax + input + color: darken(ajax, 30) + background: ajax-bg + border-color: ajax + + .icon + background: url(../img/loading.gif) + + .error + display: none + position: absolute + z-index: 1 + left: 100% + top: 50% + padding: 1em 1.5em + width: error-width + margin-left: 32 + 8 px + if not icon + margin-left: 1.25em + background: error + background: linear-gradient(error, lighten(error, 7)) + color: lighten(error, 90) + font-size: 85% + font-weight: bold + text-shadow: 0 1px 0 rgba(black, .3) + line-height: 1.35 + border: 1px solid darken(error, 10) + border-radius: 0 radius radius radius + box-shadow: 0 1px 1px rgba(black, .15) + + &:after + content: "" + position: absolute + z-index: -1 + top: -1px + left: -.7em + border-width: .7em + border-style: solid + border-color: transparent + border-top-color: error + + .idealforms-field-checkbox + .idealforms-field-radio + .idealforms-field-textarea + .icon + top: 8px + margin-top: 0 + + .error + top: 20px diff --git a/styl/vars.styl b/styl/vars.styl new file mode 100644 index 0000000..083299b --- /dev/null +++ b/styl/vars.styl @@ -0,0 +1,42 @@ +// Theme +//--------------------------------------- + +valid = #3F9DCC +valid-bg = #EDF7FC +invalid = #CC2A18 +invalid-bg = #FFEDED +ajax = #CFAA19 +ajax-bg = #FAF9E8 +ui-element = #ddd +error = #285d85 + +label-width = 120px +input-width = 290px +error-width = (input-width/1.5) +radius = 3px + +icon = true +group-horizontal = false + +// Mixins +//--------------------------------------- + +ui() + color: darken(ui-element, 70) + background: #eee + background: linear-gradient(lighten(ui-element, 15), ui-element) + border: 1px solid darken(ui-element, 20) + border-bottom-color: darken(ui-element, 30) + box-shadow: 0 1px 2px rgba(black, .15) + border-radius: radius + +idealbutton() + ui() + padding: .55em 1.5em + + &:hover + background: linear-gradient(lighten(ui-element, 20), lighten(ui-element, 5)) + + &:active + background: ui-element +