diff --git a/Gruntfile.js b/Gruntfile.js
index 0a9791dd4..2a050e452 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -62,6 +62,8 @@ module.exports = function(grunt) {
sass: {
build: {
options: {
+ sourcemap: 'none',
+ trace: true,
style: 'expanded',
precision: 8
},
@@ -94,7 +96,7 @@ module.exports = function(grunt) {
grunt.task.loadTasks('./builder/');
//if you choose to use scss, or any preprocessor, you can add it here
- grunt.registerTask('default', ['clean', 'concat', 'patternlab', /*'sass',*/ 'copy']);
+ grunt.registerTask('default', ['clean', 'concat', 'patternlab', 'sass', 'copy']);
//travis CI task
grunt.registerTask('travis', ['clean', 'concat', 'patternlab', /*'sass',*/ 'copy', 'nodeunit']);
diff --git a/builder/patternlab.js b/builder/patternlab.js
index 37d75805b..a765df683 100644
--- a/builder/patternlab.js
+++ b/builder/patternlab.js
@@ -8,347 +8,458 @@
*
*/
-var patternlab_engine = function(){
- var path = require('path'),
- fs = require('fs-extra'),
- diveSync = require('diveSync'),
- mustache = require('mustache'),
- of = require('./object_factory'),
- pa = require('./pattern_assembler'),
- patternlab = {};
-
- patternlab.package =fs.readJSONSync('./package.json');
- patternlab.config = fs.readJSONSync('./config.json');
-
- function getVersion() {
- console.log(patternlab.package.version);
- }
-
- function help(){
- console.log('Patternlab Node Help');
- console.log('===============================');
- console.log('Command Line Arguments');
- console.log('patternlab:only_patterns');
- console.log(' > Compiles the patterns only, outputting to ./public/patterns');
- console.log('patternlab:v');
- console.log(' > Retrieve the version of patternlab-node you have installed');
- console.log('patternlab:help');
- console.log(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
- console.log('===============================');
- console.log('Visit http://patternlab.io/docs/index.html for general help on pattern-lab');
- console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open a bug.');
- }
-
- function printDebug() {
- //debug file can be written by setting flag on config.json
- if(patternlab.config.debug){
- console.log('writing patternlab debug file to ./patternlab.json');
- fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, null, 3));
- }
- }
-
- function buildPatterns(callback){
- patternlab.data = fs.readJSONSync('./source/_data/data.json');
- patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json');
- patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8');
- patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8');
- patternlab.patterns = [];
- patternlab.patternIndex = [];
- patternlab.partials = {};
-
- diveSync('./source/_patterns', function(err, file){
-
- //log any errors
- if(err){
- console.log(err);
- return;
- }
-
- //extract some information
- var abspath = file.substring(2);
- var subdir = path.dirname(path.relative('./source/_patterns', file));
- var filename = path.basename(file);
-
- //check if the pattern already exists.
- var patternName = filename.substring(0, filename.indexOf('.')),
- patternIndex = patternlab.patternIndex.indexOf(subdir + '-' + patternName),
- currentPattern,
- flatPatternPath;
-
- //ignore _underscored patterns, json, and dotfiles
- if(filename.charAt(0) === '_' || path.extname(filename) === '.json' || filename.charAt(0) === '.'){
- return;
- }
-
- //make a new Pattern Object
- var flatPatternName = subdir.replace(/\\/g, '-') + '-' + patternName;
-
- flatPatternName = flatPatternName.replace(/\\/g, '-');
- currentPattern = new of.oPattern(flatPatternName, subdir, filename, {});
- currentPattern.patternName = patternName.substring(patternName.indexOf('-') + 1);
- currentPattern.data = null;
-
- //see if this file has a state
- if(patternlab.config.patternStates[currentPattern.patternName]){
- currentPattern.patternState = patternlab.config.patternStates[currentPattern.patternName];
- }
-
- //look for a json file for this template
- try {
- var jsonFilename = abspath.substr(0, abspath.lastIndexOf(".")) + ".json";
- currentPattern.data = fs.readJSONSync(jsonFilename);
- }
- catch(e) {
-
- }
-
- currentPattern.template = fs.readFileSync(abspath, 'utf8');
-
- //render the pattern. pass partials object just in case.
- if(currentPattern.data) { // Pass JSON as data
- currentPattern.patternPartial = renderPattern(currentPattern.template, currentPattern.data, patternlab.partials);
- }else{ // Pass global patternlab data
- currentPattern.patternPartial = renderPattern(currentPattern.template, patternlab.data, patternlab.partials);
- }
-
- //write the compiled template to the public patterns directory
- flatPatternPath = currentPattern.name + '/' + currentPattern.name + '.html';
-
- //add footer info before writing
- var currentPatternFooter = renderPattern(patternlab.footer, currentPattern);
-
- fs.outputFileSync('./public/patterns/' + flatPatternPath, patternlab.header + currentPattern.patternPartial + currentPatternFooter);
- currentPattern.patternLink = flatPatternPath;
-
- //add as a partial in case this is referenced later. convert to syntax needed by existing patterns
- var sub = subdir.substring(subdir.indexOf('-') + 1);
- var folderIndex = sub.indexOf('/'); //THIS IS MOST LIKELY WINDOWS ONLY. path.sep not working yet
- var cleanSub = sub.substring(0, folderIndex);
-
- //add any templates found to an object of partials, so downstream templates may use them too
- //exclude the template patterns - we don't need them as partials because pages will just swap data
- if(cleanSub !== ''){
- var partialname = cleanSub + '-' + patternName.substring(patternName.indexOf('-') + 1);
-
- patternlab.partials[partialname] = currentPattern.template;
-
- //done
- }
-
- //add to patternlab arrays so we can look these up later. this could probably just be an object.
- patternlab.patternIndex.push(currentPattern.name);
- patternlab.patterns.push(currentPattern);
- });
-
- }
-
- function buildFrontEnd(){
- patternlab.buckets = [];
- patternlab.bucketIndex = [];
- patternlab.patternPaths = {};
- patternlab.viewAllPaths = {};
-
- //build the styleguide
- var styleguideTemplate = fs.readFileSync('./source/_patternlab-files/styleguide.mustache', 'utf8');
- var styleguideHtml = renderPattern(styleguideTemplate, {partials: patternlab.patterns});
- fs.outputFileSync('./public/styleguide/html/styleguide.html', styleguideHtml);
-
- //build the patternlab website
- var patternlabSiteTemplate = fs.readFileSync('./source/_patternlab-files/index.mustache', 'utf8');
-
- //loop through all patterns. deciding to do this separate from the recursion, even at a performance hit, to attempt to separate the tasks of styleguide creation versus site menu creation
- for(var i = 0; i < patternlab.patterns.length; i++){
- var pattern = patternlab.patterns[i];
- var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];
-
- //check if the bucket already exists
- var bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
- if(bucketIndex === -1){
- //add the bucket
- var bucket = new of.oBucket(bucketName);
-
- //add paternPath
- patternlab.patternPaths[bucketName] = {};
-
- //get the navItem
- var navItemName = pattern.subdir.split('-').pop();
-
- //get the navSubItem
- var navSubItemName = pattern.patternName.replace(/-/g, ' ');
-
- //test whether the pattern struture is flat or not - usually due to a template or page
- var flatPatternItem = false;
- if(navItemName === bucketName){
- flatPatternItem = true;
- }
-
- //assume the navItem does not exist.
- var navItem = new of.oNavItem(navItemName);
-
- //assume the navSubItem does not exist.
- var navSubItem = new of.oNavSubItem(navSubItemName);
- navSubItem.patternPath = pattern.patternLink;
- navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name
-
- //add the patternState if it exists
- if(pattern.patternState){
- navSubItem.patternState = pattern.patternState;
- }
-
- //if it is flat - we should not add the pattern to patternPaths
- if(flatPatternItem){
-
- bucket.patternItems.push(navSubItem);
-
- //add to patternPaths
- addToPatternPaths(bucketName, pattern);
-
- } else{
-
- bucket.navItems.push(navItem);
- bucket.navItemsIndex.push(navItemName);
- navItem.navSubItems.push(navSubItem);
- navItem.navSubItemsIndex.push(navSubItemName);
-
- //add to patternPaths
- addToPatternPaths(bucketName, pattern);
-
- }
-
- //add the bucket.
- patternlab.buckets.push(bucket);
- patternlab.bucketIndex.push(bucketName);
-
- //done
-
- } else{
- //find the bucket
- var bucket = patternlab.buckets[bucketIndex];
-
- //get the navItem
- var navItemName = pattern.subdir.split('-').pop();
-
- //get the navSubItem
- var navSubItemName = pattern.patternName.replace(/-/g, ' ');
-
- //assume the navSubItem does not exist.
- var navSubItem = new of.oNavSubItem(navSubItemName);
- navSubItem.patternPath = pattern.patternLink;
- navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name
-
- //add the patternState if it exists
- if(pattern.patternState){
- navSubItem.patternState = pattern.patternState;
- }
-
- //test whether the pattern struture is flat or not - usually due to a template or page
- var flatPatternItem = false;
- if(navItemName === bucketName){
- flatPatternItem = true;
- }
-
- //if it is flat - we should not add the pattern to patternPaths
- if(flatPatternItem){
-
- //add the navItem to patternItems
- bucket.patternItems.push(navSubItem);
-
- //add to patternPaths
- addToPatternPaths(bucketName, pattern);
-
- } else{
- //check to see if navItem exists
- var navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
- if(navItemIndex === -1){
-
- var navItem = new of.oNavItem(navItemName);
-
- //add the navItem and navSubItem
- navItem.navSubItems.push(navSubItem);
- navItem.navSubItemsIndex.push(navSubItemName);
- bucket.navItems.push(navItem);
- bucket.navItemsIndex.push(navItemName);
-
- } else{
- //add the navSubItem
- var navItem = bucket.navItems[navItemIndex];
- navItem.navSubItems.push(navSubItem);
- navItem.navSubItemsIndex.push(navSubItemName);
- }
-
- // just add to patternPaths
- addToPatternPaths(bucketName, pattern);
- }
-
- }
-
- }
-
- //the patternlab site requires a lot of partials to be rendered.
- //patternNav
- var patternNavTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternNav.mustache', 'utf8');
- var patternNavPartialHtml = renderPattern(patternNavTemplate, patternlab);
-
- //ishControls
- var ishControlsTemplate = fs.readFileSync('./source/_patternlab-files/partials/ishControls.mustache', 'utf8');
- var ishControlsPartialHtml = renderPattern(ishControlsTemplate, patternlab.config);
-
- //patternPaths
- var patternPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternPaths.mustache', 'utf8');
- var patternPathsPartialHtml = renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)});
-
- //viewAllPaths
- var viewAllPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/viewAllPaths.mustache', 'utf8');
- var viewAllPathersPartialHtml = renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});
-
- //websockets
- var websocketsTemplate = fs.readFileSync('./source/_patternlab-files/partials/websockets.mustache', 'utf8');
- patternlab.contentsyncport = patternlab.config.contentSyncPort;
- patternlab.navsyncport = patternlab.config.navSyncPort;
-
- var websocketsPartialHtml = renderPattern(websocketsTemplate, patternlab);
-
- //render the patternlab template, with all partials
- var patternlabSiteHtml = renderPattern(patternlabSiteTemplate, {}, {
- 'ishControls': ishControlsPartialHtml,
- 'patternNav': patternNavPartialHtml,
- 'patternPaths': patternPathsPartialHtml,
- 'websockets': websocketsPartialHtml,
- 'viewAllPaths': viewAllPathersPartialHtml
- });
- fs.outputFileSync('./public/index.html', patternlabSiteHtml);
- }
-
- function renderPattern(name, data, partials) {
- if(partials) {
- return mustache.render(name, data, partials);
- }else{
- return mustache.render(name, data);
- }
- }
-
- function addToPatternPaths(bucketName, pattern){
- //this is messy, could use a refactor.
- patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.filename.substring(0, pattern.filename.indexOf('.'));
- }
-
- return {
- version: function(){
- return getVersion();
- },
- build: function(){
- buildPatterns();
- buildFrontEnd();
- printDebug();
- },
- help: function(){
- help();
- },
- build_patterns_only: function(){
- buildPatterns();
- printDebug();
- }
- };
+/*
+ * patternlab-node - v0.1.3 - 2014
+ *
+ * Brian Muenzenmeyer, and the web community.
+ * Licensed under the MIT license.
+ *
+ * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
+ *
+ */
+
+/*
+ * patternlab-node - v0.1.3 - 2014
+ *
+ * Brian Muenzenmeyer, and the web community.
+ * Licensed under the MIT license.
+ *
+ * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
+ *
+ */
+
+/*
+ * patternlab-node - v0.1.3 - 2014
+ *
+ * Brian Muenzenmeyer, and the web community.
+ * Licensed under the MIT license.
+ *
+ * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
+ *
+ */
+
+/*
+ * patternlab-node - v0.1.3 - 2014
+ *
+ * Brian Muenzenmeyer, and the web community.
+ * Licensed under the MIT license.
+ *
+ * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
+ *
+ */
+
+/*jslint indent:4*/
+
+var patternlab_engine = function () {
+ var path = require('path'),
+ fs = require('fs-extra'),
+ diveSync = require('diveSync'),
+ of = require('./object_factory'),
+ //pa = require('./pattern_assembler'),
+ markdown = require('markdown').markdown,
+ patternlab = {},
+ renderEngines = {},
+ templates = {};
+
+ patternlab.package = fs.readJSONSync('./package.json');
+ patternlab.config = fs.readJSONSync('./config.json');
+
+ // add rendering engines
+ if (!patternlab.config['rendering-engines']) {
+ throw new Error('Missing "rendering-engines" in config');
+ }
+ Object.keys(patternlab.config['rendering-engines']).every(function (engine) {
+ renderEngines[engine] = require(patternlab.config['rendering-engines'][engine]);
+ });
+
+ function getVersion() {
+ console.log(patternlab.package.version);
+ }
+
+ function help() {
+ console.log('Patternlab Node Help');
+ console.log('===============================');
+ console.log('Command Line Arguments');
+ console.log('patternlab:only_patterns');
+ console.log(' > Compiles the patterns only, outputting to ./public/patterns');
+ console.log('patternlab:v');
+ console.log(' > Retrieve the version of patternlab-node you have installed');
+ console.log('patternlab:help');
+ console.log(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
+ console.log('===============================');
+ console.log('Visit http://patternlab.io/docs/index.html for general help on pattern-lab');
+ console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open a bug.');
+ }
+
+ function printDebug() {
+ //debug file can be written by setting flag on config.json
+ if (patternlab.config.debug) {
+ console.log('writing patternlab debug file to ./patternlab.json');
+ fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, null, 3));
+ }
+ }
+
+ function _getExtension(filename) {
+ var ext = filename.split('.');
+ return ext[ext.length - 1];
+ }
+
+ function _renderTemplate(name, data, partials) {
+ var template = templates[name] || false;
+
+ if (!template) {
+ console.log('Template ' + name + ' not found');
+ return '';
+ }
+
+ if (!renderEngines[template.type]) {
+ throw new Error('Missing rendering engine for "' + templates.type + '"-templates');
+ }
+ if (partials) {
+ return renderEngines[template.type].render(template.template, data, partials);
+ }
+ return renderEngines[template.type].render(template.template, data);
+ }
+
+ function _readTemplate(src, type) {
+ var name = src;
+ if (arguments.length === 1) {
+ if (typeof src === 'object') {
+ name = src.name || src.src;
+ type = src.type || _getExtension(src.src);
+ src = src.src;
+ } else {
+ type = _getExtension(src);
+ }
+ }
+ var template = fs.readFileSync(src, 'utf8');
+
+ templates[name] = {
+ template: template,
+ type : type
+ };
+ return {
+ render: function (data, partials) {
+ return _renderTemplate(name, data, partials);
+ }
+ };
+ }
+
+ function buildPatterns() { // removed callback variable - not used
+ patternlab.data = fs.readJSONSync('./source/_data/data.json');
+ patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json');
+
+ // Read header and footers
+ patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8');
+ patternlab.footer = _readTemplate({
+ src : './source/_patternlab-files/pattern-header-footer/footer.html',
+ name : 'footer',
+ type : 'mustache'
+ });
+ patternlab.readme = _readTemplate({
+ src : './source/_patternlab-files/pattern-header-footer/readme.html',
+ name : 'readme',
+ type : 'mustache'
+ });
+
+ patternlab.patterns = [];
+ patternlab.patternIndex = [];
+ patternlab.partials = {};
+
+ diveSync(patternlab.config.patterns.source, function (err, file) {
+ //log any errors
+ if (err) {
+ console.log(err);
+ return;
+ }
+
+ //extract some information
+ var abspath = file.substring(2),
+ subdir = path.dirname(path.relative('./source/_patterns', file)),
+ filename = path.basename(file);
+
+ //check if the pattern already exists.
+ var patternName = filename.substring(0, filename.indexOf('.')),
+ //patternIndex = patternlab.patternIndex.indexOf(subdir + '-' + patternName),
+ currentPattern,
+ flatPatternPath;
+
+ //Get file extension
+ var fileType = path.extname(file);
+
+ //ignore _underscored patterns, json, and dotfiles
+ if (filename.charAt(0) === '_' || fileType === '.json' || fileType === '.md' || filename.charAt(0) === '.') {
+ return;
+ }
+
+ //make a new Pattern Object
+ var flatPatternName = subdir.replace(/[\\\/]/g, '-') + '-' + patternName;
+ flatPatternName = flatPatternName.replace(/\\/g, '-');
+ currentPattern = new of.oPattern(flatPatternName, subdir, filename, {});
+ currentPattern.patternName = patternName.substring(patternName.indexOf('-') + 1);
+ currentPattern.data = null;
+
+ //see if this file has a state
+ if (patternlab.config.patternStates[currentPattern.patternName]) {
+ currentPattern.patternState = patternlab.config.patternStates[currentPattern.patternName];
+ }
+
+ //look for a json file for this template
+ try {
+ var jsonFilename = abspath.substr(0, abspath.lastIndexOf(".")) + ".json";
+ currentPattern.data = fs.readJSONSync(jsonFilename);
+ } catch (ignore) {}
+
+ currentPattern.template = fs.readFileSync(abspath, 'utf8');
+
+ //render the pattern. pass partials object just in case.
+ if (currentPattern.data) { // Pass JSON as data
+ currentPattern.patternPartial = _readTemplate(abspath).render(currentPattern.data, patternlab.partials);
+ } else { // Pass global patternlab data
+ currentPattern.patternPartial = _readTemplate(abspath).render(patternlab.data, patternlab.partials);
+ }
+
+ // Add readme docs
+ var readme = '';
+ try {
+ var doc = abspath.substr(0, abspath.lastIndexOf('.')) + '.md';
+ readme = patternlab.readme.render({
+ readme: markdown.toHTML(fs.readFileSync(doc, {encoding: 'utf8'}))
+ });
+ console.log(readme);
+ } catch (ignore) {}
+
+ //write the compiled template to the public patterns directory
+ flatPatternPath = currentPattern.name + '/' + currentPattern.name + '.html';
+
+ //add footer info before writing
+ var currentPatternFooter = patternlab.footer.render(currentPattern);
+
+ fs.outputFileSync('./public/patterns/' + flatPatternPath, patternlab.header + currentPattern.patternPartial + readme + currentPatternFooter);
+ currentPattern.patternLink = flatPatternPath;
+
+ //add as a partial in case this is referenced later. convert to syntax needed by existing patterns
+ var sub = subdir.substring(subdir.indexOf('-') + 1);
+ var folderIndex = sub.indexOf('/'); //THIS IS MOST LIKELY WINDOWS ONLY. path.sep not working yet
+ var cleanSub = sub.substring(0, folderIndex);
+
+ //add any templates found to an object of partials, so downstream templates may use them too
+ //exclude the template patterns - we don't need them as partials because pages will just swap data
+ if (cleanSub !== '') {
+ var partialname = cleanSub + '-' + patternName.substring(patternName.indexOf('-') + 1);
+
+ patternlab.partials[partialname] = currentPattern.template;
+
+ //done
+ }
+
+ //add to patternlab arrays so we can look these up later. this could probably just be an object.
+ //patternlab.patternIndex.push(currentPattern.name);
+ patternlab.patterns.push(currentPattern);
+ });
+
+ }
+
+ function addToPatternPaths(bucketName, pattern) {
+ //this is messy, could use a refactor.
+ patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.filename.substring(0, pattern.filename.indexOf('.'));
+ }
+
+ function buildFrontEnd() {
+ patternlab.buckets = [];
+ patternlab.bucketIndex = [];
+ patternlab.patternPaths = {};
+ patternlab.viewAllPaths = {};
+
+ var styleguideHtml,
+ i,
+ l,
+ pattern,
+ bucket,
+ bucketName,
+ bucketIndex,
+ navItem,
+ navSubItem,
+ navSubItemName,
+ navItemName,
+ navItemIndex,
+ flatPatternItem;
+
+ //build the styleguide
+ styleguideHtml = _readTemplate('./source/_patternlab-files/styleguide.mustache', 'mustache').render({partials: patternlab.patterns});
+ fs.outputFileSync('./public/styleguide/html/styleguide.html', styleguideHtml);
+
+ //loop through all patterns. deciding to do this separate from the recursion, even at a performance hit, to attempt to separate the tasks of styleguide creation versus site menu creation
+ for (i = 0, l = patternlab.patterns.length; i < l; i++) {
+ pattern = patternlab.patterns[i];
+ bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];
+
+ //check if the bucket already exists
+ bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
+ if (bucketIndex === -1) {
+ //add the bucket
+ bucket = new of.oBucket(bucketName);
+
+ //add paternPath
+ patternlab.patternPaths[bucketName] = {};
+
+ //get the navItem
+ navItemName = pattern.subdir.split('-').pop();
+
+ //get the navSubItem
+ navSubItemName = pattern.patternName.replace(/-/g, ' ');
+
+ //test whether the pattern struture is flat or not - usually due to a template or page
+ flatPatternItem = false;
+ if (navItemName === bucketName) {
+ flatPatternItem = true;
+ }
+
+ //assume the navItem does not exist.
+ navItem = new of.oNavItem(navItemName);
+
+ //assume the navSubItem does not exist.
+ navSubItem = new of.oNavSubItem(navSubItemName);
+ navSubItem.patternPath = pattern.patternLink;
+ navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name
+
+ //add the patternState if it exists
+ if (pattern.patternState) {
+ navSubItem.patternState = pattern.patternState;
+ }
+
+ //if it is flat - we should not add the pattern to patternPaths
+ if (flatPatternItem) {
+ bucket.patternItems.push(navSubItem);
+
+ //add to patternPaths
+ addToPatternPaths(bucketName, pattern);
+ } else {
+ bucket.navItems.push(navItem);
+ bucket.navItemsIndex.push(navItemName);
+ navItem.navSubItems.push(navSubItem);
+ navItem.navSubItemsIndex.push(navSubItemName);
+
+ //add to patternPaths
+ addToPatternPaths(bucketName, pattern);
+ }
+
+ //add the bucket.
+ patternlab.buckets.push(bucket);
+ patternlab.bucketIndex.push(bucketName);
+
+ //done
+
+ } else {
+ //find the bucket
+ bucket = patternlab.buckets[bucketIndex];
+
+ //get the navItem
+ navItemName = pattern.subdir.split('-').pop();
+
+ //get the navSubItem
+ navSubItemName = pattern.patternName.replace(/-/g, ' ');
+
+ //assume the navSubItem does not exist.
+ navSubItem = new of.oNavSubItem(navSubItemName);
+ navSubItem.patternPath = pattern.patternLink;
+ navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name
+
+ //add the patternState if it exists
+ if (pattern.patternState) {
+ navSubItem.patternState = pattern.patternState;
+ }
+
+ //test whether the pattern struture is flat or not - usually due to a template or page
+ flatPatternItem = false;
+ if (navItemName === bucketName) {
+ flatPatternItem = true;
+ }
+
+ //if it is flat - we should not add the pattern to patternPaths
+ if (flatPatternItem) {
+
+ //add the navItem to patternItems
+ bucket.patternItems.push(navSubItem);
+
+ //add to patternPaths
+ addToPatternPaths(bucketName, pattern);
+
+ } else {
+ //check to see if navItem exists
+ navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
+ if (navItemIndex === -1) {
+
+ navItem = new of.oNavItem(navItemName);
+
+ //add the navItem and navSubItem
+ navItem.navSubItems.push(navSubItem);
+ navItem.navSubItemsIndex.push(navSubItemName);
+ bucket.navItems.push(navItem);
+ bucket.navItemsIndex.push(navItemName);
+
+ } else {
+ //add the navSubItem
+ navItem = bucket.navItems[navItemIndex];
+ navItem.navSubItems.push(navSubItem);
+ navItem.navSubItemsIndex.push(navSubItemName);
+ }
+
+ // just add to patternPaths
+ addToPatternPaths(bucketName, pattern);
+ }
+
+ }
+
+ }
+
+ //the patternlab site requires a lot of partials to be rendered.
+ //patternNav
+ var patternNavPartialHtml = _readTemplate('./source/_patternlab-files/partials/patternNav.mustache').render(patternlab);
+
+ //ishControls
+ var ishControlsPartialHtml = _readTemplate('./source/_patternlab-files/partials/ishControls.mustache').render(patternlab.config);
+
+ //patternPaths
+ var patternPathsPartialHtml = _readTemplate('./source/_patternlab-files/partials/patternPaths.mustache').render({'patternPaths': JSON.stringify(patternlab.patternPaths)});
+
+ //viewAllPaths
+ var viewAllPathersPartialHtml = _readTemplate('./source/_patternlab-files/partials/viewAllPaths.mustache').render({'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});
+
+ //websockets
+ patternlab.contentsyncport = patternlab.config.contentSyncPort;
+ patternlab.navsyncport = patternlab.config.navSyncPort;
+
+ var websocketsPartialHtml = _readTemplate('./source/_patternlab-files/partials/websockets.mustache').render(patternlab);
+
+ //render the patternlab template, with all partials
+ var patternlabSiteHtml = _readTemplate('./source/_patternlab-files/index.mustache').render({}, {
+ 'ishControls': ishControlsPartialHtml,
+ 'patternNav': patternNavPartialHtml,
+ 'patternPaths': patternPathsPartialHtml,
+ 'websockets': websocketsPartialHtml,
+ 'viewAllPaths': viewAllPathersPartialHtml
+ });
+ fs.outputFileSync('./public/index.html', patternlabSiteHtml);
+ }
+
+ return {
+ version: function () {
+ return getVersion();
+ },
+ build: function () {
+ buildPatterns();
+ buildFrontEnd();
+ printDebug();
+ },
+ help: function () {
+ help();
+ },
+ build_patterns_only: function () {
+ buildPatterns();
+ printDebug();
+ }
+ };
};
diff --git a/config.json b/config.json
index 65a6e56fa..b094156fe 100644
--- a/config.json
+++ b/config.json
@@ -1,33 +1,36 @@
- {
- "patterns" : {
- "source" : "./source/_patterns/",
- "public" : "./public/patterns/"
- },
- "ignored-extensions" : ["scss", "DS_Store", "less"],
- "ignored-directories" : ["scss"],
- "contentSyncPort" : 8002,
- "navSyncPort" : 8003,
- "debug": false,
- "ishControlsVisible": {
- "s": true,
- "m": true,
- "l": true,
- "full": true,
- "ranndom": true,
- "disco": true,
- "hay": true,
- "mqs": false,
- "find": false,
- "views-all": true,
- "views-annotations": true,
- "views-code": true,
- "views-new": true,
- "tools-all": true,
- "tools-follow": false,
- "tools-reload": false,
- "tools-shortcuts": false,
- "tools-docs": true
- },
- "patternStates": {
- }
- }
\ No newline at end of file
+{
+ "patterns" : {
+ "source" : "./source/_patterns/",
+ "public" : "./public/patterns/"
+ },
+ "ignored-extensions" : ["scss", "DS_Store", "less"],
+ "ignored-directories" : ["scss"],
+ "rendering-engines": {
+ "mustache": "../lib/render_engines/mustache.js"
+ },
+ "contentSyncPort" : 8002,
+ "navSyncPort" : 8003,
+ "debug": false,
+ "ishControlsVisible": {
+ "s": true,
+ "m": true,
+ "l": true,
+ "full": true,
+ "ranndom": true,
+ "disco": true,
+ "hay": true,
+ "mqs": false,
+ "find": false,
+ "views-all": true,
+ "views-annotations": true,
+ "views-code": true,
+ "views-new": true,
+ "tools-all": true,
+ "tools-follow": false,
+ "tools-reload": false,
+ "tools-shortcuts": false,
+ "tools-docs": true
+ },
+ "patternStates": {
+ }
+}
\ No newline at end of file
diff --git a/lib/render_engines/mustache.js b/lib/render_engines/mustache.js
new file mode 100644
index 000000000..832e37ba0
--- /dev/null
+++ b/lib/render_engines/mustache.js
@@ -0,0 +1,14 @@
+/*jslint indent:4*/
+'use strict';
+var mustache = require('mustache');
+
+function render(name, data, partials) {
+ if (partials) {
+ return mustache.render(name, data, partials);
+ }
+ return mustache.render(name, data);
+}
+
+module.exports = {
+ render: render
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 6d8487426..b660d96db 100644
--- a/package.json
+++ b/package.json
@@ -3,19 +3,19 @@
"description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).",
"version": "0.1.3",
"devDependencies": {
+ "diveSync": "^0.2.1",
+ "fs-extra": "^0.10.0",
"grunt": "~0.4.0",
- "grunt-contrib-watch": "~0.2.0",
- "grunt-contrib-sass": "~0.2.2",
- "grunt-contrib-copy": "~0.4.0",
- "grunt-contrib-jshint": "~0.4.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-concat": "~0.3.0",
- "grunt-contrib-nodeunit": "~0.3.0",
"grunt-contrib-connect": "^0.8.0",
- "mustache": "~0.8.1",
+ "grunt-contrib-copy": "~0.4.0",
+ "grunt-contrib-jshint": "~0.4.0",
+ "grunt-contrib-nodeunit": "~0.3.0",
+ "grunt-contrib-sass": "^0.8.1",
+ "grunt-contrib-watch": "~0.2.0",
"matchdep": "~0.3.0",
- "fs-extra": "^0.10.0",
- "diveSync": "^0.2.1"
+ "mustache": "~0.8.1"
},
"keywords": [
"Pattern Lab",
@@ -35,5 +35,8 @@
},
"engines": {
"node": ">=0.1"
+ },
+ "dependencies": {
+ "markdown": "^0.5.0"
}
}
diff --git a/public/listeners/synclisteners.js b/public/listeners/synclisteners.js
index a76ee4921..94edfec35 100644
--- a/public/listeners/synclisteners.js
+++ b/public/listeners/synclisteners.js
@@ -18,7 +18,7 @@ var wsnConnected = false;
var wsc;
var wscConnected = false;
var dataPrevious = 0;
-var host = (window.location.host != "") ? window.location.host : "127.0.0.1";
+var host = (window.location.host !== '') ? window.location.hostname : '127.0.0.1';
// handle page updates from one browser to another
function connectNavSync() {
@@ -26,6 +26,7 @@ function connectNavSync() {
if ('WebSocket' in window && window.WebSocket.CLOSING === 2) {
var navSyncCopy = "Page Follow";
+
wsn = new WebSocket("ws://"+host+":"+navSyncPort+"/navsync");
// when trying to open a connection to WebSocket update the pattern lab nav bar
diff --git a/public/styleguide/css/static.css b/public/styleguide/css/static.css
index e69de29bb..ba6048be1 100644
--- a/public/styleguide/css/static.css
+++ b/public/styleguide/css/static.css
@@ -0,0 +1,457 @@
+@charset "UTF-8";
+/*
+colors
+red: $orange; rgb(229,24,55)
+gray: #808080;
+*/
+/************Reset**************/
+* {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+html, body, div, object, iframe, fieldset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+ol, ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+header, footer, nav, section, article, hgroup, figure {
+ display: block;
+}
+
+legend {
+ display: none;
+}
+
+/************End Reset**************/
+/************Global**************/
+body {
+ background: #fff;
+ color: #000;
+ font: 100%/1.4 "HelveticaNeue", "Helvetica", "Arial", sans-serif;
+ padding: 0;
+ -webkit-text-size-adjust: 100%;
+ border-top: 20px solid #000;
+ border-bottom: 20px solid #000;
+}
+
+a {
+ color: #808080;
+ text-decoration: none;
+}
+
+a:hover, a:focus {
+ color: #bededf;
+}
+
+p {
+ margin: 0 0 1em;
+}
+
+img, object, video {
+ max-width: 100%;
+ border: 0;
+}
+
+a img {
+ border: 0;
+ outline: 0;
+}
+
+h1 {
+ font-size: 3em;
+ line-height: 1;
+ letter-spacing: -0.02em;
+ margin-bottom: 0.2em;
+}
+
+h2 {
+ font-size: 2em;
+ line-height: 1.1;
+ margin-bottom: 0.2em;
+}
+
+h3 {
+ font-weight: normal;
+ line-height: 1.1;
+ padding-bottom: 0.4em;
+ border-bottom: 1px solid #ccc;
+}
+
+h1 a, h2 a, h3 a {
+ display: block;
+ color: #000;
+}
+
+h1 a:hover, h2 a:hover, h3 a:hover {
+ color: #bededf;
+}
+
+blockquote {
+ border-left: 0.5em solid #ddd;
+ padding-left: 1em;
+ margin-left: 1em;
+}
+
+small {
+ color: #bededf;
+}
+
+input[type=search] {
+ -webkit-appearance: none;
+ border-radius: 0;
+}
+
+::-webkit-input-placeholder {
+ color: #808080;
+}
+
+:-moz-placeholder {
+ color: #808080;
+}
+
+/************End Global**************/
+/************Classes**************/
+.inactive {
+ color: #ddd;
+}
+
+/************End Classes**************/
+/************Structure**************/
+.container {
+ max-width: 60em;
+ margin: 0 auto;
+ padding: 0 1em;
+ overflow: hidden;
+}
+
+[role=main] {
+ padding-bottom: 1em;
+}
+
+/*Footer*/
+[role=contentinfo] {
+ color: #fff;
+ background: #000;
+ margin: 0 -1em;
+ position: relative;
+ z-index: 2;
+}
+[role=contentinfo] > div {
+ max-width: 60em;
+ padding: 0 1em;
+ margin: 0 auto;
+ overflow: hidden;
+}
+
+/*End Footer*/
+/*Grid*/
+.grid {
+ margin: 0 -1em;
+ overflow: hidden;
+}
+
+.grid:target {
+ -webkit-animation: fadeout 5s 1 ease-out;
+ -moz-animation: fadeout 5s 1 ease-out;
+ -o-animation: fadeout 5s 1 ease-out;
+ animation: fadeout 5s 1 ease-out;
+}
+
+.grid > h2 {
+ margin-left: 0.45em;
+}
+
+.grid > section {
+ padding: 1em 1em 0.5em;
+}
+
+.grid > section:target {
+ -webkit-animation: fadeout 5s 1 ease-out;
+ -moz-animation: fadeout 5s 1 ease-out;
+ -o-animation: fadeout 5s 1 ease-out;
+ animation: fadeout 5s 1 ease-out;
+}
+
+.grid ul {
+ overflow: hidden;
+}
+
+.grid ul li {
+ margin-bottom: 0.3em;
+}
+
+.featured:after {
+ content: "*";
+ color: #bededf;
+}
+
+/*Fluid*/
+.fluid {
+ display: block;
+ margin: 0 auto;
+ max-width: 40em;
+}
+
+/*Homepage*/
+.home h1 {
+ margin-bottom: 0.2em;
+}
+
+.intro {
+ font-size: 1.8em;
+ line-height: 1.2;
+ margin: 0 auto;
+}
+
+.intro a:hover, .intro a:focus {
+ color: #000;
+ border-bottom-color: #000;
+}
+
+.ani {
+ position: relative;
+ height: 15em;
+ margin: 1em 0 0;
+ width: 100%;
+ z-index: 0;
+}
+
+.ani div {
+ width: 100%;
+}
+
+.ani div b {
+ display: block;
+ position: absolute;
+ top: 5%;
+ right: 5%;
+ bottom: 5%;
+ left: 5%;
+ background: rgba(229, 24, 55, 0.22);
+}
+
+/*Patterns*/
+.mod {
+ padding: 1em;
+}
+
+.pattern {
+ background: #f7f7f7;
+ border-bottom: 1px solid #808080;
+ margin-bottom: 1em;
+ overflow: hidden;
+}
+
+.pattern-description h1 {
+ font-size: 3.4em;
+ margin-bottom: 0.5em;
+}
+
+.pattern-description {
+ max-width: 40em;
+ margin: 0 auto;
+}
+
+.pattern-description ul, .pattern-description ol {
+ margin-bottom: 2em;
+}
+
+.pattern-description li {
+ margin-bottom: 1em;
+}
+
+/*Blog*/
+/*Blog Header*/
+.blog .container {
+ max-width: 62em;
+}
+
+.blog header[role=banner] {
+ overflow: hidden;
+ margin-bottom: 2em;
+ padding: 2em 0 1em;
+ border-bottom: 1px solid #000;
+}
+
+.blog-logo {
+ font-weight: normal;
+ font-size: 1.2em;
+ margin: 0 0 1em;
+}
+
+.blog-logo img {
+ width: 3.3em;
+}
+
+.blog-logo a {
+ color: #000;
+}
+
+.search-form {
+ width: 100%;
+ margin-bottom: 1em;
+}
+
+.search-field {
+ width: 100%;
+ padding: 0.5em 0;
+ border: 0;
+ border-bottom: 1px solid #808080;
+ outline: none;
+}
+
+.search-field:focus {
+ background: #bededf;
+ color: #fff;
+}
+
+.search-field:focus::-webkit-input-placeholder {
+ color: #fff;
+}
+
+.search-field:focus :-moz-placeholder {
+ color: #fff;
+}
+
+.blog .nav {
+ clear: both;
+}
+
+.blog .nav a {
+ display: block;
+ font-weight: bold;
+ color: #000;
+}
+
+.blog .nav a:hover {
+ color: #bededf;
+}
+
+/*Posts*/
+.posts ol > li {
+ padding-bottom: 1em;
+ border-bottom: 1px solid #ccc;
+ margin-bottom: 1em;
+ overflow: hidden;
+}
+
+.posts h2 {
+ font-size: 1.4em;
+ margin: 0.28em 0 0.1em;
+ font-weight: normal;
+}
+
+.posts h2 a {
+ color: #000;
+}
+
+.posts h2 a:hover, .posts h2 a:focus {
+ color: #bededf;
+}
+
+.permalink {
+ display: block;
+ font-size: 0.8em;
+ margin-bottom: 1.2em;
+}
+
+.post-body a {
+ border-bottom: 1px solid #ccc;
+}
+
+.posts blockquote {
+ margin: 0 0 1em;
+ color: #666;
+ border-left: 0.25em solid #ccc;
+ padding-left: 1em;
+}
+
+.tags {
+ float: left;
+}
+
+.tags li {
+ display: inline-block;
+ font-size: 0.8em;
+ margin-right: 0.5em;
+}
+
+.posts ol > li .tags a, .permalink {
+ color: #ccc;
+ -webkit-transition: color 0.3s ease-out;
+ -moz-transition: color 0.3s ease-out;
+ -ms-transition: color 0.3s ease-out;
+ -o-transition: color 0.3s ease-out;
+ transition: color 0.3s ease-out;
+}
+
+.posts ol > li:hover .tags a, .posts ol > li:hover .permalink {
+ color: #808080;
+}
+
+.blog-nav {
+ text-align: center;
+ overflow: hidden;
+ padding: 1em 0;
+}
+
+.posts .blog-nav a {
+ border: 0;
+}
+
+.nav-next {
+ float: right;
+}
+
+.nav-prev {
+ float: left;
+}
+
+/* Sidebar */
+.sidebar {
+ font-size: 0.8em;
+ padding-bottom: 1.4em;
+}
+
+.sidebar div {
+ margin-bottom: 2em;
+}
+
+.sidebar h3 {
+ font-weight: bold;
+ font-size: 0.9em;
+ line-height: 1;
+ border-bottom: 1px solid #000;
+}
+
+.sidebar a {
+ color: #808080;
+}
+
+.sidebar a:hover, .sidebar a:focus {
+ color: #bededf;
+}
+
+.top {
+ clear: both;
+ display: block;
+ padding: 1em 0;
+}
+
+.top:before {
+ content: '▲';
+}
diff --git a/public/styleguide/css/static.css.map b/public/styleguide/css/static.css.map
new file mode 100644
index 000000000..ba4ca1494
--- /dev/null
+++ b/public/styleguide/css/static.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": ";;;;;;;AAWA,CAAE;EACD,eAAe,EAAE,UAAU;EAC3B,kBAAkB,EAAE,UAAU;EAC9B,UAAU,EAAE,UAAU;;;AAEvB,yCAA0C;EACzC,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;;;AAEV,MAAO;EACN,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AAEX,KAAM;EACL,eAAe,EAAE,QAAQ;EACzB,cAAc,EAAE,CAAC;;;AAElB,qDAAsD;EACrD,OAAO,EAAE,KAAK;;;AAEf,MAAO;EACN,OAAO,EAAE,IAAI;;;;;AAKd,IAAK;EACJ,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,0DAA0D;EAChE,OAAO,EAAE,CAAC;EACV,wBAAwB,EAAE,IAAI;EAC9B,UAAU,EAAE,eAAe;EAC3B,aAAa,EAAE,eAAe;;;AAE/B,CAAE;EACD,KAAK,EAAE,OAAO;EACd,eAAe,EAAE,IAAI;;;AAEtB,gBAAiB;EAChB,KAAK,EA/CI,OAAO;;;AAiDjB,CAAE;EACD,MAAM,EAAE,OAAO;;;AAEhB,kBAAmB;EAClB,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,CAAC;;;AAEV,KAAM;EACL,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AAEX,EAAG;EACF,SAAS,EAAE,GAAG;EACd,WAAW,EAAE,CAAC;EACd,cAAc,EAAE,OAAO;EACvB,aAAa,EAAE,KAAK;;;AAErB,EAAG;EACF,SAAS,EAAE,GAAG;EACd,WAAW,EAAE,GAAG;EAChB,aAAa,EAAE,KAAK;;;AAErB,EAAG;EACF,WAAW,EAAE,MAAM;EACnB,WAAW,EAAE,GAAG;EAChB,cAAc,EAAE,KAAK;EACrB,aAAa,EAAE,cAAc;;;AAE9B,gBAAiB;EAChB,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;;;AAEZ,kCAAmC;EAClC,KAAK,EAlFI,OAAO;;;AAoFjB,UAAW;EACV,WAAW,EAAE,gBAAgB;EAC7B,YAAY,EAAE,GAAG;EACjB,WAAW,EAAE,GAAG;;;AAEjB,KAAM;EACL,KAAK,EA1FI,OAAO;;;AA4FjB,kBAAmB;EAClB,kBAAkB,EAAE,IAAI;EACxB,aAAa,EAAE,CAAC;;;AAEjB,2BAA4B;EAC3B,KAAK,EAAE,OAAO;;;AAEf,iBAAkB;EACd,KAAK,EAAE,OAAO;;;;;AAKlB,SAAU;EACT,KAAK,EAAE,IAAI;;;;;AAKZ,UAAW;EACV,SAAS,EA9GE,IAAI;EA+Gf,MAAM,EAAE,MAAM;EACd,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,MAAM;;;AAGjB,WAAY;EACX,cAAc,EAAE,GAAG;;;;AAIpB,kBAAmB;EAClB,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,MAAM;EACd,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,CAAC;;AAEV,wBAAM;EACL,SAAS,EAjIC,IAAI;EAkId,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,MAAM;EACd,QAAQ,EAAE,MAAM;;;;;AAMlB,KAAM;EACL,MAAM,EAAE,MAAM;EACd,QAAQ,EAAE,MAAM;;;AAEjB,YAAa;EACZ,iBAAiB,EAAE,qBAAqB;EACrC,cAAc,EAAE,qBAAqB;EACrC,YAAY,EAAE,qBAAqB;EACnC,SAAS,EAAE,qBAAqB;;;AAEpC,UAAW;EACV,WAAW,EAAE,MAAM;;;AAEpB,eAAgB;EACf,OAAO,EAAE,aAAa;;;AAEvB,sBAAuB;EACtB,iBAAiB,EAAE,qBAAqB;EACrC,cAAc,EAAE,qBAAqB;EACrC,YAAY,EAAE,qBAAqB;EACnC,SAAS,EAAE,qBAAqB;;;AAEpC,QAAS;EACR,QAAQ,EAAE,MAAM;;;AAEjB,WAAY;EACX,aAAa,EAAE,KAAK;;;AAErB,eAAgB;EACf,OAAO,EAAE,GAAG;EACZ,KAAK,EA1KI,OAAO;;;;AA8KjB,MAAO;EACN,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,MAAM;EACd,SAAS,EAAE,IAAI;;;;AAIhB,QAAS;EACR,aAAa,EAAE,KAAK;;;AAErB,MAAO;EACN,SAAS,EAAE,KAAK;EAChB,WAAW,EAAE,GAAG;EAChB,MAAM,EAAE,MAAM;;;AAEf,8BAA+B;EAC9B,KAAK,EAAE,IAAI;EACX,mBAAmB,EAAE,IAAI;;;AAG1B,IAAK;EACJ,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,OAAO;EACf,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,CAAC;;;AAEX,QAAS;EACR,KAAK,EAAE,IAAI;;;AAEZ,UAAW;EACV,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,EAAE;EACP,KAAK,EAAE,EAAE;EACT,MAAM,EAAE,EAAE;EACV,IAAI,EAAE,EAAE;EACR,UAAU,EAAE,uBAAoB;;;;AAKjC,IAAK;EACJ,OAAO,EAAE,GAAG;;;AAEb,QAAS;EACR,UAAU,EAAE,OAAO;EACnB,aAAa,EAAE,iBAAiB;EAChC,aAAa,EAAE,GAAG;EAClB,QAAQ,EAAE,MAAM;;;AAEjB,uBAAwB;EACvB,SAAS,EAAE,KAAK;EAChB,aAAa,EAAE,KAAK;;;AAErB,oBAAqB;EACpB,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,MAAM;;;AAEf,gDAAiD;EAChD,aAAa,EAAE,GAAG;;;AAEnB,uBAAwB;EACvB,aAAa,EAAE,GAAG;;;;;AAMnB,gBAAiB;EAChB,SAAS,EAAE,IAAI;;;AAEhB,yBAA0B;EACzB,QAAQ,EAAE,MAAM;EAChB,aAAa,EAAE,GAAG;EAClB,OAAO,EAAE,SAAS;EAClB,aAAa,EAAE,cAAc;;;AAE9B,UAAW;EACV,WAAW,EAAE,MAAM;EACnB,SAAS,EAAE,KAAK;EAChB,MAAM,EAAE,OAAO;;;AAEhB,cAAe;EACd,KAAK,EAAE,KAAK;;;AAEb,YAAa;EACZ,KAAK,EAAE,IAAI;;;AAEZ,YAAa;EACZ,KAAK,EAAE,IAAI;EACX,aAAa,EAAE,GAAG;;;AAEnB,aAAc;EACb,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,OAAO;EAChB,MAAM,EAAE,CAAC;EACT,aAAa,EAAE,iBAAiB;EAChC,OAAO,EAAE,IAAI;;;AAEd,mBAAoB;EACnB,UAAU,EAnRD,OAAO;EAoRhB,KAAK,EAAE,IAAI;;;AAEZ,8CAA+C;EAC5C,KAAK,EAAE,IAAI;;;AAGd,qCAAsC;EACnC,KAAK,EAAE,IAAI;;;AAGd,UAAW;EACV,KAAK,EAAE,IAAI;;;AAEZ,YAAa;EACZ,OAAO,EAAE,KAAK;EACd,WAAW,EAAE,IAAI;EACjB,KAAK,EAAE,IAAI;;;AAEZ,kBAAmB;EAClB,KAAK,EAvSI,OAAO;;;;AA2SjB,cAAe;EACd,cAAc,EAAE,GAAG;EACnB,aAAa,EAAE,cAAc;EAC7B,aAAa,EAAE,GAAG;EAClB,QAAQ,EAAE,MAAM;;;AAEjB,SAAU;EACT,SAAS,EAAE,KAAK;EAChB,MAAM,EAAE,cAAc;EACtB,WAAW,EAAE,MAAM;;;AAEpB,WAAY;EACX,KAAK,EAAE,IAAI;;;AAEZ,oCAAqC;EACpC,KAAK,EA1TI,OAAO;;;AA4TjB,UAAW;EACV,OAAO,EAAE,KAAK;EACd,SAAS,EAAE,KAAK;EAChB,aAAa,EAAE,KAAK;;;AAErB,YAAa;EACZ,aAAa,EAAE,cAAc;;;AAE9B,iBAAkB;EACjB,MAAM,EAAE,OAAO;EACf,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,iBAAiB;EAC9B,YAAY,EAAE,GAAG;;;AAElB,KAAM;EACL,KAAK,EAAE,IAAI;;;AAEZ,QAAS;EACR,OAAO,EAAE,YAAY;EACrB,SAAS,EAAE,KAAK;EAChB,YAAY,EAAE,KAAK;;;AAGpB,kCAAmC;EAClC,KAAK,EAAE,IAAI;EACX,kBAAkB,EAAE,mBAAmB;EACnC,eAAe,EAAE,mBAAmB;EACnC,cAAc,EAAE,mBAAmB;EAClC,aAAa,EAAE,mBAAmB;EAC/B,UAAU,EAAE,mBAAmB;;;AAEzC,6DAA8D;EAC7D,KAAK,EAAE,OAAO;;;AAEf,SAAU;EACT,UAAU,EAAE,MAAM;EAClB,QAAQ,EAAE,MAAM;EAChB,OAAO,EAAE,KAAK;;;AAEf,kBAAmB;EAClB,MAAM,EAAE,CAAC;;;AAEV,SAAU;EACT,KAAK,EAAE,KAAK;;;AAEb,SAAU;EACT,KAAK,EAAE,IAAI;;;;AAIZ,QAAS;EACR,SAAS,EAAE,KAAK;EAChB,cAAc,EAAE,KAAK;;;AAEtB,YAAa;EACZ,aAAa,EAAE,GAAG;;;AAEnB,WAAY;EACX,WAAW,EAAE,IAAI;EACjB,SAAS,EAAE,KAAK;EAChB,WAAW,EAAE,CAAC;EACd,aAAa,EAAE,cAAc;;;AAE9B,UAAW;EACV,KAAK,EAAE,OAAO;;;AAEf,kCAAmC;EAClC,KAAK,EA/XI,OAAO;;;AAqYjB,IAAK;EACJ,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,KAAK;;;AAEf,WAAY;EACX,OAAO,EAAE,GAAG",
+"sources": ["file:///Users/tor/projects/patternlab-node/public/styleguide/css/static.scss"],
+"names": [],
+"file": "static.css"
+}
diff --git a/public/styleguide/css/styleguide.css b/public/styleguide/css/styleguide.css
index 459a602d7..7c097b592 100644
--- a/public/styleguide/css/styleguide.css
+++ b/public/styleguide/css/styleguide.css
@@ -52,12 +52,14 @@
#patternlab-html, #patternlab-body {
margin: 0;
padding: 0;
- background: #dddddd;
- -webkit-text-size-adjust: 100%; }
+ background: #ddd;
+ -webkit-text-size-adjust: 100%;
+}
.sg-nav-wrapper {
overflow: hidden;
- background: #dddddd; }
+ background: #ddd;
+}
.is-vishidden {
position: absolute !important;
@@ -66,78 +68,93 @@
height: 1px;
padding: 0;
border: 0;
- clip: rect(1px, 1px, 1px, 1px); }
+ clip: rect(1px, 1px, 1px, 1px);
+}
.sg-cf, .sg-pattern {
- /**zoom: 1;*/ }
- .sg-cf:before, .sg-pattern:before, .sg-cf:after, .sg-pattern:after {
- content: " ";
- display: table; }
- .sg-cf:after, .sg-pattern:after {
- clear: both; }
+ /**zoom: 1;*/
+}
+.sg-cf:before, .sg-pattern:before, .sg-cf:after, .sg-pattern:after {
+ content: " ";
+ display: table;
+}
+.sg-cf:after, .sg-pattern:after {
+ clear: both;
+}
/*------------------------------------*\
$PATTERN LAB HEADER
\*------------------------------------*/
/* Header */
.sg-header {
- background: #222222;
- color: white;
+ background: #222;
+ color: #fff;
font-family: "HelveticaNeue", "Helvetica", "Arial", sans-serif;
text-transform: uppercase;
position: fixed;
top: 0;
left: 0;
z-index: 2;
- width: 100%; }
- .sg-header * {
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
- box-sizing: border-box; }
- .sg-header ul, .sg-header ol {
- padding: 0;
- margin: 0; }
- .sg-header li {
- list-style: none;
- border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
- .sg-header a {
- font-size: 70%;
- color: gray;
- text-decoration: none;
- display: block;
- line-height: 1;
- padding: 1em;
- -webkit-transition: background 0.15s ease-out;
- -moz-transition: background 0.15s ease-out;
- -ms-transition: background 0.15s ease-out;
- -o-transition: background 0.15s ease-out;
- transition: background 0.15s ease-out;
- -webkit-transition: color 0.15s ease-out;
- -moz-transition: color 0.15s ease-out;
- -ms-transition: color 0.15s ease-out;
- -o-transition: color 0.15s ease-out;
- transition: color 0.15s ease-out; }
- .sg-header a:hover, .sg-header a:focus, .sg-header a.active {
- color: white;
- background: rgba(255, 255, 255, 0.05); }
- .sg-header ol ol ol a {
- padding-left: 2em;
- text-transform: none; }
+ width: 100%;
+}
+.sg-header * {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.sg-header ul, .sg-header ol {
+ padding: 0;
+ margin: 0;
+}
+.sg-header li {
+ list-style: none;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+.sg-header a {
+ font-size: 70%;
+ color: #808080;
+ text-decoration: none;
+ display: block;
+ line-height: 1;
+ padding: 1em;
+ -webkit-transition: background 0.15s ease-out;
+ -moz-transition: background 0.15s ease-out;
+ -ms-transition: background 0.15s ease-out;
+ -o-transition: background 0.15s ease-out;
+ transition: background 0.15s ease-out;
+ -webkit-transition: color 0.15s ease-out;
+ -moz-transition: color 0.15s ease-out;
+ -ms-transition: color 0.15s ease-out;
+ -o-transition: color 0.15s ease-out;
+ transition: color 0.15s ease-out;
+}
+.sg-header a:hover, .sg-header a:focus, .sg-header a.active {
+ color: #fff;
+ background: rgba(255, 255, 255, 0.05);
+}
+.sg-header ol ol ol a {
+ padding-left: 2em;
+ text-transform: none;
+}
/* Navigation */
.sg-header .sg-nav-toggle {
display: inline-block;
padding: 0.9em 1em;
- border-bottom: 1px solid rgba(0, 0, 0, 0);
+ border-bottom: 1px solid transparent;
position: relative;
text-transform: uppercase;
- z-index: 2; }
- .sg-header .sg-nav-toggle span {
- display: inline-block;
- padding-right: 0.2em; }
- @media all and (min-width: 48em) {
- .sg-header .sg-nav-toggle {
- display: none; } }
+ z-index: 2;
+}
+.sg-header .sg-nav-toggle span {
+ display: inline-block;
+ padding-right: 0.2em;
+}
+@media all and (min-width: 48em) {
+ .sg-header .sg-nav-toggle {
+ display: none;
+ }
+}
@media all and (max-width: 48em) {
.sg-nav-container {
@@ -147,48 +164,63 @@
-moz-transition: max-height 0.1s ease-out;
-ms-transition: max-height 0.1s ease-out;
-o-transition: max-height 0.1s ease-out;
- transition: max-height 0.1s ease-out; }
- .sg-nav-container.active {
- max-height: 50em; } }
+ transition: max-height 0.1s ease-out;
+ }
+ .sg-nav-container.active {
+ max-height: 50em;
+ }
+}
.sg-nav {
z-index: 1;
margin: 0;
padding: 0;
- list-style: none; }
+ list-style: none;
+}
+.sg-nav > li {
+ cursor: pointer;
+}
+@media all and (min-width: 48em) {
.sg-nav > li {
- cursor: pointer; }
- @media all and (min-width: 48em) {
- .sg-nav > li {
- border-bottom: 0;
- border-right: 1px solid rgba(255, 255, 255, 0.05);
- float: left;
- position: relative; }
- .sg-nav > li > ol {
- position: absolute;
- top: 2em;
- left: 0; } }
+ border-bottom: 0;
+ border-right: 1px solid rgba(255, 255, 255, 0.05);
+ float: left;
+ position: relative;
+ }
+ .sg-nav > li > ol {
+ position: absolute;
+ top: 2em;
+ left: 0;
+ }
+}
/* Accordion */
.sg-acc-handle:after {
content: ' +';
float: right;
- font-size: 70%; }
- @media all and (min-width: 48em) {
- .sg-acc-handle:after {
- float: none; } }
+ font-size: 70%;
+}
+@media all and (min-width: 48em) {
+ .sg-acc-handle:after {
+ float: none;
+ }
+}
.sg-acc-handle.active {
- color: white;
- background: rgba(255, 255, 255, 0.05); }
- .sg-acc-handle.active:after {
- content: ' -'; }
+ color: #fff;
+ background: rgba(255, 255, 255, 0.05);
+}
+.sg-acc-handle.active:after {
+ content: ' -';
+}
.sg-acc-handle.sg-icon:after {
- content: ""; }
+ content: "";
+}
.sg-header .sg-icon {
width: auto;
font-size: 1rem;
- padding: 0.5rem 1rem; }
+ padding: 0.5rem 1rem;
+}
.sg-acc-panel {
overflow: hidden;
@@ -198,22 +230,28 @@
-moz-transition: max-height 0.1s ease-out;
-ms-transition: max-height 0.1s ease-out;
-o-transition: max-height 0.1s ease-out;
- transition: max-height 0.1s ease-out; }
- .sg-acc-panel li {
- background: #222222; }
- .sg-acc-panel.active {
- max-height: 120em;
- overflow: auto; }
- .sg-acc-panel.sg-right {
- position: absolute;
- left: auto;
- right: 0; }
- .sg-acc-panel.sg-left {
- position: absolute;
- left: auto; }
- .sg-acc-panel [class^="sg-icon-"]:before {
- display: inline-block;
- margin-right: 0.4em; }
+ transition: max-height 0.1s ease-out;
+}
+.sg-acc-panel li {
+ background: #222;
+}
+.sg-acc-panel.active {
+ max-height: 120em;
+ overflow: auto;
+}
+.sg-acc-panel.sg-right {
+ position: absolute;
+ left: auto;
+ right: 0;
+}
+.sg-acc-panel.sg-left {
+ position: absolute;
+ left: auto;
+}
+.sg-acc-panel [class^="sg-icon-"]:before {
+ display: inline-block;
+ margin-right: 0.4em;
+}
/* Controls (sizing, view mode) */
.sg-controls {
@@ -221,74 +259,99 @@
position: absolute;
top: 0;
right: 0;
- z-index: 2; }
+ z-index: 2;
+}
.sg-control-trigger {
- border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
- @media all and (min-width: 48em) {
- .sg-control-trigger {
- border: 0; } }
- @media all and (min-width: 72em) {
- .sg-control-trigger {
- float: left;
- width: 6em; } }
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+@media all and (min-width: 48em) {
+ .sg-control-trigger {
+ border: 0;
+ }
+}
+@media all and (min-width: 72em) {
+ .sg-control-trigger {
+ float: left;
+ width: 6em;
+ }
+}
.sg-control > li {
- float: left; }
- @media all and (min-width: 48em) {
- .sg-control > li {
- border-bottom: 0;
- border-left: 1px solid rgba(255, 255, 255, 0.05); } }
+ float: left;
+}
+@media all and (min-width: 48em) {
+ .sg-control > li {
+ border-bottom: 0;
+ border-left: 1px solid rgba(255, 255, 255, 0.05);
+ }
+}
.sg-control .sg-input {
padding: 0.1em;
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
- transition: all 0.2s ease-out; }
- .sg-control .sg-input:active, .sg-control .sg-input:focus {
- outline: 0;
- background: #999999;
- color: #000; }
+ transition: all 0.2s ease-out;
+}
+.sg-control .sg-input:active, .sg-control .sg-input:focus {
+ outline: 0;
+ background: #999;
+ color: #000;
+}
.sg-current-size {
font-size: 70%;
- color: gray;
- padding: 0.85em 0.7em; }
- .sg-current-size:hover .sg-input {
- background: #999999;
- color: #000; }
- @media all and (min-width: 72em) {
- .sg-current-size {
- float: left; } }
+ color: #808080;
+ padding: 0.85em 0.7em;
+}
+.sg-current-size:hover .sg-input {
+ background: #999;
+ color: #000;
+}
+@media all and (min-width: 72em) {
+ .sg-current-size {
+ float: left;
+ }
+}
.sg-size {
- width: 135px; }
- @media all and (min-width: 48em) {
- .sg-size {
- width: auto; } }
+ width: 135px;
+}
+@media all and (min-width: 48em) {
+ .sg-size {
+ width: auto;
+ }
+}
@media all and (min-width: 72em) {
.sg-size-options {
float: left;
position: static;
max-height: none;
- max-width: none; }
- .sg-size-options > li {
- float: left;
- border: 0;
- border-left: 1px solid rgba(255, 255, 255, 0.05); } }
+ max-width: none;
+ }
+ .sg-size-options > li {
+ float: left;
+ border: 0;
+ border-left: 1px solid rgba(255, 255, 255, 0.05);
+ }
+}
#sg-size-mq {
- display: none; }
- @media all and (min-width: 72em) {
- #sg-size-mq {
- display: block; } }
+ display: none;
+}
+@media all and (min-width: 72em) {
+ #sg-size-mq {
+ display: block;
+ }
+}
#sg-form {
margin: 0;
border: 0;
- padding: 0; }
+ padding: 0;
+}
.sg-input {
margin: -2px 0 0 0;
@@ -297,25 +360,32 @@
background-color: #222;
color: gray;
width: 25px;
- text-align: right; }
- @media all and (min-width: 48em) {
- .sg-input {
- width: 35px; } }
+ text-align: right;
+}
+@media all and (min-width: 48em) {
+ .sg-input {
+ width: 35px;
+ }
+}
.sg-input-active {
background-color: #fff;
- color: #000; }
+ color: #000;
+}
.sg-view {
- position: relative; }
- .sg-view > ul {
- position: absolute;
- top: 2em;
- left: 0; }
+ position: relative;
+}
+.sg-view > ul {
+ position: absolute;
+ top: 2em;
+ left: 0;
+}
.sg-checkbox:before {
display: inline-block;
- margin-right: 0.4em; }
+ margin-right: 0.4em;
+}
/* basic styling */
.sg-pattern-state:before {
@@ -324,7 +394,8 @@
display: inline-block;
margin-bottom: -4px;
font-size: 18px;
- vertical-align: bottom; }
+ vertical-align: bottom;
+}
/* nav styling */
.sg-nav .sg-pattern-state:before {
@@ -333,29 +404,36 @@
margin-left: -4px;
height: 20px;
display: block;
- float: left; }
+ float: left;
+}
.sg-sub-nav .sg-pattern-state:before {
margin-left: -11px;
- margin-right: 4px; }
+ margin-right: 4px;
+}
/* call out for pattern's pattern state */
span.sg-pattern-state {
- color: #999; }
+ color: #999;
+}
span.sg-pattern-state:before {
margin-bottom: -3px;
- margin-left: 4px; }
+ margin-left: 4px;
+}
/* pattern states */
.inprogress:before {
- color: #FF4136 !important; }
+ color: #FF4136 !important;
+}
.inreview:before {
- color: #FFCC00 !important; }
+ color: #FFCC00 !important;
+}
.complete:before {
- color: #2ECC40 !important; }
+ color: #2ECC40 !important;
+}
/*------------------------------------*\
$PATTERN LAB VIEWPORT
@@ -369,13 +447,15 @@ span.sg-pattern-state:before {
bottom: 0;
left: 0;
right: 0;
- z-index: 0; }
- #sg-vp-wrap.wrap-animate {
- -webkit-transition: left 0.3s ease-out;
- -moz-transition: left 0.3s ease-out;
- -ms-transition: left 0.3s ease-out;
- -o-transition: left 0.3s ease-out;
- transition: left 0.3s ease-out; }
+ z-index: 0;
+}
+#sg-vp-wrap.wrap-animate {
+ -webkit-transition: left 0.3s ease-out;
+ -moz-transition: left 0.3s ease-out;
+ -ms-transition: left 0.3s ease-out;
+ -o-transition: left 0.3s ease-out;
+ transition: left 0.3s ease-out;
+}
#sg-viewport {
position: absolute;
@@ -388,18 +468,22 @@ span.sg-pattern-state:before {
bottom: 0;
left: 0;
right: 0;
- background-color: white; }
- #sg-viewport.hay-mode {
- -webkit-transition: all 40s linear;
- -moz-transition: all 40s linear;
- -ms-transition: all 40s linear;
- -o-transition: all 40s linear;
- transition: all 40s linear; }
+ background-color: white;
+}
+#sg-viewport.hay-mode {
+ -webkit-transition: all 40s linear;
+ -moz-transition: all 40s linear;
+ -ms-transition: all 40s linear;
+ -o-transition: all 40s linear;
+ transition: all 40s linear;
+}
.no-resize #sg-cover, .no-resize #sg-rightpull-container {
- display: none; }
+ display: none;
+}
.no-resize #sg-viewport {
- overflow: hidden !important; }
+ overflow: hidden !important;
+}
#sg-cover {
width: 100%;
@@ -407,7 +491,8 @@ span.sg-pattern-state:before {
display: none;
position: absolute;
z-index: 20;
- cursor: col-resize; }
+ cursor: col-resize;
+}
#sg-gen-container {
height: 100%;
@@ -416,20 +501,23 @@ span.sg-pattern-state:before {
margin: 0 auto;
-webkit-overflow-scrolling: touch;
overflow-y: auto;
- overflow-x: hidden; }
- #sg-gen-container.hay-mode {
- -webkit-transition: all 40s linear;
- -moz-transition: all 40s linear;
- -ms-transition: all 40s linear;
- -o-transition: all 40s linear;
- transition: all 40s linear; }
+ overflow-x: hidden;
+}
+#sg-gen-container.hay-mode {
+ -webkit-transition: all 40s linear;
+ -moz-transition: all 40s linear;
+ -ms-transition: all 40s linear;
+ -o-transition: all 40s linear;
+ transition: all 40s linear;
+}
#sg-rightpull-container {
width: 14px;
float: right;
margin: 0;
height: 100%;
- cursor: col-resize; }
+ cursor: col-resize;
+}
#sg-rightpull {
margin: 0;
@@ -440,19 +528,23 @@ span.sg-pattern-state:before {
-moz-transition: background 0.2s ease-out;
-ms-transition: background 0.2s ease-out;
-o-transition: background 0.2s ease-out;
- transition: background 0.2s ease-out; }
- #sg-rightpull:hover {
- background: #666; }
- #sg-rightpull:active {
- cursor: col-resize;
- background: #444; }
+ transition: background 0.2s ease-out;
+}
+#sg-rightpull:hover {
+ background: #666;
+}
+#sg-rightpull:active {
+ cursor: col-resize;
+ background: #444;
+}
.vp-animate {
-webkit-transition: width 0.8s ease-out;
-moz-transition: width 0.8s ease-out;
-ms-transition: width 0.8s ease-out;
-o-transition: width 0.8s ease-out;
- transition: width 0.8s ease-out; }
+ transition: width 0.8s ease-out;
+}
/*------------------------------------*\
$PATTERN LAB CONTENT
@@ -460,7 +552,8 @@ span.sg-pattern-state:before {
/* Section Pattern */
.sg-pattern {
margin-bottom: 2em;
- position: relative; }
+ position: relative;
+}
/* Section Head */
.sg-pattern-head {
@@ -469,14 +562,17 @@ span.sg-pattern-state:before {
font-size: 70%;
font-weight: normal;
padding: 1em 0;
- border-bottom: 1px solid gray; }
- .sg-pattern-head a {
- display: block;
- color: gray;
- text-decoration: none;
- cursor: pointer; }
- .sg-pattern-head a:hover {
- color: #222222; }
+ border-bottom: 1px solid #808080;
+}
+.sg-pattern-head a {
+ display: block;
+ color: #808080;
+ text-decoration: none;
+ cursor: pointer;
+}
+.sg-pattern-head a:hover {
+ color: #222;
+}
.sg-view-container {
-moz-box-sizing: border-box;
@@ -485,8 +581,8 @@ span.sg-pattern-state:before {
font-family: "HelveticaNeue", "Helvetica", "Arial", sans-serif;
line-height: 1.4;
font-size: 90%;
- background: #222222;
- color: gray;
+ background: #222;
+ color: #808080;
position: fixed;
top: auto;
padding: 1em;
@@ -496,39 +592,49 @@ span.sg-pattern-state:before {
width: 100%;
height: 50%;
overflow-y: auto;
- overflow-x: hidden; }
- .sg-view-container a {
- color: #999999; }
- .sg-view-container pre {
- padding: 0 1em; }
- .sg-view-container.anim-ready {
- -webkit-transition: bottom 0.3s ease-out;
- -moz-transition: bottom 0.3s ease-out;
- -webkit-transition: bottom 0.3s ease-out;
- -ms-transition: bottom 0.3s ease-out;
- -o-transition: bottom 0.3s ease-out;
- transition: bottom 0.3s ease-out; }
+ overflow-x: hidden;
+}
+.sg-view-container a {
+ color: #999;
+}
+.sg-view-container pre {
+ padding: 0 1em;
+}
+.sg-view-container.anim-ready {
+ -webkit-transition: bottom 0.3s ease-out;
+ -moz-transition: bottom 0.3s ease-out;
+ -webkit-transition: bottom 0.3s ease-out;
+ -ms-transition: bottom 0.3s ease-out;
+ -o-transition: bottom 0.3s ease-out;
+ transition: bottom 0.3s ease-out;
+}
.sg-view-close {
width: 100%;
- margin-bottom: -10px; }
+ margin-bottom: -10px;
+}
.sg-view-close-btn {
color: #fff;
text-transform: uppercase;
text-decoration: none;
text-align: right;
- display: block; }
+ display: block;
+}
.has-annotation {
cursor: help !important;
- box-shadow: 0 0 10px gray; }
- .has-annotation a, .has-annotation input {
- cursor: help !important; }
- .has-annotation:hover {
- box-shadow: 0 0 10px #222222; }
- .has-annotation.active {
- box-shadow: inset 0 0 20px gray; }
+ box-shadow: 0 0 10px #808080;
+}
+.has-annotation a, .has-annotation input {
+ cursor: help !important;
+}
+.has-annotation:hover {
+ box-shadow: 0 0 10px #222;
+}
+.has-annotation.active {
+ box-shadow: inset 0 0 20px #808080;
+}
.annotation-tip {
display: block;
@@ -543,29 +649,36 @@ span.sg-pattern-state:before {
color: #fff !important;
font-weight: bold !important;
font-size: 16px !important;
- z-index: 100; }
+ z-index: 100;
+}
#sg-comments-container {
max-width: 60em;
- margin: 0 auto; }
+ margin: 0 auto;
+}
.sg-comment-container {
padding-bottom: 2em;
margin-bottom: 1em;
- border-bottom: 1px solid rgba(255, 255, 255, 0.25); }
- .sg-comment-container p:last-child {
- margin-bottom: 0; }
- .sg-comment-container h2 {
- margin-bottom: 0.25em; }
+ border-bottom: 1px solid rgba(255, 255, 255, 0.25);
+}
+.sg-comment-container p:last-child {
+ margin-bottom: 0;
+}
+.sg-comment-container h2 {
+ margin-bottom: 0.25em;
+}
.sg-code, .sg-annotations {
clear: both;
- background: #dddddd;
- color: #222222;
+ background: #ddd;
+ color: #222;
padding: 1em 0.5em;
- margin: 1em 0; }
- .sg-code a, .sg-annotations a {
- text-decoration: underline; }
+ margin: 1em 0;
+}
+.sg-code a, .sg-annotations a {
+ text-decoration: underline;
+}
.sg-code pre {
white-space: -moz-pre-line;
@@ -574,30 +687,36 @@ span.sg-pattern-state:before {
word-wrap: break-word;
white-space: pre-line;
border: 1px solid rgba(0, 0, 0, 0.1);
- padding: 0.5em; }
+ padding: 0.5em;
+}
.sg-code-contains {
margin-bottom: 1rem;
font-size: 85%;
- color: gray; }
- .sg-code-contains code {
- padding: 0.2em;
- background: rgba(0, 0, 0, 0.3);
- color: #999999;
- position: relative;
- top: -2px; }
+ color: #808080;
+}
+.sg-code-contains code {
+ padding: 0.2em;
+ background: rgba(0, 0, 0, 0.3);
+ color: #999;
+ position: relative;
+ top: -2px;
+}
.sg-code-head {
- color: gray;
- font-size: 1em; }
+ color: #808080;
+ font-size: 1em;
+}
#sg-code-markup {
- padding-top: 10px; }
+ padding-top: 10px;
+}
#sg-code-tabs {
list-style: none;
margin: 0;
- padding: 0; }
+ padding: 0;
+}
#sg-code-tabs li {
float: left;
@@ -607,17 +726,21 @@ span.sg-pattern-state:before {
padding: 5px 15px;
border-top: 2px solid #666;
margin-right: 2px;
- cursor: pointer; }
+ cursor: pointer;
+}
.sg-code-title-active {
color: #bbb;
- background-color: #272822 !important; }
+ background-color: #272822 !important;
+}
div.clear {
- clear: both; }
+ clear: both;
+}
.sg-code-patternname {
- color: #aaa; }
+ color: #aaa;
+}
#sg-code-loader {
display: none;
@@ -629,7 +752,8 @@ div.clear {
text-align: center;
border-radius: 10px;
background-color: #000;
- z-index: 100; }
+ z-index: 100;
+}
.spinner {
height: 30px;
@@ -640,16 +764,17 @@ div.clear {
background-repeat: no-repeat;
background: url("../images/spinner.gif");
border-radius: 50%;
- opacity: .7; }
+ opacity: .7;
+}
/* Pattern Lab icon fonts */
@font-face {
font-family: 'icomoon';
- src: url("../fonts/icomoon.eot");
- src: url("../fonts/icomoon.eot") format("embedded-opentype"), url("../fonts/icomoon.woff") format("woff"), url("../fonts/icomoon.ttf") format("truetype"), url("../fonts/icomoon.svg") format("svg");
+ src: url("../fonts/icomoon.eot?srsv7g");
+ src: url("../fonts/icomoon.eot?#iefixsrsv7g") format("embedded-opentype"), url("../fonts/icomoon.woff?srsv7g") format("woff"), url("../fonts/icomoon.ttf?srsv7g") format("truetype"), url("../fonts/icomoon.svg?srsv7g#icomoon") format("svg");
font-weight: normal;
- font-style: normal; }
-
+ font-style: normal;
+}
.sg-icon-search, .sg-icon-cog, .sg-icon-minus, .sg-icon-plus, .sg-icon-menu, .sg-icon-radio-checked, .sg-checkbox.active, .sg-icon-radio-unchecked, .sg-checkbox, .sg-icon-file, .sg-icon-link, .sg-icon-keyboard, .sg-icon-qrcode, .sg-icon-eye, .sg-checkbox {
font-family: 'icomoon';
speak: none;
@@ -660,44 +785,65 @@ div.clear {
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale; }
+ -moz-osx-font-smoothing: grayscale;
+}
.sg-icon-search:before {
content: "\e600";
- font-size: 85%; }
+ font-size: 85%;
+}
.sg-icon-cog:before {
- content: "\e601"; }
+ content: "\e601";
+}
.sg-icon-minus:before {
- content: "\e602"; }
+ content: "\e602";
+}
.sg-icon-plus:before {
- content: "\e603"; }
+ content: "\e603";
+}
.sg-icon-menu:before {
- content: "\e604"; }
+ content: "\e604";
+}
.sg-icon-radio-checked:before, .sg-checkbox.active:before, .sg-checkbox.active:before {
- content: "\e605"; }
+ content: "\e605";
+}
.sg-icon-radio-unchecked:before, .sg-checkbox:before, .sg-checkbox:before {
- content: "\e606"; }
+ content: "\e606";
+}
.sg-icon-file:before {
- content: "\e607"; }
+ content: "\e607";
+}
.sg-icon-link:before {
- content: "\e608"; }
+ content: "\e608";
+}
.sg-icon-keyboard:before {
- content: "\e609"; }
+ content: "\e609";
+}
.sg-icon-qrcode:before {
- content: "\e60a"; }
+ content: "\e60a";
+}
.sg-icon-eye:before {
- content: "\e60b"; }
+ content: "\e60b";
+}
+
+/* Readme docs */
+.sg-pattern-doc {
+ background: rgba(0, 0, 0, 0.05);
+ font-size: 70%;
+ margin: 1em;
+ padding: 10px;
+}
/******************************************************************/
-/* End Pattern Lab Interface code */
\ No newline at end of file
+/* End Pattern Lab Interface code */
diff --git a/public/styleguide/css/styleguide.css.map b/public/styleguide/css/styleguide.css.map
new file mode 100644
index 000000000..47bc625dd
--- /dev/null
+++ b/public/styleguide/css/styleguide.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "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",
+"sources": ["file:///Users/tor/projects/patternlab-node/public/styleguide/css/styleguide.scss"],
+"names": [],
+"file": "styleguide.css"
+}
diff --git a/public/styleguide/css/styleguide.scss b/public/styleguide/css/styleguide.scss
index b0b38c0f7..44daa03dc 100644
--- a/public/styleguide/css/styleguide.scss
+++ b/public/styleguide/css/styleguide.scss
@@ -57,6 +57,7 @@ $sg-tint : rgba(255,255,255,0.05);
$sg-tint-2 : rgba(255,255,255,0.25);
$sg-tone : rgba(0,0,0,0.1);
$sg-tone-2 : rgba(0,0,0,0.3);
+$sg-tone-3 : rgba(0,0,0,0.05);
/* Typography */
$sg-font-size-norm : 100%;
@@ -949,5 +950,14 @@ div.clear {
content: "\e60b";
}
+
+/* Readme docs */
+.sg-pattern-doc {
+ background: $sg-tone-3;
+ font-size: $sg-font-size-sm;
+ margin: $sg-space;
+ padding: 10px;
+}
+
/******************************************************************/
/* End Pattern Lab Interface code */
\ No newline at end of file
diff --git a/public/styleguide/js/.jshintrc b/public/styleguide/js/.jshintrc
new file mode 100644
index 000000000..f5d93d99c
--- /dev/null
+++ b/public/styleguide/js/.jshintrc
@@ -0,0 +1,3 @@
+{
+ "predef": ["module"]
+}
\ No newline at end of file
diff --git a/public/styleguide/js/code-viewer.js b/public/styleguide/js/code-viewer.js
index 05c4a6fcd..5fe86cc97 100644
--- a/public/styleguide/js/code-viewer.js
+++ b/public/styleguide/js/code-viewer.js
@@ -202,7 +202,7 @@ var codeViewer = {
* if the encoded tab is the current active tab it adds the content to the default code container
*/
saveEncoded: function() {
- codeViewer.encoded = this.responseText;
+ codeViewer.encoded = this.responseText.replace('<', '<').replace('>', '>');
if (codeViewer.tabActive == "e") {
codeViewer.activateDefaultTab("e",this.responseText);
}
@@ -318,7 +318,7 @@ var codeViewer = {
// request the encoded markup version of the pattern
var e = new XMLHttpRequest();
e.onload = this.saveEncoded;
- e.open("GET", fileName.replace(/\.html/,".escaped.html") + "?" + (new Date()).getTime(), true);
+ e.open("GET", fileName /*.replace(/\.escaped.html/,".html")*/ + "?" + (new Date()).getTime(), true);
e.send();
// request the mustache markup version of the pattern
diff --git a/public/styleguide/js/config.js b/public/styleguide/js/config.js
new file mode 100644
index 000000000..8a35b7540
--- /dev/null
+++ b/public/styleguide/js/config.js
@@ -0,0 +1,8 @@
+module.exports = {
+ minViewportWidth : 240, //Minimum Size for Viewport
+ maxViewportWidth : 2600, //Maxiumum Size for Viewport
+ viewportResizeHandleWidth : 14, //Width of the viewport drag-to-resize handle
+ bodySize : parseInt(window.getComputedStyle(document.body).getPropertyValue('font-size')),
+ sw : document.body.clientWidth, //Viewport Width
+ sh : document.body.clientHeight //Viewport Height
+}
\ No newline at end of file
diff --git a/public/styleguide/js/cookie.js b/public/styleguide/js/cookie.js
new file mode 100644
index 000000000..d3ea753c4
--- /dev/null
+++ b/public/styleguide/js/cookie.js
@@ -0,0 +1,83 @@
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+
+var pluses = /\+/g;
+
+function raw(s) {
+ return s;
+}
+
+function decoded(s) {
+ return decodeURIComponent(s.replace(pluses, ' '));
+}
+
+function Cookie(options) {
+ this.options = options || {};
+}
+
+Cookie.prototype.write = function (key, value, options) {
+ var c;
+ options = options || {};
+
+ Object.keys(this.options).every(function (key) {
+ if (!options.hasOwnProperty(key)) {
+ options[key] = this.options[key];
+ }
+ return true;
+ });
+
+ if (value === null) {
+ options.expires = -1;
+ }
+
+ if (typeof options.expires === 'number') {
+ var days = options.expires,
+ t;
+
+ t = options.expires = new Date();
+ t.setDate(t.getDate() + days);
+ }
+
+ value = options.json ? JSON.stringify(value) : String(value);
+
+ c = [
+ encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+ options.path ? '; path=' + options.path : '',
+ options.domain ? '; domain=' + options.domain : '',
+ options.secure ? '; secure' : ''
+ ].join('');
+ document.cookie = c;
+ return c;
+};
+
+Cookie.prototype.read = function (key) {
+ // read
+ var decode = this.options.raw ? raw : decoded,
+ cookies = document.cookie.split('; '),
+ i,
+ l,
+ parts,
+ cookie;
+
+ for (i = 0, l = cookies.length; i < l; i++) {
+ parts = cookies[i].split('=');
+ if (decode(parts.shift()) === key) {
+ cookie = decode(parts.join('='));
+ return this.options.json ? JSON.parse(cookie) : cookie;
+ }
+ }
+
+ return null;
+};
+
+Cookie.prototype.remove = function (key, options) {
+ if (this.read(key) !== null) {
+ this.write(key, null, options);
+ return true;
+ }
+ return false;
+};
+
+module.exports = Cookie;
\ No newline at end of file
diff --git a/public/styleguide/js/data-saver.js b/public/styleguide/js/data-saver.js
index e354e1e79..e347a3c10 100644
--- a/public/styleguide/js/data-saver.js
+++ b/public/styleguide/js/data-saver.js
@@ -1,75 +1,8 @@
-/*!
- * jQuery Cookie Plugin v1.3
- * https://github.com/carhartl/jquery-cookie
- *
- * Copyright 2011, Klaus Hartl
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.opensource.org/licenses/GPL-2.0
- */
-(function ($, document, undefined) {
-
- var pluses = /\+/g;
-
- function raw(s) {
- return s;
- }
-
- function decoded(s) {
- return decodeURIComponent(s.replace(pluses, ' '));
- }
-
- var config = $.cookie = function (key, value, options) {
-
- // write
- if (value !== undefined) {
- options = $.extend({}, config.defaults, options);
-
- if (value === null) {
- options.expires = -1;
- }
-
- if (typeof options.expires === 'number') {
- var days = options.expires, t = options.expires = new Date();
- t.setDate(t.getDate() + days);
- }
-
- value = config.json ? JSON.stringify(value) : String(value);
-
- return (document.cookie = [
- encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
- options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
- options.path ? '; path=' + options.path : '',
- options.domain ? '; domain=' + options.domain : '',
- options.secure ? '; secure' : ''
- ].join(''));
- }
-
- // read
- var decode = config.raw ? raw : decoded;
- var cookies = document.cookie.split('; ');
- for (var i = 0, l = cookies.length; i < l; i++) {
- var parts = cookies[i].split('=');
- if (decode(parts.shift()) === key) {
- var cookie = decode(parts.join('='));
- return config.json ? JSON.parse(cookie) : cookie;
- }
- }
-
- return null;
- };
-
- config.defaults = {};
-
- $.removeCookie = function (key, options) {
- if ($.cookie(key) !== null) {
- $.cookie(key, null, options);
- return true;
- }
- return false;
- };
-
-})(jQuery, document);
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+var Cookie = require('./cookie'),
+ cookie = new Cookie();
/*!
* Data Saver - v0.1
@@ -79,91 +12,100 @@
*/
var DataSaver = {
-
- // the name of the cookie to store the data in
- cookieName: "patternlab",
-
- /**
- * Add a given value to the cookie
- * @param {String} the name of the key
- * @param {String} the value
- */
- addValue: function (name,val) {
- var cookieVal = $.cookie(this.cookieName);
- if ((cookieVal == null) || (cookieVal == "")) {
- cookieVal = name+"~"+val;
- } else {
- cookieVal = cookieVal+"|"+name+"~"+val;
- }
- $.cookie(this.cookieName,cookieVal);
- },
-
- /**
- * Update a value found in the cookie. If the key doesn't exist add the value
- * @param {String} the name of the key
- * @param {String} the value
- */
- updateValue: function (name,val) {
- if (this.findValue(name)) {
- var updateCookieVals = "";
- var cookieVals = $.cookie(this.cookieName).split("|");
- for (var i = 0; i < cookieVals.length; i++) {
- var fieldVals = cookieVals[i].split("~");
- if (fieldVals[0] == name) {
- fieldVals[1] = val;
- }
- if (i > 0) {
- updateCookieVals += "|"+fieldVals[0]+"~"+fieldVals[1];
- } else {
- updateCookieVals += fieldVals[0]+"~"+fieldVals[1];
- }
- }
- $.cookie(this.cookieName,updateCookieVals);
- } else {
- this.addValue(name,val);
- }
- },
-
- /**
- * Remove the given key
- * @param {String} the name of the key
- */
- removeValue: function (name) {
- var updateCookieVals = "";
- var cookieVals = $.cookie(this.cookieName).split("|");
- var k = 0;
- for (var i = 0; i < cookieVals.length; i++) {
- var fieldVals = cookieVals[i].split("~");
- if (fieldVals[0] != name) {
- if (k == 0) {
- updateCookieVals += fieldVals[0]+"~"+fieldVals[1];
- } else {
- updateCookieVals += "|"+fieldVals[0]+"~"+fieldVals[1];
- }
- k++;
- }
- }
- $.cookie(this.cookieName,updateCookieVals);
- },
-
- /**
- * Find the value using the given key
- * @param {String} the name of the key
- *
- * @return {String} the value of the key or false if the value isn't found
- */
- findValue: function (name) {
- if ($.cookie(this.cookieName)) {
- var cookieVals = $.cookie(this.cookieName).split("|");
- var k = 0;
- for (var i = 0; i < cookieVals.length; i++) {
- var fieldVals = cookieVals[i].split("~");
- if (fieldVals[0] == name) {
- return fieldVals[1];
- }
- }
- }
- return false;
- }
-
+
+ // the name of the cookie to store the data in
+ cookieName: "patternlab",
+
+ /**
+ * Add a given value to the cookie
+ * @param {String} the name of the key
+ * @param {String} the value
+ */
+ addValue: function (name, val) {
+ var cookieVal = cookie.read(this.cookieName);
+ if ((cookieVal === null) || (cookieVal === "")) {
+ cookieVal = name + "~" + val;
+ } else {
+ cookieVal = cookieVal + "|" + name + "~" + val;
+ }
+ cookie.write(this.cookieName, cookieVal);
+ },
+
+ /**
+ * Update a value found in the cookie. If the key doesn't exist add the value
+ * @param {String} the name of the key
+ * @param {String} the value
+ */
+ updateValue: function (name, val) {
+ if (this.findValue(name)) {
+ var updateCookieVals = "",
+ cookieVals = cookie.read(this.cookieName).split("|"),
+ i,
+ l,
+ fieldVals;
+ for (i = 0, l = cookieVals.length; i < l; i++) {
+ fieldVals = cookieVals[i].split("~");
+ if (fieldVals[0] === name) {
+ fieldVals[1] = val;
+ }
+ if (i > 0) {
+ updateCookieVals += "|" + fieldVals[0] + "~" + fieldVals[1];
+ } else {
+ updateCookieVals += fieldVals[0] + "~" + fieldVals[1];
+ }
+ }
+ cookie.write(this.cookieName, updateCookieVals);
+ } else {
+ this.addValue(name, val);
+ }
+ },
+
+ /**
+ * Remove the given key
+ * @param {String} the name of the key
+ */
+ removeValue: function (name) {
+ var updateCookieVals = "",
+ cookieVals = cookie.read(this.cookieName).split("|"),
+ k = 0,
+ i,
+ l,
+ fieldVals;
+ for (i = 0, l = cookieVals.length; i < l; i++) {
+ fieldVals = cookieVals[i].split("~");
+ if (fieldVals[0] !== name) {
+ if (k === 0) {
+ updateCookieVals += fieldVals[0] + "~" + fieldVals[1];
+ } else {
+ updateCookieVals += "|" + fieldVals[0] + "~" + fieldVals[1];
+ }
+ k++;
+ }
+ }
+ cookie.write(this.cookieName, updateCookieVals);
+ },
+
+ /**
+ * Find the value using the given key
+ * @param {String} the name of the key
+ *
+ * @return {String} the value of the key or false if the value isn't found
+ */
+ findValue: function (name) {
+ if (cookie.read(this.cookieName)) {
+ var cookieVals = cookie.read(this.cookieName).split("|"),
+ i,
+ l,
+ fieldVals;
+ for (i = 0, l = cookieVals.length; i < l; i++) {
+ fieldVals = cookieVals[i].split("~");
+ if (fieldVals[0] === name) {
+ return fieldVals[1];
+ }
+ }
+ }
+ return false;
+ }
};
+
+module.exports = DataSaver;
\ No newline at end of file
diff --git a/public/styleguide/js/eventDelegator/eventDelegator.js b/public/styleguide/js/eventDelegator/eventDelegator.js
new file mode 100644
index 000000000..4ff04b58f
--- /dev/null
+++ b/public/styleguide/js/eventDelegator/eventDelegator.js
@@ -0,0 +1,108 @@
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+var WM = require('./weakMapSet').WeakMap,
+ delegators = new WM();
+
+require('./matches.js');
+
+function EventDelegator(element) {
+ var delegator = delegators.get(element);
+
+ if (delegator) {
+ return delegator;
+ }
+
+ this.events = {};
+ this.element = element;
+ this.handlers = {};
+ delegators.set(element, this);
+}
+
+EventDelegator.prototype._match = function (selectors, e) {
+ var target = e.target,
+ selector;
+
+ function _runCallback(selector) {
+ var i,
+ l;
+ for (i = 0, l = selectors[selector].length; i < l; i++) {
+ selectors[selector][i](e);
+ }
+ }
+ while (target !== this.element) {
+ for (selector in selectors) {
+ if (selectors.hasOwnProperty(selector) && target.matches(selector)) {
+ _runCallback(selector);
+ }
+ }
+ if (!target.parentNode) {
+ return;
+ }
+ target = target.parentNode;
+ }
+};
+
+EventDelegator.prototype.on = function (type, selector, cb) {
+ //todo support elements as selector
+
+ var _this = this;
+
+ function handler(e) {
+ _this._match(_this.events[type], e);
+ }
+
+ if (!this.events[type]) {
+ this.events[type] = {};
+
+ this.handlers[type] = handler;
+ this.element.addEventListener(type, handler, false);
+ }
+
+ this.events[type][selector] = this.events[type][selector] || [];
+
+ if (this.events[type][selector].indexOf(cb) === -1) {
+ this.events[type][selector].push(cb);
+ }
+ return this;
+};
+
+EventDelegator.prototype.off = function (type, selector, cb) {
+ if (type === undefined) {
+ Object.keys(this.events).every(function (evtType) {
+ this.element.removeEventListener(evtType, this.handlers[evtType]);
+ return true;
+ });
+ this.events = {};
+ } else if (selector === undefined) {
+ //remove all of one type
+ if (this.events[type]) {
+ this.element.removeEventListener(type, this.handlers[type]);
+ delete this.events[type];
+ delete this.handlers[type];
+ }
+ } else if (cb === undefined) {
+ // remove all handlers
+ if (this.events[type] && this.events[type][selector]) {
+ delete this.events[type][selector];
+ // Remove eventlistener if no selectors are present
+ if (Object.keys(this.events[type]).length === 0) {
+ this.off(type);
+ }
+ }
+ } else {
+ // remove specific handler
+ var i = this.events[type][selector].indexOf(cb);
+
+ if (i !== -1) {
+ this.events[type][selector].splice(i, 1);
+ }
+ }
+ return this;
+};
+
+EventDelegator.prototype.toString = function () {
+ return 'EventDelegator';
+};
+
+module.exports = EventDelegator;
\ No newline at end of file
diff --git a/public/styleguide/js/eventDelegator/matches.js b/public/styleguide/js/eventDelegator/matches.js
new file mode 100644
index 000000000..69fe093a6
--- /dev/null
+++ b/public/styleguide/js/eventDelegator/matches.js
@@ -0,0 +1,35 @@
+/*jslint indent: 4*/
+/*global window*/
+/**
+ * Polyfill for Element.matches
+ **/
+function addPolyfill(ElementPrototype) {
+ 'use strict';
+
+ if (ElementPrototype.matches !== undefined) {
+ return;
+ }
+
+ ElementPrototype.matches = ElementPrototype.matchesSelector ||
+ ElementPrototype.mozMatchesSelector ||
+ ElementPrototype.msMatchesSelector ||
+ ElementPrototype.oMatchesSelector ||
+ ElementPrototype.webkitMatchesSelector ||
+ function (selector) {
+ var node = this,
+ nodes = (node.parentNode || node.document).querySelectorAll(selector),
+ i = -1;
+
+ while (nodes[i] && nodes[i] !== node) {
+ ++i;
+ }
+
+ return !!nodes[i];
+ };
+}
+
+if (module && module.exports) {
+ module.exports = addPolyfill;
+} else {
+ addPolyfill(window.Element.prototype);
+}
\ No newline at end of file
diff --git a/public/styleguide/js/eventDelegator/package.json b/public/styleguide/js/eventDelegator/package.json
new file mode 100644
index 000000000..ffb4b8bee
--- /dev/null
+++ b/public/styleguide/js/eventDelegator/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "eventDelegator",
+ "version": "0.0.1",
+ "description": "Event delegation module",
+ "main": "eventDelegator.js",
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "test": "./node_modules/.bin/mocha --reporter spec --ui bdd",
+ "build": "browserify eventDelegator.js -o eventDelegator.min.js",
+ "watch": "watchify eventDelegator.js -o eventDelegator.min.js --debug --verbose"
+ },
+ "keywords": [
+ "events",
+ "delegation",
+ "dom"
+ ],
+ "author": "Tor Brekke Skjøtskift",
+ "license": "ISC",
+ "devDependencies": {
+ "expect.js": "^0.3.1",
+ "jsdom": "^1.0.0-pre.6",
+ "mocha": "^1.21.4"
+ }
+}
diff --git a/public/styleguide/js/eventDelegator/test/index.js b/public/styleguide/js/eventDelegator/test/index.js
new file mode 100644
index 000000000..4bd676d15
--- /dev/null
+++ b/public/styleguide/js/eventDelegator/test/index.js
@@ -0,0 +1,93 @@
+var expect = require('expect.js'),
+ jsdom = require('jsdom').jsdom,
+ EventDelegator = require('../eventDelegator'),
+ matches = require('../matches');
+
+function captureStream(stream){
+ var oldWrite = stream.write;
+ var buf = '';
+ stream.write = function(chunk, encoding, callback){
+ buf += chunk.toString(); // chunk is a String or Buffer
+ oldWrite.apply(stream, arguments);
+ }
+
+ return {
+ unhook: function unhook(){
+ stream.write = oldWrite;
+ },
+ captured: function(){
+ return buf;
+ }
+ };
+}
+
+describe('eventDelegator', function () {
+ var document = jsdom('
'),
+ window = document.parentWindow,
+ el = document.getElementById('test');
+
+ // Add polyfill
+ matches(window.HTMLElement.prototype);
+
+ var hook;
+
+ beforeEach(function(){
+ hook = captureStream(process.stdout);
+ });
+ afterEach(function(){
+ hook.unhook();
+ });
+
+ it('should create a eventDelegator object', function () {
+ var delegator = new EventDelegator(el);
+ expect(delegator.toString()).to.equal('EventDelegator');
+ });
+
+ it('should return the first object if two eventDelegators are created on the same element', function() {
+ var delegator = new EventDelegator(el),
+ delegator2 = new EventDelegator(el);
+
+ expect(delegator).to.equal(delegator2);
+ });
+
+ it('should capture a click', function (done) {
+ var delegator = new EventDelegator(el);
+ delegator.on('click', '#handler', function (e) {
+ expect(e.target.id).to.equal('handler');
+ done();
+ });
+
+ var e = window.document.createEvent('MouseEvent');
+ e.initEvent('click', true, true);
+ document.getElementById('handler').dispatchEvent(e);
+ //console.log(hook.captured());
+ });
+
+ it('should remove all events', function () {
+ var delegator = new EventDelegator(el);
+
+ delegator.off('click');
+
+ expect(typeof delegator.events.click).to.equal('undefined');
+ })
+
+ it('should remove an event', function (done) {
+ var delegator = new EventDelegator(el),
+ clicked = false;
+
+ /*delegator.on('click', function (e) {
+ clicked = true;
+ });*/
+
+ delegator.off('click');
+
+ var e = window.document.createEvent('MouseEvent');
+ e.initEvent('click', true, true);
+ //document.getElementById('handler').dispatchEvent(e);
+
+ setTimeout(function() {
+ expect(clicked).to.equal(false);
+ done();
+ },300);
+ })
+});
\ No newline at end of file
diff --git a/public/styleguide/js/eventDelegator/weakMapSet.js b/public/styleguide/js/eventDelegator/weakMapSet.js
new file mode 100644
index 000000000..ebd74e53e
--- /dev/null
+++ b/public/styleguide/js/eventDelegator/weakMapSet.js
@@ -0,0 +1,271 @@
+"WeakMap" in this || (function (module) {"use strict";
+
+ //!(C) WebReflection - Mit Style License
+ // size and performances oriented polyfill for ES6
+ // WeakMap, Map, and Set
+ // compatible with node.js, Rhino, any browser
+ // does not implement default vaule during wm.get()
+ // since ES.next won't probably do that
+ // use wm.has(o) ? wm.get(o) : d3fault; instead
+
+ // WeakMap(void):WeakMap
+ function WeakMap() {
+
+ // private references holders
+ var
+ keys = [],
+ values = []
+ ;
+
+ // returns freshly new created
+ // instanceof WeakMap in any case
+ return create(WeakMapPrototype, {
+ // WeakMap#delete(key:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, TRUE, keys, values)},
+ //:was WeakMap#get(key:void*[, d3fault:void*]):void*
+ // WeakMap#get(key:void*):void*
+ get: {value: bind.call(sharedGet, NULL, TRUE, keys, values)},
+ // WeakMap#has(key:void*):boolean
+ has: {value: bind.call(sharedHas, NULL, TRUE, keys, values)},
+ // WeakMap#set(key:void*, value:void*):void
+ set: {value: bind.call(sharedSet, NULL, TRUE, keys, values)}
+ });
+
+ }
+
+ // Map(void):Map
+ function Map() {
+
+ // private references holders
+ var
+ keys = [],
+ values = []
+ ;
+
+ // returns freshly new created
+ // instanceof WeakMap in any case
+ return create(MapPrototype, {
+ // Map#delete(key:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, FALSE, keys, values)},
+ //:was Map#get(key:void*[, d3fault:void*]):void*
+ // Map#get(key:void*):void*
+ get: {value: bind.call(sharedGet, NULL, FALSE, keys, values)},
+ // Map#has(key:void*):boolean
+ has: {value: bind.call(sharedHas, NULL, FALSE, keys, values)},
+ // Map#set(key:void*, value:void*):void
+ set: {value: bind.call(sharedSet, NULL, FALSE, keys, values)}
+ /*,
+ // Map#size(void):number === Mozilla only so far
+ size: {value: bind.call(sharedSize, NULL, keys)},
+ // Map#keys(void):Array === not in specs
+ keys: {value: boundSlice(keys)},
+ // Map#values(void):Array === not in specs
+ values: {value: boundSlice(values)},
+ // Map#iterate(callback:Function, context:void*):void ==> callback.call(context, key, value, index) === not in specs
+ iterate: {value: bind.call(sharedIterate, NULL, FALSE, keys, values)}
+ //*/
+ });
+
+ }
+
+ // Set(void):Set
+ /**
+ * to be really honest, I would rather pollute Array.prototype
+ * in order to have Set like behavior
+ * Object.defineProperties(Array.prototype, {
+ * add: {value: function add(value) {
+ * return -1 < this.indexOf(value) && !!this.push(value);
+ * }}
+ * has: {value: function has(value) {
+ * return -1 < this.indexOf(value);
+ * }}
+ * delete: {value: function delete(value) {
+ * var i = this.indexOf(value);
+ * return -1 < i && !!this.splice(i, 1);
+ * }}
+ * });
+ * ... anyway ...
+ */
+ function Set() {
+ var
+ keys = [], // placeholder used simply to recycle functions
+ values = [],// real storage
+ has = bind.call(sharedHas, NULL, FALSE, values, keys)
+ ;
+ return create(SetPrototype, {
+ // Set#delete(value:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, FALSE, values, keys)},
+ // Set#has(value:void*):boolean
+ has: {value: has},
+ // Set#add(value:void*):boolean
+ add: {value: bind.call(Set_add, NULL, FALSE, has, values)}
+ /*,
+ // Map#size(void):number === Mozilla only
+ size: {value: bind.call(sharedSize, NULL, values)},
+ // Set#values(void):Array === not in specs
+ values: {value: boundSlice(values)},
+ // Set#iterate(callback:Function, context:void*):void ==> callback.call(context, value, index) === not in specs
+ iterate: {value: bind.call(Set_iterate, NULL, FALSE, NULL, values)}
+ //*/
+ });
+ }
+
+ // common shared method recycled for all shims through bind
+ function sharedDel(objectOnly, keys, values, key) {
+ if (sharedHas(objectOnly, keys, values, key)) {
+ keys.splice(i, 1);
+ values.splice(i, 1);
+ }
+ // Aurora here does it while Canary doesn't
+ return -1 < i;
+ }
+
+ function sharedGet(objectOnly, keys, values, key/*, d3fault*/) {
+ return sharedHas(objectOnly, keys, values, key) ? values[i] : undefined; //d3fault;
+ }
+
+ function sharedHas(objectOnly, keys, values, key) {
+ if (objectOnly && key !== Object(key)) {
+ console.log(key);
+ throw new TypeError("not a non-null object");
+ }
+ i = betterIndexOf.call(keys, key);
+ return -1 < i;
+ }
+
+ function sharedSet(objectOnly, keys, values, key, value) {
+ /* return */sharedHas(objectOnly, keys, values, key) ?
+ values[i] = value
+ :
+ values[keys.push(key) - 1] = value
+ ;
+ }
+
+ /* keys, values, and iterate related methods
+ function boundSlice(values) {
+ return function () {
+ return slice.call(values);
+ };
+ }
+
+ function sharedSize(keys) {
+ return keys.length;
+ }
+
+ function sharedIterate(objectOnly, keys, values, callback, context) {
+ for (var
+ k = slice.call(keys), v = slice.call(values),
+ i = 0, length = k.length;
+ i < length; callback.call(context, k[i], v[i], i++)
+ );
+ }
+
+ function Set_iterate(objectOnly, keys, values, callback, context) {
+ for (var
+ v = slice.call(values),
+ i = 0, length = v.length;
+ i < length; callback.call(context, v[i], i++)
+ );
+ }
+ //*/
+
+ // Set#add recycled through bind per each instanceof Set
+ function Set_add(objectOnly, has, values, value) {
+ /*return */(!has(value) && !!values.push(value));
+ }
+
+ // a more reliable indexOf
+ function betterIndexOf(value) {
+ if (value != value || value === 0) {
+ for (i = this.length; i-- && !is(this[i], value););
+ } else {
+ i = indexOf.call(this, value);
+ }
+ return i;
+ }
+
+ // need for an empty constructor ...
+ function Constructor(){} // GC'ed if !!Object.create
+ // ... so that new WeakMapInstance and new WeakMap
+ // produces both an instanceof WeakMap
+
+ var
+ // shortcuts and ...
+ NULL = null, TRUE = true, FALSE = false,
+ notInNode = module == "undefined",
+ window = notInNode ? this : global,
+ module = notInNode ? {} : exports,
+ Object = window.Object,
+ WeakMapPrototype = WeakMap.prototype,
+ MapPrototype = Map.prototype,
+ SetPrototype = Set.prototype,
+ defineProperty = Object.defineProperty,
+ slice = [].slice,
+
+ // Object.is(a, b) shim
+ is = Object.is || function (a, b) {
+ return a === b ?
+ a !== 0 || 1 / a == 1 / b :
+ a != a && b != b
+ ;
+ },
+
+ // partial polyfill for this aim only
+ bind = WeakMap.bind || function bind(context, objectOnly, keys, values) {
+ // partial fast ad-hoc Function#bind polyfill if not available
+ var callback = this;
+ return function bound(key, value) {
+ if (!!key === false) {
+ console.log(arguments.caller.callee);
+ };
+ return callback.call(context, objectOnly, keys, values, key, value);
+ };
+ },
+
+ create = Object.create || function create(proto, descriptor) {
+ // partial ad-hoc Object.create shim if not available
+ Constructor.prototype = proto;
+ var object = new Constructor(), key;
+ for (key in descriptor) {
+ object[key] = descriptor[key].value;
+ }
+ return object;
+ },
+
+ indexOf = [].indexOf || function indexOf(value) {
+ // partial fast Array#indexOf polyfill if not available
+ for (i = this.length; i-- && this[i] !== value;);
+ return i;
+ },
+
+ undefined,
+ i // recycle ALL the variables !
+ ;
+
+ // ~indexOf.call([NaN], NaN) as future possible feature detection
+
+ // used to follow FF behavior where WeakMap.prototype is a WeakMap itself
+ WeakMap.prototype = WeakMapPrototype = WeakMap();
+ Map.prototype = MapPrototype = Map();
+ Set.prototype = SetPrototype = Set();
+
+ // assign it to the global context
+ // if already there, e.g. in node, export native
+ window.WeakMap = module.WeakMap = window.WeakMap || WeakMap;
+ window.Map = module.Map = window.Map || Map;
+ window.Set = module.Set = window.Set || Set;
+
+ /* probably not needed, add a slash to ensure non configurable and non writable
+ if (defineProperty) {
+ defineProperty(window, "WeakMap", {value: WeakMap});
+ defineProperty(window, "Map", {value: Map});
+ defineProperty(window, "Set", {value: Set});
+ }
+ //*/
+
+ // that's pretty much it
+
+}.call(
+ this,
+ typeof exports
+));
\ No newline at end of file
diff --git a/public/styleguide/js/gui.js b/public/styleguide/js/gui.js
new file mode 100644
index 000000000..09d724c35
--- /dev/null
+++ b/public/styleguide/js/gui.js
@@ -0,0 +1,219 @@
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+var config = require('./config'),
+ dataSaver = require('./data-saver'),
+ urlHandler = require('./url-handler'),
+ elGenContainer = document.getElementById('sg-gen-container'),
+ elViewport = document.getElementById('sg-viewport'),
+ elSizePx = document.querySelector('.sg-size-px'), //Px size input element in toolbar
+ elSizeEms = document.querySelector('.sg-size-em'), //Em size input element in toolbar;
+ discoID = false,
+ discoMode = false,
+ hayMode = false;
+
+//Update Pixel and Em inputs
+//'size' is the input number
+//'unit' is the type of unit: either px or em. Default is px. Accepted values are 'px' and 'em'
+//'target' is what inputs to update. Defaults to both
+function updateSizeReading(size, unit, target) {
+ var emSize = (unit === 'em' ? Math.floor(size * config.bodySize) : size),
+ pxSize = (unit === 'em' ? size / config.bodySize : size);
+
+ if (target === 'updatePxInput') {
+ elSizePx.value = pxSize;
+ } else if (target === 'updateEmInput') {
+ elSizeEms.value = emSize;
+ } else {
+ elSizeEms.value = emSize;
+ elSizePx.value = pxSize;
+ }
+}
+
+function saveSize(size) {
+ if (!dataSaver.findValue('vpWidth')) {
+ dataSaver.addValue('vpWidth', size);
+ } else {
+ dataSaver.updateValue('vpWidth', size);
+ }
+}
+
+/* Returns a random number between min and max */
+function getRandom(min, max) {
+ return Math.random() * (max - min) + min;
+}
+
+//Resize the viewport
+//'size' is the target size of the viewport
+//'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
+function sizeiframe(size, animate) {
+ var theSize;
+
+ if (size > config.maxViewportWidth) { //If the entered size is larger than the max allowed viewport size, cap value at max vp size
+ theSize = config.maxViewportWidth;
+ } else if (size < config.minViewportWidth) { //If the entered size is less than the minimum allowed viewport size, cap value at min vp size
+ theSize = config.minViewportWidth;
+ } else {
+ theSize = size;
+ }
+
+ //Conditionally remove CSS animation class from viewport
+ elGenContainer.classList.remove('vp-animate', animate);
+ elViewport.classList.remove('vp-animate', animate);
+
+ elGenContainer.style.width = (theSize + config.viewportResizeHandleWidth) + 'px'; //Resize viewport wrapper to desired size + size of drag resize handler
+ elViewport.style.width = theSize + 'px'; //Resize viewport to desired size
+
+ updateSizeReading(theSize); //Update values in toolbar
+ saveSize(theSize); //Save current viewport to cookie
+}
+
+function updateViewportWidth(size) {
+ size = parseInt(size, 10);
+ elViewport.style.width = parseInt(size, 10) + 'px';
+ elGenContainer.style.width = (size + 14) + 'px';
+
+ updateSizeReading(size);
+}
+
+/* Disco Mode */
+function disco() {
+ sizeiframe(getRandom(config.minViewportWidth, config.sw));
+}
+
+function killDisco() {
+ discoMode = false;
+ clearInterval(discoID);
+ discoID = false;
+}
+
+function startDisco() {
+ discoMode = true;
+ discoID = setInterval(disco, 800);
+}
+
+function toggleDisco() {
+ if (!discoMode) {
+ startDisco();
+ } else {
+ killDisco();
+ }
+}
+
+//Stop Hay! Mode
+function killHay() {
+ var currentWidth = elViewport.offsetWidth;
+ hayMode = false;
+ elViewport.classList.remove('hay-mode');
+ elGenContainer.classList.remove('hay-mode');
+ sizeiframe(Math.floor(currentWidth));
+}
+
+// start Hay! mode
+function startHay() {
+ hayMode = true;
+ elGenContainer.classList.remove('vp-animate');
+ elGenContainer.style.width = (config.minViewportWidth + config.viewportResizeHandleWidth) + 'px';
+ elViewport.classList.remove('vp-animate');
+ elViewport.style.width = config.minViewportWidth + 'px';
+
+ window.setTimeout(function () {
+ elGenContainer.classList.add('hay-mode');
+ elGenContainer.style.width = (config.maxViewportWidth + config.viewportResizeHandleWidth) + 'px';
+ elViewport.classList.add('hay-mode');
+ elViewport.style.width = config.maxViewportWidth + 'px';
+
+ //todo this is not removed
+ setInterval(function () {
+ var vpSize = elViewport.offsetWidth;
+ updateSizeReading(vpSize);
+ }, 100);
+ }, 200);
+}
+
+function toggleHay() {
+ if (!hayMode) {
+ startHay();
+ } else {
+ killHay();
+ }
+}
+
+// handle when someone clicks on the grey area of the viewport so it auto-closes the nav
+function closePanels() {
+ // close up the menu
+ var panels = document.querySelectorAll('.sg-acc-panel'),
+ handles = document.querySelectorAll('.sg-acc-handle');
+
+ [].forEach.call(panels, function (panel) {
+ panel.classList.remove('active');
+ });
+
+
+ [].forEach.call(handles, function (handle) {
+ handle.classList.remove('active');
+ });
+}
+
+function init() {
+ var origViewportWidth = elViewport.offsetWidth,
+ oGetVars = urlHandler.getRequestVars(), // get the request vars
+ vpWidth = 0,
+ trackViewportWidth = true, // can toggle this feature on & off
+ patternName = 'all',
+ patternPath = '',
+ iFramePath = window.location.protocol + '//' + window.location.host + window.location.pathname.replace('index.html', '') + 'styleguide/html/styleguide.html';
+
+ // capture the viewport width that was loaded and modify it so it fits with the pull bar
+ elGenContainer.style.width = origViewportWidth + 'px';
+ elViewport.style.width = (origViewportWidth - 14) + 'px';
+ updateSizeReading(origViewportWidth - 14);
+
+ // pre-load the viewport width
+ if (oGetVars.h || oGetVars.hay) {
+ startHay();
+ } else if (oGetVars.d || oGetVars.disco) {
+ startDisco();
+ } else if (oGetVars.w || oGetVars.width) {
+ vpWidth = oGetVars.w || oGetVars.width;
+ vpWidth = vpWidth.indexOf('em') !== -1 ? Math.floor(Math.floor(vpWidth.replace('em', '')) * config.bodySize) : Math.floor(vpWidth.replace('px', ''));
+
+ dataSaver.updateValue('vpWidth', vpWidth);
+ updateViewportWidth(vpWidth);
+ } else if (trackViewportWidth && dataSaver.findValue('vpWidth')) {
+ updateViewportWidth(dataSaver.findValue('vpWidth'));
+ }
+
+ // load the iframe source
+ if (oGetVars.p || oGetVars.pattern) {
+ patternName = oGetVars.p || oGetVars.pattern;
+ patternPath = urlHandler.getFileName(patternName);
+ iFramePath = (patternPath !== '') ? window.location.protocol + '//' + window.location.host + window.location.pathname.replace('index.html', '') + patternPath : iFramePath;
+ }
+
+ if (patternName !== 'all') {
+ document.getElementById('title').innerHTML = 'Pattern Lab - ' + patternName;
+ window.history.replaceState({ 'pattern': patternName }, null, null);
+ }
+
+ document.getElementById('sg-raw').setAttribute('href', urlHandler.getFileName(patternName));
+
+ urlHandler.skipBack = true;
+ document.getElementById('sg-viewport').contentWindow.location.replace(iFramePath);
+}
+
+module.exports = {
+ sizeiframe : sizeiframe,
+ getRandom : getRandom,
+ updateViewportWidth : updateViewportWidth,
+ disco : disco,
+ killDisco : killDisco,
+ startDisco : startDisco,
+ startHay : startHay,
+ killHay : killHay,
+ toggleDisco : toggleDisco,
+ toggleHay : toggleHay,
+ updateSizeReading : updateSizeReading,
+ closePanels : closePanels,
+ init : init
+};
\ No newline at end of file
diff --git a/public/styleguide/js/handlers.js b/public/styleguide/js/handlers.js
new file mode 100644
index 000000000..a226da4b9
--- /dev/null
+++ b/public/styleguide/js/handlers.js
@@ -0,0 +1,290 @@
+/*jslint indent: 4, regexp: true*/
+/*global window*/
+var EventDelegator = require('./eventDelegator/eventDelegator'),
+ config = require('./config'),
+ dataSaver = require('./data-saver'),
+ gui = require('./gui'),
+ urlHandler = require('./url-handler'),
+ delegator = new EventDelegator(document.documentElement),
+ elViewport = document.getElementById('sg-viewport'),
+ elCover = document.getElementById('sg-cover');
+
+function _parents(element, selector, cb) {
+ var target = element.parentNode;
+
+ while (target && target !== document.documentElement) {
+ if (target.matches(selector)) {
+ cb(target);
+ }
+ target = target.parentNode;
+ }
+}
+
+function _siblings(element, selector, cb) {
+ var target = element.parentNode.children[0];
+
+ while (target) {
+ if (target.matches(selector)) {
+ cb(target);
+ }
+ target = target.nextSibling;
+ }
+}
+
+function _toggleUL(e) {
+ e.preventDefault();
+ var target = e.target.parentNode;
+
+ _parents(target, 'ul', function (el) {
+ el.classList.toggle('active');
+ });
+}
+
+function _size(num) {
+ gui.killDisco();
+ gui.killHay();
+ gui.sizeiframe(num);
+}
+
+delegator
+ // handles widening the "viewport"
+ // 1. on "mousedown" store the click location
+ // 2. make a hidden div visible so that it can track mouse movements and make sure the pointer doesn't get lost in the iframe
+ // 3. on "mousemove" calculate the math, save the results to a cookie, and update the viewport
+ .on('mousedown', '#sg-rightpull', function (e) {
+ // capture default data
+ var origClientX = e.clientX,
+ origViewportWidth = elViewport.offsetWidth;
+
+ // show the cover
+ elCover.style.display = 'block';
+
+ // add the mouse move event and capture data. also update the viewport width
+ delegator.on('mousemove', '#sg-cover', function (e) {
+ var viewportWidth = (origClientX > e.clientX) ?
+ origViewportWidth - ((origClientX - e.clientX) * 2) :
+ origViewportWidth + ((e.clientX - origClientX) * 2);
+
+ if (viewportWidth > config.minViewportWidth) {
+ if (!dataSaver.findValue('vpWidth')) {
+ dataSaver.addValue('vpWidth', viewportWidth);
+ } else {
+ dataSaver.updateValue('vpWidth', viewportWidth);
+ }
+
+ gui.sizeiframe(viewportWidth, false);
+ }
+ });
+ })
+
+ // on "mouseup" we unbind the "mousemove" event and hide the cover again
+ .on('mouseup', 'body', function () {
+ delegator.off('mousemove', '#sg-cover');
+ elCover.style.display = 'none';
+ })
+
+ /* Pattern Lab accordion dropdown */
+ .on('click', '.sg-acc-handle', function (e) {
+ var next = e.target;
+
+ while (next && (next.nodeType !== 1 || !next.matches('.sg-acc-panel'))) {
+ next = next.nextSibling;
+ }
+
+ e.preventDefault();
+
+ e.target.classList.toggle('active');
+ if (next) {
+ next.classList.toggle('active');
+ }
+ })
+
+ .on('click', '.sg-nav-toggle', function (e) {
+ e.preventDefault();
+ document.querySelector('.sg-nav-container').classList.toggle('active');
+ })
+
+ //View (containing clean, code, raw, etc options) Trigger
+ .on('click', '#sg-t-toggle', _toggleUL)
+
+ //Size Trigger
+ .on('click', '#sg-size-toggle', _toggleUL)
+
+ //Phase View Events
+ .on('click', '.sg-size[data-size]', function (e) {
+ e.preventDefault();
+ gui.killDisco();
+ gui.killHay();
+
+ var val = e.target.getAttribute('data-size');
+
+ if (val.indexOf('px') > -1) {
+ config.bodySize = 1;
+ }
+
+ val = val.replace(/[^\d.\-]/g, '');
+ gui.sizeiframe(Math.floor(val * config.bodySize));
+ })
+
+ //Size View Events
+
+ //Click Size Small Button
+ .on('click', '#sg-size-s', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(config.minViewportWidth, 500));
+ })
+
+ //Click Size Medium Button
+ .on('click', '#sg-size-m', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(500, 800));
+ })
+
+ //Click Size Large Button
+ .on('click', '#sg-size-l', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(800, 1200));
+ })
+
+ //Click Full Width Button
+ .on('click', '#sg-size-full', function (e) { //Resets
+ e.preventDefault();
+ _size(config.sw);
+ })
+
+ //Click Random Size Button
+ .on('click', '#sg-size-random', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(config.minViewportWidth, config.sw));
+ })
+
+ //Click for Disco Mode, which resizes the viewport randomly
+ .on('click', '#sg-size-disco', function (e) {
+ e.preventDefault();
+ gui.killHay();
+ gui.toggleDisco();
+ })
+
+ //Stephen Hay Mode - "Start with the small screen first, then expand until it looks like shit. Time for a breakpoint!"
+ .on('click', '#sg-size-hay', function (e) {
+ e.preventDefault();
+ gui.killDisco();
+ gui.toggleHay();
+ })
+
+ //Pixel input
+ .on('keydown', '.sg-size-px', function (e) {
+ var val = parseInt(e.target.value, 10);
+
+ if (e.keyCode === 38) { //If the up arrow key is hit
+ val++;
+ gui.sizeiframe(val, false);
+ } else if (e.keyCode === 40) { //If the down arrow key is hit
+ val--;
+ gui.sizeiframe(val, false);
+ } else if (e.keyCode === 13) { //If the Enter key is hit
+ e.preventDefault();
+ gui.sizeiframe(val); //Size Iframe to value of text box
+ e.target.blur();
+ }
+ })
+
+ .on('keyup', '.sg-size-px', function (e) {
+ var val = parseInt(e.target.value, 10);
+ gui.updateSizeReading(val, 'px', 'updateEmInput');
+ })
+
+ //Em input
+ .on('keydown', '.sg-size-em', function (e) {
+ var val = parseFloat(e.target.value);
+
+ if (e.keyCode === 38) { //If the up arrow key is hit
+ val++;
+ gui.sizeiframe(Math.floor(val * config.bodySize), false);
+ } else if (e.keyCode === 40) { //If the down arrow key is hit
+ val--;
+ gui.sizeiframe(Math.floor(val * config.bodySize), false);
+ } else if (e.keyCode === 13) { //If the Enter key is hit
+ e.preventDefault();
+ gui.sizeiframe(Math.floor(val * config.bodySize)); //Size Iframe to value of text box
+ }
+ })
+
+ .on('keyup', '.sg-size-em', function (e) {
+ var val = parseFloat(e.target.value);
+ gui.updateSizeReading(val, 'em', 'updatePxInput');
+ })
+
+ // handle the MQ click
+ .on('click', '#sg-mq a', function (e) {
+ e.preventDefault();
+ var val = e.target.innerHTML,
+ type = parseInt((val.indexOf('px') !== -1 ? 'px' : 'em'), 10);
+
+ val = val.replace(type, '');
+
+ gui.sizeiframe((type === 'px' ? val : val * config.bodySize), true);
+ })
+
+ // update the iframe with the source from clicked element in pull down menu. also close the menu
+ // having it outside fixes an auto-close bug i ran into
+ .on('click', '.sg-nav a', function (e) {
+ if (e.target.matches('.sg-acc-handle')) {
+ return;
+ }
+ e.preventDefault();
+
+ // update the iframe via the history api handler
+ document.getElementById('sg-viewport').contentWindow.postMessage(
+ {
+ 'path': urlHandler.getFileName(e.target.getAttribute('data-patternpartial'))
+ },
+ urlHandler.targetOrigin
+ );
+
+ // close up the menu
+ _parents(e.target, '.sg-acc-panel', function (el) {
+ el.classList.toggle('active');
+ _siblings(el, '.sg-acc-handle', function (el) {
+ el.classList.toggle('active');
+ });
+ });
+ return false;
+ })
+
+ .on('click', '#sg-vp-wrap', function () {
+ gui.closePanels();
+ });
+
+window.addEventListener('resize', function () {
+ config.sw = document.body.clientWidth;
+ config.sh = document.body.clientHeight;
+}, false);
+
+window.addEventListener('message', function receiveIframeMessage(event) {
+ // does the origin sending the message match the current host? if not dev/null the request
+ if ((window.location.protocol !== 'file:') && (event.origin !== window.location.protocol + '//' + window.location.host)) {
+ return;
+ }
+
+ if (event.data.bodyclick !== undefined) {
+ gui.closePanels();
+ } else if (event.data.patternpartial !== undefined) {
+ if (!urlHandler.skipBack) {
+ if (window.history.state === null || window.history.state.pattern !== event.data.patternpartial) {
+ urlHandler.pushPattern(event.data.patternpartial, event.data.path);
+ }
+ if (window.wsnConnected) {
+ console.log('wsn');
+ var iFramePath = urlHandler.getFileName(event.data.patternpartial);
+ window.wsn.send('{"url": "' + iFramePath + '", "patternpartial": "' + event.data.patternpartial + '" }');
+ }
+ }
+
+ // for testing purposes
+ //console.log(event.data.lineage);
+
+ // reset the defaults
+ urlHandler.skipBack = false;
+ }
+}, false);
\ No newline at end of file
diff --git a/public/styleguide/js/main.js b/public/styleguide/js/main.js
new file mode 100644
index 000000000..07108fcf5
--- /dev/null
+++ b/public/styleguide/js/main.js
@@ -0,0 +1,5 @@
+var gui = require('./gui');
+
+require('./handlers');
+
+gui.init();
\ No newline at end of file
diff --git a/public/styleguide/js/package.json b/public/styleguide/js/package.json
new file mode 100644
index 000000000..02c902022
--- /dev/null
+++ b/public/styleguide/js/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "patternLabStyleguideJS",
+ "version": "0.1.0",
+ "description": "",
+ "main": "main.js",
+ "scripts": {
+ "test": "test",
+ "build": "browserify main.js -o styleguide.js",
+ "watch": "watchify main.js -o styleguide.js --debug --verbose"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/public/styleguide/js/postmessage.js b/public/styleguide/js/postmessage.js
index cac192e3a..038a723ad 100644
--- a/public/styleguide/js/postmessage.js
+++ b/public/styleguide/js/postmessage.js
@@ -1,78 +1,114 @@
/*!
* Basic postMessage Support - v0.1
*
- * Copyright (c) 2013 Dave Olsen, http://dmolsen.com
+ * Copyright (c) 2013-2014 Dave Olsen, http://dmolsen.com
* Licensed under the MIT license
*
* Handles the postMessage stuff in the pattern, view-all, and style guide templates.
*
*/
+/*jslint indent:4*/
+/*global window*/
+
+function _jwertyCb(k, t) {
+ return function () {
+ var obj = JSON.stringify({ "keyPress": "ctrl+shift+" + k });
+ window.parent.postMessage(obj, t);
+ return false;
+ };
+}
+
+function _aClick(e) {
+ e.preventDefault();
+ var href = this.getAttribute("href");
+ if (href !== "#") {
+ window.location.replace(href);
+ }
+}
+
// alert the iframe parent that the pattern has loaded assuming this view was loaded in an iframe
-if (self != top) {
-
- // handle the options that could be sent to the parent window
- // - all get path
- // - pattern & view all get a pattern partial, styleguide gets all
- // - pattern shares lineage
- var options = { "path": window.location.toString() };
- options.patternpartial = (patternPartial != "") ? patternPartial : "all";
- if (lineage != "") {
- options.lineage = lineage;
- }
-
- var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
- parent.postMessage(options, targetOrigin);
-
- // find all links and add an onclick handler for replacing the iframe address so the history works
- var aTags = document.getElementsByTagName('a');
- for (a in aTags) {
- aTags[a].onclick = function(e) {
- e.preventDefault();
- window.location.replace(this.getAttribute("href"));
- };
- }
-
+if (window.self !== window.top) {
+ // handle the options that could be sent to the parent window
+ // - all get path
+ // - pattern & view all get a pattern partial, styleguide gets all
+ // - pattern shares lineage
+ var path = window.location.toString(),
+ parts = path.split('?'),
+ options = {'path': parts[0]},
+ i;
+
+ options.patternpartial = (window.patternPartial !== '') ? window.patternPartial : 'all';
+ if (window.lineage !== '') {
+ options.lineage = window.lineage;
+ }
+
+ var targetOrigin = (window.location.protocol === 'file:') ? '*' : window.location.protocol + '//' + window.location.host;
+ window.parent.postMessage(options, targetOrigin);
+
+ // find all links and add an onclick handler for replacing the iframe address so the history works
+ var aTags = document.getElementsByTagName('a');
+ for (i = 0; i < aTags.length; i++) {
+ aTags[i].onclick = _aClick;
+ }
+
+ // bind the keyboard shortcuts for various viewport resizings + pattern search
+ var keys = [ "s", "m", "l", "d", "h", "f" ];
+ for (i = 0; i < keys.length; i++) {
+ window.jwerty.key('ctrl+shift+' + keys[i], _jwertyCb(keys[i], targetOrigin));
+ }
+
+ // bind the keyboard shortcuts for mqs
+ var i = 0;
+ while (i < 10) {
+ window.jwerty.key('ctrl+shift+' + i, _jwertyCb(i, targetOrigin));
+ i++;
+ }
}
// if there are clicks on the iframe make sure the nav in the iframe parent closes
var body = document.getElementsByTagName('body');
-body[0].onclick = function() {
- var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
- parent.postMessage( { "bodyclick": "bodyclick" }, targetOrigin)
+body[0].onclick = function () {
+ var targetOrigin = (window.location.protocol === "file:") ? "*" : window.location.protocol + "//" + window.location.host;
+ var obj = JSON.stringify({ "bodyclick": "bodyclick" });
+ window.parent.postMessage(obj, targetOrigin);
};
// watch the iframe source so that it can be sent back to everyone else.
function receiveIframeMessage(event) {
-
- // does the origin sending the message match the current host? if not dev/null the request
- if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) {
- return;
- }
-
- // see if it got a path to replace
- if (event.data.path != undefined) {
-
- if (patternPartial != "") {
-
- // handle patterns and the view all page
- var re = /patterns\/(.*)$/;
- var path = window.location.protocol+"//"+window.location.host+window.location.pathname.replace(re,'')+event.data.path;
- window.location.replace(path);
-
- } else {
-
- // handle the style guide
- var path = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("styleguide\/html\/styleguide.html","")+event.data.path;
- window.location.replace(path);
-
- }
-
- } else if (event.data.reload != undefined) {
-
- // reload the location if there was a message to do so
- window.location.reload();
- }
-
+ var data = (typeof event.data !== "string") ? event.data : JSON.parse(event.data),
+ path;
+
+ // does the origin sending the message match the current host? if not dev/null the request
+ if ((window.location.protocol !== "file:") && (event.origin !== window.location.protocol + "//" + window.location.host)) {
+ return;
+ }
+
+ // see if it got a path to replace
+ if (data.path !== undefined) {
+
+ if (window.patternPartial !== '') {
+
+ // handle patterns and the view all page
+ /*jslint regexp:true*/
+ var re = /patterns\/(.*)$/;
+ path = window.location.protocol + "//" + window.location.host + window.location.pathname.replace(re, '') + data.path + '?' + Date.now();
+ window.location.replace(path);
+
+ } else {
+
+ // handle the style guide
+ path = window.location.protocol + "//" + window.location.host + window.location.pathname.replace("styleguide\/html\/styleguide.html", "") + data.path + '?' + Date.now();
+ window.location.replace(path);
+
+ }
+
+ } else if (data.reload !== undefined) {
+
+ // reload the location if there was a message to do so
+ window.location.reload();
+
+ }
+
}
-window.addEventListener("message", receiveIframeMessage, false);
+window.addEventListener("message", receiveIframeMessage, false);
\ No newline at end of file
diff --git a/public/styleguide/js/styleguide.js b/public/styleguide/js/styleguide.js
index e3b860fba..a62db93c9 100644
--- a/public/styleguide/js/styleguide.js
+++ b/public/styleguide/js/styleguide.js
@@ -1,461 +1,1327 @@
-(function(w){
-
- var sw = document.body.clientWidth, //Viewport Width
- sh = document.body.clientHeight, //Viewport Height
- minViewportWidth = 240, //Minimum Size for Viewport
- maxViewportWidth = 2600, //Maxiumum Size for Viewport
- viewportResizeHandleWidth = 14, //Width of the viewport drag-to-resize handle
- $sgViewport = $('#sg-viewport'), //Viewport element
- $sizePx = $('.sg-size-px'), //Px size input element in toolbar
- $sizeEms = $('.sg-size-em'), //Em size input element in toolbar
- $bodySize = parseInt($('body').css('font-size')), //Body size of the document
- $vp = Object,
- $sgPattern = Object,
- discoID = false,
- discoMode = false,
- hayMode = false;
-
-
- $(w).resize(function(){ //Update dimensions on resize
- sw = document.body.clientWidth;
- sh = document.body.clientHeight;
- });
-
- /* Pattern Lab accordion dropdown */
- $('.sg-acc-handle').on("click", function(e){
- var $this = $(this),
- $panel = $this.next('.sg-acc-panel');
- e.preventDefault();
- $this.toggleClass('active');
- $panel.toggleClass('active');
- });
-
- $('.sg-nav-toggle').on("click", function(e){
- e.preventDefault();
- $('.sg-nav-container').toggleClass('active');
- });
-
- //"View (containing clean, code, raw, etc options) Trigger
- $('#sg-t-toggle').on("click", function(e){
- e.preventDefault();
- $(this).parents('ul').toggleClass('active');
- });
-
- //Size Trigger
- $('#sg-size-toggle').on("click", function(e){
- e.preventDefault();
- $(this).parents('ul').toggleClass('active');
- });
-
- //Phase View Events
- $('.sg-size[data-size]').on("click", function(e){
- e.preventDefault();
- killDisco();
- killHay();
-
- var val = $(this).attr('data-size');
-
- if (val.indexOf('px') > -1) {
- $bodySize = 1;
- }
-
- val = val.replace(/[^\d.-]/g,'')
- sizeiframe(Math.floor(val*$bodySize));
- });
-
- //Size View Events
-
- //Click Size Small Button
- $('#sg-size-s').on("click", function(e){
- e.preventDefault();
- killDisco();
- killHay();
- sizeiframe(getRandom(minViewportWidth,500));
- });
-
- //Click Size Medium Button
- $('#sg-size-m').on("click", function(e){
- e.preventDefault();
- killDisco();
- killHay();
- sizeiframe(getRandom(500,800));
- });
-
- //Click Size Large Button
- $('#sg-size-l').on("click", function(e){
- e.preventDefault();
- killDisco();
- killHay();
- sizeiframe(getRandom(800,1200));
- });
-
- //Click Full Width Button
- $('#sg-size-full').on("click", function(e){ //Resets
- e.preventDefault();
- killDisco();
- killHay();
- sizeiframe(sw);
- });
-
- //Click Random Size Button
- $('#sg-size-random').on("click", function(e){
- e.preventDefault();
- killDisco();
- killHay();
- sizeiframe(getRandom(minViewportWidth,sw));
- });
-
- //Click for Disco Mode, which resizes the viewport randomly
- $('#sg-size-disco').on("click", function(e){
- e.preventDefault();
- killHay();
-
- if (discoMode) {
- killDisco();
-
- } else {
- startDisco();
- }
- });
-
- /* Disco Mode */
- function disco() {
- sizeiframe(getRandom(minViewportWidth,sw));
- }
-
- function killDisco() {
- discoMode = false;
- clearInterval(discoID);
- discoID = false;
- }
-
- function startDisco() {
- discoMode = true;
- discoID = setInterval(disco, 800);
- }
-
- //Stephen Hay Mode - "Start with the small screen first, then expand until it looks like shit. Time for a breakpoint!"
- $('#sg-size-hay').on("click", function(e){
- e.preventDefault();
- killDisco();
-
- if (hayMode) {
- killHay();
- } else {
- startHay();
- }
- });
-
- //Stop Hay! Mode
- function killHay() {
- var currentWidth = $sgViewport.width();
- hayMode = false;
- $sgViewport.removeClass('hay-mode');
- $('#sg-gen-container').removeClass('hay-mode');
- sizeiframe(Math.floor(currentWidth));
- }
-
- // start Hay! mode
- function startHay() {
- hayMode = true;
- $('#sg-gen-container').removeClass("vp-animate").width(minViewportWidth+viewportResizeHandleWidth);
- $sgViewport.removeClass("vp-animate").width(minViewportWidth);
-
- var timeoutID = window.setTimeout(function(){
- $('#sg-gen-container').addClass('hay-mode').width(maxViewportWidth+viewportResizeHandleWidth);
- $sgViewport.addClass('hay-mode').width(maxViewportWidth);
-
- setInterval(function(){ var vpSize = $sgViewport.width(); updateSizeReading(vpSize); },100);
- }, 200);
- }
-
- //Pixel input
- $sizePx.on('keydown', function(e){
- var val = Math.floor($(this).val());
-
- if(e.keyCode == 38) { //If the up arrow key is hit
- val++;
- sizeiframe(val,false);
- } else if(e.keyCode == 40) { //If the down arrow key is hit
- val--;
- sizeiframe(val,false);
- } else if(e.keyCode == 13) { //If the Enter key is hit
- e.preventDefault();
- sizeiframe(val); //Size Iframe to value of text box
- $(this).blur();
- }
-
- });
-
- $sizePx.on('keyup', function(e){
- var val = Math.floor($(this).val());
- updateSizeReading(val,'px','updateEmInput');
- });
-
- //Em input
- $sizeEms.on('keydown', function(e){
- var val = parseFloat($(this).val());
-
- if(e.keyCode == 38) { //If the up arrow key is hit
- val++;
- sizeiframe(Math.floor(val*$bodySize),false);
- } else if(e.keyCode == 40) { //If the down arrow key is hit
- val--;
- sizeiframe(Math.floor(val*$bodySize),false);
- } else if(e.keyCode == 13) { //If the Enter key is hit
- e.preventDefault();
- sizeiframe(Math.floor(val*$bodySize)); //Size Iframe to value of text box
- }
- });
-
- $sizeEms.on('keyup', function(e){
- var val = parseFloat($(this).val());
- updateSizeReading(val,'em','updatePxInput');
- });
-
- // handle the MQ click
- $('#sg-mq a').on("click", function(e){
- e.preventDefault();
- var val = $(this).html();
- var type = (val.indexOf("px") != -1) ? "px" : "em";
- val = val.replace(type,"");
- var width = (type == "px") ? val*1 : val*$bodySize;
- sizeiframe(width,true);
- });
-
- //Resize the viewport
- //'size' is the target size of the viewport
- //'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
- function sizeiframe(size,animate) {
- var theSize;
-
- if(size>maxViewportWidth) { //If the entered size is larger than the max allowed viewport size, cap value at max vp size
- theSize = maxViewportWidth;
- } else if(size event.clientX) ? origViewportWidth - ((origClientX - event.clientX)*2) : origViewportWidth + ((event.clientX - origClientX)*2);
-
- if (viewportWidth > minViewportWidth) {
-
- if (!DataSaver.findValue('vpWidth')) {
- DataSaver.addValue("vpWidth",viewportWidth);
- } else {
- DataSaver.updateValue("vpWidth",viewportWidth);
- }
-
- sizeiframe(viewportWidth,false);
- }
- });
- });
-
- // on "mouseup" we unbind the "mousemove" event and hide the cover again
- $('body').mouseup(function(event) {
- $('#sg-cover').unbind('mousemove');
- $('#sg-cover').css("display","none");
- });
-
- // capture the viewport width that was loaded and modify it so it fits with the pull bar
- var origViewportWidth = $("#sg-viewport").width();
- $("#sg-gen-container").width(origViewportWidth);
- $("#sg-viewport").width(origViewportWidth - 14);
- updateSizeReading($("#sg-viewport").width());
-
- // get the request vars
- var oGetVars = urlHandler.getRequestVars();
-
- // pre-load the viewport width
- var vpWidth = 0;
- var trackViewportWidth = true; // can toggle this feature on & off
- if ((oGetVars.h != undefined) || (oGetVars.hay != undefined)) {
- startHay();
- } else if ((oGetVars.d != undefined) || (oGetVars.disco != undefined)) {
- startDisco();
- } else if ((oGetVars.w != undefined) || (oGetVars.width != undefined)) {
- vpWidth = (oGetVars.w != undefined) ? oGetVars.w : oGetVars.width;
- vpWidth = (vpWidth.indexOf("em") != -1) ? Math.floor(Math.floor(vpWidth.replace("em",""))*$bodySize) : Math.floor(vpWidth.replace("px",""));
- DataSaver.updateValue("vpWidth",vpWidth);
- updateViewportWidth(vpWidth);
- } else if (trackViewportWidth && (vpWidth = DataSaver.findValue("vpWidth"))) {
- updateViewportWidth(vpWidth);
- }
-
- // load the iframe source
- var patternName = "all";
- var patternPath = "";
- var iFramePath = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+"styleguide/html/styleguide.html";
- if ((oGetVars.p != undefined) || (oGetVars.pattern != undefined)) {
- patternName = (oGetVars.p != undefined) ? oGetVars.p : oGetVars.pattern;
- patternPath = urlHandler.getFileName(patternName);
- iFramePath = (patternPath != "") ? window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+patternPath : iFramePath;
- }
-
- if (patternName != "all") {
- document.getElementById("title").innerHTML = "Pattern Lab - "+patternName;
- history.replaceState({ "pattern": patternName }, null, null);
- }
-
- document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(patternName));
-
- urlHandler.skipBack = true;
- document.getElementById("sg-viewport").contentWindow.location.replace(iFramePath);
-
- //IFrame functionality
-
-})(this);
-
-// update the iframe with the source from clicked element in pull down menu. also close the menu
-// having it outside fixes an auto-close bug i ran into
-$('.sg-nav a').not('.sg-acc-handle').on("click", function(e){
-
- e.preventDefault();
-
- // update the iframe via the history api handler
- document.getElementById("sg-viewport").contentWindow.postMessage( { "path": urlHandler.getFileName($(this).attr("data-patternpartial")) }, urlHandler.targetOrigin);
-
- // close up the menu
- $(this).parents('.sg-acc-panel').toggleClass('active');
- $(this).parents('.sg-acc-panel').siblings('.sg-acc-handle').toggleClass('active');
-
- return false;
-
-});
+(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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) {
+ updateCookieVals += "|" + fieldVals[0] + "~" + fieldVals[1];
+ } else {
+ updateCookieVals += fieldVals[0] + "~" + fieldVals[1];
+ }
+ }
+ cookie.write(this.cookieName, updateCookieVals);
+ } else {
+ this.addValue(name, val);
+ }
+ },
+
+ /**
+ * Remove the given key
+ * @param {String} the name of the key
+ */
+ removeValue: function (name) {
+ var updateCookieVals = "",
+ cookieVals = cookie.read(this.cookieName).split("|"),
+ k = 0,
+ i,
+ l,
+ fieldVals;
+ for (i = 0, l = cookieVals.length; i < l; i++) {
+ fieldVals = cookieVals[i].split("~");
+ if (fieldVals[0] !== name) {
+ if (k === 0) {
+ updateCookieVals += fieldVals[0] + "~" + fieldVals[1];
+ } else {
+ updateCookieVals += "|" + fieldVals[0] + "~" + fieldVals[1];
+ }
+ k++;
+ }
+ }
+ cookie.write(this.cookieName, updateCookieVals);
+ },
+
+ /**
+ * Find the value using the given key
+ * @param {String} the name of the key
+ *
+ * @return {String} the value of the key or false if the value isn't found
+ */
+ findValue: function (name) {
+ if (cookie.read(this.cookieName)) {
+ var cookieVals = cookie.read(this.cookieName).split("|"),
+ i,
+ l,
+ fieldVals;
+ for (i = 0, l = cookieVals.length; i < l; i++) {
+ fieldVals = cookieVals[i].split("~");
+ if (fieldVals[0] === name) {
+ return fieldVals[1];
+ }
+ }
+ }
+ return false;
+ }
+};
+
+module.exports = DataSaver;
+},{"./cookie":"/Users/tor/projects/patternlab-node/public/styleguide/js/cookie.js"}],"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/eventDelegator.js":[function(require,module,exports){
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+var WM = require('./weakMapSet').WeakMap,
+ delegators = new WM();
+
+require('./matches.js');
+
+function EventDelegator(element) {
+ var delegator = delegators.get(element);
+
+ if (delegator) {
+ return delegator;
+ }
+
+ this.events = {};
+ this.element = element;
+ this.handlers = {};
+ delegators.set(element, this);
+}
+
+EventDelegator.prototype._match = function (selectors, e) {
+ var target = e.target,
+ selector;
+
+ function _runCallback(selector) {
+ var i,
+ l;
+ for (i = 0, l = selectors[selector].length; i < l; i++) {
+ selectors[selector][i](e);
+ }
+ }
+ while (target !== this.element) {
+ for (selector in selectors) {
+ if (selectors.hasOwnProperty(selector) && target.matches(selector)) {
+ _runCallback(selector);
+ }
+ }
+ if (!target.parentNode) {
+ return;
+ }
+ target = target.parentNode;
+ }
+};
+
+EventDelegator.prototype.on = function (type, selector, cb) {
+ //todo support elements as selector
+
+ var _this = this;
+
+ function handler(e) {
+ _this._match(_this.events[type], e);
+ }
+
+ if (!this.events[type]) {
+ this.events[type] = {};
+
+ this.handlers[type] = handler;
+ this.element.addEventListener(type, handler, false);
+ }
+
+ this.events[type][selector] = this.events[type][selector] || [];
+
+ if (this.events[type][selector].indexOf(cb) === -1) {
+ this.events[type][selector].push(cb);
+ }
+ return this;
+};
+
+EventDelegator.prototype.off = function (type, selector, cb) {
+ if (type === undefined) {
+ Object.keys(this.events).every(function (evtType) {
+ this.element.removeEventListener(evtType, this.handlers[evtType]);
+ return true;
+ });
+ this.events = {};
+ } else if (selector === undefined) {
+ //remove all of one type
+ if (this.events[type]) {
+ this.element.removeEventListener(type, this.handlers[type]);
+ delete this.events[type];
+ delete this.handlers[type];
+ }
+ } else if (cb === undefined) {
+ // remove all handlers
+ if (this.events[type] && this.events[type][selector]) {
+ delete this.events[type][selector];
+ // Remove eventlistener if no selectors are present
+ if (Object.keys(this.events[type]).length === 0) {
+ this.off(type);
+ }
+ }
+ } else {
+ // remove specific handler
+ var i = this.events[type][selector].indexOf(cb);
+
+ if (i !== -1) {
+ this.events[type][selector].splice(i, 1);
+ }
+ }
+ return this;
+};
+
+EventDelegator.prototype.toString = function () {
+ return 'EventDelegator';
+};
+
+module.exports = EventDelegator;
+},{"./matches.js":"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/matches.js","./weakMapSet":"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/weakMapSet.js"}],"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/matches.js":[function(require,module,exports){
+/*jslint indent: 4*/
+/*global window*/
+/**
+ * Polyfill for Element.matches
+ **/
+function addPolyfill(ElementPrototype) {
+ 'use strict';
+
+ if (ElementPrototype.matches !== undefined) {
+ return;
+ }
+
+ ElementPrototype.matches = ElementPrototype.matchesSelector ||
+ ElementPrototype.mozMatchesSelector ||
+ ElementPrototype.msMatchesSelector ||
+ ElementPrototype.oMatchesSelector ||
+ ElementPrototype.webkitMatchesSelector ||
+ function (selector) {
+ var node = this,
+ nodes = (node.parentNode || node.document).querySelectorAll(selector),
+ i = -1;
+
+ while (nodes[i] && nodes[i] !== node) {
+ ++i;
+ }
+
+ return !!nodes[i];
+ };
+}
+
+if (module && module.exports) {
+ module.exports = addPolyfill;
+} else {
+ addPolyfill(window.Element.prototype);
+}
+},{}],"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/weakMapSet.js":[function(require,module,exports){
+(function (global){
+"WeakMap" in this || (function (module) {"use strict";
+
+ //!(C) WebReflection - Mit Style License
+ // size and performances oriented polyfill for ES6
+ // WeakMap, Map, and Set
+ // compatible with node.js, Rhino, any browser
+ // does not implement default vaule during wm.get()
+ // since ES.next won't probably do that
+ // use wm.has(o) ? wm.get(o) : d3fault; instead
+
+ // WeakMap(void):WeakMap
+ function WeakMap() {
+
+ // private references holders
+ var
+ keys = [],
+ values = []
+ ;
+
+ // returns freshly new created
+ // instanceof WeakMap in any case
+ return create(WeakMapPrototype, {
+ // WeakMap#delete(key:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, TRUE, keys, values)},
+ //:was WeakMap#get(key:void*[, d3fault:void*]):void*
+ // WeakMap#get(key:void*):void*
+ get: {value: bind.call(sharedGet, NULL, TRUE, keys, values)},
+ // WeakMap#has(key:void*):boolean
+ has: {value: bind.call(sharedHas, NULL, TRUE, keys, values)},
+ // WeakMap#set(key:void*, value:void*):void
+ set: {value: bind.call(sharedSet, NULL, TRUE, keys, values)}
+ });
+
+ }
+
+ // Map(void):Map
+ function Map() {
+
+ // private references holders
+ var
+ keys = [],
+ values = []
+ ;
+
+ // returns freshly new created
+ // instanceof WeakMap in any case
+ return create(MapPrototype, {
+ // Map#delete(key:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, FALSE, keys, values)},
+ //:was Map#get(key:void*[, d3fault:void*]):void*
+ // Map#get(key:void*):void*
+ get: {value: bind.call(sharedGet, NULL, FALSE, keys, values)},
+ // Map#has(key:void*):boolean
+ has: {value: bind.call(sharedHas, NULL, FALSE, keys, values)},
+ // Map#set(key:void*, value:void*):void
+ set: {value: bind.call(sharedSet, NULL, FALSE, keys, values)}
+ /*,
+ // Map#size(void):number === Mozilla only so far
+ size: {value: bind.call(sharedSize, NULL, keys)},
+ // Map#keys(void):Array === not in specs
+ keys: {value: boundSlice(keys)},
+ // Map#values(void):Array === not in specs
+ values: {value: boundSlice(values)},
+ // Map#iterate(callback:Function, context:void*):void ==> callback.call(context, key, value, index) === not in specs
+ iterate: {value: bind.call(sharedIterate, NULL, FALSE, keys, values)}
+ //*/
+ });
+
+ }
+
+ // Set(void):Set
+ /**
+ * to be really honest, I would rather pollute Array.prototype
+ * in order to have Set like behavior
+ * Object.defineProperties(Array.prototype, {
+ * add: {value: function add(value) {
+ * return -1 < this.indexOf(value) && !!this.push(value);
+ * }}
+ * has: {value: function has(value) {
+ * return -1 < this.indexOf(value);
+ * }}
+ * delete: {value: function delete(value) {
+ * var i = this.indexOf(value);
+ * return -1 < i && !!this.splice(i, 1);
+ * }}
+ * });
+ * ... anyway ...
+ */
+ function Set() {
+ var
+ keys = [], // placeholder used simply to recycle functions
+ values = [],// real storage
+ has = bind.call(sharedHas, NULL, FALSE, values, keys)
+ ;
+ return create(SetPrototype, {
+ // Set#delete(value:void*):boolean
+ "delete": {value: bind.call(sharedDel, NULL, FALSE, values, keys)},
+ // Set#has(value:void*):boolean
+ has: {value: has},
+ // Set#add(value:void*):boolean
+ add: {value: bind.call(Set_add, NULL, FALSE, has, values)}
+ /*,
+ // Map#size(void):number === Mozilla only
+ size: {value: bind.call(sharedSize, NULL, values)},
+ // Set#values(void):Array === not in specs
+ values: {value: boundSlice(values)},
+ // Set#iterate(callback:Function, context:void*):void ==> callback.call(context, value, index) === not in specs
+ iterate: {value: bind.call(Set_iterate, NULL, FALSE, NULL, values)}
+ //*/
+ });
+ }
+
+ // common shared method recycled for all shims through bind
+ function sharedDel(objectOnly, keys, values, key) {
+ if (sharedHas(objectOnly, keys, values, key)) {
+ keys.splice(i, 1);
+ values.splice(i, 1);
+ }
+ // Aurora here does it while Canary doesn't
+ return -1 < i;
+ }
+
+ function sharedGet(objectOnly, keys, values, key/*, d3fault*/) {
+ return sharedHas(objectOnly, keys, values, key) ? values[i] : undefined; //d3fault;
+ }
+
+ function sharedHas(objectOnly, keys, values, key) {
+ if (objectOnly && key !== Object(key)) {
+ console.log(key);
+ throw new TypeError("not a non-null object");
+ }
+ i = betterIndexOf.call(keys, key);
+ return -1 < i;
+ }
+
+ function sharedSet(objectOnly, keys, values, key, value) {
+ /* return */sharedHas(objectOnly, keys, values, key) ?
+ values[i] = value
+ :
+ values[keys.push(key) - 1] = value
+ ;
+ }
+
+ /* keys, values, and iterate related methods
+ function boundSlice(values) {
+ return function () {
+ return slice.call(values);
+ };
+ }
+
+ function sharedSize(keys) {
+ return keys.length;
+ }
+
+ function sharedIterate(objectOnly, keys, values, callback, context) {
+ for (var
+ k = slice.call(keys), v = slice.call(values),
+ i = 0, length = k.length;
+ i < length; callback.call(context, k[i], v[i], i++)
+ );
+ }
+
+ function Set_iterate(objectOnly, keys, values, callback, context) {
+ for (var
+ v = slice.call(values),
+ i = 0, length = v.length;
+ i < length; callback.call(context, v[i], i++)
+ );
+ }
+ //*/
+
+ // Set#add recycled through bind per each instanceof Set
+ function Set_add(objectOnly, has, values, value) {
+ /*return */(!has(value) && !!values.push(value));
+ }
+
+ // a more reliable indexOf
+ function betterIndexOf(value) {
+ if (value != value || value === 0) {
+ for (i = this.length; i-- && !is(this[i], value););
+ } else {
+ i = indexOf.call(this, value);
+ }
+ return i;
+ }
+
+ // need for an empty constructor ...
+ function Constructor(){} // GC'ed if !!Object.create
+ // ... so that new WeakMapInstance and new WeakMap
+ // produces both an instanceof WeakMap
+
+ var
+ // shortcuts and ...
+ NULL = null, TRUE = true, FALSE = false,
+ notInNode = module == "undefined",
+ window = notInNode ? this : global,
+ module = notInNode ? {} : exports,
+ Object = window.Object,
+ WeakMapPrototype = WeakMap.prototype,
+ MapPrototype = Map.prototype,
+ SetPrototype = Set.prototype,
+ defineProperty = Object.defineProperty,
+ slice = [].slice,
+
+ // Object.is(a, b) shim
+ is = Object.is || function (a, b) {
+ return a === b ?
+ a !== 0 || 1 / a == 1 / b :
+ a != a && b != b
+ ;
+ },
+
+ // partial polyfill for this aim only
+ bind = WeakMap.bind || function bind(context, objectOnly, keys, values) {
+ // partial fast ad-hoc Function#bind polyfill if not available
+ var callback = this;
+ return function bound(key, value) {
+ if (!!key === false) {
+ console.log(arguments.caller.callee);
+ };
+ return callback.call(context, objectOnly, keys, values, key, value);
+ };
+ },
+
+ create = Object.create || function create(proto, descriptor) {
+ // partial ad-hoc Object.create shim if not available
+ Constructor.prototype = proto;
+ var object = new Constructor(), key;
+ for (key in descriptor) {
+ object[key] = descriptor[key].value;
+ }
+ return object;
+ },
+
+ indexOf = [].indexOf || function indexOf(value) {
+ // partial fast Array#indexOf polyfill if not available
+ for (i = this.length; i-- && this[i] !== value;);
+ return i;
+ },
+
+ undefined,
+ i // recycle ALL the variables !
+ ;
+
+ // ~indexOf.call([NaN], NaN) as future possible feature detection
+
+ // used to follow FF behavior where WeakMap.prototype is a WeakMap itself
+ WeakMap.prototype = WeakMapPrototype = WeakMap();
+ Map.prototype = MapPrototype = Map();
+ Set.prototype = SetPrototype = Set();
+
+ // assign it to the global context
+ // if already there, e.g. in node, export native
+ window.WeakMap = module.WeakMap = window.WeakMap || WeakMap;
+ window.Map = module.Map = window.Map || Map;
+ window.Set = module.Set = window.Set || Set;
+
+ /* probably not needed, add a slash to ensure non configurable and non writable
+ if (defineProperty) {
+ defineProperty(window, "WeakMap", {value: WeakMap});
+ defineProperty(window, "Map", {value: Map});
+ defineProperty(window, "Set", {value: Set});
+ }
+ //*/
+
+ // that's pretty much it
+
+}.call(
+ this,
+ typeof exports
+));
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],"/Users/tor/projects/patternlab-node/public/styleguide/js/gui.js":[function(require,module,exports){
+/*jslint indent: 4*/
+/*global window*/
+'use strict';
+var config = require('./config'),
+ dataSaver = require('./data-saver'),
+ urlHandler = require('./url-handler'),
+ elGenContainer = document.getElementById('sg-gen-container'),
+ elViewport = document.getElementById('sg-viewport'),
+ elSizePx = document.querySelector('.sg-size-px'), //Px size input element in toolbar
+ elSizeEms = document.querySelector('.sg-size-em'), //Em size input element in toolbar;
+ discoID = false,
+ discoMode = false,
+ hayMode = false;
+
+//Update Pixel and Em inputs
+//'size' is the input number
+//'unit' is the type of unit: either px or em. Default is px. Accepted values are 'px' and 'em'
+//'target' is what inputs to update. Defaults to both
+function updateSizeReading(size, unit, target) {
+ var emSize = (unit === 'em' ? Math.floor(size * config.bodySize) : size),
+ pxSize = (unit === 'em' ? size / config.bodySize : size);
+
+ if (target === 'updatePxInput') {
+ elSizePx.value = pxSize;
+ } else if (target === 'updateEmInput') {
+ elSizeEms.value = emSize;
+ } else {
+ elSizeEms.value = emSize;
+ elSizePx.value = pxSize;
+ }
+}
+
+function saveSize(size) {
+ if (!dataSaver.findValue('vpWidth')) {
+ dataSaver.addValue('vpWidth', size);
+ } else {
+ dataSaver.updateValue('vpWidth', size);
+ }
+}
+
+/* Returns a random number between min and max */
+function getRandom(min, max) {
+ return Math.random() * (max - min) + min;
+}
+
+//Resize the viewport
+//'size' is the target size of the viewport
+//'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
+function sizeiframe(size, animate) {
+ var theSize;
+
+ if (size > config.maxViewportWidth) { //If the entered size is larger than the max allowed viewport size, cap value at max vp size
+ theSize = config.maxViewportWidth;
+ } else if (size < config.minViewportWidth) { //If the entered size is less than the minimum allowed viewport size, cap value at min vp size
+ theSize = config.minViewportWidth;
+ } else {
+ theSize = size;
+ }
+
+ //Conditionally remove CSS animation class from viewport
+ elGenContainer.classList.remove('vp-animate', animate);
+ elViewport.classList.remove('vp-animate', animate);
+
+ elGenContainer.style.width = (theSize + config.viewportResizeHandleWidth) + 'px'; //Resize viewport wrapper to desired size + size of drag resize handler
+ elViewport.style.width = theSize + 'px'; //Resize viewport to desired size
+
+ updateSizeReading(theSize); //Update values in toolbar
+ saveSize(theSize); //Save current viewport to cookie
+}
+
+function updateViewportWidth(size) {
+ size = parseInt(size, 10);
+ elViewport.style.width = parseInt(size, 10) + 'px';
+ elGenContainer.style.width = (size + 14) + 'px';
+
+ updateSizeReading(size);
+}
+
+/* Disco Mode */
+function disco() {
+ sizeiframe(getRandom(config.minViewportWidth, config.sw));
+}
+
+function killDisco() {
+ discoMode = false;
+ clearInterval(discoID);
+ discoID = false;
+}
+
+function startDisco() {
+ discoMode = true;
+ discoID = setInterval(disco, 800);
+}
+
+function toggleDisco() {
+ if (!discoMode) {
+ startDisco();
+ } else {
+ killDisco();
+ }
+}
+
+//Stop Hay! Mode
+function killHay() {
+ var currentWidth = elViewport.offsetWidth;
+ hayMode = false;
+ elViewport.classList.remove('hay-mode');
+ elGenContainer.classList.remove('hay-mode');
+ sizeiframe(Math.floor(currentWidth));
+}
+
+// start Hay! mode
+function startHay() {
+ hayMode = true;
+ elGenContainer.classList.remove('vp-animate');
+ elGenContainer.style.width = (config.minViewportWidth + config.viewportResizeHandleWidth) + 'px';
+ elViewport.classList.remove('vp-animate');
+ elViewport.style.width = config.minViewportWidth + 'px';
+
+ window.setTimeout(function () {
+ elGenContainer.classList.add('hay-mode');
+ elGenContainer.style.width = (config.maxViewportWidth + config.viewportResizeHandleWidth) + 'px';
+ elViewport.classList.add('hay-mode');
+ elViewport.style.width = config.maxViewportWidth + 'px';
+
+ //todo this is not removed
+ setInterval(function () {
+ var vpSize = elViewport.offsetWidth;
+ updateSizeReading(vpSize);
+ }, 100);
+ }, 200);
+}
+
+function toggleHay() {
+ if (!hayMode) {
+ startHay();
+ } else {
+ killHay();
+ }
+}
// handle when someone clicks on the grey area of the viewport so it auto-closes the nav
function closePanels() {
- // close up the menu
- $('.sg-acc-panel').each(function() {
- if ($(this).hasClass('active')) {
- $(this).toggleClass('active');
- }
- });
-
- $('.sg-acc-handle').each(function() {
- if ($(this).hasClass('active')) {
- $(this).toggleClass('active');
- }
- });
+ // close up the menu
+ var panels = document.querySelectorAll('.sg-acc-panel'),
+ handles = document.querySelectorAll('.sg-acc-handle');
+
+ [].forEach.call(panels, function (panel) {
+ panel.classList.remove('active');
+ });
+
+
+ [].forEach.call(handles, function (handle) {
+ handle.classList.remove('active');
+ });
+}
+
+function init() {
+ var origViewportWidth = elViewport.offsetWidth,
+ oGetVars = urlHandler.getRequestVars(), // get the request vars
+ vpWidth = 0,
+ trackViewportWidth = true, // can toggle this feature on & off
+ patternName = 'all',
+ patternPath = '',
+ iFramePath = window.location.protocol + '//' + window.location.host + window.location.pathname.replace('index.html', '') + 'styleguide/html/styleguide.html';
+
+ // capture the viewport width that was loaded and modify it so it fits with the pull bar
+ elGenContainer.style.width = origViewportWidth + 'px';
+ elViewport.style.width = (origViewportWidth - 14) + 'px';
+ updateSizeReading(origViewportWidth - 14);
+
+ // pre-load the viewport width
+ if (oGetVars.h || oGetVars.hay) {
+ startHay();
+ } else if (oGetVars.d || oGetVars.disco) {
+ startDisco();
+ } else if (oGetVars.w || oGetVars.width) {
+ vpWidth = oGetVars.w || oGetVars.width;
+ vpWidth = vpWidth.indexOf('em') !== -1 ? Math.floor(Math.floor(vpWidth.replace('em', '')) * config.bodySize) : Math.floor(vpWidth.replace('px', ''));
+
+ dataSaver.updateValue('vpWidth', vpWidth);
+ updateViewportWidth(vpWidth);
+ } else if (trackViewportWidth && dataSaver.findValue('vpWidth')) {
+ updateViewportWidth(dataSaver.findValue('vpWidth'));
+ }
+
+ // load the iframe source
+ if (oGetVars.p || oGetVars.pattern) {
+ patternName = oGetVars.p || oGetVars.pattern;
+ patternPath = urlHandler.getFileName(patternName);
+ iFramePath = (patternPath !== '') ? window.location.protocol + '//' + window.location.host + window.location.pathname.replace('index.html', '') + patternPath : iFramePath;
+ }
+
+ if (patternName !== 'all') {
+ document.getElementById('title').innerHTML = 'Pattern Lab - ' + patternName;
+ window.history.replaceState({ 'pattern': patternName }, null, null);
+ }
+
+ document.getElementById('sg-raw').setAttribute('href', urlHandler.getFileName(patternName));
+
+ urlHandler.skipBack = true;
+ document.getElementById('sg-viewport').contentWindow.location.replace(iFramePath);
+}
+
+module.exports = {
+ sizeiframe : sizeiframe,
+ getRandom : getRandom,
+ updateViewportWidth : updateViewportWidth,
+ disco : disco,
+ killDisco : killDisco,
+ startDisco : startDisco,
+ startHay : startHay,
+ killHay : killHay,
+ toggleDisco : toggleDisco,
+ toggleHay : toggleHay,
+ updateSizeReading : updateSizeReading,
+ closePanels : closePanels,
+ init : init
+};
+},{"./config":"/Users/tor/projects/patternlab-node/public/styleguide/js/config.js","./data-saver":"/Users/tor/projects/patternlab-node/public/styleguide/js/data-saver.js","./url-handler":"/Users/tor/projects/patternlab-node/public/styleguide/js/url-handler.js"}],"/Users/tor/projects/patternlab-node/public/styleguide/js/handlers.js":[function(require,module,exports){
+/*jslint indent: 4, regexp: true*/
+/*global window*/
+var EventDelegator = require('./eventDelegator/eventDelegator'),
+ config = require('./config'),
+ dataSaver = require('./data-saver'),
+ gui = require('./gui'),
+ urlHandler = require('./url-handler'),
+ delegator = new EventDelegator(document.documentElement),
+ elViewport = document.getElementById('sg-viewport'),
+ elCover = document.getElementById('sg-cover');
+
+function _parents(element, selector, cb) {
+ var target = element.parentNode;
+
+ while (target && target !== document.documentElement) {
+ if (target.matches(selector)) {
+ cb(target);
+ }
+ target = target.parentNode;
+ }
+}
+
+function _siblings(element, selector, cb) {
+ var target = element.parentNode.children[0];
+
+ while (target) {
+ if (target.matches(selector)) {
+ cb(target);
+ }
+ target = target.nextSibling;
+ }
}
-$('#sg-vp-wrap').click(function(e) {
-
- closePanels();
-
-});
-
-// watch the iframe source so that it can be sent back to everyone else.
-// based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
-function receiveIframeMessage(event) {
-
- // does the origin sending the message match the current host? if not dev/null the request
- if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) {
- return;
- }
-
- if (event.data.bodyclick != undefined) {
-
- closePanels();
-
- } else if (event.data.patternpartial != undefined) {
-
- if (!urlHandler.skipBack) {
-
- if ((history.state == null) || (history.state.pattern != event.data.patternpartial)) {
- urlHandler.pushPattern(event.data.patternpartial, event.data.path);
- }
-
- if (wsnConnected) {
- var iFramePath = urlHandler.getFileName(event.data.patternpartial);
- wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+event.data.patternpartial+'" }' );
- }
-
- }
-
- // for testing purposes
- console.log(event.data.lineage);
-
- // reset the defaults
- urlHandler.skipBack = false;
-
- }
-
+function _toggleUL(e) {
+ e.preventDefault();
+ var target = e.target.parentNode;
+
+ _parents(target, 'ul', function (el) {
+ el.classList.toggle('active');
+ });
+}
+
+function _size(num) {
+ gui.killDisco();
+ gui.killHay();
+ gui.sizeiframe(num);
}
-window.addEventListener("message", receiveIframeMessage, false);
\ No newline at end of file
+
+delegator
+ // handles widening the "viewport"
+ // 1. on "mousedown" store the click location
+ // 2. make a hidden div visible so that it can track mouse movements and make sure the pointer doesn't get lost in the iframe
+ // 3. on "mousemove" calculate the math, save the results to a cookie, and update the viewport
+ .on('mousedown', '#sg-rightpull', function (e) {
+ // capture default data
+ var origClientX = e.clientX,
+ origViewportWidth = elViewport.offsetWidth;
+
+ // show the cover
+ elCover.style.display = 'block';
+
+ // add the mouse move event and capture data. also update the viewport width
+ delegator.on('mousemove', '#sg-cover', function (e) {
+ var viewportWidth = (origClientX > e.clientX) ?
+ origViewportWidth - ((origClientX - e.clientX) * 2) :
+ origViewportWidth + ((e.clientX - origClientX) * 2);
+
+ if (viewportWidth > config.minViewportWidth) {
+ if (!dataSaver.findValue('vpWidth')) {
+ dataSaver.addValue('vpWidth', viewportWidth);
+ } else {
+ dataSaver.updateValue('vpWidth', viewportWidth);
+ }
+
+ gui.sizeiframe(viewportWidth, false);
+ }
+ });
+ })
+
+ // on "mouseup" we unbind the "mousemove" event and hide the cover again
+ .on('mouseup', 'body', function () {
+ delegator.off('mousemove', '#sg-cover');
+ elCover.style.display = 'none';
+ })
+
+ /* Pattern Lab accordion dropdown */
+ .on('click', '.sg-acc-handle', function (e) {
+ var next = e.target;
+
+ while (next && (next.nodeType !== 1 || !next.matches('.sg-acc-panel'))) {
+ next = next.nextSibling;
+ }
+
+ e.preventDefault();
+
+ e.target.classList.toggle('active');
+ if (next) {
+ next.classList.toggle('active');
+ }
+ })
+
+ .on('click', '.sg-nav-toggle', function (e) {
+ e.preventDefault();
+ document.querySelector('.sg-nav-container').classList.toggle('active');
+ })
+
+ //View (containing clean, code, raw, etc options) Trigger
+ .on('click', '#sg-t-toggle', _toggleUL)
+
+ //Size Trigger
+ .on('click', '#sg-size-toggle', _toggleUL)
+
+ //Phase View Events
+ .on('click', '.sg-size[data-size]', function (e) {
+ e.preventDefault();
+ gui.killDisco();
+ gui.killHay();
+
+ var val = e.target.getAttribute('data-size');
+
+ if (val.indexOf('px') > -1) {
+ config.bodySize = 1;
+ }
+
+ val = val.replace(/[^\d.\-]/g, '');
+ gui.sizeiframe(Math.floor(val * config.bodySize));
+ })
+
+ //Size View Events
+
+ //Click Size Small Button
+ .on('click', '#sg-size-s', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(config.minViewportWidth, 500));
+ })
+
+ //Click Size Medium Button
+ .on('click', '#sg-size-m', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(500, 800));
+ })
+
+ //Click Size Large Button
+ .on('click', '#sg-size-l', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(800, 1200));
+ })
+
+ //Click Full Width Button
+ .on('click', '#sg-size-full', function (e) { //Resets
+ e.preventDefault();
+ _size(config.sw);
+ })
+
+ //Click Random Size Button
+ .on('click', '#sg-size-random', function (e) {
+ e.preventDefault();
+ _size(gui.getRandom(config.minViewportWidth, config.sw));
+ })
+
+ //Click for Disco Mode, which resizes the viewport randomly
+ .on('click', '#sg-size-disco', function (e) {
+ e.preventDefault();
+ gui.killHay();
+ gui.toggleDisco();
+ })
+
+ //Stephen Hay Mode - "Start with the small screen first, then expand until it looks like shit. Time for a breakpoint!"
+ .on('click', '#sg-size-hay', function (e) {
+ e.preventDefault();
+ gui.killDisco();
+ gui.toggleHay();
+ })
+
+ //Pixel input
+ .on('keydown', '.sg-size-px', function (e) {
+ var val = parseInt(e.target.value, 10);
+
+ if (e.keyCode === 38) { //If the up arrow key is hit
+ val++;
+ gui.sizeiframe(val, false);
+ } else if (e.keyCode === 40) { //If the down arrow key is hit
+ val--;
+ gui.sizeiframe(val, false);
+ } else if (e.keyCode === 13) { //If the Enter key is hit
+ e.preventDefault();
+ gui.sizeiframe(val); //Size Iframe to value of text box
+ e.target.blur();
+ }
+ })
+
+ .on('keyup', '.sg-size-px', function (e) {
+ var val = parseInt(e.target.value, 10);
+ gui.updateSizeReading(val, 'px', 'updateEmInput');
+ })
+
+ //Em input
+ .on('keydown', '.sg-size-em', function (e) {
+ var val = parseFloat(e.target.value);
+
+ if (e.keyCode === 38) { //If the up arrow key is hit
+ val++;
+ gui.sizeiframe(Math.floor(val * config.bodySize), false);
+ } else if (e.keyCode === 40) { //If the down arrow key is hit
+ val--;
+ gui.sizeiframe(Math.floor(val * config.bodySize), false);
+ } else if (e.keyCode === 13) { //If the Enter key is hit
+ e.preventDefault();
+ gui.sizeiframe(Math.floor(val * config.bodySize)); //Size Iframe to value of text box
+ }
+ })
+
+ .on('keyup', '.sg-size-em', function (e) {
+ var val = parseFloat(e.target.value);
+ gui.updateSizeReading(val, 'em', 'updatePxInput');
+ })
+
+ // handle the MQ click
+ .on('click', '#sg-mq a', function (e) {
+ e.preventDefault();
+ var val = e.target.innerHTML,
+ type = parseInt((val.indexOf('px') !== -1 ? 'px' : 'em'), 10);
+
+ val = val.replace(type, '');
+
+ gui.sizeiframe((type === 'px' ? val : val * config.bodySize), true);
+ })
+
+ // update the iframe with the source from clicked element in pull down menu. also close the menu
+ // having it outside fixes an auto-close bug i ran into
+ .on('click', '.sg-nav a', function (e) {
+ if (e.target.matches('.sg-acc-handle')) {
+ return;
+ }
+ e.preventDefault();
+
+ // update the iframe via the history api handler
+ document.getElementById('sg-viewport').contentWindow.postMessage(
+ {
+ 'path': urlHandler.getFileName(e.target.getAttribute('data-patternpartial'))
+ },
+ urlHandler.targetOrigin
+ );
+
+ // close up the menu
+ _parents(e.target, '.sg-acc-panel', function (el) {
+ el.classList.toggle('active');
+ _siblings(el, '.sg-acc-handle', function (el) {
+ el.classList.toggle('active');
+ });
+ });
+ return false;
+ })
+
+ .on('click', '#sg-vp-wrap', function () {
+ gui.closePanels();
+ });
+
+window.addEventListener('resize', function () {
+ config.sw = document.body.clientWidth;
+ config.sh = document.body.clientHeight;
+}, false);
+
+window.addEventListener('message', function receiveIframeMessage(event) {
+ // does the origin sending the message match the current host? if not dev/null the request
+ if ((window.location.protocol !== 'file:') && (event.origin !== window.location.protocol + '//' + window.location.host)) {
+ return;
+ }
+
+ if (event.data.bodyclick !== undefined) {
+ gui.closePanels();
+ } else if (event.data.patternpartial !== undefined) {
+ if (!urlHandler.skipBack) {
+ if (window.history.state === null || window.history.state.pattern !== event.data.patternpartial) {
+ urlHandler.pushPattern(event.data.patternpartial, event.data.path);
+ }
+ if (window.wsnConnected) {
+ console.log('wsn');
+ var iFramePath = urlHandler.getFileName(event.data.patternpartial);
+ window.wsn.send('{"url": "' + iFramePath + '", "patternpartial": "' + event.data.patternpartial + '" }');
+ }
+ }
+
+ // for testing purposes
+ //console.log(event.data.lineage);
+
+ // reset the defaults
+ urlHandler.skipBack = false;
+ }
+}, false);
+},{"./config":"/Users/tor/projects/patternlab-node/public/styleguide/js/config.js","./data-saver":"/Users/tor/projects/patternlab-node/public/styleguide/js/data-saver.js","./eventDelegator/eventDelegator":"/Users/tor/projects/patternlab-node/public/styleguide/js/eventDelegator/eventDelegator.js","./gui":"/Users/tor/projects/patternlab-node/public/styleguide/js/gui.js","./url-handler":"/Users/tor/projects/patternlab-node/public/styleguide/js/url-handler.js"}],"/Users/tor/projects/patternlab-node/public/styleguide/js/main.js":[function(require,module,exports){
+var gui = require('./gui');
+
+require('./handlers');
+
+gui.init();
+},{"./gui":"/Users/tor/projects/patternlab-node/public/styleguide/js/gui.js","./handlers":"/Users/tor/projects/patternlab-node/public/styleguide/js/handlers.js"}],"/Users/tor/projects/patternlab-node/public/styleguide/js/url-handler.js":[function(require,module,exports){
+/*!
+ * URL Handler - v0.1
+ *
+ * Copyright (c) 2013 Dave Olsen, http://dmolsen.com
+ * Licensed under the MIT license
+ *
+ * Helps handle the initial iFrame source. Parses a string to see if it matches
+ * an expected pattern in Pattern Lab. Supports Pattern Labs fuzzy pattern partial
+ * matching style.
+ *
+ */
+
+var urlHandler = {
+
+ // set-up some default vars
+ skipBack: false,
+ targetOrigin: (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host,
+
+ /**
+ * get the real file name for a given pattern name
+ * @param {String} the shorthand partials syntax for a given pattern
+ *
+ * @return {String} the real file path
+ */
+ getFileName: function (name) {
+
+ var baseDir = "patterns";
+ var fileName = "";
+
+ if (name == undefined) {
+ return fileName;
+ }
+
+ if (name == "all") {
+ return "styleguide/html/styleguide.html";
+ }
+
+ var paths = (name.indexOf("viewall-") != -1) ? viewAllPaths : patternPaths;
+ nameClean = name.replace("viewall-","");
+
+ // look at this as a regular pattern
+ var bits = this.getPatternInfo(nameClean, paths);
+ var patternType = bits[0];
+ var pattern = bits[1];
+
+ if ((paths[patternType] != undefined) && (paths[patternType][pattern] != undefined)) {
+
+ fileName = paths[patternType][pattern];
+
+ } else if (paths[patternType] != undefined) {
+
+ for (patternMatchKey in paths[patternType]) {
+ if (patternMatchKey.indexOf(pattern) != -1) {
+ fileName = paths[patternType][patternMatchKey];
+ break;
+ }
+ }
+
+ }
+
+ if (fileName == "") {
+ return fileName;
+ }
+
+ var regex = /\//g;
+ if ((name.indexOf("viewall-") != -1) && (fileName != "")) {
+ fileName = baseDir+"/"+fileName.replace(regex,"-")+"/index.html";
+ } else if (fileName != "") {
+ fileName = baseDir+"/"+fileName.replace(regex,"-")+"/"+fileName.replace(regex,"-")+".html";
+ }
+
+ return fileName;
+ },
+
+ /**
+ * break up a pattern into its parts, pattern type and pattern name
+ * @param {String} the shorthand partials syntax for a given pattern
+ * @param {Object} the paths to be compared
+ *
+ * @return {Array} the pattern type and pattern name
+ */
+ getPatternInfo: function (name, paths) {
+ var patternBits = name.split("-");
+
+ var i = 1;
+ var c = patternBits.length;
+
+ var patternType = patternBits[0];
+ while ((paths[patternType] == undefined) && (i < c)) {
+ patternType += "-"+patternBits[i];
+ i++;
+ }
+
+ pattern = name.slice(patternType.length+1,name.length);
+
+ return [patternType, pattern];
+
+ },
+
+ /**
+ * search the request vars for a particular item
+ *
+ * @return {Object} a search of the window.location.search vars
+ */
+ getRequestVars: function() {
+
+ // the following is taken from https://developer.mozilla.org/en-US/docs/Web/API/window.location
+ var oGetVars = new (function (sSearch) {
+ if (sSearch.length > 1) {
+ for (var aItKey, nKeyId = 0, aCouples = sSearch.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+ aItKey = aCouples[nKeyId].split("=");
+ this[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : "";
+ }
+ }
+ })(window.location.search);
+
+ return oGetVars;
+
+ },
+
+ /**
+ * push a pattern onto the current history based on a click
+ * @param {String} the shorthand partials syntax for a given pattern
+ * @param {String} the path given by the loaded iframe
+ */
+ pushPattern: function (pattern, givenPath) {
+ var data = { "pattern": pattern };
+ var fileName = urlHandler.getFileName(pattern);
+ var expectedPath = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("public/index.html","public/")+fileName;
+ if (givenPath != expectedPath) {
+ // make sure to update the iframe because there was a click
+ document.getElementById("sg-viewport").contentWindow.postMessage( { "path": fileName }, urlHandler.targetOrigin);
+ } else {
+ // add to the history
+ var addressReplacement = (window.location.protocol == "file:") ? null : window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+"?p="+pattern;
+ history.pushState(data, null, addressReplacement);
+ document.getElementById("title").innerHTML = "Pattern Lab - "+pattern;
+ document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(pattern));
+ }
+ },
+
+ /**
+ * based on a click forward or backward modify the url and iframe source
+ * @param {Object} event info like state and properties set in pushState()
+ */
+ popPattern: function (e) {
+
+ var state = e.state;
+
+ if (state == null) {
+ this.skipBack = false;
+ return;
+ } else if (state != null) {
+ var patternName = state.pattern;
+ }
+
+ var iFramePath = "";
+ iFramePath = this.getFileName(patternName);
+ if (iFramePath == "") {
+ iFramePath = "styleguide/html/styleguide.html";
+ }
+
+ document.getElementById("sg-viewport").contentWindow.postMessage( { "path": iFramePath }, urlHandler.targetOrigin);
+ document.getElementById("title").innerHTML = "Pattern Lab - "+patternName;
+ document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(patternName));
+
+ if (wsnConnected) {
+ wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+patternName+'" }' );
+ }
+
+ }
+
+}
+
+/**
+* handle the onpopstate event
+*/
+window.onpopstate = function (event) {
+ urlHandler.skipBack = true;
+ urlHandler.popPattern(event);
+}
+
+module.exports = window.urlHandler = urlHandler;
+},{}]},{},["/Users/tor/projects/patternlab-node/public/styleguide/js/main.js"])
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy93YXRjaGlmeS9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiL1VzZXJzL3Rvci9wcm9qZWN0cy9wYXR0ZXJubGFiLW5vZGUvcHVibGljL3N0eWxlZ3VpZGUvanMvY29uZmlnLmpzIiwiL1VzZXJzL3Rvci9wcm9qZWN0cy9wYXR0ZXJubGFiLW5vZGUvcHVibGljL3N0eWxlZ3VpZGUvanMvY29va2llLmpzIiwiL1VzZXJzL3Rvci9wcm9qZWN0cy9wYXR0ZXJubGFiLW5vZGUvcHVibGljL3N0eWxlZ3VpZGUvanMvZGF0YS1zYXZlci5qcyIsIi9Vc2Vycy90b3IvcHJvamVjdHMvcGF0dGVybmxhYi1ub2RlL3B1YmxpYy9zdHlsZWd1aWRlL2pzL2V2ZW50RGVsZWdhdG9yL2V2ZW50RGVsZWdhdG9yLmpzIiwiL1VzZXJzL3Rvci9wcm9qZWN0cy9wYXR0ZXJubGFiLW5vZGUvcHVibGljL3N0eWxlZ3VpZGUvanMvZXZlbnREZWxlZ2F0b3IvbWF0Y2hlcy5qcyIsIi9Vc2Vycy90b3IvcHJvamVjdHMvcGF0dGVybmxhYi1ub2RlL3B1YmxpYy9zdHlsZWd1aWRlL2pzL2V2ZW50RGVsZWdhdG9yL3dlYWtNYXBTZXQuanMiLCIvVXNlcnMvdG9yL3Byb2plY3RzL3BhdHRlcm5sYWItbm9kZS9wdWJsaWMvc3R5bGVndWlkZS9qcy9ndWkuanMiLCIvVXNlcnMvdG9yL3Byb2plY3RzL3BhdHRlcm5sYWItbm9kZS9wdWJsaWMvc3R5bGVndWlkZS9qcy9oYW5kbGVycy5qcyIsIi9Vc2Vycy90b3IvcHJvamVjdHMvcGF0dGVybmxhYi1ub2RlL3B1YmxpYy9zdHlsZWd1aWRlL2pzL21haW4uanMiLCIvVXNlcnMvdG9yL3Byb2plY3RzL3BhdHRlcm5sYWItbm9kZS9wdWJsaWMvc3R5bGVndWlkZS9qcy91cmwtaGFuZGxlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtaW5WaWV3cG9ydFdpZHRoICAgICAgICAgICAgOiAyNDAsIC8vTWluaW11bSBTaXplIGZvciBWaWV3cG9ydFxuICAgIG1heFZpZXdwb3J0V2lkdGggICAgICAgICAgICA6IDI2MDAsIC8vTWF4aXVtdW0gU2l6ZSBmb3IgVmlld3BvcnRcbiAgICB2aWV3cG9ydFJlc2l6ZUhhbmRsZVdpZHRoICAgOiAxNCwgLy9XaWR0aCBvZiB0aGUgdmlld3BvcnQgZHJhZy10by1yZXNpemUgaGFuZGxlXG4gICAgYm9keVNpemUgICAgICAgICAgICAgICAgICAgIDogcGFyc2VJbnQod2luZG93LmdldENvbXB1dGVkU3R5bGUoZG9jdW1lbnQuYm9keSkuZ2V0UHJvcGVydHlWYWx1ZSgnZm9udC1zaXplJykpLFxuICAgIHN3ICAgICAgICAgICAgICAgICAgICAgICAgICA6IGRvY3VtZW50LmJvZHkuY2xpZW50V2lkdGgsIC8vVmlld3BvcnQgV2lkdGhcbiAgICBzaCAgICAgICAgICAgICAgICAgICAgICAgICAgOiBkb2N1bWVudC5ib2R5LmNsaWVudEhlaWdodCAvL1ZpZXdwb3J0IEhlaWdodFxufSIsIi8qanNsaW50IGluZGVudDogNCovXG4vKmdsb2JhbCB3aW5kb3cqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgcGx1c2VzID0gL1xcKy9nO1xuXG5mdW5jdGlvbiByYXcocykge1xuICAgIHJldHVybiBzO1xufVxuXG5mdW5jdGlvbiBkZWNvZGVkKHMpIHtcbiAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KHMucmVwbGFjZShwbHVzZXMsICcgJykpO1xufVxuXG5mdW5jdGlvbiBDb29raWUob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHzCoHt9O1xufVxuXG5Db29raWUucHJvdG90eXBlLndyaXRlID0gZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICB2YXIgYztcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fMKge307XG5cbiAgICBPYmplY3Qua2V5cyh0aGlzLm9wdGlvbnMpLmV2ZXJ5KGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgaWYgKCFvcHRpb25zLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHRoaXMub3B0aW9uc1trZXldO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0pO1xuXG4gICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgIG9wdGlvbnMuZXhwaXJlcyA9IC0xO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5leHBpcmVzID09PSAnbnVtYmVyJykge1xuICAgICAgICB2YXIgZGF5cyAgICA9IG9wdGlvbnMuZXhwaXJlcyxcbiAgICAgICAgICAgIHQ7XG5cbiAgICAgICAgdCA9IG9wdGlvbnMuZXhwaXJlcyA9IG5ldyBEYXRlKCk7XG4gICAgICAgIHQuc2V0RGF0ZSh0LmdldERhdGUoKSArIGRheXMpO1xuICAgIH1cblxuICAgIHZhbHVlID0gb3B0aW9ucy5qc29uID8gSlNPTi5zdHJpbmdpZnkodmFsdWUpIDogU3RyaW5nKHZhbHVlKTtcblxuICAgIGMgPSBbXG4gICAgICAgIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLCAnPScsIG9wdGlvbnMucmF3ID8gdmFsdWUgOiBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpLFxuICAgICAgICBvcHRpb25zLmV4cGlyZXMgPyAnOyBleHBpcmVzPScgKyBvcHRpb25zLmV4cGlyZXMudG9VVENTdHJpbmcoKSA6ICcnLCAvLyB1c2UgZXhwaXJlcyBhdHRyaWJ1dGUsIG1heC1hZ2UgaXMgbm90IHN1cHBvcnRlZCBieSBJRVxuICAgICAgICBvcHRpb25zLnBhdGggICAgPyAnOyBwYXRoPScgKyBvcHRpb25zLnBhdGggOiAnJyxcbiAgICAgICAgb3B0aW9ucy5kb21haW4gID8gJzsgZG9tYWluPScgKyBvcHRpb25zLmRvbWFpbiA6ICcnLFxuICAgICAgICBvcHRpb25zLnNlY3VyZSAgPyAnOyBzZWN1cmUnIDogJydcbiAgICBdLmpvaW4oJycpO1xuICAgIGRvY3VtZW50LmNvb2tpZSA9IGM7XG4gICAgcmV0dXJuIGM7XG59O1xuXG5Db29raWUucHJvdG90eXBlLnJlYWQgPSBmdW5jdGlvbiAoa2V5KSB7XG4gICAgLy8gcmVhZFxuICAgIHZhciBkZWNvZGUgID0gdGhpcy5vcHRpb25zLnJhdyA/IHJhdyA6IGRlY29kZWQsXG4gICAgICAgIGNvb2tpZXMgPSBkb2N1bWVudC5jb29raWUuc3BsaXQoJzsgJyksXG4gICAgICAgIGksXG4gICAgICAgIGwsXG4gICAgICAgIHBhcnRzLFxuICAgICAgICBjb29raWU7XG5cbiAgICBmb3IgKGkgPSAwLCBsID0gY29va2llcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgcGFydHMgPSBjb29raWVzW2ldLnNwbGl0KCc9Jyk7XG4gICAgICAgIGlmIChkZWNvZGUocGFydHMuc2hpZnQoKSkgPT09IGtleSkge1xuICAgICAgICAgICAgY29va2llID0gZGVjb2RlKHBhcnRzLmpvaW4oJz0nKSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcHRpb25zLmpzb24gPyBKU09OLnBhcnNlKGNvb2tpZSkgOiBjb29raWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbn07XG5cbkNvb2tpZS5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgIGlmICh0aGlzLnJlYWQoa2V5KSAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLndyaXRlKGtleSwgbnVsbCwgb3B0aW9ucyk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENvb2tpZTsiLCIvKmpzbGludCBpbmRlbnQ6IDQqL1xuLypnbG9iYWwgd2luZG93Ki9cbid1c2Ugc3RyaWN0JztcbnZhciBDb29raWUgPSByZXF1aXJlKCcuL2Nvb2tpZScpLFxuICAgIGNvb2tpZSA9IG5ldyBDb29raWUoKTtcblxuLyohXG4gKiBEYXRhIFNhdmVyIC0gdjAuMVxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMyBEYXZlIE9sc2VuLCBodHRwOi8vZG1vbHNlbi5jb21cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZVxuICovXG5cbnZhciBEYXRhU2F2ZXIgPSB7XG5cbiAgICAvLyB0aGUgbmFtZSBvZiB0aGUgY29va2llIHRvIHN0b3JlIHRoZSBkYXRhIGluXG4gICAgY29va2llTmFtZTogXCJwYXR0ZXJubGFiXCIsXG5cbiAgICAvKipcbiAgICAqIEFkZCBhIGdpdmVuIHZhbHVlIHRvIHRoZSBjb29raWVcbiAgICAqIEBwYXJhbSAge1N0cmluZ30gICAgICAgdGhlIG5hbWUgb2YgdGhlIGtleVxuICAgICogQHBhcmFtICB7U3RyaW5nfSAgICAgICB0aGUgdmFsdWVcbiAgICAqL1xuICAgIGFkZFZhbHVlOiBmdW5jdGlvbiAobmFtZSwgdmFsKSB7XG4gICAgICAgIHZhciBjb29raWVWYWwgPSBjb29raWUucmVhZCh0aGlzLmNvb2tpZU5hbWUpO1xuICAgICAgICBpZiAoKGNvb2tpZVZhbCA9PT0gbnVsbCkgfHwgKGNvb2tpZVZhbCA9PT0gXCJcIikpIHtcbiAgICAgICAgICAgIGNvb2tpZVZhbCA9IG5hbWUgKyBcIn5cIiArIHZhbDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvb2tpZVZhbCA9IGNvb2tpZVZhbCArIFwifFwiICsgbmFtZSArIFwiflwiICsgdmFsO1xuICAgICAgICB9XG4gICAgICAgIGNvb2tpZS53cml0ZSh0aGlzLmNvb2tpZU5hbWUsIGNvb2tpZVZhbCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICogVXBkYXRlIGEgdmFsdWUgZm91bmQgaW4gdGhlIGNvb2tpZS4gSWYgdGhlIGtleSBkb2Vzbid0IGV4aXN0IGFkZCB0aGUgdmFsdWVcbiAgICAqIEBwYXJhbSAge1N0cmluZ30gICAgICAgdGhlIG5hbWUgb2YgdGhlIGtleVxuICAgICogQHBhcmFtICB7U3RyaW5nfSAgICAgICB0aGUgdmFsdWVcbiAgICAqL1xuICAgIHVwZGF0ZVZhbHVlOiBmdW5jdGlvbiAobmFtZSwgdmFsKSB7XG4gICAgICAgIGlmICh0aGlzLmZpbmRWYWx1ZShuYW1lKSkge1xuICAgICAgICAgICAgdmFyIHVwZGF0ZUNvb2tpZVZhbHMgPSBcIlwiLFxuICAgICAgICAgICAgICAgIGNvb2tpZVZhbHMgPSBjb29raWUucmVhZCh0aGlzLmNvb2tpZU5hbWUpLnNwbGl0KFwifFwiKSxcbiAgICAgICAgICAgICAgICBpLFxuICAgICAgICAgICAgICAgIGwsXG4gICAgICAgICAgICAgICAgZmllbGRWYWxzO1xuICAgICAgICAgICAgZm9yIChpID0gMCwgbCA9IGNvb2tpZVZhbHMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgZmllbGRWYWxzID0gY29va2llVmFsc1tpXS5zcGxpdChcIn5cIik7XG4gICAgICAgICAgICAgICAgaWYgKGZpZWxkVmFsc1swXSA9PT0gbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBmaWVsZFZhbHNbMV0gPSB2YWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChpID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVDb29raWVWYWxzICs9IFwifFwiICsgZmllbGRWYWxzWzBdICsgXCJ+XCIgKyBmaWVsZFZhbHNbMV07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlQ29va2llVmFscyArPSBmaWVsZFZhbHNbMF0gKyBcIn5cIiArIGZpZWxkVmFsc1sxXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb29raWUud3JpdGUodGhpcy5jb29raWVOYW1lLCB1cGRhdGVDb29raWVWYWxzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWRkVmFsdWUobmFtZSwgdmFsKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIFJlbW92ZSB0aGUgZ2l2ZW4ga2V5XG4gICAgKiBAcGFyYW0gIHtTdHJpbmd9ICAgICAgIHRoZSBuYW1lIG9mIHRoZSBrZXlcbiAgICAqL1xuICAgIHJlbW92ZVZhbHVlOiBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICB2YXIgdXBkYXRlQ29va2llVmFscyA9IFwiXCIsXG4gICAgICAgICAgICBjb29raWVWYWxzID0gY29va2llLnJlYWQodGhpcy5jb29raWVOYW1lKS5zcGxpdChcInxcIiksXG4gICAgICAgICAgICBrID0gMCxcbiAgICAgICAgICAgIGksXG4gICAgICAgICAgICBsLFxuICAgICAgICAgICAgZmllbGRWYWxzO1xuICAgICAgICBmb3IgKGkgPSAwLCBsID0gY29va2llVmFscy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIGZpZWxkVmFscyA9IGNvb2tpZVZhbHNbaV0uc3BsaXQoXCJ+XCIpO1xuICAgICAgICAgICAgaWYgKGZpZWxkVmFsc1swXSAhPT0gbmFtZSkge1xuICAgICAgICAgICAgICAgIGlmIChrID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZUNvb2tpZVZhbHMgKz0gZmllbGRWYWxzWzBdICsgXCJ+XCIgKyBmaWVsZFZhbHNbMV07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlQ29va2llVmFscyArPSBcInxcIiArIGZpZWxkVmFsc1swXSArIFwiflwiICsgZmllbGRWYWxzWzFdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBrKys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29va2llLndyaXRlKHRoaXMuY29va2llTmFtZSwgdXBkYXRlQ29va2llVmFscyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICogRmluZCB0aGUgdmFsdWUgdXNpbmcgdGhlIGdpdmVuIGtleVxuICAgICogQHBhcmFtICB7U3RyaW5nfSAgICAgICB0aGUgbmFtZSBvZiB0aGUga2V5XG4gICAgKlxuICAgICogQHJldHVybiB7U3RyaW5nfSAgICAgICB0aGUgdmFsdWUgb2YgdGhlIGtleSBvciBmYWxzZSBpZiB0aGUgdmFsdWUgaXNuJ3QgZm91bmRcbiAgICAqL1xuICAgIGZpbmRWYWx1ZTogZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgaWYgKGNvb2tpZS5yZWFkKHRoaXMuY29va2llTmFtZSkpIHtcbiAgICAgICAgICAgIHZhciBjb29raWVWYWxzID0gY29va2llLnJlYWQodGhpcy5jb29raWVOYW1lKS5zcGxpdChcInxcIiksXG4gICAgICAgICAgICAgICAgaSxcbiAgICAgICAgICAgICAgICBsLFxuICAgICAgICAgICAgICAgIGZpZWxkVmFscztcbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGwgPSBjb29raWVWYWxzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgIGZpZWxkVmFscyA9IGNvb2tpZVZhbHNbaV0uc3BsaXQoXCJ+XCIpO1xuICAgICAgICAgICAgICAgIGlmIChmaWVsZFZhbHNbMF0gPT09IG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZpZWxkVmFsc1sxXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRGF0YVNhdmVyOyIsIi8qanNsaW50IGluZGVudDogNCovXG4vKmdsb2JhbCB3aW5kb3cqL1xuJ3VzZSBzdHJpY3QnO1xudmFyIFdNICAgICAgICAgID0gcmVxdWlyZSgnLi93ZWFrTWFwU2V0JykuV2Vha01hcCxcbiAgICBkZWxlZ2F0b3JzICA9IG5ldyBXTSgpO1xuXG5yZXF1aXJlKCcuL21hdGNoZXMuanMnKTtcblxuZnVuY3Rpb24gRXZlbnREZWxlZ2F0b3IoZWxlbWVudCkge1xuICAgIHZhciBkZWxlZ2F0b3IgPSBkZWxlZ2F0b3JzLmdldChlbGVtZW50KTtcblxuICAgIGlmIChkZWxlZ2F0b3IpIHtcbiAgICAgICAgcmV0dXJuIGRlbGVnYXRvcjtcbiAgICB9XG5cbiAgICB0aGlzLmV2ZW50cyAgICAgPSB7fTtcbiAgICB0aGlzLmVsZW1lbnQgICAgPSBlbGVtZW50O1xuICAgIHRoaXMuaGFuZGxlcnMgICA9IHt9O1xuICAgIGRlbGVnYXRvcnMuc2V0KGVsZW1lbnQsIHRoaXMpO1xufVxuXG5FdmVudERlbGVnYXRvci5wcm90b3R5cGUuX21hdGNoID0gZnVuY3Rpb24gKHNlbGVjdG9ycywgZSkge1xuICAgIHZhciB0YXJnZXQgID0gZS50YXJnZXQsXG4gICAgICAgIHNlbGVjdG9yO1xuXG4gICAgZnVuY3Rpb24gX3J1bkNhbGxiYWNrKHNlbGVjdG9yKSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgbDtcbiAgICAgICAgZm9yIChpID0gMCwgbCA9IHNlbGVjdG9yc1tzZWxlY3Rvcl0ubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICBzZWxlY3RvcnNbc2VsZWN0b3JdW2ldKGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHdoaWxlICh0YXJnZXQgIT09IHRoaXMuZWxlbWVudCkge1xuICAgICAgICBmb3IgKHNlbGVjdG9yIGluIHNlbGVjdG9ycykge1xuICAgICAgICAgICAgaWYgKHNlbGVjdG9ycy5oYXNPd25Qcm9wZXJ0eShzZWxlY3RvcikgJiYgdGFyZ2V0Lm1hdGNoZXMoc2VsZWN0b3IpKSB7XG4gICAgICAgICAgICAgICAgX3J1bkNhbGxiYWNrKHNlbGVjdG9yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRhcmdldC5wYXJlbnROb2RlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGFyZ2V0ID0gdGFyZ2V0LnBhcmVudE5vZGU7XG4gICAgfVxufTtcblxuRXZlbnREZWxlZ2F0b3IucHJvdG90eXBlLm9uID0gZnVuY3Rpb24gKHR5cGUsIHNlbGVjdG9yLCBjYikge1xuICAgIC8vdG9kbyBzdXBwb3J0IGVsZW1lbnRzIGFzIHNlbGVjdG9yXG5cbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgZnVuY3Rpb24gaGFuZGxlcihlKSB7XG4gICAgICAgIF90aGlzLl9tYXRjaChfdGhpcy5ldmVudHNbdHlwZV0sIGUpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5ldmVudHNbdHlwZV0pIHtcbiAgICAgICAgdGhpcy5ldmVudHNbdHlwZV0gPSB7fTtcblxuICAgICAgICB0aGlzLmhhbmRsZXJzW3R5cGVdID0gaGFuZGxlcjtcbiAgICAgICAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlciwgZmFsc2UpO1xuICAgIH1cblxuICAgIHRoaXMuZXZlbnRzW3R5cGVdW3NlbGVjdG9yXSA9IHRoaXMuZXZlbnRzW3R5cGVdW3NlbGVjdG9yXSB8fMKgW107XG5cbiAgICBpZiAodGhpcy5ldmVudHNbdHlwZV1bc2VsZWN0b3JdLmluZGV4T2YoY2IpID09PSAtMSkge1xuICAgICAgICB0aGlzLmV2ZW50c1t0eXBlXVtzZWxlY3Rvcl0ucHVzaChjYik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnREZWxlZ2F0b3IucHJvdG90eXBlLm9mZiA9IGZ1bmN0aW9uICh0eXBlLCBzZWxlY3RvciwgY2IpIHtcbiAgICBpZiAodHlwZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIE9iamVjdC5rZXlzKHRoaXMuZXZlbnRzKS5ldmVyeShmdW5jdGlvbiAoZXZ0VHlwZSkge1xuICAgICAgICAgICAgdGhpcy5lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZ0VHlwZSwgdGhpcy5oYW5kbGVyc1tldnRUeXBlXSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZXZlbnRzID0ge307XG4gICAgfSBlbHNlIGlmIChzZWxlY3RvciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vcmVtb3ZlIGFsbCBvZiBvbmUgdHlwZVxuICAgICAgICBpZiAodGhpcy5ldmVudHNbdHlwZV0pIHtcbiAgICAgICAgICAgIHRoaXMuZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIHRoaXMuaGFuZGxlcnNbdHlwZV0pO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuZXZlbnRzW3R5cGVdO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuaGFuZGxlcnNbdHlwZV07XG4gICAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGNiID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgLy8gcmVtb3ZlIGFsbCBoYW5kbGVyc1xuICAgICAgICBpZiAodGhpcy5ldmVudHNbdHlwZV0gJiYgdGhpcy5ldmVudHNbdHlwZV1bc2VsZWN0b3JdKSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudHNbdHlwZV1bc2VsZWN0b3JdO1xuICAgICAgICAgICAgLy8gUmVtb3ZlIGV2ZW50bGlzdGVuZXIgaWYgbm8gc2VsZWN0b3JzIGFyZSBwcmVzZW50XG4gICAgICAgICAgICBpZiAoT2JqZWN0LmtleXModGhpcy5ldmVudHNbdHlwZV0pLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMub2ZmKHR5cGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gcmVtb3ZlIHNwZWNpZmljIGhhbmRsZXJcbiAgICAgICAgdmFyIGkgPSB0aGlzLmV2ZW50c1t0eXBlXVtzZWxlY3Rvcl0uaW5kZXhPZihjYik7XG5cbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLmV2ZW50c1t0eXBlXVtzZWxlY3Rvcl0uc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnREZWxlZ2F0b3IucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAnRXZlbnREZWxlZ2F0b3InO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudERlbGVnYXRvcjsiLCIvKmpzbGludCBpbmRlbnQ6IDQqL1xuLypnbG9iYWwgd2luZG93Ki9cbi8qKlxuICogUG9seWZpbGwgZm9yIEVsZW1lbnQubWF0Y2hlc1xuICoqL1xuZnVuY3Rpb24gYWRkUG9seWZpbGwoRWxlbWVudFByb3RvdHlwZSkge1xuICAgICd1c2Ugc3RyaWN0JztcblxuICAgIGlmIChFbGVtZW50UHJvdG90eXBlLm1hdGNoZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgRWxlbWVudFByb3RvdHlwZS5tYXRjaGVzID0gRWxlbWVudFByb3RvdHlwZS5tYXRjaGVzU2VsZWN0b3IgfHxcbiAgICAgICAgRWxlbWVudFByb3RvdHlwZS5tb3pNYXRjaGVzU2VsZWN0b3IgfHxcbiAgICAgICAgRWxlbWVudFByb3RvdHlwZS5tc01hdGNoZXNTZWxlY3RvciB8fFxuICAgICAgICBFbGVtZW50UHJvdG90eXBlLm9NYXRjaGVzU2VsZWN0b3IgfHxcbiAgICAgICAgRWxlbWVudFByb3RvdHlwZS53ZWJraXRNYXRjaGVzU2VsZWN0b3IgfHxcbiAgICAgICAgZnVuY3Rpb24gKHNlbGVjdG9yKSB7XG4gICAgICAgICAgICB2YXIgbm9kZSAgICA9IHRoaXMsXG4gICAgICAgICAgICAgICAgbm9kZXMgICA9IChub2RlLnBhcmVudE5vZGUgfHwgbm9kZS5kb2N1bWVudCkucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvciksXG4gICAgICAgICAgICAgICAgaSAgICAgICA9IC0xO1xuXG4gICAgICAgICAgICB3aGlsZSAobm9kZXNbaV0gJiYgbm9kZXNbaV0gIT09IG5vZGUpIHtcbiAgICAgICAgICAgICAgICArK2k7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiAhIW5vZGVzW2ldO1xuICAgICAgICB9O1xufVxuXG5pZiAobW9kdWxlICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBhZGRQb2x5ZmlsbDtcbn0gZWxzZSB7XG4gICAgYWRkUG9seWZpbGwod2luZG93LkVsZW1lbnQucHJvdG90eXBlKTtcbn0iLCIoZnVuY3Rpb24gKGdsb2JhbCl7XG5cIldlYWtNYXBcIiBpbiB0aGlzIHx8IChmdW5jdGlvbiAobW9kdWxlKSB7XCJ1c2Ugc3RyaWN0XCI7XG5cbiAgLy8hKEMpIFdlYlJlZmxlY3Rpb24gLSBNaXQgU3R5bGUgTGljZW5zZVxuICAvLyBzaXplIGFuZCBwZXJmb3JtYW5jZXMgb3JpZW50ZWQgcG9seWZpbGwgZm9yIEVTNlxuICAvLyBXZWFrTWFwLCBNYXAsIGFuZCBTZXRcbiAgLy8gY29tcGF0aWJsZSB3aXRoIG5vZGUuanMsIFJoaW5vLCBhbnkgYnJvd3NlclxuICAvLyBkb2VzIG5vdCBpbXBsZW1lbnQgZGVmYXVsdCB2YXVsZSBkdXJpbmcgd20uZ2V0KClcbiAgLy8gc2luY2UgRVMubmV4dCB3b24ndCBwcm9iYWJseSBkbyB0aGF0XG4gIC8vIHVzZSB3bS5oYXMobykgPyB3bS5nZXQobykgOiBkM2ZhdWx0OyBpbnN0ZWFkXG5cbiAgLy8gV2Vha01hcCh2b2lkKTpXZWFrTWFwXG4gIGZ1bmN0aW9uIFdlYWtNYXAoKSB7XG5cbiAgICAvLyBwcml2YXRlIHJlZmVyZW5jZXMgaG9sZGVyc1xuICAgIHZhclxuICAgICAga2V5cyA9IFtdLFxuICAgICAgdmFsdWVzID0gW11cbiAgICA7XG5cbiAgICAvLyByZXR1cm5zIGZyZXNobHkgbmV3IGNyZWF0ZWRcbiAgICAvLyBpbnN0YW5jZW9mIFdlYWtNYXAgaW4gYW55IGNhc2VcbiAgICByZXR1cm4gY3JlYXRlKFdlYWtNYXBQcm90b3R5cGUsIHtcbiAgICAgIC8vIFdlYWtNYXAjZGVsZXRlKGtleTp2b2lkKik6Ym9vbGVhblxuICAgICAgXCJkZWxldGVcIjoge3ZhbHVlOiBiaW5kLmNhbGwoc2hhcmVkRGVsLCBOVUxMLCBUUlVFLCBrZXlzLCB2YWx1ZXMpfSxcbiAgICAgIC8vOndhcyBXZWFrTWFwI2dldChrZXk6dm9pZCpbLCBkM2ZhdWx0OnZvaWQqXSk6dm9pZCpcbiAgICAgIC8vIFdlYWtNYXAjZ2V0KGtleTp2b2lkKik6dm9pZCpcbiAgICAgIGdldDogICAgICB7dmFsdWU6IGJpbmQuY2FsbChzaGFyZWRHZXQsIE5VTEwsIFRSVUUsIGtleXMsIHZhbHVlcyl9LFxuICAgICAgLy8gV2Vha01hcCNoYXMoa2V5OnZvaWQqKTpib29sZWFuXG4gICAgICBoYXM6ICAgICAge3ZhbHVlOiBiaW5kLmNhbGwoc2hhcmVkSGFzLCBOVUxMLCBUUlVFLCBrZXlzLCB2YWx1ZXMpfSxcbiAgICAgIC8vIFdlYWtNYXAjc2V0KGtleTp2b2lkKiwgdmFsdWU6dm9pZCopOnZvaWRcbiAgICAgIHNldDogICAgICB7dmFsdWU6IGJpbmQuY2FsbChzaGFyZWRTZXQsIE5VTEwsIFRSVUUsIGtleXMsIHZhbHVlcyl9XG4gICAgfSk7XG5cbiAgfVxuXG4gIC8vIE1hcCh2b2lkKTpNYXBcbiAgZnVuY3Rpb24gTWFwKCkge1xuXG4gICAgLy8gcHJpdmF0ZSByZWZlcmVuY2VzIGhvbGRlcnNcbiAgICB2YXJcbiAgICAgIGtleXMgPSBbXSxcbiAgICAgIHZhbHVlcyA9IFtdXG4gICAgO1xuXG4gICAgLy8gcmV0dXJucyBmcmVzaGx5IG5ldyBjcmVhdGVkXG4gICAgLy8gaW5zdGFuY2VvZiBXZWFrTWFwIGluIGFueSBjYXNlXG4gICAgcmV0dXJuIGNyZWF0ZShNYXBQcm90b3R5cGUsIHtcbiAgICAgIC8vIE1hcCNkZWxldGUoa2V5OnZvaWQqKTpib29sZWFuXG4gICAgICBcImRlbGV0ZVwiOiB7dmFsdWU6IGJpbmQuY2FsbChzaGFyZWREZWwsIE5VTEwsIEZBTFNFLCBrZXlzLCB2YWx1ZXMpfSxcbiAgICAgIC8vOndhcyBNYXAjZ2V0KGtleTp2b2lkKlssIGQzZmF1bHQ6dm9pZCpdKTp2b2lkKlxuICAgICAgLy8gTWFwI2dldChrZXk6dm9pZCopOnZvaWQqXG4gICAgICBnZXQ6ICAgICAge3ZhbHVlOiBiaW5kLmNhbGwoc2hhcmVkR2V0LCBOVUxMLCBGQUxTRSwga2V5cywgdmFsdWVzKX0sXG4gICAgICAvLyBNYXAjaGFzKGtleTp2b2lkKik6Ym9vbGVhblxuICAgICAgaGFzOiAgICAgIHt2YWx1ZTogYmluZC5jYWxsKHNoYXJlZEhhcywgTlVMTCwgRkFMU0UsIGtleXMsIHZhbHVlcyl9LFxuICAgICAgLy8gTWFwI3NldChrZXk6dm9pZCosIHZhbHVlOnZvaWQqKTp2b2lkXG4gICAgICBzZXQ6ICAgICAge3ZhbHVlOiBiaW5kLmNhbGwoc2hhcmVkU2V0LCBOVUxMLCBGQUxTRSwga2V5cywgdmFsdWVzKX1cbiAgICAgIC8qLFxuICAgICAgLy8gTWFwI3NpemUodm9pZCk6bnVtYmVyID09PSBNb3ppbGxhIG9ubHkgc28gZmFyXG4gICAgICBzaXplOiAgICAge3ZhbHVlOiBiaW5kLmNhbGwoc2hhcmVkU2l6ZSwgTlVMTCwga2V5cyl9LFxuICAgICAgLy8gTWFwI2tleXModm9pZCk6QXJyYXkgPT09IG5vdCBpbiBzcGVjc1xuICAgICAga2V5czogICAgIHt2YWx1ZTogYm91bmRTbGljZShrZXlzKX0sXG4gICAgICAvLyBNYXAjdmFsdWVzKHZvaWQpOkFycmF5ID09PSBub3QgaW4gc3BlY3NcbiAgICAgIHZhbHVlczogICB7dmFsdWU6IGJvdW5kU2xpY2UodmFsdWVzKX0sXG4gICAgICAvLyBNYXAjaXRlcmF0ZShjYWxsYmFjazpGdW5jdGlvbiwgY29udGV4dDp2b2lkKik6dm9pZCA9PT4gY2FsbGJhY2suY2FsbChjb250ZXh0LCBrZXksIHZhbHVlLCBpbmRleCkgPT09IG5vdCBpbiBzcGVjc1xuICAgICAgaXRlcmF0ZTogIHt2YWx1ZTogYmluZC5jYWxsKHNoYXJlZEl0ZXJhdGUsIE5VTEwsIEZBTFNFLCBrZXlzLCB2YWx1ZXMpfVxuICAgICAgLy8qL1xuICAgIH0pO1xuXG4gIH1cblxuICAvLyBTZXQodm9pZCk6U2V0XG4gIC8qKlxuICAgKiB0byBiZSByZWFsbHkgaG9uZXN0LCBJIHdvdWxkIHJhdGhlciBwb2xsdXRlIEFycmF5LnByb3RvdHlwZVxuICAgKiBpbiBvcmRlciB0byBoYXZlIFNldCBsaWtlIGJlaGF2aW9yXG4gICAqIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEFycmF5LnByb3RvdHlwZSwge1xuICAgKiAgIGFkZDoge3ZhbHVlOiBmdW5jdGlvbiBhZGQodmFsdWUpIHtcbiAgICogICAgIHJldHVybiAtMSA8IHRoaXMuaW5kZXhPZih2YWx1ZSkgJiYgISF0aGlzLnB1c2godmFsdWUpO1xuICAgKiAgIH19XG4gICAqICAgaGFzOiB7dmFsdWU6IGZ1bmN0aW9uIGhhcyh2YWx1ZSkge1xuICAgKiAgICAgcmV0dXJuIC0xIDwgdGhpcy5pbmRleE9mKHZhbHVlKTtcbiAgICogICB9fVxuICAgKiAgIGRlbGV0ZToge3ZhbHVlOiBmdW5jdGlvbiBkZWxldGUodmFsdWUpIHtcbiAgICogICAgIHZhciBpID0gdGhpcy5pbmRleE9mKHZhbHVlKTtcbiAgICogICAgIHJldHVybiAtMSA8IGkgJiYgISF0aGlzLnNwbGljZShpLCAxKTtcbiAgICogICB9fVxuICAgKiB9KTtcbiAgICogLi4uIGFueXdheSAuLi5cbiAgICovXG4gIGZ1bmN0aW9uIFNldCgpIHtcbiAgICB2YXJcbiAgICAgIGtleXMgPSBbXSwgIC8vIHBsYWNlaG9sZGVyIHVzZWQgc2ltcGx5IHRvIHJlY3ljbGUgZnVuY3Rpb25zXG4gICAgICB2YWx1ZXMgPSBbXSwvLyByZWFsIHN0b3JhZ2VcbiAgICAgIGhhcyA9IGJpbmQuY2FsbChzaGFyZWRIYXMsIE5VTEwsIEZBTFNFLCB2YWx1ZXMsIGtleXMpXG4gICAgO1xuICAgIHJldHVybiBjcmVhdGUoU2V0UHJvdG90eXBlLCB7XG4gICAgICAvLyBTZXQjZGVsZXRlKHZhbHVlOnZvaWQqKTpib29sZWFuXG4gICAgICBcImRlbGV0ZVwiOiB7dmFsdWU6IGJpbmQuY2FsbChzaGFyZWREZWwsIE5VTEwsIEZBTFNFLCB2YWx1ZXMsIGtleXMpfSxcbiAgICAgIC8vIFNldCNoYXModmFsdWU6dm9pZCopOmJvb2xlYW5cbiAgICAgIGhhczogICAgICB7dmFsdWU6IGhhc30sXG4gICAgICAvLyBTZXQjYWRkKHZhbHVlOnZvaWQqKTpib29sZWFuXG4gICAgICBhZGQ6ICAgICAge3ZhbHVlOiBiaW5kLmNhbGwoU2V0X2FkZCwgTlVMTCwgRkFMU0UsIGhhcywgdmFsdWVzKX1cbiAgICAgIC8qLFxuICAgICAgLy8gTWFwI3NpemUodm9pZCk6bnVtYmVyID09PSBNb3ppbGxhIG9ubHlcbiAgICAgIHNpemU6ICAgICB7dmFsdWU6IGJpbmQuY2FsbChzaGFyZWRTaXplLCBOVUxMLCB2YWx1ZXMpfSxcbiAgICAgIC8vIFNldCN2YWx1ZXModm9pZCk6QXJyYXkgPT09IG5vdCBpbiBzcGVjc1xuICAgICAgdmFsdWVzOiAgIHt2YWx1ZTogYm91bmRTbGljZSh2YWx1ZXMpfSxcbiAgICAgIC8vIFNldCNpdGVyYXRlKGNhbGxiYWNrOkZ1bmN0aW9uLCBjb250ZXh0OnZvaWQqKTp2b2lkID09PiBjYWxsYmFjay5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCkgPT09IG5vdCBpbiBzcGVjc1xuICAgICAgaXRlcmF0ZTogIHt2YWx1ZTogYmluZC5jYWxsKFNldF9pdGVyYXRlLCBOVUxMLCBGQUxTRSwgTlVMTCwgdmFsdWVzKX1cbiAgICAgIC8vKi9cbiAgICB9KTtcbiAgfVxuXG4gIC8vIGNvbW1vbiBzaGFyZWQgbWV0aG9kIHJlY3ljbGVkIGZvciBhbGwgc2hpbXMgdGhyb3VnaCBiaW5kXG4gIGZ1bmN0aW9uIHNoYXJlZERlbChvYmplY3RPbmx5LCBrZXlzLCB2YWx1ZXMsIGtleSkge1xuICAgIGlmIChzaGFyZWRIYXMob2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBrZXkpKSB7XG4gICAgICBrZXlzLnNwbGljZShpLCAxKTtcbiAgICAgIHZhbHVlcy5zcGxpY2UoaSwgMSk7XG4gICAgfVxuICAgIC8vIEF1cm9yYSBoZXJlIGRvZXMgaXQgd2hpbGUgQ2FuYXJ5IGRvZXNuJ3RcbiAgICByZXR1cm4gLTEgPCBpO1xuICB9XG5cbiAgZnVuY3Rpb24gc2hhcmVkR2V0KG9iamVjdE9ubHksIGtleXMsIHZhbHVlcywga2V5LyosIGQzZmF1bHQqLykge1xuICAgIHJldHVybiBzaGFyZWRIYXMob2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBrZXkpID8gdmFsdWVzW2ldIDogdW5kZWZpbmVkOyAvL2QzZmF1bHQ7XG4gIH1cblxuICBmdW5jdGlvbiBzaGFyZWRIYXMob2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBrZXkpIHtcbiAgICBpZiAob2JqZWN0T25seSAmJiBrZXkgIT09IE9iamVjdChrZXkpKSB7XG4gICAgICBjb25zb2xlLmxvZyhrZXkpO1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIm5vdCBhIG5vbi1udWxsIG9iamVjdFwiKTtcbiAgICB9XG4gICAgaSA9IGJldHRlckluZGV4T2YuY2FsbChrZXlzLCBrZXkpO1xuICAgIHJldHVybiAtMSA8IGk7XG4gIH1cblxuICBmdW5jdGlvbiBzaGFyZWRTZXQob2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBrZXksIHZhbHVlKSB7XG4gICAgLyogcmV0dXJuICovc2hhcmVkSGFzKG9iamVjdE9ubHksIGtleXMsIHZhbHVlcywga2V5KSA/XG4gICAgICB2YWx1ZXNbaV0gPSB2YWx1ZVxuICAgICAgOlxuICAgICAgdmFsdWVzW2tleXMucHVzaChrZXkpIC0gMV0gPSB2YWx1ZVxuICAgIDtcbiAgfVxuXG4gIC8qIGtleXMsIHZhbHVlcywgYW5kIGl0ZXJhdGUgcmVsYXRlZCBtZXRob2RzXG4gIGZ1bmN0aW9uIGJvdW5kU2xpY2UodmFsdWVzKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBzbGljZS5jYWxsKHZhbHVlcyk7XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNoYXJlZFNpemUoa2V5cykge1xuICAgIHJldHVybiBrZXlzLmxlbmd0aDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNoYXJlZEl0ZXJhdGUob2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBjYWxsYmFjaywgY29udGV4dCkge1xuICAgIGZvciAodmFyXG4gICAgICBrID0gc2xpY2UuY2FsbChrZXlzKSwgdiA9IHNsaWNlLmNhbGwodmFsdWVzKSxcbiAgICAgIGkgPSAwLCBsZW5ndGggPSBrLmxlbmd0aDtcbiAgICAgIGkgPCBsZW5ndGg7IGNhbGxiYWNrLmNhbGwoY29udGV4dCwga1tpXSwgdltpXSwgaSsrKVxuICAgICk7XG4gIH1cblxuICBmdW5jdGlvbiBTZXRfaXRlcmF0ZShvYmplY3RPbmx5LCBrZXlzLCB2YWx1ZXMsIGNhbGxiYWNrLCBjb250ZXh0KSB7XG4gICAgZm9yICh2YXJcbiAgICAgIHYgPSBzbGljZS5jYWxsKHZhbHVlcyksXG4gICAgICBpID0gMCwgbGVuZ3RoID0gdi5sZW5ndGg7XG4gICAgICBpIDwgbGVuZ3RoOyBjYWxsYmFjay5jYWxsKGNvbnRleHQsIHZbaV0sIGkrKylcbiAgICApO1xuICB9XG4gIC8vKi9cblxuICAvLyBTZXQjYWRkIHJlY3ljbGVkIHRocm91Z2ggYmluZCBwZXIgZWFjaCBpbnN0YW5jZW9mIFNldFxuICBmdW5jdGlvbiBTZXRfYWRkKG9iamVjdE9ubHksIGhhcywgdmFsdWVzLCB2YWx1ZSkge1xuICAgIC8qcmV0dXJuICovKCFoYXModmFsdWUpICYmICEhdmFsdWVzLnB1c2godmFsdWUpKTtcbiAgfVxuXG4gIC8vIGEgbW9yZSByZWxpYWJsZSBpbmRleE9mXG4gIGZ1bmN0aW9uIGJldHRlckluZGV4T2YodmFsdWUpIHtcbiAgICBpZiAodmFsdWUgIT0gdmFsdWUgfHwgdmFsdWUgPT09IDApIHtcbiAgICAgIGZvciAoaSA9IHRoaXMubGVuZ3RoOyBpLS0gJiYgIWlzKHRoaXNbaV0sIHZhbHVlKTspO1xuICAgIH0gZWxzZSB7XG4gICAgICBpID0gaW5kZXhPZi5jYWxsKHRoaXMsIHZhbHVlKTtcbiAgICB9XG4gICAgcmV0dXJuIGk7XG4gIH1cblxuICAvLyBuZWVkIGZvciBhbiBlbXB0eSBjb25zdHJ1Y3RvciAuLi5cbiAgZnVuY3Rpb24gQ29uc3RydWN0b3IoKXt9ICAvLyBHQydlZCBpZiAhIU9iamVjdC5jcmVhdGVcbiAgLy8gLi4uIHNvIHRoYXQgbmV3IFdlYWtNYXBJbnN0YW5jZSBhbmQgbmV3IFdlYWtNYXBcbiAgLy8gcHJvZHVjZXMgYm90aCBhbiBpbnN0YW5jZW9mIFdlYWtNYXBcblxuICB2YXJcbiAgICAvLyBzaG9ydGN1dHMgYW5kIC4uLlxuICAgIE5VTEwgPSBudWxsLCBUUlVFID0gdHJ1ZSwgRkFMU0UgPSBmYWxzZSxcbiAgICBub3RJbk5vZGUgPSBtb2R1bGUgPT0gXCJ1bmRlZmluZWRcIixcbiAgICB3aW5kb3cgPSBub3RJbk5vZGUgPyB0aGlzIDogZ2xvYmFsLFxuICAgIG1vZHVsZSA9IG5vdEluTm9kZSA/IHt9IDogZXhwb3J0cyxcbiAgICBPYmplY3QgPSB3aW5kb3cuT2JqZWN0LFxuICAgIFdlYWtNYXBQcm90b3R5cGUgPSBXZWFrTWFwLnByb3RvdHlwZSxcbiAgICBNYXBQcm90b3R5cGUgPSBNYXAucHJvdG90eXBlLFxuICAgIFNldFByb3RvdHlwZSA9IFNldC5wcm90b3R5cGUsXG4gICAgZGVmaW5lUHJvcGVydHkgPSBPYmplY3QuZGVmaW5lUHJvcGVydHksXG4gICAgc2xpY2UgPSBbXS5zbGljZSxcblxuICAgIC8vIE9iamVjdC5pcyhhLCBiKSBzaGltXG4gICAgaXMgPSBPYmplY3QuaXMgfHwgZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgIHJldHVybiBhID09PSBiID9cbiAgICAgICAgYSAhPT0gMCB8fCAxIC8gYSA9PSAxIC8gYiA6XG4gICAgICAgIGEgIT0gYSAmJiBiICE9IGJcbiAgICAgIDtcbiAgICB9LFxuXG4gICAgLy8gcGFydGlhbCBwb2x5ZmlsbCBmb3IgdGhpcyBhaW0gb25seVxuICAgIGJpbmQgPSBXZWFrTWFwLmJpbmQgfHwgZnVuY3Rpb24gYmluZChjb250ZXh0LCBvYmplY3RPbmx5LCBrZXlzLCB2YWx1ZXMpIHtcbiAgICAgIC8vIHBhcnRpYWwgZmFzdCBhZC1ob2MgRnVuY3Rpb24jYmluZCBwb2x5ZmlsbCBpZiBub3QgYXZhaWxhYmxlXG4gICAgICB2YXIgY2FsbGJhY2sgPSB0aGlzO1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIGJvdW5kKGtleSwgdmFsdWUpIHtcbiAgICAgICAgaWYgKCEha2V5ID09PSBmYWxzZSkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGFyZ3VtZW50cy5jYWxsZXIuY2FsbGVlKTtcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgb2JqZWN0T25seSwga2V5cywgdmFsdWVzLCBrZXksIHZhbHVlKTtcbiAgICAgIH07XG4gICAgfSxcblxuICAgIGNyZWF0ZSA9IE9iamVjdC5jcmVhdGUgfHwgZnVuY3Rpb24gY3JlYXRlKHByb3RvLCBkZXNjcmlwdG9yKSB7XG4gICAgICAvLyBwYXJ0aWFsIGFkLWhvYyBPYmplY3QuY3JlYXRlIHNoaW0gaWYgbm90IGF2YWlsYWJsZVxuICAgICAgQ29uc3RydWN0b3IucHJvdG90eXBlID0gcHJvdG87XG4gICAgICB2YXIgb2JqZWN0ID0gbmV3IENvbnN0cnVjdG9yKCksIGtleTtcbiAgICAgIGZvciAoa2V5IGluIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgb2JqZWN0W2tleV0gPSBkZXNjcmlwdG9yW2tleV0udmFsdWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gb2JqZWN0O1xuICAgIH0sXG5cbiAgICBpbmRleE9mID0gW10uaW5kZXhPZiB8fCBmdW5jdGlvbiBpbmRleE9mKHZhbHVlKSB7XG4gICAgICAvLyBwYXJ0aWFsIGZhc3QgQXJyYXkjaW5kZXhPZiBwb2x5ZmlsbCBpZiBub3QgYXZhaWxhYmxlXG4gICAgICBmb3IgKGkgPSB0aGlzLmxlbmd0aDsgaS0tICYmIHRoaXNbaV0gIT09IHZhbHVlOyk7XG4gICAgICByZXR1cm4gaTtcbiAgICB9LFxuXG4gICAgdW5kZWZpbmVkLFxuICAgIGkgLy8gcmVjeWNsZSBBTEwgdGhlIHZhcmlhYmxlcyAhXG4gIDtcblxuICAvLyB+aW5kZXhPZi5jYWxsKFtOYU5dLCBOYU4pIGFzIGZ1dHVyZSBwb3NzaWJsZSBmZWF0dXJlIGRldGVjdGlvblxuXG4gIC8vIHVzZWQgdG8gZm9sbG93IEZGIGJlaGF2aW9yIHdoZXJlIFdlYWtNYXAucHJvdG90eXBlIGlzIGEgV2Vha01hcCBpdHNlbGZcbiAgV2Vha01hcC5wcm90b3R5cGUgPSBXZWFrTWFwUHJvdG90eXBlID0gV2Vha01hcCgpO1xuICBNYXAucHJvdG90eXBlID0gTWFwUHJvdG90eXBlID0gTWFwKCk7XG4gIFNldC5wcm90b3R5cGUgPSBTZXRQcm90b3R5cGUgPSBTZXQoKTtcblxuICAvLyBhc3NpZ24gaXQgdG8gdGhlIGdsb2JhbCBjb250ZXh0XG4gIC8vIGlmIGFscmVhZHkgdGhlcmUsIGUuZy4gaW4gbm9kZSwgZXhwb3J0IG5hdGl2ZVxuICB3aW5kb3cuV2Vha01hcCA9IG1vZHVsZS5XZWFrTWFwID0gd2luZG93LldlYWtNYXAgfHwgV2Vha01hcDtcbiAgd2luZG93Lk1hcCA9IG1vZHVsZS5NYXAgPSB3aW5kb3cuTWFwIHx8IE1hcDtcbiAgd2luZG93LlNldCA9IG1vZHVsZS5TZXQgPSB3aW5kb3cuU2V0IHx8IFNldDtcblxuICAvKiBwcm9iYWJseSBub3QgbmVlZGVkLCBhZGQgYSBzbGFzaCB0byBlbnN1cmUgbm9uIGNvbmZpZ3VyYWJsZSBhbmQgbm9uIHdyaXRhYmxlXG4gIGlmIChkZWZpbmVQcm9wZXJ0eSkge1xuICAgIGRlZmluZVByb3BlcnR5KHdpbmRvdywgXCJXZWFrTWFwXCIsIHt2YWx1ZTogV2Vha01hcH0pO1xuICAgIGRlZmluZVByb3BlcnR5KHdpbmRvdywgXCJNYXBcIiwge3ZhbHVlOiBNYXB9KTtcbiAgICBkZWZpbmVQcm9wZXJ0eSh3aW5kb3csIFwiU2V0XCIsIHt2YWx1ZTogU2V0fSk7XG4gIH1cbiAgLy8qL1xuXG4gIC8vIHRoYXQncyBwcmV0dHkgbXVjaCBpdFxuXG59LmNhbGwoXG4gIHRoaXMsXG4gIHR5cGVvZiBleHBvcnRzXG4pKTtcbn0pLmNhbGwodGhpcyx0eXBlb2YgZ2xvYmFsICE9PSBcInVuZGVmaW5lZFwiID8gZ2xvYmFsIDogdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCIgPyBzZWxmIDogdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHt9KSIsIi8qanNsaW50IGluZGVudDogNCovXG4vKmdsb2JhbCB3aW5kb3cqL1xuJ3VzZSBzdHJpY3QnO1xudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJyksXG4gICAgZGF0YVNhdmVyID0gcmVxdWlyZSgnLi9kYXRhLXNhdmVyJyksXG4gICAgdXJsSGFuZGxlciA9IHJlcXVpcmUoJy4vdXJsLWhhbmRsZXInKSxcbiAgICBlbEdlbkNvbnRhaW5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy1nZW4tY29udGFpbmVyJyksXG4gICAgZWxWaWV3cG9ydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy12aWV3cG9ydCcpLFxuICAgIGVsU2l6ZVB4ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNnLXNpemUtcHgnKSwgLy9QeCBzaXplIGlucHV0IGVsZW1lbnQgaW4gdG9vbGJhclxuICAgIGVsU2l6ZUVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zZy1zaXplLWVtJyksIC8vRW0gc2l6ZSBpbnB1dCBlbGVtZW50IGluIHRvb2xiYXI7XG4gICAgZGlzY29JRCA9IGZhbHNlLFxuICAgIGRpc2NvTW9kZSA9IGZhbHNlLFxuICAgIGhheU1vZGUgPSBmYWxzZTtcblxuLy9VcGRhdGUgUGl4ZWwgYW5kIEVtIGlucHV0c1xuLy8nc2l6ZScgaXMgdGhlIGlucHV0IG51bWJlclxuLy8ndW5pdCcgaXMgdGhlIHR5cGUgb2YgdW5pdDogZWl0aGVyIHB4IG9yIGVtLiBEZWZhdWx0IGlzIHB4LiBBY2NlcHRlZCB2YWx1ZXMgYXJlICdweCcgYW5kICdlbSdcbi8vJ3RhcmdldCcgaXMgd2hhdCBpbnB1dHMgdG8gdXBkYXRlLiBEZWZhdWx0cyB0byBib3RoXG5mdW5jdGlvbiB1cGRhdGVTaXplUmVhZGluZyhzaXplLCB1bml0LCB0YXJnZXQpIHtcbiAgICB2YXIgZW1TaXplID0gKHVuaXQgPT09ICdlbScgPyBNYXRoLmZsb29yKHNpemUgKiBjb25maWcuYm9keVNpemUpIDogc2l6ZSksXG4gICAgICAgIHB4U2l6ZSA9ICh1bml0ID09PSAnZW0nID8gc2l6ZSAvIGNvbmZpZy5ib2R5U2l6ZSA6IHNpemUpO1xuXG4gICAgaWYgKHRhcmdldCA9PT0gJ3VwZGF0ZVB4SW5wdXQnKSB7XG4gICAgICAgIGVsU2l6ZVB4LnZhbHVlID0gcHhTaXplO1xuICAgIH0gZWxzZSBpZiAodGFyZ2V0ID09PSAndXBkYXRlRW1JbnB1dCcpIHtcbiAgICAgICAgZWxTaXplRW1zLnZhbHVlID0gZW1TaXplO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGVsU2l6ZUVtcy52YWx1ZSA9IGVtU2l6ZTtcbiAgICAgICAgZWxTaXplUHgudmFsdWUgPSBweFNpemU7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBzYXZlU2l6ZShzaXplKSB7XG4gICAgaWYgKCFkYXRhU2F2ZXIuZmluZFZhbHVlKCd2cFdpZHRoJykpIHtcbiAgICAgICAgZGF0YVNhdmVyLmFkZFZhbHVlKCd2cFdpZHRoJywgc2l6ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgZGF0YVNhdmVyLnVwZGF0ZVZhbHVlKCd2cFdpZHRoJywgc2l6ZSk7XG4gICAgfVxufVxuXG4vKiBSZXR1cm5zIGEgcmFuZG9tIG51bWJlciBiZXR3ZWVuIG1pbiBhbmQgbWF4ICovXG5mdW5jdGlvbiBnZXRSYW5kb20obWluLCBtYXgpIHtcbiAgICByZXR1cm4gTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4pICsgbWluO1xufVxuXG4vL1Jlc2l6ZSB0aGUgdmlld3BvcnRcbi8vJ3NpemUnIGlzIHRoZSB0YXJnZXQgc2l6ZSBvZiB0aGUgdmlld3BvcnRcbi8vJ2FuaW1hdGUnIGlzIGEgYm9vbGVhbiBmb3Igc3dpdGNoaW5nIHRoZSBDU1MgYW5pbWF0aW9uIG9uIG9yIG9mZi4gJ2FuaW1hdGUnIGlzIHRydWUgYnkgZGVmYXVsdCwgYnV0IGNhbiBiZSBzZXQgdG8gZmFsc2UgZm9yIHRoaW5ncyBsaWtlIG51ZGdpbmcgYW5kIGRyYWdnaW5nXG5mdW5jdGlvbiBzaXplaWZyYW1lKHNpemUsIGFuaW1hdGUpIHtcbiAgICB2YXIgdGhlU2l6ZTtcblxuICAgIGlmIChzaXplID4gY29uZmlnLm1heFZpZXdwb3J0V2lkdGgpIHsgLy9JZiB0aGUgZW50ZXJlZCBzaXplIGlzIGxhcmdlciB0aGFuIHRoZSBtYXggYWxsb3dlZCB2aWV3cG9ydCBzaXplLCBjYXAgdmFsdWUgYXQgbWF4IHZwIHNpemVcbiAgICAgICAgdGhlU2l6ZSA9IGNvbmZpZy5tYXhWaWV3cG9ydFdpZHRoO1xuICAgIH0gZWxzZSBpZiAoc2l6ZSA8IGNvbmZpZy5taW5WaWV3cG9ydFdpZHRoKSB7IC8vSWYgdGhlIGVudGVyZWQgc2l6ZSBpcyBsZXNzIHRoYW4gdGhlIG1pbmltdW0gYWxsb3dlZCB2aWV3cG9ydCBzaXplLCBjYXAgdmFsdWUgYXQgbWluIHZwIHNpemVcbiAgICAgICAgdGhlU2l6ZSA9IGNvbmZpZy5taW5WaWV3cG9ydFdpZHRoO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRoZVNpemUgPSBzaXplO1xuICAgIH1cblxuICAgIC8vQ29uZGl0aW9uYWxseSByZW1vdmUgQ1NTIGFuaW1hdGlvbiBjbGFzcyBmcm9tIHZpZXdwb3J0XG4gICAgZWxHZW5Db250YWluZXIuY2xhc3NMaXN0LnJlbW92ZSgndnAtYW5pbWF0ZScsIGFuaW1hdGUpO1xuICAgIGVsVmlld3BvcnQuY2xhc3NMaXN0LnJlbW92ZSgndnAtYW5pbWF0ZScsIGFuaW1hdGUpO1xuXG4gICAgZWxHZW5Db250YWluZXIuc3R5bGUud2lkdGggPSAodGhlU2l6ZSArIGNvbmZpZy52aWV3cG9ydFJlc2l6ZUhhbmRsZVdpZHRoKSArICdweCc7IC8vUmVzaXplIHZpZXdwb3J0IHdyYXBwZXIgdG8gZGVzaXJlZCBzaXplICsgc2l6ZSBvZiBkcmFnIHJlc2l6ZSBoYW5kbGVyXG4gICAgZWxWaWV3cG9ydC5zdHlsZS53aWR0aCA9IHRoZVNpemUgKyAncHgnOyAvL1Jlc2l6ZSB2aWV3cG9ydCB0byBkZXNpcmVkIHNpemVcblxuICAgIHVwZGF0ZVNpemVSZWFkaW5nKHRoZVNpemUpOyAvL1VwZGF0ZSB2YWx1ZXMgaW4gdG9vbGJhclxuICAgIHNhdmVTaXplKHRoZVNpemUpOyAvL1NhdmUgY3VycmVudCB2aWV3cG9ydCB0byBjb29raWVcbn1cblxuZnVuY3Rpb24gdXBkYXRlVmlld3BvcnRXaWR0aChzaXplKSB7XG4gICAgc2l6ZSA9IHBhcnNlSW50KHNpemUsIDEwKTtcbiAgICBlbFZpZXdwb3J0LnN0eWxlLndpZHRoID0gcGFyc2VJbnQoc2l6ZSwgMTApICsgJ3B4JztcbiAgICBlbEdlbkNvbnRhaW5lci5zdHlsZS53aWR0aCA9IChzaXplICsgMTQpICsgJ3B4JztcblxuICAgIHVwZGF0ZVNpemVSZWFkaW5nKHNpemUpO1xufVxuXG4vKiBEaXNjbyBNb2RlICovXG5mdW5jdGlvbiBkaXNjbygpIHtcbiAgICBzaXplaWZyYW1lKGdldFJhbmRvbShjb25maWcubWluVmlld3BvcnRXaWR0aCwgY29uZmlnLnN3KSk7XG59XG5cbmZ1bmN0aW9uIGtpbGxEaXNjbygpIHtcbiAgICBkaXNjb01vZGUgPSBmYWxzZTtcbiAgICBjbGVhckludGVydmFsKGRpc2NvSUQpO1xuICAgIGRpc2NvSUQgPSBmYWxzZTtcbn1cblxuZnVuY3Rpb24gc3RhcnREaXNjbygpIHtcbiAgICBkaXNjb01vZGUgPSB0cnVlO1xuICAgIGRpc2NvSUQgPSBzZXRJbnRlcnZhbChkaXNjbywgODAwKTtcbn1cblxuZnVuY3Rpb24gdG9nZ2xlRGlzY28oKSB7XG4gICAgaWYgKCFkaXNjb01vZGUpIHtcbiAgICAgICAgc3RhcnREaXNjbygpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGtpbGxEaXNjbygpO1xuICAgIH1cbn1cblxuLy9TdG9wIEhheSEgTW9kZVxuZnVuY3Rpb24ga2lsbEhheSgpIHtcbiAgICB2YXIgY3VycmVudFdpZHRoID0gZWxWaWV3cG9ydC5vZmZzZXRXaWR0aDtcbiAgICBoYXlNb2RlID0gZmFsc2U7XG4gICAgZWxWaWV3cG9ydC5jbGFzc0xpc3QucmVtb3ZlKCdoYXktbW9kZScpO1xuICAgIGVsR2VuQ29udGFpbmVyLmNsYXNzTGlzdC5yZW1vdmUoJ2hheS1tb2RlJyk7XG4gICAgc2l6ZWlmcmFtZShNYXRoLmZsb29yKGN1cnJlbnRXaWR0aCkpO1xufVxuXG4vLyBzdGFydCBIYXkhIG1vZGVcbmZ1bmN0aW9uIHN0YXJ0SGF5KCkge1xuICAgIGhheU1vZGUgPSB0cnVlO1xuICAgIGVsR2VuQ29udGFpbmVyLmNsYXNzTGlzdC5yZW1vdmUoJ3ZwLWFuaW1hdGUnKTtcbiAgICBlbEdlbkNvbnRhaW5lci5zdHlsZS53aWR0aCA9IChjb25maWcubWluVmlld3BvcnRXaWR0aCArIGNvbmZpZy52aWV3cG9ydFJlc2l6ZUhhbmRsZVdpZHRoKSArICdweCc7XG4gICAgZWxWaWV3cG9ydC5jbGFzc0xpc3QucmVtb3ZlKCd2cC1hbmltYXRlJyk7XG4gICAgZWxWaWV3cG9ydC5zdHlsZS53aWR0aCA9IGNvbmZpZy5taW5WaWV3cG9ydFdpZHRoICsgJ3B4JztcblxuICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZWxHZW5Db250YWluZXIuY2xhc3NMaXN0LmFkZCgnaGF5LW1vZGUnKTtcbiAgICAgICAgZWxHZW5Db250YWluZXIuc3R5bGUud2lkdGggPSAoY29uZmlnLm1heFZpZXdwb3J0V2lkdGggKyBjb25maWcudmlld3BvcnRSZXNpemVIYW5kbGVXaWR0aCkgKyAncHgnO1xuICAgICAgICBlbFZpZXdwb3J0LmNsYXNzTGlzdC5hZGQoJ2hheS1tb2RlJyk7XG4gICAgICAgIGVsVmlld3BvcnQuc3R5bGUud2lkdGggPSBjb25maWcubWF4Vmlld3BvcnRXaWR0aCArICdweCc7XG5cbiAgICAgICAgLy90b2RvIHRoaXMgaXMgbm90IHJlbW92ZWRcbiAgICAgICAgc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHZwU2l6ZSA9IGVsVmlld3BvcnQub2Zmc2V0V2lkdGg7XG4gICAgICAgICAgICB1cGRhdGVTaXplUmVhZGluZyh2cFNpemUpO1xuICAgICAgICB9LCAxMDApO1xuICAgIH0sIDIwMCk7XG59XG5cbmZ1bmN0aW9uIHRvZ2dsZUhheSgpIHtcbiAgICBpZiAoIWhheU1vZGUpIHtcbiAgICAgICAgc3RhcnRIYXkoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBraWxsSGF5KCk7XG4gICAgfVxufVxuXG4vLyBoYW5kbGUgd2hlbiBzb21lb25lIGNsaWNrcyBvbiB0aGUgZ3JleSBhcmVhIG9mIHRoZSB2aWV3cG9ydCBzbyBpdCBhdXRvLWNsb3NlcyB0aGUgbmF2XG5mdW5jdGlvbiBjbG9zZVBhbmVscygpIHtcbiAgICAvLyBjbG9zZSB1cCB0aGUgbWVudVxuICAgIHZhciBwYW5lbHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2ctYWNjLXBhbmVsJyksXG4gICAgICAgIGhhbmRsZXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2ctYWNjLWhhbmRsZScpO1xuXG4gICAgW10uZm9yRWFjaC5jYWxsKHBhbmVscywgZnVuY3Rpb24gKHBhbmVsKSB7XG4gICAgICAgIHBhbmVsLmNsYXNzTGlzdC5yZW1vdmUoJ2FjdGl2ZScpO1xuICAgIH0pO1xuXG5cbiAgICBbXS5mb3JFYWNoLmNhbGwoaGFuZGxlcywgZnVuY3Rpb24gKGhhbmRsZSkge1xuICAgICAgICBoYW5kbGUuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIGluaXQoKSB7XG4gICAgdmFyIG9yaWdWaWV3cG9ydFdpZHRoICAgPSBlbFZpZXdwb3J0Lm9mZnNldFdpZHRoLFxuICAgICAgICBvR2V0VmFycyAgICAgICAgICAgID0gdXJsSGFuZGxlci5nZXRSZXF1ZXN0VmFycygpLCAvLyBnZXQgdGhlIHJlcXVlc3QgdmFyc1xuICAgICAgICB2cFdpZHRoICAgICAgICAgICAgID0gMCxcbiAgICAgICAgdHJhY2tWaWV3cG9ydFdpZHRoICA9IHRydWUsIC8vIGNhbiB0b2dnbGUgdGhpcyBmZWF0dXJlIG9uICYgb2ZmXG4gICAgICAgIHBhdHRlcm5OYW1lICAgICAgICAgPSAnYWxsJyxcbiAgICAgICAgcGF0dGVyblBhdGggICAgICAgICA9ICcnLFxuICAgICAgICBpRnJhbWVQYXRoICAgICAgICAgID0gd2luZG93LmxvY2F0aW9uLnByb3RvY29sICsgJy8vJyArIHdpbmRvdy5sb2NhdGlvbi5ob3N0ICsgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnJlcGxhY2UoJ2luZGV4Lmh0bWwnLCAnJykgKyAnc3R5bGVndWlkZS9odG1sL3N0eWxlZ3VpZGUuaHRtbCc7XG5cbiAgICAvLyBjYXB0dXJlIHRoZSB2aWV3cG9ydCB3aWR0aCB0aGF0IHdhcyBsb2FkZWQgYW5kIG1vZGlmeSBpdCBzbyBpdCBmaXRzIHdpdGggdGhlIHB1bGwgYmFyXG4gICAgZWxHZW5Db250YWluZXIuc3R5bGUud2lkdGggPSBvcmlnVmlld3BvcnRXaWR0aCArICdweCc7XG4gICAgZWxWaWV3cG9ydC5zdHlsZS53aWR0aCA9IChvcmlnVmlld3BvcnRXaWR0aCAtIDE0KSArICdweCc7XG4gICAgdXBkYXRlU2l6ZVJlYWRpbmcob3JpZ1ZpZXdwb3J0V2lkdGggLSAxNCk7XG5cbiAgICAvLyBwcmUtbG9hZCB0aGUgdmlld3BvcnQgd2lkdGhcbiAgICBpZiAob0dldFZhcnMuaCB8fCBvR2V0VmFycy5oYXkpIHtcbiAgICAgICAgc3RhcnRIYXkoKTtcbiAgICB9IGVsc2UgaWYgKG9HZXRWYXJzLmQgfHwgb0dldFZhcnMuZGlzY28pIHtcbiAgICAgICAgc3RhcnREaXNjbygpO1xuICAgIH0gZWxzZSBpZiAob0dldFZhcnMudyB8fCBvR2V0VmFycy53aWR0aCkge1xuICAgICAgICB2cFdpZHRoID0gb0dldFZhcnMudyB8fCBvR2V0VmFycy53aWR0aDtcbiAgICAgICAgdnBXaWR0aCA9IHZwV2lkdGguaW5kZXhPZignZW0nKSAhPT0gLTEgPyBNYXRoLmZsb29yKE1hdGguZmxvb3IodnBXaWR0aC5yZXBsYWNlKCdlbScsICcnKSkgKiBjb25maWcuYm9keVNpemUpIDogTWF0aC5mbG9vcih2cFdpZHRoLnJlcGxhY2UoJ3B4JywgJycpKTtcblxuICAgICAgICBkYXRhU2F2ZXIudXBkYXRlVmFsdWUoJ3ZwV2lkdGgnLCB2cFdpZHRoKTtcbiAgICAgICAgdXBkYXRlVmlld3BvcnRXaWR0aCh2cFdpZHRoKTtcbiAgICB9IGVsc2UgaWYgKHRyYWNrVmlld3BvcnRXaWR0aCAmJiBkYXRhU2F2ZXIuZmluZFZhbHVlKCd2cFdpZHRoJykpIHtcbiAgICAgICAgdXBkYXRlVmlld3BvcnRXaWR0aChkYXRhU2F2ZXIuZmluZFZhbHVlKCd2cFdpZHRoJykpO1xuICAgIH1cblxuICAgIC8vIGxvYWQgdGhlIGlmcmFtZSBzb3VyY2VcbiAgICBpZiAob0dldFZhcnMucCB8fCBvR2V0VmFycy5wYXR0ZXJuKSB7XG4gICAgICAgIHBhdHRlcm5OYW1lID0gb0dldFZhcnMucCB8fCBvR2V0VmFycy5wYXR0ZXJuO1xuICAgICAgICBwYXR0ZXJuUGF0aCA9IHVybEhhbmRsZXIuZ2V0RmlsZU5hbWUocGF0dGVybk5hbWUpO1xuICAgICAgICBpRnJhbWVQYXRoICA9IChwYXR0ZXJuUGF0aCAhPT0gJycpID8gd2luZG93LmxvY2F0aW9uLnByb3RvY29sICsgJy8vJyArIHdpbmRvdy5sb2NhdGlvbi5ob3N0ICsgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnJlcGxhY2UoJ2luZGV4Lmh0bWwnLCAnJykgKyBwYXR0ZXJuUGF0aCA6IGlGcmFtZVBhdGg7XG4gICAgfVxuXG4gICAgaWYgKHBhdHRlcm5OYW1lICE9PSAnYWxsJykge1xuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGl0bGUnKS5pbm5lckhUTUwgPSAnUGF0dGVybiBMYWIgLSAnICsgcGF0dGVybk5hbWU7XG4gICAgICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZSh7ICdwYXR0ZXJuJzogcGF0dGVybk5hbWUgfSwgbnVsbCwgbnVsbCk7XG4gICAgfVxuXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3NnLXJhdycpLnNldEF0dHJpYnV0ZSgnaHJlZicsIHVybEhhbmRsZXIuZ2V0RmlsZU5hbWUocGF0dGVybk5hbWUpKTtcblxuICAgIHVybEhhbmRsZXIuc2tpcEJhY2sgPSB0cnVlO1xuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy12aWV3cG9ydCcpLmNvbnRlbnRXaW5kb3cubG9jYXRpb24ucmVwbGFjZShpRnJhbWVQYXRoKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgc2l6ZWlmcmFtZSAgICAgICAgICA6IHNpemVpZnJhbWUsXG4gICAgZ2V0UmFuZG9tICAgICAgICAgICA6IGdldFJhbmRvbSxcbiAgICB1cGRhdGVWaWV3cG9ydFdpZHRoIDogdXBkYXRlVmlld3BvcnRXaWR0aCxcbiAgICBkaXNjbyAgICAgICAgICAgICAgIDogZGlzY28sXG4gICAga2lsbERpc2NvICAgICAgICAgICA6IGtpbGxEaXNjbyxcbiAgICBzdGFydERpc2NvICAgICAgICAgIDogc3RhcnREaXNjbyxcbiAgICBzdGFydEhheSAgICAgICAgICAgIDogc3RhcnRIYXksXG4gICAga2lsbEhheSAgICAgICAgICAgICA6IGtpbGxIYXksXG4gICAgdG9nZ2xlRGlzY28gICAgICAgICA6IHRvZ2dsZURpc2NvLFxuICAgIHRvZ2dsZUhheSAgICAgICAgICAgOiB0b2dnbGVIYXksXG4gICAgdXBkYXRlU2l6ZVJlYWRpbmcgICA6IHVwZGF0ZVNpemVSZWFkaW5nLFxuICAgIGNsb3NlUGFuZWxzICAgICAgICAgOiBjbG9zZVBhbmVscyxcbiAgICBpbml0ICAgICAgICAgICAgICAgIDogaW5pdFxufTsiLCIvKmpzbGludCBpbmRlbnQ6IDQsIHJlZ2V4cDogdHJ1ZSovXG4vKmdsb2JhbCB3aW5kb3cqL1xudmFyIEV2ZW50RGVsZWdhdG9yICA9IHJlcXVpcmUoJy4vZXZlbnREZWxlZ2F0b3IvZXZlbnREZWxlZ2F0b3InKSxcbiAgICBjb25maWcgICAgICAgICAgPSByZXF1aXJlKCcuL2NvbmZpZycpLFxuICAgIGRhdGFTYXZlciAgICAgICA9IHJlcXVpcmUoJy4vZGF0YS1zYXZlcicpLFxuICAgIGd1aSAgICAgICAgICAgICA9IHJlcXVpcmUoJy4vZ3VpJyksXG4gICAgdXJsSGFuZGxlciAgICAgID0gcmVxdWlyZSgnLi91cmwtaGFuZGxlcicpLFxuICAgIGRlbGVnYXRvciAgICAgICA9IG5ldyBFdmVudERlbGVnYXRvcihkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpLFxuICAgIGVsVmlld3BvcnQgICAgICA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy12aWV3cG9ydCcpLFxuICAgIGVsQ292ZXIgICAgICAgICA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy1jb3ZlcicpO1xuXG5mdW5jdGlvbiBfcGFyZW50cyhlbGVtZW50LCBzZWxlY3RvciwgY2IpIHtcbiAgICB2YXIgdGFyZ2V0ID0gZWxlbWVudC5wYXJlbnROb2RlO1xuXG4gICAgd2hpbGUgKHRhcmdldCAmJiB0YXJnZXQgIT09IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCkge1xuICAgICAgICBpZiAodGFyZ2V0Lm1hdGNoZXMoc2VsZWN0b3IpKSB7XG4gICAgICAgICAgICBjYih0YXJnZXQpO1xuICAgICAgICB9XG4gICAgICAgIHRhcmdldCA9IHRhcmdldC5wYXJlbnROb2RlO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gX3NpYmxpbmdzKGVsZW1lbnQsIHNlbGVjdG9yLCBjYikge1xuICAgIHZhciB0YXJnZXQgPSBlbGVtZW50LnBhcmVudE5vZGUuY2hpbGRyZW5bMF07XG5cbiAgICB3aGlsZSAodGFyZ2V0KSB7XG4gICAgICAgIGlmICh0YXJnZXQubWF0Y2hlcyhzZWxlY3RvcikpIHtcbiAgICAgICAgICAgIGNiKHRhcmdldCk7XG4gICAgICAgIH1cbiAgICAgICAgdGFyZ2V0ID0gdGFyZ2V0Lm5leHRTaWJsaW5nO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gX3RvZ2dsZVVMKGUpIHtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgdmFyIHRhcmdldCA9IGUudGFyZ2V0LnBhcmVudE5vZGU7XG5cbiAgICBfcGFyZW50cyh0YXJnZXQsICd1bCcsIGZ1bmN0aW9uIChlbCkge1xuICAgICAgICBlbC5jbGFzc0xpc3QudG9nZ2xlKCdhY3RpdmUnKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gX3NpemUobnVtKSB7XG4gICAgZ3VpLmtpbGxEaXNjbygpO1xuICAgIGd1aS5raWxsSGF5KCk7XG4gICAgZ3VpLnNpemVpZnJhbWUobnVtKTtcbn1cblxuZGVsZWdhdG9yXG4gICAgLy8gaGFuZGxlcyB3aWRlbmluZyB0aGUgXCJ2aWV3cG9ydFwiXG4gICAgLy8gICAxLiBvbiBcIm1vdXNlZG93blwiIHN0b3JlIHRoZSBjbGljayBsb2NhdGlvblxuICAgIC8vICAgMi4gbWFrZSBhIGhpZGRlbiBkaXYgdmlzaWJsZSBzbyB0aGF0IGl0IGNhbiB0cmFjayBtb3VzZSBtb3ZlbWVudHMgYW5kIG1ha2Ugc3VyZSB0aGUgcG9pbnRlciBkb2Vzbid0IGdldCBsb3N0IGluIHRoZSBpZnJhbWVcbiAgICAvLyAgIDMuIG9uIFwibW91c2Vtb3ZlXCIgY2FsY3VsYXRlIHRoZSBtYXRoLCBzYXZlIHRoZSByZXN1bHRzIHRvIGEgY29va2llLCBhbmQgdXBkYXRlIHRoZSB2aWV3cG9ydFxuICAgIC5vbignbW91c2Vkb3duJywgJyNzZy1yaWdodHB1bGwnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAvLyBjYXB0dXJlIGRlZmF1bHQgZGF0YVxuICAgICAgICB2YXIgb3JpZ0NsaWVudFggPSBlLmNsaWVudFgsXG4gICAgICAgICAgICBvcmlnVmlld3BvcnRXaWR0aCA9IGVsVmlld3BvcnQub2Zmc2V0V2lkdGg7XG5cbiAgICAgICAgLy8gc2hvdyB0aGUgY292ZXJcbiAgICAgICAgZWxDb3Zlci5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblxuICAgICAgICAvLyBhZGQgdGhlIG1vdXNlIG1vdmUgZXZlbnQgYW5kIGNhcHR1cmUgZGF0YS4gYWxzbyB1cGRhdGUgdGhlIHZpZXdwb3J0IHdpZHRoXG4gICAgICAgIGRlbGVnYXRvci5vbignbW91c2Vtb3ZlJywgJyNzZy1jb3ZlcicsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICB2YXIgdmlld3BvcnRXaWR0aCA9IChvcmlnQ2xpZW50WCA+IGUuY2xpZW50WCkgP1xuICAgICAgICAgICAgICAgICAgICBvcmlnVmlld3BvcnRXaWR0aCAtICgob3JpZ0NsaWVudFggLSBlLmNsaWVudFgpICogMikgOlxuICAgICAgICAgICAgICAgICAgICBvcmlnVmlld3BvcnRXaWR0aCArICgoZS5jbGllbnRYIC0gb3JpZ0NsaWVudFgpICogMik7XG5cbiAgICAgICAgICAgIGlmICh2aWV3cG9ydFdpZHRoID4gY29uZmlnLm1pblZpZXdwb3J0V2lkdGgpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWRhdGFTYXZlci5maW5kVmFsdWUoJ3ZwV2lkdGgnKSkge1xuICAgICAgICAgICAgICAgICAgICBkYXRhU2F2ZXIuYWRkVmFsdWUoJ3ZwV2lkdGgnLCB2aWV3cG9ydFdpZHRoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkYXRhU2F2ZXIudXBkYXRlVmFsdWUoJ3ZwV2lkdGgnLCB2aWV3cG9ydFdpZHRoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBndWkuc2l6ZWlmcmFtZSh2aWV3cG9ydFdpZHRoLCBmYWxzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pXG5cbiAgICAvLyBvbiBcIm1vdXNldXBcIiB3ZSB1bmJpbmQgdGhlIFwibW91c2Vtb3ZlXCIgZXZlbnQgYW5kIGhpZGUgdGhlIGNvdmVyIGFnYWluXG4gICAgLm9uKCdtb3VzZXVwJywgJ2JvZHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGRlbGVnYXRvci5vZmYoJ21vdXNlbW92ZScsICcjc2ctY292ZXInKTtcbiAgICAgICAgZWxDb3Zlci5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIH0pXG5cbiAgICAvKiBQYXR0ZXJuIExhYiBhY2NvcmRpb24gZHJvcGRvd24gKi9cbiAgICAub24oJ2NsaWNrJywgJy5zZy1hY2MtaGFuZGxlJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgdmFyIG5leHQgPSBlLnRhcmdldDtcblxuICAgICAgICB3aGlsZSAobmV4dCAmJiAobmV4dC5ub2RlVHlwZSAhPT0gMSB8fCAhbmV4dC5tYXRjaGVzKCcuc2ctYWNjLXBhbmVsJykpKSB7XG4gICAgICAgICAgICBuZXh0ID0gbmV4dC5uZXh0U2libGluZztcbiAgICAgICAgfVxuXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICBlLnRhcmdldC5jbGFzc0xpc3QudG9nZ2xlKCdhY3RpdmUnKTtcbiAgICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgICAgIG5leHQuY2xhc3NMaXN0LnRvZ2dsZSgnYWN0aXZlJyk7XG4gICAgICAgIH1cbiAgICB9KVxuXG4gICAgLm9uKCdjbGljaycsICcuc2ctbmF2LXRvZ2dsZScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNnLW5hdi1jb250YWluZXInKS5jbGFzc0xpc3QudG9nZ2xlKCdhY3RpdmUnKTtcbiAgICB9KVxuXG4gICAgLy9WaWV3IChjb250YWluaW5nIGNsZWFuLCBjb2RlLCByYXcsIGV0YyBvcHRpb25zKSBUcmlnZ2VyXG4gICAgLm9uKCdjbGljaycsICcjc2ctdC10b2dnbGUnLCBfdG9nZ2xlVUwpXG5cbiAgICAvL1NpemUgVHJpZ2dlclxuICAgIC5vbignY2xpY2snLCAnI3NnLXNpemUtdG9nZ2xlJywgX3RvZ2dsZVVMKVxuXG4gICAgLy9QaGFzZSBWaWV3IEV2ZW50c1xuICAgIC5vbignY2xpY2snLCAnLnNnLXNpemVbZGF0YS1zaXplXScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgZ3VpLmtpbGxEaXNjbygpO1xuICAgICAgICBndWkua2lsbEhheSgpO1xuXG4gICAgICAgIHZhciB2YWwgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoJ2RhdGEtc2l6ZScpO1xuXG4gICAgICAgIGlmICh2YWwuaW5kZXhPZigncHgnKSA+IC0xKSB7XG4gICAgICAgICAgICBjb25maWcuYm9keVNpemUgPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFsID0gdmFsLnJlcGxhY2UoL1teXFxkLlxcLV0vZywgJycpO1xuICAgICAgICBndWkuc2l6ZWlmcmFtZShNYXRoLmZsb29yKHZhbCAqIGNvbmZpZy5ib2R5U2l6ZSkpO1xuICAgIH0pXG5cbiAgICAvL1NpemUgVmlldyBFdmVudHNcblxuICAgIC8vQ2xpY2sgU2l6ZSBTbWFsbCBCdXR0b25cbiAgICAub24oJ2NsaWNrJywgJyNzZy1zaXplLXMnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIF9zaXplKGd1aS5nZXRSYW5kb20oY29uZmlnLm1pblZpZXdwb3J0V2lkdGgsIDUwMCkpO1xuICAgIH0pXG5cbiAgICAvL0NsaWNrIFNpemUgTWVkaXVtIEJ1dHRvblxuICAgIC5vbignY2xpY2snLCAnI3NnLXNpemUtbScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgX3NpemUoZ3VpLmdldFJhbmRvbSg1MDAsIDgwMCkpO1xuICAgIH0pXG5cbiAgICAvL0NsaWNrIFNpemUgTGFyZ2UgQnV0dG9uXG4gICAgLm9uKCdjbGljaycsICcjc2ctc2l6ZS1sJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBfc2l6ZShndWkuZ2V0UmFuZG9tKDgwMCwgMTIwMCkpO1xuICAgIH0pXG5cbiAgICAvL0NsaWNrIEZ1bGwgV2lkdGggQnV0dG9uXG4gICAgLm9uKCdjbGljaycsICcjc2ctc2l6ZS1mdWxsJywgZnVuY3Rpb24gKGUpIHsgLy9SZXNldHMgXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgX3NpemUoY29uZmlnLnN3KTtcbiAgICB9KVxuXG4gICAgLy9DbGljayBSYW5kb20gU2l6ZSBCdXR0b25cbiAgICAub24oJ2NsaWNrJywgJyNzZy1zaXplLXJhbmRvbScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgX3NpemUoZ3VpLmdldFJhbmRvbShjb25maWcubWluVmlld3BvcnRXaWR0aCwgY29uZmlnLnN3KSk7XG4gICAgfSlcblxuICAgIC8vQ2xpY2sgZm9yIERpc2NvIE1vZGUsIHdoaWNoIHJlc2l6ZXMgdGhlIHZpZXdwb3J0IHJhbmRvbWx5XG4gICAgLm9uKCdjbGljaycsICcjc2ctc2l6ZS1kaXNjbycsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgZ3VpLmtpbGxIYXkoKTtcbiAgICAgICAgZ3VpLnRvZ2dsZURpc2NvKCk7XG4gICAgfSlcblxuICAgIC8vU3RlcGhlbiBIYXkgTW9kZSAtIFwiU3RhcnQgd2l0aCB0aGUgc21hbGwgc2NyZWVuIGZpcnN0LCB0aGVuIGV4cGFuZCB1bnRpbCBpdCBsb29rcyBsaWtlIHNoaXQuIFRpbWUgZm9yIGEgYnJlYWtwb2ludCFcIlxuICAgIC5vbignY2xpY2snLCAnI3NnLXNpemUtaGF5JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBndWkua2lsbERpc2NvKCk7XG4gICAgICAgIGd1aS50b2dnbGVIYXkoKTtcbiAgICB9KVxuXG4gICAgLy9QaXhlbCBpbnB1dFxuICAgIC5vbigna2V5ZG93bicsICcuc2ctc2l6ZS1weCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB2YWwgPSBwYXJzZUludChlLnRhcmdldC52YWx1ZSwgMTApO1xuXG4gICAgICAgIGlmIChlLmtleUNvZGUgPT09IDM4KSB7IC8vSWYgdGhlIHVwIGFycm93IGtleSBpcyBoaXRcbiAgICAgICAgICAgIHZhbCsrO1xuICAgICAgICAgICAgZ3VpLnNpemVpZnJhbWUodmFsLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZS5rZXlDb2RlID09PSA0MCkgeyAvL0lmIHRoZSBkb3duIGFycm93IGtleSBpcyBoaXRcbiAgICAgICAgICAgIHZhbC0tO1xuICAgICAgICAgICAgZ3VpLnNpemVpZnJhbWUodmFsLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZS5rZXlDb2RlID09PSAxMykgeyAvL0lmIHRoZSBFbnRlciBrZXkgaXMgaGl0XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBndWkuc2l6ZWlmcmFtZSh2YWwpOyAvL1NpemUgSWZyYW1lIHRvIHZhbHVlIG9mIHRleHQgYm94XG4gICAgICAgICAgICBlLnRhcmdldC5ibHVyKCk7XG4gICAgICAgIH1cbiAgICB9KVxuXG4gICAgLm9uKCdrZXl1cCcsICcuc2ctc2l6ZS1weCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB2YWwgPSBwYXJzZUludChlLnRhcmdldC52YWx1ZSwgMTApO1xuICAgICAgICBndWkudXBkYXRlU2l6ZVJlYWRpbmcodmFsLCAncHgnLCAndXBkYXRlRW1JbnB1dCcpO1xuICAgIH0pXG5cbiAgICAvL0VtIGlucHV0XG4gICAgLm9uKCdrZXlkb3duJywgJy5zZy1zaXplLWVtJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgdmFyIHZhbCA9IHBhcnNlRmxvYXQoZS50YXJnZXQudmFsdWUpO1xuXG4gICAgICAgIGlmIChlLmtleUNvZGUgPT09IDM4KSB7IC8vSWYgdGhlIHVwIGFycm93IGtleSBpcyBoaXRcbiAgICAgICAgICAgIHZhbCsrO1xuICAgICAgICAgICAgZ3VpLnNpemVpZnJhbWUoTWF0aC5mbG9vcih2YWwgKiBjb25maWcuYm9keVNpemUpLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZS5rZXlDb2RlID09PSA0MCkgeyAvL0lmIHRoZSBkb3duIGFycm93IGtleSBpcyBoaXRcbiAgICAgICAgICAgIHZhbC0tO1xuICAgICAgICAgICAgZ3VpLnNpemVpZnJhbWUoTWF0aC5mbG9vcih2YWwgKiBjb25maWcuYm9keVNpemUpLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZS5rZXlDb2RlID09PSAxMykgeyAvL0lmIHRoZSBFbnRlciBrZXkgaXMgaGl0XG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBndWkuc2l6ZWlmcmFtZShNYXRoLmZsb29yKHZhbCAqIGNvbmZpZy5ib2R5U2l6ZSkpOyAvL1NpemUgSWZyYW1lIHRvIHZhbHVlIG9mIHRleHQgYm94XG4gICAgICAgIH1cbiAgICB9KVxuXG4gICAgLm9uKCdrZXl1cCcsICcuc2ctc2l6ZS1lbScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIHZhciB2YWwgPSBwYXJzZUZsb2F0KGUudGFyZ2V0LnZhbHVlKTtcbiAgICAgICAgZ3VpLnVwZGF0ZVNpemVSZWFkaW5nKHZhbCwgJ2VtJywgJ3VwZGF0ZVB4SW5wdXQnKTtcbiAgICB9KVxuXG4gICAgLy8gaGFuZGxlIHRoZSBNUSBjbGlja1xuICAgIC5vbignY2xpY2snLCAnI3NnLW1xIGEnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHZhciB2YWwgICAgID0gZS50YXJnZXQuaW5uZXJIVE1MLFxuICAgICAgICAgICAgdHlwZSAgICA9IHBhcnNlSW50KCh2YWwuaW5kZXhPZigncHgnKSAhPT0gLTEgPyAncHgnIDogJ2VtJyksIDEwKTtcblxuICAgICAgICB2YWwgPSB2YWwucmVwbGFjZSh0eXBlLCAnJyk7XG5cbiAgICAgICAgZ3VpLnNpemVpZnJhbWUoKHR5cGUgPT09ICdweCcgPyB2YWwgOiB2YWwgKiBjb25maWcuYm9keVNpemUpLCB0cnVlKTtcbiAgICB9KVxuXG4gICAgLy8gdXBkYXRlIHRoZSBpZnJhbWUgd2l0aCB0aGUgc291cmNlIGZyb20gY2xpY2tlZCBlbGVtZW50IGluIHB1bGwgZG93biBtZW51LiBhbHNvIGNsb3NlIHRoZSBtZW51XG4gICAgLy8gaGF2aW5nIGl0IG91dHNpZGUgZml4ZXMgYW4gYXV0by1jbG9zZSBidWcgaSByYW4gaW50b1xuICAgIC5vbignY2xpY2snLCAnLnNnLW5hdiBhJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKGUudGFyZ2V0Lm1hdGNoZXMoJy5zZy1hY2MtaGFuZGxlJykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgLy8gdXBkYXRlIHRoZSBpZnJhbWUgdmlhIHRoZSBoaXN0b3J5IGFwaSBoYW5kbGVyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZy12aWV3cG9ydCcpLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgJ3BhdGgnOiB1cmxIYW5kbGVyLmdldEZpbGVOYW1lKGUudGFyZ2V0LmdldEF0dHJpYnV0ZSgnZGF0YS1wYXR0ZXJucGFydGlhbCcpKVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHVybEhhbmRsZXIudGFyZ2V0T3JpZ2luXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gY2xvc2UgdXAgdGhlIG1lbnVcbiAgICAgICAgX3BhcmVudHMoZS50YXJnZXQsICcuc2ctYWNjLXBhbmVsJywgZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgICAgICBlbC5jbGFzc0xpc3QudG9nZ2xlKCdhY3RpdmUnKTtcbiAgICAgICAgICAgIF9zaWJsaW5ncyhlbCwgJy5zZy1hY2MtaGFuZGxlJywgZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgICAgICAgICAgZWwuY2xhc3NMaXN0LnRvZ2dsZSgnYWN0aXZlJyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9KVxuXG4gICAgLm9uKCdjbGljaycsICcjc2ctdnAtd3JhcCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZ3VpLmNsb3NlUGFuZWxzKCk7XG4gICAgfSk7XG5cbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCBmdW5jdGlvbiAoKSB7XG4gICAgY29uZmlnLnN3ID0gZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aDtcbiAgICBjb25maWcuc2ggPSBkb2N1bWVudC5ib2R5LmNsaWVudEhlaWdodDtcbn0sIGZhbHNlKTtcblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBmdW5jdGlvbiByZWNlaXZlSWZyYW1lTWVzc2FnZShldmVudCkge1xuICAgIC8vIGRvZXMgdGhlIG9yaWdpbiBzZW5kaW5nIHRoZSBtZXNzYWdlIG1hdGNoIHRoZSBjdXJyZW50IGhvc3Q/IGlmIG5vdCBkZXYvbnVsbCB0aGUgcmVxdWVzdFxuICAgIGlmICgod2luZG93LmxvY2F0aW9uLnByb3RvY29sICE9PSAnZmlsZTonKSAmJiAoZXZlbnQub3JpZ2luICE9PSB3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgKyAnLy8nICsgd2luZG93LmxvY2F0aW9uLmhvc3QpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXZlbnQuZGF0YS5ib2R5Y2xpY2sgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBndWkuY2xvc2VQYW5lbHMoKTtcbiAgICB9IGVsc2UgaWYgKGV2ZW50LmRhdGEucGF0dGVybnBhcnRpYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAoIXVybEhhbmRsZXIuc2tpcEJhY2spIHtcbiAgICAgICAgICAgIGlmICh3aW5kb3cuaGlzdG9yeS5zdGF0ZSA9PT0gbnVsbCB8fCB3aW5kb3cuaGlzdG9yeS5zdGF0ZS5wYXR0ZXJuICE9PSBldmVudC5kYXRhLnBhdHRlcm5wYXJ0aWFsKSB7XG4gICAgICAgICAgICAgICAgdXJsSGFuZGxlci5wdXNoUGF0dGVybihldmVudC5kYXRhLnBhdHRlcm5wYXJ0aWFsLCBldmVudC5kYXRhLnBhdGgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHdpbmRvdy53c25Db25uZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnd3NuJyk7XG4gICAgICAgICAgICAgICAgdmFyIGlGcmFtZVBhdGggPSB1cmxIYW5kbGVyLmdldEZpbGVOYW1lKGV2ZW50LmRhdGEucGF0dGVybnBhcnRpYWwpO1xuICAgICAgICAgICAgICAgIHdpbmRvdy53c24uc2VuZCgne1widXJsXCI6IFwiJyArIGlGcmFtZVBhdGggKyAnXCIsIFwicGF0dGVybnBhcnRpYWxcIjogXCInICsgZXZlbnQuZGF0YS5wYXR0ZXJucGFydGlhbCArICdcIiB9Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBmb3IgdGVzdGluZyBwdXJwb3Nlc1xuICAgICAgICAvL2NvbnNvbGUubG9nKGV2ZW50LmRhdGEubGluZWFnZSk7XG5cbiAgICAgICAgLy8gcmVzZXQgdGhlIGRlZmF1bHRzXG4gICAgICAgIHVybEhhbmRsZXIuc2tpcEJhY2sgPSBmYWxzZTtcbiAgICB9XG59LCBmYWxzZSk7IiwidmFyIGd1aSAgICAgID0gcmVxdWlyZSgnLi9ndWknKTtcblxucmVxdWlyZSgnLi9oYW5kbGVycycpO1xuXG5ndWkuaW5pdCgpOyIsIi8qIVxuICogVVJMIEhhbmRsZXIgLSB2MC4xXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEzIERhdmUgT2xzZW4sIGh0dHA6Ly9kbW9sc2VuLmNvbVxuICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKlxuICogSGVscHMgaGFuZGxlIHRoZSBpbml0aWFsIGlGcmFtZSBzb3VyY2UuIFBhcnNlcyBhIHN0cmluZyB0byBzZWUgaWYgaXQgbWF0Y2hlc1xuICogYW4gZXhwZWN0ZWQgcGF0dGVybiBpbiBQYXR0ZXJuIExhYi4gU3VwcG9ydHMgUGF0dGVybiBMYWJzIGZ1enp5IHBhdHRlcm4gcGFydGlhbFxuICogbWF0Y2hpbmcgc3R5bGUuXG4gKlxuICovXG5cbnZhciB1cmxIYW5kbGVyID0ge1xuICAgIFxuICAgIC8vIHNldC11cCBzb21lIGRlZmF1bHQgdmFyc1xuICAgIHNraXBCYWNrOiBmYWxzZSxcbiAgICB0YXJnZXRPcmlnaW46ICh3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgPT0gXCJmaWxlOlwiKSA/IFwiKlwiIDogd2luZG93LmxvY2F0aW9uLnByb3RvY29sK1wiLy9cIit3aW5kb3cubG9jYXRpb24uaG9zdCxcbiAgICBcbiAgICAvKipcbiAgICAqIGdldCB0aGUgcmVhbCBmaWxlIG5hbWUgZm9yIGEgZ2l2ZW4gcGF0dGVybiBuYW1lXG4gICAgKiBAcGFyYW0gIHtTdHJpbmd9ICAgICAgIHRoZSBzaG9ydGhhbmQgcGFydGlhbHMgc3ludGF4IGZvciBhIGdpdmVuIHBhdHRlcm5cbiAgICAqXG4gICAgKiBAcmV0dXJuIHtTdHJpbmd9ICAgICAgIHRoZSByZWFsIGZpbGUgcGF0aFxuICAgICovXG4gICAgZ2V0RmlsZU5hbWU6IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIFxuICAgICAgICB2YXIgYmFzZURpciAgICAgPSBcInBhdHRlcm5zXCI7XG4gICAgICAgIHZhciBmaWxlTmFtZSAgICA9IFwiXCI7XG4gICAgICAgIFxuICAgICAgICBpZiAobmFtZSA9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmaWxlTmFtZTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgaWYgKG5hbWUgPT0gXCJhbGxcIikge1xuICAgICAgICAgICAgcmV0dXJuIFwic3R5bGVndWlkZS9odG1sL3N0eWxlZ3VpZGUuaHRtbFwiO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICB2YXIgcGF0aHMgPSAobmFtZS5pbmRleE9mKFwidmlld2FsbC1cIikgIT0gLTEpID8gdmlld0FsbFBhdGhzIDogcGF0dGVyblBhdGhzO1xuICAgICAgICBuYW1lQ2xlYW4gPSBuYW1lLnJlcGxhY2UoXCJ2aWV3YWxsLVwiLFwiXCIpO1xuICAgICAgICBcbiAgICAgICAgLy8gbG9vayBhdCB0aGlzIGFzIGEgcmVndWxhciBwYXR0ZXJuXG4gICAgICAgIHZhciBiaXRzICAgICAgICA9IHRoaXMuZ2V0UGF0dGVybkluZm8obmFtZUNsZWFuLCBwYXRocyk7XG4gICAgICAgIHZhciBwYXR0ZXJuVHlwZSA9IGJpdHNbMF07XG4gICAgICAgIHZhciBwYXR0ZXJuICAgICA9IGJpdHNbMV07XG4gICAgICAgIFxuICAgICAgICBpZiAoKHBhdGhzW3BhdHRlcm5UeXBlXSAhPSB1bmRlZmluZWQpICYmIChwYXRoc1twYXR0ZXJuVHlwZV1bcGF0dGVybl0gIT0gdW5kZWZpbmVkKSkge1xuICAgICAgICAgICAgXG4gICAgICAgICAgICBmaWxlTmFtZSA9IHBhdGhzW3BhdHRlcm5UeXBlXVtwYXR0ZXJuXTtcbiAgICAgICAgICAgIFxuICAgICAgICB9IGVsc2UgaWYgKHBhdGhzW3BhdHRlcm5UeXBlXSAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgZm9yIChwYXR0ZXJuTWF0Y2hLZXkgaW4gcGF0aHNbcGF0dGVyblR5cGVdKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBhdHRlcm5NYXRjaEtleS5pbmRleE9mKHBhdHRlcm4pICE9IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lID0gcGF0aHNbcGF0dGVyblR5cGVdW3BhdHRlcm5NYXRjaEtleV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmIChmaWxlTmFtZSA9PSBcIlwiKSB7XG4gICAgICAgICAgICByZXR1cm4gZmlsZU5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHZhciByZWdleCA9IC9cXC8vZztcbiAgICAgICAgaWYgKChuYW1lLmluZGV4T2YoXCJ2aWV3YWxsLVwiKSAhPSAtMSkgJiYgKGZpbGVOYW1lICE9IFwiXCIpKSB7XG4gICAgICAgICAgICBmaWxlTmFtZSA9IGJhc2VEaXIrXCIvXCIrZmlsZU5hbWUucmVwbGFjZShyZWdleCxcIi1cIikrXCIvaW5kZXguaHRtbFwiO1xuICAgICAgICB9IGVsc2UgaWYgKGZpbGVOYW1lICE9IFwiXCIpIHtcbiAgICAgICAgICAgIGZpbGVOYW1lID0gYmFzZURpcitcIi9cIitmaWxlTmFtZS5yZXBsYWNlKHJlZ2V4LFwiLVwiKStcIi9cIitmaWxlTmFtZS5yZXBsYWNlKHJlZ2V4LFwiLVwiKStcIi5odG1sXCI7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHJldHVybiBmaWxlTmFtZTtcbiAgICB9LFxuICAgIFxuICAgIC8qKlxuICAgICogYnJlYWsgdXAgYSBwYXR0ZXJuIGludG8gaXRzIHBhcnRzLCBwYXR0ZXJuIHR5cGUgYW5kIHBhdHRlcm4gbmFtZVxuICAgICogQHBhcmFtICB7U3RyaW5nfSAgICAgICB0aGUgc2hvcnRoYW5kIHBhcnRpYWxzIHN5bnRheCBmb3IgYSBnaXZlbiBwYXR0ZXJuXG4gICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgICAgIHRoZSBwYXRocyB0byBiZSBjb21wYXJlZFxuICAgICpcbiAgICAqIEByZXR1cm4ge0FycmF5fSAgICAgICAgdGhlIHBhdHRlcm4gdHlwZSBhbmQgcGF0dGVybiBuYW1lXG4gICAgKi9cbiAgICBnZXRQYXR0ZXJuSW5mbzogZnVuY3Rpb24gKG5hbWUsIHBhdGhzKSB7XG4gICAgICAgIHZhciBwYXR0ZXJuQml0cyA9IG5hbWUuc3BsaXQoXCItXCIpO1xuICAgICAgICBcbiAgICAgICAgdmFyIGkgPSAxO1xuICAgICAgICB2YXIgYyA9IHBhdHRlcm5CaXRzLmxlbmd0aDtcbiAgICAgICAgXG4gICAgICAgIHZhciBwYXR0ZXJuVHlwZSA9IHBhdHRlcm5CaXRzWzBdO1xuICAgICAgICB3aGlsZSAoKHBhdGhzW3BhdHRlcm5UeXBlXSA9PSB1bmRlZmluZWQpICYmIChpIDwgYykpIHtcbiAgICAgICAgICAgIHBhdHRlcm5UeXBlICs9IFwiLVwiK3BhdHRlcm5CaXRzW2ldO1xuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBwYXR0ZXJuID0gbmFtZS5zbGljZShwYXR0ZXJuVHlwZS5sZW5ndGgrMSxuYW1lLmxlbmd0aCk7XG4gICAgICAgIFxuICAgICAgICByZXR1cm4gW3BhdHRlcm5UeXBlLCBwYXR0ZXJuXTtcbiAgICAgICAgXG4gICAgfSxcbiAgICBcbiAgICAvKipcbiAgICAqIHNlYXJjaCB0aGUgcmVxdWVzdCB2YXJzIGZvciBhIHBhcnRpY3VsYXIgaXRlbVxuICAgICpcbiAgICAqIEByZXR1cm4ge09iamVjdH0gICAgICAgYSBzZWFyY2ggb2YgdGhlIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2ggdmFyc1xuICAgICovXG4gICAgZ2V0UmVxdWVzdFZhcnM6IGZ1bmN0aW9uKCkge1xuICAgICAgICBcbiAgICAgICAgLy8gdGhlIGZvbGxvd2luZyBpcyB0YWtlbiBmcm9tIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS93aW5kb3cubG9jYXRpb25cbiAgICAgICAgdmFyIG9HZXRWYXJzID0gbmV3IChmdW5jdGlvbiAoc1NlYXJjaCkge1xuICAgICAgICAgIGlmIChzU2VhcmNoLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGFJdEtleSwgbktleUlkID0gMCwgYUNvdXBsZXMgPSBzU2VhcmNoLnN1YnN0cigxKS5zcGxpdChcIiZcIik7IG5LZXlJZCA8IGFDb3VwbGVzLmxlbmd0aDsgbktleUlkKyspIHtcbiAgICAgICAgICAgICAgYUl0S2V5ID0gYUNvdXBsZXNbbktleUlkXS5zcGxpdChcIj1cIik7XG4gICAgICAgICAgICAgIHRoaXNbdW5lc2NhcGUoYUl0S2V5WzBdKV0gPSBhSXRLZXkubGVuZ3RoID4gMSA/IHVuZXNjYXBlKGFJdEtleVsxXSkgOiBcIlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSkod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gICAgICAgIFxuICAgICAgICByZXR1cm4gb0dldFZhcnM7XG4gICAgICAgIFxuICAgIH0sXG4gICAgXG4gICAgLyoqXG4gICAgKiBwdXNoIGEgcGF0dGVybiBvbnRvIHRoZSBjdXJyZW50IGhpc3RvcnkgYmFzZWQgb24gYSBjbGlja1xuICAgICogQHBhcmFtICB7U3RyaW5nfSAgICAgICB0aGUgc2hvcnRoYW5kIHBhcnRpYWxzIHN5bnRheCBmb3IgYSBnaXZlbiBwYXR0ZXJuXG4gICAgKiBAcGFyYW0gIHtTdHJpbmd9ICAgICAgIHRoZSBwYXRoIGdpdmVuIGJ5IHRoZSBsb2FkZWQgaWZyYW1lXG4gICAgKi9cbiAgICBwdXNoUGF0dGVybjogZnVuY3Rpb24gKHBhdHRlcm4sIGdpdmVuUGF0aCkge1xuICAgICAgICB2YXIgZGF0YSAgICAgICAgID0geyBcInBhdHRlcm5cIjogcGF0dGVybiB9O1xuICAgICAgICB2YXIgZmlsZU5hbWUgICAgID0gdXJsSGFuZGxlci5nZXRGaWxlTmFtZShwYXR0ZXJuKTtcbiAgICAgICAgdmFyIGV4cGVjdGVkUGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wcm90b2NvbCtcIi8vXCIrd2luZG93LmxvY2F0aW9uLmhvc3Qrd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLnJlcGxhY2UoXCJwdWJsaWMvaW5kZXguaHRtbFwiLFwicHVibGljL1wiKStmaWxlTmFtZTtcbiAgICAgICAgaWYgKGdpdmVuUGF0aCAhPSBleHBlY3RlZFBhdGgpIHtcbiAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB0byB1cGRhdGUgdGhlIGlmcmFtZSBiZWNhdXNlIHRoZXJlIHdhcyBhIGNsaWNrXG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInNnLXZpZXdwb3J0XCIpLmNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoIHsgXCJwYXRoXCI6IGZpbGVOYW1lIH0sIHVybEhhbmRsZXIudGFyZ2V0T3JpZ2luKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGFkZCB0byB0aGUgaGlzdG9yeVxuICAgICAgICAgICAgdmFyIGFkZHJlc3NSZXBsYWNlbWVudCA9ICh3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgPT0gXCJmaWxlOlwiKSA/IG51bGwgOiB3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wrXCIvL1wiK3dpbmRvdy5sb2NhdGlvbi5ob3N0K3dpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5yZXBsYWNlKFwiaW5kZXguaHRtbFwiLFwiXCIpK1wiP3A9XCIrcGF0dGVybjtcbiAgICAgICAgICAgIGhpc3RvcnkucHVzaFN0YXRlKGRhdGEsIG51bGwsIGFkZHJlc3NSZXBsYWNlbWVudCk7XG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInRpdGxlXCIpLmlubmVySFRNTCA9IFwiUGF0dGVybiBMYWIgLSBcIitwYXR0ZXJuO1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJzZy1yYXdcIikuc2V0QXR0cmlidXRlKFwiaHJlZlwiLHVybEhhbmRsZXIuZ2V0RmlsZU5hbWUocGF0dGVybikpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBcbiAgICAvKipcbiAgICAqIGJhc2VkIG9uIGEgY2xpY2sgZm9yd2FyZCBvciBiYWNrd2FyZCBtb2RpZnkgdGhlIHVybCBhbmQgaWZyYW1lIHNvdXJjZVxuICAgICogQHBhcmFtICB7T2JqZWN0fSAgICAgIGV2ZW50IGluZm8gbGlrZSBzdGF0ZSBhbmQgcHJvcGVydGllcyBzZXQgaW4gcHVzaFN0YXRlKClcbiAgICAqL1xuICAgIHBvcFBhdHRlcm46IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIFxuICAgICAgICB2YXIgc3RhdGUgPSBlLnN0YXRlO1xuICAgICAgICBcbiAgICAgICAgaWYgKHN0YXRlID09IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc2tpcEJhY2sgPSBmYWxzZTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSBlbHNlIGlmIChzdGF0ZSAhPSBudWxsKSB7XG4gICAgICAgICAgICB2YXIgcGF0dGVybk5hbWUgPSBzdGF0ZS5wYXR0ZXJuO1xuICAgICAgICB9IFxuICAgICAgICBcbiAgICAgICAgdmFyIGlGcmFtZVBhdGggPSBcIlwiO1xuICAgICAgICBpRnJhbWVQYXRoID0gdGhpcy5nZXRGaWxlTmFtZShwYXR0ZXJuTmFtZSk7XG4gICAgICAgIGlmIChpRnJhbWVQYXRoID09IFwiXCIpIHtcbiAgICAgICAgICAgIGlGcmFtZVBhdGggPSBcInN0eWxlZ3VpZGUvaHRtbC9zdHlsZWd1aWRlLmh0bWxcIjtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJzZy12aWV3cG9ydFwiKS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKCB7IFwicGF0aFwiOiBpRnJhbWVQYXRoIH0sIHVybEhhbmRsZXIudGFyZ2V0T3JpZ2luKTtcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJ0aXRsZVwiKS5pbm5lckhUTUwgPSBcIlBhdHRlcm4gTGFiIC0gXCIrcGF0dGVybk5hbWU7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwic2ctcmF3XCIpLnNldEF0dHJpYnV0ZShcImhyZWZcIix1cmxIYW5kbGVyLmdldEZpbGVOYW1lKHBhdHRlcm5OYW1lKSk7XG4gICAgICAgIFxuICAgICAgICBpZiAod3NuQ29ubmVjdGVkKSB7XG4gICAgICAgICAgICB3c24uc2VuZCggJ3tcInVybFwiOiBcIicraUZyYW1lUGF0aCsnXCIsIFwicGF0dGVybnBhcnRpYWxcIjogXCInK3BhdHRlcm5OYW1lKydcIiB9JyApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgIH1cbiAgICBcbn1cblxuLyoqXG4qIGhhbmRsZSB0aGUgb25wb3BzdGF0ZSBldmVudFxuKi9cbndpbmRvdy5vbnBvcHN0YXRlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgdXJsSGFuZGxlci5za2lwQmFjayA9IHRydWU7XG4gICAgdXJsSGFuZGxlci5wb3BQYXR0ZXJuKGV2ZW50KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB3aW5kb3cudXJsSGFuZGxlciA9IHVybEhhbmRsZXI7Il19
diff --git a/public/styleguide/js/url-handler.js b/public/styleguide/js/url-handler.js
index 1cfde3cab..757a1f309 100644
--- a/public/styleguide/js/url-handler.js
+++ b/public/styleguide/js/url-handler.js
@@ -11,172 +11,173 @@
*/
var urlHandler = {
-
- // set-up some default vars
- skipBack: false,
- targetOrigin: (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host,
-
- /**
- * get the real file name for a given pattern name
- * @param {String} the shorthand partials syntax for a given pattern
- *
- * @return {String} the real file path
- */
- getFileName: function (name) {
-
- var baseDir = "patterns";
- var fileName = "";
-
- if (name == undefined) {
- return fileName;
- }
-
- if (name == "all") {
- return "styleguide/html/styleguide.html";
- }
-
- var paths = (name.indexOf("viewall-") != -1) ? viewAllPaths : patternPaths;
- nameClean = name.replace("viewall-","");
-
- // look at this as a regular pattern
- var bits = this.getPatternInfo(nameClean, paths);
- var patternType = bits[0];
- var pattern = bits[1];
-
- if ((paths[patternType] != undefined) && (paths[patternType][pattern] != undefined)) {
-
- fileName = paths[patternType][pattern];
-
- } else if (paths[patternType] != undefined) {
-
- for (patternMatchKey in paths[patternType]) {
- if (patternMatchKey.indexOf(pattern) != -1) {
- fileName = paths[patternType][patternMatchKey];
- break;
- }
- }
-
- }
-
- if (fileName == "") {
- return fileName;
- }
-
- var regex = /\//g;
- if ((name.indexOf("viewall-") != -1) && (fileName != "")) {
- fileName = baseDir+"/"+fileName.replace(regex,"-")+"/index.html";
- } else if (fileName != "") {
- fileName = baseDir+"/"+fileName.replace(regex,"-")+"/"+fileName.replace(regex,"-")+".html";
- }
-
- return fileName;
- },
-
- /**
- * break up a pattern into its parts, pattern type and pattern name
- * @param {String} the shorthand partials syntax for a given pattern
- * @param {Object} the paths to be compared
- *
- * @return {Array} the pattern type and pattern name
- */
- getPatternInfo: function (name, paths) {
-
- var patternBits = name.split("-");
-
- var i = 1;
- var c = patternBits.length;
-
- var patternType = patternBits[0];
- while ((paths[patternType] == undefined) && (i < c)) {
- patternType += "-"+patternBits[i];
- i++;
- }
-
- pattern = name.slice(patternType.length+1,name.length);
-
- return [patternType, pattern];
-
- },
-
- /**
- * search the request vars for a particular item
- *
- * @return {Object} a search of the window.location.search vars
- */
- getRequestVars: function() {
-
- // the following is taken from https://developer.mozilla.org/en-US/docs/Web/API/window.location
- var oGetVars = new (function (sSearch) {
- if (sSearch.length > 1) {
- for (var aItKey, nKeyId = 0, aCouples = sSearch.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
- aItKey = aCouples[nKeyId].split("=");
- this[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : "";
- }
- }
- })(window.location.search);
-
- return oGetVars;
-
- },
-
- /**
- * push a pattern onto the current history based on a click
- * @param {String} the shorthand partials syntax for a given pattern
- * @param {String} the path given by the loaded iframe
- */
- pushPattern: function (pattern, givenPath) {
- var data = { "pattern": pattern };
- var fileName = urlHandler.getFileName(pattern);
- var expectedPath = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("public/index.html","public/")+fileName;
- if (givenPath != expectedPath) {
- // make sure to update the iframe because there was a click
- document.getElementById("sg-viewport").contentWindow.postMessage( { "path": fileName }, urlHandler.targetOrigin);
- } else {
- // add to the history
- var addressReplacement = (window.location.protocol == "file:") ? null : window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+"?p="+pattern;
- history.pushState(data, null, addressReplacement);
- document.getElementById("title").innerHTML = "Pattern Lab - "+pattern;
- document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(pattern));
- }
- },
-
- /**
- * based on a click forward or backward modify the url and iframe source
- * @param {Object} event info like state and properties set in pushState()
- */
- popPattern: function (e) {
-
- var state = e.state;
-
- if (state == null) {
- this.skipBack = false;
- return;
- } else if (state != null) {
- var patternName = state.pattern;
- }
-
- var iFramePath = "";
- iFramePath = this.getFileName(patternName);
- if (iFramePath == "") {
- iFramePath = "styleguide/html/styleguide.html";
- }
-
- document.getElementById("sg-viewport").contentWindow.postMessage( { "path": iFramePath }, urlHandler.targetOrigin);
- document.getElementById("title").innerHTML = "Pattern Lab - "+patternName;
- document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(patternName));
-
- if (wsnConnected) {
- wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+patternName+'" }' );
- }
-
- }
-
+
+ // set-up some default vars
+ skipBack: false,
+ targetOrigin: (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host,
+
+ /**
+ * get the real file name for a given pattern name
+ * @param {String} the shorthand partials syntax for a given pattern
+ *
+ * @return {String} the real file path
+ */
+ getFileName: function (name) {
+
+ var baseDir = "patterns";
+ var fileName = "";
+
+ if (name == undefined) {
+ return fileName;
+ }
+
+ if (name == "all") {
+ return "styleguide/html/styleguide.html";
+ }
+
+ var paths = (name.indexOf("viewall-") != -1) ? viewAllPaths : patternPaths;
+ nameClean = name.replace("viewall-","");
+
+ // look at this as a regular pattern
+ var bits = this.getPatternInfo(nameClean, paths);
+ var patternType = bits[0];
+ var pattern = bits[1];
+
+ if ((paths[patternType] != undefined) && (paths[patternType][pattern] != undefined)) {
+
+ fileName = paths[patternType][pattern];
+
+ } else if (paths[patternType] != undefined) {
+
+ for (patternMatchKey in paths[patternType]) {
+ if (patternMatchKey.indexOf(pattern) != -1) {
+ fileName = paths[patternType][patternMatchKey];
+ break;
+ }
+ }
+
+ }
+
+ if (fileName == "") {
+ return fileName;
+ }
+
+ var regex = /\//g;
+ if ((name.indexOf("viewall-") != -1) && (fileName != "")) {
+ fileName = baseDir+"/"+fileName.replace(regex,"-")+"/index.html";
+ } else if (fileName != "") {
+ fileName = baseDir+"/"+fileName.replace(regex,"-")+"/"+fileName.replace(regex,"-")+".html";
+ }
+
+ return fileName;
+ },
+
+ /**
+ * break up a pattern into its parts, pattern type and pattern name
+ * @param {String} the shorthand partials syntax for a given pattern
+ * @param {Object} the paths to be compared
+ *
+ * @return {Array} the pattern type and pattern name
+ */
+ getPatternInfo: function (name, paths) {
+ var patternBits = name.split("-");
+
+ var i = 1;
+ var c = patternBits.length;
+
+ var patternType = patternBits[0];
+ while ((paths[patternType] == undefined) && (i < c)) {
+ patternType += "-"+patternBits[i];
+ i++;
+ }
+
+ pattern = name.slice(patternType.length+1,name.length);
+
+ return [patternType, pattern];
+
+ },
+
+ /**
+ * search the request vars for a particular item
+ *
+ * @return {Object} a search of the window.location.search vars
+ */
+ getRequestVars: function() {
+
+ // the following is taken from https://developer.mozilla.org/en-US/docs/Web/API/window.location
+ var oGetVars = new (function (sSearch) {
+ if (sSearch.length > 1) {
+ for (var aItKey, nKeyId = 0, aCouples = sSearch.substr(1).split("&"); nKeyId < aCouples.length; nKeyId++) {
+ aItKey = aCouples[nKeyId].split("=");
+ this[unescape(aItKey[0])] = aItKey.length > 1 ? unescape(aItKey[1]) : "";
+ }
+ }
+ })(window.location.search);
+
+ return oGetVars;
+
+ },
+
+ /**
+ * push a pattern onto the current history based on a click
+ * @param {String} the shorthand partials syntax for a given pattern
+ * @param {String} the path given by the loaded iframe
+ */
+ pushPattern: function (pattern, givenPath) {
+ var data = { "pattern": pattern };
+ var fileName = urlHandler.getFileName(pattern);
+ var expectedPath = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("public/index.html","public/")+fileName;
+ if (givenPath != expectedPath) {
+ // make sure to update the iframe because there was a click
+ document.getElementById("sg-viewport").contentWindow.postMessage( { "path": fileName }, urlHandler.targetOrigin);
+ } else {
+ // add to the history
+ var addressReplacement = (window.location.protocol == "file:") ? null : window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+"?p="+pattern;
+ history.pushState(data, null, addressReplacement);
+ document.getElementById("title").innerHTML = "Pattern Lab - "+pattern;
+ document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(pattern));
+ }
+ },
+
+ /**
+ * based on a click forward or backward modify the url and iframe source
+ * @param {Object} event info like state and properties set in pushState()
+ */
+ popPattern: function (e) {
+
+ var state = e.state;
+
+ if (state == null) {
+ this.skipBack = false;
+ return;
+ } else if (state != null) {
+ var patternName = state.pattern;
+ }
+
+ var iFramePath = "";
+ iFramePath = this.getFileName(patternName);
+ if (iFramePath == "") {
+ iFramePath = "styleguide/html/styleguide.html";
+ }
+
+ document.getElementById("sg-viewport").contentWindow.postMessage( { "path": iFramePath }, urlHandler.targetOrigin);
+ document.getElementById("title").innerHTML = "Pattern Lab - "+patternName;
+ document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(patternName));
+
+ if (wsnConnected) {
+ wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+patternName+'" }' );
+ }
+
+ }
+
}
/**
* handle the onpopstate event
*/
window.onpopstate = function (event) {
- urlHandler.skipBack = true;
- urlHandler.popPattern(event);
-}
\ No newline at end of file
+ urlHandler.skipBack = true;
+ urlHandler.popPattern(event);
+}
+
+module.exports = window.urlHandler = urlHandler;
\ No newline at end of file
diff --git a/public/styleguide/js/vendor/arrayIndexOf.js b/public/styleguide/js/vendor/arrayIndexOf.js
new file mode 100644
index 000000000..529b63891
--- /dev/null
+++ b/public/styleguide/js/vendor/arrayIndexOf.js
@@ -0,0 +1,63 @@
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function (searchElement, fromIndex) {
+
+ var k;
+
+ // 1. Let O be the result of calling ToObject passing
+ // the this value as the argument.
+ if (this == null) {
+ throw new TypeError('"this" is null or not defined');
+ }
+
+ var O = Object(this);
+
+ // 2. Let lenValue be the result of calling the Get
+ // internal method of O with the argument "length".
+ // 3. Let len be ToUint32(lenValue).
+ var len = O.length >>> 0;
+
+ // 4. If len is 0, return -1.
+ if (len === 0) {
+ return -1;
+ }
+
+ // 5. If argument fromIndex was passed let n be
+ // ToInteger(fromIndex); else let n be 0.
+ var n = +fromIndex || 0;
+
+ if (Math.abs(n) === Infinity) {
+ n = 0;
+ }
+
+ // 6. If n >= len, return -1.
+ if (n >= len) {
+ return -1;
+ }
+
+ // 7. If n >= 0, then Let k be n.
+ // 8. Else, n<0, Let k be len - abs(n).
+ // If k is less than 0, then let k be 0.
+ k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
+
+ // 9. Repeat, while k < len
+ while (k < len) {
+ // a. Let Pk be ToString(k).
+ // This is implicit for LHS operands of the in operator
+ // b. Let kPresent be the result of calling the
+ // HasProperty internal method of O with argument Pk.
+ // This step can be combined with c
+ // c. If kPresent is true, then
+ // i. Let elementK be the result of calling the Get
+ // internal method of O with the argument ToString(k).
+ // ii. Let same be the result of applying the
+ // Strict Equality Comparison Algorithm to
+ // searchElement and elementK.
+ // iii. If same is true, return k.
+ if (k in O && O[k] === searchElement) {
+ return k;
+ }
+ k++;
+ }
+ return -1;
+ };
+}
\ No newline at end of file
diff --git a/public/styleguide/js/vendor/classlist.js b/public/styleguide/js/vendor/classlist.js
new file mode 100644
index 000000000..025983951
--- /dev/null
+++ b/public/styleguide/js/vendor/classlist.js
@@ -0,0 +1,237 @@
+/*
+ * classList.js: Cross-browser full element.classList implementation.
+ * 2014-07-23
+ *
+ * By Eli Grey, http://eligrey.com
+ * Public Domain.
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ */
+
+/*global self, document, DOMException */
+
+/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
+
+if ("document" in self) {
+
+// Full polyfill for browsers with no classList support
+if (!("classList" in document.createElement("_"))) {
+
+(function (view) {
+
+"use strict";
+
+if (!('Element' in view)) return;
+
+var
+ classListProp = "classList"
+ , protoProp = "prototype"
+ , elemCtrProto = view.Element[protoProp]
+ , objCtr = Object
+ , strTrim = String[protoProp].trim || function () {
+ return this.replace(/^\s+|\s+$/g, "");
+ }
+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
+ var
+ i = 0
+ , len = this.length
+ ;
+ for (; i < len; i++) {
+ if (i in this && this[i] === item) {
+ return i;
+ }
+ }
+ return -1;
+ }
+ // Vendors: please allow content code to instantiate DOMExceptions
+ , DOMEx = function (type, message) {
+ this.name = type;
+ this.code = DOMException[type];
+ this.message = message;
+ }
+ , checkTokenAndGetIndex = function (classList, token) {
+ if (token === "") {
+ throw new DOMEx(
+ "SYNTAX_ERR"
+ , "An invalid or illegal string was specified"
+ );
+ }
+ if (/\s/.test(token)) {
+ throw new DOMEx(
+ "INVALID_CHARACTER_ERR"
+ , "String contains an invalid character"
+ );
+ }
+ return arrIndexOf.call(classList, token);
+ }
+ , ClassList = function (elem) {
+ var
+ trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
+ , i = 0
+ , len = classes.length
+ ;
+ for (; i < len; i++) {
+ this.push(classes[i]);
+ }
+ this._updateClassName = function () {
+ elem.setAttribute("class", this.toString());
+ };
+ }
+ , classListProto = ClassList[protoProp] = []
+ , classListGetter = function () {
+ return new ClassList(this);
+ }
+;
+// Most DOMException implementations don't allow calling DOMException's toString()
+// on non-DOMExceptions. Error's toString() is sufficient here.
+DOMEx[protoProp] = Error[protoProp];
+classListProto.item = function (i) {
+ return this[i] || null;
+};
+classListProto.contains = function (token) {
+ token += "";
+ return checkTokenAndGetIndex(this, token) !== -1;
+};
+classListProto.add = function () {
+ var
+ tokens = arguments
+ , i = 0
+ , l = tokens.length
+ , token
+ , updated = false
+ ;
+ do {
+ token = tokens[i] + "";
+ if (checkTokenAndGetIndex(this, token) === -1) {
+ this.push(token);
+ updated = true;
+ }
+ }
+ while (++i < l);
+
+ if (updated) {
+ this._updateClassName();
+ }
+};
+classListProto.remove = function () {
+ var
+ tokens = arguments
+ , i = 0
+ , l = tokens.length
+ , token
+ , updated = false
+ , index
+ ;
+ do {
+ token = tokens[i] + "";
+ index = checkTokenAndGetIndex(this, token);
+ while (index !== -1) {
+ this.splice(index, 1);
+ updated = true;
+ index = checkTokenAndGetIndex(this, token);
+ }
+ }
+ while (++i < l);
+
+ if (updated) {
+ this._updateClassName();
+ }
+};
+classListProto.toggle = function (token, force) {
+ token += "";
+
+ var
+ result = this.contains(token)
+ , method = result ?
+ force !== true && "remove"
+ :
+ force !== false && "add"
+ ;
+
+ if (method) {
+ this[method](token);
+ }
+
+ if (force === true || force === false) {
+ return force;
+ } else {
+ return !result;
+ }
+};
+classListProto.toString = function () {
+ return this.join(" ");
+};
+
+if (objCtr.defineProperty) {
+ var classListPropDesc = {
+ get: classListGetter
+ , enumerable: true
+ , configurable: true
+ };
+ try {
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ } catch (ex) { // IE 8 doesn't support enumerable:true
+ if (ex.number === -0x7FF5EC54) {
+ classListPropDesc.enumerable = false;
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ }
+ }
+} else if (objCtr[protoProp].__defineGetter__) {
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
+}
+
+}(self));
+
+} else {
+// There is full or partial native classList support, so just check if we need
+// to normalize the add/remove and toggle APIs.
+
+(function () {
+ "use strict";
+
+ var testElement = document.createElement("_");
+
+ testElement.classList.add("c1", "c2");
+
+ // Polyfill for IE 10/11 and Firefox <26, where classList.add and
+ // classList.remove exist but support only one argument at a time.
+ if (!testElement.classList.contains("c2")) {
+ var createMethod = function(method) {
+ var original = DOMTokenList.prototype[method];
+
+ DOMTokenList.prototype[method] = function(token) {
+ var i, len = arguments.length;
+
+ for (i = 0; i < len; i++) {
+ token = arguments[i];
+ original.call(this, token);
+ }
+ };
+ };
+ createMethod('add');
+ createMethod('remove');
+ }
+
+ testElement.classList.toggle("c3", false);
+
+ // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
+ // support the second argument.
+ if (testElement.classList.contains("c3")) {
+ var _toggle = DOMTokenList.prototype.toggle;
+
+ DOMTokenList.prototype.toggle = function(token, force) {
+ if (1 in arguments && !this.contains(token) === !force) {
+ return force;
+ } else {
+ return _toggle.call(this, token);
+ }
+ };
+
+ }
+
+ testElement = null;
+}());
+
+}
+
+}
\ No newline at end of file
diff --git a/source/_patternlab-files/index.mustache b/source/_patternlab-files/index.mustache
index 630680200..7dcc349b1 100644
--- a/source/_patternlab-files/index.mustache
+++ b/source/_patternlab-files/index.mustache
@@ -79,10 +79,8 @@
-
{{> patternPaths }}
{{> viewAllPaths }}
-
{{> websockets }}
diff --git a/source/_patternlab-files/pattern-header-footer/footer.html b/source/_patternlab-files/pattern-header-footer/footer.html
index e2f666fe0..b4bcb48bc 100644
--- a/source/_patternlab-files/pattern-header-footer/footer.html
+++ b/source/_patternlab-files/pattern-header-footer/footer.html
@@ -9,8 +9,10 @@