| exports.parse = exports.decode = decode | 
|   | 
| exports.stringify = exports.encode = encode | 
|   | 
| exports.safe = safe | 
| exports.unsafe = unsafe | 
|   | 
| var eol = typeof process !== 'undefined' && | 
|   process.platform === 'win32' ? '\r\n' : '\n' | 
|   | 
| function encode (obj, opt) { | 
|   var children = [] | 
|   var out = '' | 
|   | 
|   if (typeof opt === 'string') { | 
|     opt = { | 
|       section: opt, | 
|       whitespace: false, | 
|     } | 
|   } else { | 
|     opt = opt || {} | 
|     opt.whitespace = opt.whitespace === true | 
|   } | 
|   | 
|   var separator = opt.whitespace ? ' = ' : '=' | 
|   | 
|   Object.keys(obj).forEach(function (k, _, __) { | 
|     var val = obj[k] | 
|     if (val && Array.isArray(val)) { | 
|       val.forEach(function (item) { | 
|         out += safe(k + '[]') + separator + safe(item) + '\n' | 
|       }) | 
|     } else if (val && typeof val === 'object') | 
|       children.push(k) | 
|     else | 
|       out += safe(k) + separator + safe(val) + eol | 
|   }) | 
|   | 
|   if (opt.section && out.length) | 
|     out = '[' + safe(opt.section) + ']' + eol + out | 
|   | 
|   children.forEach(function (k, _, __) { | 
|     var nk = dotSplit(k).join('\\.') | 
|     var section = (opt.section ? opt.section + '.' : '') + nk | 
|     var child = encode(obj[k], { | 
|       section: section, | 
|       whitespace: opt.whitespace, | 
|     }) | 
|     if (out.length && child.length) | 
|       out += eol | 
|   | 
|     out += child | 
|   }) | 
|   | 
|   return out | 
| } | 
|   | 
| function dotSplit (str) { | 
|   return str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') | 
|     .replace(/\\\./g, '\u0001') | 
|     .split(/\./).map(function (part) { | 
|       return part.replace(/\1/g, '\\.') | 
|         .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001') | 
|     }) | 
| } | 
|   | 
| function decode (str) { | 
|   var out = {} | 
|   var p = out | 
|   var section = null | 
|   //          section     |key      = value | 
|   var re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i | 
|   var lines = str.split(/[\r\n]+/g) | 
|   | 
|   lines.forEach(function (line, _, __) { | 
|     if (!line || line.match(/^\s*[;#]/)) | 
|       return | 
|     var match = line.match(re) | 
|     if (!match) | 
|       return | 
|     if (match[1] !== undefined) { | 
|       section = unsafe(match[1]) | 
|       if (section === '__proto__') { | 
|         // not allowed | 
|         // keep parsing the section, but don't attach it. | 
|         p = {} | 
|         return | 
|       } | 
|       p = out[section] = out[section] || {} | 
|       return | 
|     } | 
|     var key = unsafe(match[2]) | 
|     if (key === '__proto__') | 
|       return | 
|     var value = match[3] ? unsafe(match[4]) : true | 
|     switch (value) { | 
|       case 'true': | 
|       case 'false': | 
|       case 'null': value = JSON.parse(value) | 
|     } | 
|   | 
|     // Convert keys with '[]' suffix to an array | 
|     if (key.length > 2 && key.slice(-2) === '[]') { | 
|       key = key.substring(0, key.length - 2) | 
|       if (key === '__proto__') | 
|         return | 
|       if (!p[key]) | 
|         p[key] = [] | 
|       else if (!Array.isArray(p[key])) | 
|         p[key] = [p[key]] | 
|     } | 
|   | 
|     // safeguard against resetting a previously defined | 
|     // array by accidentally forgetting the brackets | 
|     if (Array.isArray(p[key])) | 
|       p[key].push(value) | 
|     else | 
|       p[key] = value | 
|   }) | 
|   | 
|   // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}} | 
|   // use a filter to return the keys that have to be deleted. | 
|   Object.keys(out).filter(function (k, _, __) { | 
|     if (!out[k] || | 
|       typeof out[k] !== 'object' || | 
|       Array.isArray(out[k])) | 
|       return false | 
|   | 
|     // see if the parent section is also an object. | 
|     // if so, add it to that, and mark this one for deletion | 
|     var parts = dotSplit(k) | 
|     var p = out | 
|     var l = parts.pop() | 
|     var nl = l.replace(/\\\./g, '.') | 
|     parts.forEach(function (part, _, __) { | 
|       if (part === '__proto__') | 
|         return | 
|       if (!p[part] || typeof p[part] !== 'object') | 
|         p[part] = {} | 
|       p = p[part] | 
|     }) | 
|     if (p === out && nl === l) | 
|       return false | 
|   | 
|     p[nl] = out[k] | 
|     return true | 
|   }).forEach(function (del, _, __) { | 
|     delete out[del] | 
|   }) | 
|   | 
|   return out | 
| } | 
|   | 
| function isQuoted (val) { | 
|   return (val.charAt(0) === '"' && val.slice(-1) === '"') || | 
|     (val.charAt(0) === "'" && val.slice(-1) === "'") | 
| } | 
|   | 
| function safe (val) { | 
|   return (typeof val !== 'string' || | 
|     val.match(/[=\r\n]/) || | 
|     val.match(/^\[/) || | 
|     (val.length > 1 && | 
|      isQuoted(val)) || | 
|     val !== val.trim()) | 
|     ? JSON.stringify(val) | 
|     : val.replace(/;/g, '\\;').replace(/#/g, '\\#') | 
| } | 
|   | 
| function unsafe (val, doUnesc) { | 
|   val = (val || '').trim() | 
|   if (isQuoted(val)) { | 
|     // remove the single quotes before calling JSON.parse | 
|     if (val.charAt(0) === "'") | 
|       val = val.substr(1, val.length - 2) | 
|   | 
|     try { | 
|       val = JSON.parse(val) | 
|     } catch (_) {} | 
|   } else { | 
|     // walk the val to find the first not-escaped ; character | 
|     var esc = false | 
|     var unesc = '' | 
|     for (var i = 0, l = val.length; i < l; i++) { | 
|       var c = val.charAt(i) | 
|       if (esc) { | 
|         if ('\\;#'.indexOf(c) !== -1) | 
|           unesc += c | 
|         else | 
|           unesc += '\\' + c | 
|   | 
|         esc = false | 
|       } else if (';#'.indexOf(c) !== -1) | 
|         break | 
|       else if (c === '\\') | 
|         esc = true | 
|       else | 
|         unesc += c | 
|     } | 
|     if (esc) | 
|       unesc += '\\' | 
|   | 
|     return unesc.trim() | 
|   } | 
|   return val | 
| } |